cpl 1.1.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check_cpln_links.yml +19 -0
  3. data/.github/workflows/rspec.yml +1 -1
  4. data/.overcommit.yml +3 -0
  5. data/CHANGELOG.md +47 -2
  6. data/CONTRIBUTING.md +2 -6
  7. data/Gemfile.lock +8 -8
  8. data/README.md +57 -15
  9. data/docs/commands.md +29 -23
  10. data/docs/dns.md +9 -0
  11. data/docs/migrating.md +3 -3
  12. data/examples/controlplane.yml +67 -4
  13. data/lib/command/apply_template.rb +2 -1
  14. data/lib/command/base.rb +62 -0
  15. data/lib/command/build_image.rb +5 -1
  16. data/lib/command/config.rb +0 -5
  17. data/lib/command/copy_image_from_upstream.rb +5 -4
  18. data/lib/command/delete.rb +40 -11
  19. data/lib/command/env.rb +1 -0
  20. data/lib/command/generate.rb +45 -0
  21. data/lib/command/info.rb +15 -33
  22. data/lib/command/latest_image.rb +1 -0
  23. data/lib/command/maintenance.rb +9 -4
  24. data/lib/command/maintenance_off.rb +8 -4
  25. data/lib/command/maintenance_on.rb +8 -4
  26. data/lib/command/no_command.rb +1 -0
  27. data/lib/command/ps.rb +5 -1
  28. data/lib/command/run.rb +20 -23
  29. data/lib/command/run_detached.rb +38 -30
  30. data/lib/command/setup_app.rb +3 -3
  31. data/lib/command/version.rb +1 -0
  32. data/lib/core/config.rb +194 -66
  33. data/lib/core/controlplane.rb +28 -7
  34. data/lib/core/controlplane_api.rb +13 -1
  35. data/lib/core/controlplane_api_direct.rb +18 -2
  36. data/lib/core/helpers.rb +16 -0
  37. data/lib/core/shell.rb +25 -3
  38. data/lib/cpl/version.rb +1 -1
  39. data/lib/cpl.rb +32 -3
  40. data/lib/generator_templates/Dockerfile +27 -0
  41. data/lib/generator_templates/controlplane.yml +57 -0
  42. data/lib/generator_templates/entrypoint.sh +8 -0
  43. data/lib/generator_templates/templates/gvc.yml +21 -0
  44. data/lib/generator_templates/templates/postgres.yml +176 -0
  45. data/lib/generator_templates/templates/rails.yml +36 -0
  46. data/script/check_cpln_links +45 -0
  47. metadata +14 -3
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`
@@ -23,6 +30,8 @@ module Command
23
30
  EXAMPLES = ""
24
31
  # If `true`, hides the command from `cpl help`
25
32
  HIDE = false
33
+ # Whether or not to show key information like ORG and APP name in commands
34
+ WITH_INFO_HEADER = true
26
35
 
27
36
  NO_IMAGE_AVAILABLE = "NO_IMAGE_AVAILABLE"
28
37
 
@@ -38,6 +47,10 @@ module Command
38
47
  end
39
48
  end
40
49
 
50
+ def self.common_options
51
+ [org_option, verbose_option, trace_option]
52
+ end
53
+
41
54
  def self.org_option(required: false)
42
55
  {
43
56
  name: :org,
@@ -103,6 +116,31 @@ module Command
103
116
  }
104
117
  end
105
118
 
119
+ def self.location_option(required: false)
120
+ {
121
+ name: :location,
122
+ params: {
123
+ aliases: ["-l"],
124
+ banner: "LOCATION_NAME",
125
+ desc: "Location name",
126
+ type: :string,
127
+ required: required
128
+ }
129
+ }
130
+ end
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
+
106
144
  def self.upstream_token_option(required: false)
107
145
  {
108
146
  name: :upstream_token,
@@ -188,6 +226,29 @@ module Command
188
226
  }
189
227
  end
190
228
 
229
+ def self.trace_option(required: false)
230
+ {
231
+ name: :trace,
232
+ params: {
233
+ desc: "Shows trace of API calls. WARNING: may contain sensitive data",
234
+ type: :boolean,
235
+ required: required
236
+ }
237
+ }
238
+ end
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
+
191
252
  def self.all_options
192
253
  methods.grep(/_option$/).map { |method| send(method.to_s) }
193
254
  end
@@ -239,6 +300,7 @@ module Command
239
300
  end
240
301
 
241
302
  def latest_image_next(app = config.app, org = config.org, commit: nil)
303
+ # debugger
242
304
  commit ||= config.options[:commit]
243
305
 
244
306
  @latest_image_next ||= {}
@@ -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
@@ -21,11 +21,6 @@ module Command
21
21
  EX
22
22
 
23
23
  def call # rubocop:disable Metrics/MethodLength
24
- if config.org_comes_from_env
25
- puts Shell.color("Org comes from CPLN_ORG env var", :yellow)
26
- puts
27
- end
28
-
29
24
  if config.app
30
25
  puts "#{Shell.color("Current config (app '#{config.app}')", :blue)}:"
31
26
  puts pretty_print(config.current)
@@ -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
 
@@ -7,21 +7,45 @@ module Command
7
7
  app_option(required: true),
8
8
  skip_confirm_option
9
9
  ].freeze
10
- DESCRIPTION = "Deletes the whole app (GVC with all workloads and all images)"
10
+ DESCRIPTION = "Deletes the whole app (GVC with all workloads, all volumesets and all images)"
11
11
  LONG_DESCRIPTION = <<~DESC
12
- - Deletes the whole app (GVC with all workloads and all images)
12
+ - Deletes the whole app (GVC with all workloads, all volumesets and all images)
13
13
  - Will ask for explicit user confirmation
14
14
  DESC
15
15
 
16
16
  def call
17
+ return progress.puts("App '#{config.app}' does not exist.") if cp.fetch_gvc.nil?
18
+
19
+ check_volumesets
20
+ check_images
17
21
  return unless confirm_delete
18
22
 
23
+ delete_volumesets
19
24
  delete_gvc
20
25
  delete_images
21
26
  end
22
27
 
23
28
  private
24
29
 
30
+ def check_volumesets
31
+ @volumesets = cp.fetch_volumesets["items"]
32
+ return progress.puts("No volumesets to delete.") unless @volumesets.any?
33
+
34
+ message = "The following volumesets will be deleted along with the app:"
35
+ volumesets_list = @volumesets.map { |volumeset| "- #{volumeset['name']}" }.join("\n")
36
+ progress.puts("#{Shell.color(message, :red)}\n#{volumesets_list}\n\n")
37
+ end
38
+
39
+ def check_images
40
+ @images = cp.query_images["items"]
41
+ .select { |image| image["name"].start_with?("#{config.app}:") }
42
+ return progress.puts("No images to delete.") unless @images.any?
43
+
44
+ message = "The following images will be deleted along with the app:"
45
+ images_list = @images.map { |image| "- #{image['name']}" }.join("\n")
46
+ progress.puts("#{Shell.color(message, :red)}\n#{images_list}\n\n")
47
+ end
48
+
25
49
  def confirm_delete
26
50
  return true if config.options[:yes]
27
51
 
@@ -33,22 +57,27 @@ module Command
33
57
  end
34
58
 
35
59
  def delete_gvc
36
- return progress.puts("App '#{config.app}' does not exist.") if cp.fetch_gvc.nil?
37
-
38
60
  step("Deleting app '#{config.app}'") do
39
61
  cp.gvc_delete
40
62
  end
41
63
  end
42
64
 
43
- def delete_images
44
- images = cp.query_images["items"]
45
- .filter_map { |item| item["name"] if item["name"].start_with?("#{config.app}:") }
65
+ def delete_volumesets
66
+ @volumesets.each do |volumeset|
67
+ step("Deleting volumeset '#{volumeset['name']}'") do
68
+ # If the volumeset is attached to a workload, we need to delete the workload first
69
+ workload = volumeset.dig("status", "usedByWorkload")&.split("/")&.last
70
+ cp.delete_workload(workload) if workload
46
71
 
47
- return progress.puts("No images to delete.") unless images.any?
72
+ cp.delete_volumeset(volumeset["name"])
73
+ end
74
+ end
75
+ end
48
76
 
49
- images.each do |image|
50
- step("Deleting image '#{image}'") do
51
- cp.image_delete(image)
77
+ def delete_images
78
+ @images.each do |image|
79
+ step("Deleting image '#{image['name']}'") do
80
+ cp.image_delete(image["name"])
52
81
  end
53
82
  end
54
83
  end
data/lib/command/env.rb CHANGED
@@ -10,6 +10,7 @@ module Command
10
10
  LONG_DESCRIPTION = <<~DESC
11
11
  - Displays app-specific environment variables
12
12
  DESC
13
+ WITH_INFO_HEADER = false
13
14
 
14
15
  def call
15
16
  cp.fetch_gvc!.dig("spec", "env").map do |prop|
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Command
4
+ class Generator < Thor::Group
5
+ include Thor::Actions
6
+
7
+ def copy_files
8
+ directory("generator_templates", ".controlplane")
9
+ end
10
+
11
+ def self.source_root
12
+ File.expand_path("../", __dir__)
13
+ end
14
+ end
15
+
16
+ class Generate < Base
17
+ NAME = "generate"
18
+ DESCRIPTION = "Creates base Control Plane config and template files"
19
+ LONG_DESCRIPTION = <<~DESC
20
+ Creates base Control Plane config and template files
21
+ DESC
22
+ EXAMPLES = <<~EX
23
+ ```sh
24
+ # Creates .controlplane directory with Control Plane config and other templates
25
+ cpl generate
26
+ ```
27
+ EX
28
+ WITH_INFO_HEADER = false
29
+
30
+ def call
31
+ if controlplane_directory_exists?
32
+ Shell.warn("The directory '.controlplane' already exists!")
33
+ return
34
+ end
35
+
36
+ Generator.start
37
+ end
38
+
39
+ private
40
+
41
+ def controlplane_directory_exists?
42
+ Dir.exist? ".controlplane"
43
+ end
44
+ end
45
+ end
data/lib/command/info.rb CHANGED
@@ -4,7 +4,6 @@ module Command
4
4
  class Info < Base # rubocop:disable Metrics/ClassLength
5
5
  NAME = "info"
6
6
  OPTIONS = [
7
- org_option,
8
7
  app_option
9
8
  ].freeze
10
9
  DESCRIPTION = "Displays the diff between defined/available apps/workloads (apps equal GVCs)"
@@ -17,7 +16,7 @@ module Command
17
16
  DESC
18
17
  EXAMPLES = <<~EX
19
18
  ```sh
