cpl 1.4.0 → 2.0.0.rc.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/command_docs.yml +1 -1
  3. data/.github/workflows/rspec-shared.yml +56 -0
  4. data/.github/workflows/rspec.yml +19 -31
  5. data/.github/workflows/rubocop.yml +2 -10
  6. data/.gitignore +2 -0
  7. data/.simplecov_spawn.rb +10 -0
  8. data/CHANGELOG.md +8 -0
  9. data/CONTRIBUTING.md +32 -2
  10. data/Gemfile.lock +34 -29
  11. data/README.md +34 -25
  12. data/cpl.gemspec +1 -1
  13. data/docs/commands.md +54 -54
  14. data/docs/dns.md +6 -0
  15. data/docs/migrating.md +10 -10
  16. data/docs/tips.md +12 -10
  17. data/examples/circleci.yml +3 -3
  18. data/examples/controlplane.yml +25 -16
  19. data/lib/command/apply_template.rb +9 -9
  20. data/lib/command/base.rb +132 -37
  21. data/lib/command/build_image.rb +4 -9
  22. data/lib/command/cleanup_stale_apps.rb +1 -1
  23. data/lib/command/copy_image_from_upstream.rb +0 -7
  24. data/lib/command/delete.rb +39 -7
  25. data/lib/command/deploy_image.rb +18 -3
  26. data/lib/command/exists.rb +1 -1
  27. data/lib/command/generate.rb +1 -1
  28. data/lib/command/info.rb +7 -3
  29. data/lib/command/logs.rb +22 -2
  30. data/lib/command/maintenance_off.rb +1 -1
  31. data/lib/command/maintenance_on.rb +1 -1
  32. data/lib/command/open.rb +2 -2
  33. data/lib/command/open_console.rb +2 -2
  34. data/lib/command/ps.rb +1 -1
  35. data/lib/command/ps_start.rb +2 -1
  36. data/lib/command/ps_stop.rb +40 -8
  37. data/lib/command/ps_wait.rb +3 -2
  38. data/lib/command/run.rb +430 -69
  39. data/lib/command/setup_app.rb +4 -1
  40. data/lib/constants/exit_code.rb +7 -0
  41. data/lib/core/config.rb +1 -1
  42. data/lib/core/controlplane.rb +109 -48
  43. data/lib/core/controlplane_api.rb +7 -1
  44. data/lib/core/controlplane_api_cli.rb +3 -3
  45. data/lib/core/controlplane_api_direct.rb +1 -1
  46. data/lib/core/shell.rb +15 -9
  47. data/lib/cpl/version.rb +1 -1
  48. data/lib/cpl.rb +48 -9
  49. data/lib/deprecated_commands.json +2 -1
  50. data/lib/generator_templates/controlplane.yml +2 -2
  51. data/script/check_cpln_links +3 -3
  52. data/templates/{gvc.yml → app.yml} +5 -0
  53. data/templates/secrets.yml +8 -0
  54. metadata +23 -26
  55. data/.rspec +0 -1
  56. data/lib/command/run_cleanup.rb +0 -116
  57. data/lib/command/run_detached.rb +0 -176
  58. data/lib/core/scripts.rb +0 -34
  59. data/templates/identity.yml +0 -3
  60. data/templates/secrets-policy.yml +0 -4
  61. /data/lib/generator_templates/templates/{gvc.yml → app.yml} +0 -0
data/lib/command/base.rb CHANGED
@@ -51,6 +51,7 @@ module Command
51
51
  [org_option, verbose_option, trace_option]
52
52
  end
53
53
 
54
+ # rubocop:disable Metrics/MethodLength
54
55
  def self.org_option(required: false)
55
56
  {
56
57
  name: :org,
@@ -90,6 +91,19 @@ module Command
90
91
  }
91
92
  end
92
93
 
94
+ def self.replica_option(required: false)
95
+ {
96
+ name: :replica,
97
+ params: {
98
+ aliases: ["-r"],
99
+ banner: "REPLICA_NAME",
100
+ desc: "Replica name",
101
+ type: :string,
102
+ required: required
103
+ }
104
+ }
105
+ end
106
+
93
107
  def self.image_option(required: false)
94
108
  {
95
109
  name: :image,
@@ -103,6 +117,20 @@ module Command
103
117
  }
104
118
  end
105
119
 
