cpflow 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/check_cpln_links.yml +19 -0
  3. data/.github/workflows/command_docs.yml +24 -0
  4. data/.github/workflows/rspec-shared.yml +56 -0
  5. data/.github/workflows/rspec.yml +28 -0
  6. data/.github/workflows/rubocop.yml +24 -0
  7. data/.gitignore +18 -0
  8. data/.overcommit.yml +16 -0
  9. data/.rubocop.yml +22 -0
  10. data/.simplecov_spawn.rb +10 -0
  11. data/CHANGELOG.md +259 -0
  12. data/CONTRIBUTING.md +73 -0
  13. data/Gemfile +7 -0
  14. data/Gemfile.lock +126 -0
  15. data/LICENSE +21 -0
  16. data/README.md +546 -0
  17. data/Rakefile +21 -0
  18. data/bin/cpflow +6 -0
  19. data/cpflow +6 -0
  20. data/cpflow.gemspec +41 -0
  21. data/docs/assets/grafana-alert.png +0 -0
  22. data/docs/assets/memcached.png +0 -0
  23. data/docs/assets/sidekiq-pre-stop-hook.png +0 -0
  24. data/docs/commands.md +454 -0
  25. data/docs/dns.md +15 -0
  26. data/docs/migrating.md +262 -0
  27. data/docs/postgres.md +436 -0
  28. data/docs/redis.md +128 -0
  29. data/docs/secrets-and-env-values.md +42 -0
  30. data/docs/tips.md +150 -0
  31. data/docs/troubleshooting.md +6 -0
  32. data/examples/circleci.yml +104 -0
  33. data/examples/controlplane.yml +159 -0
  34. data/lib/command/apply_template.rb +209 -0
  35. data/lib/command/base.rb +540 -0
  36. data/lib/command/build_image.rb +49 -0
  37. data/lib/command/cleanup_images.rb +136 -0
  38. data/lib/command/cleanup_stale_apps.rb +79 -0
  39. data/lib/command/config.rb +48 -0
  40. data/lib/command/copy_image_from_upstream.rb +108 -0
  41. data/lib/command/delete.rb +149 -0
  42. data/lib/command/deploy_image.rb +56 -0
  43. data/lib/command/doctor.rb +47 -0
  44. data/lib/command/env.rb +22 -0
  45. data/lib/command/exists.rb +23 -0
  46. data/lib/command/generate.rb +45 -0
  47. data/lib/command/info.rb +222 -0
  48. data/lib/command/latest_image.rb +19 -0
  49. data/lib/command/logs.rb +49 -0
  50. data/lib/command/maintenance.rb +42 -0
  51. data/lib/command/maintenance_off.rb +62 -0
  52. data/lib/command/maintenance_on.rb +62 -0
  53. data/lib/command/maintenance_set_page.rb +34 -0
  54. data/lib/command/no_command.rb +23 -0
  55. data/lib/command/open.rb +33 -0
  56. data/lib/command/open_console.rb +26 -0
  57. data/lib/command/promote_app_from_upstream.rb +38 -0
  58. data/lib/command/ps.rb +41 -0
  59. data/lib/command/ps_restart.rb +37 -0
  60. data/lib/command/ps_start.rb +51 -0
  61. data/lib/command/ps_stop.rb +82 -0
  62. data/lib/command/ps_wait.rb +40 -0
  63. data/lib/command/run.rb +573 -0
  64. data/lib/command/setup_app.rb +113 -0
  65. data/lib/command/test.rb +23 -0
  66. data/lib/command/version.rb +18 -0
  67. data/lib/constants/exit_code.rb +7 -0
  68. data/lib/core/config.rb +316 -0
  69. data/lib/core/controlplane.rb +552 -0
  70. data/lib/core/controlplane_api.rb +170 -0
  71. data/lib/core/controlplane_api_direct.rb +112 -0
  72. data/lib/core/doctor_service.rb +104 -0
  73. data/lib/core/helpers.rb +26 -0
  74. data/lib/core/shell.rb +100 -0
  75. data/lib/core/template_parser.rb +76 -0
  76. data/lib/cpflow/version.rb +6 -0
  77. data/lib/cpflow.rb +288 -0
  78. data/lib/deprecated_commands.json +9 -0
  79. data/lib/generator_templates/Dockerfile +27 -0
  80. data/lib/generator_templates/controlplane.yml +62 -0
  81. data/lib/generator_templates/entrypoint.sh +8 -0
  82. data/lib/generator_templates/templates/app.yml +21 -0
  83. data/lib/generator_templates/templates/postgres.yml +176 -0
  84. data/lib/generator_templates/templates/rails.yml +36 -0
  85. data/rakelib/create_release.rake +81 -0
  86. data/script/add_command +37 -0
  87. data/script/check_command_docs +3 -0
  88. data/script/check_cpln_links +45 -0
  89. data/script/rename_command +43 -0
  90. data/script/update_command_docs +62 -0
  91. data/templates/app.yml +13 -0
  92. data/templates/daily-task.yml +32 -0
  93. data/templates/maintenance.yml +25 -0
  94. data/templates/memcached.yml +24 -0
  95. data/templates/postgres.yml +32 -0
  96. data/templates/rails.yml +27 -0
  97. data/templates/redis.yml +21 -0
  98. data/templates/redis2.yml +37 -0
  99. data/templates/sidekiq.yml +38 -0
  100. metadata +341 -0
