cpl 1.2.0 → 1.4.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check_cpln_links.yml +19 -0
  3. data/.overcommit.yml +3 -0
  4. data/CHANGELOG.md +43 -1
  5. data/Gemfile.lock +9 -5
  6. data/README.md +43 -7
  7. data/cpl.gemspec +1 -0
  8. data/docs/commands.md +30 -23
  9. data/docs/dns.md +9 -0
  10. data/docs/tips.md +11 -1
  11. data/examples/controlplane.yml +22 -1
  12. data/lib/command/apply_template.rb +58 -10
  13. data/lib/command/base.rb +79 -2
  14. data/lib/command/build_image.rb +5 -1
  15. data/lib/command/cleanup_stale_apps.rb +0 -2
  16. data/lib/command/copy_image_from_upstream.rb +5 -4
  17. data/lib/command/deploy_image.rb +20 -2
  18. data/lib/command/info.rb +11 -26
  19. data/lib/command/maintenance.rb +8 -4
  20. data/lib/command/maintenance_off.rb +8 -4
  21. data/lib/command/maintenance_on.rb +8 -4
  22. data/lib/command/promote_app_from_upstream.rb +5 -25
  23. data/lib/command/run.rb +20 -22
  24. data/lib/command/run_detached.rb +38 -30
  25. data/lib/command/setup_app.rb +19 -2
  26. data/lib/core/config.rb +36 -14
  27. data/lib/core/controlplane.rb +34 -7
  28. data/lib/core/controlplane_api.rb +12 -0
  29. data/lib/core/controlplane_api_direct.rb +33 -5
  30. data/lib/core/helpers.rb +6 -0
  31. data/lib/cpl/version.rb +1 -1
  32. data/lib/cpl.rb +6 -1
  33. data/lib/generator_templates/controlplane.yml +5 -0
  34. data/lib/generator_templates/templates/gvc.yml +4 -4
  35. data/lib/generator_templates/templates/postgres.yml +1 -1
  36. data/lib/generator_templates/templates/rails.yml +1 -1
  37. data/script/check_cpln_links +45 -0
  38. data/templates/daily-task.yml +3 -2
  39. data/templates/gvc.yml +5 -5
  40. data/templates/identity.yml +2 -1
  41. data/templates/rails.yml +3 -2
  42. data/templates/secrets-policy.yml +4 -0
  43. data/templates/secrets.yml +3 -0
  44. data/templates/sidekiq.yml +3 -2
  45. metadata +21 -2
data/lib/command/base.rb CHANGED
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../core/helpers"
4
+
3
5
  module Command
4
6
  class Base # rubocop:disable Metrics/ClassLength
5
7
  attr_reader :config
6
8
 
9
+ include Helpers
10
+
7
11
  # Used to call the command (`cpl NAME`)
8
12
  # NAME = ""
9
13
  # Displayed when running `cpl help` or `cpl help NAME` (defaults to `NAME`)
@@ -15,6 +19,9 @@ module Command
15
19
  DEFAULT_ARGS = [].freeze
16
20
  # Options for the command (use option methods below)
17
21
  OPTIONS = [].freeze
22
+ # Does not throw error if `true` and extra options
23
+ # that are not specified in `OPTIONS` are passed to the command
24
+ ACCEPTS_EXTRA_OPTIONS = false
18
25
  # Displayed when running `cpl help`
19
26
  # DESCRIPTION = ""
20
27
  # Displayed when running `cpl help NAME`
@@ -122,6 +129,18 @@ module Command
122
129
  }
123
130
  end
124
131
 
132
+ def self.domain_option(required: false)
133
+ {
134
+ name: :domain,
135
+ params: {
136
+ banner: "DOMAIN_NAME",
137
+ desc: "Domain name",
138
+ type: :string,
139
+ required: required
140
+ }
141
+ }
142
+ end
143
+
125
144
  def self.upstream_token_option(required: false)
126
145
  {
127
146
  name: :upstream_token,
@@ -218,6 +237,40 @@ module Command
218
237
  }