120
+ def self.log_method_option(required: false)
121
+ {
122
+ name: :log_method,
123
+ params: {
124
+ type: :numeric,
125
+ banner: "LOG_METHOD",
126
+ desc: "Log method",
127
+ required: required,
128
+ valid_values: [1, 2, 3],
129
+ default: 3
130
+ }
131
+ }
132
+ end
133
+
106
134
  def self.commit_option(required: false)
107
135
  {
108
136
  name: :commit,
@@ -198,7 +226,8 @@ module Command
198
226
  banner: "ROWS,COLS",
199
227
  desc: "Override remote terminal size (e.g. `--terminal-size 10,20`)",
200
228
  type: :string,
201
- required: required
229
+ required: required,
230
+ valid_regex: /^\d+,\d+$/
202
231
  }
203
232
  }
204
233
  end
@@ -237,66 +266,128 @@ module Command
237
266
  }
238
267
  end
239
268
 
240
- def self.clean_on_failure_option(required: false)
269
+ def self.skip_secret_access_binding_option(required: false)
241
270
  {
242
- name: :clean_on_failure,
271
+ name: :skip_secret_access_binding,
243
272
  params: {
244
- desc: "Deletes workload when finished with failure (success always deletes)",
273
+ desc: "Skips secret access binding",
245
274
  type: :boolean,
275
+ required: required
276
+ }
277
+ }
278
+ end
279
+
280
+ def self.run_release_phase_option(required: false)
281
+ {
282
+ name: :run_release_phase,
283
+ params: {
284
+ desc: "Runs release phase",
285
+ type: :boolean,
286
+ required: required
287
+ }
288
+ }
289
+ end
290
+
291
+ def self.logs_limit_option(required: false)
292
+ {
293
+ name: :limit,
294
+ params: {
295
+ banner: "NUMBER",
296
+ desc: "Limit on number of log entries to show",
297
+ type: :numeric,
246
298
  required: required,
247
- default: true
299
+ default: 200
248
300
  }
249
301
  }
250
302
  end
251
303
 
252
- def self.skip_secret_access_binding_option(required: false)
304
+ def self.logs_since_option(required: false)
253
305
  {
254
- name: :skip_secret_access_binding,
306
+ name: :since,
255
307
  params: {
256
- desc: "Skips secret access binding",
308
+ banner: "DURATION",
309
+ desc: "Loopback window for showing logs " \
310
+ "(see https://www.npmjs.com/package/parse-duration for the accepted formats, e.g., '1h')",
311
+ type: :string,
312
+ required: required,
313
+ default: "1h"
314
+ }
315
+ }
316
+ end
317
+
318
+ def self.interactive_option(required: false)
319
+ {
320
+ name: :interactive,
321
+ params: {
322
+ desc: "Runs interactive command",
257
323
  type: :boolean,
258
324
  required: required
259
325
  }
260
326
  }
261
327
  end
262
328
 
263
- def self.run_release_phase_option(required: false)
329
+ def self.detached_option(required: false)
264
330
  {
265
- name: :run_release_phase,
331
+ name: :detached,
266
332
  params: {
267
- desc: "Runs release phase",
333
+ desc: "Runs non-interactive command, detaches, and prints commands to log and stop the job",
268
334
  type: :boolean,
269
335
  required: required
270
336
  }
271
337
  }
272
338
  end
273
339
 
274
- def self.all_options
275
- methods.grep(/_option$/).map { |method| send(method.to_s) }
340
+ def self.cpu_option(required: false)
341
+ {
342
+ name: :cpu,
343
+ params: {
344
+ banner: "CPU",
345
+ desc: "Overrides CPU millicores " \
346
+ "(e.g., '100m' for 100 millicores, '1' for 1 core)",
347
+ type: :string,
348
+ required: required,
349
+ valid_regex: /^\d+m?$/
350
+ }
351
+ }
276
352
  end
277
353
 
278
- def self.all_options_by_key_name
279
- all_options.each_with_object({}) do |option, result|
280
- option[:params][:aliases]&.each { |current_alias| result[current_alias.to_s] = option }
281
- result["--#{option[:name]}"] = option
282
- end
354
+ def self.memory_option(required: false)
355
+ {
356
+ name: :memory,
357
+ params: {
358
+ banner: "MEMORY",
359
+ desc: "Overrides memory size " \
360
+ "(e.g., '100Mi' for 100 mebibytes, '1Gi' for 1 gibibyte)",
361
+ type: :string,
362
+ required: required,
363
+ valid_regex: /^\d+[MG]i$/
364
+ }
365
+ }
283
366
  end
