dash 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +13 -0
  4. data/bin/dash +18 -0
  5. data/bin/kamal +18 -0
  6. data/lib/kamal/cli/accessory.rb +342 -0
  7. data/lib/kamal/cli/alias/command.rb +10 -0
  8. data/lib/kamal/cli/app/assets.rb +24 -0
  9. data/lib/kamal/cli/app/boot.rb +126 -0
  10. data/lib/kamal/cli/app/error_pages.rb +33 -0
  11. data/lib/kamal/cli/app/ssl_certificates.rb +28 -0
  12. data/lib/kamal/cli/app.rb +368 -0
  13. data/lib/kamal/cli/base.rb +324 -0
  14. data/lib/kamal/cli/build/clone.rb +59 -0
  15. data/lib/kamal/cli/build/port_forwarding.rb +66 -0
  16. data/lib/kamal/cli/build.rb +242 -0
  17. data/lib/kamal/cli/healthcheck/barrier.rb +33 -0
  18. data/lib/kamal/cli/healthcheck/error.rb +2 -0
  19. data/lib/kamal/cli/healthcheck/poller.rb +42 -0
  20. data/lib/kamal/cli/lock.rb +34 -0
  21. data/lib/kamal/cli/main.rb +299 -0
  22. data/lib/kamal/cli/proxy.rb +419 -0
  23. data/lib/kamal/cli/prune.rb +34 -0
  24. data/lib/kamal/cli/registry.rb +49 -0
  25. data/lib/kamal/cli/secrets.rb +50 -0
  26. data/lib/kamal/cli/server.rb +70 -0
  27. data/lib/kamal/cli/templates/deploy.yml +102 -0
  28. data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +3 -0
  29. data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +3 -0
  30. data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +14 -0
  31. data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +3 -0
  32. data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +3 -0
  33. data/lib/kamal/cli/templates/sample_hooks/pre-build.sample +51 -0
  34. data/lib/kamal/cli/templates/sample_hooks/pre-connect.sample +47 -0
  35. data/lib/kamal/cli/templates/sample_hooks/pre-deploy.sample +122 -0
  36. data/lib/kamal/cli/templates/sample_hooks/pre-proxy-reboot.sample +3 -0
  37. data/lib/kamal/cli/templates/secrets +22 -0
  38. data/lib/kamal/cli.rb +9 -0
  39. data/lib/kamal/commander/specifics.rb +62 -0
  40. data/lib/kamal/commander.rb +230 -0
  41. data/lib/kamal/commands/accessory/proxy.rb +16 -0
  42. data/lib/kamal/commands/accessory.rb +118 -0
  43. data/lib/kamal/commands/app/assets.rb +51 -0
  44. data/lib/kamal/commands/app/containers.rb +31 -0
  45. data/lib/kamal/commands/app/error_pages.rb +9 -0
  46. data/lib/kamal/commands/app/execution.rb +38 -0
  47. data/lib/kamal/commands/app/images.rb +13 -0
  48. data/lib/kamal/commands/app/logging.rb +28 -0
  49. data/lib/kamal/commands/app/proxy.rb +32 -0
  50. data/lib/kamal/commands/app.rb +125 -0
  51. data/lib/kamal/commands/auditor.rb +39 -0
  52. data/lib/kamal/commands/base.rb +147 -0
  53. data/lib/kamal/commands/builder/base.rb +143 -0
  54. data/lib/kamal/commands/builder/clone.rb +32 -0
  55. data/lib/kamal/commands/builder/cloud.rb +22 -0
  56. data/lib/kamal/commands/builder/hybrid.rb +21 -0
  57. data/lib/kamal/commands/builder/local.rb +20 -0
  58. data/lib/kamal/commands/builder/pack.rb +46 -0
  59. data/lib/kamal/commands/builder/remote.rb +75 -0
  60. data/lib/kamal/commands/builder.rb +54 -0
  61. data/lib/kamal/commands/docker.rb +50 -0
  62. data/lib/kamal/commands/hook.rb +20 -0
  63. data/lib/kamal/commands/loadbalancer.rb +130 -0
  64. data/lib/kamal/commands/lock.rb +70 -0
  65. data/lib/kamal/commands/proxy.rb +150 -0
  66. data/lib/kamal/commands/prune.rb +38 -0
  67. data/lib/kamal/commands/registry.rb +38 -0
  68. data/lib/kamal/commands/server.rb +15 -0
  69. data/lib/kamal/commands.rb +2 -0
  70. data/lib/kamal/configuration/accessory.rb +280 -0
  71. data/lib/kamal/configuration/alias.rb +15 -0
  72. data/lib/kamal/configuration/boot.rb +29 -0
  73. data/lib/kamal/configuration/builder.rb +218 -0
  74. data/lib/kamal/configuration/docs/accessory.yml +160 -0
  75. data/lib/kamal/configuration/docs/alias.yml +29 -0
  76. data/lib/kamal/configuration/docs/boot.yml +21 -0
  77. data/lib/kamal/configuration/docs/builder.yml +132 -0
  78. data/lib/kamal/configuration/docs/configuration.yml +228 -0
  79. data/lib/kamal/configuration/docs/env.yml +118 -0
  80. data/lib/kamal/configuration/docs/logging.yml +21 -0
  81. data/lib/kamal/configuration/docs/output.yml +25 -0
  82. data/lib/kamal/configuration/docs/proxy.yml +207 -0
  83. data/lib/kamal/configuration/docs/registry.yml +64 -0
  84. data/lib/kamal/configuration/docs/role.yml +54 -0
  85. data/lib/kamal/configuration/docs/servers.yml +27 -0
  86. data/lib/kamal/configuration/docs/ssh.yml +81 -0
  87. data/lib/kamal/configuration/docs/sshkit.yml +31 -0
  88. data/lib/kamal/configuration/env/tag.rb +13 -0
  89. data/lib/kamal/configuration/env.rb +42 -0
  90. data/lib/kamal/configuration/loadbalancer.rb +34 -0
  91. data/lib/kamal/configuration/logging.rb +33 -0
  92. data/lib/kamal/configuration/output.rb +34 -0
  93. data/lib/kamal/configuration/proxy/boot.rb +124 -0
  94. data/lib/kamal/configuration/proxy/run.rb +152 -0
  95. data/lib/kamal/configuration/proxy.rb +156 -0
  96. data/lib/kamal/configuration/registry.rb +40 -0
  97. data/lib/kamal/configuration/role.rb +247 -0
  98. data/lib/kamal/configuration/servers.rb +25 -0
  99. data/lib/kamal/configuration/ssh.rb +76 -0
  100. data/lib/kamal/configuration/sshkit.rb +26 -0
  101. data/lib/kamal/configuration/validation.rb +27 -0
  102. data/lib/kamal/configuration/validator/accessory.rb +13 -0
  103. data/lib/kamal/configuration/validator/alias.rb +15 -0
  104. data/lib/kamal/configuration/validator/builder.rb +15 -0
  105. data/lib/kamal/configuration/validator/configuration.rb +6 -0
  106. data/lib/kamal/configuration/validator/env.rb +54 -0
  107. data/lib/kamal/configuration/validator/proxy.rb +47 -0
  108. data/lib/kamal/configuration/validator/registry.rb +27 -0
  109. data/lib/kamal/configuration/validator/role.rb +13 -0
  110. data/lib/kamal/configuration/validator/servers.rb +7 -0
  111. data/lib/kamal/configuration/validator.rb +251 -0
  112. data/lib/kamal/configuration/volume.rb +29 -0
  113. data/lib/kamal/configuration.rb +465 -0
  114. data/lib/kamal/docker.rb +30 -0
  115. data/lib/kamal/env_file.rb +44 -0
  116. data/lib/kamal/git.rb +37 -0
  117. data/lib/kamal/otel_shipper.rb +176 -0
  118. data/lib/kamal/output/base_logger.rb +29 -0
  119. data/lib/kamal/output/file_logger.rb +51 -0
  120. data/lib/kamal/output/formatter.rb +36 -0
  121. data/lib/kamal/output/otel_logger.rb +70 -0
  122. data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +59 -0
  123. data/lib/kamal/secrets/adapters/base.rb +33 -0
  124. data/lib/kamal/secrets/adapters/bitwarden.rb +81 -0
  125. data/lib/kamal/secrets/adapters/bitwarden_secrets_manager.rb +66 -0
  126. data/lib/kamal/secrets/adapters/doppler.rb +57 -0
  127. data/lib/kamal/secrets/adapters/enpass.rb +71 -0
  128. data/lib/kamal/secrets/adapters/gcp_secret_manager.rb +112 -0
  129. data/lib/kamal/secrets/adapters/last_pass.rb +40 -0
  130. data/lib/kamal/secrets/adapters/one_password.rb +104 -0
  131. data/lib/kamal/secrets/adapters/passbolt.rb +129 -0
  132. data/lib/kamal/secrets/adapters/test.rb +16 -0
  133. data/lib/kamal/secrets/adapters.rb +16 -0
  134. data/lib/kamal/secrets/dotenv/inline_command_substitution.rb +47 -0
  135. data/lib/kamal/secrets.rb +53 -0
  136. data/lib/kamal/sshkit_with_ext.rb +273 -0
  137. data/lib/kamal/tags.rb +40 -0
  138. data/lib/kamal/utils/sensitive.rb +20 -0
  139. data/lib/kamal/utils.rb +110 -0
  140. data/lib/kamal/version.rb +3 -0
  141. data/lib/kamal.rb +15 -0
  142. metadata +388 -0
