cpl 2.0.2 → 2.2.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.
data/lib/command/run.rb CHANGED
@@ -36,12 +36,17 @@ module Command
36
36
  - - log async fetching for non-interactive mode
37
37
  - The Dockerfile entrypoint is used as the command by default, which assumes `exec "${@}"` to be present,
38
38
  and the args ["bash", "-c", cmd_to_run] are passed
39
- - The entrypoint can be overriden through `--entrypoint`, which must be a single command or a script path that exists in the container,
39
+ - The entrypoint can be overridden through `--entrypoint`, which must be a single command or a script path that exists in the container,
40
40
  and the args ["bash", "-c", cmd_to_run] are passed,
41
41
  unless the entrypoint is `bash`, in which case the args ["-c", cmd_to_run] are passed
42
42
  - Providing `--entrypoint none` sets the entrypoint to `bash` by default
43
43
  - If `fix_terminal_size` is `true` in the `.controlplane/controlplane.yml` file,
44
- the remote terminal size will be fixed to match the local terminal size (may also be overriden through `--terminal-size`)
44
+ the remote terminal size will be fixed to match the local terminal size (may also be overridden through `--terminal-size`)
45
+ - By default, all jobs use a CPU size of 1 (1 core) and a memory size of 2Gi (2 gibibytes)
46
+ (can be configured through `runner_job_default_cpu` and `runner_job_default_memory` in `controlplane.yml`,
47
+ and also overridden per job through `--cpu` and `--memory`)
48
+ - By default, the job is stopped if it takes longer than 6 hours to finish
49
+ (can be configured though `runner_job_timeout` in `controlplane.yml`)
45
50
  DESC
46
51
  EXAMPLES = <<~EX
47
52
  ```sh
@@ -84,12 +89,17 @@ module Command
84
89
  ```
85
90
  EX
86
91
 
92
+ DEFAULT_JOB_CPU = "1"
93
+ DEFAULT_JOB_MEMORY = "2Gi"
94
+ DEFAULT_JOB_TIMEOUT = 21_600 # 6 hours
95
+ DEFAULT_JOB_HISTORY_LIMIT = 10
87
96
  MAGIC_END = "---cpl run command finished---"
88
97
 
89
98
  attr_reader :interactive, :detached, :location, :original_workload, :runner_workload,
99
+ :default_image, :default_cpu, :default_memory, :job_timeout, :job_history_limit,
90
100
  :container, :expected_deployed_version, :job, :replica, :command
91
101
 
92
- def call # rubocop:disable Metrics/MethodLength
102
+ def call # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
93
103
  @interactive = config.options[:interactive] || interactive_command?
94
104
  @detached = config.options[:detached]
95
105
  @log_method = config.options[:log_method]
@@ -97,6 +107,11 @@ module Command
97
107
  @location = config.location
98
108
  @original_workload = config.options[:workload] || config[:one_off_workload]
99
109
  @runner_workload = "#{original_workload}-runner"
110
+ @default_image = "#{config.app}:#{Controlplane::NO_IMAGE_AVAILABLE}"
111
+ @default_cpu = config.current[:runner_job_default_cpu] || DEFAULT_JOB_CPU
112
+ @default_memory = config.current[:runner_job_default_memory] || DEFAULT_JOB_MEMORY
113
+ @job_timeout = config.current[:runner_job_timeout] || DEFAULT_JOB_TIMEOUT
114
+ @job_history_limit = DEFAULT_JOB_HISTORY_LIMIT
100
115
 
101
116
  unless interactive
102
117
  @internal_sigint = false
@@ -110,12 +125,10 @@ module Command
110
125
  end
111
126
  end
112
127
 
113
- if cp.fetch_workload(runner_workload).nil?
114
- create_runner_workload
115
- wait_for_runner_workload_create
116
- end
128
+ create_runner_workload if cp.fetch_workload(runner_workload).nil?
129
+ wait_for_runner_workload_deploy
117
130
  update_runner_workload