284
367
 
285
- def wait_for_workload(workload)
286
- step("Waiting for workload", retry_on_failure: true) do
287
- cp.fetch_workload(workload)
288
- end
368
+ def self.entrypoint_option(required: false)
369
+ {
370
+ name: :entrypoint,
371
+ params: {
372
+ banner: "ENTRYPOINT",
373
+ desc: "Overrides entrypoint " \
374
+ "(must be a single command or a script path that exists in the container)",
375
+ type: :string,
376
+ required: required,
377
+ valid_regex: /^\S+$/
378
+ }
379
+ }
289
380
  end
381
+ # rubocop:enable Metrics/MethodLength
290
382
 
291
- def wait_for_replica(workload, location)
292
- step("Waiting for replica", retry_on_failure: true) do
293
- cp.workload_get_replicas_safely(workload, location: location)&.dig("items", 0)
294
- end
383
+ def self.all_options
384
+ methods.grep(/_option$/).map { |method| send(method.to_s) }
295
385
  end
296
386
 
297
- def ensure_workload_deleted(workload)
298
- step("Deleting workload") do
299
- cp.delete_workload(workload)
387
+ def self.all_options_by_key_name
388
+ all_options.each_with_object({}) do |option, result|
389
+ option[:params][:aliases]&.each { |current_alias| result[current_alias.to_s] = option }
390
+ result["--#{option[:name]}"] = option
300
391
  end
301
392
  end
302
393
 
@@ -312,8 +403,9 @@ module Command
312
403
  end
313
404
  end
314
405
 
315
- def latest_image(app = config.app, org = config.org)
406
+ def latest_image(app = config.app, org = config.org, refresh: false)
316
407
  @latest_image ||= {}
408
+ @latest_image[app] = nil if refresh
317
409
  @latest_image[app] ||=
318
410
  begin
319
411
  items = cp.query_images(app, org)["items"]
@@ -377,7 +469,7 @@ module Command
377
469
  if retry_on_failure
378
470
  until (success = yield)
379
471
  progress.print(".")
380
- sleep 1
472
+ Kernel.sleep(1)
381
473
  end
382
474
  else
383
475
  success = yield
@@ -394,10 +486,6 @@ module Command
394
486
  @cp ||= Controlplane.new(config)
395
487
  end
396
488
 
397
- def perform!(cmd)
398
- system(cmd) || exit(1)
399
- end
400
-
401
489
  def app_location_link
402
490
  "/org/#{config.org}/location/#{config.location}"
403
491
  end
@@ -415,11 +503,18 @@ module Command
415
503
  end
416
504
 
417
505
  def app_secrets
418
- "#{config.app_prefix}-secrets"
506
+ config.current[:secrets_name] || "#{config.app_prefix}-secrets"
419
507
  end
420
508
 
421
509
  def app_secrets_policy
422
- "#{app_secrets}-policy"
510
+ config.current[:secrets_policy_name] || "#{app_secrets}-policy"
511
+ end
512
+
513
+ def ensure_docker_running!
514
+ result = Shell.cmd("docker", "version", capture_stderr: true)
515
+ return if result[:success]
516
+
517
+ raise "Can't run Docker. Please make sure that it's installed and started, then try again."
423
518
  end
424
519
 
425
520
  private
@@ -38,16 +38,11 @@ module Command
38
38
  docker_args: config.args,
39
39
  build_args: build_args)
40
40
 
41
- progress.puts("\nPushed image to '/org/#{config.org}/image/#{image_name}'.")
42
- end
43
-
44
- private
45
-
46
- def ensure_docker_running!
47
- `docker version > /dev/null 2>&1`
48
- return if $CHILD_STATUS.success?
41
+ progress.puts("\nPushed image to '/org/#{config.org}/image/#{image_name}'.\n\n")
49
42
 
50
- raise "Can't run Docker. Please make sure that it's installed and started, then try again."
43
+ step("Waiting for image to be available", retry_on_failure: true) do
44
+ image_name == latest_image(refresh: true)
45
+ end
51
46
  end
52
47
  end