@@ -0,0 +1,299 @@
1
+ class Kamal::Cli::Main < Kamal::Cli::Base
2
+ desc "setup", "Setup all accessories, push the env, and deploy app to servers"
3
+ option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
4
+ option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
5
+ def setup
6
+ print_runtime do
7
+ modify(lock: true) do
8
+ invoke_options = deploy_options
9
+
10
+ say "Ensure Docker is installed...", :magenta
11
+ invoke "kamal:cli:server:bootstrap", [], invoke_options
12
+
13
+ deploy(boot_accessories: true)
14
+ end
15
+ end
16
+ end
17
+
18
+ desc "deploy", "Deploy app to servers"
19
+ option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
20
+ option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
21
+ def deploy(boot_accessories: false)
22
+ modify do
23
+ runtime = print_runtime do
24
+ invoke_options = deploy_options
25
+
26
+ if options[:skip_push]
27
+ say "Pull app image...", :magenta
28
+ invoke "kamal:cli:build:pull", [], invoke_options
29
+ else
30
+ say "Build and push app image...", :magenta
31
+ invoke "kamal:cli:build:deliver", [], invoke_options
32
+ end
33
+
34
+ modify(lock: true) do
35
+ run_hook "pre-deploy", secrets: true
36
+
37
+ say "Ensure kamal-proxy is running...", :magenta
38
+ invoke "kamal:cli:proxy:boot", [], invoke_options
39
+
40
+ invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options if boot_accessories
41
+
42
+ say "Detect stale containers...", :magenta
43
+ invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
44
+
45
+ invoke "kamal:cli:app:boot", [], invoke_options
46
+
47
+ if KAMAL.config.proxy.load_balancing?
48
+ say "Updating loadbalancer configuration...", :magenta
49
+ invoke "kamal:cli:proxy:loadbalancer", [ "deploy" ], invoke_options
50
+ end
51
+
52
+ say "Prune old containers and images...", :magenta
53
+ invoke "kamal:cli:prune:all", [], invoke_options
54
+ end
55
+ end
56
+
57
+ run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
58
+ end
59
+ end
60
+
61
+ desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy and pruning"
62
+ option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
63
+ option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
64
+ def redeploy
65
+ modify do
66
+ runtime = print_runtime do
67
+ invoke_options = deploy_options
68
+
69
+ if options[:skip_push]
70
+ say "Pull app image...", :magenta
71
+ invoke "kamal:cli:build:pull", [], invoke_options
72
+ else
73
+ say "Build and push app image...", :magenta
74
+ invoke "kamal:cli:build:deliver", [], invoke_options
75
+ end
76
+
77
+ modify(lock: true) do
78
+ run_hook "pre-deploy", secrets: true
79
+
80
+ say "Detect stale containers...", :magenta
81
+ invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
82
+
83
+ invoke "kamal:cli:app:boot", [], invoke_options
84
+
85
+ if KAMAL.config.proxy.load_balancing?
86
+ say "Updating loadbalancer configuration...", :magenta
87
+ invoke "kamal:cli:proxy:loadbalancer", [ "deploy" ], invoke_options
88
+ end
89
+ end
90
+ end
91
+
92
+ run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
93
+ end
94
+ end
95
+
96
+ desc "rollback [VERSION]", "Rollback app to VERSION"
97
+ def rollback(version)
98
+ rolled_back = false
99
+
100
+ modify do
101
+ runtime = print_runtime do
102
+ modify(lock: true) do
103
+ invoke_options = deploy_options
104
+
105
+ KAMAL.config.version = version
106
+
107
+ if container_available?(version)
108
+ run_hook "pre-deploy", secrets: true
109
+
110
+ invoke "kamal:cli:app:boot", [], invoke_options.merge(version: version)
111
+ rolled_back = true
112
+ else
113
+ say "The app version '#{version}' is not available as a container (use 'kamal app containers' for available versions)", :red
114
+ end
115
+ end
116
+ end
117
+
118
+ run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s if rolled_back
119
+ end
120
+ end
121
+
122
+ desc "details", "Show details about all containers"
123
+ def details
124
+ invoke "kamal:cli:proxy:details"
125
+ invoke "kamal:cli:app:details"
126
+ invoke "kamal:cli:accessory:details", [ "all" ]
127
+ end
128
+
129
+ desc "audit", "Show audit log from servers"
130
+ def audit
131
+ quiet = options[:quiet]
132
+ on(KAMAL.hosts) do |host|
133
+ puts_by_host host, capture_with_info(*KAMAL.auditor.reveal), quiet: quiet
134
+ end
135
+ end
136
+
137
+ desc "config", "Show combined config (including secrets!)"
138
+ def config
139
+ run_locally do
140
+ puts Kamal::Utils.redacted(KAMAL.config.to_h).to_yaml
141
+ end
142
+ end
143
+
144
+ desc "docs [SECTION]", "Show Kamal configuration documentation"
145
+ def docs(section = nil)
146
+ case section
147
+ when NilClass
148
+ puts Kamal::Configuration.validation_doc
149
+ else
150
+ puts Kamal::Configuration.const_get(section.titlecase.to_sym).validation_doc
151
+ end
152
+ rescue NameError
153
+ puts "No documentation found for #{section}"
154
+ end
155
+
156
+ desc "init", "Create config stub in config/deploy.yml and secrets stub in .kamal"
157
+ option :bundle, type: :boolean, default: false, desc: "Add Kamal to the Gemfile and create a bin/kamal binstub"
158
+ def init
159
+ require "fileutils"
160
+
161
+ if (deploy_file = Pathname.new(File.expand_path("config/deploy.yml"))).exist?
162
+ puts "Config file already exists in config/deploy.yml (remove first to create a new one)"
163
+ else
164
+ FileUtils.mkdir_p deploy_file.dirname
165
+ FileUtils.cp_r Pathname.new(File.expand_path("templates/deploy.yml", __dir__)), deploy_file
166
+ puts "Created configuration file in config/deploy.yml"
167
+ end
168
+
169
+ unless (secrets_file = Pathname.new(File.expand_path(".kamal/secrets"))).exist?
170
+ FileUtils.mkdir_p secrets_file.dirname
171
+ FileUtils.cp_r Pathname.new(File.expand_path("templates/secrets", __dir__)), secrets_file
172
+ puts "Created .kamal/secrets file"
173
+ end
174
+
175
+ unless (hooks_dir = Pathname.new(File.expand_path(".kamal/hooks"))).exist?
176
+ hooks_dir.mkpath
177
+ Pathname.new(File.expand_path("templates/sample_hooks", __dir__)).each_child do |sample_hook|
178
+ FileUtils.cp sample_hook, hooks_dir, preserve: true
179
+ end
180
+ puts "Created sample hooks in .kamal/hooks"
181
+ end
182
+
183
+ if options[:bundle]
184
+ if (binstub = Pathname.new(File.expand_path("bin/kamal"))).exist?
185
+ puts "Binstub already exists in bin/kamal (remove first to create a new one)"
186
+ else
187
+ puts "Adding Kamal to Gemfile and bundle..."
188
+ run_locally do
189
+ execute :bundle, :add, :kamal
190
+ execute :bundle, :binstubs, :kamal
191
+ end
192
+ puts "Created binstub file in bin/kamal"
193
+ end
194
+ end
195
+ end
196
+
197
+ desc "remove", "Remove kamal-proxy, app, accessories, and registry session from servers"
198
+ option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
199
+ def remove
200
+ confirming "This will remove all containers and images. Are you sure?" do
201
+ modify(lock: true) do
202
+ invoke "kamal:cli:app:remove", [], options.without(:confirmed)
203
+ invoke "kamal:cli:proxy:remove", [], options.without(:confirmed)
204
+ invoke "kamal:cli:accessory:remove", [ "all" ], options
205
+ invoke "kamal:cli:registry:remove", [], options.without(:confirmed).merge(skip_local: true)
206
+ end
207
+ end
208
+ end
209
+
210
+ desc "upgrade", "Upgrade from Kamal 1.x to 2.0"
211
+ option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
212
+ option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
213
+ def upgrade
214
+ confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
215
+ modify(lock: true) do
216
+ if options[:rolling]
217
+ KAMAL.hosts.each do |host|
218
+ KAMAL.with_specific_hosts(host) do
219
+ say "Upgrading #{host}...", :magenta
220
+ if KAMAL.app_hosts.include?(host)
221
+ invoke "kamal:cli:proxy:upgrade", [], options.merge(confirmed: true, rolling: false)
222
+ reset_invocation(Kamal::Cli::Proxy)
223
+ end
224
+ if KAMAL.accessory_hosts.include?(host)
225
+ invoke "kamal:cli:accessory:upgrade", [ "all" ], options.merge(confirmed: true, rolling: false)
226
+ reset_invocation(Kamal::Cli::Accessory)
227
+ end
228
+ say "Upgraded #{host}", :magenta
229
+ end
230
+ end
231
+ else
232
+ say "Upgrading all hosts...", :magenta
233
+ invoke "kamal:cli:proxy:upgrade", [], options.merge(confirmed: true)
234
+ invoke "kamal:cli:accessory:upgrade", [ "all" ], options.merge(confirmed: true)
235
+ say "Upgraded all hosts", :magenta
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ desc "version", "Show Kamal version"
242
+ def version
243
+ puts Kamal::VERSION
244
+ end
245
+
246
+ desc "accessory", "Manage accessories (db/redis/search)"
247
+ subcommand "accessory", Kamal::Cli::Accessory
248
+
249
+ desc "app", "Manage application"
250
+ subcommand "app", Kamal::Cli::App
251
+
252
+ desc "build", "Build application image"
253
+ subcommand "build", Kamal::Cli::Build
254
+
255
+ desc "lock", "Manage the deploy lock"
256
+ subcommand "lock", Kamal::Cli::Lock
257
+
258
+ desc "proxy", "Manage kamal-proxy"
259
+ subcommand "proxy", Kamal::Cli::Proxy
260
+
261
+ desc "prune", "Prune old application images and containers"
262
+ subcommand "prune", Kamal::Cli::Prune
263
+
264
+ desc "registry", "Login and -out of the image registry"
265
+ subcommand "registry", Kamal::Cli::Registry
266
+
267
+ desc "secrets", "Helpers for extracting secrets"
268
+ subcommand "secrets", Kamal::Cli::Secrets
269
+
270
+ desc "server", "Bootstrap servers with curl and Docker"
271
+ subcommand "server", Kamal::Cli::Server
272
+
273
+ private
274
+ def container_available?(version)
275
+ begin
276
+ on(KAMAL.app_hosts) do
277
+ KAMAL.roles_on(host).each do |role|
278
+ container_id = capture_with_info(*KAMAL.app(role: role, host: host).container_id_for_version(version))
279
+ raise "Container not found" unless container_id.present?
280
+ end
281
+ end
282
+ rescue SSHKit::Runner::ExecuteError, SSHKit::Runner::MultipleExecuteError => e
283
+ if e.message =~ /Container not found/
284
+ say "Error looking for container version #{version}: #{e.message}"
285
+ return false
286
+ else
287
+ raise
288
+ end
289
+ end
290
+
291
+ true
292
+ end
293
+
294
+ def deploy_options
295
+ base_options = options.without("skip_push")
296
+ base_options = base_options.except("no_cache") unless base_options["no_cache"]
297
+ { "version" => KAMAL.config.version }.merge(base_options)
298
+ end
299
+ end