Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec4aa45852 | ||
|
|
5e11a64181 | ||
|
|
57d9ce177a | ||
|
|
8a98949634 | ||
|
|
0eb9f48082 | ||
|
|
9db6fc0704 | ||
|
|
27fede3caa | ||
|
|
29c723f7ec | ||
|
|
2755582c47 |
@@ -1,7 +1,7 @@
|
|||||||
# Use the official Ruby 3.2.0 Alpine image as the base image
|
# Use the official Ruby 3.2.0 Alpine image as the base image
|
||||||
FROM ruby:3.2.0-alpine
|
FROM ruby:3.2.0-alpine
|
||||||
|
|
||||||
# Install docker/buildx-bin
|
# Install docker/buildx-bin
|
||||||
COPY --from=docker/buildx-bin /buildx /usr/libexec/docker/cli-plugins/docker-buildx
|
COPY --from=docker/buildx-bin /buildx /usr/libexec/docker/cli-plugins/docker-buildx
|
||||||
|
|
||||||
# Set the working directory to /kamal
|
# Set the working directory to /kamal
|
||||||
@@ -14,7 +14,7 @@ COPY Gemfile Gemfile.lock kamal.gemspec ./
|
|||||||
COPY lib/kamal/version.rb /kamal/lib/kamal/version.rb
|
COPY lib/kamal/version.rb /kamal/lib/kamal/version.rb
|
||||||
|
|
||||||
# Install system dependencies
|
# Install system dependencies
|
||||||
RUN apk add --no-cache --update build-base git docker openrc openssh-client-default \
|
RUN apk add --no-cache build-base git docker openrc openssh-client-default \
|
||||||
&& rc-update add docker boot \
|
&& rc-update add docker boot \
|
||||||
&& gem install bundler --version=2.4.3 \
|
&& gem install bundler --version=2.4.3 \
|
||||||
&& bundle install
|
&& bundle install
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
kamal (1.8.0)
|
kamal (1.8.1)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
mirror_hosts = Concurrent::Hash.new
|
mirror_hosts = Concurrent::Hash.new
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
first_mirror = capture_with_info(*KAMAL.builder.first_mirror).strip.presence
|
first_mirror = capture_with_info(*KAMAL.builder.first_mirror).strip.presence
|
||||||
mirror_hosts[first_mirror] ||= host if first_mirror
|
mirror_hosts[first_mirror] ||= host.to_s if first_mirror
|
||||||
rescue SSHKit::Command::Failed => e
|
rescue SSHKit::Command::Failed => e
|
||||||
raise unless e.message =~ /error calling index: reflect: slice index out of range/
|
raise unless e.message =~ /error calling index: reflect: slice index out of range/
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class Kamal::Configuration
|
|||||||
@destination = destination
|
@destination = destination
|
||||||
@declared_version = version
|
@declared_version = version
|
||||||
|
|
||||||
validate! raw_config, example: validation_yml.symbolize_keys, context: ""
|
validate! raw_config, example: validation_yml.symbolize_keys, context: "", with: Kamal::Configuration::Validator::Configuration
|
||||||
|
|
||||||
# Eager load config to validate it, these are first as they have dependencies later on
|
# Eager load config to validate it, these are first as they have dependencies later on
|
||||||
@servers = Servers.new(config: self)
|
@servers = Servers.new(config: self)
|
||||||
|
|||||||
@@ -2,13 +2,24 @@
|
|||||||
#
|
#
|
||||||
# Configuration is read from the `config/deploy.yml`
|
# Configuration is read from the `config/deploy.yml`
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Destinations
|
||||||
|
#
|
||||||
# When running commands, you can specify a destination with the `-d` flag,
|
# When running commands, you can specify a destination with the `-d` flag,
|
||||||
# e.g. `kamal deploy -d staging`
|
# e.g. `kamal deploy -d staging`
|
||||||
#
|
#
|
||||||
# In this case the configuration will also be read from `config/deploy.staging.yml`
|
# In this case the configuration will also be read from `config/deploy.staging.yml`
|
||||||
# and merged with the base configuration.
|
# and merged with the base configuration.
|
||||||
|
|
||||||
|
# Extensions
|
||||||
#
|
#
|
||||||
# The available configuration options are explained below.
|
# Kamal will not accept unrecognized keys in the configuration file.
|
||||||
|
#
|
||||||
|
# However, you might want to declare a configuration block using YAML anchors
|
||||||
|
# and aliases to avoid repetition.
|
||||||
|
#
|
||||||
|
# You can use prefix a configuration section with `x-` to indicate that it is an
|
||||||
|
# extension. Kamal will ignore the extension and not raise an error.
|
||||||
|
|
||||||
# The service name
|
# The service name
|
||||||
# This is a required value. It is used as the container name prefix.
|
# This is a required value. It is used as the container name prefix.
|
||||||
|
|||||||
@@ -15,11 +15,10 @@ class Kamal::Configuration::Validator
|
|||||||
def validate_against_example!(validation_config, example)
|
def validate_against_example!(validation_config, example)
|
||||||
validate_type! validation_config, Hash
|
validate_type! validation_config, Hash
|
||||||
|
|
||||||
if (unknown_keys = validation_config.keys - example.keys).any?
|
check_unknown_keys! validation_config, example
|
||||||
unknown_keys_error unknown_keys
|
|
||||||
end
|
|
||||||
|
|
||||||
validation_config.each do |key, value|
|
validation_config.each do |key, value|
|
||||||
|
next if extension?(key)
|
||||||
with_context(key) do
|
with_context(key) do
|
||||||
example_value = example[key]
|
example_value = example[key]
|
||||||
|
|
||||||
@@ -137,4 +136,18 @@ class Kamal::Configuration::Validator
|
|||||||
ensure
|
ensure
|
||||||
@context = old_context
|
@context = old_context
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def allow_extensions?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def extension?(key)
|
||||||
|
key.to_s.start_with?("x-")
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_unknown_keys!(config, example)
|
||||||
|
unknown_keys = config.keys - example.keys
|
||||||
|
unknown_keys.reject! { |key| extension?(key) } if allow_extensions?
|
||||||
|
unknown_keys_error unknown_keys if unknown_keys.present?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
6
lib/kamal/configuration/validator/configuration.rb
Normal file
6
lib/kamal/configuration/validator/configuration.rb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
class Kamal::Configuration::Validator::Configuration < Kamal::Configuration::Validator
|
||||||
|
private
|
||||||
|
def allow_extensions?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
module Kamal
|
module Kamal
|
||||||
VERSION = "1.8.0"
|
VERSION = "1.8.1"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class CliBuildTest < CliTestCase
|
|||||||
run_command("pull").tap do |output|
|
run_command("pull").tap do |output|
|
||||||
assert_match /Pulling image on 1\.1\.1\.\d to seed the mirror\.\.\./, output
|
assert_match /Pulling image on 1\.1\.1\.\d to seed the mirror\.\.\./, output
|
||||||
assert_match "Pulling image on remaining hosts...", output
|
assert_match "Pulling image on remaining hosts...", output
|
||||||
assert_match /docker pull dhh\/app:999/, output
|
assert_equal 4, output.scan(/docker pull dhh\/app:999/).size, output
|
||||||
assert_match "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:999 | grep -x app || (echo \"Image dhh/app:999 is missing the 'service' label\" && exit 1)", output
|
assert_match "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:999 | grep -x app || (echo \"Image dhh/app:999 is missing the 'service' label\" && exit 1)", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -199,7 +199,7 @@ class CliBuildTest < CliTestCase
|
|||||||
run_command("pull").tap do |output|
|
run_command("pull").tap do |output|
|
||||||
assert_match /Pulling image on 1\.1\.1\.\d, 1\.1\.1\.\d to seed the mirrors\.\.\./, output
|
assert_match /Pulling image on 1\.1\.1\.\d, 1\.1\.1\.\d to seed the mirrors\.\.\./, output
|
||||||
assert_match "Pulling image on remaining hosts...", output
|
assert_match "Pulling image on remaining hosts...", output
|
||||||
assert_match /docker pull dhh\/app:999/, output
|
assert_equal 4, output.scan(/docker pull dhh\/app:999/).size, output
|
||||||
assert_match "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:999 | grep -x app || (echo \"Image dhh/app:999 is missing the 'service' label\" && exit 1)", output
|
assert_match "docker inspect -f '{{ .Config.Labels.service }}' dhh/app:999 | grep -x app || (echo \"Image dhh/app:999 is missing the 'service' label\" && exit 1)", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -42,12 +42,13 @@ class CliTestCase < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def assert_hook_ran(hook, output, version:, service_version:, hosts:, command:, subcommand: nil, runtime: false)
|
def assert_hook_ran(hook, output, version:, service_version:, hosts:, command:, subcommand: nil, runtime: false)
|
||||||
performer = Kamal::Git.email.presence || `whoami`.chomp
|
whoami = `whoami`.chomp
|
||||||
|
performer = Kamal::Git.email.presence || whoami
|
||||||
service = service_version.split("@").first
|
service = service_version.split("@").first
|
||||||
|
|
||||||
assert_match "Running the #{hook} hook...\n", output
|
assert_match "Running the #{hook} hook...\n", output
|
||||||
|
|
||||||
expected = %r{Running\s/usr/bin/env\s\.kamal/hooks/#{hook}\sas\s#{performer}@localhost\n\s
|
expected = %r{Running\s/usr/bin/env\s\.kamal/hooks/#{hook}\sas\s#{whoami}@localhost\n\s
|
||||||
DEBUG\s\[[0-9a-f]*\]\sCommand:\s\(\sexport\s
|
DEBUG\s\[[0-9a-f]*\]\sCommand:\s\(\sexport\s
|
||||||
KAMAL_RECORDED_AT=\"\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\"\s
|
KAMAL_RECORDED_AT=\"\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\"\s
|
||||||
KAMAL_PERFORMER=\"#{performer}\"\s
|
KAMAL_PERFORMER=\"#{performer}\"\s
|
||||||
|
|||||||
@@ -344,4 +344,12 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
assert_raises(Kamal::ConfigurationError) { Kamal::Configuration.new(@deploy_with_roles.merge(retain_containers: 0)) }
|
assert_raises(Kamal::ConfigurationError) { Kamal::Configuration.new(@deploy_with_roles.merge(retain_containers: 0)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "extensions" do
|
||||||
|
dest_config_file = Pathname.new(File.expand_path("fixtures/deploy_with_extensions.yml", __dir__))
|
||||||
|
|
||||||
|
config = Kamal::Configuration.create_from config_file: dest_config_file
|
||||||
|
assert_equal config.role(:web_tokyo).running_traefik?, true
|
||||||
|
assert_equal config.role(:web_chicago).running_traefik?, true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
24
test/fixtures/deploy_with_extensions.yml
vendored
Normal file
24
test/fixtures/deploy_with_extensions.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
x-web: &web
|
||||||
|
traefik: true
|
||||||
|
|
||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
web_chicago:
|
||||||
|
<<: *web
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.1.1.2
|
||||||
|
web_tokyo:
|
||||||
|
<<: *web
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.3
|
||||||
|
- 1.1.1.4
|
||||||
|
env:
|
||||||
|
REDIS_URL: redis://x/y
|
||||||
|
registry:
|
||||||
|
server: registry.digitalocean.com
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
|
primary_role: web_tokyo
|
||||||
Reference in New Issue
Block a user