Skip to content

Commit

Permalink
Merge pull request #715 from basecamp/use-role-not-string-in-config
Browse files Browse the repository at this point in the history
Pass around Roles instead of Strings
  • Loading branch information
djmb authored Mar 8, 2024
2 parents 52bb40a + 4966d52 commit e8b9f89
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 60 deletions.
10 changes: 4 additions & 6 deletions lib/kamal/cli/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ def boot

KAMAL.roles_on(host).each do |role|
app = KAMAL.app(role: role)
role_config = KAMAL.config.role(role)

if role_config.assets?
if role.assets?
execute *app.extract_assets
old_version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
execute *app.sync_asset_volumes(old_version: old_version)
Expand All @@ -27,7 +26,6 @@ def boot
KAMAL.roles_on(host).each do |role|
app = KAMAL.app(role: role)
auditor = KAMAL.auditor(role: role)
role_config = KAMAL.config.role(role)

if capture_with_info(*app.container_id_for_version(version), raise_on_non_zero_exit: false).present?
tmp_version = "#{version}_replaced_#{SecureRandom.hex(8)}"
Expand All @@ -38,7 +36,7 @@ def boot

old_version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip

execute *app.tie_cord(role_config.cord_host_file) if role_config.uses_cord?
execute *app.tie_cord(role.cord_host_file) if role.uses_cord?

execute *auditor.record("Booted app version #{version}"), verbosity: :debug

Expand All @@ -47,7 +45,7 @@ def boot
Kamal::Cli::Healthcheck::Poller.wait_for_healthy(pause_after_ready: true) { capture_with_info(*app.status(version: version)) }

if old_version.present?
if role_config.uses_cord?
if role.uses_cord?
cord = capture_with_info(*app.cord(version: old_version), raise_on_non_zero_exit: false).strip
if cord.present?
execute *app.cut_cord(cord)
Expand All @@ -57,7 +55,7 @@ def boot

execute *app.stop(version: old_version), raise_on_non_zero_exit: false

execute *app.clean_up_assets if role_config.assets?
execute *app.clean_up_assets if role.assets?
end
end
end
Expand Down
4 changes: 1 addition & 3 deletions lib/kamal/cli/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ def push
execute *KAMAL.auditor.record("Pushed env files"), verbosity: :debug

KAMAL.roles_on(host).each do |role|
role_config = KAMAL.config.role(role)
execute *KAMAL.app(role: role).make_env_directory
upload! StringIO.new(role_config.env_file), role_config.host_env_file_path, mode: 400
upload! StringIO.new(role.env_file), role.host_env_file_path, mode: 400
end
end

Expand All @@ -36,7 +35,6 @@ def delete
execute *KAMAL.auditor.record("Deleted env files"), verbosity: :debug

KAMAL.roles_on(host).each do |role|
role_config = KAMAL.config.role(role)
execute *KAMAL.app(role: role).remove_env_file
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/kamal/commander.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def specific_hosts=(hosts)

def primary_host
# Given a list of specific roles, make an effort to match up with the primary_role
specific_hosts&.first || specific_roles&.detect { |role| role.name == config.primary_role }&.primary_host || specific_roles&.first&.primary_host || config.primary_host
specific_hosts&.first || specific_roles&.detect { |role| role == config.primary_role }&.primary_host || specific_roles&.first&.primary_host || config.primary_host
end

def primary_role
Expand All @@ -73,7 +73,7 @@ def hosts
end

def roles_on(host)
roles.select { |role| role.hosts.include?(host.to_s) }.map(&:name)
roles.select { |role| role.hosts.include?(host.to_s) }
end

def traefik_hosts
Expand Down
25 changes: 12 additions & 13 deletions lib/kamal/commands/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ class Kamal::Commands::App < Kamal::Commands::Base

ACTIVE_DOCKER_STATUSES = [ :running, :restarting ]

attr_reader :role, :role_config
attr_reader :role, :role

def initialize(config, role: nil)
super(config)
@role = role
@role_config = config.role(self.role)
end

def run(hostname: nil)
Expand All @@ -19,15 +18,15 @@ def run(hostname: nil)
*(["--hostname", hostname] if hostname),
"-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
"-e", "KAMAL_VERSION=\"#{config.version}\"",
*role_config.env_args,
*role_config.health_check_args,
*role_config.logging_args,
*role.env_args,
*role.health_check_args,
*role.logging_args,
*config.volume_args,
*role_config.asset_volume_args,
*role_config.label_args,
*role_config.option_args,
*role.asset_volume_args,
*role.label_args,
*role.option_args,
config.absolute_image,
role_config.cmd
role.cmd
end

