cpl 1.0.1 → 1.0.3

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: da0cd8b4b3f57a141b2a148a35555069f4ff4135803e4ae95932cd3887e3a567
4
- data.tar.gz: dab258fecce6a5948374057418959d736915ab69f84593e1b189c148f62f00be
3
+ metadata.gz: 9d187c354ac6a9a75c0aea498f8fbc060f741809d075439ee22663fdf06f265d
4
+ data.tar.gz: ffde2f0f3be4663ba85baadf599c6a12882c2ba11734f9220d26366bacc5368d
5
5
  SHA512:
6
- metadata.gz: 31c5cfe13e647abf6f34f6b021c808c220db07a48cd223d0d277ad7814ab0942961a7b75c63d89c3c109e7ca670d478285e5289fdb9fe64ccd828917b7fccf22
7
- data.tar.gz: 926431c8d7fb4c5f8ba7930a3a156d70718dcce6eb1c717e9859f5a8546900266e4267cee7c755ca4c99612fb1b574a7cbfdd6ca23a2fd5483c1eb3c743a83db
6
+ metadata.gz: 70941d48b8ccc5bb3fb46b6c96c91fd0d3c2f13f2a702822ee6541231d90957df5a3b3c9d60d2091afad9f6e76be8870953f69085a97315c2a865d534d0c1ce7
7
+ data.tar.gz: 3a109996c812ec2b2e9dc76c189bd5d3518835e5b221ff8f12416982f3542f1753dcba441dbb3ec32224e807d0c83db54fe78e21cad43da0d829b8d65593a6d5
data/CHANGELOG.md CHANGED
@@ -1,9 +1,38 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.1 - 2023-03-09
3
+ All notable changes to this project's source code will be documented in this file. Items under `Unreleased` are upcoming features that will be out in the next version.
4
4
 
