cpl 2.1.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 468f47cb0e1cf3cdb710b885949188c68f40fd74ad4236379a5a6c6fd55739c1
4
- data.tar.gz: fc83d4ef5ee3ded08d52ca5f2df92e5ee261df6fcefd27f673452d0ba265a650
3
+ metadata.gz: 27661f3a2e2aff2f7018e2cb0e77835ee4de88a8ee0268ec549cafa9d02dfbaa
4
+ data.tar.gz: 001a114b051c3501b5449eb6d3e4c9f7dea3fa608c6e4595e2129c3bcad8f855
5
5
  SHA512:
6
- metadata.gz: dac1051680d2b3c69473636a9babd19b8799ea6e2eaadbb26582836641f7a73e843e4a26c32f41206edb0a6b21ab89b9b62cc08087360d75a562c3b6bb40188d
7
- data.tar.gz: 52ca1f46ff0d459f450e1a1bd82b6efce780e9b6480ebbda955722eef4bea3a98d71cdaff076691b4cfe93e77c42285f358bfb4ba9adf857c961108302a4f5d6
6
+ metadata.gz: 38dfd9ca9aa2d28dc7df577677e5732f37740448beb857269ff156da7a8ff2f8627872c958b63e9d1d308ce091df1376e44c09aff96bc82f128edb887e1aba94
7
+ data.tar.gz: 14c73bf485166dd5be51ff276b6cef8aa3152bb0482fd92b6752e47575cd43ab0bd620ba1c49de619863cff955b628477eb32188a8f76393423c50b1a81e5b07
data/CHANGELOG.md CHANGED
@@ -16,6 +16,22 @@ _Please add entries here for your pull requests that have not yet been released.
16
16
 
17
17
  ### Fixed
18
18
 