219
238
  end
220
239
 
240
+ def self.clean_on_failure_option(required: false)
241
+ {
242
+ name: :clean_on_failure,
243
+ params: {
244
+ desc: "Deletes workload when finished with failure (success always deletes)",
245
+ type: :boolean,
246
+ required: required,
247
+ default: true
248
+ }
249
+ }
250
+ end
251
+
252
+ def self.skip_secret_access_binding_option(required: false)
253
+ {
254
+ name: :skip_secret_access_binding,
255
+ params: {
256
+ desc: "Skips secret access binding",
257
+ type: :boolean,
258
+ required: required
259
+ }
260
+ }
261
+ end
262
+
263
+ def self.run_release_phase_option(required: false)
264
+ {
265
+ name: :run_release_phase,
266
+ params: {
267
+ desc: "Runs release phase",
268
+ type: :boolean,
269
+ required: required
270
+ }
271
+ }
272
+ end
273
+
221
274
  def self.all_options
222
275
  methods.grep(/_option$/).map { |method| send(method.to_s) }
223
276
  end
@@ -341,8 +394,32 @@ module Command
341
394
  @cp ||= Controlplane.new(config)
342
395
  end
343
396
 
344
- def perform(cmd)
345
- system(cmd) || exit(false)
397
+ def perform!(cmd)
398
+ system(cmd) || exit(1)
399
+ end
400
+
401
+ def app_location_link
402
+ "/org/#{config.org}/location/#{config.location}"
403
+ end
404
+
405
+ def app_image_link
406
+ "/org/#{config.org}/image/#{latest_image}"
407
+ end
408
+
409
+ def app_identity
410
+ "#{config.app}-identity"
411
+ end
412
+
413
+ def app_identity_link
414
+ "/org/#{config.org}/gvc/#{config.app}/identity/#{app_identity}"
415
+ end
416
+
417
+ def app_secrets
418
+ "#{config.app_prefix}-secrets"
419
+ end
420
+
421
+ def app_secrets_policy
422
+ "#{app_secrets}-policy"
346
423
  end
347
424
 
348
425
  private
@@ -7,12 +7,14 @@ module Command
7
7
  app_option(required: true),
8
8
  commit_option
9
9
  ].freeze
10
+ ACCEPTS_EXTRA_OPTIONS = true
10
11
  DESCRIPTION = "Builds and pushes the image to Control Plane"
11
12
  LONG_DESCRIPTION = <<~DESC
12
13
  - Builds and pushes the image to Control Plane
13
14
  - Automatically assigns image numbers, e.g., `app:1`, `app:2`, etc.
14
15
  - Uses `.controlplane/Dockerfile` or a different Dockerfile specified through `dockerfile` in the `.controlplane/controlplane.yml` file
15
16
  - If a commit is provided through `--commit` or `-c`, it will be set as the runtime env var `GIT_COMMIT`
17
+ - Accepts extra options that are passed to `docker build`
16
18
  DESC
17
19
 
18
20
  def call # rubocop:disable Metrics/MethodLength
@@ -32,7 +34,9 @@ module Command
32
34
  build_args = []
33
35
  build_args.push("GIT_COMMIT=#{commit}") if commit
34
36
 
35
- cp.image_build(image_url, dockerfile: dockerfile, build_args: build_args)
37
+ cp.image_build(image_url, dockerfile: dockerfile,
38
+ docker_args: config.args,
39
+ build_args: build_args)
36
40
 
37
41
  progress.puts("\nPushed image to '/org/#{config.org}/image/#{image_name}'.")
38
42
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "date"
4
-
5
3
  module Command
6
4
  class CleanupStaleApps < Base
7
5
  NAME = "cleanup-stale-apps"
@@ -11,7 +11,7 @@ module Command
11
11
  DESCRIPTION = "Copies an image (by default the latest) from a source org to the current org"
12
12
  LONG_DESCRIPTION = <<~DESC
13
13
  - Copies an image (by default the latest) from a source org to the current org