5
- - Fixed issue with default gems for older Ruby versions (#14)
5
+ ## Contributors
6
6
 
7
- ## 0.1.0 - 2023-02-19
7
+ Please follow the recommendations outlined at [keepachangelog.com](https://keepachangelog.com). Please use the existing headings and styling as a guide, and add a link for the version diff at the bottom of the file. Also, please update the `Unreleased` link to compare it to the latest release version.
8
+
9
+ ## Versions
10
+
11
+ ## [Unreleased]
12
+
13
+ Changes since the last non-beta release.
14
+
15
+ _Please add entries here for your pull requests that are not yet released._
16
+
17
+ ### Added
18
+
19
+ - Added steps to migrate to docs. [PR 57](https://github.com/shakacode/heroku-to-control-plane/pull/57) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
20
+ - Added `ps:wait` command. [PR 58](https://github.com/shakacode/heroku-to-control-plane/pull/58) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
21
+
22
+ ## [1.0.1] - 2023-06-28
23
+
24
+ ### Fixed
25
+
26
+ - Fixed `cleanup-stale-apps` command when app does not have image. [PR 55](https://github.com/shakacode/heroku-to-control-plane/pull/55) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
27
+
28
+ ### Changed
29
+
30
+ - Improved docs. [PR 50](https://github.com/shakacode/heroku-to-control-plane/pull/50) by [Rafael Gomes](https://github.com/rafaelgomesxyz).
31
+
32
+ ## [1.0.0] - 2023-05-29
8
33
 
9
34
  - Initial release
35
+
36
+ [Unreleased]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.0.1...HEAD
37
+ [1.0.1]: https://github.com/shakacode/heroku-to-control-plane/compare/v1.0.0...v1.0.1
38
+ [1.0.0]: https://github.com/shakacode/heroku-to-control-plane/releases/tag/v1.0.0
data/CONTRIBUTING.md CHANGED
@@ -1,13 +1,15 @@
1
1
  # Contributing
2
2
 
3
3
  ## Installation
4
- Rather than installing `cpl` as a Ruby gem, install this repo locally and alias `cpl` command globally for easier access, e.g.:
4
+
5
+ Rather than installing `cpl` as a Ruby gem, install this repo locally and alias the `cpl` command globally for easier
6
+ access, e.g.:
5
7
 
6
8
  ```sh
7
9
  git clone https://github.com/shakacode/heroku-to-control-plane
8
10
 
9
11
  # Create an alias in some local shell startup script, e.g., `.profile`, `.bashrc`, etc.
10
- alias cpl="~/projects/heroku-to-control-plane/cpl"
12
+ alias cpl="~/projects/heroku-to-control-plane/bin/cpl"
11
13
  ```
12
14
 
13
15
  Or set the path of the Ruby gem in your Gemfile.
@@ -16,13 +18,30 @@ Or set the path of the Ruby gem in your Gemfile.
16
18
  gem 'cpl', path: '~/projects/heroku-to-control-plane'
17
19
  ```
18
20
 
19
- ## Linting
20
- Be sure to run `rubocop -a` before committing code.
21
+ ## Linting/Testing
22
+
23
+ Before committing or pushing code, be sure to:
24
+
25
+ - Run `bundle exec rake update_command_docs` to sync any doc changes made in the source code to the docs
26
+ - Run `bundle exec rubocop -a` to fix any linting errors
27
+ - Run `bundle exec rspec` to run the test suite
28
+
29
+ You can also install [overcommit](https://github.com/sds/overcommit) and let it automatically check for you:
30
+
31
+ ```sh
32
+ gem install overcommit
33
+
34
+ overcommit --install
35
+ ```
21
36
 
22
37
  ## Debugging
23
38
 
24
- 1. Install gem: `gem install debug`
25
- 2. Require: Add a `require "debug"` statement to the file you want to debug.
26
- 3. Add breakpoint: Add a `debugger` statement to the line you want to debug.
27
- 4. Modify the `lib/command/test.rb` file to triggger the code that you want to run.
28
- 5. Run the test in your test app with a `.controlplane` directory. `cpl test -a my-app-name`
39
+ 1. Add a breakpoint (`debugger`) to any line of code you want to debug.
40
+ 2. Modify the `lib/command/test.rb` file to trigger the code you want to test. To simulate a command, you can use
41
+ `Cpl::Cli.start` (e.g., `Cpl::Cli.start(["deploy-image", "-a", "my-app-name"])` would be the same as running
42
+ `cpl deploy-image -a my-app-name`).
43
+ 3. Run the `test` command in your test app with a `.controlplane` directory.
44
+
45
+ ```sh
46
+ cpl test
47
+ ```
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpl (1.0.1)
4
+ cpl (1.0.3)
5
5
  debug (~> 1.7.1)
6
6
  dotenv (~> 2.8.1)
7
7
  psych (~> 5.1.0)
@@ -25,7 +25,7 @@ GEM
25
25
  hashdiff (1.0.1)
26
26
  iniparse (1.5.0)
27
27
  io-console (0.6.0)
28
- irb (1.7.0)
28
+ irb (1.7.1)
29
29
  reline (>= 0.3.0)
30
30
  json (2.6.3)
31
31
  overcommit (0.60.0)
data/README.md CHANGED
@@ -28,10 +28,8 @@ a **helper CLI** based on templates to save lots of day-to-day typing (and human
28
28
  1. [Key Features](#key-features)
29
29
  2. [Concept Mapping](#concept-mapping)
30
30
  3. [Installation](#installation)
31
- 4. [Example CLI Flow for Application Build/Deployment](#example-cli-flow-for-application-builddeployment)
32
- - [Initial Setup and Deployment](#initial-setup-and-deployment)
33
- - [Promoting Code Upgrades](#promoting-code-upgrades)
34
- 5. [Example Project Modifications for Control Plane](#example-project-modifications-for-control-plane)
31
+ 4. [Steps to Migrate](#steps-to-migrate)
32
+ 5. [Config](#config)
35
33
  6. [Environment](#environment)
36
34
  7. [Database](#database)
37
35
  8. [In-memory Databases](#in-memory-databases)
@@ -110,104 +108,13 @@ gem install cpl
110
108
  **Note:** Do not confuse the `cpl` CLI with the `cpln` CLI. The `cpl` CLI is the Heroku to Control Plane playbook CLI.
111
109
  The `cpln` CLI is the Control Plane CLI.
112
110
 
113
- ## Example CLI Flow for Application Build/Deployment
111
+ ## Steps to Migrate
114
112
 
115
- **Notes:**
113
+ Click [here](/docs/migrating.md) to see the steps to migrate.
116
114
 
117
- - `my-app` is an app name defined in the `.controlplane/controlplane.yml` file, such as `ror-tutorial` in
118
- [this `controlplane.yml` file](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/controlplane.yml).
119
- - Other files in the `.controlplane/templates/` directory are used by the `cpl setup-app` and `cpl apply-template`
120
- commands.
115
+ ## Config
121
116
 
122
- ### Initial Setup and Deployment
123
-
124
- For each Git project that you want to deploy to Control Plane, copy project-specific configs to a `.controlplane/`
125
- directory at the top of your project. `cpl` will pick those up depending on which project folder tree it runs. Thus,
126
- this automates running several projects with different configs without explicitly switching configs.
127
-
128
- Before the initial setup, add the templates for the app to `.controlplane/controlplane.yml`, using the `setup` key, e.g.:
129
-
130
- ```yaml
131
- my-app:
132
- setup:
133
- - gvc
134
- - postgres
135
- - redis
136
- - memcached
137
- - rails
138
- - sidekiq
139
- ```
140
-
141
- Note how the templates correspond to files in the `.controlplane/templates/` directory.
142
-
143
- Then create a `Dockerfile` for your deployment. See
144
- [this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/Dockerfile).
145
-
146
- ```sh
147
- # Provision infrastructure (one-time-only for new apps) using templates.
148
- cpl setup-app -a my-app
149
-
150
- # Build and push image with auto-tagging, e.g., "my-app:1_456".
151
- cpl build-image -a my-app --commit 456
152
-
153
- # Prepare database.
154
- cpl run:detached -a my-app --image latest -- rails db:prepare
155
-
156
- # Deploy latest image.
157
- cpl deploy-image -a my-app
158
-
159
- # Open app in browser.
160
- cpl open -a my-app
161
- ```
162
-
163
- ### Promoting Code Upgrades
164
-
165
- ```sh
166
- # Build and push new image with sequential tagging, e.g., "my-app:2".
167
- cpl build-image -a my-app
168
-
169
- # Or build and push new image with sequential tagging and commit SHA, e.g., "my-app:2_ABC".
170
- cpl build-image -a my-app --commit ABC
171
-
172
- # Run database migrations (or other release tasks) with latest image, while app is still running on previous image.
173
- # This is analogous to the release phase.
174
- cpl run:detached -a my-app --image latest -- rails db:migrate
175
-
176
- # Deploy latest image.
177
- cpl deploy-image -a my-app
178
- ```
179
-
180
- ## Example Project Modifications for Control Plane
181
-
182
- _See this for a complete example._
183
-
184
- To learn how to migrate an app, we recommend following along with
185
- [this example project](https://github.com/shakacode/react-webpack-rails-tutorial).
186
-
187
- 1. Create the `.controlplane/` directory at the top of your project and copy files from the `templates/` directory of
188
- this repository to something as follows:
189
-
190
- ```sh
191
- app_main_folder/
192
- .controlplane/
193
- Dockerfile # Your app's Dockerfile, with some Control Plane changes.
194
- controlplane.yml
195
- entrypoint.sh # App-specific - edit as needed.
196
- templates/
197
- gvc.yml
198
- memcached.yml
199
- postgres.yml
200
- rails.yml
201
- redis.yml
202
- sidekiq.yml
203
- ```
204
-
205
- The example
206
- [`.controlplane/` directory](https://github.com/shakacode/react-webpack-rails-tutorial/tree/master/.controlplane)
207
- already contains these files.
208
-
209
- 2. Edit your `controlplane.yml` file as needed. For example, see
210
- [this `controlplane.yml` file](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/controlplane.yml).
117
+ Here's a complete example of all supported config keys explained:
211
118
 
212
119
  ```yaml
213
120
  # Keys beginning with "cpln_" correspond to your settings in Control Plane.
@@ -221,6 +128,16 @@ aliases:
221
128
  # Example apps use only one location. Control Plane offers the ability to use multiple locations.
222
129
  default_location: aws-us-east-2
223
130
 
131
+ # Allows running the command `cpl setup-app`
132
+ # instead of `cpl apply-template gvc redis postgres memcached rails sidekiq`.
133
+ setup:
134
+ - gvc
135
+ - redis
136
+ - postgres
137
+ - memcached
138
+ - rails
139
+ - sidekiq
140
+
224
141
  # Configure the workload name used as a template for one-off scripts, like a Heroku one-off dyno.
225
142
  one_off_workload: rails
226
143
 
@@ -235,40 +152,58 @@ aliases:
235
152
  - postgres
236
153
  - memcached
237
154
 
238
- # Configure the workload name used when maintenance mode is on (defaults to "maintenance")
155
+ # Configure the workload name used when maintenance mode is on (defaults to "maintenance").
239
156
  maintenance_workload: maintenance
240
157
 
158
+ # Fixes the remote terminal size to match the local terminal size
159
+ # when running the commands `cpl run` or `cpl run:detached`.
160
+ fix_terminal_size: true
161
+
162
+ # Apps with a deployed image created before this amount of days will be listed for deletion
163
+ # when running the command `cpl cleanup-stale-apps`.
164
+ stale_app_image_deployed_days: 5
165
+
166
+ # Images created before this amount of days will be listed for deletion
167
+ # when running the command `cpl cleanup-old-images`.
168
+ old_image_retention_days: 5
169
+
170
+ # Run workloads created before this amount of days will be listed for deletion
171
+ # when running the command `cpl run:cleanup`.
172
+ stale_run_workload_created_days: 2
173
+
241
174
  apps:
242
175
  my-app-staging:
243
176
  # Use the values from the common section above.
244
177
  <<: *common
178
+
245
179
  my-app-review:
246
180
  <<: *common
181
+
247
182
  # If `match_if_app_name_starts_with` is `true`, then use this config for app names starting with this name,
248
183
  # e.g., "my-app-review-pr123", "my-app-review-anything-goes", etc.
249
184
  match_if_app_name_starts_with: true
185
+
250
186
  my-app-production:
251
187
  <<: *common
188
+
252
189
  # Use a different organization for production.
253
190
  cpln_org: my-org-production
191
+
254
192
  # Allows running the command `cpl promote-app-from-upstream -a my-app-production`
255
193
  # to promote the staging app to production.
256
194
  upstream: my-app-staging
195
+
196
+ # Used by the command `cpl promote-app-from-upstream` to run a release script before deploying.
197
+ # This is relative to the `.controlplane/` directory.
198
+ release_script: release_script
199
+
257
200
  my-app-other:
258
201
  <<: *common
202
+
259
203
  # You can specify a different `Dockerfile` relative to the `.controlplane/` directory (defaults to "Dockerfile").
260
204
  dockerfile: ../some_other/Dockerfile
261
205
  ```
262
206
 
263
- 3. We recommend that you try out the commands listed in
264
- [the example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/readme.md).
265
- These steps will guide you to the following:
266
-
267
- 1. Provision the GVC and workloads.
268
- 2. Build the Docker image.
269
- 3. Run Rails migrations, like in the Heroku release phase.
270
- 4. Promote the latest Docker image.
271
-
272
207
  ## Environment
273
208
 
274
209
  There are two main places where we can set up environment variables in Control Plane:
data/bin/cpl CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "cpl"
4
+ require_relative "../lib/cpl"
5
5
 
6
6
  Cpl::Cli.start
data/cpl CHANGED
@@ -1,15 +1,6 @@
1
- #!/bin/sh
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- SCRIPT_DIR=$(dirname $(realpath $0))
4
+ require_relative "lib/cpl"
4
5
 
5
- # exports .env to vars
6
- #
7
- # Example .env:
8
- # CPLN_TOKEN=xxx
9
- #
10
- if [ -f "$SCRIPT_DIR/.env" ]; then
11
- export $(grep -v '^#' $SCRIPT_DIR/.env | xargs -0)
12
- fi
13
-
14
- # exec $SCRIPT_DIR/old_commands/main.sh "$@"
15
- exec ruby $SCRIPT_DIR/lib/main.rb "$@"
6
+ Cpl::Cli.start
data/docs/commands.md CHANGED
@@ -285,6 +285,18 @@ cpl ps:stop -a $APP_NAME
285
285
  cpl ps:stop -a $APP_NAME -w $WORKLOAD_NAME
286
286
  ```
287
287
 
288
+ ### `ps:wait`
289
+
290
+ - Waits for workloads in app to be ready after re-deployment
291
+
292
+ ```sh
293
+ # Waits for all workloads in app.
294
+ cpl ps:wait -a $APP_NAME
295
+
296
+ # Waits for a specific workload in app.
297
+ cpl ps:swait -a $APP_NAME -w $WORKLOAD_NAME
298
+ ```
299
+
288
300
  ### `run`
289
301
 
290
302
  - Runs one-off **_interactive_** replicas (analog of `heroku run`)
@@ -329,6 +341,7 @@ cpl run bash -a $APP_NAME --use-local-token
329
341
  - Deletes stale run workloads for an app
330
342
  - Workloads are considered stale based on how many days since created
331
343
  - `stale_run_workload_created_days` in the `.controlplane/controlplane.yml` file specifies the number of days after created that the workload is considered stale
344
+ - Works for both interactive workloads (created with `cpl run`) and non-interactive workloads (created with `cpl run:detached`)
332
345
  - Will ask for explicit user confirmation of deletion
333
346
 
334
347
  ```sh
@@ -352,18 +365,16 @@ cpl run:detached 'LOG_LEVEL=warn rails db:migrate' -a $APP_NAME
352
365
  # COMMAND may also be passed at the end (in this case, no need to quote).
353
366
  cpl run:detached -a $APP_NAME -- rails db:migrate
354
367
 
355
- # Uses some other image.
356
- cpl run:detached rails db:migrate -a $APP_NAME --image /some/full/image/path
357
-
358
- # Uses latest app image (which may not be promoted yet).
359
- cpl run:detached rails db:migrate -a $APP_NAME --image latest
360
-
361
368
  # Uses a different image (which may not be promoted yet).
362
369
  cpl run:detached rails db:migrate -a $APP_NAME --image appimage:123 # Exact image name
363
370
  cpl run:detached rails db:migrate -a $APP_NAME --image latest # Latest sequential image
364
371
 
365
372
  # Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
366
373
  cpl run:detached rails db:migrate:status -a $APP_NAME -w other-workload
374
+
375
+ # Overrides remote CPLN_TOKEN env variable with local token.
376
+ # Useful when superuser rights are needed in remote container.
377
+ cpl run:detached rails db:migrate:status -a $APP_NAME --use-local-token
367
378
  ```
368
379
 
369
380
  ### `setup-app`
data/docs/migrating.md ADDED
@@ -0,0 +1,262 @@
1
+ # Steps to Migrate from Heroku to Control Plane
2
+
3
+ We recommend following along with
4
+ [this example project](https://github.com/shakacode/react-webpack-rails-tutorial).
5
+
6
+ 1. [Clone the Staging Environment](#clone-the-staging-environment)
7
+ - [Review Special Gems](#review-special-gems)
8
+ - [Create a Minimum Bootable Config](#create-a-minimum-bootable-config)
9
+ 2. [Create the Review App Process](#create-the-review-app-process)
10
+ - [Database for Review Apps](#database-for-review-apps)
11
+ - [Redis and Memcached for Review Apps](#redis-and-memcached-for-review-apps)
12
+ 3. [Deploy to Production](#deploy-to-production)
13
+
14
+ ## Clone the Staging Environment
15
+
16
+ By cloning the staging environment on Heroku, you can speed up the initial provisioning of the app on Control Plane
17
+ without compromising your current environment.
18
+
19
+ Consider migrating just the web dyno first, and get other types of dynos working afterward. You can also move the
20
+ add-ons to Control Plane later once the app works as expected.
21
+
22
+ First, create a new Heroku app with all the add-ons, copying the data from the current staging app.
23
+
24
+ Then, copy project-specific configs to a `.controlplane/` directory at the top of your project. `cpl` will pick those up
25
+ depending on which project folder tree it runs. Thus, this automates running several projects with different configs
26
+ without explicitly switching configs.
27
+
28
+ Edit the `.controlplane/controlplane.yml` file as needed. Note that the `my-app-staging` name used in the examples below
29
+ is defined in this file. See
30
+ [this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/controlplane.yml).
31
+
32
+ Before the initial setup, add the templates for the app to the `.controlplane/controlplane.yml` file, using the `setup`
33
+ key, e.g.:
34
+
35
+ ```yaml
36
+ my-app-staging:
37
+ <<: *common
38
+ setup:
39
+ - gvc
40
+ - redis
41
+ - memcached
42
+ - rails
43
+ - sidekiq
44
+ ```
45
+
46
+ Note how the templates correspond to files in the `.controlplane/templates/` directory. These files will be used by the
47
+ `cpl setup-app` and `cpl apply-template` commands.
48
+
49
+ Ensure that env vars point to the Heroku add-ons in the template for the app (`.controlplane/templates/gvc.yml`). See
50
+ [this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/templates/gvc.yml).
51
+
52
+ After that, create a Dockerfile in `.controlplane/Dockerfile` for your deployment. See
53
+ [this example](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/Dockerfile).
54
+
55
+ You should have a folder structure similar to the following:
56
+
57
+ ```sh
58
+ app_main_folder/
59
+ .controlplane/
60
+ Dockerfile # Your app's Dockerfile, with some Control Plane changes.
61
+ controlplane.yml
62
+ entrypoint.sh # App-specific - edit as needed.
63
+ templates/
64
+ gvc.yml
65
+ memcached.yml
66
+ rails.yml
67
+ redis.yml
68
+ sidekiq.yml
69
+ ```
70
+
71
+ The example
72
+ [`.controlplane/` directory](https://github.com/shakacode/react-webpack-rails-tutorial/tree/master/.controlplane)
73
+ already contains these files.
74
+
75
+ Finally, check the app for any Heroku-specific code and update it, such as the `HEROKU_SLUG_COMMIT` env var and other
76
+ env vars beginning with `HEROKU_`. You should add some logic to check for the Control Plane equivalents - it might be
77
+ worth adding a `CONTROLPLANE` env var to act as a feature flag and help run different code for Heroku and Control Plane
78
+ until the migration is complete.
79
+
80
+ You might want to [review special gems](#review-special-gems) and
81
+ [create a minimum bootable config](#create-a-minimum-bootable-config).
82
+
83
+ At first, do the deployments from the command line. Then set up CI scripts to trigger the deployment upon merges to
84
+ master/main.
85
+
86
+ Use these commands for the initial setup and deployment:
87
+
88
+ ```sh
89
+ # Provision infrastructure (one-time-only for new apps) using templates.
90
+ cpl setup-app -a my-app-staging
91
+
92
+ # Build and push image with auto-tagging, e.g., "my-app-staging:1_456".
93
+ cpl build-image -a my-app-staging --commit 456
94
+
95
+ # Prepare database.
96
+ cpl run:detached -a my-app-staging --image latest -- rails db:prepare
97
+
98
+ # Deploy latest image.
99
+ cpl deploy-image -a my-app-staging
100
+
101
+ # Open app in browser.
102
+ cpl open -a my-app-staging
103
+ ```
104
+
105
+ Then for promoting code upgrades:
106
+
107
+ ```sh
108
+ # Build and push new image with sequential tagging, e.g., "my-app-staging:2".
109
+ cpl build-image -a my-app-staging
110
+
111
+ # Or build and push new image with sequential tagging and commit SHA, e.g., "my-app-staging:2_ABC".
112
+ cpl build-image -a my-app-staging --commit ABC
113
+
114
+ # Run database migrations (or other release tasks) with latest image, while app is still running on previous image.
115
+ # This is analogous to the release phase.
116
+ cpl run:detached -a my-app-staging --image latest -- rails db:migrate
117
+
118
+ # Deploy latest image.
119
+ cpl deploy-image -a my-app-staging
120
+ ```
121
+
122
+ ### Review Special Gems
123
+
124
+ Make sure to review "special" gems which might be related to Heroku, e.g.:
125
+
126
+ - `rails_autoscale_agent`. It's specific to Heroku, so it must be removed.
127
+ - `puma_worker_killer`. In general, it's unnecessary on Control Plane, as Kubernetes containers will restart on their
128
+ own logic and may not restart at all if everything is ok.
129
+ - `rack-timeout`. It could possibly be replaced with Control Plane's `timeout` option.
130
+
131
+ You can use the `CONTROLPLANE` env var to separate the gems, e.g.:
132
+
133
+ ```ruby
134
+ # Gemfile
135
+ group :staging, :production do
136
+ gem "rack-timeout"
137
+
138
+ unless ENV.key?("CONTROLPLANE")
139
+ gem "rails_autoscale_agent"
140
+ gem "puma_worker_killer"
141
+ end
142
+ end
143
+ ```
144
+
145
+ ### Create a Minimum Bootable Config
146
+
147
+ You can try to create a minimum bootable config to migrate parts of your app gradually. To do that, follow these steps:
148
+
149
+ 1. Rename the existing `application.yml` file to some other name (e.g., `application.old.yml`)
150
+ 2. Create a new **minimal** `application.yml` file, e.g.:
151
+
152
+ ```yaml
153
+ SECRET_KEY_BASE: "123"
154
+ # This should be enabled for `rails s`, not `rails assets:precompile`.
155
+ # DATABASE_URL: postgres://localhost:5432/dbname
156
+ # RAILS_SERVE_STATIC_FILES: "true"
157
+
158
+ # You will add whatever env vars are required here later.
159
+ ```
160
+
161
+ 3. Try running `RAILS_ENV=production CONTROLPLANE=true rails assets:precompile`
162
+ (theoretically, this should work without any additional env vars)
163
+ 4. Fix whatever code needs to be fixed and add missing env vars
164
+ (the fewer env vars are needed, the cleaner the `Dockerfile` will be)
165
+ 5. Enable `DATABASE_URL` and `RAILS_SERVE_STATIC_FILES` env vars
166
+ 6. Try running `RAILS_ENV=production CONTROLPLANE=true rails s`
167
+ 7. Fix whatever code needs to be fixed and add required env vars to `application.yml`
168
+ 8. Try running your **production** entrypoint command, e.g.,
169
+ `RAILS_ENV=production RACK_ENV=production CONTROLPLANE=true puma -C config/puma.rb`
170
+ 9. Fix whatever code needs to be fixed and add required env vars to `application.yml`
171
+
172
+ Now you should have a minimal bootable config.
173
+
174
+ Then you can temporarily set the `LOG_LEVEL=debug` env var and disable unnecessary services to help with the process,
175
+ e.g.:
176
+
177
+ ```yaml
178
+ DISABLE_SPRING: "true"
179
+ SCOUT_MONITOR: "false"
180
+ RACK_TIMEOUT_SERVICE_TIMEOUT: "0"
181
+ ```
182
+
183
+ ## Create the Review App Process
184
+
185
+ Add an entry for review apps to the `.controlplane/controlplane.yml` file. By adding a `match_if_app_name_starts_with`
186
+ key with the value `true`, any app that starts with the entry's name will use this config. Doing this allows you to
187
+ configure an entry for, e.g., `my-app-review`, and then create review apps starting with that name (e.g.,
188
+ `my-app-review-1234`, `my-app-review-5678`, etc.). Here's an example:
189
+
190
+ ```yaml
191
+ my-app-review:
192
+ <<: *common
193
+ match_if_app_name_starts_with: true
194
+ setup:
195
+ - gvc
196
+ - redis
197
+ - memcached
198
+ - rails
199
+ - sidekiq
200
+ ```
201
+
202
+ In your CI scripts, you can create a review app using some identifier (e.g., the number of the PR on GitHub).
203
+
204
+ ```yaml
205
+ # On CircleCI, you can use `echo $CIRCLE_PULL_REQUEST | grep -Eo '[0-9]+$'` to extract the number of the PR.
206
+ PR_NUM=$(... extract the number of the PR here ...)
207
+ echo "export APP_NAME=my-app-review-$PR_NUM" >> $BASH_ENV
208
+
209
+ # Only create the app if it doesn't exist yet, as we may have multiple triggers for the review app
210
+ # (such as when a PR gets updated).
211
+ if ! cpl exists -a ${APP_NAME}; then
212
+ cpl setup-app -a ${APP_NAME}
213
+ echo "export NEW_APP=true" >> $BASH_ENV
214
+ fi
215
+
216
+ # The `NEW_APP` env var that we exported above can be used to either reset or migrate the database before deploying.
217
+ if [ -n "${NEW_APP}" ]; then
218
+ cpl run:detached 'LOG_LEVEL=warn rails db:reset' -a ${APP_NAME} --image latest
219
+ else
220
+ cpl run:detached 'LOG_LEVEL=warn rails db:migrate_and_wait_replica' -a ${APP_NAME} --image latest
221
+ fi
222
+ ```
223
+
224
+ Then follow the same steps for the initial deployment or code upgrades.
225
+
226
+ ### Database for Review Apps
227
+
228
+ For the review app resources, these should be handled as env vars in the template for the app
229
+ (`.controlplane/templates/gvc.yml`), .e.g.:
230
+
231
+ ```yaml
232
+ - name: DATABASE_URL
233
+ value: postgres://postgres:XXXXXXXX@cpln-XXXX-staging.XXXXXX.us-east-1.rds.amazonaws.com:5432/APP_GVC
234
+ ```
235
+
236
+ Notice that `APP_GVC` is the app name, which is used as the database name on RDS, so that each review app gets its own
237
+ database on the one RDS instance used for all review apps, which would be, e.g., `my-app-review-1234`.
238
+
239
+ ### Redis and Memcached for Review Apps
240
+
241
+ So long as no persistence is needed for Redis and Memcached, we have templates for workloads that should be sufficient
242
+ for review apps in the `templates/` directory of this repository. Using these templates results in considerable cost
243
+ savings compared to paying for the resources on Heroku.
244
+
245
+ ```yaml
246
+ - name: MEMCACHE_SERVERS
247
+ value: memcached.APP_GVC.cpln.local
248
+ - name: REDIS_URL
249
+ value: redis://redis.APP_GVC.cpln.local:6379
250
+ ```
251
+
252
+ ## Deploy to Production
253
+
254
+ Only try deploying to production once staging and review apps are working well.
255
+
256
+ For simplicity, keep add-ons running on Heroku initially. You could move over the database to RDS first. However, it's a
257
+ bit simpler to isolate any differences in cost and performance by first moving over your compute to Control Plane.
258
+
259
+ Ensure that your Control Plane compute is in the AWS region `US-EAST-1`; otherwise, you'll have noticeable extra latency
260
+ with your calls to resources. You might also have egress charges from Control Plane.
261
+
262
+ Use the `cpl promote-app-from-upstream` command to promote the staging app to production.
@@ -59,8 +59,7 @@ build-review-app:
59
59
  cpln profile create default --token ${CPLN_TOKEN} --org ${CPLN_ORG} --gvc ${APP_NAME}
60
60
  cpln image docker-login
61
61
 
62
- git clone https://github.com/shakacode/heroku-to-control-plane ~/heroku-to-control-plane
63
- sudo ln -s ~/heroku-to-control-plane/cpl /usr/local/bin/cpl
62
+ gem install cpl
64
63
  - run:
65
64
  name: Provision review app if needed
66
65
  command: |
@@ -31,6 +31,18 @@ module Command
31
31
 
32
32
  private
33
33
 
34
+ def app_prefix
35
+ config.should_app_start_with?(config.app) ? "#{config.app}-" : "#{config.app}:"
36
+ end
37
+
38
+ def remove_deployed_image(app, app_images)
39
+ return app_images unless cp.fetch_gvc(app)
40
+
41
+ # If app exists, remove latest image, because we don't want to delete the image that is currently deployed
42
+ latest_image_name = latest_image_from(app_images, app_name: app)
43
+ app_images.filter { |item| item["name"] != latest_image_name }
44
+ end
45
+
34
46
  def old_images # rubocop:disable Metrics/MethodLength
35
47
  @old_images ||=
36
48
  begin
@@ -39,21 +51,20 @@ module Command
39
51
  now = DateTime.now
40
52
  old_image_retention_days = config[:old_image_retention_days]
41
53
 
42
- images = cp.image_query["items"].filter { |item| item["name"].start_with?("#{config.app}:") }
43
-
44
- # Remove latest image, because we don't want to delete the image that is currently deployed
45
- latest_image_name = latest_image_from(images)
46
- images = images.filter { |item| item["name"] != latest_image_name }
47
-
48
- images.each do |image|
49
- created_date = DateTime.parse(image["created"])
50
- diff_in_days = (now - created_date).to_i
51
- next unless diff_in_days >= old_image_retention_days
52
-
53
- result_images.push({
54
- name: image["name"],
55
- date: created_date
56
- })
54
+ images = cp.image_query["items"].filter { |item| item["name"].start_with?(app_prefix) }
55
+ images_by_app = images.group_by { |item| item["repository"] }
56
+ images_by_app.each do |app, app_images|
57
+ app_images = remove_deployed_image(app, app_images)
58
+ app_images.each do |image|
59
+ created_date = DateTime.parse(image["created"])
60
+ diff_in_days = (now - created_date).to_i
61
+ next unless diff_in_days >= old_image_retention_days
62
+
63
+ result_images.push({
64
+ name: image["name"],
65
+ date: created_date
66
+ })
67
+ end
57
68
  end
58
69
 
59
70
  result_images
data/lib/command/info.rb CHANGED
@@ -112,10 +112,6 @@ module Command
112
112
  result.uniq.sort
113
113
  end
114
114
 
115
- def should_app_start_with?(app)
116
- config.apps[app.to_sym]&.dig(:match_if_app_name_starts_with)
117
- end
118
-
119
115
  def any_app_starts_with?(app)
120
116
  @app_workloads.keys.find { |app_name| app_matches?(app_name, app, config.apps[app.to_sym]) }
121
117
  end
@@ -132,7 +128,7 @@ module Command
132
128
  end
133
129
 
134
130
  def add_to_missing_workloads(app, workload)
135
- if should_app_start_with?(app)
131
+ if config.should_app_start_with?(app)
136
132
  @missing_apps_starting_with[app] ||= []
137
133
  @missing_apps_starting_with[app].push(workload)
138
134
  else
@@ -142,7 +138,7 @@ module Command
142
138
  end
143
139
 
144
140
  def print_app(app, org)
145
- if should_app_start_with?(app)
141
+ if config.should_app_start_with?(app)
146
142
  check_any_app_starts_with(app)
147
143
  elsif cp.fetch_gvc(app, org).nil?
148
144
  @missing_apps_workloads[app] = ["gvc"]
@@ -42,9 +42,7 @@ module Command
42
42
 
43
43
  @workloads.reverse_each do |workload|
44
44
  step("Waiting for workload '#{workload}' to be ready", retry_on_failure: true) do
45
- cp.fetch_workload_deployments(workload)&.dig("items")&.any? do |item|
46
- item.dig("status", "ready")
47
- end
45
+ cp.workload_deployments_ready?(workload, expected_status: true)
48
46
  end
49
47
  end
50
48
  end
@@ -6,7 +6,7 @@ module Command
6
6
  OPTIONS = [
7
7
  app_option(required: true),
8
8
  workload_option,
9
- wait_option("workload to be not ready")
9
+ wait_option("workload to not be ready")
10
10
  ].freeze
11
11
  DESCRIPTION = "Stops workloads in app"
12
12
  LONG_DESCRIPTION = <<~DESC
@@ -41,10 +41,8 @@ module Command
41
41
  progress.puts
42
42
 
43
43
  @workloads.each do |workload|
44
- step("Waiting for workload '#{workload}' to be not ready", retry_on_failure: true) do
45
- cp.fetch_workload_deployments(workload)&.dig("items")&.all? do |item|
46
- !item.dig("status", "ready")
47
- end
44
+ step("Waiting for workload '#{workload}' to not be ready", retry_on_failure: true) do
45
+ cp.workload_deployments_ready?(workload, expected_status: false)
48
46
  end
49
47
  end
50
48
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Command
4
+ class PsWait < Base
5
+ NAME = "ps:wait"
6
+ OPTIONS = [
7
+ app_option(required: true),
8
+ workload_option
9
+ ].freeze
10
+ DESCRIPTION = "Waits for workloads in app to be ready after re-deployment"
11
+ LONG_DESCRIPTION = <<~DESC
12
+ - Waits for workloads in app to be ready after re-deployment
13
+ DESC
14
+ EXAMPLES = <<~EX
15
+ ```sh
16
+ # Waits for all workloads in app.
17
+ cpl ps:wait -a $APP_NAME
18
+
19
+ # Waits for a specific workload in app.
20
+ cpl ps:swait -a $APP_NAME -w $WORKLOAD_NAME
21
+ ```
22
+ EX
23
+
24
+ def call
25
+ @workloads = [config.options[:workload]] if config.options[:workload]
26
+ @workloads ||= config[:app_workloads] + config[:additional_workloads]
27
+
28
+ @workloads.reverse_each do |workload|
29
+ step("Waiting for workload '#{workload}' to be ready", retry_on_failure: true) do
30
+ cp.workload_deployments_ready?(workload, expected_status: true)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/command/run.rb CHANGED
@@ -99,8 +99,8 @@ module Command
99
99
 
100
100
  # Override image if specified
101
101
  image = config.options[:image]
102
- image = "/org/#{config.org}/image/#{latest_image}" if image == "latest"
103
- container_spec["image"] = image if image
102
+ image = latest_image if image == "latest"
103
+ container_spec["image"] = "/org/#{config.org}/image/#{image}"
104
104
 
105
105
  # Set runner
106
106
  container_spec["env"] ||= []
@@ -12,6 +12,7 @@ module Command
12
12
  - Deletes stale run workloads for an app
13
13
  - Workloads are considered stale based on how many days since created
14
14
  - `stale_run_workload_created_days` in the `.controlplane/controlplane.yml` file specifies the number of days after created that the workload is considered stale
15
+ - Works for both interactive workloads (created with `cpl run`) and non-interactive workloads (created with `cpl run:detached`)
15
16
  - Will ask for explicit user confirmation of deletion
16
17
  DESC
17
18
 
@@ -20,8 +21,14 @@ module Command
20
21
 
21
22
  progress.puts("Stale run workloads:")
22
23
  stale_run_workloads.each do |workload|
23
- progress.puts(" #{workload[:name]} " \
24
- "(#{Shell.color("#{workload[:date]} - #{workload[:days]} days ago", :red)})")
24
+ output = ""
25
+ output += if config.should_app_start_with?(config.app)
26
+ " #{workload[:app]} - #{workload[:name]}"
27
+ else
28
+ " #{workload[:name]}"
29
+ end
30
+ output += " (#{Shell.color("#{workload[:date]} - #{workload[:days]} days ago", :red)})"
31
+ progress.puts(output)
25
32
  end
26
33
 
27
34
  return unless confirm_delete
@@ -62,11 +69,19 @@ module Command
62
69
  now = DateTime.now
63
70
  stale_run_workload_created_days = config[:stale_run_workload_created_days]
64
71
 
65
- workloads = cp.query_workloads("-run-", partial_match: true)["items"]
72
+ interactive_workloads = cp.query_workloads(
73
+ "-run-", partial_gvc_match: config.should_app_start_with?(config.app), partial_workload_match: true
74
+ )["items"]
75
+ non_interactive_workloads = cp.query_workloads(
76
+ "-runner-", partial_gvc_match: config.should_app_start_with?(config.app), partial_workload_match: true
77
+ )["items"]
78
+ workloads = interactive_workloads + non_interactive_workloads
79
+
66
80
  workloads.each do |workload|
81
+ app_name = workload["links"].find { |link| link["rel"] == "gvc" }["href"].split("/").last
67
82
  workload_name = workload["name"]
68
83
 
69
- original_workload_name, workload_number = workload_name.split("-run-")
84
+ original_workload_name, workload_number = workload_name.split(/-run-|-runner-/)
70
85
  next unless defined_workloads.include?(original_workload_name) && workload_number.match?(/^\d{4}$/)
71
86
 
72
87
  created_date = DateTime.parse(workload["created"])
@@ -74,6 +89,7 @@ module Command
74
89
  next unless diff_in_days >= stale_run_workload_created_days
75
90
 
76
91
  run_workloads.push({
92
+ app: app_name,
77
93
  name: workload_name,
78
94
  date: created_date,
79
95
  days: diff_in_days
@@ -91,8 +107,13 @@ module Command
91
107
  end
92
108
 
93
109
  def delete_workload(workload)
94
- step("Deleting run workload '#{workload[:name]}'") do
95
- cp.delete_workload(workload[:name])
110
+ message = if config.should_app_start_with?(config.app)
111
+ "Deleting run workload '#{workload[:app]} - #{workload[:name]}'"
112
+ else
113
+ "Deleting run workload '#{workload[:name]}'"
114
+ end
115
+ step(message) do
116
+ cp.delete_workload(workload[:name], workload[:app])
96
117
  end
97
118
  end
98
119
  end
@@ -8,7 +8,8 @@ module Command
8
8
  OPTIONS = [
9
9
  app_option(required: true),
10
10
  image_option,
11
- workload_option
11
+ workload_option,
12
+ use_local_token_option
12
13
  ].freeze
13
14
  DESCRIPTION = "Runs one-off **_non-interactive_** replicas (close analog of `heroku run:detached`)"
14
15
  LONG_DESCRIPTION = <<~DESC
@@ -28,18 +29,16 @@ module Command
28
29
  # COMMAND may also be passed at the end (in this case, no need to quote).
29
30
  cpl run:detached -a $APP_NAME -- rails db:migrate
30
31
 
31
- # Uses some other image.
32
- cpl run:detached rails db:migrate -a $APP_NAME --image /some/full/image/path
33
-
34
- # Uses latest app image (which may not be promoted yet).
35
- cpl run:detached rails db:migrate -a $APP_NAME --image latest
36
-
37
32
  # Uses a different image (which may not be promoted yet).
38
33
  cpl run:detached rails db:migrate -a $APP_NAME --image appimage:123 # Exact image name
39
34
  cpl run:detached rails db:migrate -a $APP_NAME --image latest # Latest sequential image
40
35
 
41
36
  # Uses a different workload than `one_off_workload` from `.controlplane/controlplane.yml`.
42
37
  cpl run:detached rails db:migrate:status -a $APP_NAME -w other-workload
38
+
39
+ # Overrides remote CPLN_TOKEN env variable with local token.
40
+ # Useful when superuser rights are needed in remote container.
41
+ cpl run:detached rails db:migrate:status -a $APP_NAME --use-local-token
43
42
  ```
44
43
  EX
45
44
 
@@ -91,8 +90,8 @@ module Command
91
90
 
92
91
  # Override image if specified
93
92
  image = config.options[:image]
94
- image = "/org/#{config.org}/image/#{latest_image}" if image == "latest"
95
- container_spec["image"] = image if image
93
+ image = latest_image if image == "latest"
94
+ container_spec["image"] = "/org/#{config.org}/image/#{image}"
96
95
 
97
96
  # Set cron job props
98
97
  spec["type"] = "cron"
@@ -108,10 +107,16 @@ module Command
108
107
  cp.apply("kind" => "workload", "name" => one_off, "spec" => spec)
109
108
  end
110
109
 
111
- def runner_script
110
+ def runner_script # rubocop:disable Metrics/MethodLength
112
111
  script = "echo '-- STARTED RUNNER SCRIPT --'\n"
113
112
  script += Scripts.helpers_cleanup
114
113
 
114
+ if config.options["use_local_token"]
115
+ script += <<~SHELL
116
+ CPLN_TOKEN=$CONTROLPLANE_TOKEN
117
+ SHELL
118
+ end
119
+
115
120
  script += <<~SHELL
116
121
  if ! eval "#{args_join(config.args)}"; then echo "----- CRASHED -----"; fi
117
122
 
data/lib/command/test.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Be sure to have run: gem install debug
4
3
  require "debug"
5
4
 
6
5
  module Command
@@ -14,13 +13,10 @@ module Command
14
13
  HIDE = true
15
14
 
16
15
  def call
17
- # Change code here to test.
16
+ # Modify this method to trigger the code you want to test.
18
17
  # You can use `debugger` to debug.
19
- # debugger
20
- # Or print values
21
- # rubocop:disable Lint/Debugger
22
- pp latest_image_next
23
- # rubocop:enable Lint/Debugger
18
+ # You can use `Cpl::Cli.start` to simulate a command
19
+ # (e.g., `Cpl::Cli.start(["deploy-image", "-a", "my-app-name"])`).
24
20
  end
25
21
  end
26
22
  end
data/lib/core/config.rb CHANGED
@@ -34,6 +34,10 @@ class Config
34
34
  "#{app_dir}/.controlplane"
35
35
  end
36
36
 
37
+ def should_app_start_with?(app)
38
+ apps[app.to_sym]&.dig(:match_if_app_name_starts_with) || false
39
+ end
40
+
37
41
  private
38
42
 
39
43
  def ensure_current_config!
@@ -45,7 +45,11 @@ class Controlplane # rubocop:disable Metrics/ClassLength
45
45
  end
46
46
 
47
47
  def image_query(app_name = config.app, org_name = config.org)
48
- cmd = "cpln image query --org #{org_name} -o yaml --max -1 --prop repository=#{app_name}"
48
+ # When `match_if_app_name_starts_with` is `true`, we query for images from any gvc containing the name,
49
+ # otherwise we query for images from a gvc with the exact name.
50
+ op = config.should_app_start_with?(app_name) ? "~" : "="
51
+
52
+ cmd = "cpln image query --org #{org_name} -o yaml --max -1 --prop repository#{op}#{app_name}"
49
53
  perform_yaml(cmd)
50
54
  end
51
55
 
@@ -86,7 +90,7 @@ class Controlplane # rubocop:disable Metrics/ClassLength
86
90
  def gvc_query(app_name = config.app)
87
91
  # When `match_if_app_name_starts_with` is `true`, we query for any gvc containing the name,
88
92
  # otherwise we query for a gvc with the exact name.
89
- op = config.current[:match_if_app_name_starts_with] ? "~" : "="
93
+ op = config.should_app_start_with?(app_name) ? "~" : "="
90
94
 
91
95
  cmd = "cpln gvc query --org #{org} -o yaml --prop name#{op}#{app_name}"
92
96
  perform_yaml(cmd)
@@ -128,10 +132,11 @@ class Controlplane # rubocop:disable Metrics/ClassLength
128
132
  raise "Can't find workload '#{workload}', please create it with 'cpl apply-template #{workload} -a #{config.app}'."
129
133
  end
130
134
 
131
- def query_workloads(workload, partial_match: false)
132
- op = partial_match ? "~" : "="
135
+ def query_workloads(workload, partial_gvc_match: false, partial_workload_match: false)
136
+ gvc_op = partial_gvc_match ? "~" : "="
137
+ workload_op = partial_workload_match ? "~" : "="
133
138
 
134
- api.query_workloads(org: org, gvc: gvc, workload: workload, op_type: op)
139
+ api.query_workloads(org: org, gvc: gvc, workload: workload, gvc_op_type: gvc_op, workload_op_type: workload_op)
135
140
  end
136
141
 
137
142
  def workload_get_replicas(workload, location:)
@@ -149,6 +154,26 @@ class Controlplane # rubocop:disable Metrics/ClassLength
149
154
  api.workload_deployments(workload: workload, gvc: gvc, org: org)
150
155
  end
151
156
 
157
+ def workload_deployment_version_ready?(version, next_version, expected_status:)
158
+ return false unless version["workload"] == next_version
159
+
160
+ version["containers"]&.all? do |_, container|
161
+ ready = container.dig("resources", "replicas") == container.dig("resources", "replicasReady")
162
+ expected_status == true ? ready : !ready
163
+ end
164
+ end
165
+
166
+ def workload_deployments_ready?(workload, expected_status:)
167
+ deployments = fetch_workload_deployments(workload)["items"]
168
+ deployments.all? do |deployment|
169
+ next_version = deployment.dig("status", "expectedDeploymentVersion")
170
+
171
+ deployment.dig("status", "versions")&.all? do |version|
172
+ workload_deployment_version_ready?(version, next_version, expected_status: expected_status)
173
+ end
174
+ end
175
+ end
176
+
152
177
  def workload_set_image_ref(workload, container:, image:)
153
178
  cmd = "cpln workload update #{workload} #{gvc_org}"
154
179
  cmd += " --set spec.containers.#{container}.image=/org/#{config.org}/image/#{image}"
@@ -184,8 +209,8 @@ class Controlplane # rubocop:disable Metrics/ClassLength
184
209
  perform!(cmd)
185
210
  end
186
211
 
187
- def delete_workload(workload)
188
- api.delete_workload(org: org, gvc: gvc, workload: workload)
212
+ def delete_workload(workload, a_gvc = gvc)
213
+ api.delete_workload(org: org, gvc: a_gvc, workload: workload)
189
214
  end
190
215
 
191
216
  def workload_connect(workload, location:, container: nil, shell: nil)
@@ -33,7 +33,7 @@ class ControlplaneApi
33
33
  api_json_direct("/logs/org/#{org}/loki/api/v1/query_range?#{params}", method: :get, host: :logs)
34
34
  end
35
35
 
36
- def query_workloads(org:, gvc:, workload:, op_type:) # rubocop:disable Metrics/MethodLength
36
+ def query_workloads(org:, gvc:, workload:, gvc_op_type:, workload_op_type:) # rubocop:disable Metrics/MethodLength
37
37
  body = {
38
38
  kind: "string",
39
39
  spec: {
@@ -41,12 +41,12 @@ class ControlplaneApi
41
41
  terms: [
42
42
  {
43
43
  rel: "gvc",
44
- op: "=",
44
+ op: gvc_op_type,
45
45
  value: gvc
46
46
  },
47
47
  {
48
48
  property: "name",
49
- op: op_type,
49
+ op: workload_op_type,
50
50
  value: workload
51
51
  }
52
52
  ]
data/lib/cpl/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpl
4
- VERSION = "1.0.1"
4
+ VERSION = "1.0.3"
5
5
  MIN_CPLN_VERSION = "0.0.71"
6
6
  end
data/lib/cpl.rb CHANGED
@@ -13,7 +13,7 @@ require "yaml"
13
13
  require_relative "command/base"
14
14
 
15
15
  modules = Dir["#{__dir__}/**/*.rb"].reject do |file|
16
- file == __FILE__ || file.end_with?("main.rb") || file.end_with?("base.rb")
16
+ file == __FILE__ || file.end_with?("base.rb")
17
17
  end
18
18
  modules.sort.each { require(_1) }
19
19
 
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: 1.0.1
4
+ version: 1.0.3
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: 2023-06-28 00:00:00.000000000 Z
12
+ date: 2023-07-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug
@@ -223,6 +223,7 @@ files:
223
223
  - docs/assets/memcached.png
224
224
  - docs/assets/sidekiq-pre-stop-hook.png
225
225
  - docs/commands.md
226
+ - docs/migrating.md
226
227
  - docs/postgres.md
227
228
  - docs/redis.md
228
229
  - docs/tips.md
@@ -255,6 +256,7 @@ files:
255
256
  - lib/command/ps_restart.rb
256
257
  - lib/command/ps_start.rb
257
258
  - lib/command/ps_stop.rb
259
+ - lib/command/ps_wait.rb
258
260
  - lib/command/run.rb
259
261
  - lib/command/run_cleanup.rb
260
262
  - lib/command/run_detached.rb
@@ -271,7 +273,6 @@ files:
271
273
  - lib/cpl.rb
272
274
  - lib/cpl/version.rb
273
275
  - lib/deprecated_commands.json
274
- - lib/main.rb
275
276
  - rakelib/create_release.rake
276
277
  - script/add_command
277
278
  - script/check_command_docs
data/lib/main.rb DELETED
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "cpl"
4
-
5
- Cpl::Cli.start