53
48
  end
@@ -21,7 +21,7 @@ module Command
21
21
 
22
22
  progress.puts("Stale apps:")
23
23
  stale_apps.each do |app|
24
- progress.puts(" #{app[:name]} (#{Shell.color((app[:date]).to_s, :red)})")
24
+ progress.puts(" - #{app[:name]} (#{Shell.color((app[:date]).to_s, :red)})")
25
25
  end
26
26
 
27
27
  return unless confirm_delete
@@ -44,13 +44,6 @@ module Command
44
44
 
45
45
  private
46
46
 
47
- def ensure_docker_running!
48
- `docker version > /dev/null 2>&1`
49
- return if $CHILD_STATUS.success?
50
-
51
- raise "Can't run Docker. Please make sure that it's installed and started, then try again."
52
- end
53
-
54
47
  def ensure_upstream_org!
55
48
  return if @upstream_org
56
49
 
@@ -5,28 +5,54 @@ module Command
5
5
  NAME = "delete"
6
6
  OPTIONS = [
7
7
  app_option(required: true),
8
+ workload_option,
8
9
  skip_confirm_option
9
10
  ].freeze
10
- DESCRIPTION = "Deletes the whole app (GVC with all workloads, all volumesets and all images)"
11
+ DESCRIPTION = "Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload"
11
12
  LONG_DESCRIPTION = <<~DESC
12
- - Deletes the whole app (GVC with all workloads, all volumesets and all images)
13
+ - Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload
13
14
  - Will ask for explicit user confirmation
14
15
  DESC
16
+ EXAMPLES = <<~EX
17
+ ```sh
18
+ # Deletes the whole app (GVC with all workloads, all volumesets and all images).
19
+ cpl delete -a $APP_NAME
20
+
21
+ # Deletes a specific workload.
22
+ cpl delete -a $APP_NAME -w $WORKLOAD_NAME
23
+ ```
24
+ EX
15
25
 
16
26
  def call
27
+ workload = config.options[:workload]
28
+ if workload
29
+ delete_single_workload(workload)
30
+ else
31
+ delete_whole_app
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def delete_single_workload(workload)
38
+ return progress.puts("Workload '#{workload}' does not exist.") if cp.fetch_workload(workload).nil?
39
+ return unless confirm_delete(workload)
40
+
41
+ delete_workload(workload)
42
+ end
43
+
44
+ def delete_whole_app
17
45
  return progress.puts("App '#{config.app}' does not exist.") if cp.fetch_gvc.nil?
18
46
 
19
47
  check_volumesets
20
48
  check_images
21
- return unless confirm_delete
49
+ return unless confirm_delete(config.app)
22
50
 
23
51
  delete_volumesets
24
52
  delete_gvc
25
53
  delete_images
26
54
  end
27
55
 
28
- private
29
-
30
56
  def check_volumesets
31
57
  @volumesets = cp.fetch_volumesets["items"]
32
58
  return progress.puts("No volumesets to delete.") unless @volumesets.any?
@@ -46,10 +72,10 @@ module Command
46
72
  progress.puts("#{Shell.color(message, :red)}\n#{images_list}\n\n")
47
73
  end
48
74
 
49
- def confirm_delete
75
+ def confirm_delete(item)
50
76
  return true if config.options[:yes]
51
77
 
52
- confirmed = Shell.confirm("Are you sure you want to delete '#{config.app}'?")
78
+ confirmed = Shell.confirm("Are you sure you want to delete '#{item}'?")
53
79
  return false unless confirmed
54
80
 
55
81
  progress.puts
@@ -62,6 +88,12 @@ module Command
62
88
  end
63
89
  end
64
90
 
91
+ def delete_workload(workload)
92
+ step("Deleting workload '#{workload}'") do
93
+ cp.delete_workload(workload)
94
+ end
95
+ end
96
+
65
97
  def delete_volumesets
66
98
  @volumesets.each do |volumeset|
67
99
  step("Deleting volumeset '#{volumeset['name']}'") do
@@ -11,6 +11,7 @@ module Command
11
11
  LONG_DESCRIPTION = <<~DESC
12
12
  - Deploys the latest image to app workloads
13
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 release script is run in the context of `cpl run` with the latest image
14
15
  - The deploy will fail if the release script exits with a non-zero code or doesn't exist
15
16
  DESC
16
17
 
