Skip to content

Commit

Permalink
Catch up with main
Browse files Browse the repository at this point in the history
  • Loading branch information
nickhammond committed Nov 26, 2024
2 parents 9ac3d57 + 69867e2 commit 9f6660d
Show file tree
Hide file tree
Showing 36 changed files with 749 additions and 87 deletions.
6 changes: 2 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
kamal (2.2.2)
kamal (2.3.0)
activesupport (>= 7.0)
base64 (~> 0.2)
bcrypt_pbkdf (~> 1.0)
Expand Down Expand Up @@ -122,8 +122,7 @@ GEM
regexp_parser (2.9.2)
reline (0.5.9)
io-console (~> 0.5)
rexml (3.3.6)
strscan
rexml (3.3.9)
rubocop (1.65.1)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
Expand Down Expand Up @@ -161,7 +160,6 @@ GEM
net-sftp (>= 2.1.2)
net-ssh (>= 2.8.0)
stringio (3.1.1)
strscan (3.1.0)
thor (1.3.1)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
Expand Down
29 changes: 22 additions & 7 deletions lib/kamal/cli/accessory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ def boot(name, prepare: true)
execute *accessory.ensure_env_directory
upload! accessory.secrets_io, accessory.secrets_path, mode: "0600"
execute *accessory.run

if accessory.running_proxy?
target = capture_with_info(*accessory.container_id_for(container_name: accessory.service_name, only_running: true)).strip
execute *accessory.deploy(target: target)
end
end
end
end
Expand Down Expand Up @@ -75,6 +80,10 @@ def start(name)
on(hosts) do
execute *KAMAL.auditor.record("Started #{name} accessory"), verbosity: :debug
execute *accessory.start
if accessory.running_proxy?
target = capture_with_info(*accessory.container_id_for(container_name: accessory.service_name, only_running: true)).strip
execute *accessory.deploy(target: target)
end
end
end
end
Expand All @@ -87,6 +96,11 @@ def stop(name)
on(hosts) do
execute *KAMAL.auditor.record("Stopped #{name} accessory"), verbosity: :debug
execute *accessory.stop, raise_on_non_zero_exit: false

if accessory.running_proxy?
target = capture_with_info(*accessory.container_id_for(container_name: accessory.service_name, only_running: true)).strip
execute *accessory.remove if target
end
end
end
end
Expand All @@ -112,14 +126,15 @@ def details(name)
end
end

desc "exec [NAME] [CMD]", "Execute a custom command on servers (use --help to show options)"
desc "exec [NAME] [CMD...]", "Execute a custom command on servers within the accessory container (use --help to show options)"
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
def exec(name, cmd)
def exec(name, *cmd)
cmd = Kamal::Utils.join_commands(cmd)
with_accessory(name) do |accessory, hosts|
case
when options[:interactive] && options[:reuse]
say "Launching interactive command with via SSH from existing container...", :magenta
say "Launching interactive command via SSH from existing container...", :magenta
run_locally { exec accessory.execute_in_existing_container_over_ssh(cmd) }

when options[:interactive]
Expand All @@ -128,16 +143,16 @@ def exec(name, cmd)

when options[:reuse]
say "Launching command from existing container...", :magenta
on(hosts) do
on(hosts) do |host|
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug
capture_with_info(*accessory.execute_in_existing_container(cmd))
puts_by_host host, capture_with_info(*accessory.execute_in_existing_container(cmd))
end

else
say "Launching command from new container...", :magenta
on(hosts) do
on(hosts) do |host|
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on #{name} accessory"), verbosity: :debug
capture_with_info(*accessory.execute_in_new_container(cmd))
puts_by_host host, capture_with_info(*accessory.execute_in_new_container(cmd))
end
end
end
Expand Down
12 changes: 9 additions & 3 deletions lib/kamal/cli/secrets.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
class Kamal::Cli::Secrets < Kamal::Cli::Base
desc "fetch [SECRETS...]", "Fetch secrets from a vault"
option :adapter, type: :string, aliases: "-a", required: true, desc: "Which vault adapter to use"
option :account, type: :string, required: true, desc: "The account identifier or username"
option :account, type: :string, required: false, desc: "The account identifier or username"
option :from, type: :string, required: false, desc: "A vault or folder to fetch the secrets from"
option :inline, type: :boolean, required: false, hidden: true
def fetch(*secrets)
results = adapter(options[:adapter]).fetch(secrets, **options.slice(:account, :from).symbolize_keys)
adapter = initialize_adapter(options[:adapter])