118
- wait_for_runner_workload_update
131
+ wait_for_runner_workload_update if expected_deployed_version
119
132
 
120
133
  start_job
121
134
  wait_for_replica_for_job
@@ -154,6 +167,11 @@ module Command
154
167
  container_spec.delete("livenessProbe")
155
168
  container_spec.delete("readinessProbe")
156
169
 
170
+ # Set image, CPU, and memory to default values
171
+ container_spec["image"] = default_image
172
+ container_spec["cpu"] = default_cpu
173
+ container_spec["memory"] = default_memory
174
+
157
175
  # Ensure cron workload won't run per schedule
158
176
  spec["defaultOptions"]["suspend"] = true
159
177
 
@@ -163,9 +181,14 @@ module Command
163
181
 
164
182
  # Set cron job props
165
183
  spec["type"] = "cron"
184
+ spec["job"] = {
185
+ # Next job set to run on January 1st, 2029
186
+ "schedule" => "0 0 1 1 1",
166
187
 
167
- # Next job set to run on January 1st, 2029
168
- spec["job"] = { "schedule" => "0 0 1 1 1", "restartPolicy" => "Never" }
188
+ "restartPolicy" => "Never",
189
+ "activeDeadlineSeconds" => job_timeout,
190
+ "historyLimit" => job_history_limit
191
+ }
169
192
 
170
193
  # Create runner workload
171
194
  cp.apply_hash("kind" => "workload", "name" => runner_workload, "spec" => spec)
@@ -173,46 +196,60 @@ module Command
173
196
  end
174
197
 
175
198
  def update_runner_workload # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
176
- step("Updating runner workload '#{runner_workload}' based on '#{original_workload}'") do # rubocop:disable Metrics/BlockLength
177
- @expected_deployed_version = cp.cron_workload_deployed_version(runner_workload)
178
- should_update = false
199
+ should_update = false
200
+ spec = nil
179
201
 
202
+ step("Checking if runner workload '#{runner_workload}' needs to be updated") do # rubocop:disable Metrics/BlockLength
180
203
  _, original_container_spec = base_workload_specs(original_workload)
181
204
  spec, container_spec = base_workload_specs(runner_workload)
182
205
 
183
- # Override image if specified
184
- image = config.options[:image]
185
- image_link = if image
186
- image = latest_image if image == "latest"
187
- "/org/#{config.org}/image/#{image}"
188
- else
189
- original_container_spec["image"]
190
- end
191
- if container_spec["image"] != image_link
192
- container_spec["image"] = image_link
206
+ # Keep ENV synced between original and runner workloads
207
+ original_env_str = original_container_spec["env"]&.sort_by { |env| env["name"] }.to_s
208
+ env_str = container_spec["env"]&.sort_by { |env| env["name"] }.to_s
209
+ if original_env_str != env_str
210
+ container_spec["env"] = original_container_spec["env"]
211
+ should_update = true
212
+ end
213
+
214
+ if container_spec["image"] != default_image
215
+ container_spec["image"] = default_image
193
216
  should_update = true
194
217
  end
195
218
 
196
- # Container overrides
197
- if config.options[:cpu] && container_spec["cpu"] != config.options[:cpu]
198
- container_spec["cpu"] = config.options[:cpu]
219
+ if container_spec["cpu"] != default_cpu
220
+ container_spec["cpu"] = default_cpu
199
221
  should_update = true
200
222
  end
201
- if config.options[:memory] && container_spec["memory"] != config.options[:memory]
202
- container_spec["memory"] = config.options[:memory]
223
+
224
+ if container_spec["memory"] != default_memory
225
+ container_spec["memory"] = default_memory
203
226
  should_update = true
204
227
  end
205
228
 
206
- next true unless should_update
229
+ if spec["job"]["activeDeadlineSeconds"] != job_timeout
230
+ spec["job"]["activeDeadlineSeconds"] = job_timeout
231
+ should_update = true
232
+ end
207
233
 