20
- # Shows diff for all apps in all orgs.
19
+ # Shows diff for all apps in all orgs (based on `.controlplane/controlplane.yml`).
21
20
  cpl info
22
21
 
23
22
  # Shows diff for all apps in a specific org.
@@ -27,12 +26,13 @@ module Command
27
26
  cpl info -a $APP_NAME
28
27
  ```
29
28
  EX
29
+ WITH_INFO_HEADER = false
30
30
 
31
31
  def call
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,24 +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/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
72
+ def orgs
85
73
  result = []
86
74
 
87
- if config.options[:org]
88
- result.push(config.options[:org])
75
+ if config.org
76
+ result.push(config.org)
89
77
  else
90
- org_from_env = ENV.fetch("CPLN_ORG", nil)
91
- result.push(org_from_env) if org_from_env
92
-
93
- config.apps.each do |app_name, app_options|
94
- next if config.app && !app_matches?(config.app, app_name, app_options)
95
-
78
+ config.apps.each do |_, app_options|
96
79
  org = app_options[:cpln_org]
97
80
  result.push(org) if org && !result.include?(org)
98
81
  end
@@ -105,7 +88,7 @@ module Command
105
88
  result = []
106
89
 
107
90
  config.apps.each do |app_name, app_options|
108
- 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)
109
92
 
110
93
  app_org = app_options[:cpln_org]
111
94
  result.push(app_name.to_s) if app_org == org
@@ -116,7 +99,7 @@ module Command
116
99
  end
117
100
 
118
101
  def any_app_starts_with?(app)
119
- @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]) }
120
103
  end
121
104
 
122
105
  def check_any_app_starts_with(app)
@@ -187,8 +170,7 @@ module Command
187
170
  "(replace 'whatever' with whatever suffix you want):"
188
171
 
189
172
  @missing_apps_starting_with.each do |app, _workloads|
190
- app_with_suffix = "#{app}#{app.end_with?('-') ? '' : '-'}whatever"
191
- puts " - `cpl setup-app -a #{app_with_suffix}`"
173
+ puts " - `cpl setup-app -a #{app}-whatever`"
192
174
  end