if adapter.requires_account? && options[:account].blank?
return puts "No value provided for required options '--account'"
end

results = adapter.fetch(secrets, **options.slice(:account, :from).symbolize_keys)

return_or_puts JSON.dump(results).shellescape, inline: options[:inline]
end
Expand All @@ -29,7 +35,7 @@ def print
end

private
def adapter(adapter)
def initialize_adapter(adapter)
Kamal::Secrets::Adapters.lookup(adapter)
end

Expand Down
7 changes: 5 additions & 2 deletions lib/kamal/cli/templates/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ servers:
# Enable SSL auto certification via Let's Encrypt and allow for multiple apps on a single web server.
# Remove this section when using multiple web servers and ensure you terminate SSL at your load balancer.
#
# Note: If using Cloudflare, set encryption mode in SSL/TLS setting to "Full" to enable CF-to-app encryption.
proxy:
# Note: If using Cloudflare, set encryption mode in SSL/TLS setting to "Full" to enable CF-to-app encryption.
proxy:
ssl: true
host: app.example.com
# Proxy connects to your container on port 80 by default.
Expand All @@ -36,6 +36,9 @@ registry:
# Configure builder setup.
builder:
arch: amd64
# Pass in additional build args needed for your Dockerfile.
# args:
# RUBY_VERSION: <%= File.read('.ruby-version').strip %>

# Inject ENV variables into containers (secrets come from .kamal/secrets).
#
Expand Down
6 changes: 5 additions & 1 deletion lib/kamal/commands/accessory.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
class Kamal::Commands::Accessory < Kamal::Commands::Base
include Proxy

attr_reader :accessory_config
delegate :service_name, :image, :hosts, :port, :files, :directories, :cmd,
:network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args,
:secrets_io, :secrets_path, :env_directory,
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?,
to: :accessory_config
delegate :proxy_container_name, to: :config


def initialize(config, name:)
super(config)
Expand Down
16 changes: 16 additions & 0 deletions lib/kamal/commands/accessory/proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Kamal::Commands::Accessory::Proxy
delegate :proxy_container_name, to: :config

def deploy(target:)
proxy_exec :deploy, service_name, *proxy.deploy_command_args(target: target)
end

def remove
proxy_exec :remove, service_name
end

private
def proxy_exec(*command)
docker :exec, proxy_container_name, "kamal-proxy", *command
end
end
22 changes: 15 additions & 7 deletions lib/kamal/commands/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def stop(version: nil)
end

def info
docker :ps, *filter_args
docker :ps, *container_filter_args
end


Expand All @@ -67,7 +67,7 @@ def current_running_version

def list_versions(*docker_args, statuses: nil)
pipe \
docker(:ps, *filter_args(statuses: statuses), *docker_args, "--format", '"{{.Names}}"'),
docker(:ps, *container_filter_args(statuses: statuses), *docker_args, "--format", '"{{.Names}}"'),
extract_version_from_name
end

Expand All @@ -91,25 +91,33 @@ def latest_image_container(format:)
end

def latest_container(format:, filters: nil)
docker :ps, "--latest", *format, *filter_args(statuses: ACTIVE_DOCKER_STATUSES), argumentize("--filter", filters)
docker :ps, "--latest", *format, *container_filter_args(statuses: ACTIVE_DOCKER_STATUSES), argumentize("--filter", filters)
end

def filter_args(statuses: nil)
argumentize "--filter", filters(statuses: statuses)
def container_filter_args(statuses: nil)
argumentize "--filter", container_filters(statuses: statuses)
end

def image_filter_args
argumentize "--filter", image_filters
end

