Merge branch 'main' into global-logging-config
This commit is contained in:
@@ -6,7 +6,8 @@ class CliAccessoryTest < CliTestCase
|
||||
Mrsk::Cli::Accessory.any_instance.expects(:upload).with("mysql")
|
||||
|
||||
run_command("boot", "mysql").tap do |output|
|
||||
assert_match "docker run --name app-mysql --detach --restart unless-stopped --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 login.*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
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,8 +18,10 @@ class CliAccessoryTest < CliTestCase
|
||||
Mrsk::Cli::Accessory.any_instance.expects(:upload).with("redis")
|
||||
|
||||
run_command("boot", "all").tap do |output|
|
||||
assert_match "docker run --name app-mysql --detach --restart unless-stopped --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 --publish 6379:6379 --volume $PWD/app-redis/data:/data --label service=\"app-redis\" redis:latest on 1.1.1.4", output
|
||||
assert_match /docker login.*on 1.1.1.3/, output
|
||||
assert_match /docker login.*on 1.1.1.4/, 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
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -88,11 +88,23 @@ class CliMainTest < CliTestCase
|
||||
|
||||
test "rollback good version" do
|
||||
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").times(2)
|
||||
|
||||
run_command("rollback", "123").tap do |output|
|
||||
assert_match /Start version 123/, output
|
||||
assert_match /docker ps -q --filter label=service=app | xargs docker stop/, output
|
||||
assert_match /docker start app-123/, output
|
||||
assert_match "Start version 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"
|
||||
end
|
||||
end
|
||||
|
||||
test "rollback without old version" do
|
||||
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("").times(2)
|
||||
|
||||
run_command("rollback", "123").tap do |output|
|
||||
assert_match "Start version 123", output
|
||||
assert_match "docker start app-123", output
|
||||
assert_no_match "docker stop", output
|
||||
end
|
||||
end
|
||||
|
||||
@@ -114,7 +126,7 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
|
||||
test "config" do
|
||||
run_command("config").tap do |output|
|
||||
run_command("config", config_file: "deploy_with_accessories").tap do |output|
|
||||
config = YAML.load(output)
|
||||
|
||||
assert_equal ["web"], config[:roles]
|
||||
@@ -126,6 +138,32 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
end
|
||||
|
||||
test "config with roles" do
|
||||
run_command("config", config_file: "deploy_with_roles").tap do |output|
|
||||
config = YAML.load(output)
|
||||
|
||||
assert_equal ["web", "workers"], config[:roles]
|
||||
assert_equal ["1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4"], config[:hosts]
|
||||
assert_equal "999", config[:version]
|
||||
assert_equal "registry.digitalocean.com/dhh/app", config[:repository]
|
||||
assert_equal "registry.digitalocean.com/dhh/app:999", config[:absolute_image]
|
||||
assert_equal "app-999", config[:service_with_version]
|
||||
end
|
||||
end
|
||||
|
||||
test "config with destination" do
|
||||
run_command("config", "-d", "world", config_file: "deploy_for_dest").tap do |output|
|
||||
config = YAML.load(output)
|
||||
|
||||
assert_equal ["web"], config[:roles]
|
||||
assert_equal ["1.1.1.1", "1.1.1.2"], config[:hosts]
|
||||
assert_equal "999", config[:version]
|
||||
assert_equal "registry.digitalocean.com/dhh/app", config[:repository]
|
||||
assert_equal "registry.digitalocean.com/dhh/app:999", config[:absolute_image]
|
||||
assert_equal "app-999", config[:service_with_version]
|
||||
end
|
||||
end
|
||||
|
||||
test "init" do
|
||||
Pathname.any_instance.expects(:exist?).returns(false).twice
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
@@ -215,7 +253,7 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
|
||||
private
|
||||
def run_command(*command)
|
||||
stdouted { Mrsk::Cli::Main.start([*command, "-c", "test/fixtures/deploy_with_accessories.yml"]) }
|
||||
def run_command(*command, config_file: "deploy_with_accessories")
|
||||
stdouted { Mrsk::Cli::Main.start([*command, "-c", "test/fixtures/#{config_file}.yml"]) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,23 +2,15 @@ require "test_helper"
|
||||
|
||||
class CommanderTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@mrsk = Mrsk::Commander.new config_file: Pathname.new(File.expand_path("fixtures/deploy_with_roles.yml", __dir__))
|
||||
@mrsk = Mrsk::Commander.new.tap do |mrsk|
|
||||
mrsk.configure config_file: Pathname.new(File.expand_path("fixtures/deploy_with_roles.yml", __dir__))
|
||||
end
|
||||
end
|
||||
|
||||
test "lazy configuration" do
|
||||
assert_equal Mrsk::Configuration, @mrsk.config.class
|
||||
end
|
||||
|
||||
test "commit hash as version" do
|
||||
assert_equal `git rev-parse HEAD`.strip, @mrsk.config.version
|
||||
end
|
||||
|
||||
test "commit hash as version but not in git" do
|
||||
@mrsk.expects(:system).with("git rev-parse").returns(nil)
|
||||
error = assert_raises(RuntimeError) { @mrsk.config }
|
||||
assert_match /no git repository found/, error.message
|
||||
end
|
||||
|
||||
test "overwriting hosts" do
|
||||
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @mrsk.hosts
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ require "test_helper"
|
||||
class CommandsAccessoryTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@config = {
|
||||
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
||||
service: "app", image: "dhh/app", registry: { "server" => "private.registry", "username" => "dhh", "password" => "secret" },
|
||||
servers: [ "1.1.1.1" ],
|
||||
accessories: {
|
||||
"mysql" => {
|
||||
"image" => "mysql:8.0",
|
||||
"image" => "private.registry/mysql:8.0",
|
||||
"host" => "1.1.1.5",
|
||||
"port" => "3306",
|
||||
"env" => {
|
||||
@@ -32,6 +32,10 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
||||
"volumes" => [
|
||||
"/var/lib/redis:/data"
|
||||
]
|
||||
},
|
||||
"busybox" => {
|
||||
"image" => "busybox:latest",
|
||||
"host" => "1.1.1.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,24 +49,16 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
||||
|
||||
test "run" do
|
||||
assert_equal \
|
||||
"docker run --name app-mysql --detach --restart unless-stopped --publish 3306:3306 -e MYSQL_ROOT_PASSWORD=\"secret123\" -e MYSQL_ROOT_HOST=\"%\" --label service=\"app-mysql\" mysql:8.0",
|
||||
"docker run --name app-mysql --detach --restart unless-stopped --log-opt max-size=10m --publish 3306:3306 -e MYSQL_ROOT_PASSWORD=\"secret123\" -e MYSQL_ROOT_HOST=\"%\" --label service=\"app-mysql\" private.registry/mysql:8.0",
|
||||
new_command(:mysql).run.join(" ")
|
||||
|
||||
assert_equal \
|
||||
"docker run --name app-redis --detach --restart unless-stopped --publish 6379:6379 -e SOMETHING=\"else\" --volume /var/lib/redis:/data --label service=\"app-redis\" --label cache=\"true\" redis:latest",
|
||||
"docker run --name app-redis --detach --restart unless-stopped --log-opt max-size=10m --publish 6379:6379 -e SOMETHING=\"else\" --volume /var/lib/redis:/data --label service=\"app-redis\" --label cache=\"true\" redis:latest",
|
||||
new_command(:redis).run.join(" ")
|
||||
end
|
||||
|
||||
test "run with logging config" do
|
||||
@config[:logging] = { "driver" => "local", "options" => { "max-size" => "10m", "max-file" => "3" } }
|
||||
|
||||
assert_equal \
|
||||
"docker run --name app-mysql --detach --restart unless-stopped --publish 3306:3306 --log-driver local --log-opt max-size=\"10m\" --log-opt max-file=\"3\" -e MYSQL_ROOT_PASSWORD=\"secret123\" -e MYSQL_ROOT_HOST=\"%\" --label service=\"app-mysql\" mysql:8.0",
|
||||
new_command(:mysql).run.join(" ")
|
||||
|
||||
assert_equal \
|
||||
"docker run --name app-redis --detach --restart unless-stopped --publish 6379:6379 --log-driver local --log-opt max-size=\"10m\" --log-opt max-file=\"3\" -e SOMETHING=\"else\" --volume /var/lib/redis:/data --label service=\"app-redis\" --label cache=\"true\" redis:latest",
|
||||
new_command(:redis).run.join(" ")
|
||||
"docker run --name app-busybox --detach --restart unless-stopped --log-opt max-size=10m --label service=\"app-busybox\" busybox:latest",
|
||||
new_command(:busybox).run.join(" ")
|
||||
end
|
||||
|
||||
test "start" do
|
||||
@@ -86,7 +82,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
||||
|
||||
test "execute in new container" do
|
||||
assert_equal \
|
||||
"docker run --rm -e MYSQL_ROOT_PASSWORD=\"secret123\" -e MYSQL_ROOT_HOST=\"%\" mysql:8.0 mysql -u root",
|
||||
"docker run --rm -e MYSQL_ROOT_PASSWORD=\"secret123\" -e MYSQL_ROOT_HOST=\"%\" private.registry/mysql:8.0 mysql -u root",
|
||||
new_command(:mysql).execute_in_new_container("mysql", "-u", "root").join(" ")
|
||||
end
|
||||
|
||||
@@ -97,8 +93,8 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "execute in new container over ssh" do
|
||||
new_command(:mysql).stub(:run_over_ssh, ->(cmd) { cmd.join(" ") }) do
|
||||
assert_match %r|docker run -it --rm -e MYSQL_ROOT_PASSWORD=\"secret123\" -e MYSQL_ROOT_HOST=\"%\" mysql:8.0 mysql -u root|,
|
||||
@mysql.stub(:run_over_ssh, ->(cmd) { cmd.join(" ") }) do
|
||||
assert_match %r|docker run -it --rm -e MYSQL_ROOT_PASSWORD=\"secret123\" -e MYSQL_ROOT_HOST=\"%\" private.registry/mysql:8.0 mysql -u root|,
|
||||
new_command(:mysql).execute_in_new_container_over_ssh("mysql", "-u", "root")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,6 +19,39 @@ class CommandsTraefikTest < ActiveSupport::TestCase
|
||||
new_command.run.join(" ")
|
||||
end
|
||||
|
||||
test "run with ports configured" do
|
||||
assert_equal \
|
||||
"docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||
new_command.run.join(" ")
|
||||
|
||||
@config[:traefik]["options"] = {"publish" => %w[9000:9000 9001:9001]}
|
||||
assert_equal \
|
||||
"docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --publish \"9000:9000\" --publish \"9001:9001\" traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||
new_command.run.join(" ")
|
||||
end
|
||||
|
||||
test "run with volumes configured" do
|
||||
assert_equal \
|
||||
"docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||
new_command.run.join(" ")
|
||||
|
||||
@config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json] }
|
||||
assert_equal \
|
||||
"docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||
new_command.run.join(" ")
|
||||
end
|
||||
|
||||
test "run with several options configured" do
|
||||
assert_equal \
|
||||
"docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||
new_command.run.join(" ")
|
||||
|
||||
@config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json], "publish" => %w[8080:8080], "memory" => "512m"}
|
||||
assert_equal \
|
||||
"docker run --name traefik --detach --restart unless-stopped --log-opt max-size=10m --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" --publish \"8080:8080\" --memory \"512m\" traefik --providers.docker --log.level=DEBUG --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||
new_command.run.join(" ")
|
||||
end
|
||||
|
||||
test "run without configuration" do
|
||||
@config.delete(:traefik)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ require "test_helper"
|
||||
class ConfigurationTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
ENV["RAILS_MASTER_KEY"] = "456"
|
||||
ENV["VERSION"] = "missing"
|
||||
|
||||
@deploy = {
|
||||
service: "app", image: "dhh/app",
|
||||
@@ -22,17 +23,23 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
teardown do
|
||||
ENV["RAILS_MASTER_KEY"] = nil
|
||||
ENV.delete("RAILS_MASTER_KEY")
|
||||
ENV.delete("VERSION")
|
||||
end
|
||||
|
||||
test "ensure valid keys" do
|
||||
assert_raise(ArgumentError) do
|
||||
Mrsk::Configuration.new(@deploy.tap { _1.delete(:service) })
|
||||
Mrsk::Configuration.new(@deploy.tap { _1.delete(:image) })
|
||||
Mrsk::Configuration.new(@deploy.tap { _1.delete(:registry) })
|
||||
%i[ service image registry ].each do |key|
|
||||
test "#{key} config required" do
|
||||
assert_raise(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.tap { _1.delete key }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Mrsk::Configuration.new(@deploy.tap { _1[:registry].delete("username") })
|
||||
Mrsk::Configuration.new(@deploy.tap { _1[:registry].delete("password") })
|
||||
%w[ username password ].each do |key|
|
||||
test "registry #{key} required" do
|
||||
assert_raise(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.tap { _1[:registry].delete key }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -67,8 +74,20 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "version" do
|
||||
assert_equal "missing", @config.version
|
||||
assert_equal "123", Mrsk::Configuration.new(@deploy, version: "123").version
|
||||
ENV.delete("VERSION")
|
||||
|
||||
@config.expects(:system).with("git rev-parse").returns(nil)
|
||||
error = assert_raises(RuntimeError) { @config.version}
|
||||
assert_match /no git repository found/, error.message
|
||||
|
||||
@config.expects(:current_commit_hash).returns("git-version")
|
||||
assert_equal "git-version", @config.version
|
||||
|
||||
ENV["VERSION"] = "env-version"
|
||||
assert_equal "env-version", @config.version
|
||||
|
||||
@config.version = "arg-version"
|
||||
assert_equal "arg-version", @config.version
|
||||
end
|
||||
|
||||
test "repository" do
|
||||
@@ -135,6 +154,39 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
|
||||
test "valid config" do
|
||||
assert @config.valid?
|
||||
assert @config_with_roles.valid?
|
||||
end
|
||||
|
||||
test "hosts required for all roles" do
|
||||
# Empty server list for implied web role
|
||||
assert_raises(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.merge(servers: [])
|
||||
end
|
||||
|
||||
# Empty server list
|
||||
assert_raises(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.merge(servers: { "web" => [] })
|
||||
end
|
||||
|
||||
# Missing hosts key
|
||||
assert_raises(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.merge(servers: { "web" => {} })
|
||||
end
|
||||
|
||||
# Empty hosts list
|
||||
assert_raises(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.merge(servers: { "web" => { "hosts" => [] } })
|
||||
end
|
||||
|
||||
# Nil hosts
|
||||
assert_raises(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.merge(servers: { "web" => { "hosts" => nil } })
|
||||
end
|
||||
|
||||
# One role with hosts, one without
|
||||
assert_raises(ArgumentError) do
|
||||
Mrsk::Configuration.new @deploy.merge(servers: { "web" => %w[ web ], "workers" => { "hosts" => %w[ ] } })
|
||||
end
|
||||
end
|
||||
|
||||
test "ssh options" do
|
||||
@@ -163,17 +215,17 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "erb evaluation of yml config" do
|
||||
config = Mrsk::Configuration.create_from Pathname.new(File.expand_path("fixtures/deploy.erb.yml", __dir__))
|
||||
config = Mrsk::Configuration.create_from config_file: Pathname.new(File.expand_path("fixtures/deploy.erb.yml", __dir__))
|
||||
assert_equal "my-user", config.registry["username"]
|
||||
end
|
||||
|
||||
test "destination yml config merge" do
|
||||
dest_config_file = Pathname.new(File.expand_path("fixtures/deploy_for_dest.yml", __dir__))
|
||||
|
||||
config = Mrsk::Configuration.create_from dest_config_file, destination: "world"
|
||||
config = Mrsk::Configuration.create_from config_file: dest_config_file, destination: "world"
|
||||
assert_equal "1.1.1.1", config.all_hosts.first
|
||||
|
||||
config = Mrsk::Configuration.create_from dest_config_file, destination: "mars"
|
||||
config = Mrsk::Configuration.create_from config_file: dest_config_file, destination: "mars"
|
||||
assert_equal "1.1.1.3", config.all_hosts.first
|
||||
end
|
||||
|
||||
@@ -181,7 +233,7 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
dest_config_file = Pathname.new(File.expand_path("fixtures/deploy_for_dest.yml", __dir__))
|
||||
|
||||
assert_raises(RuntimeError) do
|
||||
config = Mrsk::Configuration.create_from dest_config_file, destination: "missing"
|
||||
config = Mrsk::Configuration.create_from config_file: dest_config_file, destination: "missing"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
5
test/fixtures/deploy_with_roles.yml
vendored
5
test/fixtures/deploy_with_roles.yml
vendored
@@ -5,8 +5,9 @@ servers:
|
||||
- 1.1.1.1
|
||||
- 1.1.1.2
|
||||
workers:
|
||||
- 1.1.1.3
|
||||
- 1.1.1.4
|
||||
hosts:
|
||||
- 1.1.1.3
|
||||
- 1.1.1.4
|
||||
env:
|
||||
REDIS_URL: redis://x/y
|
||||
registry:
|
||||
|
||||
Reference in New Issue
Block a user