193
175
  end
194
176
 
@@ -200,7 +182,7 @@ module Command
200
182
  @defined_workloads = find_workloads(config.app)
201
183
  @available_workloads = fetch_workloads(config.app)
202
184
 
203
- workloads = (@defined_workloads + @available_workloads).uniq.sort
185
+ workloads = (@defined_workloads + @available_workloads).uniq
204
186
  workloads.each do |workload|
205
187
  print_workload(config.app, workload)
206
188
  end
@@ -220,7 +202,7 @@ module Command
220
202
  @defined_workloads = find_workloads(app)
221
203
  @available_workloads = @app_workloads[app] || []
222
204
 
223
- workloads = (@defined_workloads + @available_workloads).uniq.sort
205
+ workloads = (@defined_workloads + @available_workloads).uniq
224
206
  workloads.each do |workload|
225
207
  print_workload(app, workload)
226
208
  end
@@ -10,6 +10,7 @@ module Command
10
10
  LONG_DESCRIPTION = <<~DESC
11
11
  - Displays the latest image name
12
12
  DESC
13
+ WITH_INFO_HEADER = false
13
14
 
14
15
  def call
15
16
  puts latest_image
@@ -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
@@ -14,20 +15,24 @@ module Command
14
15
  - Optionally specify the maintenance workload through `maintenance_workload` in the `.controlplane/controlplane.yml` file (defaults to 'maintenance')