def start
Expand Down Expand Up @@ -64,22 +63,22 @@ def current_running_version
def list_versions(*docker_args, statuses: nil)
pipe \
docker(:ps, *filter_args(statuses: statuses), *docker_args, "--format", '"{{.Names}}"'),
%(while read line; do echo ${line##{role_config.container_prefix}-}; done) # Extract SHA from "service-role-dest-SHA"
%(while read line; do echo ${line##{role.container_prefix}-}; done) # Extract SHA from "service-role-dest-SHA"
end


def make_env_directory
make_directory role_config.host_env_directory
make_directory role.host_env_directory
end

def remove_env_file
[ :rm, "-f", role_config.host_env_file_path ]
[ :rm, "-f", role.host_env_file_path ]
end


private
def container_name(version = nil)
[ role_config.container_prefix, version || config.version ].compact.join("-")
[ role.container_prefix, version || config.version ].compact.join("-")
end

def filter_args(statuses: nil)
Expand Down
16 changes: 8 additions & 8 deletions lib/kamal/commands/app/assets.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
module Kamal::Commands::App::Assets
def extract_assets
asset_container = "#{role_config.container_prefix}-assets"
asset_container = "#{role.container_prefix}-assets"

combine \
make_directory(role_config.asset_extracted_path),
make_directory(role.asset_extracted_path),
[*docker(:stop, "-t 1", asset_container, "2> /dev/null"), "|| true"],
docker(:run, "--name", asset_container, "--detach", "--rm", config.latest_image, "sleep 1000000"),
docker(:cp, "-L", "#{asset_container}:#{role_config.asset_path}/.", role_config.asset_extracted_path),
docker(:cp, "-L", "#{asset_container}:#{role.asset_path}/.", role.asset_extracted_path),
docker(:stop, "-t 1", asset_container),
by: "&&"
end

def sync_asset_volumes(old_version: nil)
new_extracted_path, new_volume_path = role_config.asset_extracted_path(config.version), role_config.asset_volume.host_path
new_extracted_path, new_volume_path = role.asset_extracted_path(config.version), role.asset_volume.host_path
if old_version.present?
old_extracted_path, old_volume_path = role_config.asset_extracted_path(old_version), role_config.asset_volume(old_version).host_path
old_extracted_path, old_volume_path = role.asset_extracted_path(old_version), role.asset_volume(old_version).host_path
end

commands = [make_directory(new_volume_path), copy_contents(new_extracted_path, new_volume_path)]
Expand All @@ -29,8 +29,8 @@ def sync_asset_volumes(old_version: nil)

def clean_up_assets
chain \
find_and_remove_older_siblings(role_config.asset_extracted_path),
find_and_remove_older_siblings(role_config.asset_volume_path)
find_and_remove_older_siblings(role.asset_extracted_path),
find_and_remove_older_siblings(role.asset_volume_path)
end

private
Expand All @@ -39,7 +39,7 @@ def find_and_remove_older_siblings(path)
:find,
Pathname.new(path).dirname.to_s,
"-maxdepth 1",
"-name", "'#{role_config.container_prefix}-*'",
"-name", "'#{role.container_prefix}-*'",
"!", "-name", Pathname.new(path).basename.to_s,
"-exec rm -rf \"{}\" +"
]
Expand Down
6 changes: 3 additions & 3 deletions lib/kamal/commands/app/cord.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Kamal::Commands::App::Cord
def cord(version:)
pipe \
docker(:inspect, "-f '{{ range .Mounts }}{{printf \"%s %s\\n\" .Source .Destination}}{{ end }}'", container_name(version)),
[:awk, "'$2 == \"#{role_config.cord_volume.container_path}\" {print $1}'"]
[:awk, "'$2 == \"#{role.cord_volume.container_path}\" {print $1}'"]
end

def tie_cord(cord)
Expand All @@ -12,8 +12,8 @@ def tie_cord(cord)
def cut_cord(cord)
remove_directory(cord)
end
private

private
def create_empty_file(file)
chain \
make_directory_for(file),
Expand Down
4 changes: 2 additions & 2 deletions lib/kamal/commands/app/execution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ def execute_in_new_container(*command, interactive: false)
docker :run,
("-it" if interactive),
"--rm",
*role_config&.env_args,
*role&.env_args,
*config.volume_args,
*role_config&.option_args,
*role&.option_args,
config.absolute_image,
*command
end
Expand Down
30 changes: 17 additions & 13 deletions lib/kamal/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,19 @@ def all_hosts
end

def primary_host
role(primary_role)&.primary_host
primary_role&.primary_host
end

def primary_role_name
raw_config.primary_role || "web"
end

def primary_role
role(primary_role_name)
end

def allow_empty_roles?
raw_config.allow_empty_roles
end

def traefik_roles
Expand Down Expand Up @@ -212,14 +224,6 @@ def asset_path
raw_config.asset_path
end

def primary_role
raw_config.primary_role || "web"
end

def allow_empty_roles?
raw_config.allow_empty_roles
end


def valid?
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version && ensure_retain_containers_valid && ensure_valid_service_name
Expand Down Expand Up @@ -268,12 +272,12 @@ def ensure_required_keys_present
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
end

unless role_names.include?(primary_role)
raise ArgumentError, "The primary_role #{primary_role} isn't defined"
unless role_names.include?(primary_role_name)
raise ArgumentError, "The primary_role #{primary_role_name} isn't defined"
end

if role(primary_role).hosts.empty?
raise ArgumentError, "No servers specified for the #{primary_role} primary_role"
if primary_role.hosts.empty?
raise ArgumentError, "No servers specified for the #{primary_role.name} primary_role"
end

unless allow_empty_roles?
Expand Down
5 changes: 3 additions & 2 deletions lib/kamal/configuration/role.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ class Kamal::Configuration::Role
delegate :argumentize, :optionize, to: Kamal::Utils

attr_accessor :name
alias to_s name

def initialize(name, config:)
@name, @config = name.inquiry, config
@name, @config = name.inquiry, config
end

def primary_host
Expand Down Expand Up @@ -113,7 +114,7 @@ def running_traefik?
end

def primary?
@config.primary_role == name
self == @config.primary_role
end


Expand Down
10 changes: 5 additions & 5 deletions test/commander_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,14 @@ class CommanderTest < ActiveSupport::TestCase
end

test "primary_role" do
assert_equal "web", @kamal.primary_role
assert_equal "web", @kamal.primary_role.name
@kamal.specific_roles = "workers"
assert_equal "workers", @kamal.primary_role
assert_equal "workers", @kamal.primary_role.name
end

test "roles_on" do
assert_equal [ "web" ], @kamal.roles_on("1.1.1.1")
assert_equal [ "workers" ], @kamal.roles_on("1.1.1.3")
assert_equal [ "web" ], @kamal.roles_on("1.1.1.1").map(&:name)
assert_equal [ "workers" ], @kamal.roles_on("1.1.1.3").map(&:name)
end

test "default group strategy" do
Expand Down Expand Up @@ -120,7 +120,7 @@ class CommanderTest < ActiveSupport::TestCase

@kamal.specific_roles = [ "web_*" ]
assert_equal [ "web_chicago", "web_tokyo" ], @kamal.roles.map(&:name)
assert_equal "web_tokyo", @kamal.primary_role
assert_equal "web_tokyo", @kamal.primary_role.name
assert_equal "1.1.1.3", @kamal.primary_host
end

Expand Down
3 changes: 2 additions & 1 deletion test/commands/app_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ class CommandsAppTest < ActiveSupport::TestCase

private
def new_command(role: "web", **additional_config)
Kamal::Commands::App.new(Kamal::Configuration.new(@config.merge(additional_config), destination: @destination, version: "999"), role: role)
config = Kamal::Configuration.new(@config.merge(additional_config), destination: @destination, version: "999")
Kamal::Commands::App.new(config, role: config.role(role))
end
end
4 changes: 2 additions & 2 deletions test/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -300,14 +300,14 @@ class ConfigurationTest < ActiveSupport::TestCase
end

test "primary role" do
assert_equal "web", @config.primary_role
assert_equal "web", @config.primary_role.name

config = Kamal::Configuration.new(@deploy_with_roles.deep_merge({
servers: { "alternate_web" => { "hosts" => [ "1.1.1.4", "1.1.1.5" ] } },
primary_role: "alternate_web" } ))


assert_equal "alternate_web", config.primary_role
assert_equal "alternate_web", config.primary_role.name
assert_equal "1.1.1.4", config.primary_host
assert config.role(:alternate_web).primary?
assert config.role(:alternate_web).running_traefik?
Expand Down

0 comments on commit e8b9f89

Please sign in to comment.