cpl 1.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/command_docs.yml +1 -1
- data/.github/workflows/rspec-shared.yml +56 -0
- data/.github/workflows/rspec.yml +19 -31
- data/.github/workflows/rubocop.yml +2 -10
- data/.gitignore +2 -0
- data/.simplecov_spawn.rb +10 -0
- data/CHANGELOG.md +28 -1
- data/CONTRIBUTING.md +32 -2
- data/Gemfile.lock +38 -29
- data/README.md +43 -17
- data/cpl.gemspec +2 -1
- data/docs/commands.md +68 -59
- data/docs/dns.md +6 -0
- data/docs/migrating.md +10 -10
- data/docs/tips.md +15 -3
- data/examples/circleci.yml +3 -3
- data/examples/controlplane.yml +35 -9
- data/lib/command/apply_template.rb +66 -18
- data/lib/command/base.rb +168 -27
- data/lib/command/build_image.rb +4 -9
- data/lib/command/cleanup_stale_apps.rb +1 -3
- data/lib/command/copy_image_from_upstream.rb +0 -7
- data/lib/command/delete.rb +39 -7
- data/lib/command/deploy_image.rb +35 -2
- data/lib/command/exists.rb +1 -1
- data/lib/command/generate.rb +1 -1
- data/lib/command/info.rb +7 -3
- data/lib/command/logs.rb +22 -2
- data/lib/command/maintenance_off.rb +1 -1
- data/lib/command/maintenance_on.rb +1 -1
- data/lib/command/open.rb +2 -2
- data/lib/command/open_console.rb +2 -2
- data/lib/command/promote_app_from_upstream.rb +5 -25
- data/lib/command/ps.rb +1 -1
- data/lib/command/ps_start.rb +2 -1
- data/lib/command/ps_stop.rb +40 -8
- data/lib/command/ps_wait.rb +3 -2
- data/lib/command/run.rb +430 -68
- data/lib/command/setup_app.rb +22 -2
- data/lib/constants/exit_code.rb +7 -0
- data/lib/core/config.rb +11 -3
- data/lib/core/controlplane.rb +126 -47
- data/lib/core/controlplane_api.rb +15 -1
- data/lib/core/controlplane_api_cli.rb +3 -3
- data/lib/core/controlplane_api_direct.rb +33 -5
- data/lib/core/shell.rb +15 -9
- data/lib/cpl/version.rb +1 -1
- data/lib/cpl.rb +50 -9
- data/lib/deprecated_commands.json +2 -1
- data/lib/generator_templates/controlplane.yml +5 -0
- data/lib/generator_templates/templates/{gvc.yml → app.yml} +4 -4
- data/lib/generator_templates/templates/postgres.yml +1 -1
- data/lib/generator_templates/templates/rails.yml +1 -1
- data/script/check_cpln_links +3 -3
- data/templates/app.yml +18 -0
- data/templates/daily-task.yml +3 -2
- data/templates/rails.yml +3 -2
- data/templates/secrets.yml +11 -0
- data/templates/sidekiq.yml +3 -2
- metadata +38 -25
- data/.rspec +0 -1
- data/lib/command/run_cleanup.rb +0 -116
- data/lib/command/run_detached.rb +0 -175
- data/lib/core/scripts.rb +0 -34
- data/templates/gvc.yml +0 -13
- data/templates/identity.yml +0 -2
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,44 +266,128 @@ module Command
|
|
237
266
|
}
|
238
267
|
end
|
239
268
|
|
240
|
-
def self.
|
269
|
+
def self.skip_secret_access_binding_option(required: false)
|
241
270
|
{
|
242
|
-
name: :
|
271
|
+
name: :skip_secret_access_binding,
|
243
272
|
params: {
|
244
|
-
desc: "
|
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:
|
299
|
+
default: 200
|
248
300
|
}
|
249
301
|
}
|
250
302
|
end
|
251
303
|
|
252
|
-
def self.
|
253
|
-
|
304
|
+
def self.logs_since_option(required: false)
|
305
|
+
{
|
306
|
+
name: :since,
|
307
|
+
params: {
|
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
|
+
}
|
254
316
|
end
|
255
317
|
|
256
|
-
def self.
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
318
|
+
def self.interactive_option(required: false)
|
319
|
+
{
|
320
|
+
name: :interactive,
|
321
|
+
params: {
|
322
|
+
desc: "Runs interactive command",
|
323
|
+
type: :boolean,
|
324
|
+
required: required
|
325
|
+
}
|
326
|
+
}
|
261
327
|
end
|
262
328
|
|
263
|
-
def
|
264
|
-
|
265
|
-
|
266
|
-
|
329
|
+
def self.detached_option(required: false)
|
330
|
+
{
|
331
|
+
name: :detached,
|
332
|
+
params: {
|
333
|
+
desc: "Runs non-interactive command, detaches, and prints commands to log and stop the job",
|
334
|
+
type: :boolean,
|
335
|
+
required: required
|
336
|
+
}
|
337
|
+
}
|
267
338
|
end
|
268
339
|
|
269
|
-
def
|
270
|
-
|
271
|
-
|
272
|
-
|
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
|
+
}
|
273
352
|
end
|
274
353
|
|
275
|
-
def
|
276
|
-
|
277
|
-
|
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
|
+
}
|
366
|
+
end
|
367
|
+
|
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
|
+
}
|
380
|
+
end
|
381
|
+
# rubocop:enable Metrics/MethodLength
|
382
|
+
|
383
|
+
def self.all_options
|
384
|
+
methods.grep(/_option$/).map { |method| send(method.to_s) }
|
385
|
+
end
|
386
|
+
|
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
|
278
391
|
end
|
279
392
|
end
|
280
393
|
|
@@ -290,8 +403,9 @@ module Command
|
|
290
403
|
end
|
291
404
|
end
|
292
405
|
|
293
|
-
def latest_image(app = config.app, org = config.org)
|
406
|
+
def latest_image(app = config.app, org = config.org, refresh: false)
|
294
407
|
@latest_image ||= {}
|
408
|
+
@latest_image[app] = nil if refresh
|
295
409
|
@latest_image[app] ||=
|
296
410
|
begin
|
297
411
|
items = cp.query_images(app, org)["items"]
|
@@ -355,7 +469,7 @@ module Command
|
|
355
469
|
if retry_on_failure
|
356
470
|
until (success = yield)
|
357
471
|
progress.print(".")
|
358
|
-
sleep
|
472
|
+
Kernel.sleep(1)
|
359
473
|
end
|
360
474
|
else
|
361
475
|
success = yield
|
@@ -372,8 +486,35 @@ module Command
|
|
372
486
|
@cp ||= Controlplane.new(config)
|
373
487
|
end
|
374
488
|
|
375
|
-
def
|
376
|
-
|
489
|
+
def app_location_link
|
490
|
+
"/org/#{config.org}/location/#{config.location}"
|
491
|
+
end
|
492
|
+
|
493
|
+
def app_image_link
|
494
|
+
"/org/#{config.org}/image/#{latest_image}"
|
495
|
+
end
|
496
|
+
|
497
|
+
def app_identity
|
498
|
+
"#{config.app}-identity"
|
499
|
+
end
|
500
|
+
|
501
|
+
def app_identity_link
|
502
|
+
"/org/#{config.org}/gvc/#{config.app}/identity/#{app_identity}"
|
503
|
+
end
|
504
|
+
|
505
|
+
def app_secrets
|
506
|
+
config.current[:secrets_name] || "#{config.app_prefix}-secrets"
|
507
|
+
end
|
508
|
+
|
509
|
+
def 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."
|
377
518
|
end
|
378
519
|
|
379
520
|
private
|
data/lib/command/build_image.rb
CHANGED
@@ -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
|
-
|
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
|
@@ -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"
|
@@ -23,7 +21,7 @@ module Command
|
|
23
21
|
|
24
22
|
progress.puts("Stale apps:")
|
25
23
|
stale_apps.each do |app|
|
26
|
-
progress.puts(" #{app[:name]} (#{Shell.color((app[:date]).to_s, :red)})")
|
24
|
+
progress.puts(" - #{app[:name]} (#{Shell.color((app[:date]).to_s, :red)})")
|
27
25
|
end
|
28
26
|
|
29
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
|
|
data/lib/command/delete.rb
CHANGED
@@ -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 '#{
|
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
|
data/lib/command/deploy_image.rb
CHANGED
@@ -4,17 +4,28 @@ 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 release script is run in the context of `cpl run` with the latest image
|
15
|
+
- The deploy will fail if the release script exits with a non-zero code or doesn't exist
|
12
16
|
DESC
|
13
17
|
|
14
18
|
def call # rubocop:disable Metrics/MethodLength
|
19
|
+
run_release_script if config.options[:run_release_phase]
|
20
|
+
|
15
21
|
deployed_endpoints = {}
|
16
22
|
|
17
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
|
18
29
|
|
19
30
|
config[:app_workloads].each do |workload|
|
20
31
|
workload_data = cp.fetch_workload!(workload)
|
@@ -34,5 +45,27 @@ module Command
|
|
34
45
|
progress.puts(" - #{workload}: #{endpoint}")
|
35
46
|
end
|
36
47
|
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def run_release_script # rubocop:disable Metrics/MethodLength
|
52
|
+
release_script_name = config[:release_script]
|
53
|
+
release_script_path = Pathname.new("#{config.app_cpln_dir}/#{release_script_name}").expand_path
|
54
|
+
|
55
|
+
raise "Can't find release script in '#{release_script_path}'." unless File.exist?(release_script_path)
|
56
|
+
|
57
|
+
progress.puts("Running release script...\n\n")
|
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
|
69
|
+
end
|
37
70
|
end
|
38
71
|
end
|
data/lib/command/exists.rb
CHANGED
data/lib/command/generate.rb
CHANGED
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
|
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
|
-
|
94
|
-
result.push(app_name.to_s) if
|
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
|
-
|
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
|
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 =
|
28
|
+
opener = Shell.cmd("which", "xdg-open", "open")[:output].split("\n").grep_v("not found").first
|
29
29
|
|
30
|
-
exec
|
30
|
+
Kernel.exec(opener, url)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
data/lib/command/open_console.rb
CHANGED
@@ -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 =
|
21
|
+
opener = Shell.cmd("which", "xdg-open", "open")[:output].split("\n").grep_v("not found").first
|
22
22
|
|
23
|
-
exec
|
23
|
+
Kernel.exec(opener, url)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
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
|
-
|
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/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.
|
36
|
+
result = cp.fetch_workload_replicas(workload, location: location)
|
37
37
|
result["items"].each { |replica| puts replica }
|
38
38
|
end
|
39
39
|
end
|