19
+ - Fixed issue where `ps:wait` command hangs forever if workloads are suspended. [PR 198](https://github.com/shakacode/control-plane-flow/pull/198) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
20
+
21
+ ### Added
22
+
23
+ - Added a timeout for `run` jobs (6 hours by default, but configurable through `runner_job_timeout` in `controlplane.yml`). [PR 194](https://github.com/shakacode/control-plane-flow/pull/194) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
24
+
25
+ ### Changed
26
+
27
+ - `run` command now overrides the `--image`, `--cpu`, and `--memory` for each job separately, which completely removes any race conditions when running simultaneous jobs with different overrides. [PR 182](https://github.com/shakacode/control-plane-flow/pull/182) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
28
+ - `run` jobs now use a CPU size of 1 (1 core) and a memory size of 2Gi (2 gibibytes) by default (configurable through `runner_job_default_cpu` and `runner_job_default_memory` in `controlplane.yml`). [PR 182](https://github.com/shakacode/control-plane-flow/pull/182) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
29
+ - `run` command now keeps ENV values synced between original and runner workloads. [PR 196](https://github.com/shakacode/control-plane-flow/pull/196) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
30
+
31
+ ## [2.1.0] - 2024-05-27
32
+
33
+ ### Fixed
34
+
19
35
  - Fixed issue where release script was not running from the app image. [PR 183](https://github.com/shakacode/control-plane-flow/pull/183) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
20
36
  - Fixed issue where deprecated options were not being warned. [PR 183](https://github.com/shakacode/control-plane-flow/pull/183) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
21
37
 
@@ -214,7 +230,8 @@ _Please add entries here for your pull requests that have not yet been released.
214
230
 
215
231
  - Initial release
216
232
 
217
- [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v2.0.2...HEAD
233
+ [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v2.1.0...HEAD
234
+ [2.1.0]: https://github.com/shakacode/control-plane-flow/compare/v2.0.2...v2.1.0
218
235
  [2.0.2]: https://github.com/shakacode/control-plane-flow/compare/v2.0.1...v2.0.2
219
236
  [2.0.1]: https://github.com/shakacode/control-plane-flow/compare/v2.0.0...v2.0.1
220
237
  [2.0.0]: https://github.com/shakacode/control-plane-flow/compare/v1.4.0...v2.0.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpl (2.1.0)
4
+ cpl (2.2.0)
5
5
  debug (~> 1.7.1)
6
6
  dotenv (~> 2.8.1)
7
7
  jwt (~> 2.8.1)
@@ -52,7 +52,7 @@ GEM
52
52
  rdoc (6.7.0)
53
53
  psych (>= 4.0.0)
54
54
  regexp_parser (2.9.0)
55
- reline (0.5.7)
55
+ reline (0.5.8)
56
56
  io-console (~> 0.5)
57
57
  rexml (3.2.6)
58
58
  rspec (3.12.0)
data/README.md CHANGED
@@ -249,6 +249,18 @@ aliases:
249
249
  # when running `cpl run`.
250
250
  fix_terminal_size: true
251
251
 
252
+ # Sets a default CPU size for `cpl run` jobs (can be overridden per job through `--cpu`).
253
+ # If not specified, defaults to "1" (1 core).
254
+ runner_job_default_cpu: "2"
255
+
256
+ # Sets a default memory size for `cpl run` jobs (can be overridden per job through `--memory`).
257
+ # If not specified, defaults to "2Gi" (2 gibibytes).
258
+ runner_job_default_memory: "4Gi"
259
+
260
+ # Sets the maximum number of seconds that `cpl run` jobs can execute before being stopped.
261
+ # If not specified, defaults to 21600 (6 hours).
262
+ runner_job_timeout: 1000
263
+
252
264
  # Apps with a deployed image created before this amount of days will be listed for deletion
253
265
  # when running the command `cpl cleanup-stale-apps`.
254
266
  stale_app_image_deployed_days: 5
data/docs/commands.md CHANGED
@@ -371,12 +371,17 @@ cpl ps:swait -a $APP_NAME -w $WORKLOAD_NAME
371
371
  - - log async fetching for non-interactive mode
372
372
  - The Dockerfile entrypoint is used as the command by default, which assumes `exec "${@}"` to be present,
373
373
  and the args ["bash", "-c", cmd_to_run] are passed
374
- - The entrypoint can be overriden through `--entrypoint`, which must be a single command or a script path that exists in the container,
374
+ - The entrypoint can be overridden through `--entrypoint`, which must be a single command or a script path that exists in the container,
375
375
  and the args ["bash", "-c", cmd_to_run] are passed,
376
376
  unless the entrypoint is `bash`, in which case the args ["-c", cmd_to_run] are passed
377
377
  - Providing `--entrypoint none` sets the entrypoint to `bash` by default
378
378
  - If `fix_terminal_size` is `true` in the `.controlplane/controlplane.yml` file,
379
- the remote terminal size will be fixed to match the local terminal size (may also be overriden through `--terminal-size`)
379
+ the remote terminal size will be fixed to match the local terminal size (may also be overridden through `--terminal-size`)
380
+ - By default, all jobs use a CPU size of 1 (1 core) and a memory size of 2Gi (2 gibibytes)
381
+ (can be configured through `runner_job_default_cpu` and `runner_job_default_memory` in `controlplane.yml`,
382
+ and also overridden per job through `--cpu` and `--memory`)
383
+ - By default, the job is stopped if it takes longer than 6 hours to finish
384
+ (can be configured though `runner_job_timeout` in `controlplane.yml`)
380
385
 
381
386
  ```sh
382
387
  # Opens shell (bash by default).
@@ -84,6 +84,18 @@ aliases:
84
84
  # when running `cpl run`.
85
85
  fix_terminal_size: true
86
86
 
87
+ # Sets a default CPU size for `cpl run` jobs (can be overridden per job through `--cpu`).
88
+ # If not specified, defaults to "1" (1 core).
89
+ runner_job_default_cpu: "2"
90
+
91
+ # Sets a default memory size for `cpl run` jobs (can be overridden per job through `--memory`).
92
+ # If not specified, defaults to "2Gi" (2 gibibytes).
93
+ runner_job_default_memory: "4Gi"
94
+
95
+ # Sets the maximum number of seconds that `cpl run` jobs can execute before being stopped.
96
+ # If not specified, defaults to 21600 (6 hours).
97
+ runner_job_timeout: 1000
98
+
87
99
  # Apps with a deployed image created before this amount of days will be listed for deletion
88
100
  # when running the command `cpl cleanup-stale-apps`.
89
101
  stale_app_image_deployed_days: 5
@@ -22,13 +22,17 @@ module Command
22
22
  ```
23
23
  EX
24
24
 
25
- def call
25
+ def call # rubocop:disable Metrics/MethodLength
26
26
  @workloads = [config.options[:workload]] if config.options[:workload]
27
27
  @workloads ||= config[:app_workloads] + config[:additional_workloads]
28
28
 
29
29
  @workloads.reverse_each do |workload|
30
- step("Waiting for workload '#{workload}' to be ready", retry_on_failure: true) do
31
- cp.workload_deployments_ready?(workload, location: config.location, expected_status: true)
30
+ if cp.workload_suspended?(workload)
31
+ progress.puts("Workload '#{workload}' is suspended. Skipping...")
32
+ else
33
+ step("Waiting for workload '#{workload}' to be ready", retry_on_failure: true) do
34
+ cp.workload_deployments_ready?(workload, location: config.location, expected_status: true)
35
+ end
32
36
  end
33
37
  end
34
38
  end
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 = cp.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
@@ -256,6 +256,11 @@ class Controlplane # rubocop:disable Metrics/ClassLength
256
256
  api.update_workload(org: org, gvc: gvc, workload: workload, data: data)
257
257
  end
258
258
 
259
+ def workload_suspended?(workload)
260
+ details = fetch_workload!(workload)
261
+ details["spec"]["defaultOptions"]["suspend"]
262
+ end
263
+
259
264
  def workload_force_redeployment(workload)
260
265
  cmd = "cpln workload force-redeployment #{workload} #{gvc_org}"
261
266
  perform!(cmd)
data/lib/cpl/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpl
4
- VERSION = "2.1.0"
4
+ VERSION = "2.2.0"
5
5
  MIN_CPLN_VERSION = "2.0.1"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpl
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-05-27 00:00:00.000000000 Z
12
+ date: 2024-06-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug