Remove the envify command

Instead of using `kamal envify` to generate the .env file, we now assume
that it will be in place for us.

Options in place of `kamal envify`:
1. Pre-generate the .env file
2. Create the env file in the `.pre-init` hook
3. Log into a secret store/check you are logged in in the pre-init hook
   Then use .dotenv command and variable substitution to interpolate the
   secrets.
This commit is contained in:
Donal McBreen
2024-07-30 17:26:45 +01:00
parent cbb4c87035
commit d2f57b1889
11 changed files with 8 additions and 93 deletions

View File

@@ -10,7 +10,6 @@ class Kamal::Cli::Main < Kamal::Cli::Base
invoke "kamal:cli:server:bootstrap", [], invoke_options invoke "kamal:cli:server:bootstrap", [], invoke_options
say "Evaluate and push env files...", :magenta say "Evaluate and push env files...", :magenta
invoke "kamal:cli:main:envify", [], invoke_options
invoke "kamal:cli:env:push", [], invoke_options invoke "kamal:cli:env:push", [], invoke_options
invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options
@@ -179,31 +178,6 @@ class Kamal::Cli::Main < Kamal::Cli::Base
end end
end end
desc "envify", "Create .kamal/.env by evaluating .kamal/.env.erb (or .kamal/.env.staging.erb -> .kamal/.env.staging when using -d staging)"
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip .env file push"
def envify
if destination = options[:destination]
env_template_path = ".kamal/.env.#{destination}.erb"
env_path = ".kamal/.env.#{destination}"
else
env_template_path = ".kamal/.env.erb"
env_path = ".kamal/.env"
end
if Pathname.new(File.expand_path(env_template_path)).exist?
# Ensure existing env doesn't pollute template evaluation
content = with_original_env { ERB.new(File.read(env_template_path), trim_mode: "-").result }
File.write(env_path, content, perm: 0600)
unless options[:skip_push]
reload_env
invoke "kamal:cli:env:push", options
end
else
puts "Skipping envify (no #{env_template_path} exist)"
end
end
desc "remove", "Remove Traefik, app, accessories, and registry session from servers" desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question" option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
def remove def remove

View File

@@ -24,14 +24,14 @@ env:
# KAMAL_REGISTRY_PASSWORD=pw # KAMAL_REGISTRY_PASSWORD=pw
# DB_PASSWORD=secret123 # DB_PASSWORD=secret123
# ``` # ```
# See https://kamal-deploy.org/docs/commands/envify/ for how to use generated .env files. # See https://kamal-deploy.org/docs/commands/env/ for how to use generated .env files.
# #
# To pass the secrets you should list them under the `secret` key. When you do this the # To pass the secrets you should list them under the `secret` key. When you do this the
# other variables need to be moved under the `clear` key. # other variables need to be moved under the `clear` key.
# #
# Unlike clear valies, secrets are not passed directly to the container, # Unlike clear valies, secrets are not passed directly to the container,
# but are stored in an env file on the host # but are stored in an env file on the host
# The file is not updated when deploying, only when running `kamal envify` or `kamal env push`. # The file is not updated when deploying, only when running `kamal env push`.
env: env:
clear: clear:
DB_USER: app DB_USER: app

View File

@@ -8,7 +8,6 @@ class CliMainTest < CliTestCase
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false }
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:server:bootstrap", [], invoke_options) Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:server:bootstrap", [], invoke_options)
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:main:envify", [], invoke_options)
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push", [], invoke_options) Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push", [], invoke_options)
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:boot", [ "all" ], invoke_options) Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:boot", [ "all" ], invoke_options)
Kamal::Cli::Main.any_instance.expects(:deploy) Kamal::Cli::Main.any_instance.expects(:deploy)
@@ -24,7 +23,6 @@ class CliMainTest < CliTestCase
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:server:bootstrap", [], invoke_options) Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:server:bootstrap", [], invoke_options)
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push", [], invoke_options) Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push", [], invoke_options)
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:main:envify", [], invoke_options)
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:boot", [ "all" ], invoke_options) Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:boot", [ "all" ], invoke_options)
# deploy # deploy
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: true)) Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: true))
@@ -62,7 +60,7 @@ class CliMainTest < CliTestCase
hook_variables = { version: 999, service_version: "app@999", hosts: "1.1.1.1,1.1.1.2", command: "deploy" } hook_variables = { version: 999, service_version: "app@999", hosts: "1.1.1.1,1.1.1.2", command: "deploy" }
run_command("deploy", "--verbose").tap do |output| run_command("deploy", "--verbose").tap do |output|
assert_match "Running /usr/bin/env .kamal/hooks/pre-init", output assert_match "Running the pre-init hook...", output
assert_hook_ran "pre-connect", output, **hook_variables assert_hook_ran "pre-connect", output, **hook_variables
assert_match /Log into image registry/, output assert_match /Log into image registry/, output
assert_match /Build and push app image/, output assert_match /Build and push app image/, output
@@ -447,50 +445,6 @@ class CliMainTest < CliTestCase
end end
end end
test "envify" do
with_test_dotenv(".env.erb": "HELLO=<%= 'world' %>") do
run_command("envify")
assert_equal("HELLO=world", File.read(".kamal/.env"))
end
end
test "envify with blank line trimming" do
file = <<~EOF
HELLO=<%= 'world' %>
<% if true -%>
KEY=value
<% end -%>
EOF
with_test_dotenv(".env.erb": file) do
run_command("envify")
assert_equal("HELLO=world\nKEY=value\n", File.read(".kamal/.env"))
end
end
test "envify with destination" do
with_test_dotenv(".env.world.erb": "HELLO=<%= 'world' %>") do
run_command("envify", "-d", "world", config_file: "deploy_for_dest")
assert_equal "HELLO=world", File.read(".kamal/.env.world")
end
end
test "envify with skip_push" do
Pathname.any_instance.expects(:exist?).returns(true).times(2)
File.expects(:read).with(".kamal/.env.erb").returns("HELLO=<%= 'world' %>")
File.expects(:write).with(".kamal/.env", "HELLO=world", perm: 0600)
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push").never
run_command("envify", "--skip-push")
end
test "envify with clean env" do
with_test_dotenv(".env": "HELLO=already", ".env.erb": "HELLO=<%= ENV.fetch 'HELLO', 'never' %>") do
run_command("envify", "--skip-push")
assert_equal "HELLO=never", File.read(".kamal/.env")
end
end
test "remove with confirmation" do test "remove with confirmation" do
run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output| run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output|
assert_match /docker container stop traefik/, output assert_match /docker container stop traefik/, output

View File

@@ -2,8 +2,6 @@ require_relative "integration_test"
class AccessoryTest < IntegrationTest class AccessoryTest < IntegrationTest
test "boot, stop, start, restart, logs, remove" do test "boot, stop, start, restart, logs, remove" do
kamal :envify
kamal :accessory, :boot, :busybox kamal :accessory, :boot, :busybox
assert_accessory_running :busybox assert_accessory_running :busybox

View File

@@ -2,8 +2,6 @@ require_relative "integration_test"
class AppTest < IntegrationTest class AppTest < IntegrationTest
test "stop, start, boot, logs, images, containers, exec, remove" do test "stop, start, boot, logs, images, containers, exec, remove" do
kamal :envify
kamal :deploy kamal :deploy
assert_app_is_up assert_app_is_up

View File

@@ -4,8 +4,6 @@ class BrokenDeployTest < IntegrationTest
test "deploying a bad image" do test "deploying a bad image" do
@app = "app_with_roles" @app = "app_with_roles"
kamal :envify
first_version = latest_app_version first_version = latest_app_version
kamal :deploy kamal :deploy

View File

@@ -1,2 +0,0 @@
SECRET_TOKEN='1234 with "中文"'
SECRET_TAG='TAGME'

View File

@@ -1 +0,0 @@
SECRET_TOKEN='1234 with "中文"'

View File

@@ -2,8 +2,6 @@ require_relative "integration_test"
class LockTest < IntegrationTest class LockTest < IntegrationTest
test "acquire, release, status" do test "acquire, release, status" do
kamal :envify
kamal :lock, :acquire, "-m 'Integration Tests'" kamal :lock, :acquire, "-m 'Integration Tests'"
status = kamal :lock, :status, capture: true status = kamal :lock, :status, capture: true

View File

@@ -1,8 +1,8 @@
require_relative "integration_test" require_relative "integration_test"
class MainTest < IntegrationTest class MainTest < IntegrationTest
test "envify, deploy, redeploy, rollback, details and audit" do test "env push, deploy, redeploy, rollback, details and audit" do
kamal :envify kamal :env, :push
assert_env_files assert_env_files
remove_local_env_file remove_local_env_file
@@ -45,7 +45,7 @@ class MainTest < IntegrationTest
test "app with roles" do test "app with roles" do
@app = "app_with_roles" @app = "app_with_roles"
kamal :envify kamal :env, :push
version = latest_app_version version = latest_app_version
@@ -65,7 +65,7 @@ class MainTest < IntegrationTest
end end
test "config" do test "config" do
config = YAML.load(kamal(:config, "-q", capture: true)) config = YAML.load(kamal(:config, capture: true))
version = latest_app_version version = latest_app_version
assert_equal [ "web" ], config[:roles] assert_equal [ "web" ], config[:roles]
@@ -87,7 +87,7 @@ class MainTest < IntegrationTest
kamal :remove, "-y" kamal :remove, "-y"
assert_no_images_or_containers assert_no_images_or_containers
kamal :envify kamal :env, :push
kamal :setup kamal :setup
assert_images_and_containers assert_images_and_containers

View File

@@ -2,8 +2,6 @@ require_relative "integration_test"
class TraefikTest < IntegrationTest class TraefikTest < IntegrationTest
test "boot, reboot, stop, start, restart, logs, remove" do test "boot, reboot, stop, start, restart, logs, remove" do
kamal :envify
kamal :traefik, :boot kamal :traefik, :boot
assert_traefik_running assert_traefik_running