diff --git a/README.md b/README.md index 9cd8e17a..d9de0567 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,14 @@ If the referenced secret ENVs are missing, the configuration will be halted with Note: Marking an ENV as secret currently only redacts its value in the output for MRSK. The ENV is still injected in the clear into the container at runtime. +### Using volumes + +You can add custom volumes into the app containers using `volumes`: + +```yaml +volumes: + - "/local/path:/container/path" +``` ### Using different roles for servers diff --git a/lib/mrsk/commands/app.rb b/lib/mrsk/commands/app.rb index 245d0e33..fa5e02af 100644 --- a/lib/mrsk/commands/app.rb +++ b/lib/mrsk/commands/app.rb @@ -10,6 +10,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base "--name", config.service_with_version, *rails_master_key_arg, *role.env_args, + *config.volume_args, *role.label_args, config.absolute_image, role.cmd @@ -43,6 +44,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base ("-it" if interactive), *rails_master_key_arg, *config.env_args, + *config.volume_args, config.service_with_version, *command end @@ -53,6 +55,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base "--rm", *rails_master_key_arg, *config.env_args, + *config.volume_args, config.absolute_image, *command end diff --git a/lib/mrsk/configuration.rb b/lib/mrsk/configuration.rb index f2f628b2..498700a8 100644 --- a/lib/mrsk/configuration.rb +++ b/lib/mrsk/configuration.rb @@ -98,6 +98,14 @@ class Mrsk::Configuration end end + def volume_args + if config.volumes.present? + config.volumes.map { |volume| "--volume #{volume}" } + else + [] + end + end + def ssh_user raw_config.ssh_user || "root" end @@ -120,8 +128,10 @@ class Mrsk::Configuration absolute_image: absolute_image, service_with_version: service_with_version, env_args: env_args, + volume_args: volume_args, ssh_options: ssh_options, builder: raw_config.builder + builder: config.builder }.compact end diff --git a/test/commands/app_test.rb b/test/commands/app_test.rb index 5297b6fa..15f72d66 100644 --- a/test/commands/app_test.rb +++ b/test/commands/app_test.rb @@ -15,6 +15,13 @@ class CommandsAppTest < ActiveSupport::TestCase [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-missing", "-e", "RAILS_MASTER_KEY=456", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:missing"], @app.run end + test "run with volumes" do + @config[:volumes] = ["/local/path:/container/path" ] + + assert_equal \ + [:docker, :run, "-d", "--restart unless-stopped", "--name", "app-missing", "-e", "RAILS_MASTER_KEY=456", "--volume /local/path:/container/path", "--label", "service=app", "--label", "role=web", "--label", "traefik.http.routers.app.rule='PathPrefix(`/`)'", "--label", "traefik.http.services.app.loadbalancer.healthcheck.path=/up", "--label", "traefik.http.services.app.loadbalancer.healthcheck.interval=1s", "--label", "traefik.http.middlewares.app.retry.attempts=3", "--label", "traefik.http.middlewares.app.retry.initialinterval=500ms", "dhh/app:missing"], @app.run + end + test "run with" do assert_equal \ [ :docker, :run, "--rm", "-e", "RAILS_MASTER_KEY=456", "dhh/app:missing", "bin/rails", "db:setup" ], diff --git a/test/configuration_test.rb b/test/configuration_test.rb index eff0ddac..3870e460 100644 --- a/test/configuration_test.rb +++ b/test/configuration_test.rb @@ -9,7 +9,8 @@ class ConfigurationTest < ActiveSupport::TestCase 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" ] + servers: [ "1.1.1.1", "1.1.1.2" ], + volumes: ["/local/path:/container/path"] } @config = Mrsk::Configuration.new(@deploy) @@ -84,15 +85,14 @@ class ConfigurationTest < ActiveSupport::TestCase 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" ] } + 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 @@ -103,8 +103,8 @@ class ConfigurationTest < ActiveSupport::TestCase test "env args with only secrets" do ENV["PASSWORD"] = "secret123" - config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ - env: { "secret" => [ "PASSWORD" ] } + config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ + env: { "secret" => [ "PASSWORD" ] } }) }) assert_equal [ "-e", "PASSWORD=secret123" ], config.env_args @@ -114,8 +114,8 @@ class ConfigurationTest < ActiveSupport::TestCase end test "env args with missing secret" do - config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ - env: { "secret" => [ "PASSWORD" ] } + config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!({ + env: { "secret" => [ "PASSWORD" ] } }) }) assert_raises(KeyError) do @@ -134,6 +134,9 @@ class ConfigurationTest < ActiveSupport::TestCase assert_equal "456", @config.master_key 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 Pathname.new(File.expand_path("fixtures/deploy.erb.yml", __dir__)) @@ -159,6 +162,6 @@ class ConfigurationTest < ActiveSupport::TestCase 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"]} }, @config.to_h) + 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"] }, @config.to_h) end end