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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87e32bc116e1b72a8282d38542a4ff8ba39240b4038e5cd5ad61bb7fda27a492
4
- data.tar.gz: 496bc3b6fc6c49f6865a430c91d12e98400c6af3e9eb97cac24090b575365918
3
+ metadata.gz: 468f47cb0e1cf3cdb710b885949188c68f40fd74ad4236379a5a6c6fd55739c1
4
+ data.tar.gz: fc83d4ef5ee3ded08d52ca5f2df92e5ee261df6fcefd27f673452d0ba265a650
5
5
  SHA512:
6
- metadata.gz: 6ac8eec9af37340bb5c2ac4b635daf6ab1b60c77893ecd412224879ae700c1569b0ac76675f520b245f4021d1d7476aafb95d5d067b4e5efaabedee1a8068176
7
- data.tar.gz: 9d67284e4db41824b6492dd9a9aa6db37ea49261ac965dadc6efad5e0d4a4f9cc1aa383aac3964bd16ee5b879a76ee63dafa5f895a0e451a033bf35efce591b3
6
+ metadata.gz: dac1051680d2b3c69473636a9babd19b8799ea6e2eaadbb26582836641f7a73e843e4a26c32f41206edb0a6b21ab89b9b62cc08087360d75a562c3b6bb40188d
7
+ data.tar.gz: 52ca1f46ff0d459f450e1a1bd82b6efce780e9b6480ebbda955722eef4bea3a98d71cdaff076691b4cfe93e77c42285f358bfb4ba9adf857c961108302a4f5d6
data/.gitignore CHANGED
@@ -15,3 +15,4 @@
15
15
  .rspec_status
16
16
 
17
17
  /spec.log
18
+ /spec/dummy/.controlplane/controlplane*-tmp-*.yml
data/CHANGELOG.md CHANGED
@@ -14,6 +14,26 @@ Changes since the last non-beta release.
14
14
 
15
15
  _Please add entries here for your pull requests that have not yet been released._
16
16
 
