cpflow 4.1.0 → 4.2.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.
- checksums.yaml +4 -4
- data/.github/workflows/claude-code-review.yml +44 -0
- data/.github/workflows/claude.yml +50 -0
- data/.gitignore +6 -0
- data/CHANGELOG.md +17 -1
- data/Gemfile.lock +2 -2
- data/README.md +17 -14
- data/docs/ci-automation.md +28 -0
- data/docs/commands.md +21 -1
- data/docs/terraform/details.md +415 -0
- data/docs/terraform/example/.controlplane/controlplane.yml +29 -0
- data/docs/terraform/example/.controlplane/templates/app.yml +38 -0
- data/docs/terraform/example/.controlplane/templates/postgres.yml +30 -0
- data/docs/terraform/example/.controlplane/templates/rails.yml +26 -0
- data/docs/terraform/overview.md +105 -0
- data/lib/command/base.rb +29 -5
- data/lib/command/base_sub_command.rb +15 -0
- data/lib/command/generate.rb +1 -1
- data/lib/command/ps.rb +1 -1
- data/lib/command/ps_stop.rb +2 -1
- data/lib/command/ps_wait.rb +5 -1
- data/lib/command/run.rb +4 -21
- data/lib/command/terraform/base.rb +35 -0
- data/lib/command/terraform/generate.rb +99 -0
- data/lib/command/terraform/import.rb +79 -0
- data/lib/core/config.rb +1 -1
- data/lib/core/controlplane.rb +7 -6
- data/lib/core/controlplane_api_direct.rb +23 -1
- data/lib/core/shell.rb +9 -4
- data/lib/core/terraform_config/agent.rb +31 -0
- data/lib/core/terraform_config/audit_context.rb +31 -0
- data/lib/core/terraform_config/base.rb +25 -0
- data/lib/core/terraform_config/dsl.rb +102 -0
- data/lib/core/terraform_config/generator.rb +184 -0
- data/lib/core/terraform_config/gvc.rb +63 -0
- data/lib/core/terraform_config/identity.rb +35 -0
- data/lib/core/terraform_config/local_variable.rb +30 -0
- data/lib/core/terraform_config/policy.rb +151 -0
- data/lib/core/terraform_config/provider.rb +22 -0
- data/lib/core/terraform_config/required_provider.rb +23 -0
- data/lib/core/terraform_config/secret.rb +138 -0
- data/lib/core/terraform_config/volume_set.rb +155 -0
- data/lib/core/terraform_config/workload/main.tf +316 -0
- data/lib/core/terraform_config/workload/required_providers.tf +8 -0
- data/lib/core/terraform_config/workload/variables.tf +263 -0
- data/lib/core/terraform_config/workload.rb +132 -0
- data/lib/cpflow/version.rb +1 -1
- data/lib/cpflow.rb +51 -9
- data/lib/generator_templates/templates/postgres.yml +1 -1
- data/lib/patches/array.rb +8 -0
- data/lib/patches/hash.rb +47 -0
- data/lib/patches/string.rb +34 -0
- data/script/update_command_docs +6 -2
- metadata +37 -4
- /data/docs/{migrating.md → migrating-heroku-to-control-plane.md} +0 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
### Terraform Configurations from CPLN Templates
|
|
2
|
+
|
|
3
|
+
#### Providers
|
|
4
|
+
|
|
5
|
+
Terraform provider configurations are controlled via `required_providers.tf` and `providers.tf`:
|
|
6
|
+
|
|
7
|
+
- **`required_providers.tf`**
|
|
8
|
+
|
|
9
|
+
```hcl
|
|
10
|
+
terraform {
|
|
11
|
+
required_providers {
|
|
12
|
+
cpln = {
|
|
13
|
+
source = "controlplane-com/cpln"
|
|
14
|
+
version = "~> 1.0"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- **`providers.tf`**
|
|
21
|
+
|
|
22
|
+
```hcl
|
|
23
|
+
provider "cpln" {
|
|
24
|
+
org = "org-name-example"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
#### GVC (Global Virtual Cloud)
|
|
29
|
+
|
|
30
|
+
CPLN template in YAML format:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
kind: gvc
|
|
34
|
+
name: app-name
|
|
35
|
+
description: app-description
|
|
36
|
+
tags:
|
|
37
|
+
tag-name-1: "tag-value-1"
|
|
38
|
+
tag-name-2: "tag-value-2"
|
|
39
|
+
spec:
|
|
40
|
+
domain: "app.example.com"
|
|
41
|
+
env:
|
|
42
|
+
- name: DATABASE_URL
|
|
43
|
+
value: "postgres://the_user:the_password@postgres.app-name.cpln.local:5432/app-name"
|
|
44
|
+
- name: RAILS_ENV
|
|
45
|
+
value: production
|
|
46
|
+
- name: RAILS_SERVE_STATIC_FILES
|
|
47
|
+
value: "true"
|
|
48
|
+
staticPlacement:
|
|
49
|
+
locationLinks:
|
|
50
|
+
- "//location/aws-us-west-2"
|
|
51
|
+
pullSecretLinks:
|
|
52
|
+
- "/org/org-name/secret/some-secret"
|
|
53
|
+
loadBalancer:
|
|
54
|
+
dedicated: true
|
|
55
|
+
trustedProxies: 0
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Will transform to Terraform config:
|
|
59
|
+
|
|
60
|
+
```hcl
|
|
61
|
+
resource "cpln_gvc" "app-name" {
|
|
62
|
+
name = "app-name"
|
|
63
|
+
description = "app-description"
|
|
64
|
+
tags = {
|
|
65
|
+
tag_name_1 = "tag-value-1"
|
|
66
|
+
tag_name_2 = "tag-value-2"
|
|
67
|
+
}
|
|
68
|
+
domain = "app.example.com"
|
|
69
|
+
locations = ["aws-us-west-2"]
|
|
70
|
+
pull_secrets = ["cpln_secret.some-secret.name"]
|
|
71
|
+
env = {
|
|
72
|
+
DATABASE_URL = "postgres://the_user:the_password@postgres.app-name.cpln.local:5432/app-name"
|
|
73
|
+
RAILS_ENV = "production"
|
|
74
|
+
RAILS_SERVE_STATIC_FILES = "true"
|
|
75
|
+
}
|
|
76
|
+
load_balancer {
|
|
77
|
+
dedicated = true
|
|
78
|
+
trusted_proxies = 0
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### Identity
|
|
84
|
+
|
|
85
|
+
CPLN template in YAML format:
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
kind: identity
|
|
89
|
+
name: postgres-poc-identity
|
|
90
|
+
description: postgres-poc-identity
|
|
91
|
+
tags:
|
|
92
|
+
tag-name-1: "tag-value-1"
|
|
93
|
+
tag-name-2: "tag-value-2"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Will transform to Terraform config:
|
|
97
|
+
|
|
98
|
+
```hcl
|
|
99
|
+
resource "cpln_identity" "postgres-poc-identity" {
|
|
100
|
+
name = "postgres-poc-identity"
|
|
101
|
+
description = "postgres-poc-identity"
|
|
102
|
+
tags = {
|
|
103
|
+
tag_name_1 = "tag-value-1"
|
|
104
|
+
tag_name_2 = "tag-value-2"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Secret
|
|
110
|
+
|
|
111
|
+
CPLN template in YAML format
|
|
112
|
+
|
|
113
|
+
**For `aws` secret:**
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
kind: secret
|
|
117
|
+
name: aws
|
|
118
|
+
description: aws
|
|
119
|
+
type: aws
|
|
120
|
+
data:
|
|
121
|
+
accessKey: 'AccessKeyExample'
|
|
122
|
+
externalId: 'ExternalIdExample'
|
|
123
|
+
roleArn: arn:awskey
|
|
124
|
+
secretKey: 'SecretKeyExample'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Will transform to Terraform config:
|
|
128
|
+
|
|
129
|
+
```hcl
|
|
130
|
+
resource "cpln_secret" "aws" {
|
|
131
|
+
name = "aws"
|
|
132
|
+
description = "aws"
|
|
133
|
+
aws {
|
|
134
|
+
secret_key = "SecretKeyExample"
|
|
135
|
+
access_key = "AccessKeyExample"
|
|
136
|
+
role_arn = "arn:awskey"
|
|
137
|
+
external_id = "ExternalIdExample"
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**For `azure-connector` secret:**
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
kind: secret
|
|
146
|
+
name: azure-connector
|
|
147
|
+
description: azure_connector
|
|
148
|
+
tags:
|
|
149
|
+
tag1: tag-val
|
|
150
|
+
type: azure-connector
|
|
151
|
+
data:
|
|
152
|
+
code: 'CodeExample'
|
|
153
|
+
url: https://example.com
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Will transform to Terraform config:
|
|
157
|
+
|
|
158
|
+
```hcl
|
|
159
|
+
resource "cpln_secret" "azure-connector" {
|
|
160
|
+
name = "azure-connector"
|
|
161
|
+
description = "azure_connector"
|
|
162
|
+
tags = {
|
|
163
|
+
tag1 = "tag-val"
|
|
164
|
+
}
|
|
165
|
+
azure_connector {
|
|
166
|
+
url = "https://example.com"
|
|
167
|
+
code = "CodeExample"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**For `azure-sdk-secret` secret:**
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
kind: secret
|
|
176
|
+
name: azure-sdk-secret
|
|
177
|
+
description: azure-sdk-secret
|
|
178
|
+
type: azure-sdk
|
|
179
|
+
data: >-
|
|
180
|
+
{"subscriptionId":"subscriptionId","tenantId":"tenantId","clientId":"clientId","clientSecret":"CONFIDENTIAL"}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Will transform to Terraform config:
|
|
184
|
+
|
|
185
|
+
```hcl
|
|
186
|
+
resource "cpln_secret" "azure-sdk-secret" {
|
|
187
|
+
name = "azure-sdk-secret"
|
|
188
|
+
description = "azure-sdk-secret"
|
|
189
|
+
azure_sdk = "{"subscriptionId":"subscriptionId","tenantId":"tenantId","clientId":"clientID","clientSecret":"CONFIDENTIAL"}"
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**For `dictionary` secret:**
|
|
194
|
+
|
|
195
|
+
```yaml
|
|
196
|
+
kind: secret
|
|
197
|
+
name: dictionary
|
|
198
|
+
description: dictionary
|
|
199
|
+
tags: {}
|
|
200
|
+
type: dictionary
|
|
201
|
+
data:
|
|
202
|
+
example: 'value'
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Will transform to Terraform config:
|
|
206
|
+
|
|
207
|
+
```hcl
|
|
208
|
+
resource "cpln_secret" "dictionary" {
|
|
209
|
+
name = "dictionary"
|
|
210
|
+
description = "dictionary"
|
|
211
|
+
tags = {
|
|
212
|
+
}
|
|
213
|
+
dictionary = {
|
|
214
|
+
example = "value"
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Supported all types of the secrets which can be configured in Control Plane.
|
|
220
|
+
|
|
221
|
+
#### Policy
|
|
222
|
+
|
|
223
|
+
CPLN template in YAML format:
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
kind: policy
|
|
227
|
+
name: policy-name
|
|
228
|
+
description: policy description
|
|
229
|
+
tags:
|
|
230
|
+
tag1: tag1_value
|
|
231
|
+
tag2: tag2_value
|
|
232
|
+
target: all
|
|
233
|
+
targetKind: secret
|
|
234
|
+
targetLinks:
|
|
235
|
+
- "//secret/postgres-poc-credentials"
|
|
236
|
+
- "//secret/postgres-poc-entrypoint-script"
|
|
237
|
+
bindings:
|
|
238
|
+
- permissions:
|
|
239
|
+
- reveal
|
|
240
|
+
- view
|
|
241
|
+
- use
|
|
242
|
+
principalLinks:
|
|
243
|
+
- "//gvc/{{APP_NAME}}/identity/postgres-poc-identity"
|
|
244
|
+
- permissions:
|
|
245
|
+
- view
|
|
246
|
+
principalLinks:
|
|
247
|
+
- user/fake-user@fake-email.com
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Will be transformed to Terraform config:
|
|
251
|
+
|
|
252
|
+
```hcl
|
|
253
|
+
resource "cpln_policy" "policy-name" {
|
|
254
|
+
name = "policy-name"
|
|
255
|
+
description = "policy description"
|
|
256
|
+
tags = {
|
|
257
|
+
tag1 = "tag1_value"
|
|
258
|
+
tag2 = "tag2_value"
|
|
259
|
+
}
|
|
260
|
+
target_kind = "secret"
|
|
261
|
+
gvc = cpln_gvc.app-name.name
|
|
262
|
+
target = "all"
|
|
263
|
+
target_links = ["postgres-poc-credentials", "postgres-poc-entrypoint-script"]
|
|
264
|
+
binding {
|
|
265
|
+
permissions = ["reveal", "view", "use"]
|
|
266
|
+
principal_links = ["gvc/app-name/identity/postgres-poc-identity"]
|
|
267
|
+
}
|
|
268
|
+
binding {
|
|
269
|
+
permissions = ["view"]
|
|
270
|
+
principal_links = ["user/fake-user@fake-email.com"]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### Volumeset
|
|
276
|
+
|
|
277
|
+
CPLN template in YAML format:
|
|
278
|
+
|
|
279
|
+
```yaml
|
|
280
|
+
kind: volumeset
|
|
281
|
+
name: postgres-poc-vs
|
|
282
|
+
description: postgres-poc-vs
|
|
283
|
+
spec:
|
|
284
|
+
autoscaling:
|
|
285
|
+
maxCapacity: 1000
|
|
286
|
+
minFreePercentage: 1
|
|
287
|
+
scalingFactor: 1.1
|
|
288
|
+
fileSystemType: ext4
|
|
289
|
+
initialCapacity: 10
|
|
290
|
+
performanceClass: general-purpose-ssd
|
|
291
|
+
snapshots:
|
|
292
|
+
createFinalSnapshot: true
|
|
293
|
+
retentionDuration: 7d
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Will be transformed to Terraform config:
|
|
297
|
+
|
|
298
|
+
```hcl
|
|
299
|
+
resource "cpln_volume_set" "postgres-poc-vs" {
|
|
300
|
+
gvc = cpln_gvc.app-name.name
|
|
301
|
+
name = "postgres-poc-vs"
|
|
302
|
+
description = "postgres-poc-vs"
|
|
303
|
+
initial_capacity = 10
|
|
304
|
+
performance_class = "general-purpose-ssd"
|
|
305
|
+
file_system_type = "ext4"
|
|
306
|
+
snapshots {
|
|
307
|
+
create_final_snapshot = true
|
|
308
|
+
retention_duration = "7d"
|
|
309
|
+
}
|
|
310
|
+
autoscaling {
|
|
311
|
+
max_capacity = 1000
|
|
312
|
+
min_free_percentage = 1
|
|
313
|
+
scaling_factor = 1.1
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### Workload
|
|
319
|
+
|
|
320
|
+
CPLN template in YAML format:
|
|
321
|
+
|
|
322
|
+
```yaml
|
|
323
|
+
kind: workload
|
|
324
|
+
name: rails
|
|
325
|
+
spec:
|
|
326
|
+
type: standard
|
|
327
|
+
containers:
|
|
328
|
+
- name: rails
|
|
329
|
+
cpu: 300m
|
|
330
|
+
env:
|
|
331
|
+
- name: LOG_LEVEL
|
|
332
|
+
value: debug
|
|
333
|
+
inheritEnv: true
|
|
334
|
+
image: {{APP_IMAGE_LINK}}
|
|
335
|
+
memory: 512Mi
|
|
336
|
+
ports:
|
|
337
|
+
- number: 3000
|
|
338
|
+
protocol: http
|
|
339
|
+
defaultOptions:
|
|
340
|
+
autoscaling:
|
|
341
|
+
maxScale: 1
|
|
342
|
+
capacityAI: false
|
|
343
|
+
firewallConfig:
|
|
344
|
+
external:
|
|
345
|
+
inboundAllowCIDR:
|
|
346
|
+
- 0.0.0.0/0
|
|
347
|
+
outboundAllowCIDR:
|
|
348
|
+
- 0.0.0.0/0
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Will be transformed to Terraform configs:
|
|
352
|
+
|
|
353
|
+
- **`rails.tf`**
|
|
354
|
+
|
|
355
|
+
```hcl
|
|
356
|
+
module "rails" {
|
|
357
|
+
source = "../workload"
|
|
358
|
+
type = "standard"
|
|
359
|
+
name = "rails"
|
|
360
|
+
gvc = cpln_gvc.my-app-production.name
|
|
361
|
+
containers = {
|
|
362
|
+
rails: {
|
|
363
|
+
image: "/org/shakacode-demo/image/my-app-production:rails",
|
|
364
|
+
cpu: "300m",
|
|
365
|
+
memory: "512Mi",
|
|
366
|
+
inherit_env: true,
|
|
367
|
+
envs: local.rails_envs,
|
|
368
|
+
ports: [
|
|
369
|
+
{
|
|
370
|
+
number: 3000,
|
|
371
|
+
protocol: "http"
|
|
372
|
+
}
|
|
373
|
+
]
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
options = {
|
|
377
|
+
autoscaling: {
|
|
378
|
+
max_scale: 1
|
|
379
|
+
}
|
|
380
|
+
capacity_ai: false
|
|
381
|
+
}
|
|
382
|
+
firewall_spec = {
|
|
383
|
+
external: {
|
|
384
|
+
inbound_allow_cidr: [
|
|
385
|
+
"0.0.0.0/0"
|
|
386
|
+
],
|
|
387
|
+
outbound_allow_cidr: [
|
|
388
|
+
"0.0.0.0/0"
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Notice the `source: ../workload` line - there is a common `workload` module which is used for generating Terraform configs from workload templates:
|
|
396
|
+
```
|
|
397
|
+
workload/
|
|
398
|
+
├── main.tf -- Configurable workload resource in HCL
|
|
399
|
+
├── required_providers.tf -- Required providers for Terraform in HCL
|
|
400
|
+
├── variables.tf -- Variables used to configure workload resource above
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
- **`rails_envs.tf`**
|
|
404
|
+
|
|
405
|
+
```hcl
|
|
406
|
+
locals {
|
|
407
|
+
rails_envs = {
|
|
408
|
+
LOG_LEVEL = "debug"
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### References
|
|
414
|
+
|
|
415
|
+
- [Control Plane Terraform Provider](https://registry.terraform.io/providers/controlplane-com/cpln/latest/docs)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
allow_org_override_by_env: true
|
|
2
|
+
allow_app_override_by_env: true
|
|
3
|
+
|
|
4
|
+
aliases:
|
|
5
|
+
common: &common
|
|
6
|
+
cpln_org: my-org-staging
|
|
7
|
+
default_location: aws-us-east-2
|
|
8
|
+
setup_app_templates:
|
|
9
|
+
- app
|
|
10
|
+
- postgres
|
|
11
|
+
- rails
|
|
12
|
+
one_off_workload: rails
|
|
13
|
+
app_workloads:
|
|
14
|
+
- rails
|
|
15
|
+
additional_workloads:
|
|
16
|
+
- postgres
|
|
17
|
+
apps:
|
|
18
|
+
rails-app-staging:
|
|
19
|
+
<<: *common
|
|
20
|
+
hooks:
|
|
21
|
+
post_creation: bundle exec rake db:prepare
|
|
22
|
+
pre_deletion: bundle exec rake db:drop
|
|
23
|
+
|
|
24
|
+
rails-app-production:
|
|
25
|
+
<<: *common
|
|
26
|
+
allow_org_override_by_env: false
|
|
27
|
+
allow_app_override_by_env: false
|
|
28
|
+
cpln_org: my-org-production
|
|
29
|
+
upstream: rails-app-staging
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
kind: gvc
|
|
2
|
+
name: {{APP_NAME}}
|
|
3
|
+
description: Global Virtual Cloud for Rails Application
|
|
4
|
+
spec:
|
|
5
|
+
env:
|
|
6
|
+
- name: DATABASE_URL
|
|
7
|
+
value: "postgres://user:password@postgres.{{APP_NAME}}.cpln.local:5432/{{APP_NAME}}"
|
|
8
|
+
- name: RAILS_ENV
|
|
9
|
+
value: production
|
|
10
|
+
- name: RAILS_SERVE_STATIC_FILES
|
|
11
|
+
value: "true"
|
|
12
|
+
staticPlacement:
|
|
13
|
+
locationLinks:
|
|
14
|
+
- {{APP_LOCATION_LINK}}
|
|
15
|
+
pullSecretLinks:
|
|
16
|
+
- "/org/org-name/secret/rails-app-secret"
|
|
17
|
+
loadBalancer:
|
|
18
|
+
dedicated: true
|
|
19
|
+
trustedProxies: 0
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
kind: identity
|
|
24
|
+
name: rails-app-identity
|
|
25
|
+
description: Identity for Rails Application
|
|
26
|
+
tags:
|
|
27
|
+
environment: production
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
kind: secret
|
|
32
|
+
name: rails-app-secret
|
|
33
|
+
description: Secret for Rails Application
|
|
34
|
+
type: aws
|
|
35
|
+
data:
|
|
36
|
+
accessKey: 'AccessKeyExample'
|
|
37
|
+
secretKey: 'SecretKeyExample'
|
|
38
|
+
region: 'us-west-2'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
kind: workload
|
|
2
|
+
name: postgres
|
|
3
|
+
spec:
|
|
4
|
+
type: standard
|
|
5
|
+
containers:
|
|
6
|
+
- name: postgres
|
|
7
|
+
cpu: 500m
|
|
8
|
+
env:
|
|
9
|
+
- name: POSTGRES_USER
|
|
10
|
+
value: "user"
|
|
11
|
+
- name: POSTGRES_PASSWORD
|
|
12
|
+
value: "password"
|
|
13
|
+
- name: POSTGRES_DB
|
|
14
|
+
value: "rails_app"
|
|
15
|
+
inheritEnv: true
|
|
16
|
+
image: "postgres:latest"
|
|
17
|
+
memory: 1Gi
|
|
18
|
+
ports:
|
|
19
|
+
- number: 5432
|
|
20
|
+
protocol: tcp
|
|
21
|
+
defaultOptions:
|
|
22
|
+
autoscaling:
|
|
23
|
+
maxScale: 1
|
|
24
|
+
capacityAI: false
|
|
25
|
+
firewallConfig:
|
|
26
|
+
external:
|
|
27
|
+
inboundAllowCIDR:
|
|
28
|
+
- 0.0.0.0/0
|
|
29
|
+
outboundAllowCIDR:
|
|
30
|
+
- 0.0.0.0/0
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
kind: workload
|
|
2
|
+
name: rails
|
|
3
|
+
spec:
|
|
4
|
+
type: standard
|
|
5
|
+
containers:
|
|
6
|
+
- name: rails
|
|
7
|
+
cpu: 300m
|
|
8
|
+
env:
|
|
9
|
+
- name: LOG_LEVEL
|
|
10
|
+
value: debug
|
|
11
|
+
inheritEnv: true
|
|
12
|
+
image: {{APP_IMAGE_LINK}}
|
|
13
|
+
memory: 512Mi
|
|
14
|
+
ports:
|
|
15
|
+
- number: 3000
|
|
16
|
+
protocol: http
|
|
17
|
+
defaultOptions:
|
|
18
|
+
autoscaling:
|
|
19
|
+
maxScale: 1
|
|
20
|
+
capacityAI: false
|
|
21
|
+
firewallConfig:
|
|
22
|
+
external:
|
|
23
|
+
inboundAllowCIDR:
|
|
24
|
+
- 0.0.0.0/0
|
|
25
|
+
outboundAllowCIDR:
|
|
26
|
+
- 0.0.0.0/0
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Terraform
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Terraform feature in this project allows you to manage your Control Plane (CPLN) configurations using Terraform by:
|
|
6
|
+
1. Generating Terraform configuration files from existing CPLN YAML configuration files
|
|
7
|
+
2. Easily importing existing infrastructure into Terraform management
|
|
8
|
+
|
|
9
|
+
You can continue working with CPLN configuration files in YAML format and start using Terraform at any time.
|
|
10
|
+
|
|
11
|
+
## Benefits of Using Terraform Over YAML Configs
|
|
12
|
+
|
|
13
|
+
1. **State Management**: Terraform maintains a state file that tracks the current state of your infrastructure, making it easier to manage changes and updates.
|
|
14
|
+
2. **Dependency Management**: Terraform automatically handles dependencies between resources, ensuring that they are created or destroyed in the correct order.
|
|
15
|
+
3. **Multi-Cloud Support**: With Terraform, you can manage resources across multiple cloud providers seamlessly, allowing for a more flexible architecture.
|
|
16
|
+
4. **Plan and Apply**: Terraform provides a clear plan of what changes will be made before applying them, reducing the risk of unintended modifications.
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
Let's take a look at how to deploy a [simple Rails application](https://github.com/shakacode/control-plane-flow/tree/main/docs/terraform/example/.controlplane/controlplane.yml) on CPLN using Terraform:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
.controlplane/
|
|
24
|
+
├── templates/
|
|
25
|
+
│ ├── app.yml -- GVC config
|
|
26
|
+
│ ├── postgres.yml -- Workload config for PostgreSQL
|
|
27
|
+
│ └── rails.yml -- Workload config for Rails
|
|
28
|
+
└── controlplane.yml -- Configs for overall application
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Generating Terraform configurations
|
|
32
|
+
|
|
33
|
+
To generate Terraform configurations, run the following command from the project root:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
cpflow terraform generate
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Invoking this command will generate a new `terraform` folder with subfolders containing Terraform configurations for each application described in `controlplane.yml`:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
terraform/
|
|
43
|
+
├── rails-app-production/ -- Terraform configurations for production environment
|
|
44
|
+
│ ├── gvc.tf -- GVC config in HCL
|
|
45
|
+
│ ├── identities.tf -- Identities config in HCL
|
|
46
|
+
│ ├── postgres.tf -- Postgres workload config in HCL
|
|
47
|
+
│ ├── postgres_envs.tf -- ENV variables for Postgres workload in HCL
|
|
48
|
+
│ ├── providers.tf -- Providers config in HCL
|
|
49
|
+
│ ├── rails.tf -- Rails workload config in HCL
|
|
50
|
+
│ ├── rails_envs.tf -- ENV variables for Rails workload in HCL
|
|
51
|
+
│ ├── required_providers.tf -- Required providers config in HCL
|
|
52
|
+
│ └── secrets.tf -- Secrets config in HCL
|
|
53
|
+
├── rails-app-staging/ -- Terraform configurations for staging environment
|
|
54
|
+
│ ├── gvc.tf -- GVC config in HCL
|
|
55
|
+
│ ├── identities.tf -- Identities config in HCL
|
|
56
|
+
│ ├── postgres.tf -- Postgres workload config in HCL
|
|
57
|
+
│ ├── postgres_envs.tf -- ENV variables for Postgres workload in HCL
|
|
58
|
+
│ ├── providers.tf -- Providers config in HCL
|
|
59
|
+
│ ├── rails.tf -- Rails workload config in HCL
|
|
60
|
+
│ ├── rails_envs.tf -- ENV variables for Rails workload in HCL
|
|
61
|
+
│ ├── required_providers.tf -- Required providers config in HCL
|
|
62
|
+
│ └── secrets.tf -- Secrets config in HCL
|
|
63
|
+
├── workload/ -- Terraform configurations for workload module
|
|
64
|
+
│ ├── main.tf -- Main config for workload resource in HCL
|
|
65
|
+
│ ├── required_providers.tf -- Required providers for Terraform in HCL
|
|
66
|
+
│ └── variables.tf -- Variables used to create config for workload resource in HCL
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Importing existing infrastructure
|
|
70
|
+
|
|
71
|
+
Now we need to import existing infrastructure into Terraform management because some resources can already exist on CPLN and Terraform needs to know about this:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
cpflow terraform import
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This command will initialize Terraform and import resources defined in your `controlplane.yml` and `templates` folder into the Terraform state for each application.
|
|
78
|
+
|
|
79
|
+
Please note that during the import process, you may encounter errors indicating that non-existing resources are being imported. This is expected behavior and can be safely ignored.
|
|
80
|
+
|
|
81
|
+
### Application deployment using Terraform
|
|
82
|
+
|
|
83
|
+
Preparations are complete, and now we can use Terraform commands directly to deploy our application.
|
|
84
|
+
|
|
85
|
+
1. **Navigate to the Application Folder**:
|
|
86
|
+
```sh
|
|
87
|
+
cd terraform/rails-app-staging
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
2. **Plan the Deployment**:
|
|
91
|
+
```sh
|
|
92
|
+
terraform plan
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
3. **Apply the Configuration**:
|
|
96
|
+
```sh
|
|
97
|
+
terraform apply
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
You can visit [Details](https://github.com/shakacode/control-plane-flow/tree/main/docs/terraform/details.md) to learn more about how CPLN templates in YAML format are transformed to Terraform configurations.
|
|
101
|
+
|
|
102
|
+
## References
|
|
103
|
+
|
|
104
|
+
- [Terraform Provider Plugin](https://shakadocs.controlplane.com/terraform/installation#terraform-provider-plugin)
|
|
105
|
+
- [Terraform - Control Plane Examples](https://github.com/controlplane-com/examples/tree/main/terraform)
|
data/lib/command/base.rb
CHANGED
|
@@ -12,6 +12,8 @@ module Command
|
|
|
12
12
|
VALIDATIONS_WITH_ADDITIONAL_OPTIONS = %w[templates].freeze
|
|
13
13
|
ALL_VALIDATIONS = VALIDATIONS_WITHOUT_ADDITIONAL_OPTIONS + VALIDATIONS_WITH_ADDITIONAL_OPTIONS
|
|
14
14
|
|
|
15
|
+
# Used to call the command (`cpflow SUBCOMMAND_NAME NAME`)
|
|
16
|
+
SUBCOMMAND_NAME = nil
|
|
15
17
|
# Used to call the command (`cpflow NAME`)
|
|
16
18
|
# NAME = ""
|
|
17
19
|
# Displayed when running `cpflow help` or `cpflow help NAME` (defaults to `NAME`)
|
|
@@ -43,11 +45,21 @@ module Command
|
|
|
43
45
|
@config = config
|
|
44
46
|
end
|
|
45
47
|
|
|
46
|
-
def self.all_commands
|
|
47
|
-
Dir["#{__dir__}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
def self.all_commands # rubocop:disable Metrics/MethodLength
|
|
49
|
+
Dir["#{__dir__}/**/*.rb"].each_with_object({}) do |file, result|
|
|
50
|
+
content = File.read(file)
|
|
51
|
+
|
|
52
|
+
classname = content.match(/^\s+class (?!Base\b)(\w+) < (?:.*(?!Command::)Base)(?:$| .*$)/)&.captures&.first
|
|
53
|
+
next unless classname
|
|
54
|
+
|
|
55
|
+
namespaces = content.scan(/^\s+module (\w+)/).flatten
|
|
56
|
+
full_classname = [*namespaces, classname].join("::").prepend("::")
|
|
57
|
+
|
|
58
|
+
command_key = File.basename(file, ".rb")
|
|
59
|
+
prefix = namespaces[1..].map(&:downcase).join("_")
|
|
60
|
+
command_key.prepend(prefix.concat("_")) unless prefix.empty?
|
|
61
|
+
|
|
62
|
+
result[command_key.to_sym] = Object.const_get(full_classname)
|
|
51
63
|
end
|
|
52
64
|
end
|
|
53
65
|
|
|
@@ -453,6 +465,18 @@ module Command
|
|
|
453
465
|
}
|
|
454
466
|
}
|
|
455
467
|
end
|
|
468
|
+
|
|
469
|
+
def self.dir_option(required: false)
|
|
470
|
+
{
|
|
471
|
+
name: :dir,
|
|
472
|
+
params: {
|
|
473
|
+
banner: "DIR",
|
|
474
|
+
desc: "Output directory",
|
|
475
|
+
type: :string,
|
|
476
|
+
required: required
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
end
|
|
456
480
|
# rubocop:enable Metrics/MethodLength
|
|
457
481
|
|
|
458
482
|
def self.all_options
|