@rulebricks/cli 2.1.7 → 2.3.2
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 +51 -16
- package/cluster-setup/aws/README.md +96 -47
- package/cluster-setup/aws/check-aws-access.sh +216 -52
- package/cluster-setup/aws/parameters.json +13 -0
- package/cluster-setup/aws/rulebricks-cluster.cfn.yaml +355 -0
- package/cluster-setup/azure/README.md +103 -55
- package/cluster-setup/azure/check-aks-prereqs.sh +236 -56
- package/cluster-setup/azure/parameters.json +30 -0
- package/cluster-setup/azure/rulebricks-cluster.bicep +546 -0
- package/cluster-setup/gcp/README.md +51 -34
- package/cluster-setup/gcp/check-gke-prereqs.sh +222 -60
- 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 -54
- 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 +157 -36
- package/dist/components/Wizard/WizardContext.js +872 -160
- package/dist/components/Wizard/steps/CloudProviderStep.js +192 -107
- 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 +739 -425
- 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 -12
- 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 +1841 -289
- package/dist/lib/helmValues.test.d.ts +1 -0
- package/dist/lib/helmValues.test.js +1012 -0
- package/dist/lib/htpasswd.d.ts +1 -0
- package/dist/lib/htpasswd.js +15 -0
- package/dist/lib/kubernetes.d.ts +124 -17
- package/dist/lib/kubernetes.js +576 -145
- 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 +1860 -164
- package/dist/types/index.js +518 -295
- package/package.json +9 -4
- package/schema/values.schema.json +1934 -0
- package/cluster-setup/aws/cluster.yaml +0 -33
- package/cluster-setup/azure/main.bicep +0 -282
- package/cluster-setup/azure/main.parameters.json +0 -21
- 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/commands/deploy.js
CHANGED
|
@@ -1,74 +1,50 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { Box, Text, useApp
|
|
2
|
+
import { useCallback, useEffect, useState } from "react";
|
|
3
|
+
import { Box, Text, useApp } from "ink";
|
|
4
4
|
import { platform } from "os";
|
|
5
|
-
import { BorderBox, Spinner, StatusLine, ThemeProvider, useTheme, Logo, } from "../components/common/index.js";
|
|
5
|
+
import { BorderBox, Spinner, StatusLine, ThemeProvider, useTheme, Logo, CommandApprovalProvider, } from "../components/common/index.js";
|
|
6
6
|
import { DNSWaitScreen } from "../components/DNSWaitScreen.js";
|
|
7
|
-
import { loadDeploymentConfig, loadDeploymentState, saveDeploymentState, updateDeploymentStatus,
|
|
8
|
-
import { setupTerraformWorkspace, terraformInit, terraformPlan, terraformApply, terraformDestroy, cleanupOrphanedResources, updateKubeconfig, hasTerraformState, isTerraformInstalled, generateTerraformVars, } from "../lib/terraform.js";
|
|
9
|
-
import { checkGcpApplicationDefaultCredentials, checkAzureResourceProviders, checkAzureVmQuota, AZURE_TIER_CORES, } from "../lib/cloudCli.js";
|
|
7
|
+
import { loadDeploymentConfig, loadDeploymentState, loadHelmValues, saveDeploymentState, updateDeploymentStatus, } from "../lib/config.js";
|
|
10
8
|
import { installOrUpgradeChart, upgradeChart, isHelmInstalled, } from "../lib/helm.js";
|
|
9
|
+
import { assertValidHelmValues } from "../lib/validateValues.js";
|
|
11
10
|
import { isKubectlInstalled, checkClusterAccessible, waitForCertificatesReady, } from "../lib/kubernetes.js";
|
|
11
|
+
import { updateKubeconfig, checkAuroraLogicalReplication, } from "../lib/cloudCli.js";
|
|
12
|
+
import { ensureWorkloadIdentityFederation } from "../lib/workloadIdentity.js";
|
|
12
13
|
import { generateHelmValues, updateHelmValuesForTLS, } from "../lib/helmValues.js";
|
|
14
|
+
import { ensureNamespace, applyDeploymentSecrets } from "../lib/secrets.js";
|
|
15
|
+
import { CommandDeniedError } from "../lib/commandApproval.js";
|
|
13
16
|
import { isSupportedDnsProvider, getNamespace, getReleaseName, } from "../types/index.js";
|
|
14
|
-
function
|
|
17
|
+
function getConfigProductVersion(config) {
|
|
18
|
+
return config.version;
|
|
19
|
+
}
|
|
20
|
+
function DeployCommandInner({ name, skipDns, version, regenerateValues = true, assumeDnsConfigured = false, inlineSecrets = false, }) {
|
|
21
|
+
const secretMode = inlineSecrets ? "inline" : "k8s";
|
|
15
22
|
const { exit } = useApp();
|
|
16
23
|
const { colors } = useTheme();
|
|
17
24
|
const [step, setStep] = useState("loading");
|
|
18
25
|
const [config, setConfig] = useState(null);
|
|
19
26
|
const [error, setError] = useState(null);
|
|
20
27
|
const [useExternalDns, setUseExternalDns] = useState(false);
|
|
21
|
-
const infraStartedRef = useRef(false); // Track if we started infra provisioning (ref for sync access)
|
|
22
|
-
const [cleanupError, setCleanupError] = useState(null);
|
|
23
28
|
const [tlsWarning, setTlsWarning] = useState(null);
|
|
29
|
+
const [federationWarning, setFederationWarning] = useState(null);
|
|
24
30
|
const [status, setStatus] = useState({
|
|
25
31
|
preflight: "pending",
|
|
26
|
-
|
|
32
|
+
federation: "pending",
|
|
27
33
|
kubeconfig: "pending",
|
|
28
34
|
helmInstall: "pending",
|
|
29
35
|
certCheck: "pending",
|
|
30
36
|
dnsConfig: "pending",
|
|
31
37
|
helmUpgradeTls: "pending",
|
|
32
38
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
setStep("cleanup-running");
|
|
36
|
-
try {
|
|
37
|
-
const cloudContext = config?.infrastructure.provider && config?.infrastructure.region
|
|
38
|
-
? {
|
|
39
|
-
provider: config.infrastructure.provider,
|
|
40
|
-
clusterName: config.infrastructure.clusterName || `${name}-cluster`,
|
|
41
|
-
region: config.infrastructure.region,
|
|
42
|
-
}
|
|
43
|
-
: undefined;
|
|
44
|
-
await terraformDestroy(name, cloudContext);
|
|
45
|
-
setStep("cleanup-complete");
|
|
46
|
-
setTimeout(() => exit(), 3000);
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
setCleanupError(err instanceof Error ? err.message : "Cleanup failed");
|
|
50
|
-
setStep("cleanup-complete");
|
|
51
|
-
setTimeout(() => exit(), 5000);
|
|
52
|
-
}
|
|
53
|
-
}, [name, config, exit]);
|
|
54
|
-
const skipCleanup = useCallback(() => {
|
|
55
|
-
setStep("error");
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
runDeployment();
|
|
56
41
|
}, []);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
skipCleanup();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
else if (key.escape &&
|
|
67
|
-
(step === "error" || step === "cleanup-complete")) {
|
|
68
|
-
exit();
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
// Resume after DNS wait (manual DNS flow)
|
|
42
|
+
const markRunning = (key) => {
|
|
43
|
+
setStatus((s) => ({ ...s, [key]: "running" }));
|
|
44
|
+
};
|
|
45
|
+
const markSuccess = (key) => {
|
|
46
|
+
setStatus((s) => ({ ...s, [key]: "success" }));
|
|
47
|
+
};
|
|
72
48
|
const handleDnsComplete = useCallback(async () => {
|
|
73
49
|
if (!config)
|
|
74
50
|
return;
|
|
@@ -79,45 +55,21 @@ function DeployCommandInner({ name, skipInfra, skipDns, version, }) {
|
|
|
79
55
|
dnsConfig: "success",
|
|
80
56
|
helmUpgradeTls: "running",
|
|
81
57
|
}));
|
|
82
|
-
// Update helm values to enable TLS
|
|
83
58
|
await updateHelmValuesForTLS(name, true);
|
|
84
59
|
const namespace = getNamespace(config.name);
|
|
85
60
|
const releaseName = getReleaseName(config.name);
|
|
86
|
-
// Upgrade the chart with TLS enabled
|
|
87
61
|
await upgradeChart(name, { releaseName, namespace, version, wait: true });
|
|
88
62
|
setStatus((s) => ({ ...s, helmUpgradeTls: "success", certCheck: "running" }));
|
|
89
63
|
setStep("cert-check");
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
setStatus((s) => ({ ...s, certCheck: "success" }));
|
|
93
|
-
}
|
|
94
|
-
catch (certErr) {
|
|
95
|
-
setStatus((s) => ({ ...s, certCheck: "error" }));
|
|
96
|
-
setTlsWarning("TLS certificates are still being issued. " +
|
|
97
|
-
"HTTPS may not be available yet.");
|
|
98
|
-
}
|
|
99
|
-
// Update state
|
|
100
|
-
await updateDeploymentStatus(name, "running", {
|
|
101
|
-
application: {
|
|
102
|
-
appVersion: config.appVersion || "latest",
|
|
103
|
-
hpsVersion: config.hpsVersion || config.appVersion || "latest",
|
|
104
|
-
chartVersion: version || "latest",
|
|
105
|
-
namespace,
|
|
106
|
-
url: `https://${config.domain}`,
|
|
107
|
-
},
|
|
108
|
-
});
|
|
64
|
+
await verifyCertificates(namespace);
|
|
65
|
+
await markRunningState(config, namespace);
|
|
109
66
|
setStep("complete");
|
|
110
67
|
setTimeout(() => exit(), 5000);
|
|
111
68
|
}
|
|
112
69
|
catch (err) {
|
|
113
|
-
|
|
114
|
-
setError(message);
|
|
115
|
-
setStep("error");
|
|
116
|
-
setStatus((s) => ({ ...s, helmUpgradeTls: "error" }));
|
|
117
|
-
await updateDeploymentStatus(name, "failed");
|
|
70
|
+
await failDeployment(err, "TLS upgrade failed");
|
|
118
71
|
}
|
|
119
72
|
}, [config, name, version, exit]);
|
|
120
|
-
// Skip DNS validation (manual DNS flow)
|
|
121
73
|
const handleDnsSkip = useCallback(async () => {
|
|
122
74
|
if (!config)
|
|
123
75
|
return;
|
|
@@ -128,11 +80,10 @@ function DeployCommandInner({ name, skipInfra, skipDns, version, }) {
|
|
|
128
80
|
certCheck: "skipped",
|
|
129
81
|
}));
|
|
130
82
|
const namespace = getNamespace(config.name);
|
|
131
|
-
|
|
132
|
-
await updateDeploymentStatus(name, "
|
|
83
|
+
const productVersion = getConfigProductVersion(config);
|
|
84
|
+
await updateDeploymentStatus(name, "waiting-dns", {
|
|
133
85
|
application: {
|
|
134
|
-
|
|
135
|
-
hpsVersion: config.hpsVersion || config.appVersion || "latest",
|
|
86
|
+
version: productVersion,
|
|
136
87
|
chartVersion: version || "latest",
|
|
137
88
|
namespace,
|
|
138
89
|
url: `https://${config.domain}`,
|
|
@@ -141,19 +92,12 @@ function DeployCommandInner({ name, skipInfra, skipDns, version, }) {
|
|
|
141
92
|
setStep("complete");
|
|
142
93
|
setTimeout(() => exit(), 5000);
|
|
143
94
|
}, [config, name, version, exit]);
|
|
144
|
-
useEffect(() => {
|
|
145
|
-
runDeployment();
|
|
146
|
-
}, []);
|
|
147
95
|
async function runDeployment() {
|
|
148
96
|
try {
|
|
149
|
-
// Load configuration
|
|
150
97
|
const cfg = await loadDeploymentConfig(name);
|
|
151
98
|
setConfig(cfg);
|
|
152
|
-
// Determine if External DNS is enabled
|
|
153
|
-
// External DNS = supported provider + auto-manage enabled
|
|
154
99
|
const externalDnsEnabled = cfg.dns.autoManage && isSupportedDnsProvider(cfg.dns.provider);
|
|
155
100
|
setUseExternalDns(externalDnsEnabled);
|
|
156
|
-
// Initialize deployment state
|
|
157
101
|
const existingState = await loadDeploymentState(name);
|
|
158
102
|
const state = existingState || {
|
|
159
103
|
name,
|
|
@@ -163,68 +107,41 @@ function DeployCommandInner({ name, skipInfra, skipDns, version, }) {
|
|
|
163
107
|
status: "deploying",
|
|
164
108
|
};
|
|
165
109
|
await saveDeploymentState(name, { ...state, status: "deploying" });
|
|
166
|
-
// Preflight checks
|
|
167
110
|
setStep("preflight");
|
|
168
|
-
|
|
111
|
+
markRunning("preflight");
|
|
169
112
|
await runPreflightChecks(cfg);
|
|
170
|
-
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
// Generate and save terraform variables (always do this before plan,
|
|
183
|
-
// even if state exists, in case config changed)
|
|
184
|
-
const terraformVars = generateTerraformVars(cfg);
|
|
185
|
-
await saveTerraformVars(name, terraformVars);
|
|
186
|
-
setStep("infra-init");
|
|
187
|
-
await terraformInit(name);
|
|
188
|
-
setStep("infra-plan");
|
|
189
|
-
await terraformPlan(name);
|
|
190
|
-
// Clean up orphaned cloud resources from prior failed deployments
|
|
191
|
-
// (e.g. CloudWatch log groups that survived an incomplete destroy)
|
|
192
|
-
if (cfg.infrastructure.provider && cfg.infrastructure.region) {
|
|
193
|
-
await cleanupOrphanedResources(cfg.infrastructure.provider, cfg.infrastructure.clusterName || `${name}-cluster`, cfg.infrastructure.region);
|
|
194
|
-
}
|
|
195
|
-
setStep("infra-apply");
|
|
196
|
-
await terraformApply(name);
|
|
197
|
-
setStatus((s) => ({ ...s, infrastructure: "success" }));
|
|
198
|
-
// Update kubeconfig
|
|
199
|
-
setStep("kubeconfig");
|
|
200
|
-
setStatus((s) => ({ ...s, kubeconfig: "running" }));
|
|
201
|
-
await updateKubeconfig(cfg.infrastructure.provider, cfg.infrastructure.clusterName || `${name}-cluster`, cfg.infrastructure.region, {
|
|
202
|
-
gcpProjectId: cfg.infrastructure.gcpProjectId,
|
|
203
|
-
azureResourceGroup: cfg.infrastructure.azureResourceGroup,
|
|
204
|
-
});
|
|
205
|
-
// Note: StorageClass is managed by the Helm chart, not the CLI
|
|
206
|
-
// This avoids conflicts where kubectl-created resources lack Helm ownership labels
|
|
207
|
-
setStatus((s) => ({ ...s, kubeconfig: "success" }));
|
|
113
|
+
markSuccess("preflight");
|
|
114
|
+
// Ensure the per-namespace workload-identity trust exists. cluster-setup
|
|
115
|
+
// creates the deployment-independent identity; this wires it to this
|
|
116
|
+
// deployment's ServiceAccounts so one cluster can host many deployments.
|
|
117
|
+
setStep("federation");
|
|
118
|
+
markRunning("federation");
|
|
119
|
+
try {
|
|
120
|
+
const federation = await ensureWorkloadIdentityFederation(cfg);
|
|
121
|
+
setStatus((s) => ({
|
|
122
|
+
...s,
|
|
123
|
+
federation: federation.skipped ? "skipped" : "success",
|
|
124
|
+
}));
|
|
208
125
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
126
|
+
catch (federationError) {
|
|
127
|
+
if (!(federationError instanceof CommandDeniedError)) {
|
|
128
|
+
throw federationError;
|
|
129
|
+
}
|
|
130
|
+
setFederationWarning("Workload identity setup was skipped because a cloud CLI command was denied. Continuing assumes you created the trust manually.");
|
|
213
131
|
setStatus((s) => ({
|
|
214
132
|
...s,
|
|
215
|
-
|
|
216
|
-
kubeconfig: s.kubeconfig === "success" ? "success" : "skipped",
|
|
133
|
+
federation: "skipped",
|
|
217
134
|
}));
|
|
218
135
|
}
|
|
219
|
-
// Helm Chart Installation
|
|
220
136
|
setStep("helm-install");
|
|
221
|
-
|
|
137
|
+
markRunning("helmInstall");
|
|
222
138
|
const namespace = getNamespace(cfg.name);
|
|
223
139
|
const releaseName = getReleaseName(cfg.name);
|
|
224
140
|
if (externalDnsEnabled) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
141
|
+
if (regenerateValues) {
|
|
142
|
+
await generateHelmValues(cfg, { tlsEnabled: true, secretMode });
|
|
143
|
+
}
|
|
144
|
+
await ensureGeneratedValuesValid();
|
|
228
145
|
await installOrUpgradeChart(name, {
|
|
229
146
|
releaseName,
|
|
230
147
|
namespace,
|
|
@@ -234,25 +151,59 @@ function DeployCommandInner({ name, skipInfra, skipDns, version, }) {
|
|
|
234
151
|
setStatus((s) => ({
|
|
235
152
|
...s,
|
|
236
153
|
helmInstall: "success",
|
|
237
|
-
dnsConfig: "skipped",
|
|
238
|
-
helmUpgradeTls: "skipped",
|
|
154
|
+
dnsConfig: "skipped",
|
|
155
|
+
helmUpgradeTls: "skipped",
|
|
239
156
|
certCheck: "running",
|
|
240
157
|
}));
|
|
241
158
|
setStep("cert-check");
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
159
|
+
await verifyCertificates(namespace);
|
|
160
|
+
await markRunningState(cfg, namespace);
|
|
161
|
+
setStep("complete");
|
|
162
|
+
setTimeout(() => exit(), 5000);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (regenerateValues) {
|
|
166
|
+
await generateHelmValues(cfg, { tlsEnabled: false, secretMode });
|
|
167
|
+
}
|
|
168
|
+
await ensureGeneratedValuesValid();
|
|
169
|
+
// k8s secret mode: create the namespace + Secrets (idempotent upsert) so
|
|
170
|
+
// they exist before Helm runs and the chart's secretRef seams resolve.
|
|
171
|
+
if (secretMode === "k8s") {
|
|
172
|
+
await ensureNamespace(namespace);
|
|
173
|
+
await applyDeploymentSecrets(cfg, namespace);
|
|
174
|
+
}
|
|
175
|
+
await installOrUpgradeChart(name, {
|
|
176
|
+
releaseName,
|
|
177
|
+
namespace,
|
|
178
|
+
version,
|
|
179
|
+
wait: true,
|
|
180
|
+
});
|
|
181
|
+
markSuccess("helmInstall");
|
|
182
|
+
if (assumeDnsConfigured) {
|
|
183
|
+
setStatus((s) => ({
|
|
184
|
+
...s,
|
|
185
|
+
dnsConfig: "skipped",
|
|
186
|
+
helmUpgradeTls: "skipped",
|
|
187
|
+
certCheck: "running",
|
|
188
|
+
}));
|
|
189
|
+
setStep("cert-check");
|
|
190
|
+
await verifyCertificates(namespace);
|
|
191
|
+
await markRunningState(cfg, namespace);
|
|
192
|
+
setStep("complete");
|
|
193
|
+
setTimeout(() => exit(), 5000);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (skipDns) {
|
|
197
|
+
setStatus((s) => ({
|
|
198
|
+
...s,
|
|
199
|
+
dnsConfig: "skipped",
|
|
200
|
+
helmUpgradeTls: "skipped",
|
|
201
|
+
certCheck: "skipped",
|
|
202
|
+
}));
|
|
203
|
+
const productVersion = getConfigProductVersion(cfg);
|
|
204
|
+
await updateDeploymentStatus(name, "waiting-dns", {
|
|
253
205
|
application: {
|
|
254
|
-
|
|
255
|
-
hpsVersion: cfg.hpsVersion || cfg.appVersion || "latest",
|
|
206
|
+
version: productVersion,
|
|
256
207
|
chartVersion: version || "latest",
|
|
257
208
|
namespace,
|
|
258
209
|
url: `https://${cfg.domain}`,
|
|
@@ -260,65 +211,28 @@ function DeployCommandInner({ name, skipInfra, skipDns, version, }) {
|
|
|
260
211
|
});
|
|
261
212
|
setStep("complete");
|
|
262
213
|
setTimeout(() => exit(), 5000);
|
|
214
|
+
return;
|
|
263
215
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
await generateHelmValues(cfg, { tlsEnabled: false });
|
|
268
|
-
await installOrUpgradeChart(name, {
|
|
269
|
-
releaseName,
|
|
270
|
-
namespace,
|
|
271
|
-
version,
|
|
272
|
-
wait: true,
|
|
273
|
-
});
|
|
274
|
-
setStatus((s) => ({ ...s, helmInstall: "success" }));
|
|
275
|
-
// If skipping DNS, go straight to complete
|
|
276
|
-
if (skipDns) {
|
|
277
|
-
setStatus((s) => ({
|
|
278
|
-
...s,
|
|
279
|
-
dnsConfig: "skipped",
|
|
280
|
-
helmUpgradeTls: "skipped",
|
|
281
|
-
certCheck: "skipped",
|
|
282
|
-
}));
|
|
283
|
-
await updateDeploymentStatus(name, "waiting-dns", {
|
|
284
|
-
application: {
|
|
285
|
-
appVersion: cfg.appVersion || "latest",
|
|
286
|
-
hpsVersion: cfg.hpsVersion || cfg.appVersion || "latest",
|
|
287
|
-
chartVersion: version || "latest",
|
|
288
|
-
namespace,
|
|
289
|
-
url: `https://${cfg.domain}`,
|
|
290
|
-
},
|
|
291
|
-
});
|
|
292
|
-
setStep("complete");
|
|
293
|
-
setTimeout(() => exit(), 5000);
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
// Update state to waiting for DNS
|
|
297
|
-
await updateDeploymentStatus(name, "waiting-dns");
|
|
298
|
-
// Phase 2: DNS configuration wait
|
|
299
|
-
setStep("dns-wait");
|
|
300
|
-
setStatus((s) => ({ ...s, dnsConfig: "running" }));
|
|
301
|
-
}
|
|
216
|
+
await updateDeploymentStatus(name, "waiting-dns");
|
|
217
|
+
setStep("dns-wait");
|
|
218
|
+
markRunning("dnsConfig");
|
|
302
219
|
}
|
|
303
220
|
catch (err) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
221
|
+
await failDeployment(err, "Unknown error");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Guardrail: validate the values we're about to install against the chart's
|
|
225
|
+
// bundled schema. Catches reused/hand-edited values too (regenerateValues=false).
|
|
226
|
+
async function ensureGeneratedValuesValid() {
|
|
227
|
+
const values = await loadHelmValues(name);
|
|
228
|
+
if (values) {
|
|
229
|
+
assertValidHelmValues(values);
|
|
314
230
|
}
|
|
315
231
|
}
|
|
316
232
|
async function runPreflightChecks(cfg) {
|
|
317
|
-
|
|
318
|
-
const [helm, kubectl, terraform] = await Promise.all([
|
|
233
|
+
const [helm, kubectl] = await Promise.all([
|
|
319
234
|
isHelmInstalled(),
|
|
320
235
|
isKubectlInstalled(),
|
|
321
|
-
isTerraformInstalled(),
|
|
322
236
|
]);
|
|
323
237
|
if (!helm) {
|
|
324
238
|
throw new Error("Helm is not installed. Please install Helm first.");
|
|
@@ -326,141 +240,135 @@ function DeployCommandInner({ name, skipInfra, skipDns, version, }) {
|
|
|
326
240
|
if (!kubectl) {
|
|
327
241
|
throw new Error("kubectl is not installed. Please install kubectl first.");
|
|
328
242
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
// 1. Verify resource providers are registered
|
|
350
|
-
const providerCheck = await checkAzureResourceProviders();
|
|
351
|
-
if (!providerCheck.allRegistered) {
|
|
352
|
-
throw new Error(`Azure resource providers not registered: ${providerCheck.missing.join(", ")}\n\n` +
|
|
353
|
-
"To register:\n" +
|
|
354
|
-
providerCheck.missing
|
|
355
|
-
.map((p) => ` • az provider register --namespace ${p}`)
|
|
356
|
-
.join("\n") +
|
|
357
|
-
"\n\nNote: Registration may take a few minutes to complete.");
|
|
358
|
-
}
|
|
359
|
-
// 2. Check VM quota for the selected tier
|
|
360
|
-
const tier = cfg.tier || "small";
|
|
361
|
-
const region = cfg.infrastructure.region;
|
|
362
|
-
if (!region) {
|
|
363
|
-
throw new Error("Azure region is required for infrastructure provisioning");
|
|
364
|
-
}
|
|
365
|
-
const requiredCores = AZURE_TIER_CORES[tier] || AZURE_TIER_CORES.small;
|
|
366
|
-
const quotaCheck = await checkAzureVmQuota(region, requiredCores);
|
|
367
|
-
if (!quotaCheck.sufficient) {
|
|
368
|
-
throw new Error(`Insufficient Azure vCPU quota in ${region}.\n` +
|
|
369
|
-
`Required: ${requiredCores} cores (${tier} tier), Available: ${quotaCheck.available}/${quotaCheck.limit}\n\n` +
|
|
370
|
-
"Request a quota increase in the Azure portal:\n" +
|
|
371
|
-
" • Go to: Subscriptions > Usage + quotas\n" +
|
|
372
|
-
" • Request increase for 'Total Regional vCPUs' in your region");
|
|
243
|
+
let clusterError = await checkClusterAccessible();
|
|
244
|
+
if (clusterError &&
|
|
245
|
+
cfg.infrastructure.provider &&
|
|
246
|
+
cfg.infrastructure.region &&
|
|
247
|
+
cfg.infrastructure.clusterName) {
|
|
248
|
+
try {
|
|
249
|
+
setStep("kubeconfig");
|
|
250
|
+
setStatus((s) => ({
|
|
251
|
+
...s,
|
|
252
|
+
preflight: "success",
|
|
253
|
+
kubeconfig: "running",
|
|
254
|
+
}));
|
|
255
|
+
await updateKubeconfig(cfg.infrastructure.provider, cfg.infrastructure.clusterName, cfg.infrastructure.region, {
|
|
256
|
+
gcpProjectId: cfg.infrastructure.gcpProjectId,
|
|
257
|
+
azureResourceGroup: cfg.infrastructure.azureResourceGroup,
|
|
258
|
+
});
|
|
259
|
+
clusterError = await checkClusterAccessible();
|
|
260
|
+
if (!clusterError) {
|
|
261
|
+
markSuccess("kubeconfig");
|
|
262
|
+
}
|
|
373
263
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if (cfg.infrastructure.mode === "existing") {
|
|
377
|
-
let clusterError = await checkClusterAccessible();
|
|
378
|
-
// If cluster not accessible but we have provider details, try updating kubeconfig
|
|
379
|
-
if (clusterError &&
|
|
380
|
-
cfg.infrastructure.provider &&
|
|
381
|
-
cfg.infrastructure.region &&
|
|
382
|
-
cfg.infrastructure.clusterName) {
|
|
383
|
-
try {
|
|
384
|
-
// Show visual feedback for kubeconfig update
|
|
385
|
-
setStep("kubeconfig");
|
|
386
|
-
setStatus((s) => ({
|
|
387
|
-
...s,
|
|
388
|
-
preflight: "success",
|
|
389
|
-
kubeconfig: "running",
|
|
390
|
-
}));
|
|
391
|
-
await updateKubeconfig(cfg.infrastructure.provider, cfg.infrastructure.clusterName, cfg.infrastructure.region, {
|
|
392
|
-
gcpProjectId: cfg.infrastructure.gcpProjectId,
|
|
393
|
-
azureResourceGroup: cfg.infrastructure.azureResourceGroup,
|
|
394
|
-
});
|
|
395
|
-
// Retry cluster access check
|
|
264
|
+
catch (kubeconfigError) {
|
|
265
|
+
if (kubeconfigError instanceof CommandDeniedError) {
|
|
396
266
|
clusterError = await checkClusterAccessible();
|
|
397
267
|
if (!clusterError) {
|
|
398
|
-
|
|
268
|
+
markSuccess("kubeconfig");
|
|
269
|
+
return;
|
|
399
270
|
}
|
|
400
271
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
`Cluster error: ${clusterError}\n` +
|
|
408
|
-
`Kubeconfig update error: ${kubeconfigMsg}`);
|
|
409
|
-
}
|
|
272
|
+
const kubeconfigMsg = kubeconfigError instanceof Error
|
|
273
|
+
? kubeconfigError.message
|
|
274
|
+
: "Unknown error";
|
|
275
|
+
throw new Error(`Cannot access Kubernetes cluster and kubeconfig refresh failed:\n` +
|
|
276
|
+
`Cluster error: ${clusterError}\n` +
|
|
277
|
+
`Kubeconfig error: ${kubeconfigMsg}`);
|
|
410
278
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
279
|
+
}
|
|
280
|
+
if (clusterError) {
|
|
281
|
+
throw new Error(`Cannot access Kubernetes cluster:\n${clusterError}`);
|
|
282
|
+
}
|
|
283
|
+
setStatus((s) => ({
|
|
284
|
+
...s,
|
|
285
|
+
kubeconfig: s.kubeconfig === "success" ? "success" : "skipped",
|
|
286
|
+
}));
|
|
287
|
+
// External AWS Aurora needs logical replication for Supabase Realtime - a
|
|
288
|
+
// static cluster parameter bootstrap.sql can't set - so catch it here before
|
|
289
|
+
// a long deploy ends in a Realtime crashloop. Fail-open: the check returns
|
|
290
|
+
// "unknown" (and we proceed) on any ambiguity; we only block when the
|
|
291
|
+
// parameter is definitively off.
|
|
292
|
+
const pg = cfg.externalServices?.postgres;
|
|
293
|
+
if (pg?.mode === "external" &&
|
|
294
|
+
pg.external?.provider === "aws" &&
|
|
295
|
+
pg.external.host) {
|
|
296
|
+
const lr = await checkAuroraLogicalReplication(pg.external.host, cfg.infrastructure.region);
|
|
297
|
+
if (lr.status === "disabled") {
|
|
298
|
+
const pgName = lr.parameterGroup ?? "<db-cluster-parameter-group>";
|
|
299
|
+
throw new Error("External Aurora Postgres has logical replication DISABLED" +
|
|
300
|
+
(lr.parameterGroup ? ` (parameter group ${lr.parameterGroup})` : "") +
|
|
301
|
+
". Supabase Realtime requires it, and rds.logical_replication is a " +
|
|
302
|
+
"static parameter the chart's bootstrap cannot set. Enable it, then " +
|
|
303
|
+
"reboot the writer, before deploying:\n" +
|
|
304
|
+
` aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name ${pgName} \\\n` +
|
|
305
|
+
' --parameters "ParameterName=rds.logical_replication,ParameterValue=1,ApplyMethod=pending-reboot"\n' +
|
|
306
|
+
" aws rds reboot-db-instance --db-instance-identifier <writer-instance>\n" +
|
|
307
|
+
"(If the cluster uses a default parameter group, create a custom one first and attach it.)");
|
|
421
308
|
}
|
|
422
309
|
}
|
|
423
310
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
311
|
+
async function verifyCertificates(namespace) {
|
|
312
|
+
try {
|
|
313
|
+
await waitForCertificatesReady(namespace);
|
|
314
|
+
markSuccess("certCheck");
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
setStatus((s) => ({ ...s, certCheck: "error" }));
|
|
318
|
+
setTlsWarning("TLS certificates are still being issued. HTTPS may not be available yet.");
|
|
319
|
+
}
|
|
427
320
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
321
|
+
async function markRunningState(cfg, namespace) {
|
|
322
|
+
const productVersion = getConfigProductVersion(cfg);
|
|
323
|
+
await updateDeploymentStatus(name, "running", {
|
|
324
|
+
application: {
|
|
325
|
+
version: productVersion,
|
|
326
|
+
chartVersion: version || "latest",
|
|
327
|
+
namespace,
|
|
328
|
+
url: `https://${cfg.domain}`,
|
|
329
|
+
},
|
|
330
|
+
});
|
|
431
331
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
332
|
+
async function failDeployment(err, fallback) {
|
|
333
|
+
const message = err instanceof Error ? err.message : fallback;
|
|
334
|
+
setError(message);
|
|
335
|
+
setStep("error");
|
|
336
|
+
setStatus((s) => ({
|
|
337
|
+
...s,
|
|
338
|
+
preflight: step === "preflight" ? "error" : s.preflight,
|
|
339
|
+
federation: step === "federation" ? "error" : s.federation,
|
|
340
|
+
helmInstall: step === "helm-install" ? "error" : s.helmInstall,
|
|
341
|
+
helmUpgradeTls: step === "helm-upgrade-tls" ? "error" : s.helmUpgradeTls,
|
|
342
|
+
}));
|
|
343
|
+
await updateDeploymentStatus(name, "failed");
|
|
435
344
|
}
|
|
436
|
-
// Error screen (non-infra failures or when user skips cleanup)
|
|
437
345
|
if (step === "error") {
|
|
438
|
-
// Format error message, preserving newlines for multi-line errors
|
|
439
346
|
const errorLines = error?.split("\n") || ["Unknown error"];
|
|
440
|
-
return (_jsx(BorderBox, { title: "Deployment Failed", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: colors.error, bold: true, children: "\u2717 Error" }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: errorLines.map((line, i) => (_jsx(Text, { color: line.startsWith(" •") ? colors.muted : colors.error, children: line }, i))) })
|
|
347
|
+
return (_jsx(BorderBox, { title: "Deployment Failed", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: colors.error, bold: true, children: "\u2717 Error" }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: errorLines.map((line, i) => (_jsx(Text, { color: line.startsWith(" •") ? colors.muted : colors.error, children: line }, i))) })] }) }));
|
|
441
348
|
}
|
|
442
|
-
// DNS wait screen (only for manual DNS flow)
|
|
443
349
|
if (step === "dns-wait" && config) {
|
|
444
|
-
return (_jsx(DNSWaitScreen, { domain: config.domain, selfHostedSupabase: config.database.type === "self-hosted",
|
|
350
|
+
return (_jsx(DNSWaitScreen, { domain: config.domain, selfHostedSupabase: config.database.type === "self-hosted", builtInObservability: config.features.observability?.clickstack?.enabled ?? true, valkeyAdminIngress: config.features.cache?.valkeyAdmin?.enabled === true &&
|
|
351
|
+
config.features.cache.valkeyAdmin.exposure === "ingress", valkeyAdminHostname: config.features.cache?.valkeyAdmin?.hostname, namespace: getNamespace(config.name), onComplete: handleDnsComplete, onSkip: handleDnsSkip }));
|
|
445
352
|
}
|
|
446
|
-
// Complete screen
|
|
447
353
|
if (step === "complete") {
|
|
448
|
-
const tlsSkipped = status.helmUpgradeTls === "skipped" &&
|
|
449
|
-
|
|
354
|
+
const tlsSkipped = status.helmUpgradeTls === "skipped" &&
|
|
355
|
+
!useExternalDns &&
|
|
356
|
+
!assumeDnsConfigured;
|
|
357
|
+
return (_jsx(BorderBox, { title: "Deployment Complete", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: colors.success, bold: true, children: "\u2713 Rulebricks deployed successfully!" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: ["URL:", " ", _jsxs(Text, { color: colors.accent, children: ["https://", config?.domain, "/auth/signup"] })] }), useExternalDns && (_jsx(Text, { color: colors.muted, children: "DNS records will be created automatically by external-dns" })), tlsSkipped && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.warning, children: ["\u26A0 TLS not configured. Run `rulebricks deploy ", name, "` again after DNS setup."] }) })), tlsWarning && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.warning, children: ["\u26A0 ", tlsWarning] }) })), federationWarning && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.warning, children: ["\u26A0 ", federationWarning] }) }))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Next steps:" }), _jsx(Text, { color: colors.muted, children: " \u2022 Visit the URL to complete setup" }), _jsxs(Text, { color: colors.muted, children: [" ", "\u2022 Run `rulebricks status ", name, "` to check deployment health"] }), tlsSkipped && (_jsxs(Text, { color: colors.muted, children: [" ", "\u2022 Configure DNS and re-run deploy for TLS"] }))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.muted, dimColor: true, children: "Tip: If the URL isn't accessible yet, your local DNS may need time to propagate." }), _jsxs(Text, { color: colors.muted, dimColor: true, children: ["Flush DNS cache: ", getDnsFlushCommand()] })] })] }) }));
|
|
450
358
|
}
|
|
451
|
-
// Progress screen
|
|
452
359
|
const helmInstallLabel = useExternalDns
|
|
453
360
|
? "Helm chart installation (with TLS)"
|
|
454
361
|
: "Helm chart installation";
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
362
|
+
// The federation step does the cloud-appropriate per-namespace identity wiring;
|
|
363
|
+
// label it for the cluster's cloud so it's clear what's happening.
|
|
364
|
+
const federationLabel = config?.infrastructure.provider === "aws"
|
|
365
|
+
? "EKS Pod Identity associations"
|
|
366
|
+
: config?.infrastructure.provider === "gcp"
|
|
367
|
+
? "Workload Identity bindings"
|
|
368
|
+
: config?.infrastructure.provider === "azure"
|
|
369
|
+
? "Azure federated identity credentials"
|
|
370
|
+
: "Workload identity setup";
|
|
371
|
+
return (_jsx(BorderBox, { title: `Deploying ${name}`, children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(StatusLine, { status: status.preflight, label: "Preflight checks" }), _jsx(StatusLine, { status: status.kubeconfig, label: "Kubernetes configuration" }), _jsx(StatusLine, { status: status.federation, label: federationLabel }), federationWarning && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: colors.warning, children: federationWarning }) })), _jsx(StatusLine, { status: status.helmInstall, label: helmInstallLabel }), !useExternalDns && (_jsxs(_Fragment, { children: [_jsx(StatusLine, { status: status.dnsConfig, label: "DNS configuration" }), _jsx(StatusLine, { status: status.helmUpgradeTls, label: "TLS configuration" })] })), _jsx(StatusLine, { status: status.certCheck, label: "TLS certificate verification" }), _jsx(Box, { marginTop: 1, children: _jsx(Spinner, { label: getStepLabel(step, useExternalDns) }) })] }) }));
|
|
464
372
|
}
|
|
465
373
|
function getDnsFlushCommand() {
|
|
466
374
|
switch (platform()) {
|
|
@@ -478,16 +386,8 @@ function getStepLabel(step, useExternalDns) {
|
|
|
478
386
|
return "Loading configuration...";
|
|
479
387
|
case "preflight":
|
|
480
388
|
return "Running preflight checks...";
|
|
481
|
-
case "infra-setup":
|
|
482
|
-
return "Setting up Terraform workspace...";
|
|
483
|
-
case "infra-init":
|
|
484
|
-
return "Initializing Terraform...";
|
|
485
|
-
case "infra-plan":
|
|
486
|
-
return "Planning infrastructure changes...";
|
|
487
|
-
case "infra-apply":
|
|
488
|
-
return "Creating infrastructure (may take up to 15 minutes)...";
|
|
489
389
|
case "kubeconfig":
|
|
490
|
-
return "
|
|
390
|
+
return "Refreshing kubeconfig...";
|
|
491
391
|
case "helm-install":
|
|
492
392
|
return useExternalDns
|
|
493
393
|
? "Installing Helm chart with TLS..."
|
|
@@ -503,5 +403,5 @@ function getStepLabel(step, useExternalDns) {
|
|
|
503
403
|
}
|
|
504
404
|
}
|
|
505
405
|
export function DeployCommand(props) {
|
|
506
|
-
return (_jsxs(ThemeProvider, { theme: "deploy", children: [_jsx(Logo, {}), _jsx(DeployCommandInner, { ...props })] }));
|
|
406
|
+
return (_jsxs(ThemeProvider, { theme: "deploy", children: [_jsx(Logo, {}), _jsx(CommandApprovalProvider, { children: _jsx(DeployCommandInner, { ...props }) })] }));
|
|
507
407
|
}
|