234
+ if spec["job"]["historyLimit"] != job_history_limit
235
+ spec["job"]["historyLimit"] = job_history_limit
236
+ should_update = true
237
+ end
238
+
239
+ true
240
+ end
241
+
242
+ return unless should_update
243
+
244
+ step("Updating runner workload '#{runner_workload}'") do
208
245
  # Update runner workload
209
- @expected_deployed_version += 1
246
+ @expected_deployed_version = cp.cron_workload_deployed_version(runner_workload) + 1
210
247
  cp.apply_hash("kind" => "workload", "name" => runner_workload, "spec" => spec)
211
248
  end
212
249
  end
213
250
 
214
- def wait_for_runner_workload_create
215
- step("Waiting for runner workload '#{runner_workload}' to be created", retry_on_failure: true) do
251
+ def wait_for_runner_workload_deploy
252
+ step("Waiting for runner workload '#{runner_workload}' to be deployed", retry_on_failure: true) do
216
253
  !cp.cron_workload_deployed_version(runner_workload).nil?
217
254
  end
218
255
  end
@@ -302,12 +339,14 @@ module Command
302
339
  def base_workload_specs(workload)
303
340
  spec = cp.fetch_workload!(workload).fetch("spec")
304
341
  container_spec = spec["containers"].detect { _1["name"] == original_workload } || spec["containers"].first
305
- @container = container_spec["name"]
306
342
 
307
343
  [spec, container_spec]
308
344
  end
309
345
 
310
346
  def build_job_start_yaml # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
347
+ _, original_container_spec = base_workload_specs(original_workload)
348
+ @container = original_container_spec["name"]
349
+
311
350
  job_start_hash = { "name" => container }
312
351
 
313
352
  if config.options[:use_local_token]
@@ -335,6 +374,18 @@ module Command
335
374
  job_start_hash["args"].push('eval "$CPL_RUNNER_SCRIPT"')
336
375
  end
337
376
 
377
+ image = config.options[:image]
378
+ image_link = if image
379
+ image = cp.latest_image if image == "latest"
380
+ "/org/#{config.org}/image/#{image}"
381
+ else
382
+ original_container_spec["image"]
383
+ end
384
+
385
+ job_start_hash["image"] = image_link
386
+ job_start_hash["cpu"] = config.options[:cpu] if config.options[:cpu]
387
+ job_start_hash["memory"] = config.options[:memory] if config.options[:memory]
388
+
338
389
  job_start_hash.to_yaml
339
390
  end
340
391
 
@@ -434,6 +485,8 @@ module Command
434
485
  end
435
486
 
436
487
  def print_detached_commands
488
+ return unless replica
489
+
437
490
  app_workload_replica_config = app_workload_replica_args.join(" ")