@@ -20,6 +21,11 @@ module Command
20
21
  deployed_endpoints = {}
21
22
 
22
23
  image = latest_image
24
+ if cp.fetch_image_details(image).nil?
25
+ raise "Image '#{image}' does not exist in the Docker repository on Control Plane " \
26
+ "(see https://console.cpln.io/console/org/#{config.org}/repository/#{config.app}). " \
27
+ "Use `cpl build-image` first."
28
+ end
23
29
 
24
30
  config[:app_workloads].each do |workload|
25
31
  workload_data = cp.fetch_workload!(workload)
@@ -42,15 +48,24 @@ module Command
42
48
 
43
49
  private
44
50
 
45
- def run_release_script
51
+ def run_release_script # rubocop:disable Metrics/MethodLength
46
52
  release_script_name = config[:release_script]
47
53
  release_script_path = Pathname.new("#{config.app_cpln_dir}/#{release_script_name}").expand_path
48
54
 
49
55
  raise "Can't find release script in '#{release_script_path}'." unless File.exist?(release_script_path)
50
56
 
51
57
  progress.puts("Running release script...\n\n")
52
- perform!("bash #{release_script_path}")
53
- progress.puts
58
+
59
+ release_script = File.read(release_script_path)
60
+ begin
61
+ Cpl::Cli.start(["run", "-a", config.app, "--image", "latest", "--", release_script])
62
+ rescue SystemExit => e
63
+ progress.puts
64
+
65
+ raise "Failed to run release script." if e.status.nonzero?
66
+
67
+ progress.puts("Finished running release script.\n\n")
68
+ end
54
69
  end
55
70
  end
56
71
  end
@@ -17,7 +17,7 @@ module Command
17
17
  EX
18
18
 
19
19
  def call
20
- exit(!cp.fetch_gvc.nil?)
20
+ exit(cp.fetch_gvc.nil? ? ExitCode::ERROR_DEFAULT : ExitCode::SUCCESS)
21
21
  end
22
22
  end
23
23
  end
@@ -5,7 +5,7 @@ module Command
5
5
  include Thor::Actions
6
6
 
7
7
  def copy_files
8
- directory("generator_templates", ".controlplane")
8
+ directory("generator_templates", ".controlplane", verbose: ENV.fetch("HIDE_COMMAND_OUTPUT", nil) != "true")
9
9
  end
10
10
 
11
11
  def self.source_root
data/lib/command/info.rb CHANGED
@@ -76,7 +76,7 @@ module Command
76
76
  result.push(config.org)
77
77
  else
78
78
  config.apps.each do |_, app_options|
79
- org = app_options[:cpln_org]
79
+ org = app_org(app_options)
80
80
  result.push(org) if org && !result.include?(org)
81
81
  end
82
82
  end
@@ -90,14 +90,18 @@ module Command
90
90
  config.apps.each do |app_name, app_options|
91
91
  next if config.app && !config.app_matches?(config.app, app_name, app_options)
92
92
 
93
- app_org = app_options[:cpln_org]
94
- result.push(app_name.to_s) if app_org == org
93
+ current_app_org = app_org(app_options)
94
+ result.push(app_name.to_s) if current_app_org == org
95
95
  end
96
96
 
97
97
  result += @app_workloads.keys.map(&:to_s)
98
98
  result.uniq.sort
99
99
  end
100
100
 
101
+ def app_org(app_options)
102
+ app_options[:cpln_org]
103
+ end
104
+
101
105
  def any_app_starts_with?(app)
102
106
  @app_workloads.keys.find { |app_name| config.app_matches?(app_name, app, config.apps[app.to_sym]) }
103
107
  end
data/lib/command/logs.rb CHANGED
@@ -5,11 +5,15 @@ module Command
5
5
  NAME = "logs"
6
6
  OPTIONS = [
7
7
  app_option(required: true),
8
- workload_option
8
+ workload_option,
9
+ replica_option,
10
+ logs_limit_option,
11
+ logs_since_option
9
12
  ].freeze
10
13
  DESCRIPTION = "Light wrapper to display tailed raw logs for app/workload syntax"
11
14
  LONG_DESCRIPTION = <<~DESC
12
15
  - Light wrapper to display tailed raw logs for app/workload syntax
16
+ - Defaults to showing the last 200 entries from the past 1 hour before tailing
13
17
  DESC