def extract_version_from_name
# Extract SHA from "service-role-dest-SHA"
%(while read line; do echo ${line##{role.container_prefix}-}; done)
end

def filters(statuses: nil)
def container_filters(statuses: nil)
[ "label=service=#{config.service}" ].tap do |filters|
filters << "label=destination=#{config.destination}" if config.destination
filters << "label=destination=#{config.destination}"
filters << "label=role=#{role}" if role
statuses&.each do |status|
filters << "status=#{status}"
end
end
end

def image_filters
[ "label=service=#{config.service}" ]
end
end
4 changes: 2 additions & 2 deletions lib/kamal/commands/app/containers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Kamal::Commands::App::Containers
DOCKER_HEALTH_LOG_FORMAT = "'{{json .State.Health}}'"

def list_containers
docker :container, :ls, "--all", *filter_args
docker :container, :ls, "--all", *container_filter_args
end

def list_container_names
Expand All @@ -20,7 +20,7 @@ def rename_container(version:, new_version:)
end

def remove_containers
docker :container, :prune, "--force", *filter_args
docker :container, :prune, "--force", *container_filter_args
end

def container_health_log(version:)
Expand Down
2 changes: 1 addition & 1 deletion lib/kamal/commands/app/images.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ def list_images
end

def remove_images
docker :image, :prune, "--all", "--force", *filter_args
docker :image, :prune, "--all", "--force", *image_filter_args
end

def tag_latest_image
Expand Down
8 changes: 6 additions & 2 deletions lib/kamal/commands/builder/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class BuilderError < StandardError; end
delegate \
:args, :secrets, :dockerfile, :target, :arches, :local_arches, :remote_arches, :remote,
:pack?, :pack_builder, :pack_buildpacks,
:cache_from, :cache_to, :ssh, :provenance, :driver, :docker_driver?,
:cache_from, :cache_to, :ssh, :provenance, :sbom, :driver, :docker_driver?,
to: :builder_config

def clean
Expand Down Expand Up @@ -38,7 +38,7 @@ def inspect_builder
end

def build_options
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh, *builder_provenance ]
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_target, *build_ssh, *builder_provenance, *builder_sbom ]
end

def build_context
Expand Down Expand Up @@ -102,6 +102,10 @@ def builder_provenance
argumentize "--provenance", provenance unless provenance.nil?
end

def builder_sbom
argumentize "--sbom", sbom unless sbom.nil?
end

def builder_config
config.builder
end
Expand Down
2 changes: 1 addition & 1 deletion lib/kamal/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Kamal::Configuration

include Validation

PROXY_MINIMUM_VERSION = "v0.8.1"
PROXY_MINIMUM_VERSION = "v0.8.2"
PROXY_HTTP_PORT = 80
PROXY_HTTPS_PORT = 443
PROXY_LOG_MAX_SIZE = "10m"
Expand Down
19 changes: 17 additions & 2 deletions lib/kamal/configuration/accessory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Kamal::Configuration::Accessory

delegate :argumentize, :optionize, to: Kamal::Utils

attr_reader :name, :accessory_config, :env
attr_reader :name, :accessory_config, :env, :proxy

def initialize(name, config:)
@name, @config, @accessory_config = name.inquiry, config, config.raw_config["accessories"][name]
Expand All @@ -20,6 +20,8 @@ def initialize(name, config:)
config: accessory_config.fetch("env", {}),
secrets: config.secrets,
context: "accessories/#{name}/env"

initialize_proxy if running_proxy?
end

def service_name
Expand Down Expand Up @@ -106,6 +108,17 @@ def cmd
accessory_config["cmd"]
end

def running_proxy?
@accessory_config["proxy"].present?
end

def initialize_proxy
@proxy = Kamal::Configuration::Proxy.new \
config: config,
proxy_config: accessory_config["proxy"],
context: "accessories/#{name}/proxy"
end

private
attr_accessor :config

Expand Down Expand Up @@ -176,7 +189,9 @@ def hosts_from_hosts

def hosts_from_roles
if accessory_config.key?("roles")
accessory_config["roles"].flat_map { |role| config.role(role).hosts }
accessory_config["roles"].flat_map do |role|
config.role(role)&.hosts || raise(Kamal::ConfigurationError, "Unknown role in accessories config: '#{role}'")
end
end
end

Expand Down
4 changes: 4 additions & 0 deletions lib/kamal/configuration/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ def provenance
builder_config["provenance"]
end

def sbom
builder_config["sbom"]
end

def git_clone?
Kamal::Git.used? && builder_config["context"].nil?
end
Expand Down
4 changes: 4 additions & 0 deletions lib/kamal/configuration/docs/accessory.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,7 @@ accessories:
# Defaults to kamal:
network: custom

# Proxy
#
proxy:
...
6 changes: 6 additions & 0 deletions lib/kamal/configuration/docs/builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,9 @@ builder:
# It is used to configure provenance attestations for the build result.
# The value can also be a boolean to enable or disable provenance attestations.
provenance: mode=max

# SBOM (Software Bill of Materials)
#
# It is used to configure SBOM generation for the build result.
# The value can also be a boolean to enable or disable SBOM generation.
sbom: true
Loading

0 comments on commit 9f6660d

Please sign in to comment.