@rulebricks/cli 2.1.6 → 2.3.1
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.
- package/README.md +75 -14
- package/cluster-setup/aws/README.md +123 -0
- package/cluster-setup/aws/check-aws-access.sh +242 -0
- package/cluster-setup/aws/parameters.json +13 -0
- package/cluster-setup/aws/rulebricks-cluster.cfn.yaml +355 -0
- package/cluster-setup/azure/README.md +141 -0
- package/cluster-setup/azure/check-aks-prereqs.sh +276 -0
- package/cluster-setup/azure/parameters.json +30 -0
- package/cluster-setup/azure/rulebricks-cluster.bicep +546 -0
- package/cluster-setup/gcp/README.md +189 -0
- package/cluster-setup/gcp/check-gke-prereqs.sh +260 -0
- package/dist/commands/backup.d.ts +5 -0
- package/dist/commands/backup.js +104 -0
- package/dist/commands/deploy.d.ts +3 -1
- package/dist/commands/deploy.js +226 -326
- package/dist/commands/destroy.d.ts +1 -1
- package/dist/commands/destroy.js +73 -123
- package/dist/commands/init.d.ts +5 -1
- package/dist/commands/init.js +78 -47
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +74 -0
- package/dist/commands/open.d.ts +1 -1
- package/dist/commands/open.js +4 -12
- package/dist/commands/redeploy.d.ts +6 -0
- package/dist/commands/redeploy.js +310 -0
- package/dist/commands/restore.d.ts +5 -0
- package/dist/commands/restore.js +338 -0
- package/dist/commands/status.js +62 -49
- package/dist/commands/upgrade.js +74 -51
- package/dist/components/DNSWaitScreen.d.ts +5 -1
- package/dist/components/DNSWaitScreen.js +47 -41
- package/dist/components/Wizard/WizardContext.d.ts +174 -29
- package/dist/components/Wizard/WizardContext.js +896 -91
- package/dist/components/Wizard/steps/CloudProviderStep.js +192 -102
- package/dist/components/Wizard/steps/DomainStep.js +5 -24
- package/dist/components/Wizard/steps/ExternalServicesStep.d.ts +6 -0
- package/dist/components/Wizard/steps/ExternalServicesStep.js +645 -0
- package/dist/components/Wizard/steps/FeatureConfigStep.d.ts +2 -1
- package/dist/components/Wizard/steps/FeatureConfigStep.js +959 -248
- package/dist/components/Wizard/steps/FeaturesStep.js +31 -35
- package/dist/components/Wizard/steps/ObservabilityStep.d.ts +6 -0
- package/dist/components/Wizard/steps/ObservabilityStep.js +137 -0
- package/dist/components/Wizard/steps/ReviewStep.d.ts +2 -1
- package/dist/components/Wizard/steps/ReviewStep.js +56 -7
- package/dist/components/Wizard/steps/StorageStep.d.ts +9 -0
- package/dist/components/Wizard/steps/StorageStep.js +592 -0
- package/dist/components/Wizard/steps/SupabaseCredentialsStep.js +20 -21
- package/dist/components/Wizard/steps/VersionStep.js +45 -23
- package/dist/components/Wizard/steps/index.d.ts +3 -3
- package/dist/components/Wizard/steps/index.js +3 -3
- package/dist/components/common/CommandApproval.d.ts +12 -0
- package/dist/components/common/CommandApproval.js +91 -0
- package/dist/components/common/DeploymentPicker.d.ts +14 -0
- package/dist/components/common/DeploymentPicker.js +16 -0
- package/dist/components/common/index.d.ts +2 -0
- package/dist/components/common/index.js +2 -0
- package/dist/index.js +94 -62
- package/dist/lib/cloudCli.d.ts +134 -63
- package/dist/lib/cloudCli.js +512 -220
- package/dist/lib/clusterSetupDefaults.d.ts +30 -0
- package/dist/lib/clusterSetupDefaults.js +64 -0
- package/dist/lib/commandApproval.d.ts +26 -0
- package/dist/lib/commandApproval.js +114 -0
- package/dist/lib/config.d.ts +12 -10
- package/dist/lib/config.js +91 -33
- package/dist/lib/configFixtures.d.ts +5 -0
- package/dist/lib/configFixtures.js +513 -0
- package/dist/lib/deploymentHealth.d.ts +32 -0
- package/dist/lib/deploymentHealth.js +157 -0
- package/dist/lib/dns.d.ts +1 -1
- package/dist/lib/dns.js +19 -1
- package/dist/lib/dns.test.d.ts +1 -0
- package/dist/lib/dns.test.js +27 -0
- package/dist/lib/dockerHub.d.ts +12 -1
- package/dist/lib/dockerHub.js +18 -8
- package/dist/lib/helm.d.ts +4 -0
- package/dist/lib/helm.js +16 -0
- package/dist/lib/helmValues.d.ts +25 -0
- package/dist/lib/helmValues.js +1937 -259
- package/dist/lib/helmValues.test.d.ts +1 -0
- package/dist/lib/helmValues.test.js +966 -0
- package/dist/lib/htpasswd.d.ts +1 -0
- package/dist/lib/htpasswd.js +15 -0
- package/dist/lib/kubernetes.d.ts +126 -13
- package/dist/lib/kubernetes.js +624 -134
- package/dist/lib/secrets.d.ts +23 -0
- package/dist/lib/secrets.js +158 -0
- package/dist/lib/validateValues.d.ts +31 -0
- package/dist/lib/validateValues.js +253 -0
- package/dist/lib/versions.d.ts +82 -11
- package/dist/lib/versions.js +131 -31
- package/dist/lib/versions.test.d.ts +1 -0
- package/dist/lib/versions.test.js +81 -0
- package/dist/lib/wizardSteps.d.ts +14 -0
- package/dist/lib/wizardSteps.js +23 -0
- package/dist/lib/workloadIdentity.d.ts +26 -0
- package/dist/lib/workloadIdentity.js +323 -0
- package/dist/lib/workloadIdentity.test.d.ts +1 -0
- package/dist/lib/workloadIdentity.test.js +57 -0
- package/dist/types/index.d.ts +2152 -95
- package/dist/types/index.js +554 -286
- package/package.json +10 -4
- package/schema/values.schema.json +1934 -0
- package/dist/components/Wizard/steps/CredentialsStep.d.ts +0 -6
- package/dist/components/Wizard/steps/CredentialsStep.js +0 -22
- package/dist/components/Wizard/steps/DeploymentModeStep.d.ts +0 -5
- package/dist/components/Wizard/steps/DeploymentModeStep.js +0 -26
- package/dist/components/Wizard/steps/TierStep.d.ts +0 -6
- package/dist/components/Wizard/steps/TierStep.js +0 -29
- package/dist/lib/terraform.d.ts +0 -66
- package/dist/lib/terraform.js +0 -754
- package/terraform/aws/main.tf +0 -355
- package/terraform/azure/main.tf +0 -371
- package/terraform/gcp/main.tf +0 -407
package/dist/types/index.js
CHANGED
|
@@ -6,22 +6,10 @@ export const SUPPORTED_DNS_PROVIDERS = [
|
|
|
6
6
|
"google",
|
|
7
7
|
"azure",
|
|
8
8
|
];
|
|
9
|
-
// Sink category mappings
|
|
10
|
-
export const LOGGING_SINK_CATEGORIES = {
|
|
11
|
-
s3: "cloud-storage",
|
|
12
|
-
"azure-blob": "cloud-storage",
|
|
13
|
-
gcs: "cloud-storage",
|
|
14
|
-
datadog: "logging-platform",
|
|
15
|
-
splunk: "logging-platform",
|
|
16
|
-
elasticsearch: "logging-platform",
|
|
17
|
-
loki: "logging-platform",
|
|
18
|
-
newrelic: "logging-platform",
|
|
19
|
-
axiom: "logging-platform",
|
|
20
|
-
};
|
|
21
9
|
// Region mappings
|
|
22
10
|
export const CLOUD_REGIONS = {
|
|
23
11
|
aws: [
|
|
24
|
-
// US regions
|
|
12
|
+
// US regions
|
|
25
13
|
"us-east-1",
|
|
26
14
|
"us-east-2",
|
|
27
15
|
"us-west-1",
|
|
@@ -29,7 +17,7 @@ export const CLOUD_REGIONS = {
|
|
|
29
17
|
// Canada
|
|
30
18
|
"ca-central-1",
|
|
31
19
|
"ca-west-1",
|
|
32
|
-
// Europe
|
|
20
|
+
// Europe
|
|
33
21
|
"eu-west-1",
|
|
34
22
|
"eu-west-2",
|
|
35
23
|
"eu-west-3",
|
|
@@ -38,7 +26,7 @@ export const CLOUD_REGIONS = {
|
|
|
38
26
|
"eu-north-1",
|
|
39
27
|
"eu-south-1",
|
|
40
28
|
"eu-south-2",
|
|
41
|
-
// Asia Pacific
|
|
29
|
+
// Asia Pacific
|
|
42
30
|
"ap-northeast-1",
|
|
43
31
|
"ap-northeast-2",
|
|
44
32
|
"ap-northeast-3",
|
|
@@ -60,31 +48,30 @@ export const CLOUD_REGIONS = {
|
|
|
60
48
|
"il-central-1",
|
|
61
49
|
],
|
|
62
50
|
gcp: [
|
|
63
|
-
// Tier 1: Full C4A (Google Axion ARM64) availability - 3+ zones confirmed
|
|
64
51
|
// US regions
|
|
65
|
-
"us-central1",
|
|
66
|
-
"us-east1",
|
|
67
|
-
"us-east4",
|
|
68
|
-
"us-west1",
|
|
69
|
-
"us-west4",
|
|
52
|
+
"us-central1",
|
|
53
|
+
"us-east1",
|
|
54
|
+
"us-east4",
|
|
55
|
+
"us-west1",
|
|
56
|
+
"us-west4",
|
|
70
57
|
// North America
|
|
71
|
-
"northamerica-south1",
|
|
58
|
+
"northamerica-south1",
|
|
72
59
|
// Europe
|
|
73
|
-
"europe-west1",
|
|
74
|
-
"europe-west2",
|
|
75
|
-
"europe-west3",
|
|
76
|
-
"europe-west4",
|
|
77
|
-
"europe-north1",
|
|
60
|
+
"europe-west1",
|
|
61
|
+
"europe-west2",
|
|
62
|
+
"europe-west3",
|
|
63
|
+
"europe-west4",
|
|
64
|
+
"europe-north1",
|
|
78
65
|
// Asia Pacific
|
|
79
|
-
"asia-east1",
|
|
80
|
-
"asia-northeast1",
|
|
81
|
-
"asia-south1",
|
|
82
|
-
"asia-southeast1",
|
|
66
|
+
"asia-east1",
|
|
67
|
+
"asia-northeast1",
|
|
68
|
+
"asia-south1",
|
|
69
|
+
"asia-southeast1",
|
|
83
70
|
// Australia
|
|
84
|
-
"australia-southeast2",
|
|
71
|
+
"australia-southeast2",
|
|
85
72
|
],
|
|
86
73
|
azure: [
|
|
87
|
-
// US regions
|
|
74
|
+
// US regions
|
|
88
75
|
"eastus",
|
|
89
76
|
"eastus2",
|
|
90
77
|
"westus",
|
|
@@ -99,7 +86,7 @@ export const CLOUD_REGIONS = {
|
|
|
99
86
|
"canadaeast",
|
|
100
87
|
// South America
|
|
101
88
|
"brazilsouth",
|
|
102
|
-
// Europe
|
|
89
|
+
// Europe
|
|
103
90
|
"northeurope",
|
|
104
91
|
"westeurope",
|
|
105
92
|
"uksouth",
|
|
@@ -137,156 +124,6 @@ export const CLOUD_REGIONS = {
|
|
|
137
124
|
"israelcentral",
|
|
138
125
|
],
|
|
139
126
|
};
|
|
140
|
-
// Performance tier configurations
|
|
141
|
-
export const TIER_CONFIGS = {
|
|
142
|
-
small: {
|
|
143
|
-
description: "Development & Testing",
|
|
144
|
-
throughput: "<1,000 rules/sec",
|
|
145
|
-
nodes: { min: 4, max: 4 },
|
|
146
|
-
resources: "2 vCPU, 4GB RAM each",
|
|
147
|
-
// HPS
|
|
148
|
-
hpsReplicas: 2,
|
|
149
|
-
hpsWorkerReplicas: { min: 4, max: 8 },
|
|
150
|
-
hpsResources: {
|
|
151
|
-
requests: { cpu: "500m", memory: "1Gi" },
|
|
152
|
-
limits: { cpu: "1500m", memory: "1536Mi" },
|
|
153
|
-
},
|
|
154
|
-
hpsWorkerResources: {
|
|
155
|
-
requests: { cpu: "100m", memory: "128Mi" },
|
|
156
|
-
limits: { cpu: "500m", memory: "512Mi" },
|
|
157
|
-
},
|
|
158
|
-
// Kafka
|
|
159
|
-
kafkaStorage: "10Gi",
|
|
160
|
-
kafkaReplication: 1,
|
|
161
|
-
kafkaResources: {
|
|
162
|
-
requests: { cpu: "500m", memory: "2Gi" },
|
|
163
|
-
limits: { cpu: "2000m", memory: "3Gi" },
|
|
164
|
-
},
|
|
165
|
-
kafkaHeapOpts: "-Xmx1g -Xms1g -XX:+UseZGC -XX:+AlwaysPreTouch",
|
|
166
|
-
// Redis
|
|
167
|
-
redisResources: {
|
|
168
|
-
requests: { cpu: "200m", memory: "256Mi" },
|
|
169
|
-
limits: { cpu: "500m", memory: "2Gi" },
|
|
170
|
-
},
|
|
171
|
-
redisPersistenceSize: "4Gi",
|
|
172
|
-
// Vector
|
|
173
|
-
vectorReplicas: 2,
|
|
174
|
-
vectorResources: {
|
|
175
|
-
requests: { cpu: "50m", memory: "128Mi" },
|
|
176
|
-
limits: { cpu: "200m", memory: "256Mi" },
|
|
177
|
-
},
|
|
178
|
-
// Database
|
|
179
|
-
dbResources: {
|
|
180
|
-
requests: { cpu: "500m", memory: "1Gi" },
|
|
181
|
-
limits: { cpu: "1000m", memory: "2Gi" },
|
|
182
|
-
},
|
|
183
|
-
dbPersistenceSize: "10Gi",
|
|
184
|
-
// App
|
|
185
|
-
appReplicas: 2,
|
|
186
|
-
appResources: {
|
|
187
|
-
requests: { cpu: "500m", memory: "512Mi" },
|
|
188
|
-
limits: { cpu: "2000m", memory: "2Gi" },
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
medium: {
|
|
192
|
-
description: "Production",
|
|
193
|
-
throughput: "1,000-10,000 rules/sec",
|
|
194
|
-
nodes: { min: 4, max: 8 },
|
|
195
|
-
resources: "2-4 vCPU, 4-8GB RAM each",
|
|
196
|
-
// HPS
|
|
197
|
-
hpsReplicas: 3,
|
|
198
|
-
hpsWorkerReplicas: { min: 10, max: 24 },
|
|
199
|
-
hpsResources: {
|
|
200
|
-
requests: { cpu: "1000m", memory: "1Gi" },
|
|
201
|
-
limits: { cpu: "4000m", memory: "4Gi" },
|
|
202
|
-
},
|
|
203
|
-
hpsWorkerResources: {
|
|
204
|
-
requests: { cpu: "500m", memory: "512Mi" },
|
|
205
|
-
limits: { cpu: "2000m", memory: "2Gi" },
|
|
206
|
-
},
|
|
207
|
-
// Kafka
|
|
208
|
-
kafkaStorage: "50Gi",
|
|
209
|
-
kafkaReplication: 2,
|
|
210
|
-
kafkaResources: {
|
|
211
|
-
requests: { cpu: "1000m", memory: "3Gi" },
|
|
212
|
-
limits: { cpu: "2000m", memory: "4Gi" },
|
|
213
|
-
},
|
|
214
|
-
kafkaHeapOpts: "-Xmx2g -Xms2g -XX:+UseZGC -XX:+AlwaysPreTouch",
|
|
215
|
-
// Redis
|
|
216
|
-
redisResources: {
|
|
217
|
-
requests: { cpu: "200m", memory: "512Mi" },
|
|
218
|
-
limits: { cpu: "1000m", memory: "4Gi" },
|
|
219
|
-
},
|
|
220
|
-
redisPersistenceSize: "8Gi",
|
|
221
|
-
// Vector
|
|
222
|
-
vectorReplicas: 2,
|
|
223
|
-
vectorResources: {
|
|
224
|
-
requests: { cpu: "100m", memory: "256Mi" },
|
|
225
|
-
limits: { cpu: "500m", memory: "512Mi" },
|
|
226
|
-
},
|
|
227
|
-
// Database
|
|
228
|
-
dbResources: {
|
|
229
|
-
requests: { cpu: "1000m", memory: "2Gi" },
|
|
230
|
-
limits: { cpu: "2000m", memory: "4Gi" },
|
|
231
|
-
},
|
|
232
|
-
dbPersistenceSize: "50Gi",
|
|
233
|
-
// App
|
|
234
|
-
appReplicas: 2,
|
|
235
|
-
appResources: {
|
|
236
|
-
requests: { cpu: "500m", memory: "512Mi" },
|
|
237
|
-
limits: { cpu: "2000m", memory: "2Gi" },
|
|
238
|
-
},
|
|
239
|
-
},
|
|
240
|
-
large: {
|
|
241
|
-
description: "High Performance",
|
|
242
|
-
throughput: ">10,000 rules/sec",
|
|
243
|
-
nodes: { min: 5, max: 16 },
|
|
244
|
-
resources: "2-4 vCPU, 4-8GB RAM each",
|
|
245
|
-
// HPS
|
|
246
|
-
hpsReplicas: 4,
|
|
247
|
-
hpsWorkerReplicas: { min: 10, max: 48 },
|
|
248
|
-
hpsResources: {
|
|
249
|
-
requests: { cpu: "2000m", memory: "2Gi" },
|
|
250
|
-
limits: { cpu: "4000m", memory: "4Gi" },
|
|
251
|
-
},
|
|
252
|
-
hpsWorkerResources: {
|
|
253
|
-
requests: { cpu: "1000m", memory: "1Gi" },
|
|
254
|
-
limits: { cpu: "2000m", memory: "2Gi" },
|
|
255
|
-
},
|
|
256
|
-
// Kafka
|
|
257
|
-
kafkaStorage: "100Gi",
|
|
258
|
-
kafkaReplication: 3,
|
|
259
|
-
kafkaResources: {
|
|
260
|
-
requests: { cpu: "2000m", memory: "4Gi" },
|
|
261
|
-
limits: { cpu: "4000m", memory: "6Gi" },
|
|
262
|
-
},
|
|
263
|
-
kafkaHeapOpts: "-Xmx3g -Xms3g -XX:+UseZGC -XX:+AlwaysPreTouch",
|
|
264
|
-
// Redis
|
|
265
|
-
redisResources: {
|
|
266
|
-
requests: { cpu: "500m", memory: "1Gi" },
|
|
267
|
-
limits: { cpu: "2000m", memory: "8Gi" },
|
|
268
|
-
},
|
|
269
|
-
redisPersistenceSize: "16Gi",
|
|
270
|
-
// Vector
|
|
271
|
-
vectorReplicas: 3,
|
|
272
|
-
vectorResources: {
|
|
273
|
-
requests: { cpu: "200m", memory: "512Mi" },
|
|
274
|
-
limits: { cpu: "1000m", memory: "1Gi" },
|
|
275
|
-
},
|
|
276
|
-
// Database
|
|
277
|
-
dbResources: {
|
|
278
|
-
requests: { cpu: "2000m", memory: "4Gi" },
|
|
279
|
-
limits: { cpu: "4000m", memory: "8Gi" },
|
|
280
|
-
},
|
|
281
|
-
dbPersistenceSize: "100Gi",
|
|
282
|
-
// App
|
|
283
|
-
appReplicas: 3,
|
|
284
|
-
appResources: {
|
|
285
|
-
requests: { cpu: "1000m", memory: "1Gi" },
|
|
286
|
-
limits: { cpu: "2000m", memory: "2Gi" },
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
127
|
// Default SMTP providers
|
|
291
128
|
export const SMTP_PROVIDERS = {
|
|
292
129
|
"aws-ses": {
|
|
@@ -315,6 +152,13 @@ export const DNS_PROVIDER_NAMES = {
|
|
|
315
152
|
azure: "Azure DNS",
|
|
316
153
|
other: "Other / Not sure",
|
|
317
154
|
};
|
|
155
|
+
// Cloud provider display names with proper casing for UI labels. Acronyms stay
|
|
156
|
+
// uppercase; Azure is title-cased (so it doesn't render as "AZURE").
|
|
157
|
+
export const CLOUD_PROVIDER_NAMES = {
|
|
158
|
+
aws: "AWS",
|
|
159
|
+
gcp: "GCP",
|
|
160
|
+
azure: "Azure",
|
|
161
|
+
};
|
|
318
162
|
// Logging sink display info
|
|
319
163
|
export const LOGGING_SINK_INFO = {
|
|
320
164
|
console: {
|
|
@@ -325,19 +169,6 @@ export const LOGGING_SINK_INFO = {
|
|
|
325
169
|
name: "External (not configured)",
|
|
326
170
|
description: "External logging enabled but destination not selected",
|
|
327
171
|
},
|
|
328
|
-
// Cloud Storage
|
|
329
|
-
s3: {
|
|
330
|
-
name: "AWS S3",
|
|
331
|
-
description: "Store logs in an S3 bucket",
|
|
332
|
-
},
|
|
333
|
-
"azure-blob": {
|
|
334
|
-
name: "Azure Blob Storage",
|
|
335
|
-
description: "Store logs in Azure Blob container",
|
|
336
|
-
},
|
|
337
|
-
gcs: {
|
|
338
|
-
name: "Google Cloud Storage",
|
|
339
|
-
description: "Store logs in a GCS bucket",
|
|
340
|
-
},
|
|
341
172
|
// Logging Platforms
|
|
342
173
|
datadog: {
|
|
343
174
|
name: "Datadog",
|
|
@@ -364,24 +195,320 @@ export const LOGGING_SINK_INFO = {
|
|
|
364
195
|
description: "Send logs to Axiom dataset",
|
|
365
196
|
},
|
|
366
197
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
198
|
+
const SecretKeyRefSchema = z.object({
|
|
199
|
+
name: z.string().min(1),
|
|
200
|
+
key: z.string().min(1),
|
|
201
|
+
});
|
|
202
|
+
/**
|
|
203
|
+
* Validates a Prometheus remote_write config the same way buildHelmValues and
|
|
204
|
+
* the Helm chart do, returning human-readable errors. Centralized so the wizard
|
|
205
|
+
* gate, the Zod schema (load time), and Helm value generation all enforce the
|
|
206
|
+
* exact same per-destination/auth requirements. This is what prevents the CLI
|
|
207
|
+
* from ever persisting a monitoring config that throws at deploy time (e.g.
|
|
208
|
+
* "Azure Monitor remote_write managed identity requires client ID").
|
|
209
|
+
*/
|
|
210
|
+
export function validateRemoteWriteConfig(rw) {
|
|
211
|
+
const errors = [];
|
|
212
|
+
switch (rw.destination) {
|
|
213
|
+
case "aws-amp":
|
|
214
|
+
if (!rw.awsRegion) {
|
|
215
|
+
errors.push("AWS Managed Prometheus remote write requires a region.");
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
case "azure-monitor": {
|
|
219
|
+
// The remote_write URL must be the full DCE metrics-ingestion path, not the
|
|
220
|
+
// bare DCE host. Azure Monitor expects:
|
|
221
|
+
// https://<dce>.<region>.metrics.ingest.monitor.azure.com/dataCollectionRules/<dcrImmutableId>/streams/Microsoft-PrometheusMetrics/api/v1/write?api-version=2023-04-24
|
|
222
|
+
// A bare host silently 404s, so catch the common copy-paste mistake here.
|
|
223
|
+
if (rw.url &&
|
|
224
|
+
!(rw.url.includes("/dataCollectionRules/") &&
|
|
225
|
+
rw.url.includes("/streams/") &&
|
|
226
|
+
rw.url.includes("/api/v1/write"))) {
|
|
227
|
+
errors.push("Azure Monitor remote write URL must be the full DCE metrics-ingestion path " +
|
|
228
|
+
"(https://<dce>.<region>.metrics.ingest.monitor.azure.com/dataCollectionRules/<dcrImmutableId>/streams/Microsoft-PrometheusMetrics/api/v1/write?api-version=2023-04-24), " +
|
|
229
|
+
"not just the data collection endpoint host.");
|
|
230
|
+
}
|
|
231
|
+
// An unset authType is treated as managed identity (the chart default).
|
|
232
|
+
const authType = rw.authType ?? "managed-identity";
|
|
233
|
+
if (authType === "oauth") {
|
|
234
|
+
if (!rw.clientId || !rw.tenantId || !rw.clientSecretRef) {
|
|
235
|
+
errors.push("Azure Monitor remote write (OAuth) requires a client ID, tenant ID, and client secret reference.");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else if (authType === "workload-identity") {
|
|
239
|
+
if (!rw.clientId || !rw.tenantId) {
|
|
240
|
+
errors.push("Azure Monitor remote write (workload identity) requires a client ID and tenant ID.");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else if (!rw.clientId) {
|
|
244
|
+
errors.push("Azure Monitor remote write (managed identity) requires a client ID.");
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
case "grafana-cloud":
|
|
249
|
+
if (!rw.usernameSecretRef || !rw.passwordSecretRef) {
|
|
250
|
+
errors.push("Grafana Cloud remote write requires username and password secret references.");
|
|
251
|
+
}
|
|
252
|
+
break;
|
|
253
|
+
case "generic":
|
|
254
|
+
if (rw.authType === "basic" &&
|
|
255
|
+
(!rw.usernameSecretRef || !rw.passwordSecretRef)) {
|
|
256
|
+
errors.push("Basic-auth remote write requires username and password secret references.");
|
|
257
|
+
}
|
|
258
|
+
if (rw.authType === "bearer" && !rw.bearerTokenSecretRef) {
|
|
259
|
+
errors.push("Bearer-token remote write requires a token secret reference.");
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
return errors;
|
|
384
264
|
}
|
|
265
|
+
const RemoteWriteConfigSchema = z
|
|
266
|
+
.object({
|
|
267
|
+
destination: z.enum([
|
|
268
|
+
"aws-amp",
|
|
269
|
+
"azure-monitor",
|
|
270
|
+
"grafana-cloud",
|
|
271
|
+
"generic",
|
|
272
|
+
]),
|
|
273
|
+
url: z.string().url(),
|
|
274
|
+
authType: z
|
|
275
|
+
.enum([
|
|
276
|
+
"none",
|
|
277
|
+
"managed-identity",
|
|
278
|
+
"workload-identity",
|
|
279
|
+
"oauth",
|
|
280
|
+
"basic",
|
|
281
|
+
"bearer",
|
|
282
|
+
])
|
|
283
|
+
.optional(),
|
|
284
|
+
awsRegion: z.string().optional(),
|
|
285
|
+
awsRoleArn: z.string().optional(),
|
|
286
|
+
azureCloud: z
|
|
287
|
+
.enum(["AzurePublic", "AzureChina", "AzureGovernment"])
|
|
288
|
+
.optional(),
|
|
289
|
+
clientId: z.string().optional(),
|
|
290
|
+
tenantId: z.string().optional(),
|
|
291
|
+
clientSecretRef: SecretKeyRefSchema.optional(),
|
|
292
|
+
usernameSecretRef: SecretKeyRefSchema.optional(),
|
|
293
|
+
passwordSecretRef: SecretKeyRefSchema.optional(),
|
|
294
|
+
bearerTokenSecretRef: SecretKeyRefSchema.optional(),
|
|
295
|
+
})
|
|
296
|
+
.superRefine((rw, ctx) => {
|
|
297
|
+
for (const message of validateRemoteWriteConfig(rw)) {
|
|
298
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message });
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
const MonitoringDestinationSchema = z.enum([
|
|
302
|
+
"local-grafana",
|
|
303
|
+
"aws-amp",
|
|
304
|
+
"azure-monitor",
|
|
305
|
+
"grafana-cloud",
|
|
306
|
+
"generic",
|
|
307
|
+
]);
|
|
308
|
+
const TracingConfigSchema = z
|
|
309
|
+
.object({
|
|
310
|
+
enabled: z.boolean(),
|
|
311
|
+
// Absent means "elastic" for backward compatibility with existing configs.
|
|
312
|
+
destination: z.enum(["elastic", "otlp", "azure-monitor"]).optional(),
|
|
313
|
+
samplingRatio: z.number().min(0).max(1).optional(),
|
|
314
|
+
elastic: z
|
|
315
|
+
.object({
|
|
316
|
+
endpoint: z.string().url().optional(),
|
|
317
|
+
authMode: z.enum(["secret-token", "api-key", "none"]).optional(),
|
|
318
|
+
secretToken: z.string().optional(),
|
|
319
|
+
apiKey: z.string().optional(),
|
|
320
|
+
})
|
|
321
|
+
.optional(),
|
|
322
|
+
// Generic OTLP/HTTP backend (Grafana Tempo, Honeycomb, Jaeger, vendor
|
|
323
|
+
// gateways, AWS/Azure OTLP ingestion, etc.).
|
|
324
|
+
otlp: z
|
|
325
|
+
.object({
|
|
326
|
+
endpoint: z.string().url().optional(),
|
|
327
|
+
authMode: z.enum(["none", "bearer", "api-key", "header"]).optional(),
|
|
328
|
+
headerName: z.string().optional(),
|
|
329
|
+
token: z.string().optional(),
|
|
330
|
+
apiKey: z.string().optional(),
|
|
331
|
+
headerValue: z.string().optional(),
|
|
332
|
+
headers: z.record(z.string()).optional(),
|
|
333
|
+
tlsInsecureSkipVerify: z.boolean().optional(),
|
|
334
|
+
})
|
|
335
|
+
.optional(),
|
|
336
|
+
// Azure Monitor / Application Insights.
|
|
337
|
+
azureMonitor: z
|
|
338
|
+
.object({
|
|
339
|
+
connectionString: z.string().optional(),
|
|
340
|
+
})
|
|
341
|
+
.optional(),
|
|
342
|
+
})
|
|
343
|
+
.superRefine((t, ctx) => {
|
|
344
|
+
if (!t.enabled)
|
|
345
|
+
return;
|
|
346
|
+
const destination = t.destination ?? "elastic";
|
|
347
|
+
if (destination === "elastic") {
|
|
348
|
+
if (!t.elastic?.endpoint) {
|
|
349
|
+
ctx.addIssue({
|
|
350
|
+
code: z.ZodIssueCode.custom,
|
|
351
|
+
message: "features.tracing.elastic.endpoint is required when tracing destination is 'elastic'",
|
|
352
|
+
path: ["elastic", "endpoint"],
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
const mode = t.elastic?.authMode ?? "secret-token";
|
|
356
|
+
if (mode === "secret-token" && !t.elastic?.secretToken) {
|
|
357
|
+
ctx.addIssue({
|
|
358
|
+
code: z.ZodIssueCode.custom,
|
|
359
|
+
message: "features.tracing.elastic.secretToken is required for authMode 'secret-token'",
|
|
360
|
+
path: ["elastic", "secretToken"],
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (mode === "api-key" && !t.elastic?.apiKey) {
|
|
364
|
+
ctx.addIssue({
|
|
365
|
+
code: z.ZodIssueCode.custom,
|
|
366
|
+
message: "features.tracing.elastic.apiKey is required for authMode 'api-key'",
|
|
367
|
+
path: ["elastic", "apiKey"],
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else if (destination === "otlp") {
|
|
372
|
+
if (!t.otlp?.endpoint) {
|
|
373
|
+
ctx.addIssue({
|
|
374
|
+
code: z.ZodIssueCode.custom,
|
|
375
|
+
message: "features.tracing.otlp.endpoint is required when tracing destination is 'otlp'",
|
|
376
|
+
path: ["otlp", "endpoint"],
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
const mode = t.otlp?.authMode ?? "none";
|
|
380
|
+
if (mode === "bearer" && !t.otlp?.token) {
|
|
381
|
+
ctx.addIssue({
|
|
382
|
+
code: z.ZodIssueCode.custom,
|
|
383
|
+
message: "features.tracing.otlp.token is required for authMode 'bearer'",
|
|
384
|
+
path: ["otlp", "token"],
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (mode === "api-key" && !t.otlp?.apiKey) {
|
|
388
|
+
ctx.addIssue({
|
|
389
|
+
code: z.ZodIssueCode.custom,
|
|
390
|
+
message: "features.tracing.otlp.apiKey is required for authMode 'api-key'",
|
|
391
|
+
path: ["otlp", "apiKey"],
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
if (mode === "header" && !t.otlp?.headerValue) {
|
|
395
|
+
ctx.addIssue({
|
|
396
|
+
code: z.ZodIssueCode.custom,
|
|
397
|
+
message: "features.tracing.otlp.headerValue is required for authMode 'header'",
|
|
398
|
+
path: ["otlp", "headerValue"],
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else if (destination === "azure-monitor") {
|
|
403
|
+
if (!t.azureMonitor?.connectionString) {
|
|
404
|
+
ctx.addIssue({
|
|
405
|
+
code: z.ZodIssueCode.custom,
|
|
406
|
+
message: "features.tracing.azureMonitor.connectionString is required when tracing destination is 'azure-monitor'",
|
|
407
|
+
path: ["azureMonitor", "connectionString"],
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
// Application/container log shipping to a customer-managed Elasticsearch (BYO)
|
|
413
|
+
// via the Vector agent DaemonSet. Distinct from decision-log sinks.
|
|
414
|
+
const AppLogsConfigSchema = z
|
|
415
|
+
.object({
|
|
416
|
+
enabled: z.boolean(),
|
|
417
|
+
destination: z.enum(["elasticsearch", "loki", "generic"]).optional(),
|
|
418
|
+
elasticsearch: z
|
|
419
|
+
.object({
|
|
420
|
+
endpoint: z.string().url().optional(),
|
|
421
|
+
index: z.string().optional(),
|
|
422
|
+
authMode: z.enum(["basic", "api-key", "none"]).optional(),
|
|
423
|
+
username: z.string().optional(),
|
|
424
|
+
password: z.string().optional(),
|
|
425
|
+
apiKey: z.string().optional(),
|
|
426
|
+
verifyCertificate: z.boolean().optional(),
|
|
427
|
+
})
|
|
428
|
+
.optional(),
|
|
429
|
+
loki: z
|
|
430
|
+
.object({
|
|
431
|
+
endpoint: z.string().url().optional(),
|
|
432
|
+
labels: z.record(z.string()).optional(),
|
|
433
|
+
})
|
|
434
|
+
.optional(),
|
|
435
|
+
generic: z
|
|
436
|
+
.object({
|
|
437
|
+
endpoint: z.string().url().optional(),
|
|
438
|
+
authHeader: z.string().optional(),
|
|
439
|
+
})
|
|
440
|
+
.optional(),
|
|
441
|
+
})
|
|
442
|
+
.superRefine((a, ctx) => {
|
|
443
|
+
if (!a.enabled)
|
|
444
|
+
return;
|
|
445
|
+
const destination = a.destination ?? "elasticsearch";
|
|
446
|
+
if (destination === "loki") {
|
|
447
|
+
if (!a.loki?.endpoint) {
|
|
448
|
+
ctx.addIssue({
|
|
449
|
+
code: z.ZodIssueCode.custom,
|
|
450
|
+
message: "features.logging.appLogs.loki.endpoint is required when appLogs destination is 'loki'",
|
|
451
|
+
path: ["loki", "endpoint"],
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
if (destination === "generic") {
|
|
457
|
+
if (!a.generic?.endpoint) {
|
|
458
|
+
ctx.addIssue({
|
|
459
|
+
code: z.ZodIssueCode.custom,
|
|
460
|
+
message: "features.logging.appLogs.generic.endpoint is required when appLogs destination is 'generic'",
|
|
461
|
+
path: ["generic", "endpoint"],
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (!a.elasticsearch?.endpoint) {
|
|
467
|
+
ctx.addIssue({
|
|
468
|
+
code: z.ZodIssueCode.custom,
|
|
469
|
+
message: "features.logging.appLogs.elasticsearch.endpoint is required when appLogs is enabled",
|
|
470
|
+
path: ["elasticsearch", "endpoint"],
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
const mode = a.elasticsearch?.authMode ?? "basic";
|
|
474
|
+
if (mode === "basic" &&
|
|
475
|
+
(!a.elasticsearch?.username || !a.elasticsearch?.password)) {
|
|
476
|
+
ctx.addIssue({
|
|
477
|
+
code: z.ZodIssueCode.custom,
|
|
478
|
+
message: "features.logging.appLogs.elasticsearch username and password are required for authMode 'basic'",
|
|
479
|
+
path: ["elasticsearch", "username"],
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
if (mode === "api-key" && !a.elasticsearch?.apiKey) {
|
|
483
|
+
ctx.addIssue({
|
|
484
|
+
code: z.ZodIssueCode.custom,
|
|
485
|
+
message: "features.logging.appLogs.elasticsearch.apiKey is required for authMode 'api-key'",
|
|
486
|
+
path: ["elasticsearch", "apiKey"],
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
const CacheObservabilityConfigSchema = z.object({
|
|
491
|
+
valkeyAdmin: z
|
|
492
|
+
.object({
|
|
493
|
+
enabled: z.boolean(),
|
|
494
|
+
exposure: z.enum(["internal", "ingress"]).optional(),
|
|
495
|
+
hostname: z.string().optional(),
|
|
496
|
+
basicAuthUsers: z.array(z.string()).optional(),
|
|
497
|
+
basicAuthExistingSecret: z.string().optional(),
|
|
498
|
+
allowedIPs: z.array(z.string()).optional(),
|
|
499
|
+
})
|
|
500
|
+
.optional(),
|
|
501
|
+
redisExporter: z
|
|
502
|
+
.object({
|
|
503
|
+
enabled: z.boolean(),
|
|
504
|
+
})
|
|
505
|
+
.optional(),
|
|
506
|
+
kafkaExporter: z
|
|
507
|
+
.object({
|
|
508
|
+
enabled: z.boolean(),
|
|
509
|
+
})
|
|
510
|
+
.optional(),
|
|
511
|
+
});
|
|
385
512
|
// Deployment configuration schema
|
|
386
513
|
export const DeploymentConfigSchema = z.object({
|
|
387
514
|
name: z
|
|
@@ -391,12 +518,24 @@ export const DeploymentConfigSchema = z.object({
|
|
|
391
518
|
.regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/),
|
|
392
519
|
// Infrastructure
|
|
393
520
|
infrastructure: z.object({
|
|
394
|
-
mode: z.
|
|
521
|
+
mode: z.literal("existing"),
|
|
395
522
|
provider: z.enum(["aws", "gcp", "azure"]).optional(),
|
|
396
523
|
region: z.string().optional(),
|
|
397
524
|
clusterName: z.string().optional(),
|
|
398
525
|
gcpProjectId: z.string().optional(),
|
|
399
526
|
azureResourceGroup: z.string().optional(),
|
|
527
|
+
nodeArchitecture: z
|
|
528
|
+
.enum(["amd64", "arm64", "mixed", "unknown"])
|
|
529
|
+
.optional(),
|
|
530
|
+
arm64TolerationRequired: z.boolean().optional(),
|
|
531
|
+
storageClass: z.string().optional(),
|
|
532
|
+
storageProvisioner: z.string().optional(),
|
|
533
|
+
schedulableNodeCount: z.number().optional(),
|
|
534
|
+
totalCpuCores: z.number().optional(),
|
|
535
|
+
totalMemoryGi: z.number().optional(),
|
|
536
|
+
eligibleCpuCores: z.number().optional(),
|
|
537
|
+
eligibleMemoryGi: z.number().optional(),
|
|
538
|
+
totalPersistentStorageGi: z.number().optional(),
|
|
400
539
|
}),
|
|
401
540
|
// Domain & TLS
|
|
402
541
|
domain: z.string().min(1),
|
|
@@ -408,8 +547,6 @@ export const DeploymentConfigSchema = z.object({
|
|
|
408
547
|
provider: z.enum(["route53", "cloudflare", "google", "azure", "other"]),
|
|
409
548
|
// Should we auto-manage DNS records? (only applicable for supported providers)
|
|
410
549
|
autoManage: z.boolean(),
|
|
411
|
-
// For existing clusters: does external-dns already exist cluster-wide?
|
|
412
|
-
existingExternalDns: z.boolean().optional(),
|
|
413
550
|
}),
|
|
414
551
|
// SMTP Configuration
|
|
415
552
|
smtp: z.object({
|
|
@@ -435,8 +572,153 @@ export const DeploymentConfigSchema = z.object({
|
|
|
435
572
|
supabaseDashboardUser: z.string().optional(),
|
|
436
573
|
supabaseDashboardPass: z.string().optional(),
|
|
437
574
|
}),
|
|
438
|
-
//
|
|
439
|
-
|
|
575
|
+
// Shared object storage: one provider, one identity, one bucket/container.
|
|
576
|
+
// Decision logs and DB backups are just key prefixes within it.
|
|
577
|
+
storage: z
|
|
578
|
+
.object({
|
|
579
|
+
provider: z.enum(["s3", "azure-blob", "gcs"]),
|
|
580
|
+
cloudAuthMode: z.enum(["workload-identity", "secret"]).optional(),
|
|
581
|
+
// Single bucket (S3/GCS) or storage account (azure-blob) + its region.
|
|
582
|
+
bucket: z.string().min(1),
|
|
583
|
+
region: z.string().min(1),
|
|
584
|
+
awsIamRoleArn: z.string().optional(),
|
|
585
|
+
azureBlobClientId: z.string().optional(),
|
|
586
|
+
azureBlobTenantId: z.string().optional(),
|
|
587
|
+
azureBlobConnectionStringSecretRef: SecretKeyRefSchema.optional(),
|
|
588
|
+
// Single blob container (azure-blob only) holding all prefixes.
|
|
589
|
+
azureBlobContainer: z.string().optional(),
|
|
590
|
+
gcpServiceAccountEmail: z.string().optional(),
|
|
591
|
+
// Per-purpose key prefixes within the single bucket/container.
|
|
592
|
+
paths: z
|
|
593
|
+
.object({
|
|
594
|
+
decisionLogs: z.string().optional(),
|
|
595
|
+
dbBackups: z.string().optional(),
|
|
596
|
+
})
|
|
597
|
+
.optional(),
|
|
598
|
+
})
|
|
599
|
+
.optional(),
|
|
600
|
+
// External/managed Redis and Kafka (for large deployments that prefer managed
|
|
601
|
+
// services over the in-cluster defaults). Omitted/embedded means the chart
|
|
602
|
+
// deploys these in-cluster as usual.
|
|
603
|
+
externalServices: z
|
|
604
|
+
.object({
|
|
605
|
+
redis: z
|
|
606
|
+
.object({
|
|
607
|
+
mode: z.enum(["embedded", "external"]),
|
|
608
|
+
external: z
|
|
609
|
+
.object({
|
|
610
|
+
host: z.string().optional(),
|
|
611
|
+
port: z.number().int().min(1).max(65535).optional(),
|
|
612
|
+
password: z.string().optional(),
|
|
613
|
+
existingSecret: z.string().optional(),
|
|
614
|
+
existingSecretKey: z.string().optional(),
|
|
615
|
+
tls: z.boolean().optional(),
|
|
616
|
+
httpApi: z
|
|
617
|
+
.object({
|
|
618
|
+
enabled: z.boolean(),
|
|
619
|
+
url: z.string().optional(),
|
|
620
|
+
token: z.string().optional(),
|
|
621
|
+
})
|
|
622
|
+
.optional(),
|
|
623
|
+
})
|
|
624
|
+
.optional(),
|
|
625
|
+
})
|
|
626
|
+
.optional(),
|
|
627
|
+
kafka: z
|
|
628
|
+
.object({
|
|
629
|
+
mode: z.enum(["embedded", "external"]),
|
|
630
|
+
external: z
|
|
631
|
+
.object({
|
|
632
|
+
// Preset drives per-cloud auth defaults and whether the Vector
|
|
633
|
+
// bridge sidecar is required.
|
|
634
|
+
preset: z
|
|
635
|
+
.enum([
|
|
636
|
+
"aws-msk-iam",
|
|
637
|
+
"azure-event-hubs",
|
|
638
|
+
"gcp-managed",
|
|
639
|
+
"custom",
|
|
640
|
+
])
|
|
641
|
+
.optional(),
|
|
642
|
+
brokers: z.string().optional(),
|
|
643
|
+
topic: z.string().optional(),
|
|
644
|
+
// Prefix namespacing all Kafka topics (e.g. "com.rulebricks.").
|
|
645
|
+
topicPrefix: z.string().optional(),
|
|
646
|
+
// Whether the chart creates the required topics on the managed
|
|
647
|
+
// broker (via the kafka-topic-provision Job, MSK IAM only). Set
|
|
648
|
+
// false for a locked-down broker where topics are managed out of
|
|
649
|
+
// band and the workload role has no CreateTopic. Default true.
|
|
650
|
+
provisionTopics: z.boolean().optional(),
|
|
651
|
+
ssl: z.boolean().optional(),
|
|
652
|
+
sasl: z
|
|
653
|
+
.object({
|
|
654
|
+
// "" means no SASL (plaintext/SSL-only).
|
|
655
|
+
mechanism: z.enum([
|
|
656
|
+
"",
|
|
657
|
+
"aws-iam",
|
|
658
|
+
"oauthbearer",
|
|
659
|
+
"scram-sha-256",
|
|
660
|
+
"scram-sha-512",
|
|
661
|
+
"plain",
|
|
662
|
+
]),
|
|
663
|
+
region: z.string().optional(),
|
|
664
|
+
username: z.string().optional(),
|
|
665
|
+
password: z.string().optional(),
|
|
666
|
+
existingSecret: z.string().optional(),
|
|
667
|
+
})
|
|
668
|
+
.optional(),
|
|
669
|
+
// Cloud workload identity for token mechanisms (MSK IAM / GCP
|
|
670
|
+
// OAUTHBEARER). Applied to the HPS and Vector service accounts.
|
|
671
|
+
identity: z
|
|
672
|
+
.object({
|
|
673
|
+
awsRoleArn: z.string().optional(),
|
|
674
|
+
gcpServiceAccountEmail: z.string().optional(),
|
|
675
|
+
azureClientId: z.string().optional(),
|
|
676
|
+
})
|
|
677
|
+
.optional(),
|
|
678
|
+
})
|
|
679
|
+
.optional(),
|
|
680
|
+
})
|
|
681
|
+
.optional(),
|
|
682
|
+
// Managed external PostgreSQL (AWS RDS/Aurora or Azure Flexible Server).
|
|
683
|
+
// Self-hosted Supabase runs against this instead of the bundled in-cluster
|
|
684
|
+
// database. Maps to the chart's supabase.externalDatabase.* values.
|
|
685
|
+
postgres: z
|
|
686
|
+
.object({
|
|
687
|
+
mode: z.enum(["embedded", "external"]),
|
|
688
|
+
external: z
|
|
689
|
+
.object({
|
|
690
|
+
// Managed provider this database lives on (gates CLI prompts; only
|
|
691
|
+
// aws/azure are supported for the structured/managed flow).
|
|
692
|
+
provider: z.enum(["aws", "azure"]).optional(),
|
|
693
|
+
host: z.string().optional(),
|
|
694
|
+
port: z.number().int().min(1).max(65535).optional(),
|
|
695
|
+
database: z.string().optional(),
|
|
696
|
+
// One-time master/owner credentials the chart's pre-install hook
|
|
697
|
+
// uses to initialize the database (roles, schemas, auth helpers,
|
|
698
|
+
// publication). Inline creds are materialized into a hook-scoped
|
|
699
|
+
// secret; secretRef points at a pre-created secret instead.
|
|
700
|
+
bootstrap: z
|
|
701
|
+
.object({
|
|
702
|
+
enabled: z.boolean().optional(),
|
|
703
|
+
masterUsername: z.string().optional(),
|
|
704
|
+
masterPassword: z.string().optional(),
|
|
705
|
+
secretRef: z.string().optional(),
|
|
706
|
+
appRole: z.string().optional(),
|
|
707
|
+
})
|
|
708
|
+
.optional(),
|
|
709
|
+
})
|
|
710
|
+
.optional(),
|
|
711
|
+
})
|
|
712
|
+
.optional(),
|
|
713
|
+
})
|
|
714
|
+
.optional(),
|
|
715
|
+
backup: z
|
|
716
|
+
.object({
|
|
717
|
+
enabled: z.boolean(),
|
|
718
|
+
schedule: z.string().min(1),
|
|
719
|
+
retentionDays: z.number().int().min(1),
|
|
720
|
+
})
|
|
721
|
+
.optional(),
|
|
440
722
|
// Optional features
|
|
441
723
|
features: z.object({
|
|
442
724
|
ai: z.object({
|
|
@@ -454,18 +736,32 @@ export const DeploymentConfigSchema = z.object({
|
|
|
454
736
|
}),
|
|
455
737
|
monitoring: z.object({
|
|
456
738
|
enabled: z.boolean(),
|
|
457
|
-
|
|
739
|
+
destination: MonitoringDestinationSchema.optional(),
|
|
740
|
+
// Legacy optional URL retained for existing config files.
|
|
458
741
|
remoteWriteUrl: z.string().url().optional(),
|
|
742
|
+
remoteWrite: RemoteWriteConfigSchema.optional(),
|
|
459
743
|
}),
|
|
744
|
+
observability: z
|
|
745
|
+
.object({
|
|
746
|
+
clickstack: z.object({
|
|
747
|
+
enabled: z.boolean(),
|
|
748
|
+
telemetryRetentionDays: z.number().int().min(1).optional(),
|
|
749
|
+
decisionLogRetentionDays: z.number().int().min(1).optional(),
|
|
750
|
+
clickHouseStorageSize: z.string().optional(),
|
|
751
|
+
}),
|
|
752
|
+
})
|
|
753
|
+
.optional(),
|
|
754
|
+
// Distributed tracing (optional; self-hosted only). Absent on existing
|
|
755
|
+
// config files, which keeps them valid.
|
|
756
|
+
tracing: TracingConfigSchema.optional(),
|
|
757
|
+
cache: CacheObservabilityConfigSchema.optional(),
|
|
460
758
|
logging: z.object({
|
|
461
|
-
//
|
|
462
|
-
//
|
|
759
|
+
// Console logging is always on. This selects an additional external
|
|
760
|
+
// logging platform. Cloud object storage for decision logs is configured
|
|
761
|
+
// separately under `storage`.
|
|
463
762
|
sink: z.enum([
|
|
464
763
|
"console",
|
|
465
764
|
"pending",
|
|
466
|
-
"s3",
|
|
467
|
-
"azure-blob",
|
|
468
|
-
"gcs",
|
|
469
765
|
"datadog",
|
|
470
766
|
"splunk",
|
|
471
767
|
"elasticsearch",
|
|
@@ -473,11 +769,13 @@ export const DeploymentConfigSchema = z.object({
|
|
|
473
769
|
"newrelic",
|
|
474
770
|
"axiom",
|
|
475
771
|
]),
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
// For platforms: repurposed for credentials (API key) and extra config
|
|
772
|
+
// For platforms, bucket/region are repurposed to carry the credential
|
|
773
|
+
// (API key/token) and endpoint/site.
|
|
479
774
|
bucket: z.string().optional(),
|
|
480
775
|
region: z.string().optional(),
|
|
776
|
+
// Application/container log shipping to Elasticsearch via the Vector
|
|
777
|
+
// agent DaemonSet (distinct from the decision-log `sink` above).
|
|
778
|
+
appLogs: AppLogsConfigSchema.optional(),
|
|
481
779
|
}),
|
|
482
780
|
customEmails: z
|
|
483
781
|
.object({
|
|
@@ -503,65 +801,17 @@ export const DeploymentConfigSchema = z.object({
|
|
|
503
801
|
}),
|
|
504
802
|
// Credentials
|
|
505
803
|
licenseKey: z.string().min(1),
|
|
506
|
-
//
|
|
507
|
-
|
|
508
|
-
|
|
804
|
+
// Product version used for app, HPS, and HPS worker images
|
|
805
|
+
version: z.string().min(1),
|
|
806
|
+
// Optional single registry-host override for every image. Empty/unset means
|
|
807
|
+
// the chart default docker.io/rulebricks/*. When set (e.g. "myacr.azurecr.io"
|
|
808
|
+
// for an air-gapped mirror), the CLI rewrites the registry host into
|
|
809
|
+
// global.imageRegistry and into each Tier-2 chart's native image keys, keeping
|
|
810
|
+
// the rulebricks/<name> path. See the helm chart's global.imageRegistry knob.
|
|
811
|
+
imageRegistry: z.string().optional(),
|
|
509
812
|
// Legacy chart version (deprecated, kept for backwards compatibility)
|
|
510
813
|
chartVersion: z.string().optional(),
|
|
511
814
|
});
|
|
512
|
-
export const WIZARD_STEPS = [
|
|
513
|
-
{ id: "mode", title: "Deployment Mode", description: "Choose how to deploy" },
|
|
514
|
-
{
|
|
515
|
-
id: "cloud",
|
|
516
|
-
title: "Cloud Provider",
|
|
517
|
-
description: "Select your cloud provider",
|
|
518
|
-
},
|
|
519
|
-
{
|
|
520
|
-
id: "domain",
|
|
521
|
-
title: "Domain & DNS",
|
|
522
|
-
description: "Configure your domain and DNS",
|
|
523
|
-
},
|
|
524
|
-
{
|
|
525
|
-
id: "smtp",
|
|
526
|
-
title: "Email (SMTP)",
|
|
527
|
-
description: "Configure email delivery",
|
|
528
|
-
},
|
|
529
|
-
{
|
|
530
|
-
id: "database",
|
|
531
|
-
title: "Database",
|
|
532
|
-
description: "Choose your database setup",
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
id: "database-creds",
|
|
536
|
-
title: "Database Credentials",
|
|
537
|
-
description: "Configure database access",
|
|
538
|
-
},
|
|
539
|
-
{
|
|
540
|
-
id: "tier",
|
|
541
|
-
title: "Performance Tier",
|
|
542
|
-
description: "Select your deployment size",
|
|
543
|
-
},
|
|
544
|
-
{
|
|
545
|
-
id: "features",
|
|
546
|
-
title: "Optional Features",
|
|
547
|
-
description: "Enable additional features",
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
id: "feature-config",
|
|
551
|
-
title: "Feature Settings",
|
|
552
|
-
description: "Configure enabled features",
|
|
553
|
-
},
|
|
554
|
-
{
|
|
555
|
-
id: "credentials",
|
|
556
|
-
title: "License & Version",
|
|
557
|
-
description: "Enter license and select version",
|
|
558
|
-
},
|
|
559
|
-
{
|
|
560
|
-
id: "review",
|
|
561
|
-
title: "Review & Save",
|
|
562
|
-
description: "Review your configuration",
|
|
563
|
-
},
|
|
564
|
-
];
|
|
565
815
|
// Helper to check if DNS provider supports external-dns
|
|
566
816
|
export function isSupportedDnsProvider(provider) {
|
|
567
817
|
return SUPPORTED_DNS_PROVIDERS.includes(provider);
|
|
@@ -590,9 +840,27 @@ export const ProfileConfigSchema = z.object({
|
|
|
590
840
|
openaiApiKey: z.string().optional(),
|
|
591
841
|
licenseKey: z.string().optional(),
|
|
592
842
|
// Preferences
|
|
593
|
-
tier: z.enum(["small", "medium", "large"]).optional(),
|
|
594
843
|
databaseType: z.enum(["self-hosted", "supabase-cloud"]).optional(),
|
|
595
|
-
|
|
844
|
+
storage: z
|
|
845
|
+
.object({
|
|
846
|
+
provider: z.enum(["s3", "azure-blob", "gcs"]),
|
|
847
|
+
cloudAuthMode: z.enum(["workload-identity", "secret"]).optional(),
|
|
848
|
+
bucket: z.string().optional(),
|
|
849
|
+
region: z.string().optional(),
|
|
850
|
+
awsIamRoleArn: z.string().optional(),
|
|
851
|
+
azureBlobClientId: z.string().optional(),
|
|
852
|
+
azureBlobTenantId: z.string().optional(),
|
|
853
|
+
azureBlobConnectionStringSecretRef: SecretKeyRefSchema.optional(),
|
|
854
|
+
azureBlobContainer: z.string().optional(),
|
|
855
|
+
gcpServiceAccountEmail: z.string().optional(),
|
|
856
|
+
paths: z
|
|
857
|
+
.object({
|
|
858
|
+
decisionLogs: z.string().optional(),
|
|
859
|
+
dbBackups: z.string().optional(),
|
|
860
|
+
})
|
|
861
|
+
.optional(),
|
|
862
|
+
})
|
|
863
|
+
.optional(),
|
|
596
864
|
// SSO (optional)
|
|
597
865
|
ssoProvider: z
|
|
598
866
|
.enum(["azure", "google", "okta", "keycloak", "ory", "other"])
|