* main: Wording Remove accessory images using tags rather than labels Update readme to point to ghcr.io/mrsked/mrsk Validate that all roles have hosts Commander needn't accumulate configuration Pull latest image tag, so we can identity it Default to deploying the config version Remove unneeded Dockerfile.dind, update Readme add D-in-D dockerfile, update Readme
239 lines
7.7 KiB
Ruby
239 lines
7.7 KiB
Ruby
require "test_helper"
|
|
|
|
class ConfigurationTest < ActiveSupport::TestCase
|
|
setup do
|
|
ENV["RAILS_MASTER_KEY"] = "456"
|
|
ENV["VERSION"] = "missing"
|
|
|
|
@deploy = {
|
|
service: "app", image: "dhh/app",
|
|
registry: { "username" => "dhh", "password" => "secret" },
|
|
env: { "REDIS_URL" => "redis://x/y" },
|
|
servers: [ "1.1.1.1", "1.1.1.2" ],
|
|
volumes: ["/local/path:/container/path"]
|
|
}
|
|
|
|
@config = Mrsk::Configuration.new(@deploy)
|
|
|
|
@deploy_with_roles = @deploy.dup.merge({
|
|
servers: { "web" => [ "1.1.1.1", "1.1.1.2" ], "workers" => { "hosts" => [ "1.1.1.1", "1.1.1.3" ] } } })
|
|
|
|
@config_with_roles = Mrsk::Configuration.new(@deploy_with_roles)
|
|
end
|
|
|
|
teardown do
|
|
ENV.delete("RAILS_MASTER_KEY")
|
|
ENV.delete("VERSION")
|
|
end
|
|
|
|
%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
|
|
|
|
%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
|
|
|
|
test "roles" do
|
|
assert_equal %w[ web ], @config.roles.collect(&:name)
|
|
assert_equal %w[ web workers ], @config_with_roles.roles.collect(&:name)
|
|
end
|
|
|
|
test "role" do
|
|
assert_equal "web", @config.role(:web).name
|
|
assert_equal "workers", @config_with_roles.role(:workers).name
|
|
assert_nil @config.role(:missing)
|
|
end
|
|
|
|
test "all hosts" do
|
|
assert_equal [ "1.1.1.1", "1.1.1.2"], @config.all_hosts
|
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3" ], @config_with_roles.all_hosts
|
|
end
|
|
|
|
test "primary web host" do
|
|
assert_equal "1.1.1.1", @config.primary_web_host
|
|
assert_equal "1.1.1.1", @config_with_roles.primary_web_host
|
|
end
|
|
|
|
test "traefik hosts" do
|
|
assert_equal [ "1.1.1.1", "1.1.1.2" ], @config_with_roles.traefik_hosts
|
|
|
|
@deploy_with_roles[:servers]["workers"]["traefik"] = true
|
|
config = Mrsk::Configuration.new(@deploy_with_roles)
|
|
|
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3" ], config.traefik_hosts
|
|
end
|
|
|
|
test "version" do
|
|
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
|
|
assert_equal "dhh/app", @config.repository
|
|
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c[:registry].merge!({ "server" => "ghcr.io" }) })
|
|
assert_equal "ghcr.io/dhh/app", config.repository
|
|
end
|
|
|
|
test "absolute image" do
|
|
assert_equal "dhh/app:missing", @config.absolute_image
|
|
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c[:registry].merge!({ "server" => "ghcr.io" }) })
|
|
assert_equal "ghcr.io/dhh/app:missing", config.absolute_image
|
|
end
|
|
|
|
test "service with version" do
|
|
assert_equal "app-missing", @config.service_with_version
|
|
end
|
|
|
|
test "env args" do
|
|
assert_equal [ "-e", "REDIS_URL=\"redis://x/y\"" ], @config.env_args
|
|
end
|
|
|
|
test "env args with clear and secrets" do
|
|
ENV["PASSWORD"] = "secret123"
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({
|
|
env: { "clear" => { "PORT" => "3000" }, "secret" => [ "PASSWORD" ] }
|
|
}) })
|
|
|
|
assert_equal [ "-e", "PASSWORD=\"secret123\"", "-e", "PORT=\"3000\"" ], config.env_args
|
|
assert config.env_args[1].is_a?(SSHKit::Redaction)
|
|
ensure
|
|
ENV["PASSWORD"] = nil
|
|
end
|
|
|
|
test "env args with only clear" do
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({
|
|
env: { "clear" => { "PORT" => "3000" } }
|
|
}) })
|
|
|
|
assert_equal [ "-e", "PORT=\"3000\"" ], config.env_args
|
|
end
|
|
|
|
test "env args with only secrets" do
|
|
ENV["PASSWORD"] = "secret123"
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({
|
|
env: { "secret" => [ "PASSWORD" ] }
|
|
}) })
|
|
|
|
assert_equal [ "-e", "PASSWORD=\"secret123\"" ], config.env_args
|
|
assert config.env_args[1].is_a?(SSHKit::Redaction)
|
|
ensure
|
|
ENV["PASSWORD"] = nil
|
|
end
|
|
|
|
test "env args with missing secret" do
|
|
assert_raises(KeyError) do
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({
|
|
env: { "secret" => [ "PASSWORD" ] }
|
|
}) })
|
|
end
|
|
end
|
|
|
|
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
|
|
assert_equal "root", @config.ssh_options[:user]
|
|
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "user" => "app" }) })
|
|
assert_equal "app", @config.ssh_options[:user]
|
|
end
|
|
|
|
test "ssh options with proxy host" do
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "proxy" => "1.2.3.4" }) })
|
|
assert_equal "root@1.2.3.4", @config.ssh_options[:proxy].jump_proxies
|
|
end
|
|
|
|
test "ssh options with proxy host and user" do
|
|
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "proxy" => "app@1.2.3.4" }) })
|
|
assert_equal "app@1.2.3.4", @config.ssh_options[:proxy].jump_proxies
|
|
end
|
|
|
|
test "volume_args" do
|
|
assert_equal ["--volume", "/local/path:/container/path"], @config.volume_args
|
|
end
|
|
|
|
test "erb evaluation of yml config" do
|
|
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 config_file: dest_config_file, destination: "world"
|
|
assert_equal "1.1.1.1", config.all_hosts.first
|
|
|
|
config = Mrsk::Configuration.create_from config_file: dest_config_file, destination: "mars"
|
|
assert_equal "1.1.1.3", config.all_hosts.first
|
|
end
|
|
|
|
test "destination yml config file missing" do
|
|
dest_config_file = Pathname.new(File.expand_path("fixtures/deploy_for_dest.yml", __dir__))
|
|
|
|
assert_raises(RuntimeError) do
|
|
config = Mrsk::Configuration.create_from config_file: dest_config_file, destination: "missing"
|
|
end
|
|
end
|
|
|
|
test "to_h" do
|
|
assert_equal({ :roles=>["web"], :hosts=>["1.1.1.1", "1.1.1.2"], :primary_host=>"1.1.1.1", :version=>"missing", :repository=>"dhh/app", :absolute_image=>"dhh/app:missing", :service_with_version=>"app-missing", :env_args=>["-e", "REDIS_URL=\"redis://x/y\""], :ssh_options=>{:user=>"root", :auth_methods=>["publickey"]}, :volume_args=>["--volume", "/local/path:/container/path"], :healthcheck=>{"path"=>"/up", "port"=>3000 }}, @config.to_h)
|
|
end
|
|
end
|