14
- - The source org must be specified through `upstream` in the `.controlplane/controlplane.yml` file
14
+ - The source app must be specified either through the `CPLN_UPSTREAM` env var or `upstream` in the `.controlplane/controlplane.yml` file
15
15
  - Additionally, the token for the source org must be provided through `--upstream-token` or `-t`
16
16
  - A `cpln` profile will be temporarily created to pull the image from the source org
17
17
  DESC
@@ -28,8 +28,8 @@ module Command
28
28
  def call # rubocop:disable Metrics/MethodLength
29
29
  ensure_docker_running!
30
30
 
31
- @upstream = config[:upstream]
32
- @upstream_org = config.apps[@upstream.to_sym][:cpln_org] || ENV.fetch("CPLN_ORG_UPSTREAM", nil)
31
+ @upstream = ENV.fetch("CPLN_UPSTREAM", nil) || config[:upstream]
32
+ @upstream_org = ENV.fetch("CPLN_ORG_UPSTREAM", nil) || config.find_app_config(@upstream)&.dig(:cpln_org)
33
33
  ensure_upstream_org!
34
34
 
35
35
  create_upstream_profile
@@ -38,6 +38,7 @@ module Command
38
38
  pull_image_from_upstream
39
39
  push_image_to_app
40
40
  ensure
41
+ cp.profile_switch("default")
41
42
  delete_upstream_profile
42
43
  end
43
44
 
@@ -60,7 +61,7 @@ module Command
60
61
  def create_upstream_profile
61
62
  step("Creating upstream profile") do
62
63
  loop do
63
- @upstream_profile = "upstream-#{rand(1000..9999)}"
64
+ @upstream_profile = "upstream-#{random_four_digits}"
64
65
  break unless cp.profile_exists?(@upstream_profile)
65
66
  end
66
67
 
@@ -4,14 +4,19 @@ module Command
4
4
  class DeployImage < Base
5
5
  NAME = "deploy-image"
6
6
  OPTIONS = [
7
- app_option(required: true)
7
+ app_option(required: true),
8
+ run_release_phase_option
8
9
  ].freeze
9
- DESCRIPTION = "Deploys the latest image to app workloads"
10
+ DESCRIPTION = "Deploys the latest image to app workloads, and runs a release script (optional)"
10
11
  LONG_DESCRIPTION = <<~DESC
11
12
  - Deploys the latest image to app workloads
13
+ - Optionally runs a release script before deploying if specified through `release_script` in the `.controlplane/controlplane.yml` file and `--run-release-phase` is provided
14
+ - The deploy will fail if the release script exits with a non-zero code or doesn't exist
12
15
  DESC
13
16
 
14
17
  def call # rubocop:disable Metrics/MethodLength
18
+ run_release_script if config.options[:run_release_phase]
19
+
15
20
  deployed_endpoints = {}
16
21
 
17
22
  image = latest_image
@@ -34,5 +39,18 @@ module Command
34
39
  progress.puts(" - #{workload}: #{endpoint}")
35
40
  end
36
41
  end
42
+
43
+ private
44
+
45
+ def run_release_script
46
+ release_script_name = config[:release_script]
47
+ release_script_path = Pathname.new("#{config.app_cpln_dir}/#{release_script_name}").expand_path
48
+
49
+ raise "Can't find release script in '#{release_script_path}'." unless File.exist?(release_script_path)
50
+
51
+ progress.puts("Running release script...\n\n")
52
+ perform!("bash #{release_script_path}")
53
+ progress.puts
54
+ end
37
55
  end
38
56
  end
data/lib/command/info.rb CHANGED
@@ -32,7 +32,7 @@ module Command
32
32
  @missing_apps_workloads = {}
33
33
  @missing_apps_starting_with = {}
34
34
 
35
- if config.app && !config.current[:match_if_app_name_starts_with]
35
+ if config.app && !config.should_app_start_with?(config.app)
36
36
  single_app_info
37
37
  else
38
38
  multiple_apps_info