data/docs/redis.md ADDED
@@ -0,0 +1,128 @@
1
+ # Migrating Redis databases
2
+
3
+ There are two templates examples in this repo:
4
+ - `redis` - basic non-persistent template. It is good for review-apps or staging or where no persistence is required
5
+ - `redis2` - basic persistent template. Good for production where persistence is needed, but cluster is overkill.
6
+
7
+ ## Option 1: use SLAVEOF (easier way)
8
+
9
+ 1. create a redis workload that will accept data
10
+ 2. execute `SLAVEOF source_host source_port`, if needed use `masterauth` to provide auth details
11
+ 3. wait for replication to pick up all changes (usually quickly), use `INFO` or `DBSIZE` to check progress
12
+ 4. stop app completely and ensure nothing is writing to any of redises
13
+ 5. execute `SLAVEOF no one` to disconnect replication
14
+ 6. switch `REDIS_URL` in the app to point to new server
15
+ 7. start the app
16
+
17
+ ## Option 2: use Redis-RIOT (harder way, where option 1 is not possible)
18
+
19
+ ### General considerations:
20
+
21
+ 1. Heroku uses self-signed TLS certificates, which are not verifiable. It needs special handling by setting
22
+ The tool that satisfies those criteria is [Redis-RIOT](https://developer.redis.com/riot/riot-redis/index.html)
23
+
24
+ 2. We are moving to private Redis that don't have a public URL, so have to do it from a Control Plane GVC container.
25
+
26
+ The tool that satisfies those criteria is [Redis-RIOT](https://developer.redis.com/riot/riot-redis/index.html)
27
+
28
+ ### Heroku Redis:
29
+
30
+ As Redis-RIOT says, master redis should have keyspace-notifications set to `KA` to be able to do live replication.
31
+ To do that:
32
+
33
+ ```sh
34
+ heroku redis:keyspace-notifications -c KA -a my-app
35
+ ```
36
+
37
+ Connect to heroku Redis CLI:
38
+ ```sh
39
+ heroku redis:cli -a my-app
40
+ ```
41
+
42
+ ### Control Plane Redis:
43
+
44
+ Connect to Control Plane Redis CLI:
45
+
46
+ ```sh
47
+ # open cpflow interactive shell
48
+ cpflow run bash -a my-app
49
+
50
+ # install redis CLI if you don't have it in Docker
51
+ apt-get update
52
+ apt-get install redis -y
53
+
54
+ # connect to local cloud Redis
55
+ redis-cli -u MY_CONTROL_PLANE_REDIS_URL -p 6379
56
+ ```
57
+
58
+ ### Useful Redis CLI commands:
59
+
60
+ Quick-check keys qty:
61
+ ```
62
+ info keyspace
63
+
64
+ # Keyspace
65
+ db0:keys=9496,expires=2941,avg_ttl=77670114535
66
+ ```
67
+
68
+ ### Create a Control Plane sync workload
69
+
70
+ ```
71
+ name: riot-redis
72
+
73
+ suspend: true
74
+ min/max scale: 1/1
75
+
76
+ firewall: all firewalls off
77
+
78
+ image: fieldengineering/riot-redis
79
+
80
+ CPU: 1 Core
81
+ RAM: 1 GB
82
+
83
+ command args:
84
+ --info
85
+ -u
86
+ rediss://...your_heroku_redis_url...
87
+ --tls-verify=NONE
88
+ replicate
89
+ -h
90
+ ...your_control_plane_redis_host...
91
+ --mode
92
+ live
93
+ ```
94
+
95
+ ### Sync process
96
+
97
+ 1. open 1st terminal window with heroku redis CLI, check keys qty
98
+ 2. open 2nd terminal window with controlplane redis CLI, check keys qty
99
+ 3. start sync container
100
+ 4. open logs with `cpflow logs -a my-app -w riot-redis`
101
+ 4. re-check keys sync qty again
102
+ 5. stop sync container
103
+
104
+ Result:
105
+ ```
106
+ Setting commit interval to default value (1)
107
+ Setting commit interval to default value (1)
108
+ Job: [SimpleJob: [name=snapshot-replication]] launched with the following parameters: [{}]
109
+ Executing step: [snapshot-replication]
110
+ Scanning 0% ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0/8891 (0:00:00 / ?)Job: [SimpleJob: [name=scan-reader]] launched with the following parameters: [{}]
111
+ Executing step: [scan-reader]
112
+ Scanning 61% ━━━━━━━━━━━━━━━━╸━━━━━━━━━━ 5460/8891 (0:00:07 / 0:00:04) 780.0/sStep: [scan-reader] executed in 7s918ms
113
+ Closing with items still in queue
114
+ Job: [SimpleJob: [name=scan-reader]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 7s925ms
115
+ Scanning 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9482/9482 (0:00:11 / 0:00:00) 862.0/s
116
+ Step: [snapshot-replication] executed in 13s333ms
117
+ Executing step: [verification]
118
+ Verifying 0% ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0/8942 (0:00:00 / ?)Job: [SimpleJob: [name=RedisItemReader]] launched with the following parameters: [{}]
119
+ Executing step: [RedisItemReader]
120
+ Verifying 2% ╺━━━━━━━━━━━━━━━━━ 220/8942 (0:00:00 / 0:00:19) ?/s >0 T0 ≠Step: [RedisItemReader] executed in 7s521ms
121
+ Closing with items still in queue
122
+ Job: [SimpleJob: [name=RedisItemReader]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 7s522ms
123
+ Verification completed - all OK
124
+ Step: [verification] executed in 7s776ms
125
+ Job: [SimpleJob: [name=snapshot-replication]] completed with the following parameters: [{}] and the following status: [COMPLETED] in 21s320ms
126
+ ```
127
+
128
+ Total sync time ~1min
@@ -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 `cpflow 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 ADDED
@@ -0,0 +1,150 @@
1
+ # Tips
2
+
3
+ 1. [GVCs vs. Orgs](#gvcs-vs-orgs)
4
+ 2. [RAM](#ram)
5
+ 3. [Remote IP](#remote-ip)
6
+ 4. [Secrets and ENV Values](/docs/secrets-and-env-values.md)
7
+ 5. [CI](#ci)
8
+ 6. [Memcached](#memcached)
9
+ 7. [Sidekiq](#sidekiq)
10
+ - [Quieting Non-Critical Workers During Deployments](#quieting-non-critical-workers-during-deployments)
11
+ - [Setting Up a Pre Stop Hook](#setting-up-a-pre-stop-hook)
12
+ - [Setting Up a Liveness Probe](#setting-up-a-liveness-probe)
13
+ 8. [Useful Links](#useful-links)
14
+
15
+ ## GVCs vs. Orgs
16
+
17
+ - A "GVC" roughly corresponds to a Heroku "app."
18
+ - Images are available at the org level.
19
+ - Multiple GVCs within an org can use the same image.
20
+ - You can have different images within a GVC and even within a workload. This flexibility is one of the key differences
21
+ compared to Heroku apps.
22
+
23
+ ## RAM
24
+
25
+ Any workload replica that reaches the max memory is terminated and restarted. You can configure alerts for workload
26
+ restarts and the percentage of memory used in the Control Plane UX.
27
+
28
+ Here are the steps for configuring an alert for the percentage of memory used:
29
+
30
+ 1. Navigate to the workload that you want to configure the alert for
31
+ 2. Click "Metrics" on the left menu to go to Grafana
32
+ 3. On Grafana, go to the alerting page by clicking on the alert icon in the sidebar
33
+ 4. Click on "New alert rule"
34
+ 5. In the "Set a query and alert condition" section, select "Grafana managed alert"
35
+ 6. There should be a default query named `A`
36
+ 7. Change the data source of the query to `metrics`
37
+ 8. Click "Code" on the top right of the query and enter `mem_used{workload="workload_name"} / mem_reserved{workload="workload_name"} * 100`
38
+ (replace `workload_name` with the name of the workload)
39
+ 9. There should be a default expression named `B`, with the type `Reduce`, the function `Last`, and the input `A` (this
40
+ ensures that we're getting the last data point of the query)
41
+ 10. There should be a default expression named `C`, with the type `Threshold`, and the input `B` (this is where you
42
+ configure the condition for firing the alert, e.g., `IS ABOVE 95`)
43
+ 11. You can then preview the alert and check if it's firing or not based on the example time range of the query
44
+ 12. In the "Alert evaluation behavior" section, you can configure how often the alert should be evaluated and for how
45
+ long the condition should be true before firing (for example, you might want the alert only to be fired if the
46
+ percentage has been above `95` for more than 20 seconds)
47
+ 13. In the "Add details for your alert" section, fill out the name, folder, group, and summary for your alert
48
+ 14. In the "Notifications" section, you can configure a label for the alert if you're using a custom notification policy,
49
+ but there should be a default root route for all alerts
50
+ 15. Once you're done, save and exit in the top right of the page
51
+ 16. Click "Contact points" on the top menu
52
+ 17. Edit the `grafana-default-email` contact point and add the email where you want to receive notifications
53
+ 18. You should now receive notifications for the alert in your email
54
+
55
+ ![](assets/grafana-alert.png)
56
+
57
+ The steps for configuring an alert for workload restarts are almost identical, but the code for the query would be
58
+ `container_restarts`.
59
+
60
+ For more information on Grafana alerts, see: https://grafana.com/docs/grafana/latest/alerting/
61
+
62
+ ## Remote IP
63
+
64
+ The actual remote IP of the workload container is in the 127.0.0.x network, so that will be the value of the
65
+ `REMOTE_ADDR` env var.
66
+
67
+ However, Control Plane additionally sets the `x-forwarded-for` and `x-envoy-external-address` headers (and others - see:
68
+ https://shakadocs.controlplane.com/concepts/security#headers). On Rails, the `ActionDispatch::RemoteIp` middleware should
69
+ pick those up and automatically populate `request.remote_ip`.
70
+
71
+ So `REMOTE_ADDR` should not be used directly, only `request.remote_ip`.
72
+
73
+ ## CI
74
+
75
+ **Note:** Docker builds much slower on Apple Silicon, so try configuring CI to build the images when using Apple
76
+ hardware.
77
+
78
+ Make sure to create a profile on CI before running any `cpln` or `cpflow` commands.
79
+
80
+ ```sh
81
+ CPLN_TOKEN=...
82
+ cpln profile create default --token ${CPLN_TOKEN}
83
+ ```
84
+
85
+ Also, log in to the Control Plane Docker repository if building and pushing an image.
86
+
87
+ ```sh
88
+ cpln image docker-login
89
+ ```
90
+
91
+ ## Memcached
92
+
93
+ On the workload container for Memcached (using the `memcached:alpine` image), configure the command with the args
94
+ `-l 0.0.0.0`.
95
+
96
+ To do this:
97
+
98
+ 1. Navigate to the workload container for Memcached
99
+ 2. Click "Command" on the top menu
100
+ 3. Add the args and save
101
+
102
+ ![](assets/memcached.png)
103
+
104
+ ## Sidekiq
105
+
106
+ ### Quieting Non-Critical Workers During Deployments
107
+
108
+ To avoid locks in migrations, we can quiet non-critical workers during deployments. Doing this early enough in the CI
109
+ allows all workers to finish jobs gracefully before deploying the new image.
110
+
111
+ There's no need to unquiet the workers, as that will happen automatically after deploying the new image.
112
+
113
+ ```sh
114
+ cpflow run 'rails runner "Sidekiq::ProcessSet.new.each { |w| w.quiet! unless w[%q(hostname)].start_with?(%q(criticalworker.)) }"' -a my-app
115
+ ```
116
+
117
+ ### Setting Up a Pre Stop Hook
118
+
119
+ By setting up a pre stop hook in the lifecycle of the workload container for Sidekiq, which sends "QUIET" to the workers,
120
+ we can ensure that all workers will finish jobs gracefully before Control Plane stops the replica. That also works
121
+ nicely for multiple replicas.
122
+
123
+ A couple of notes:
124
+
125
+ - We can't use the process name as regex because it's Ruby, not Sidekiq.
126
+ - We need to add a space after `sidekiq`; otherwise, it sends `TSTP` to the `sidekiqswarm` process as well, and for some
127
+ reason, that doesn't work.
128
+
129
+ So with `^` and `\s`, we guarantee it's sent only to worker processes.
130
+
131
+ ```sh
132
+ pkill -TSTP -f ^sidekiq\s
133
+ ```
134
+
135
+ To do this:
136
+
137
+ 1. Navigate to the workload container for Sidekiq
138
+ 2. Click "Lifecycle" on the top menu
139
+ 3. Add the command and args below "Pre Stop Hook" and save
140
+
141
+ ![](assets/sidekiq-pre-stop-hook.png)
142
+
143
+ ### Setting Up a Liveness Probe
144
+
145
+ To set up a liveness probe on port 7433, see: https://github.com/arturictus/sidekiq_alive
146
+
147
+ ## Useful Links
148
+
149
+ - For best practices for the app's Dockerfile, see: https://lipanski.com/posts/dockerfile-ruby-best-practices
150
+ - For migrating from Heroku Postgres to RDS, see: https://pelle.io/posts/hetzner-rds-postgres
@@ -0,0 +1,6 @@
1
+ # Troubleshooting
2
+
3
+
4
+ ## App Web Page Shows `upstream request timeout`
5
+
6
+ If you get a blank screen showing the message `upstream request timeout` on your app after running `cpflow open -a my-app-name`, check out the application logs. Your image has been promoted and your app crashing when starting.
@@ -0,0 +1,104 @@
1
+ # Example config for staging app:
2
+ # - triggers on push to master
3
+ # - static app name
4
+ # - no resource provisioning
5
+ # - no database setup, only migration
6
+ build-staging:
7
+ docker:
8
+ - image: cimg/ruby:3.1-node
9
+ resource_class: large
10
+ environment:
11
+ CPLN_ORG: my-org
12
+ APP_NAME: my-app-staging
13
+ steps:
14
+ - checkout
15
+ - setup_remote_docker:
16
+ docker_layer_caching: true
17
+ - run:
18
+ name: Install Control Plane tools
19
+ command: |
20
+ sudo npm install -g @controlplane/cli && cpln --version
21
+ cpln profile create default --token ${CPLN_TOKEN} --org ${CPLN_ORG} --gvc ${APP_NAME}
22
+ cpln image docker-login
23
+
24
+ gem install cpflow
25
+ - run:
26
+ name: Containerize and push image
27
+ command: cpflow build-image -a ${APP_NAME}
28
+ - run:
29
+ name: Database tasks
30
+ command: cpflow run -a ${APP_NAME} --image latest -- rails db:migrate
31
+ - run:
32
+ name: Deploy image
33
+ command: cpflow deploy-image -a ${APP_NAME}
34
+
35
+ # Example config for review app:
36
+ # - triggers manually if needed
37
+ # - dynamic app name based on PR number
38
+ # - resources provisioning for new apps
39
+ # - initial database setup or migration
40
+ build-review-app:
41
+ docker:
42
+ - image: cimg/ruby:3.1-node
43
+ resource_class: large
44
+ environment:
45
+ CPLN_ORG: my-org
46
+ steps:
47
+ - checkout
48
+ - setup_remote_docker:
49
+ docker_layer_caching: true
50
+ - run:
51
+ name: Setup environment
52
+ command: |
53
+ PR_NUM=$(echo $CIRCLE_PULL_REQUEST | grep -Eo '[0-9]+$')
54
+ echo "export APP_NAME=hichee-review-$PR_NUM" >> $BASH_ENV
55
+ - run:
56
+ name: Install Control Plane tools
57
+ command: |
58
+ sudo npm install -g @controlplane/cli && cpln --version
59
+ cpln profile create default --token ${CPLN_TOKEN} --org ${CPLN_ORG} --gvc ${APP_NAME}
60
+ cpln image docker-login
61
+
62
+ gem install cpflow
63
+ - run:
64
+ name: Provision review app if needed
65
+ command: |
66
+ if ! cpflow exists -a ${APP_NAME}; then
67
+ cpflow setup-app -a ${APP_NAME}
68
+ echo "export NEW_APP=true" >> $BASH_ENV
69
+ fi
70
+ - run:
71
+ name: Containerize and push image
72
+ command: |
73
+ cpflow build-image -a ${APP_NAME} --commit ${CIRCLE_SHA1::7}
74
+ - run:
75
+ name: Database tasks
76
+ command: |
77
+ if [ -n "${NEW_APP}" ]; then
78
+ cpflow run -a ${APP_NAME} --image latest -- rails db:reset
79
+ else
80
+ cpflow run -a ${APP_NAME} --image latest -- rails db:migrate
81
+ fi
82
+ - run:
83
+ name: Deploy image
84
+ command: cpflow deploy-image -a ${APP_NAME}
85
+
86
+ review-app:
87
+ jobs:
88
+ - start:
89
+ filters:
90
+ branches:
91
+ ignore: master
92
+ type: approval
93
+ - build-review-app:
94
+ filters:
95
+ branches:
96
+ ignore: master
97
+ requires:
98
+ - start
99
+ staging:
100
+ jobs:
101
+ - build-staging:
102
+ filters:
103
+ branches:
104
+ only: master
@@ -0,0 +1,159 @@
1
+ # Keys beginning with "cpln_" correspond to your settings in Control Plane.
2
+
3
+ # Global settings that apply to `cpflow` usage.
4
+ # You can opt out of allowing the use of CPLN_ORG and CPLN_APP env vars
5
+ # to avoid any accidents with the wrong org / app.
6
+ allow_org_override_by_env: true
7
+ allow_app_override_by_env: true
8
+
9
+ aliases:
10
+ common: &common
11
+ # Organization for staging and QA apps is typically set as an alias.
12
+ # Production apps will use a different organization, specified in `apps`, for security.
13
+ # Change this value to your organization name
14
+ # or set the CPLN_ORG env var and it will override this for all `cpflow` commands
15
+ # (provided that `allow_org_override_by_env` is set to `true`).
16
+ cpln_org: my-org-staging
17
+
18
+ # Control Plane offers the ability to use multiple locations.
19
+ # default_location is used for commands that require a location
20
+ # including `ps`, `run`, `apply-template`.
21
+ # This can be overridden with option --location=<location> and
22
+ # CPLN_LOCATION environment variable.
23
+ # TODO: Allow specification of multiple locations.
24
+ default_location: aws-us-east-2
25
+
26
+ # Allows running the command `cpflow setup-app`
27
+ # instead of `cpflow apply-template app redis postgres memcached rails sidekiq`.
28
+ #
29
+ # Note:
30
+ # 1. These names correspond to files in the `./controlplane/templates` directory.
31
+ # 2. Each file can contain many objects, such as in the case of templates that create a resource, like `postgres`.
32
+ # 3. While the naming often corresponds to a workload or other object name, the naming is arbitrary.
33
+ # Naming does not need to match anything other than the file name without the `.yml` extension.
34
+ setup_app_templates:
35
+ - app
36
+ - redis
37
+ - postgres
38
+ - memcached
39
+ - rails
40
+ - sidekiq
41
+
42
+ # Uncomment next line to skips secrets setup when running `cpflow setup-app`.
43
+ # skip_secrets_setup: true
44
+
45
+ # Only needed if using a custom secrets name.
46
+ # The default is '{APP_PREFIX}-secrets'. For example:
47
+ # - for an app 'my-app-staging' with `match_if_app_name_starts_with` set to `false`,
48
+ # it would be 'my-app-staging-secrets'
49
+ # - for an app 'my-app-review-1234' with `match_if_app_name_starts_with` set to `true`,
50
+ # it would be 'my-app-review-secrets'
51
+ secrets_name: my-secrets
52
+
53
+ # Only needed if using a custom secrets policy name.
54
+ # The default is '{APP_SECRETS}-policy'. For example:
55
+ # - for an app 'my-app-staging' with `match_if_app_name_starts_with` set to `false`,
56
+ # it would be 'my-app-staging-secrets-policy'
57
+ # - for an app 'my-app-review-1234' with `match_if_app_name_starts_with` set to `true`,
58
+ # it would be 'my-app-review-secrets-policy'
59
+ secrets_policy_name: my-secrets-policy
60
+
61
+ # Configure the workload name used as a template for one-off scripts, like a Heroku one-off dyno.
62
+ one_off_workload: rails
63
+
64
+ # Workloads that are for the application itself and are using application Docker images.
65
+ # These are updated with the new image when running the `deploy-image` command,
66
+ # and are also used by the `info` and `ps:` commands in order to get all of the defined workloads.
67
+ # On the other hand, if you have a workload for Redis, that would NOT use the application Docker image
68
+ # and not be listed here.
69
+ app_workloads:
70
+ - rails
71
+ - sidekiq
72
+
73
+ # Additional "service type" workloads, using non-application Docker images.
74
+ # These are only used by the `info` and `ps:` commands in order to get all of the defined workloads.
75
+ additional_workloads:
76
+ - redis
77
+ - postgres
78
+ - memcached
79
+
80
+ # Configure the workload name used when maintenance mode is on (defaults to "maintenance").
81
+ maintenance_workload: maintenance
82
+
83
+ # Fixes the remote terminal size to match the local terminal size
84
+ # when running `cpflow run`.
85
+ fix_terminal_size: true
86
+
87
+ # Sets a default CPU size for `cpflow run` jobs (can be overridden per job through `--cpu`).
88
+ # If not specified, defaults to "1" (1 core).
89
+ runner_job_default_cpu: "2"
90
+
91
+ # Sets a default memory size for `cpflow run` jobs (can be overridden per job through `--memory`).
92
+ # If not specified, defaults to "2Gi" (2 gibibytes).
93
+ runner_job_default_memory: "4Gi"
94
+
95
+ # Sets the maximum number of seconds that `cpflow run` jobs can execute before being stopped.
96
+ # If not specified, defaults to 21600 (6 hours).
97
+ runner_job_timeout: 1000
98
+
99
+ # Apps with a deployed image created before this amount of days will be listed for deletion
100
+ # when running the command `cpflow cleanup-stale-apps`.
101
+ stale_app_image_deployed_days: 5
102
+
103
+ # Images that exceed this quantity will be listed for deletion
104
+ # when running the command `cpflow cleanup-images`.
105
+ image_retention_max_qty: 20
106
+
107
+ # Images created before this amount of days will be listed for deletion
108
+ # when running the command `cpflow cleanup-images` (`image_retention_max_qty` takes precedence).
109
+ image_retention_days: 5
110
+
111
+ apps:
112
+ my-app-staging:
113
+ # Use the values from the common section above.
114
+ <<: *common
115
+
116
+ my-app-review:
117
+ <<: *common
118
+
119
+ # If `match_if_app_name_starts_with` is `true`, then use this config for app names starting with this name,
120
+ # e.g., "my-app-review-pr123", "my-app-review-anything-goes", etc.
121
+ match_if_app_name_starts_with: true
122
+
123
+ # Hooks can be either a script path that exists in the app image or a command.
124
+ # They're run in the context of `cpflow run` with the latest image.
125
+ hooks:
126
+ # Used by the command `cpflow setup-app` to run a hook after creating the app.
127
+ post_creation: bundle exec rake db:prepare
128
+
129
+ # Used by the command `cpflow delete` to run a hook before deleting the app.
130
+ pre_deletion: bundle exec rake db:drop
131
+
132
+ my-app-production:
133
+ <<: *common
134
+
135
+ # You can also opt out of allowing the use of CPLN_ORG and CPLN_APP env vars per app.
136
+ # It's recommended to leave this off for production, to avoid any accidents.
137
+ allow_org_override_by_env: false
138
+ allow_app_override_by_env: false
139
+
140
+ # Use a different organization for production.
141
+ cpln_org: my-org-production
142
+
143
+ # Allows running the command `cpflow promote-app-from-upstream -a my-app-production`
144
+ # to promote the staging app to production.
145
+ upstream: my-app-staging
146
+
147
+ # Used by the command `cpflow promote-app-from-upstream` to run a release script before deploying.
148
+ # This is relative to the `.controlplane/` directory.
149
+ release_script: release_script
150
+
151
+ # default_domain is used for commands that require a domain
152
+ # including `maintenance`, `maintenance:on`, `maintenance:off`.
153
+ default_domain: domain.com
154
+
155
+ my-app-other:
156
+ <<: *common
157
+
158
+ # You can specify a different `Dockerfile` relative to the `.controlplane/` directory (defaults to "Dockerfile").
159
+ dockerfile: ../some_other/Dockerfile