Merge pull request #164 from basecamp/accessory-hosts-or-roles
Run accessories on multiple hosts or roles
This commit is contained in:
21
README.md
21
README.md
@@ -540,7 +540,8 @@ accessories:
|
|||||||
memory: "2GB"
|
memory: "2GB"
|
||||||
redis:
|
redis:
|
||||||
image: redis:latest
|
image: redis:latest
|
||||||
host: 1.1.1.4
|
role:
|
||||||
|
- web
|
||||||
port: "36379:6379"
|
port: "36379:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- /var/lib/redis:/data
|
- /var/lib/redis:/data
|
||||||
@@ -550,6 +551,24 @@ accessories:
|
|||||||
port: 44444
|
port: 44444
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The hosts that the accessories will run on can be specified by hosts or roles:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Single host
|
||||||
|
mysql:
|
||||||
|
host: 1.1.1.1
|
||||||
|
# Multiple hosts
|
||||||
|
redis:
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.1.1.2
|
||||||
|
# By role
|
||||||
|
monitoring:
|
||||||
|
roles:
|
||||||
|
- web
|
||||||
|
- jobs
|
||||||
|
```
|
||||||
|
|
||||||
Now run `mrsk accessory start mysql` to start the MySQL server on 1.1.1.3. See `mrsk accessory` for all the commands possible.
|
Now run `mrsk accessory start mysql` to start the MySQL server on 1.1.1.3. See `mrsk accessory` for all the commands possible.
|
||||||
|
|
||||||
Accessory images must be public or tagged in your private registry.
|
Accessory images must be public or tagged in your private registry.
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
directories(name)
|
directories(name)
|
||||||
upload(name)
|
upload(name)
|
||||||
|
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
execute *MRSK.registry.login
|
execute *MRSK.registry.login
|
||||||
execute *MRSK.auditor.record("Booted #{name} accessory"), verbosity: :debug
|
execute *MRSK.auditor.record("Booted #{name} accessory"), verbosity: :debug
|
||||||
execute *accessory.run
|
execute *accessory.run
|
||||||
@@ -25,7 +25,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
def upload(name)
|
def upload(name)
|
||||||
with_lock do
|
with_lock do
|
||||||
with_accessory(name) do |accessory|
|
with_accessory(name) do |accessory|
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
accessory.files.each do |(local, remote)|
|
accessory.files.each do |(local, remote)|
|
||||||
accessory.ensure_local_file_present(local)
|
accessory.ensure_local_file_present(local)
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
def directories(name)
|
def directories(name)
|
||||||
with_lock do
|
with_lock do
|
||||||
with_accessory(name) do |accessory|
|
with_accessory(name) do |accessory|
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
accessory.directories.keys.each do |host_path|
|
accessory.directories.keys.each do |host_path|
|
||||||
execute *accessory.make_directory(host_path)
|
execute *accessory.make_directory(host_path)
|
||||||
end
|
end
|
||||||
@@ -66,7 +66,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
def start(name)
|
def start(name)
|
||||||
with_lock do
|
with_lock do
|
||||||
with_accessory(name) do |accessory|
|
with_accessory(name) do |accessory|
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
execute *MRSK.auditor.record("Started #{name} accessory"), verbosity: :debug
|
execute *MRSK.auditor.record("Started #{name} accessory"), verbosity: :debug
|
||||||
execute *accessory.start
|
execute *accessory.start
|
||||||
end
|
end
|
||||||
@@ -78,7 +78,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
def stop(name)
|
def stop(name)
|
||||||
with_lock do
|
with_lock do
|
||||||
with_accessory(name) do |accessory|
|
with_accessory(name) do |accessory|
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
execute *MRSK.auditor.record("Stopped #{name} accessory"), verbosity: :debug
|
execute *MRSK.auditor.record("Stopped #{name} accessory"), verbosity: :debug
|
||||||
execute *accessory.stop, raise_on_non_zero_exit: false
|
execute *accessory.stop, raise_on_non_zero_exit: false
|
||||||
end
|
end
|
||||||
@@ -102,7 +102,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
MRSK.accessory_names.each { |accessory_name| details(accessory_name) }
|
MRSK.accessory_names.each { |accessory_name| details(accessory_name) }
|
||||||
else
|
else
|
||||||
with_accessory(name) do |accessory|
|
with_accessory(name) do |accessory|
|
||||||
on(accessory.host) { puts capture_with_info(*accessory.info) }
|
on(accessory.hosts) { puts capture_with_info(*accessory.info) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -123,14 +123,14 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
|
|
||||||
when options[:reuse]
|
when options[:reuse]
|
||||||
say "Launching command from existing container...", :magenta
|
say "Launching command from existing container...", :magenta
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
execute *MRSK.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug
|
execute *MRSK.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug
|
||||||
capture_with_info(*accessory.execute_in_existing_container(cmd))
|
capture_with_info(*accessory.execute_in_existing_container(cmd))
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
say "Launching command from new container...", :magenta
|
say "Launching command from new container...", :magenta
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
execute *MRSK.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug
|
execute *MRSK.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug
|
||||||
capture_with_info(*accessory.execute_in_new_container(cmd))
|
capture_with_info(*accessory.execute_in_new_container(cmd))
|
||||||
end
|
end
|
||||||
@@ -149,7 +149,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
|
|
||||||
if options[:follow]
|
if options[:follow]
|
||||||
run_locally do
|
run_locally do
|
||||||
info "Following logs on #{accessory.host}..."
|
info "Following logs on #{accessory.hosts}..."
|
||||||
info accessory.follow_logs(grep: grep)
|
info accessory.follow_logs(grep: grep)
|
||||||
exec accessory.follow_logs(grep: grep)
|
exec accessory.follow_logs(grep: grep)
|
||||||
end
|
end
|
||||||
@@ -157,7 +157,7 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
since = options[:since]
|
since = options[:since]
|
||||||
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
||||||
|
|
||||||
on(accessory.host) do
|
on(accessory.hosts) do
|
||||||
puts capture_with_info(*accessory.logs(since: since, lines: lines, grep: grep))
|
puts capture_with_info(*accessory.logs(since: since, lines: lines, grep: grep))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -167,15 +167,17 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
desc "remove [NAME]", "Remove accessory container, image and data directory from host (use NAME=all to remove all accessories)"
|
desc "remove [NAME]", "Remove accessory container, image and data directory from host (use NAME=all to remove all accessories)"
|
||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
def remove(name)
|
def remove(name)
|
||||||
if name == "all"
|
with_lock do
|
||||||
MRSK.accessory_names.each { |accessory_name| remove(accessory_name) }
|
if name == "all"
|
||||||
else
|
MRSK.accessory_names.each { |accessory_name| remove(accessory_name) }
|
||||||
if options[:confirmed] || ask("This will remove all containers, images and data directories for #{name}. Are you sure?", limited_to: %w( y N ), default: "N") == "y"
|
else
|
||||||
with_accessory(name) do
|
if options[:confirmed] || ask("This will remove all containers, images and data directories for #{name}. Are you sure?", limited_to: %w( y N ), default: "N") == "y"
|
||||||
stop(name)
|
with_accessory(name) do
|
||||||
remove_container(name)
|
stop(name)
|
||||||
remove_image(name)
|
remove_container(name)
|
||||||
remove_service_directory(name)
|
remove_image(name)
|
||||||
|
remove_service_directory(name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -183,29 +185,35 @@ class Mrsk::Cli::Accessory < Mrsk::Cli::Base
|
|||||||
|
|
||||||
desc "remove_container [NAME]", "Remove accessory container from host", hide: true
|
desc "remove_container [NAME]", "Remove accessory container from host", hide: true
|
||||||
def remove_container(name)
|
def remove_container(name)
|
||||||
with_accessory(name) do |accessory|
|
with_lock do
|
||||||
on(accessory.host) do
|
with_accessory(name) do |accessory|
|
||||||
execute *MRSK.auditor.record("Remove #{name} accessory container"), verbosity: :debug
|
on(accessory.hosts) do
|
||||||
execute *accessory.remove_container
|
execute *MRSK.auditor.record("Remove #{name} accessory container"), verbosity: :debug
|
||||||
|
execute *accessory.remove_container
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "remove_image [NAME]", "Remove accessory image from host", hide: true
|
desc "remove_image [NAME]", "Remove accessory image from host", hide: true
|
||||||
def remove_image(name)
|
def remove_image(name)
|
||||||
with_accessory(name) do |accessory|
|
with_lock do
|
||||||
on(accessory.host) do
|
with_accessory(name) do |accessory|
|
||||||
execute *MRSK.auditor.record("Removed #{name} accessory image"), verbosity: :debug
|
on(accessory.hosts) do
|
||||||
execute *accessory.remove_image
|
execute *MRSK.auditor.record("Removed #{name} accessory image"), verbosity: :debug
|
||||||
|
execute *accessory.remove_image
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true
|
desc "remove_service_directory [NAME]", "Remove accessory directory used for uploaded files and data directories from host", hide: true
|
||||||
def remove_service_directory(name)
|
def remove_service_directory(name)
|
||||||
with_accessory(name) do |accessory|
|
with_lock do
|
||||||
on(accessory.host) do
|
with_accessory(name) do |accessory|
|
||||||
execute *accessory.remove_service_directory
|
on(accessory.hosts) do
|
||||||
|
execute *accessory.remove_service_directory
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class Mrsk::Commander
|
|||||||
end
|
end
|
||||||
|
|
||||||
def accessory_hosts
|
def accessory_hosts
|
||||||
specific_hosts || config.accessories.collect(&:host)
|
specific_hosts || config.accessories.flat_map(&:hosts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def accessory_names
|
def accessory_names
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
||||||
attr_reader :accessory_config
|
attr_reader :accessory_config
|
||||||
delegate :service_name, :image, :host, :port, :files, :directories, :publish_args, :env_args, :volume_args,
|
delegate :service_name, :image, :hosts, :port, :files, :directories, :cmd,
|
||||||
:label_args, :option_args, to: :accessory_config
|
:publish_args, :env_args, :volume_args, :label_args, :option_args, to: :accessory_config
|
||||||
|
|
||||||
def initialize(config, name:)
|
def initialize(config, name:)
|
||||||
super(config)
|
super(config)
|
||||||
@@ -19,7 +19,8 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|||||||
*volume_args,
|
*volume_args,
|
||||||
*label_args,
|
*label_args,
|
||||||
*option_args,
|
*option_args,
|
||||||
image
|
image,
|
||||||
|
cmd
|
||||||
end
|
end
|
||||||
|
|
||||||
def start
|
def start
|
||||||
@@ -75,7 +76,7 @@ class Mrsk::Commands::Accessory < Mrsk::Commands::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def run_over_ssh(command)
|
def run_over_ssh(command)
|
||||||
super command, host: host
|
super command, host: hosts.first
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,12 @@ class Mrsk::Configuration::Accessory
|
|||||||
specifics["image"]
|
specifics["image"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def host
|
def hosts
|
||||||
specifics["host"] || raise(ArgumentError, "Missing host for accessory")
|
if (specifics.keys & ["host", "hosts", "roles"]).size != 1
|
||||||
|
raise ArgumentError, "Specify one of `host`, `hosts` or `roles` for accessory `#{name}`"
|
||||||
|
end
|
||||||
|
|
||||||
|
hosts_from_host || hosts_from_hosts || hosts_from_roles
|
||||||
end
|
end
|
||||||
|
|
||||||
def port
|
def port
|
||||||
@@ -75,6 +79,10 @@ class Mrsk::Configuration::Accessory
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cmd
|
||||||
|
specifics["cmd"]
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
attr_accessor :config
|
attr_accessor :config
|
||||||
|
|
||||||
@@ -130,4 +138,32 @@ class Mrsk::Configuration::Accessory
|
|||||||
def service_data_directory
|
def service_data_directory
|
||||||
"$PWD/#{service_name}"
|
"$PWD/#{service_name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def hosts_from_host
|
||||||
|
if specifics.key?("host")
|
||||||
|
host = specifics["host"]
|
||||||
|
if host
|
||||||
|
[host]
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Missing host for accessory `#{name}`"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def hosts_from_hosts
|
||||||
|
if specifics.key?("hosts")
|
||||||
|
hosts = specifics["hosts"]
|
||||||
|
if hosts.is_a?(Array)
|
||||||
|
hosts
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Hosts should be an Array for accessory `#{name}`"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def hosts_from_roles
|
||||||
|
if specifics.key?("roles")
|
||||||
|
specifics["roles"].flat_map { |role| config.role(role).hosts }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ class CliAccessoryTest < CliTestCase
|
|||||||
|
|
||||||
run_command("boot", "all").tap do |output|
|
run_command("boot", "all").tap do |output|
|
||||||
assert_match /docker login.*on 1.1.1.3/, output
|
assert_match /docker login.*on 1.1.1.3/, output
|
||||||
assert_match /docker login.*on 1.1.1.4/, output
|
assert_match /docker login.*on 1.1.1.1/, output
|
||||||
|
assert_match /docker login.*on 1.1.1.2/, output
|
||||||
assert_match "docker run --name app-mysql --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 3306:3306 -e [REDACTED] -e MYSQL_ROOT_HOST=\"%\" --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" mysql:5.7 on 1.1.1.3", output
|
assert_match "docker run --name app-mysql --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 3306:3306 -e [REDACTED] -e MYSQL_ROOT_HOST=\"%\" --volume $PWD/app-mysql/etc/mysql/my.cnf:/etc/mysql/my.cnf --volume $PWD/app-mysql/data:/var/lib/mysql --label service=\"app-mysql\" mysql:5.7 on 1.1.1.3", output
|
||||||
assert_match "docker run --name app-redis --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 6379:6379 --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.4", output
|
assert_match "docker run --name app-redis --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 6379:6379 --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.1", output
|
||||||
|
assert_match "docker run --name app-redis --detach --restart unless-stopped --log-opt max-size=\"10m\" --publish 6379:6379 --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.2", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "deploy" do
|
test "deploy" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
||||||
@@ -31,7 +31,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "deploy with skip_push" do
|
test "deploy with skip_push" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:server:bootstrap", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options)
|
||||||
@@ -54,7 +54,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "redeploy" do
|
test "redeploy" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
||||||
@@ -67,7 +67,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "redeploy with skip_push" do
|
test "redeploy with skip_push" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_accessories.yml", "skip_broadcast" => false, "version" => "999" }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "skip_broadcast" => false, "version" => "999" }
|
||||||
|
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:pull", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:pull", [], invoke_options)
|
||||||
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options)
|
||||||
@@ -92,7 +92,7 @@ class CliMainTest < CliTestCase
|
|||||||
Mrsk::Cli::Main.any_instance.stubs(:container_name_available?).returns(true)
|
Mrsk::Cli::Main.any_instance.stubs(:container_name_available?).returns(true)
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:docker, :ps, "--filter", "label=service=app", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1").returns("version-to-rollback\n").at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info).with(:docker, :ps, "--filter", "label=service=app", "--format", "\"{{.Names}}\"", "|", "sed 's/-/\\n/g'", "|", "tail -n 1").returns("version-to-rollback\n").at_least_once
|
||||||
|
|
||||||
run_command("rollback", "123").tap do |output|
|
run_command("rollback", "123", config_file: "deploy_with_accessories").tap do |output|
|
||||||
assert_match "Start version 123", output
|
assert_match "Start version 123", output
|
||||||
assert_match "docker start app-123", output
|
assert_match "docker start app-123", output
|
||||||
assert_match "docker container ls --all --filter name=^app-version-to-rollback$ --quiet | xargs docker stop", output, "Should stop the container that was previously running"
|
assert_match "docker container ls --all --filter name=^app-version-to-rollback$ --quiet | xargs docker stop", output, "Should stop the container that was previously running"
|
||||||
@@ -126,7 +126,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "config" do
|
test "config" do
|
||||||
run_command("config", config_file: "deploy_with_accessories").tap do |output|
|
run_command("config", config_file: "deploy_simple").tap do |output|
|
||||||
config = YAML.load(output)
|
config = YAML.load(output)
|
||||||
|
|
||||||
assert_equal ["web"], config[:roles]
|
assert_equal ["web"], config[:roles]
|
||||||
@@ -224,7 +224,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "remove with confirmation" do
|
test "remove with confirmation" do
|
||||||
run_command("remove", "-y").tap do |output|
|
run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output|
|
||||||
assert_match /docker container stop traefik/, output
|
assert_match /docker container stop traefik/, output
|
||||||
assert_match /docker container prune --force --filter label=org.opencontainers.image.title=Traefik/, output
|
assert_match /docker container prune --force --filter label=org.opencontainers.image.title=Traefik/, output
|
||||||
assert_match /docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik/, output
|
assert_match /docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik/, output
|
||||||
@@ -253,7 +253,7 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command, config_file: "deploy_with_accessories")
|
def run_command(*command, config_file: "deploy_simple")
|
||||||
stdouted { Mrsk::Cli::Main.start([*command, "-c", "test/fixtures/#{config_file}.yml"]) }
|
stdouted { Mrsk::Cli::Main.start([*command, "-c", "test/fixtures/#{config_file}.yml"]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
|||||||
setup do
|
setup do
|
||||||
@deploy = {
|
@deploy = {
|
||||||
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
||||||
servers: [ "1.1.1.1", "1.1.1.2" ],
|
servers: {
|
||||||
|
"web" => [ "1.1.1.1", "1.1.1.2" ],
|
||||||
|
"workers" => [ "1.1.1.3", "1.1.1.4" ]
|
||||||
|
},
|
||||||
env: { "REDIS_URL" => "redis://x/y" },
|
env: { "REDIS_URL" => "redis://x/y" },
|
||||||
accessories: {
|
accessories: {
|
||||||
"mysql" => {
|
"mysql" => {
|
||||||
@@ -29,7 +32,7 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
|||||||
},
|
},
|
||||||
"redis" => {
|
"redis" => {
|
||||||
"image" => "redis:latest",
|
"image" => "redis:latest",
|
||||||
"host" => "1.1.1.6",
|
"hosts" => [ "1.1.1.6", "1.1.1.7" ],
|
||||||
"port" => "6379:6379",
|
"port" => "6379:6379",
|
||||||
"labels" => {
|
"labels" => {
|
||||||
"cache" => true
|
"cache" => true
|
||||||
@@ -44,6 +47,21 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
|||||||
"cpus" => 4,
|
"cpus" => 4,
|
||||||
"memory" => "2GB"
|
"memory" => "2GB"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"monitoring" => {
|
||||||
|
"image" => "monitoring:latest",
|
||||||
|
"roles" => [ "web" ],
|
||||||
|
"port" => "4321:4321",
|
||||||
|
"labels" => {
|
||||||
|
"cache" => true
|
||||||
|
},
|
||||||
|
"env" => {
|
||||||
|
"STATSD_PORT" => "8126"
|
||||||
|
},
|
||||||
|
"options" => {
|
||||||
|
"cpus" => 4,
|
||||||
|
"memory" => "2GB"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,8 +80,9 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "host" do
|
test "host" do
|
||||||
assert_equal "1.1.1.5", @config.accessory(:mysql).host
|
assert_equal ["1.1.1.5"], @config.accessory(:mysql).hosts
|
||||||
assert_equal "1.1.1.6", @config.accessory(:redis).host
|
assert_equal ["1.1.1.6", "1.1.1.7"], @config.accessory(:redis).hosts
|
||||||
|
assert_equal ["1.1.1.1", "1.1.1.2"], @config.accessory(:monitoring).hosts
|
||||||
end
|
end
|
||||||
|
|
||||||
test "missing host" do
|
test "missing host" do
|
||||||
@@ -71,10 +90,21 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
|||||||
@config = Mrsk::Configuration.new(@deploy)
|
@config = Mrsk::Configuration.new(@deploy)
|
||||||
|
|
||||||
assert_raises(ArgumentError) do
|
assert_raises(ArgumentError) do
|
||||||
@config.accessory(:mysql).host
|
@config.accessory(:mysql).hosts
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "setting host, hosts and roles" do
|
||||||
|
@deploy[:accessories]["mysql"]["hosts"] = true
|
||||||
|
@deploy[:accessories]["mysql"]["roles"] = true
|
||||||
|
@config = Mrsk::Configuration.new(@deploy)
|
||||||
|
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
@config.accessory(:mysql).hosts
|
||||||
|
end
|
||||||
|
assert_equal "Specify one of `host`, `hosts` or `roles` for accessory `mysql`", exception.message
|
||||||
|
end
|
||||||
|
|
||||||
test "label args" do
|
test "label args" do
|
||||||
assert_equal ["--label", "service=\"app-mysql\""], @config.accessory(:mysql).label_args
|
assert_equal ["--label", "service=\"app-mysql\""], @config.accessory(:mysql).label_args
|
||||||
assert_equal ["--label", "service=\"app-redis\"", "--label", "cache=\"true\""], @config.accessory(:redis).label_args
|
assert_equal ["--label", "service=\"app-redis\"", "--label", "cache=\"true\""], @config.accessory(:redis).label_args
|
||||||
|
|||||||
8
test/fixtures/deploy_simple.yml
vendored
Normal file
8
test/fixtures/deploy_simple.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
- "1.1.1.1"
|
||||||
|
- "1.1.1.2"
|
||||||
|
registry:
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
11
test/fixtures/deploy_with_accessories.yml
vendored
11
test/fixtures/deploy_with_accessories.yml
vendored
@@ -1,8 +1,12 @@
|
|||||||
service: app
|
service: app
|
||||||
image: dhh/app
|
image: dhh/app
|
||||||
servers:
|
servers:
|
||||||
- 1.1.1.1
|
web:
|
||||||
- 1.1.1.2
|
- "1.1.1.1"
|
||||||
|
- "1.1.1.2"
|
||||||
|
workers:
|
||||||
|
- "1.1.1.3"
|
||||||
|
- "1.1.1.4"
|
||||||
registry:
|
registry:
|
||||||
username: user
|
username: user
|
||||||
password: pw
|
password: pw
|
||||||
@@ -23,7 +27,8 @@ accessories:
|
|||||||
- data:/var/lib/mysql
|
- data:/var/lib/mysql
|
||||||
redis:
|
redis:
|
||||||
image: redis:latest
|
image: redis:latest
|
||||||
host: 1.1.1.4
|
roles:
|
||||||
|
- web
|
||||||
port: 6379
|
port: 6379
|
||||||
directories:
|
directories:
|
||||||
- data:/data
|
- data:/data
|
||||||
|
|||||||
Reference in New Issue
Block a user