@@ -41,20 +41,8 @@ module Command
41
41
 
42
42
  private
43
43
 
44
- def app_matches?(app, app_name, app_options)
45
- app == app_name.to_s || (app_options[:match_if_app_name_starts_with] && app.start_with?(app_name.to_s))
46
- end
47
-
48
- def find_app_options(app)
49
- @app_options ||= {}
50
- @app_options[app] ||= config.apps.find do |app_name, app_options|
51
- app_matches?(app, app_name, app_options)
52
- end&.last
53
- end
54
-
55
44
  def find_workloads(app)
56
- app_options = find_app_options(app)
57
- return [] if app_options.nil?
45
+ app_options = config.find_app_config(app)
58
46
 
59
47
  (app_options[:app_workloads] + app_options[:additional_workloads] + [app_options[:one_off_workload]]).uniq
60
48
  end
@@ -75,21 +63,19 @@ module Command
75
63
  end
76
64
 
77
65
  if config.app
78
- result.select { |app, _| app_matches?(app, config.app, config.current) }
66
+ result.select { |app, _| config.app_matches?(app, config.app, config.current) }
79
67
  else
80
- result.reject { |app, _| find_app_options(app).nil? }
68
+ result.reject { |app, _| config.find_app_config(app).nil? }
81
69
  end
82
70
  end
83
71
 
84
- def orgs # rubocop:disable Metrics/MethodLength
72
+ def orgs
85
73
  result = []
86
74
 
87
75
  if config.org
88
76
  result.push(config.org)
89
77
  else
90
- config.apps.each do |app_name, app_options|
91
- next if config.app && !app_matches?(config.app, app_name, app_options)
92
-
78
+ config.apps.each do |_, app_options|
93
79
  org = app_options[:cpln_org]
94
80
  result.push(org) if org && !result.include?(org)
95
81
  end
@@ -102,7 +88,7 @@ module Command
102
88
  result = []
103
89
 
104
90
  config.apps.each do |app_name, app_options|
105
- next if config.app && !app_matches?(config.app, app_name, app_options)
91
+ next if config.app && !config.app_matches?(config.app, app_name, app_options)
106
92
 
107
93
  app_org = app_options[:cpln_org]
108
94
  result.push(app_name.to_s) if app_org == org
@@ -113,7 +99,7 @@ module Command
113
99
  end
114
100
 
115
101
  def any_app_starts_with?(app)
116
- @app_workloads.keys.find { |app_name| app_matches?(app_name, app, config.apps[app.to_sym]) }
102
+ @app_workloads.keys.find { |app_name| config.app_matches?(app_name, app, config.apps[app.to_sym]) }
117
103
  end
118
104
 
119
105
  def check_any_app_starts_with(app)
@@ -184,8 +170,7 @@ module Command
184
170
  "(replace 'whatever' with whatever suffix you want):"
185
171
 
186
172
  @missing_apps_starting_with.each do |app, _workloads|
187
- app_with_suffix = "#{app}#{app.end_with?('-') ? '' : '-'}whatever"
188
- puts " - `cpl setup-app -a #{app_with_suffix}`"
173
+ puts " - `cpl setup-app -a #{app}-whatever`"
189
174
  end
190
175
  end
191
176
 
@@ -197,7 +182,7 @@ module Command
197
182
  @defined_workloads = find_workloads(config.app)
198
183
  @available_workloads = fetch_workloads(config.app)
199
184
 
200
- workloads = (@defined_workloads + @available_workloads).uniq.sort
185
+ workloads = (@defined_workloads + @available_workloads).uniq
201
186
  workloads.each do |workload|
202
187
  print_workload(config.app, workload)
203
188
  end
@@ -217,7 +202,7 @@ module Command
217
202
  @defined_workloads = find_workloads(app)
218
203
  @available_workloads = @app_workloads[app] || []
219
204
 
220
- workloads = (@defined_workloads + @available_workloads).uniq.sort
205
+ workloads = (@defined_workloads + @available_workloads).uniq
221
206
  workloads.each do |workload|
