kamal 1.7.2 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 88a235b000a74c9b34e55924be1c372ebd7e59b0c0bde140f0b8c8b311614e96
4
- data.tar.gz: 7193b72065b8eeab2dbe761ae93383d9c44663104d46b37f93b32fbef00be84a
3
+ metadata.gz: 3cf788692b64036e48979bd965c6cc205442f308173c921f1b7e7f3d53e9f279
4
+ data.tar.gz: c81142cad28e8fdfab7ae68259569f1754791952993c323cbc46760252a8b42c
5
5
  SHA512:
6
- metadata.gz: 58d4e970cd573e766a1580eb5f4d343941d2bf68518fc43840776422ba9d04c89210ad25b4f72b07268920e79c483f1f2ab57c2cb440ad96c372c0447775a0ab
7
- data.tar.gz: 98e87cc46ad4e88fadb38257c5cc48b7a71c4b87121a75aa8f6bfcac290e97c7cc357351564f6b0167e35f6a2472b4a20e9e27ed21721a285c794dc7b9ab5cbe
6
+ metadata.gz: b461f6c47a6b77d3cd35aff8198dc85e8db8b840a14ffd492127042d5acb3cd2603578f59eba9629726dfd918cddceed978b7554b00045a5fe64a0ec656b6d44
7
+ data.tar.gz: 1d446485c62f5285c82d92a49f3b8b821fefd7695ac651bc5e8531a16e8c1739bd4c20e4ff4012a4a42b8c73f0d681cfd64a9f6b90da791ab27df97679ae2d0b
@@ -25,12 +25,17 @@ module Kamal::Cli
25
25
  def initialize(*)
26
26
  super
27
27
  @original_env = ENV.to_h.dup
28
- load_envs
28
+ load_env
29
29
  initialize_commander(options_with_subcommand_class_options)
30
30
  end
31
31
 
32
32
  private
33
- def load_envs
33
+ def reload_env
34
+ reset_env
35
+ load_env
36
+ end
37
+
38
+ def load_env
34
39
  if destination = options[:destination]
35
40
  Dotenv.load(".env.#{destination}", ".env")
36
41
  else
@@ -38,10 +43,27 @@ module Kamal::Cli
38
43
  end
39
44
  end
40
45
 
41
- def reload_envs
46
+ def reset_env
47
+ replace_env @original_env
48
+ end
49
+
50
+ def replace_env(env)
42
51
  ENV.clear
43
- ENV.update(@original_env)
44
- load_envs
52
+ ENV.update(env)
53
+ end
54
+
55
+ def with_original_env
56
+ keeping_current_env do
57
+ reset_env
58
+ yield
59
+ end
60
+ end
61
+
62
+ def keeping_current_env
63
+ current_env = ENV.to_h.dup
64
+ yield
65
+ ensure
66
+ replace_env(current_env)
45
67
  end
46
68
 
47
69
  def options_with_subcommand_class_options
@@ -59,11 +59,14 @@ class Kamal::Cli::Build < Kamal::Cli::Base
59
59
 
60
60
  desc "pull", "Pull app image from registry onto servers"
61
61
  def pull
62
- on(KAMAL.hosts) do
63
- execute *KAMAL.auditor.record("Pulled image with version #{KAMAL.config.version}"), verbosity: :debug
64
- execute *KAMAL.builder.clean, raise_on_non_zero_exit: false
65
- execute *KAMAL.builder.pull
66
- execute *KAMAL.builder.validate_image
62
+ if (first_hosts = mirror_hosts).any?
63
+ #  Pull on a single host per mirror first to seed them
64
+ say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta
65
+ pull_on_hosts(first_hosts)
66
+ say "Pulling image on remaining hosts...", :magenta
67
+ pull_on_hosts(KAMAL.hosts - first_hosts)
68
+ else
69
+ pull_on_hosts(KAMAL.hosts)
67
70
  end
68
71
  end
69
72
 
@@ -131,4 +134,28 @@ class Kamal::Cli::Build < Kamal::Cli::Base
131
134
  end
132
135
  end
133
136
  end
