cpflow 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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