222
207
  print_workload(app, workload)
223
208
  end
@@ -4,7 +4,8 @@ module Command
4
4
  class Maintenance < Base
5
5
  NAME = "maintenance"
6
6
  OPTIONS = [
7
- app_option(required: true)
7
+ app_option(required: true),
8
+ domain_option
8
9
  ].freeze
9
10
  DESCRIPTION = "Checks if maintenance mode is on or off for an app"
10
11
  LONG_DESCRIPTION = <<~DESC
@@ -20,15 +21,18 @@ module Command
20
21
  one_off_workload = config[:one_off_workload]
21
22
  maintenance_workload = config.current[:maintenance_workload] || "maintenance"
22
23
 
23
- domain_data = cp.find_domain_for([one_off_workload, maintenance_workload])
24
+ domain_data = if config.domain
25
+ cp.fetch_domain(config.domain)
26
+ else
27
+ cp.find_domain_for([one_off_workload, maintenance_workload])
28
+ end
24
29
  unless domain_data
25
30
  raise "Can't find domain. " \
26
31
  "Maintenance mode is only supported for domains that use path based routing mode " \
27
32
  "and have a route configured for the prefix '/' on either port 80 or 443."
28
33
  end
29
34
 
30
- domain_workload = cp.get_domain_workload(domain_data)
31
- if domain_workload == maintenance_workload
35
+ if cp.domain_workload_matches?(domain_data, maintenance_workload)
32
36
  puts "on"
33
37
  else
34
38
  puts "off"
@@ -4,7 +4,8 @@ module Command
4
4
  class MaintenanceOff < Base
5
5
  NAME = "maintenance:off"
6
6
  OPTIONS = [
7
- app_option(required: true)
7
+ app_option(required: true),
8
+ domain_option
8
9
  ].freeze
9
10
  DESCRIPTION = "Disables maintenance mode for an app"
10
11
  LONG_DESCRIPTION = <<~DESC
@@ -18,7 +19,11 @@ module Command
18
19
  one_off_workload = config[:one_off_workload]
19
20
  maintenance_workload = config.current[:maintenance_workload] || "maintenance"
20
21
 
21
- domain_data = cp.find_domain_for([one_off_workload, maintenance_workload])
22
+ domain_data = if config.domain
23
+ cp.fetch_domain(config.domain)
24
+ else
25
+ cp.find_domain_for([one_off_workload, maintenance_workload])
26
+ end
22
27
  unless domain_data
23
28
  raise "Can't find domain. " \
24
29
  "Maintenance mode is only supported for domains that use path based routing mode " \
@@ -26,8 +31,7 @@ module Command
26
31
  end
27
32
 
28
33
  domain = domain_data["name"]
29
- domain_workload = cp.get_domain_workload(domain_data)
30
- if domain_workload == one_off_workload
34
+ if cp.domain_workload_matches?(domain_data, one_off_workload)
31
35
  progress.puts("Maintenance mode is already disabled for app '#{config.app}'.")
32
36
  return
33
37
  end
@@ -4,7 +4,8 @@ module Command
4
4
  class MaintenanceOn < Base
5
5
  NAME = "maintenance:on"
6
6
  OPTIONS = [
7
- app_option(required: true)
7
+ app_option(required: true),
8
+ domain_option
8
9
  ].freeze
9
10
  DESCRIPTION = "Enables maintenance mode for an app"
10
11
  LONG_DESCRIPTION = <<~DESC
@@ -18,7 +19,11 @@ module Command
18
19
  one_off_workload = config[:one_off_workload]
19
20
  maintenance_workload = config.current[:maintenance_workload] || "maintenance"
20
21
 
21
- domain_data = cp.find_domain_for([one_off_workload, maintenance_workload])
22
+ domain_data = if config.domain
23
+ cp.fetch_domain(config.domain)
24
+ else
25
+ cp.find_domain_for([one_off_workload, maintenance_workload])
26
+ end
22
27
  unless domain_data