137
+
138
+ def mirror_hosts
139
+ if KAMAL.hosts.many?
140
+ mirror_hosts = Concurrent::Hash.new
141
+ on(KAMAL.hosts) do |host|
142
+ first_mirror = capture_with_info(*KAMAL.builder.first_mirror).strip.presence
143
+ mirror_hosts[first_mirror] ||= host if first_mirror
144
+ rescue SSHKit::Command::Failed => e
145
+ raise unless e.message =~ /error calling index: reflect: slice index out of range/
146
+ end
147
+ mirror_hosts.values
148
+ else
149
+ []
150
+ end
151
+ end
152
+
153
+ def pull_on_hosts(hosts)
154
+ on(hosts) do
155
+ execute *KAMAL.auditor.record("Pulled image with version #{KAMAL.config.version}"), verbosity: :debug
156
+ execute *KAMAL.builder.clean, raise_on_non_zero_exit: false
157
+ execute *KAMAL.builder.pull
158
+ execute *KAMAL.builder.validate_image
159
+ end
160
+ end
134
161
  end
@@ -191,10 +191,12 @@ class Kamal::Cli::Main < Kamal::Cli::Base
191
191
  end
192
192
 
193
193
  if Pathname.new(File.expand_path(env_template_path)).exist?
194
- File.write(env_path, ERB.new(File.read(env_template_path), trim_mode: "-").result, perm: 0600)
194
+ # Ensure existing env doesn't pollute template evaluation
195
+ content = with_original_env { ERB.new(File.read(env_template_path), trim_mode: "-").result }
196
+ File.write(env_path, content, perm: 0600)
195
197
 
196
198
  unless options[:skip_push]
197
- reload_envs
199
+ reload_env
198
200
  invoke "kamal:cli:env:push", options
199
201
  end
200
202
  else
@@ -1,7 +1,13 @@
1
- #!/bin/sh
1
+ #!/usr/bin/env ruby
2
2
 
3
3
  # A sample docker-setup hook
4
4
  #
5
- # Sets up a Docker network which can then be used by the application’s containers
5
+ # Sets up a Docker network on defined hosts which can then be used by the application’s containers
6
6
 
7
- ssh user@example.com docker network create kamal
7
+ hosts = ENV["KAMAL_HOSTS"].split(",")
8
+
9
+ hosts.each do |ip|
10
+ destination = "root@#{ip}"
11
+ puts "Creating a Docker network \"kamal\" on #{destination}"
12
+ `ssh #{destination} docker network create kamal`
13
+ end
@@ -9,7 +9,7 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
9
9
  # Runs remotely
10
10
  def record(line, **details)
11
11
  append \
12
- [ :echo, audit_tags(**details).except(:version, :service_version).to_s, line ],
12
+ [ :echo, audit_tags(**details).except(:version, :service_version, :service).to_s, line ],
13
13
  audit_log_file
14
14
  end
15
15
 
@@ -40,6 +40,10 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
40
40
  []
41
41
  end
42
42
 
43
+ def first_mirror
44
+ docker(:info, "--format '{{index .RegistryConfig.Mirrors 0}}'")
45
+ end
46
+
43
47
  private
44
48
  def build_tags
45
49
  [ "-t", config.absolute_image, "-t", config.latest_image ]
@@ -2,7 +2,7 @@ require "active_support/core_ext/string/filters"
2
2
 
3
3
  class Kamal::Commands::Builder < Kamal::Commands::Base
4
4
  delegate :create, :remove, :push, :clean, :pull, :info, :context_hosts, :config_context_hosts, :validate_image,
5
- to: :target
5
+ :first_mirror, to: :target
6
6
 
7
7
  include Clone
8
8
 
@@ -44,3 +44,23 @@ ssh:
44
44
  # Defaults to `fatal`. Set this to debug if you are having
45
45
  # SSH connection issues.
46
46
  log_level: debug
47
+
48
+ # Keys Only
49
+ #
50
+ # Set to true to use only private keys from keys and key_data parameters,
51
+ # even if ssh-agent offers more identities. This option is intended for
52
+ # situations where ssh-agent offers many different identites or you have
53
+ # a need to overwrite all identites and force a single one.
54
+ keys_only: false
55
+
56
+ # Keys
57
+ #
58
+ # An array of file names of private keys to use for publickey
59
+ # and hostbased authentication
60
+ keys: [ "~/.ssh/id.pem" ]
61
+
62
+ # Key Data
63
+ #
64
+ # An array of strings, with each element of the array being
65
+ # a raw private key in PEM format.
66
+ key_data: [ "-----BEGIN OPENSSH PRIVATE KEY-----" ]
@@ -26,8 +26,20 @@ class Kamal::Configuration::Ssh
26
26
  end