14
18
  EXAMPLES = <<~EX
15
19
  ```sh
@@ -18,12 +22,28 @@ module Command
18
22
 
19
23
  # Displays logs for a specific workload.
20
24
  cpl logs -a $APP_NAME -w $WORKLOAD_NAME
25
+
26
+ # Displays logs for a specific replica of a workload.
27
+ cpl logs -a $APP_NAME -w $WORKLOAD_NAME -r $REPLICA_NAME
28
+
29
+ # Uses a different limit on number of entries.
30
+ cpl logs -a $APP_NAME --limit 100
31
+
32
+ # Uses a different loopback window.
33
+ cpl logs -a $APP_NAME --since 30min
21
34
  ```
22
35
  EX
23
36
 
24
37
  def call
25
38
  workload = config.options[:workload] || config[:one_off_workload]
26
- cp.logs(workload: workload)
39
+ replica = config.options[:replica]
40
+ limit = config.options[:limit]
41
+ since = config.options[:since]
42
+
43
+ message = replica ? "replica '#{replica}'" : "workload '#{workload}'"
44
+ progress.puts("Fetching logs for #{message}...\n\n")
45
+
46
+ cp.logs(workload: workload, replica: replica, limit: limit, since: since)
27
47
  end
28
48
  end
29
49
  end
@@ -48,7 +48,7 @@ module Command
48
48
  cp.set_domain_workload(domain_data, one_off_workload)
49
49
 
50
50
  # Give it a bit of time for the domain to update
51
- sleep 30
51
+ Kernel.sleep(30)
52
52
  end
53
53
 
54
54
  progress.puts
@@ -48,7 +48,7 @@ module Command
48
48
  cp.set_domain_workload(domain_data, maintenance_workload)
49
49
 
50
50
  # Give it a bit of time for the domain to update
51
- sleep 30
51
+ Kernel.sleep(30)
52
52
  end
53
53
 
54
54
  progress.puts
data/lib/command/open.rb CHANGED
@@ -25,9 +25,9 @@ module Command
25
25
  workload = config.options[:workload] || config[:one_off_workload]
26
26
  data = cp.fetch_workload!(workload)
27
27
  url = data["status"]["endpoint"]
28
- opener = `which xdg-open open`.split("\n").grep_v("not found").first
28
+ opener = Shell.cmd("which", "xdg-open", "open")[:output].split("\n").grep_v("not found").first
29
29
 
30
- exec %(#{opener} "#{url}")
30
+ Kernel.exec(opener, url)
31
31
  end
32
32
  end
33
33
  end
@@ -18,9 +18,9 @@ module Command
18
18
  url = "https://console.cpln.io/console/org/#{config.org}/gvc/#{config.app}"
19
19
  url += "/workload/#{workload}" if workload
20
20
  url += "/-info"
21
- opener = `which xdg-open open`.split("\n").grep_v("not found").first
21
+ opener = Shell.cmd("which", "xdg-open", "open")[:output].split("\n").grep_v("not found").first
22
22
 
23
- exec %(#{opener} "#{url}")
23
+ Kernel.exec(opener, url)
24
24
  end
25
25
  end
26
26
  end
data/lib/command/ps.rb CHANGED
@@ -33,7 +33,7 @@ module Command
33
33
  workloads.each do |workload|
34
34
  cp.fetch_workload!(workload)
35
35
 
36
- result = cp.workload_get_replicas(workload, location: location)
36
+ result = cp.fetch_workload_replicas(workload, location: location)
37
37
  result["items"].each { |replica| puts replica }
38
38
  end
39
39
  end
@@ -6,6 +6,7 @@ module Command
6
6
  OPTIONS = [
7
7
  app_option(required: true),
8
8
  workload_option,
9
+ location_option,
9
10
  wait_option("workload to be ready")
10
11
  ].freeze
11
12
  DESCRIPTION = "Starts workloads in app"
@@ -42,7 +43,7 @@ module Command
42
43
 
43
44
  @workloads.reverse_each do |workload|
44
45
  step("Waiting for workload '#{workload}' to be ready", retry_on_failure: true) do
45
- cp.workload_deployments_ready?(workload, expected_status: true)
46
+ cp.workload_deployments_ready?(workload, location: config.location, expected_status: true)
46
47
  end
47
48
  end
48
49
  end