17
+ ### Fixed
18
+
19
+ - 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
+ - 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
+
22
+ ### Added
23
+
24
+ - Added post-creation hook to `setup-app` command (configurable through `hooks.post_creation` in `controlplane.yml`). [PR 183](https://github.com/shakacode/control-plane-flow/pull/183) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
25
+ - Added pre-deletion hook to `delete` command (configurable through `hooks.pre_deletion` in `controlplane.yml`). [PR 183](https://github.com/shakacode/control-plane-flow/pull/183) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
26
+ - Added `doctor` command to run validations. [PR 185](https://github.com/shakacode/control-plane-flow/pull/185) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
27
+
28
+ ### Changed
29
+
30
+ - `cpl` now sets `CPLN_SKIP_UPDATE_CHECK` to `true` for all internal `cpln` calls, which disables the version check and prevents cluttering the logs. [PR 180](https://github.com/shakacode/control-plane-flow/pull/180) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
31
+ - `setup-app` command now automatically creates a secret, policy, and identity for the app if they do not exist. The `--skip-secrets-setup` option prevents this behavior. [PR 181](https://github.com/shakacode/control-plane-flow/pull/181) by [Rafael Gomes](https://github.com/rafaelgomesxyz). [PR 190](https://github.com/shakacode/control-plane-flow/pull/190) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
32
+ - Specific validations are now run before commands, and the command will exit with a non-zero code if any validation fails. Can be disabled by setting `DISABLE_VALIDATIONS` env var to `true`. [PR 185](https://github.com/shakacode/control-plane-flow/pull/185) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
33
+ - Deprecated the `--skip-secret-access-binding` option in favor of `--skip-secrets-setup`. This can also now be configured through `skip_secrets_setup` in `controlplane.yml` [PR 190](https://github.com/shakacode/control-plane-flow/pull/190) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
34
+
35
+ ## [2.0.2] - 2024-05-17
36
+
17
37
  - Fixed issue with improper handling of job statuses. Fixed issue with interactive magic string showing and exit code. [PR 177](https://github.com/shakacode/control-plane-flow/pull/177) by [Sergey Tarasov](https://github.com/dzirtusss).
18
38
 
19
39
  ## [2.0.1] - 2024-05-15
@@ -194,7 +214,8 @@ _Please add entries here for your pull requests that have not yet been released.
194
214
 
195
215
  - Initial release
196
216
 
197
- [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v2.0.1...HEAD
217
+ [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v2.0.2...HEAD
218
+ [2.0.2]: https://github.com/shakacode/control-plane-flow/compare/v2.0.1...v2.0.2
198
219
  [2.0.1]: https://github.com/shakacode/control-plane-flow/compare/v2.0.0...v2.0.1
199
220
  [2.0.0]: https://github.com/shakacode/control-plane-flow/compare/v1.4.0...v2.0.0
200
221
  [1.4.0]: https://github.com/shakacode/control-plane-flow/compare/v1.3.0...v1.4.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpl (2.0.2)
4
+ cpl (2.1.0)
5
5
  debug (~> 1.7.1)
6
6
  dotenv (~> 2.8.1)
7
7
  jwt (~> 2.8.1)
@@ -49,7 +49,7 @@ GEM
49
49
  racc (1.7.3)
50
50
  rainbow (3.1.1)
51
51
  rake (13.2.1)
52
- rdoc (6.6.3.1)
52
+ rdoc (6.7.0)
53
53
  psych (>= 4.0.0)
54
54
  regexp_parser (2.9.0)
55
55
  reline (0.5.7)
data/README.md CHANGED
@@ -196,9 +196,6 @@ aliases:
196
196
  # 2. Each file can contain many objects, such as in the case of templates that create a resource, like `postgres`.
197
197
  # 3. While the naming often corresponds to a workload or other object name, the naming is arbitrary.
198
198
  # Naming does not need to match anything other than the file name without the `.yml` extension.
199
- #
200
- # If you're going to use secrets, you need to apply the `secrets.yml` template separately (one-time setup):
201
- # `cpl apply-template secrets -a my-app`
202
199
  setup_app_templates:
203
200
  - app
204
201
  - redis
@@ -207,6 +204,9 @@ aliases:
207
204
  - rails
208
205
  - sidekiq
209
206
 
207
+ # Skips secrets setup when running `cpl setup-app`.
208
+ skip_secrets_setup: true
209
+
210
210
  # Only needed if using a custom secrets name.
211
211
  # The default is '{APP_PREFIX}-secrets'. For example:
212
212
  # - for an app 'my-app-staging' with `match_if_app_name_starts_with` set to `false`,
@@ -273,6 +273,15 @@ apps:
273
273
  # e.g., "my-app-review-pr123", "my-app-review-anything-goes", etc.
274
274
  match_if_app_name_starts_with: true
275
275
 
276
+ # Hooks can be either a script path that exists in the app image or a command.
277
+ # They're run in the context of `cpl run` with the latest image.
278
+ hooks:
279
+ # Used by the command `cpl setup-app` to run a hook after creating the app.
280
+ post_creation: bundle exec rake db:prepare
281
+
282
+ # Used by the command `cpl delete` to run a hook before deleting the app.
283
+ pre_deletion: bundle exec rake db:drop
284
+
276
285
  my-app-production:
277
286
  <<: *common
278
287
 
data/docs/commands.md CHANGED
@@ -109,6 +109,9 @@ cpl copy-image-from-upstream -a $APP_NAME --upstream-token $UPSTREAM_TOKEN --ima
109
109
  - Deletes the whole app (GVC with all workloads, all volumesets and all images) or a specific workload
110
110
  - Also unbinds the app from the secrets policy, as long as both the identity and the policy exist (and are bound)
111
111
  - Will ask for explicit user confirmation
112
+ - Runs a pre-deletion hook before the app is deleted if `hooks.pre_deletion` is specified in the `.controlplane/controlplane.yml` file
113
+ - If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
114
+ - Use `--skip-pre-deletion-hook` to skip the hook if specified in `controlplane.yml`
112
115
 
113
116
  ```sh
114
117
  # Deletes the whole app (GVC with all workloads, all volumesets and all images).
@@ -121,14 +124,29 @@ cpl delete -a $APP_NAME -w $WORKLOAD_NAME
121
124
  ### `deploy-image`
122
125
 
123
126
  - Deploys the latest image to app workloads
124
- - Optionally runs a release script before deploying if specified through `release_script` in the `.controlplane/controlplane.yml` file and `--run-release-phase` is provided
127
+ - Runs a release script before deploying if `release_script` is specified in the `.controlplane/controlplane.yml` file and `--run-release-phase` is provided
125
128
  - The release script is run in the context of `cpl run` with the latest image
126
- - The deploy will fail if the release script exits with a non-zero code or doesn't exist
129
+ - If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
127
130
 
128
131
  ```sh
129
132
  cpl deploy-image -a $APP_NAME
130
133
  ```
131
134
 
135
+ ### `doctor`
136
+
137
+ - Runs validations
138
+
139
+ ```sh
140
+ # Runs all validations that don't require additional options by default.
141
+ cpl doctor
142
+
143
+ # Runs config validation.
144
+ cpl doctor --validations config
145
+
146
+ # Runs templates validation (requires app).
147
+ cpl doctor --validations templates -a $APP_NAME
148
+ ```
149
+
132
150
  ### `env`
133
151
 
134
152
  - Displays app-specific environment variables
@@ -276,7 +294,7 @@ cpl open-console -a $APP_NAME
276
294
  - Runs `cpl copy-image-from-upstream` to copy the latest image from upstream
277
295
  - Runs `cpl deploy-image` to deploy the image
278
296
  - If `.controlplane/controlplane.yml` includes the `release_script`, `cpl deploy-image` will use the `--run-release-phase` option
279
- - The deploy will fail if the release script exits with a non-zero code
297
+ - If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
280
298
 
281
299
  ```sh
282
300
  cpl promote-app-from-upstream -a $APP_NAME -t $UPSTREAM_TOKEN
@@ -407,9 +425,15 @@ cpl run -a $APP_NAME --entrypoint /app/alternative-entrypoint.sh -- rails db:mig
407
425
 
408
426
  - Creates an app and all its workloads
409
427
  - Specify the templates for the app and workloads through `setup_app_templates` in the `.controlplane/controlplane.yml` file
410
- - 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)
411
- - Automatically binds the app to the secrets policy, as long as both the identity and the policy exist
412
- - Use `--skip-secret-access-binding` to prevent the automatic bind
428
+ - 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)
429
+ - Configures app to have org-level secrets with default name "{APP_PREFIX}-secrets"
430
+ using org-level policy with default name "{APP_PREFIX}-secrets-policy" (names can be customized, see docs)
431
+ - Creates identity for secrets if it does not exist
432
+ - Use `--skip-secrets-setup` to prevent the automatic setup of secrets,
433
+ or set it through `skip_secrets_setup` in the `.controlplane/controlplane.yml` file
434
+ - Runs a post-creation hook after the app is created if `hooks.post_creation` is specified in the `.controlplane/controlplane.yml` file
435
+ - If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
436
+ - Use `--skip-post-creation-hook` to skip the hook if specified in `controlplane.yml`
413
437
 
414
438
  ```sh
415
439
  cpl setup-app -a $APP_NAME
@@ -0,0 +1,42 @@
1
+ # Secrets and ENV Values
2
+
3
+ You can store ENV values used by a container (within a workload) within Control Plane at the following levels:
4
+
5
+ 1. Workload Container
6
+ 2. GVC
7
+
8
+ For your "review apps," it is convenient to have simple ENVs stored in plain text in your source code. You will want to
9
+ keep some ENVs, like the Rails' `SECRET_KEY_BASE`, out of your source code. For staging and production apps, you will
10
+ set these values directly at the GVC or workload levels, so none of these ENV values are committed to the source code.
11
+
12
+ For storing ENVs in the source code, we can use a level of indirection so that you can store an ENV value in your source
13
+ code like `cpln://secret/my-app-review-env-secrets.SECRET_KEY_BASE` and then have the secret value stored at the org
14
+ level, which applies to your GVCs mapped to that org.
15
+
16
+ For setting up secrets, you'll need:
17
+
18
+ - **Org-level Secret:** This is where the values will be stored.
19
+ - **GVC Identity:** An identity that must be associated with each workload that requires access to the secret.
20
+ - **Org-level Policy:** A policy that binds the identity to the secret, granting the necessary permissions for the workload to access the secret.
21
+
22
+ You can do this during the initial app setup, like this:
23
+
24
+ 1. Add the template for `app` to `.controlplane/templates`
25
+ 2. Ensure that the `app` template is listed in `setup_app_templates` for the app in `.controlplane/controlplane.yml`
26
+ 3. Run `cpl setup-app -a $APP_NAME`
27
+ 4. The secrets, secrets policy and identity will be automatically created, along with the proper binding
28
+ 5. In the Control Plane console, upper left "Manage Org" menu, click on "Secrets"
29
+ 6. Find the created secret (it will be in the `$APP_PREFIX-secrets` format) and add the secret env vars there
30
+ 7. Use `cpln://secret/...` in the app to access the secret env vars (e.g., `cpln://secret/$APP_PREFIX-secrets.SOME_VAR`)
31
+
32
+ Here are the manual steps for reference. We recommend that you follow the steps above:
33
+
34
+ 1. In the upper left of the Control Plane console, "Manage Org" menu, click on "Secrets"
35
+ 2. Create a secret with `Secret Type: Dictionary` (e.g., `my-secrets`) and add the secret env vars there
36
+ 3. In the upper left "Manage GVC" menu, click on "Identities"
37
+ 4. Create an identity (e.g., `my-identity`)
38
+ 5. Navigate to the workload that you want to associate with the identity created
39
+ 6. Click "Identity" on the left menu and select the identity created
40
+ 7. In the lower left "Access Control" menu, click on "Policies"
41
+ 8. Create a policy with `Target Kind: Secret` and add a binding with the `reveal` permission for the identity created
42
+ 9. Use `cpln://secret/...` in the app to access the secret env vars (e.g., `cpln://secret/my-secrets.SOME_VAR`)
data/docs/tips.md CHANGED
@@ -3,7 +3,7 @@
3
3
  1. [GVCs vs. Orgs](#gvcs-vs-orgs)
4
4
  2. [RAM](#ram)
5
5
  3. [Remote IP](#remote-ip)
6
- 4. [ENV Values](#env-values)
6
+ 4. [Secrets and ENV Values](/docs/secrets-and-env-values.md)
7
7
  5. [CI](#ci)
8
8
  6. [Memcached](#memcached)
9
9
  7. [Sidekiq](#sidekiq)
@@ -70,45 +70,6 @@ pick those up and automatically populate `request.remote_ip`.
70
70
 
71
71
  So `REMOTE_ADDR` should not be used directly, only `request.remote_ip`.
72
72
 
73
- ## ENV Values
74
-
75
- You can store ENV values used by a container (within a workload) within Control Plane at the following levels:
76
-
77
- 1. Workload Container
78
- 2. GVC
79
-
80
- For your "review apps," it is convenient to have simple ENVs stored in plain text in your source code. You will want to
81
- keep some ENVs, like the Rails' `SECRET_KEY_BASE`, out of your source code. For staging and production apps, you will
82
- set these values directly at the GVC or workload levels, so none of these ENV values are committed to the source code.
83
-
84
- For storing ENVs in the source code, we can use a level of indirection so that you can store an ENV value in your source
85
- code like `cpln://secret/my-app-review-env-secrets.SECRET_KEY_BASE` and then have the secret value stored at the org
86
- level, which applies to your GVCs mapped to that org.
87
-
88
- You can do this during the initial app setup, like this:
89
-
90
- 1. Add the templates for `app` and `secrets` to `.controlplane/templates`
91
- 2. Ensure that the `app` template includes the `identity`
92
- 3. Ensure that the `app` template is listed in `setup_app_templates` for the app in `.controlplane/controlplane.yml`
93
- 4. Run `cpl apply-template secrets -a $APP_NAME` (one-time setup)
94
- 5. Run `cpl setup-app -a $APP_NAME`
95
- 6. The secrets, secrets policy and identity will be automatically created, along with the proper binding
96
- 7. In the Control Plane console, upper left "Manage Org" menu, click on "Secrets"
97
- 8. Find the created secret (it will be in the `$APP_PREFIX-secrets` format) and add the secret env vars there
98
- 9. Use `cpln://secret/...` in the app to access the secret env vars (e.g., `cpln://secret/$APP_PREFIX-secrets.SOME_VAR`)
99
-
100
- Here are the manual steps for reference. We recommend that you follow the steps above:
101
-
102
- 1. In the upper left of the Control Plane console, "Manage Org" menu, click on "Secrets"
103
- 2. Create a secret with `Secret Type: Dictionary` (e.g., `my-secrets`) and add the secret env vars there
104
- 3. In the upper left "Manage GVC" menu, click on "Identities"
105
- 4. Create an identity (e.g., `my-identity`)
106
- 5. Navigate to the workload that you want to associate with the identity created
107
- 6. Click "Identity" on the left menu and select the identity created
108
- 7. In the lower left "Access Control" menu, click on "Policies"
109
- 8. Create a policy with `Target Kind: Secret` and add a binding with the `reveal` permission for the identity created
110
- 9. Use `cpln://secret/...` in the app to access the secret env vars (e.g., `cpln://secret/my-secrets.SOME_VAR`)
111
-
112
73
  ## CI
113
74
 
114
75
  **Note:** Docker builds much slower on Apple Silicon, so try configuring CI to build the images when using Apple
@@ -31,9 +31,6 @@ aliases:
31
31
  # 2. Each file can contain many objects, such as in the case of templates that create a resource, like `postgres`.
32
32
  # 3. While the naming often corresponds to a workload or other object name, the naming is arbitrary.
33
33
  # Naming does not need to match anything other than the file name without the `.yml` extension.
34
- #
35
- # If you're going to use secrets, you need to apply the `secrets.yml` template separately (one-time setup):
36
- # `cpl apply-template secrets -a my-app`
37
34
  setup_app_templates:
38
35
  - app
39
36
  - redis
@@ -42,6 +39,9 @@ aliases:
42
39
  - rails
43
40
  - sidekiq
44
41
 
42
+ # Uncomment next line to skips secrets setup when running `cpl setup-app`.
43
+ # skip_secrets_setup: true
44
+
45
45
  # Only needed if using a custom secrets name.
46
46
  # The default is '{APP_PREFIX}-secrets'. For example:
47
47
  # - for an app 'my-app-staging' with `match_if_app_name_starts_with` set to `false`,
@@ -108,6 +108,15 @@ apps:
108
108
  # e.g., "my-app-review-pr123", "my-app-review-anything-goes", etc.
109
109
  match_if_app_name_starts_with: true
110
110
 
111
+ # Hooks can be either a script path that exists in the app image or a command.
112
+ # They're run in the context of `cpl run` with the latest image.
113
+ hooks:
114
+ # Used by the command `cpl setup-app` to run a hook after creating the app.
115
+ post_creation: bundle exec rake db:prepare
116
+
117
+ # Used by the command `cpl delete` to run a hook before deleting the app.
118
+ pre_deletion: bundle exec rake db:drop
119
+
111
120
  my-app-production:
112
121
  <<: *common
113
122
 
@@ -8,7 +8,8 @@ module Command
8
8
  OPTIONS = [
9
9
  app_option(required: true),
10
10
  location_option,
11
- skip_confirm_option
11
+ skip_confirm_option,
12
+ add_app_identity_option
12
13
  ].freeze
13
14
  DESCRIPTION = "Applies application-specific configs from templates"
14
15
  LONG_DESCRIPTION = <<~DESC
@@ -39,45 +40,27 @@ module Command
39
40
  cpl apply-template app postgres redis rails -a $APP_NAME
40
41
  ```
41
42
  EX
43
+ VALIDATIONS = %w[config templates].freeze
44
+
45
+ def call # rubocop:disable Metrics/MethodLength
46
+ @template_parser = TemplateParser.new(config)
47
+ @names_to_filenames = config.args.to_h do |name|
48
+ [name, @template_parser.template_filename(name)]
49
+ end
42
50
 
43
- def call # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
44
51
  ensure_templates!
45
52
 
46
53
  @created_items = []
47
54
  @failed_templates = []
48
55
  @skipped_templates = []
49
56
 
50
- @asked_for_confirmation = false
51
-
52
- pending_templates = templates.select do |template|
53
- if template == "app"
54
- confirm_app(template)
55
- else
56
- confirm_workload(template)
57
- end
58
- end
59
-
60
- progress.puts if @asked_for_confirmation
61
-
62
- @deprecated_variables = []
63
-
64
- pending_templates.each do |template, filename|
65
- step("Applying template '#{template}'", abort_on_error: false) do
66
- items = apply_template(filename)
67
- unless items
68
- report_failure(template)
69
- next false
70
- end
71
-
72
- items.each do |item|
73
- report_success(item)
74
- end
75
- true
76
- end
57
+ templates = @template_parser.parse(@names_to_filenames.values)
58
+ pending_templates = confirm_templates(templates)
59
+ add_app_identity_template(pending_templates) if config.options[:add_app_identity]
60
+ pending_templates.each do |template|
61
+ apply_template(template)
77
62
  end
78
63
 
79
- warn_deprecated_variables
80
-
81
64
  print_created_items
82
65
  print_failed_templates
83
66
  print_skipped_templates
@@ -87,18 +70,21 @@ module Command
87
70
 
88
71
  private
89
72
 
90
- def templates
91
- @templates ||= config.args.to_h do |template|
92
- [template, "#{config.app_cpln_dir}/templates/#{template}.yml"]
73
+ def template_kind(template)
74
+ case template["kind"]
75
+ when "gvc"
76
+ "app"
77
+ else
78
+ template["kind"]
93
79
  end
94
80
  end
95
81
 
96
82
  def ensure_templates!
97
- missing_templates = templates.reject { |_template, filename| File.exist?(filename) }.to_h
83
+ missing_templates = @names_to_filenames.reject { |_, filename| File.exist?(filename) }
98
84
  return if missing_templates.empty?
99
85
 
100
- missing_templates_str = missing_templates.map do |template, filename|
101
- " - #{template} (#{filename})"
86
+ missing_templates_str = missing_templates.map do |name, filename|
87
+ " - #{name} (#{filename})"
102
88
  end.join("\n")
103
89
  progress.puts("#{Shell.color('Missing templates:', :red)}\n#{missing_templates_str}\n\n")
104
90
 
@@ -113,10 +99,10 @@ module Command
113
99
  end
114
100
 
115
101
  def confirm_app(template)
116
- app = cp.fetch_gvc
102
+ app = cp.fetch_gvc(template["name"])
117
103
  return true unless app
118
104
 
119
- confirmed = confirm_apply("App '#{config.app}' already exists, do you want to re-create it?")
105
+ confirmed = confirm_apply("App '#{template['name']}' already exists, do you want to re-create it?")
120
106
  return true if confirmed
121
107
 
122
108
  report_skipped(template)
@@ -124,63 +110,67 @@ module Command
124
110
  end
125
111
 
126
112
  def confirm_workload(template)
127
- workload = cp.fetch_workload(template)
113
+ workload = cp.fetch_workload(template["name"])
128
114
  return true unless workload
129
115
 
130
- confirmed = confirm_apply("Workload '#{template}' already exists, do you want to re-create it?")
116
+ confirmed = confirm_apply("Workload '#{template['name']}' already exists, do you want to re-create it?")
131
117
  return true if confirmed
132
118
 
133
119
  report_skipped(template)
134
120
  false
135
121
  end
136
122
 
137
- def apply_template(filename) # rubocop:disable Metrics/MethodLength
138
- data = File.read(filename)
139
- .gsub("{{APP_ORG}}", config.org)
140
- .gsub("{{APP_NAME}}", config.app)
141
- .gsub("{{APP_LOCATION}}", config.location)
142
- .gsub("{{APP_LOCATION_LINK}}", app_location_link)
143
- .gsub("{{APP_IMAGE}}", latest_image)
144
- .gsub("{{APP_IMAGE_LINK}}", app_image_link)
145
- .gsub("{{APP_IDENTITY}}", app_identity)
146
- .gsub("{{APP_IDENTITY_LINK}}", app_identity_link)
147
- .gsub("{{APP_SECRETS}}", app_secrets)
148
- .gsub("{{APP_SECRETS_POLICY}}", app_secrets_policy)
123
+ def confirm_templates(templates) # rubocop:disable Metrics/MethodLength
124
+ @asked_for_confirmation = false
125
+
126
+ pending_templates = templates.select do |template|
127
+ case template["kind"]
128
+ when "gvc"
129
+ confirm_app(template)
130
+ when "workload"
131
+ confirm_workload(template)
132
+ else
133
+ true
134
+ end
135
+ end
149
136
 
150
- find_deprecated_variables(data)
137
+ progress.puts if @asked_for_confirmation
138
+
139
+ pending_templates
140
+ end
151
141
 
152
- # Kept for backwards compatibility
153
- data = data
154
- .gsub("APP_ORG", config.org)
155
- .gsub("APP_GVC", config.app)
156
- .gsub("APP_LOCATION", config.location)
157
- .gsub("APP_IMAGE", latest_image)
142
+ def add_app_identity_template(templates)
143
+ app_template_index = templates.index { |template| template["name"] == config.app }
144
+ app_identity_template_index = templates.index { |template| template["name"] == config.identity }
158
145
 
159
- # Don't read in YAML.safe_load as that doesn't handle multiple documents
160
- cp.apply_template(data)
146
+ return unless app_template_index && app_identity_template_index.nil?
147
+
148
+ # Adding the identity template right after the app template is important since:
149
+ # a) we can't create the identity at the beginning because the app doesn't exist yet
150
+ # b) we also can't create it at the end because any workload templates associated with it will fail to apply
151
+ templates.insert(app_template_index + 1, build_app_identity_hash)
161
152
  end
162
153
 
163
- def new_variables
154
+ def build_app_identity_hash
164
155
  {
165
- "APP_ORG" => "{{APP_ORG}}",
166
- "APP_GVC" => "{{APP_NAME}}",
167
- "APP_LOCATION" => "{{APP_LOCATION}}",
168
- "APP_IMAGE" => "{{APP_IMAGE}}"
156
+ "kind" => "identity",
157
+ "name" => config.identity
169
158
  }
170
159
  end
171
160
 
172
- def find_deprecated_variables(data)
173
- @deprecated_variables.push(*new_variables.keys.select { |old_key| data.include?(old_key) })
174
- @deprecated_variables = @deprecated_variables.uniq.sort
175
- end
176
-
177
- def warn_deprecated_variables
178
- return unless @deprecated_variables.any?
161
+ def apply_template(template) # rubocop:disable Metrics/MethodLength
162
+ step("Applying template for #{template_kind(template)} '#{template['name']}'", abort_on_error: false) do
163
+ items = cp.apply_hash(template)
164
+ unless items
165
+ report_failure(template)
166
+ next false
167
+ end
179
168
 
180
- message = "Please replace these variables in the templates, " \
181
- "as support for them will be removed in a future major version bump:"
182
- deprecated = @deprecated_variables.map { |old_key| " - #{old_key} -> #{new_variables[old_key]}" }.join("\n")
183
- progress.puts("\n#{Shell.color("DEPRECATED: #{message}", :yellow)}\n#{deprecated}")
169
+ items.each do |item|
170
+ report_success(item)
171
+ end
172
+ true
173
+ end
184
174
  end
185
175
 
186
176
  def report_success(item)
@@ -205,14 +195,14 @@ module Command
205
195
  def print_failed_templates
206
196
  return unless @failed_templates.any?
207
197
 
208
- failed = @failed_templates.map { |template| " - #{template}" }.join("\n")
198
+ failed = @failed_templates.map { |template| " - [#{template_kind(template)}] #{template['name']}" }.join("\n")
209
199
  progress.puts("\n#{Shell.color('Failed to apply templates:', :red)}\n#{failed}")
210
200
  end
211
201
 
212
202
  def print_skipped_templates
213
203
  return unless @skipped_templates.any?
214
204
 
215
- skipped = @skipped_templates.map { |template| " - #{template}" }.join("\n")
205
+ skipped = @skipped_templates.map { |template| " - [#{template_kind(template)}] #{template['name']}" }.join("\n")
216
206
  progress.puts("\n#{Shell.color('Skipped templates (already exist):', :blue)}\n#{skipped}")
217
207
  end
218
208
  end