23
28
  raise "Can't find domain. " \
24
29
  "Maintenance mode is only supported for domains that use path based routing mode " \
@@ -26,8 +31,7 @@ module Command
26
31
  end
27
32
 
28
33
  domain = domain_data["name"]
29
- domain_workload = cp.get_domain_workload(domain_data)
30
- if domain_workload == maintenance_workload
34
+ if cp.domain_workload_matches?(domain_data, maintenance_workload)
31
35
  progress.puts("Maintenance mode is already enabled for app '#{config.app}'.")
32
36
  return
33
37
  end
@@ -12,47 +12,27 @@ module Command
12
12
  - Copies the latest image from upstream, runs a release script (optional), and deploys the image
13
13
  - It performs the following steps:
14
14
  - Runs `cpl copy-image-from-upstream` to copy the latest image from upstream
15
- - Runs a release script if specified through `release_script` in the `.controlplane/controlplane.yml` file
16
15
  - Runs `cpl deploy-image` to deploy the image
16
+ - If `.controlplane/controlplane.yml` includes the `release_script`, `cpl deploy-image` will use the `--run-release-phase` option
17
+ - The deploy will fail if the release script exits with a non-zero code
17
18
  DESC
18
19
 
19
20
  def call
20
- check_release_script
21
21
  copy_image_from_upstream
22
- run_release_script
23
22
  deploy_image
24
23
  end
25
24
 
26
25
  private
27
26
 
28
- def check_release_script
29
- release_script_name = config.current[:release_script]
30
- unless release_script_name
31
- progress.puts("Can't find option 'release_script' for app '#{config.app}' in 'controlplane.yml'. " \
32
- "Skipping release script.\n\n")
33
- return
34
- end
35
-
36
- @release_script_path = Pathname.new("#{config.app_cpln_dir}/#{release_script_name}").expand_path
37
-
38
- raise "Can't find release script in '#{@release_script_path}'." unless File.exist?(@release_script_path)
39
- end
40
-
41
27
  def copy_image_from_upstream
42
28
  Cpl::Cli.start(["copy-image-from-upstream", "-a", config.app, "-t", config.options[:upstream_token]])
43
29
  progress.puts
44
30
  end
45
31
 
46
- def run_release_script
47
- return unless @release_script_path
48
-
49
- progress.puts("Running release script...\n\n")
50
- perform("bash #{@release_script_path}")
51
- progress.puts
52
- end
53
-
54
32
  def deploy_image
55
- Cpl::Cli.start(["deploy-image", "-a", config.app])
33
+ args = []
34
+ args.push("--run-release-phase") if config.current[:release_script]
35
+ Cpl::Cli.start(["deploy-image", "-a", config.app, *args])
56
36
  end
57
37
  end
58
38
  end
data/lib/command/run.rb CHANGED
@@ -29,56 +29,53 @@ module Command
29
29
  cpl run -a $APP_NAME
30
30
 
31
31
  # Need to quote COMMAND if setting ENV value or passing args.
32
- cpl run 'LOG_LEVEL=warn rails db:migrate' -a $APP_NAME
33
-
34
- # COMMAND may also be passed at the end.
35
32
  cpl run -a $APP_NAME -- 'LOG_LEVEL=warn rails db:migrate'
36
33
 
37
34
  # Runs command, displays output, and exits shell.
38
- cpl run ls / -a $APP_NAME
39
- cpl run rails db:migrate:status -a $APP_NAME
35
+ cpl run -a $APP_NAME -- ls /
36
+ cpl run -a $APP_NAME -- rails db:migrate:status
40
37
 
41
38
  # Runs command and keeps shell open.
42
- cpl run rails c -a $APP_NAME
39
+ cpl run -a $APP_NAME -- rails c
43
40
 
44
41
  # Uses a different image (which may not be promoted yet).