27
27
  end
28
28
 
29
+ def keys_only
30
+ ssh_config["keys_only"]
31
+ end
32
+
33
+ def keys
34
+ ssh_config["keys"]
35
+ end
36
+
37
+ def key_data
38
+ ssh_config["key_data"]
39
+ end
40
+
29
41
  def options
30
- { user: user, port: port, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
42
+ { user: user, port: port, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30, keys_only: keys_only, keys: keys, key_data: key_data }.compact
31
43
  end
32
44
 
33
45
  def to_h
@@ -31,9 +31,9 @@ class Kamal::Configuration::Validator
31
31
  validate_array_of! value, example_value.first.class
32
32
  elsif example_value.is_a?(Hash)
33
33
  case key.to_s
34
- when "options"
34
+ when "options", "args"
35
35
  validate_type! value, Hash
36
- when "args", "labels"
36
+ when "labels"
37
37
  validate_hash_of! value, example_value.first[1].class
38
38
  else
39
39
  validate_against_example! value, example_value
data/lib/kamal/git.rb CHANGED
@@ -9,6 +9,10 @@ module Kamal::Git
9
9
  `git config user.name`.strip
10
10
  end
11
11
 
12
+ def email
13
+ `git config user.email`.strip
14
+ end
15
+
12
16
  def revision
13
17
  `git rev-parse HEAD`.strip
14
18
  end
data/lib/kamal/tags.rb CHANGED
@@ -10,10 +10,11 @@ class Kamal::Tags
10
10
 
11
11
  def default_tags(config)
12
12
  { recorded_at: Time.now.utc.iso8601,
13
- performer: `whoami`.chomp,
13
+ performer: Kamal::Git.email.presence || `whoami`.chomp,
14
14
  destination: config.destination,
15
15
  version: config.version,
16
- service_version: service_version(config) }
16
+ service_version: service_version(config),
17
+ service: config.service }
17
18
  end
18
19
 
19
20
  def service_version(config)
data/lib/kamal/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kamal
2
- VERSION = "1.7.2"
2
+ VERSION = "1.8.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kamal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.2
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-24 00:00:00.000000000 Z
11
+ date: 2024-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.22.2
33
+ version: 1.23.0
34
34
  - - "<"
35
35
  - !ruby/object:Gem::Version
36
36
  version: '2.0'
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.22.2
43
+ version: 1.23.0
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '2.0'
@@ -114,26 +114,6 @@ dependencies:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
116
  version: '1.2'
117
- - !ruby/object:Gem::Dependency
118
- name: x25519
119
- requirement: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - "~>"
122
- - !ruby/object:Gem::Version
123
- version: '1.0'
124
- - - ">="
125
- - !ruby/object:Gem::Version
126
- version: 1.0.10
127
- type: :runtime
128
- prerelease: false
129
- version_requirements: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - "~>"
132
- - !ruby/object:Gem::Version
133
- version: '1.0'
134
- - - ">="
135
- - !ruby/object:Gem::Version
136
- version: 1.0.10
137
117
  - !ruby/object:Gem::Dependency
138
118
  name: bcrypt_pbkdf
139
119
  requirement: !ruby/object:Gem::Requirement
@@ -314,7 +294,6 @@ files:
314
294
  - lib/kamal/configuration/validation.rb
315
295
  - lib/kamal/configuration/validator.rb
316
296
  - lib/kamal/configuration/validator/accessory.rb
317
- - lib/kamal/configuration/validator/alias.rb
318
297
  - lib/kamal/configuration/validator/builder.rb
319
298
  - lib/kamal/configuration/validator/env.rb
320
299
  - lib/kamal/configuration/validator/registry.rb
@@ -1,19 +0,0 @@
1
- class Kamal::Configuration::Validator::Alias < Kamal::Configuration::Validator
2
- def validate!
3
- super
4
-
5
- name = context.delete_prefix("aliases/")
6
-
7
- if name !~ /\A[a-z0-9_-]+\z/
8
- error "Invalid alias name: '#{name}'. Must only contain lowercase letters, alphanumeric, hyphens and underscores."
9
- end
10
-
11
- if Kamal::Cli::Main.original_commands.include?(name)
12
- error "Alias '#{name}' conflicts with a built-in command."
13
- end
14
-
15
- if config["command"].empty?
16
- error "Alias '#{name}': command is required."
17
- end
18
- end
19
- end