15
16
  - Maintenance mode is only supported for domains that use path based routing mode and have a route configured for the prefix '/' on either port 80 or 443
16
17
  DESC
18
+ WITH_INFO_HEADER = false
17
19
 
18
20
  def call # rubocop:disable Metrics/MethodLength
19
21
  one_off_workload = config[:one_off_workload]
20
22
  maintenance_workload = config.current[:maintenance_workload] || "maintenance"
21
23
 
22
- 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
23
29
  unless domain_data
24
30
  raise "Can't find domain. " \
25
31
  "Maintenance mode is only supported for domains that use path based routing mode " \
26
32
  "and have a route configured for the prefix '/' on either port 80 or 443."
27
33
  end
28
34
 
29
- domain_workload = cp.get_domain_workload(domain_data)
30
- if domain_workload == maintenance_workload
35
+ if cp.domain_workload_matches?(domain_data, maintenance_workload)
31
36
  puts "on"
32
37
  else
33
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
@@ -9,6 +9,7 @@ module Command
9
9
  - Called when no command was specified
10
10
  DESC
11
11
  HIDE = true
12
+ WITH_INFO_HEADER = false
12
13
 
13
14
  def call
14
15
  if config.options[:version]
data/lib/command/ps.rb CHANGED
@@ -5,6 +5,7 @@ module Command
5
5
  NAME = "ps"
6
6
  OPTIONS = [
7
7
  app_option(required: true),
8
+ location_option,
8
9
  workload_option
9
10
  ].freeze
10
11
  DESCRIPTION = "Shows running replicas in app"
@@ -20,16 +21,19 @@ module Command
20
21
  cpl ps -a $APP_NAME -w $WORKLOAD_NAME
21
22
  ```
22
23
  EX
24
+ WITH_INFO_HEADER = false
23
25
 
24
26
  def call
25
27
  cp.fetch_gvc!
26
28
 
29
+ location = config.location
30
+
27
31
  workloads = [config.options[:workload]] if config.options[:workload]
28
32
  workloads ||= config[:app_workloads] + config[:additional_workloads]
29
33
  workloads.each do |workload|
30
34
  cp.fetch_workload!(workload)
31
35
 
32
- result = cp.workload_get_replicas(workload, location: config[:default_location])
36
+ result = cp.workload_get_replicas(workload, location: location)
33
37
  result["items"].each { |replica| puts replica }
34
38
  end
35
39
  end