45
- cpl run rails db:migrate -a $APP_NAME --image appimage:123 # Exact image name
46
- cpl run rails db:migrate -a $APP_NAME --image latest # Latest sequential image
42
+ cpl run -a $APP_NAME --image appimage:123 -- rails db:migrate # Exact image name
43
+ cpl run -a $APP_NAME --image latest -- rails db:migrate # Latest sequential image
47
44
 
48
45
  # Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
49
- cpl run bash -a $APP_NAME -w other-workload
46
+ cpl run -a $APP_NAME -w other-workload -- bash
50
47
 
51
48
  # Overrides remote CPLN_TOKEN env variable with local token.
52
49
  # Useful when superuser rights are needed in remote container.
53
- cpl run bash -a $APP_NAME --use-local-token
50
+ cpl run -a $APP_NAME --use-local-token -- bash
54
51
  ```
55
52
  EX
56
53
 
57
- attr_reader :location, :workload, :one_off, :container
54
+ attr_reader :location, :workload_to_clone, :workload_clone, :container
58
55
 
59
56
  def call # rubocop:disable Metrics/MethodLength
60
57
  @location = config.location
61
- @workload = config.options["workload"] || config[:one_off_workload]
62
- @one_off = "#{workload}-run-#{rand(1000..9999)}"
58
+ @workload_to_clone = config.options["workload"] || config[:one_off_workload]
59
+ @workload_clone = "#{workload_to_clone}-run-#{random_four_digits}"
63
60
 
64
- step("Cloning workload '#{workload}' on app '#{config.options[:app]}' to '#{one_off}'") do
61
+ step("Cloning workload '#{workload_to_clone}' on app '#{config.options[:app]}' to '#{workload_clone}'") do
65
62
  clone_workload
66
63
  end
67
64
 
68
- wait_for_workload(one_off)
69
- wait_for_replica(one_off, location)
65
+ wait_for_workload(workload_clone)
66
+ wait_for_replica(workload_clone, location)
70
67
  run_in_replica
71
68
  ensure
72
69
  progress.puts
73
- ensure_workload_deleted(one_off)
70
+ ensure_workload_deleted(workload_clone)
74
71
  end
75
72
 
76
73
  private
77
74
 
78
75
  def clone_workload # rubocop:disable Metrics/MethodLength
79
76
  # Create a base copy of workload props
80
- spec = cp.fetch_workload!(workload).fetch("spec")
81
- container_spec = spec["containers"].detect { _1["name"] == workload } || spec["containers"].first
77
+ spec = cp.fetch_workload!(workload_to_clone).fetch("spec")
78
+ container_spec = spec["containers"].detect { _1["name"] == workload_to_clone } || spec["containers"].first
82
79
  @container = container_spec["name"]
83
80
 
84
81
  # remove other containers if any
@@ -107,11 +104,12 @@ module Command
107
104
  container_spec["env"] << { "name" => "CONTROLPLANE_RUNNER", "value" => runner_script }
108
105
 
109
106
  if config.options["use_local_token"]
110
- container_spec["env"] << { "name" => "CONTROLPLANE_TOKEN", "value" => ControlplaneApiDirect.new.api_token }
107
+ container_spec["env"] << { "name" => "CONTROLPLANE_TOKEN",
108
+ "value" => ControlplaneApiDirect.new.api_token[:token] }
111
109
  end
112
110
 
113
111
  # Create workload clone
114
- cp.apply_hash("kind" => "workload", "name" => one_off, "spec" => spec)
112
+ cp.apply_hash("kind" => "workload", "name" => workload_clone, "spec" => spec)
115
113
  end
116
114
 
117
115
  def runner_script # rubocop:disable Metrics/MethodLength
@@ -141,7 +139,7 @@ module Command
141
139
  def run_in_replica
142
140
  progress.puts("Connecting...\n\n")
143
141
  command = %(bash -c 'eval "$CONTROLPLANE_RUNNER"')
144
- cp.workload_exec(one_off, location: location, container: container, command: command)
142
+ cp.workload_exec(workload_clone, location: location, container: container, command: command)
145
143
  end
146
144
  end
147
145
  end