cpl 2.0.2 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +22 -1
- data/Gemfile.lock +2 -2
- data/README.md +12 -3
- data/docs/commands.md +30 -6
- data/docs/secrets-and-env-values.md +42 -0
- data/docs/tips.md +1 -40
- data/examples/controlplane.yml +12 -3
- data/lib/command/apply_template.rb +70 -80
- data/lib/command/base.rb +82 -71
- data/lib/command/build_image.rb +2 -2
- data/lib/command/cleanup_images.rb +1 -1
- data/lib/command/cleanup_stale_apps.rb +1 -1
- data/lib/command/copy_image_from_upstream.rb +3 -3
- data/lib/command/delete.rb +17 -5
- data/lib/command/deploy_image.rb +6 -21
- data/lib/command/doctor.rb +47 -0
- data/lib/command/latest_image.rb +1 -1
- data/lib/command/no_command.rb +1 -0
- data/lib/command/promote_app_from_upstream.rb +1 -1
- data/lib/command/run.rb +1 -1
- data/lib/command/setup_app.rb +80 -16
- data/lib/command/test.rb +1 -0
- data/lib/command/version.rb +1 -0
- data/lib/core/config.rb +40 -12
- data/lib/core/controlplane.rb +53 -0
- data/lib/core/controlplane_api.rb +13 -7
- data/lib/core/controlplane_api_direct.rb +1 -1
- data/lib/core/doctor_service.rb +104 -0
- data/lib/core/helpers.rb +10 -0
- data/lib/core/template_parser.rb +76 -0
- data/lib/cpl/version.rb +1 -1
- data/lib/cpl.rb +24 -6
- data/templates/app.yml +0 -5
- metadata +6 -4
- data/lib/core/controlplane_api_cli.rb +0 -10
- data/templates/secrets.yml +0 -11
data/lib/command/base.rb
CHANGED
@@ -8,6 +8,10 @@ module Command
|
|
8
8
|
|
9
9
|
include Helpers
|
10
10
|
|
11
|
+
VALIDATIONS_WITHOUT_ADDITIONAL_OPTIONS = %w[config].freeze
|
12
|
+
VALIDATIONS_WITH_ADDITIONAL_OPTIONS = %w[templates].freeze
|
13
|
+
ALL_VALIDATIONS = VALIDATIONS_WITHOUT_ADDITIONAL_OPTIONS + VALIDATIONS_WITH_ADDITIONAL_OPTIONS
|
14
|
+
|
11
15
|
# Used to call the command (`cpl NAME`)
|
12
16
|
# NAME = ""
|
13
17
|
# Displayed when running `cpl help` or `cpl help NAME` (defaults to `NAME`)
|
@@ -32,8 +36,8 @@ module Command
|
|
32
36
|
HIDE = false
|
33
37
|
# Whether or not to show key information like ORG and APP name in commands
|
34
38
|
WITH_INFO_HEADER = true
|
35
|
-
|
36
|
-
|
39
|
+
# Which validations to run before the command
|
40
|
+
VALIDATIONS = %w[config].freeze
|
37
41
|
|
38
42
|
def initialize(config)
|
39
43
|
@config = config
|
@@ -269,6 +273,7 @@ module Command
|
|
269
273
|
def self.skip_secret_access_binding_option(required: false)
|
270
274
|
{
|
271
275
|
name: :skip_secret_access_binding,
|
276
|
+
new_name: :skip_secrets_setup,
|
272
277
|
params: {
|
273
278
|
desc: "Skips secret access binding",
|
274
279
|
type: :boolean,
|
@@ -277,6 +282,17 @@ module Command
|
|
277
282
|
}
|
278
283
|
end
|
279
284
|
|
285
|
+
def self.skip_secrets_setup_option(required: false)
|
286
|
+
{
|
287
|
+
name: :skip_secrets_setup,
|
288
|
+
params: {
|
289
|
+
desc: "Skips secrets setup",
|
290
|
+
type: :boolean,
|
291
|
+
required: required
|
292
|
+
}
|
293
|
+
}
|
294
|
+
end
|
295
|
+
|
280
296
|
def self.run_release_phase_option(required: false)
|
281
297
|
{
|
282
298
|
name: :run_release_phase,
|
@@ -378,57 +394,65 @@ module Command
|
|
378
394
|
}
|
379
395
|
}
|
380
396
|
end
|
381
|
-
# rubocop:enable Metrics/MethodLength
|
382
397
|
|
383
|
-
def self.
|
384
|
-
|
398
|
+
def self.validations_option(required: false)
|
399
|
+
{
|
400
|
+
name: :validations,
|
401
|
+
params: {
|
402
|
+
banner: "VALIDATION_1,VALIDATION_2,...",
|
403
|
+
desc: "Which validations to run " \
|
404
|
+
"(must be separated by a comma)",
|
405
|
+
type: :string,
|
406
|
+
required: required,
|
407
|
+
default: VALIDATIONS_WITHOUT_ADDITIONAL_OPTIONS.join(","),
|
408
|
+
valid_regex: /^(#{ALL_VALIDATIONS.join("|")})(,(#{ALL_VALIDATIONS.join("|")}))*$/
|
409
|
+
}
|
410
|
+
}
|
385
411
|
end
|
386
412
|
|
387
|
-
def self.
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
413
|
+
def self.skip_post_creation_hook_option(required: false)
|
414
|
+
{
|
415
|
+
name: :skip_post_creation_hook,
|
416
|
+
params: {
|
417
|
+
desc: "Skips post-creation hook",
|
418
|
+
type: :boolean,
|
419
|
+
required: required
|
420
|
+
}
|
421
|
+
}
|
392
422
|
end
|
393
423
|
|
394
|
-
def
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
end
|
424
|
+
def self.skip_pre_deletion_hook_option(required: false)
|
425
|
+
{
|
426
|
+
name: :skip_pre_deletion_hook,
|
427
|
+
params: {
|
428
|
+
desc: "Skips pre-deletion hook",
|
429
|
+
type: :boolean,
|
430
|
+
required: required
|
431
|
+
}
|
432
|
+
}
|
404
433
|
end
|
405
434
|
|
406
|
-
def
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
435
|
+
def self.add_app_identity_option(required: false)
|
436
|
+
{
|
437
|
+
name: :add_app_identity,
|
438
|
+
params: {
|
439
|
+
desc: "Adds app identity template if it does not exist",
|
440
|
+
type: :boolean,
|
441
|
+
required: required
|
442
|
+
}
|
443
|
+
}
|
414
444
|
end
|
445
|
+
# rubocop:enable Metrics/MethodLength
|
415
446
|
|
416
|
-
def
|
417
|
-
|
418
|
-
commit ||= config.options[:commit]
|
419
|
-
|
420
|
-
@latest_image_next ||= {}
|
421
|
-
@latest_image_next[app] ||= begin
|
422
|
-
latest_image_name = latest_image(app, org)
|
423
|
-
image = latest_image_name.split(":").first
|
424
|
-
image += ":#{extract_image_number(latest_image_name) + 1}"
|
425
|
-
image += "_#{commit}" if commit
|
426
|
-
image
|
427
|
-
end
|
447
|
+
def self.all_options
|
448
|
+
methods.grep(/_option$/).map { |method| send(method.to_s) }
|
428
449
|
end
|
429
450
|
|
430
|
-
def
|
431
|
-
|
451
|
+
def self.all_options_by_key_name
|
452
|
+
all_options.each_with_object({}) do |option, result|
|
453
|
+
option[:params][:aliases]&.each { |current_alias| result[current_alias.to_s] = option }
|
454
|
+
result["--#{option[:name]}"] = option
|
455
|
+
end
|
432
456
|
end
|
433
457
|
|
434
458
|
# NOTE: use simplified variant atm, as shelljoin do different escaping
|
@@ -486,30 +510,6 @@ module Command
|
|
486
510
|
@cp ||= Controlplane.new(config)
|
487
511
|
end
|
488
512
|
|
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
513
|
def ensure_docker_running!
|
514
514
|
result = Shell.cmd("docker", "version", capture_stderr: true)
|
515
515
|
return if result[:success]
|
@@ -517,13 +517,24 @@ module Command
|
|
517
517
|
raise "Can't run Docker. Please make sure that it's installed and started, then try again."
|
518
518
|
end
|
519
519
|
|
520
|
-
|
520
|
+
def run_command_in_latest_image(command, title:)
|
521
|
+
# Need to prefix the command with '.controlplane/'
|
522
|
+
# if it's a file in the '.controlplane' directory,
|
523
|
+
# for backwards compatibility
|
524
|
+
path = Pathname.new("#{config.app_cpln_dir}/#{command}").expand_path
|
525
|
+
command = ".controlplane/#{command}" if File.exist?(path)
|
526
|
+
|
527
|
+
progress.puts("Running #{title}...\n\n")
|
521
528
|
|
522
|
-
|
523
|
-
|
524
|
-
|
529
|
+
begin
|
530
|
+
Cpl::Cli.start(["run", "-a", config.app, "--image", "latest", "--", command])
|
531
|
+
rescue SystemExit => e
|
532
|
+
progress.puts
|
525
533
|
|
526
|
-
|
534
|
+
raise "Failed to run #{title}." if e.status.nonzero?
|
535
|
+
|
536
|
+
progress.puts("Finished running #{title}.\n\n")
|
537
|
+
end
|
527
538
|
end
|
528
539
|
end
|
529
540
|
end
|
data/lib/command/build_image.rb
CHANGED
@@ -27,7 +27,7 @@ module Command
|
|
27
27
|
|
28
28
|
progress.puts("Building image from Dockerfile '#{dockerfile}'...\n\n")
|
29
29
|
|
30
|
-
image_name = latest_image_next
|
30
|
+
image_name = cp.latest_image_next
|
31
31
|
image_url = "#{config.org}.registry.cpln.io/#{image_name}"
|
32
32
|
|
33
33
|
commit = config.options[:commit]
|
@@ -41,7 +41,7 @@ module Command
|
|
41
41
|
progress.puts("\nPushed image to '/org/#{config.org}/image/#{image_name}'.\n\n")
|
42
42
|
|
43
43
|
step("Waiting for image to be available", retry_on_failure: true) do
|
44
|
-
image_name == latest_image(refresh: true)
|
44
|
+
image_name == cp.latest_image(refresh: true)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -56,7 +56,7 @@ module Command
|
|
56
56
|
return images unless cp.fetch_gvc(app)
|
57
57
|
|
58
58
|
# If app exists, remove latest image, because we don't want to delete the image that is currently deployed
|
59
|
-
latest_image_name = latest_image_from(images, app_name: app)
|
59
|
+
latest_image_name = cp.latest_image_from(images, app_name: app)
|
60
60
|
images.reject { |image| image["name"] == latest_image_name }
|
61
61
|
end
|
62
62
|
|
@@ -49,7 +49,7 @@ module Command
|
|
49
49
|
app_name = gvc["name"]
|
50
50
|
|
51
51
|
images = cp.query_images(app_name)["items"].select { |item| item["name"].start_with?("#{app_name}:") }
|
52
|
-
image = latest_image_from(images, app_name: app_name, name_only: false)
|
52
|
+
image = cp.latest_image_from(images, app_name: app_name, name_only: false)
|
53
53
|
next unless image
|
54
54
|
|
55
55
|
created_date = DateTime.parse(image["created"])
|
@@ -66,8 +66,8 @@ module Command
|
|
66
66
|
step("Fetching upstream image URL") do
|
67
67
|
cp.profile_switch(@upstream_profile)
|
68
68
|
upstream_image = config.options[:image]
|
69
|
-
upstream_image = latest_image(@upstream, @upstream_org) if !upstream_image || upstream_image == "latest"
|
70
|
-
@commit = extract_image_commit(upstream_image)
|
69
|
+
upstream_image = cp.latest_image(@upstream, @upstream_org) if !upstream_image || upstream_image == "latest"
|
70
|
+
@commit = cp.extract_image_commit(upstream_image)
|
71
71
|
@upstream_image_url = "#{@upstream_org}.registry.cpln.io/#{upstream_image}"
|
72
72
|
end
|
73
73
|
end
|
@@ -75,7 +75,7 @@ module Command
|
|
75
75
|
def fetch_app_image_url
|
76
76
|
step("Fetching app image URL") do
|
77
77
|
cp.profile_switch("default")
|
78
|
-
app_image = latest_image_next(config.app, config.org, commit: @commit)
|
78
|
+
app_image = cp.latest_image_next(config.app, config.org, commit: @commit)
|
79
79
|
@app_image_url = "#{config.org}.registry.cpln.io/#{app_image}"
|
80
80
|
end
|
81
81
|
end
|
data/lib/command/delete.rb
CHANGED
@@ -6,13 +6,17 @@ module Command
|
|
6
6
|
OPTIONS = [
|
7
7
|
app_option(required: true),
|
8
8
|
workload_option,
|
9
|
-
skip_confirm_option
|
9
|
+
skip_confirm_option,
|
10
|
+
skip_pre_deletion_hook_option
|
10
11
|
].freeze
|
11
12
|
DESCRIPTION = "Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload"
|
12
13
|
LONG_DESCRIPTION = <<~DESC
|
13
14
|
- Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload
|
14
15
|
- Also unbinds the app from the secrets policy, as long as both the identity and the policy exist (and are bound)
|
15
16
|
- Will ask for explicit user confirmation
|
17
|
+
- Runs a pre-deletion hook before the app is deleted if `hooks.pre_deletion` is specified in the `.controlplane/controlplane.yml` file
|
18
|
+
- If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
19
|
+
- Use `--skip-pre-deletion-hook` to skip the hook if specified in `controlplane.yml`
|
16
20
|
DESC
|
17
21
|
EXAMPLES = <<~EX
|
18
22
|
```sh
|
@@ -51,6 +55,7 @@ module Command
|
|
51
55
|
check_images
|
52
56
|
return unless confirm_delete(config.app)
|
53
57
|
|
58
|
+
run_pre_deletion_hook unless config.options[:skip_pre_deletion_hook]
|
54
59
|
unbind_identity_from_policy
|
55
60
|
delete_volumesets
|
56
61
|
delete_gvc
|
@@ -119,19 +124,26 @@ module Command
|
|
119
124
|
end
|
120
125
|
|
121
126
|
def unbind_identity_from_policy
|
122
|
-
return if cp.fetch_identity(
|
127
|
+
return if cp.fetch_identity(config.identity).nil?
|
123
128
|
|
124
|
-
policy = cp.fetch_policy(
|
129
|
+
policy = cp.fetch_policy(config.secrets_policy)
|
125
130
|
return if policy.nil?
|
126
131
|
|
127
132
|
is_bound = policy["bindings"].any? do |binding|
|
128
|
-
binding["principalLinks"].any? { |link| link ==
|
133
|
+
binding["principalLinks"].any? { |link| link == config.identity_link }
|
129
134
|
end
|
130
135
|
return unless is_bound
|
131
136
|
|
132
137
|
step("Unbinding identity from policy for app '#{config.app}'") do
|
133
|
-
cp.unbind_identity_from_policy(
|
138
|
+
cp.unbind_identity_from_policy(config.identity_link, config.secrets_policy)
|
134
139
|
end
|
135
140
|
end
|
141
|
+
|
142
|
+
def run_pre_deletion_hook
|
143
|
+
pre_deletion_hook = config.current.dig(:hooks, :pre_deletion)
|
144
|
+
return unless pre_deletion_hook
|
145
|
+
|
146
|
+
run_command_in_latest_image(pre_deletion_hook, title: "pre-deletion hook")
|
147
|
+
end
|
136
148
|
end
|
137
149
|
end
|
data/lib/command/deploy_image.rb
CHANGED
@@ -10,9 +10,9 @@ module Command
|
|
10
10
|
DESCRIPTION = "Deploys the latest image to app workloads, and runs a release script (optional)"
|
11
11
|
LONG_DESCRIPTION = <<~DESC
|
12
12
|
- Deploys the latest image to app workloads
|
13
|
-
-
|
13
|
+
- Runs a release script before deploying if `release_script` is specified in the `.controlplane/controlplane.yml` file and `--run-release-phase` is provided
|
14
14
|
- The release script is run in the context of `cpl run` with the latest image
|
15
|
-
-
|
15
|
+
- If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
16
16
|
DESC
|
17
17
|
|
18
18
|
def call # rubocop:disable Metrics/MethodLength
|
@@ -20,7 +20,7 @@ module Command
|
|
20
20
|
|
21
21
|
deployed_endpoints = {}
|
22
22
|
|
23
|
-
image = latest_image
|
23
|
+
image = cp.latest_image
|
24
24
|
if cp.fetch_image_details(image).nil?
|
25
25
|
raise "Image '#{image}' does not exist in the Docker repository on Control Plane " \
|
26
26
|
"(see https://console.cpln.io/console/org/#{config.org}/repository/#{config.app}). " \
|
@@ -48,24 +48,9 @@ module Command
|
|
48
48
|
|
49
49
|
private
|
50
50
|
|
51
|
-
def run_release_script
|
52
|
-
|
53
|
-
|
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
|
51
|
+
def run_release_script
|
52
|
+
release_script = config[:release_script]
|
53
|
+
run_command_in_latest_image(release_script, title: "release script")
|
69
54
|
end
|
70
55
|
end
|
71
56
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Command
|
4
|
+
class Doctor < Base
|
5
|
+
NAME = "doctor"
|
6
|
+
OPTIONS = [
|
7
|
+
validations_option,
|
8
|
+
app_option
|
9
|
+
].freeze
|
10
|
+
DESCRIPTION = "Runs validations"
|
11
|
+
LONG_DESCRIPTION = <<~DESC
|
12
|
+
- Runs validations
|
13
|
+
DESC
|
14
|
+
EXAMPLES = <<~EX
|
15
|
+
```sh
|
16
|
+
# Runs all validations that don't require additional options by default.
|
17
|
+
cpl doctor
|
18
|
+
|
19
|
+
# Runs config validation.
|
20
|
+
cpl doctor --validations config
|
21
|
+
|
22
|
+
# Runs templates validation (requires app).
|
23
|
+
cpl doctor --validations templates -a $APP_NAME
|
24
|
+
```
|
25
|
+
EX
|
26
|
+
VALIDATIONS = [].freeze
|
27
|
+
|
28
|
+
def call
|
29
|
+
validations = config.options[:validations].split(",")
|
30
|
+
ensure_required_options!(validations)
|
31
|
+
|
32
|
+
doctor_service = DoctorService.new(config)
|
33
|
+
doctor_service.run_validations(validations)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def ensure_required_options!(validations)
|
39
|
+
validations.each do |validation|
|
40
|
+
case validation
|
41
|
+
when "templates"
|
42
|
+
raise "App is required for templates validation." unless config.app
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/command/latest_image.rb
CHANGED
data/lib/command/no_command.rb
CHANGED
@@ -14,7 +14,7 @@ module Command
|
|
14
14
|
- Runs `cpl copy-image-from-upstream` to copy the latest image from upstream
|
15
15
|
- Runs `cpl deploy-image` to deploy the image
|
16
16
|
- If `.controlplane/controlplane.yml` includes the `release_script`, `cpl deploy-image` will use the `--run-release-phase` option
|
17
|
-
-
|
17
|
+
- If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
18
18
|
DESC
|
19
19
|
|
20
20
|
def call
|
data/lib/command/run.rb
CHANGED
@@ -183,7 +183,7 @@ module Command
|
|
183
183
|
# Override image if specified
|
184
184
|
image = config.options[:image]
|
185
185
|
image_link = if image
|
186
|
-
image = latest_image if image == "latest"
|
186
|
+
image = cp.latest_image if image == "latest"
|
187
187
|
"/org/#{config.org}/image/#{image}"
|
188
188
|
else
|
189
189
|
original_container_spec["image"]
|
data/lib/command/setup_app.rb
CHANGED
@@ -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
|
-
-
|
16
|
-
|
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
|
-
|
38
|
+
skip_secrets_setup = config.options[:skip_secret_access_binding] ||
|
39
|
+
config.options[:skip_secrets_setup] || config.current[:skip_secrets_setup]
|
30
40
|
|
31
|
-
|
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
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
45
|
-
|
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