Host specific env with tags

Allow hosts to be tagged so we can have host specific env variables.

We might want host specific env variables for things like datacenter
specific tags or testing GC settings on a specific host.

Right now you either need to set up a separate role, or have the app
be host aware.

Now you can define tag env variables and assign those to hosts.

For example:
```
servers:
  - 1.1.1.1
  - 1.1.1.2: tag1
  - 1.1.1.2: tag2
  - 1.1.1.3: [ tag1, tag2 ]
env_tags:
  tag1:
    ENV1: value1
  tag2:
    ENV2: value2
```

The tag env supports the full env format, allowing you to set secret and
clear values.
This commit is contained in:
Donal McBreen
2024-05-02 10:36:15 +01:00
parent 3c8428504d
commit 6d062ce271
21 changed files with 334 additions and 69 deletions

102
test/configuration/env/tags_test.rb vendored Normal file
View File

@@ -0,0 +1,102 @@
require "test_helper"
class ConfigurationEnvTagsTest < ActiveSupport::TestCase
setup do
@deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => "odd" }, { "1.1.1.2" => "even" }, { "1.1.1.3" => [ "odd", "three" ] } ],
env: { "REDIS_URL" => "redis://x/y", "THREE" => "false" },
env_tags: {
"odd" => { "TYPE" => "odd" },
"even" => { "TYPE" => "even" },
"three" => { "THREE" => "true" }
}
}
@config = Kamal::Configuration.new(@deploy)
@deploy_with_roles = @deploy.dup.merge({
servers: {
"web" => [ { "1.1.1.1" => "odd" }, "1.1.1.2" ],
"workers" => {
"hosts" => [ { "1.1.1.3" => [ "odd", "oddjob" ] }, "1.1.1.4" ],
"cmd" => "bin/jobs",
"env" => {
"REDIS_URL" => "redis://a/b",
"WEB_CONCURRENCY" => 4
}
}
},
env_tags: {
"odd" => { "TYPE" => "odd" },
"oddjob" => { "TYPE" => "oddjob" }
}
})
@config_with_roles = Kamal::Configuration.new(@deploy_with_roles)
end
test "tags" do
assert_equal 3, @config.env_tags.size
assert_equal %w[ odd even three ], @config.env_tags.map(&:name)
assert_equal({ "TYPE" => "odd" }, @config.env_tag("odd").env.clear)
assert_equal({ "TYPE" => "even" }, @config.env_tag("even").env.clear)
assert_equal({ "THREE" => "true" }, @config.env_tag("three").env.clear)
end
test "tags with roles" do
assert_equal 2, @config_with_roles.env_tags.size
assert_equal %w[ odd oddjob ], @config_with_roles.env_tags.map(&:name)
assert_equal({ "TYPE" => "odd" }, @config_with_roles.env_tag("odd").env.clear)
assert_equal({ "TYPE" => "oddjob" }, @config_with_roles.env_tag("oddjob").env.clear)
end
test "tag overrides env" do
assert_equal "false", @config.role("web").env("1.1.1.1").clear["THREE"]
assert_equal "true", @config.role("web").env("1.1.1.3").clear["THREE"]
end
test "later tag wins" do
deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => [ "first", "second" ] } ],
env_tags: {
"first" => { "TYPE" => "first" },
"second" => { "TYPE" => "second" }
}
}
config = Kamal::Configuration.new(deploy)
assert_equal "second", config.role("web").env("1.1.1.1").clear["TYPE"]
end
test "tag secret env" do
ENV["PASSWORD"] = "hello"
deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => "secrets" } ],
env_tags: {
"secrets" => { "secret" => [ "PASSWORD" ] }
}
}
config = Kamal::Configuration.new(deploy)
assert_equal "hello", config.role("web").env("1.1.1.1").secrets["PASSWORD"]
ensure
ENV.delete "PASSWORD"
end
test "tag clear env" do
deploy = {
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
servers: [ { "1.1.1.1" => "clearly" } ],
env_tags: {
"clearly" => { "clear" => { "FOO" => "bar" } }
}
}
config = Kamal::Configuration.new(deploy)
assert_equal "bar", config.role("web").env("1.1.1.1").clear["FOO"]
end
end