Rename roles

Allow roles to be renamed without having to manually stop the old
containers.

If you have config like:

```
servers:
  jobs:
    hosts:
      - vm3
```

And you want to rename `jobs` to `workers`, you can do:

```
servers:
  workers:
    previously:
      - jobs
    hosts:
      - vm3
```

And the deployment will take care of stopping the old "jobs" containers.

Once deployed you can remove the `previously` key.
This commit is contained in:
Donal McBreen
2024-03-26 13:48:04 +00:00
parent d475e88dbe
commit 9a5880208a
9 changed files with 137 additions and 28 deletions

View File

@@ -53,7 +53,8 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
test "custom labels via role specialization" do
@deploy_with_roles[:labels] = { "my.custom.label" => "50" }
@deploy_with_roles[:servers]["workers"]["labels"] = { "my.custom.label" => "70" }
assert_equal "70", @config_with_roles.role(:workers).labels["my.custom.label"]
config_with_roles = Kamal::Configuration.new(@deploy_with_roles)
assert_equal "70", config_with_roles.role(:workers).labels["my.custom.label"]
end
test "overwriting default traefik label" do
@@ -109,6 +110,8 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
]
}
config_with_roles = Kamal::Configuration.new(@deploy_with_roles)
ENV["REDIS_PASSWORD"] = "secret456"
ENV["DB_PASSWORD"] = "secret&\"123"
@@ -117,8 +120,8 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
DB_PASSWORD=secret&\"123
ENV
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env.secrets_io.string
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args
assert_equal expected_secrets_file, config_with_roles.role(:workers).env.secrets_io.string
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], config_with_roles.role(:workers).env_args
ensure
ENV["REDIS_PASSWORD"] = nil
ENV["DB_PASSWORD"] = nil
@@ -135,14 +138,16 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
]
}
config_with_roles = Kamal::Configuration.new(@deploy_with_roles)
ENV["DB_PASSWORD"] = "secret123"
expected_secrets_file = <<~ENV
DB_PASSWORD=secret123
ENV
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env.secrets_io.string
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args
assert_equal expected_secrets_file, config_with_roles.role(:workers).env.secrets_io.string
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], config_with_roles.role(:workers).env_args
ensure
ENV["DB_PASSWORD"] = nil
end
@@ -185,14 +190,16 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
}
}
config_with_roles = Kamal::Configuration.new(@deploy_with_roles)
ENV["REDIS_PASSWORD"] = "secret456"
expected_secrets_file = <<~ENV
REDIS_PASSWORD=secret456
ENV
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env.secrets_io.string
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://c/d\"" ], @config_with_roles.role(:workers).env_args
assert_equal expected_secrets_file, config_with_roles.role(:workers).env.secrets_io.string
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://c/d\"" ], config_with_roles.role(:workers).env_args
ensure
ENV["REDIS_PASSWORD"] = nil
end

View File

@@ -0,0 +1,42 @@
service: app
image: app
primary_role: app
servers:
app:
previously:
- web
hosts:
- vm1
- vm2
jobs:
previously:
- workers
hosts:
- vm3
cmd: sleep infinity
asset_path: /usr/share/nginx/html/versions
registry:
server: registry:4443
username: root
password: root
builder:
multiarch: false
args:
COMMIT_SHA: <%= `git rev-parse HEAD` %>
healthcheck:
cmd: wget -qO- http://localhost > /dev/null || exit 1
traefik:
args:
accesslog: true
accesslog.format: json
image: registry:4443/traefik:v2.10
accessories:
busybox:
service: custom-busybox
image: registry:4443/busybox:1.36.0
cmd: sh -c 'echo "Starting busybox..."; trap exit term; while true; do sleep 1; done'
roles:
- app
stop_wait_time: 1

View File

@@ -0,0 +1,3 @@
#!/bin/bash
cd $1 && cp -f config/deploy_renamed_roles.yml config/deploy.yml && git commit -am 'Rename roles'

View File

@@ -131,4 +131,16 @@ class IntegrationTest < ActiveSupport::TestCase
puts "Tried to get the response code again and got #{app_response.code}"
end
end
def assert_container_running(host:, name:)
assert container_running?(host: host, name: name)
end
def assert_container_not_running(host:, name:)
assert_not container_running?(host: host, name: name)
end
def container_running?(host:, name:)
docker_compose("exec #{host} docker ps --filter=name=#{name} | tail -n+2", capture: true).strip.present?
end
end

View File

@@ -92,6 +92,33 @@ class MainTest < IntegrationTest
assert_no_images_or_containers
end
test "rename roles" do
@app = "app_with_roles"
kamal :envify
kamal :deploy
first_version = latest_app_version
assert_container_running host: :vm1, name: "app-web-#{first_version}"
assert_container_running host: :vm2, name: "app-web-#{first_version}"
assert_container_running host: :vm3, name: "app-workers-#{first_version}"
rename_roles
kamal :envify
kamal :deploy
second_version = latest_app_version
assert_container_running host: :vm1, name: "app-app-#{second_version}"
assert_container_running host: :vm2, name: "app-app-#{second_version}"
assert_container_running host: :vm3, name: "app-jobs-#{second_version}"
assert_container_not_running host: :vm1, name: "app-web-#{first_version}"
assert_container_not_running host: :vm2, name: "app-web-#{first_version}"
assert_container_not_running host: :vm3, name: "app-workers-#{first_version}"
end
private
def assert_local_env_file(contents)
assert_equal contents, deployer_exec("cat .env", capture: true)
@@ -139,7 +166,7 @@ class MainTest < IntegrationTest
assert vm1_container_ids.any?
end
def assert_container_running(host:, name:)
assert docker_compose("exec #{host} docker ps --filter=name=#{name} -q", capture: true).strip.present?
def rename_roles
deployer_exec "./rename_roles.sh #{@app}", workdir: "/"
end
end