438
491
  progress.puts(
439
492
  "\n\n" \
@@ -451,7 +504,7 @@ module Command
451
504
  Shell.debug("JOB STATUS", status)
452
505
 
453
506
  case status
454
- when "active"
507
+ when "active", "pending"
455
508
  sleep 1
456
509
  when "successful"
457
510
  break ExitCode::SUCCESS
@@ -5,18 +5,27 @@ module Command
5
5
  NAME = "setup-app"
6
6
  OPTIONS = [
7
7
  app_option(required: true),
8
- skip_secret_access_binding_option
8
+ skip_secret_access_binding_option,
9
+ skip_secrets_setup_option,
10
+ skip_post_creation_hook_option
9
11
  ].freeze
10
12
  DESCRIPTION = "Creates an app and all its workloads"
11
13
  LONG_DESCRIPTION = <<~DESC
12
14
  - Creates an app and all its workloads
13
15
  - Specify the templates for the app and workloads through `setup_app_templates` in the `.controlplane/controlplane.yml` file
14
- - This should only be used for temporary apps like review apps, never for persistent apps like production (to update workloads for those, use 'cpl apply-template' instead)
15
- - Automatically binds the app to the secrets policy, as long as both the identity and the policy exist
16
- - Use `--skip-secret-access-binding` to prevent the automatic bind
16
+ - This should only be used for temporary apps like review apps, never for persistent apps like production or staging (to update workloads for those, use 'cpl apply-template' instead)
17
+ - Configures app to have org-level secrets with default name "{APP_PREFIX}-secrets"
18
+ using org-level policy with default name "{APP_PREFIX}-secrets-policy" (names can be customized, see docs)
19
+ - Creates identity for secrets if it does not exist
20
+ - Use `--skip-secrets-setup` to prevent the automatic setup of secrets,
21
+ or set it through `skip_secrets_setup` in the `.controlplane/controlplane.yml` file
22
+ - Runs a post-creation hook after the app is created if `hooks.post_creation` is specified in the `.controlplane/controlplane.yml` file
23
+ - If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
24
+ - Use `--skip-post-creation-hook` to skip the hook if specified in `controlplane.yml`
17
25
  DESC
26
+ VALIDATIONS = %w[config templates].freeze
18
27
 
19
- def call # rubocop:disable Metrics/MethodLength
28
+ def call # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
20
29
  templates = config[:setup_app_templates]
21
30
 
22
31
  app = cp.fetch_gvc
@@ -26,24 +35,79 @@ module Command
26
35
  "or run 'cpl apply-template #{templates.join(' ')} -a #{config.app}'."
27
36
  end
28
37
 
29
- Cpl::Cli.start(["apply-template", *templates, "-a", config.app])
38
+ skip_secrets_setup = config.options[:skip_secret_access_binding] ||
39
+ config.options[:skip_secrets_setup] || config.current[:skip_secrets_setup]
30
40
 
31
- return if config.options[:skip_secret_access_binding]
41
+ create_secret_and_policy_if_not_exist unless skip_secrets_setup
42
+
43
+ args = []
44
+ args.push("--add-app-identity") unless skip_secrets_setup
45
+ Cpl::Cli.start(["apply-template", *templates, "-a", config.app, *args])
46
+
47
+ bind_identity_to_policy unless skip_secrets_setup
48
+ run_post_creation_hook unless config.options[:skip_post_creation_hook]
49
+ end
50
+
51
+ private
52
+
53
+ def create_secret_and_policy_if_not_exist
54
+ create_secret_if_not_exists
55
+ create_policy_if_not_exists
32
56
 
33
57
  progress.puts
58
+ end
34
59
 
35
- if cp.fetch_identity(app_identity).nil? || cp.fetch_policy(app_secrets_policy).nil?
36
- raise "Can't bind identity to policy: identity '#{app_identity}' or " \
37
- "policy '#{app_secrets_policy}' doesn't exist. " \
38
- "Please create them or use `--skip-secret-access-binding` to ignore this message." \
39
- "You can also set a custom secrets name with `secrets_name` " \
40
- "and a custom secrets policy name with `secrets_policy_name` " \
41
- "in the `.controlplane/controlplane.yml` file."
60
+ def create_secret_if_not_exists
61
+ if cp.fetch_secret(config.secrets)
62
+ progress.puts("Secret '#{config.secrets}' already exists. Skipping creation...")
63
+ else
64
+ step("Creating secret '#{config.secrets}'") do
65
+ cp.apply_hash(build_secret_hash)
66
+ end
42
67
  end
68
+ end
43
69
 
44
- step("Binding identity to policy") do
45
- cp.bind_identity_to_policy(app_identity_link, app_secrets_policy)
70
+ def create_policy_if_not_exists
71
+ if cp.fetch_policy(config.secrets_policy)
72
+ progress.puts("Policy '#{config.secrets_policy}' already exists. Skipping creation...")
73
+ else
74
+ step("Creating policy '#{config.secrets_policy}'") do
75
+ cp.apply_hash(build_policy_hash)
76
+ end
46
77
  end
47
78
  end
79
+
80
+ def build_secret_hash
81
+ {
82
+ "kind" => "secret",
83
+ "name" => config.secrets,
84
+ "type" => "dictionary",
85
+ "data" => {}
86
+ }
87
+ end
88
+
89
+ def build_policy_hash
90
+ {
91
+ "kind" => "policy",
92
+ "name" => config.secrets_policy,
93
+ "targetKind" => "secret",
94
+ "targetLinks" => ["//secret/#{config.secrets}"]
95
+ }
96
+ end
97
+
98
+ def bind_identity_to_policy
99
+ progress.puts
100
+
101
+ step("Binding identity '#{config.identity}' to policy '#{config.secrets_policy}'") do
102
+ cp.bind_identity_to_policy(config.identity_link, config.secrets_policy)
103
+ end
104
+ end
105
+
106
+ def run_post_creation_hook
107
+ post_creation_hook = config.current.dig(:hooks, :post_creation)
108
+ return unless post_creation_hook
109
+
110
+ run_command_in_latest_image(post_creation_hook, title: "post-creation hook")
111
+ end
48
112
  end
49
113
  end
data/lib/command/test.rb CHANGED
@@ -11,6 +11,7 @@ module Command
11
11
  - For debugging purposes
12
12
  DESC
13
13
  HIDE = true
14
+ VALIDATIONS = [].freeze
14
15
 
15
16
  def call
16
17
  # Modify this method to trigger the code you want to test.
@@ -9,6 +9,7 @@ module Command
9
9
  - Can also be done with `cpl --version` or `cpl -v`
10
10
  DESC
11
11
  WITH_INFO_HEADER = false
12
+ VALIDATIONS = [].freeze
12
13
 
13
14
  def call
14
15
  puts Cpl::VERSION
data/lib/core/config.rb CHANGED
@@ -18,6 +18,8 @@ class Config # rubocop:disable Metrics/ClassLength
18
18
 
19
19
  ensure_required_options!
20
20
 
21
+ warn_deprecated_options
22
+
21
23
  Shell.verbose_mode(options[:verbose])
22
24
  trace_mode = options[:trace]
23
25
  return unless trace_mode
@@ -38,10 +40,34 @@ class Config # rubocop:disable Metrics/ClassLength
38
40
  current&.fetch(:name)
39
41
  end
40
42
 
43
+ def identity
44
+ "#{app}-identity"
45
+ end
46
+
47
+ def identity_link
48
+ "/org/#{org}/gvc/#{app}/identity/#{identity}"
49
+ end
50
+
51
+ def secrets
52
+ current&.dig(:secrets_name) || "#{app_prefix}-secrets"
53
+ end
54
+
55
+ def secrets_policy
56
+ current&.dig(:secrets_policy_name) || "#{secrets}-policy"
57
+ end
58
+
41
59
  def location
42
60
  @location ||= load_location_from_options || load_location_from_env || load_location_from_file
43
61
  end
44
62
 
63
+ def location_link
64
+ "/org/#{org}/location/#{location}"
65
+ end
66
+
67
+ def image_link(image)
68
+ "/org/#{org}/image/#{image}"
69
+ end
70
+
45
71
  def domain
46
72
  @domain ||= load_domain_from_options || load_domain_from_file
47
73
  end
@@ -84,6 +110,8 @@ class Config # rubocop:disable Metrics/ClassLength
84
110
  @apps ||= config[:apps].to_h do |app_name, app_options|
85
111
  ensure_config_app!(app_name, app_options)
86
112
 
113
+ check_deprecated_options(app_options)
114
+
87
115
  app_options_with_new_keys = app_options.to_h do |key, value|
88
116
  new_key = new_option_keys[key]
89
117
  new_key ? [new_key, value] : [key, value]
@@ -96,14 +124,7 @@ class Config # rubocop:disable Metrics/ClassLength
96
124
  def current
97
125
  return unless app
98
126
 
99
- @current ||= begin
100
- app_config = find_app_config(app)
101
- ensure_config_app!(app, app_config)
102
-
103
- warn_deprecated_options(app_config)
104
-
105
- app_config
106
- end
127
+ @current ||= find_app_config(app)
107
128
  end
108
129
 
109
130
  def app_matches?(app_name1, app_name2, app_options)
@@ -275,11 +296,18 @@ class Config # rubocop:disable Metrics/ClassLength
275
296
  strip_str_and_validate(current.fetch(:default_domain))
276
297
  end
277
298
 
278
- def warn_deprecated_options(app_options)
279
- deprecated_option_keys = new_option_keys.select { |old_key| app_options.key?(old_key) }
280
- return if deprecated_option_keys.empty?
299
+ def check_deprecated_options(app_options)
300
+ @deprecated_option_keys ||= {}
301
+
302
+ new_option_keys.each do |old_key, new_key|
303
+ @deprecated_option_keys[old_key] = new_key if app_options.key?(old_key)
304
+ end
305
+ end
306
+
307
+ def warn_deprecated_options
308
+ return if !@deprecated_option_keys || @deprecated_option_keys.empty?
281
309
 
282
- deprecated_option_keys.each do |old_key, new_key|
310
+ @deprecated_option_keys.each do |old_key, new_key|
283
311
  Shell.warn_deprecated("Option '#{old_key}' is deprecated, " \
284
312
  "please use '#{new_key}' instead (in 'controlplane.yml').")
285
313
  end
@@ -3,6 +3,8 @@
3
3
  class Controlplane # rubocop:disable Metrics/ClassLength
4
4
  attr_reader :config, :api, :gvc, :org
5
5
 
6
+ NO_IMAGE_AVAILABLE = "NO_IMAGE_AVAILABLE"
7
+
6
8
  def initialize(config)
7
9
  @config = config
8
10
  @api = ControlplaneApi.new
@@ -37,6 +39,51 @@ class Controlplane # rubocop:disable Metrics/ClassLength
37
39
 
38
40
  # image
39
41
 
42
+ def latest_image(a_gvc = gvc, a_org = org, refresh: false)
43
+ @latest_image ||= {}
44
+ @latest_image[a_gvc] = nil if refresh
45
+ @latest_image[a_gvc] ||=
46
+ begin
47
+ items = query_images(a_gvc, a_org)["items"]
48
+ latest_image_from(items, app_name: a_gvc)
49
+ end
50
+ end
51
+
52
+ def latest_image_next(a_gvc = gvc, a_org = org, commit: nil)
53
+ commit ||= config.options[:commit]
54
+
55
+ @latest_image_next ||= {}
56
+ @latest_image_next[a_gvc] ||= begin
57
+ latest_image_name = latest_image(a_gvc, a_org)
58
+ image = latest_image_name.split(":").first
59
+ image += ":#{extract_image_number(latest_image_name) + 1}"
60
+ image += "_#{commit}" if commit
61
+ image
62
+ end
63
+ end
64
+
65
+ def latest_image_from(items, app_name: gvc, name_only: true)
66
+ matching_items = items.select { |item| item["name"].start_with?("#{app_name}:") }
67
+
68
+ # Or special string to indicate no image available
69
+ if matching_items.empty?
70
+ name_only ? "#{app_name}:#{NO_IMAGE_AVAILABLE}" : nil
71
+ else
72
+ latest_item = matching_items.max_by { |item| extract_image_number(item["name"]) }
73
+ name_only ? latest_item["name"] : latest_item
74
+ end
75
+ end
76
+
77
+ def extract_image_number(image_name)
78
+ return 0 if image_name.end_with?(NO_IMAGE_AVAILABLE)
79
+
80
+ image_name.match(/:(\d+)/)&.captures&.first.to_i
81
+ end
82
+
83
+ def extract_image_commit(image_name)
84
+ image_name.match(/_(\h+)$/)&.captures&.first
85
+ end
86
+
40
87
  def query_images(a_gvc = gvc, a_org = org, partial_gvc_match: nil)
41
88
  partial_gvc_match = config.should_app_start_with?(a_gvc) if partial_gvc_match.nil?
42
89
  gvc_op = partial_gvc_match ? "~" : "="
@@ -209,6 +256,11 @@ class Controlplane # rubocop:disable Metrics/ClassLength
209
256
  api.update_workload(org: org, gvc: gvc, workload: workload, data: data)
210
257
  end
211
258
 
259
+ def workload_suspended?(workload)
260
+ details = fetch_workload!(workload)
261
+ details["spec"]["defaultOptions"]["suspend"]
262
+ end
263
+
212
264
  def workload_force_redeployment(workload)
213
265
  cmd = "cpln workload force-redeployment #{workload} #{gvc_org}"
214
266
  perform!(cmd)
@@ -324,6 +376,12 @@ class Controlplane # rubocop:disable Metrics/ClassLength
324
376
  api.log_get(org: org, gvc: gvc, workload: workload, replica: replica, from: from, to: to)
325
377
  end
326
378
 
379
+ # secrets
380
+
381
+ def fetch_secret(secret)
382
+ api.fetch_secret(org: org, secret: secret)
383
+ end
384
+
327
385
  # identities
328
386
 
329
387
  def fetch_identity(identity, a_gvc = gvc)
@@ -52,7 +52,7 @@ class ControlplaneApi # rubocop:disable Metrics/ClassLength
52
52
  # params << "direction=forward"
53
53
  params = params.map { |k, v| %(#{k}=#{CGI.escape(v)}) }.join("&")
54
54
 
55
- api_json_direct("/logs/org/#{org}/loki/api/v1/query_range?#{params}", method: :get, host: :logs)
55
+ api_json("/logs/org/#{org}/loki/api/v1/query_range?#{params}", method: :get, host: :logs)
56
56
  end
57
57
 
58
58
  def query_workloads(org:, gvc:, workload:, gvc_op_type:, workload_op_type:) # rubocop:disable Metrics/MethodLength
@@ -116,6 +116,14 @@ class ControlplaneApi # rubocop:disable Metrics/ClassLength
116
116
  api_json("/org/#{org}/domain/#{domain}", method: :patch, body: data)
117
117
  end
118
118
 
119
+ def fetch_secret(org:, secret:)
120
+ api_json("/org/#{org}/secret/#{secret}", method: :get)
121
+ end
122
+
123
+ def delete_secret(org:, secret:)
124
+ api_json("/org/#{org}/secret/#{secret}", method: :delete)
125
+ end
126
+
119
127
  def fetch_identity(org:, gvc:, identity:)
120
128
  api_json("/org/#{org}/gvc/#{gvc}/identity/#{identity}", method: :get)
121
129
  end
@@ -124,6 +132,10 @@ class ControlplaneApi # rubocop:disable Metrics/ClassLength
124
132
  api_json("/org/#{org}/policy/#{policy}", method: :get)
125
133
  end
126
134
 
135
+ def delete_policy(org:, policy:)
136
+ api_json("/org/#{org}/policy/#{policy}", method: :delete)
137
+ end
138
+
127
139
  private
128
140
 
129
141
  def fetch_query_pages(result)
@@ -152,13 +164,7 @@ class ControlplaneApi # rubocop:disable Metrics/ClassLength
152
164
  result
153
165
  end
154
166
 
155
- # switch between cpln rest and api
156
167
  def api_json(...)
157
168
  ControlplaneApiDirect.new.call(...)
158
169
  end
159
-
160
- # only for api (where not impelemented in cpln rest)
161
- def api_json_direct(...)
162
- ControlplaneApiDirect.new.call(...)
163
- end
164
170
  end
@@ -98,7 +98,7 @@ class ControlplaneApiDirect
98
98
  end
99
99
 
100
100
  def refresh_api_token
101
- @@api_token[:token] = `cpln profile token`.chomp
101
+ @@api_token[:token] = Shell.cmd("cpln", "profile", "token")[:output].chomp
102
102
  end
103
103
 
104
104
  def self.reset_api_token