@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
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Box, Text, useApp } from "ink";
|
|
4
|
+
import { BorderBox, Logo, Spinner, ThemeProvider, useTheme, } from "../components/common/index.js";
|
|
5
|
+
import { listDeployments } from "../lib/config.js";
|
|
6
|
+
import { loadDeploymentHealth, } from "../lib/deploymentHealth.js";
|
|
7
|
+
function statusText(health) {
|
|
8
|
+
switch (health.kind) {
|
|
9
|
+
case "online":
|
|
10
|
+
return { icon: "●", label: "online", color: "green" };
|
|
11
|
+
case "installed-unreachable":
|
|
12
|
+
return { icon: "◐", label: "installed, URL unreachable", color: "yellow" };
|
|
13
|
+
case "installed-degraded":
|
|
14
|
+
return { icon: "◐", label: "installed, pods not ready", color: "yellow" };
|
|
15
|
+
case "cluster-unreachable":
|
|
16
|
+
return { icon: "?", label: "cluster unreachable", color: "yellow" };
|
|
17
|
+
case "destroyed":
|
|
18
|
+
return { icon: "○", label: "destroyed", color: "gray" };
|
|
19
|
+
case "not-installed":
|
|
20
|
+
return { icon: "○", label: "not installed", color: "gray" };
|
|
21
|
+
case "config-error":
|
|
22
|
+
return { icon: "✗", label: "config error", color: "red" };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function ListCommandInner() {
|
|
26
|
+
const { exit } = useApp();
|
|
27
|
+
const { colors } = useTheme();
|
|
28
|
+
const [step, setStep] = useState("loading");
|
|
29
|
+
const [loadingLabel, setLoadingLabel] = useState("Loading deployments...");
|
|
30
|
+
const [deployments, setDeployments] = useState([]);
|
|
31
|
+
const [error, setError] = useState(null);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
(async () => {
|
|
34
|
+
try {
|
|
35
|
+
const names = await listDeployments();
|
|
36
|
+
if (names.length === 0) {
|
|
37
|
+
setStep("empty");
|
|
38
|
+
setTimeout(() => exit(), 250);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
setLoadingLabel(`Checking health for ${names.length} deployment(s)...`);
|
|
42
|
+
const results = [];
|
|
43
|
+
for (const name of names) {
|
|
44
|
+
setLoadingLabel(`Checking ${name}...`);
|
|
45
|
+
results.push(await loadDeploymentHealth(name));
|
|
46
|
+
}
|
|
47
|
+
setDeployments(results);
|
|
48
|
+
setStep("complete");
|
|
49
|
+
setTimeout(() => exit(), 250);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
setError(err instanceof Error ? err.message : "Failed to list deployments");
|
|
53
|
+
setStep("error");
|
|
54
|
+
setTimeout(() => exit(), 1000);
|
|
55
|
+
}
|
|
56
|
+
})();
|
|
57
|
+
}, [exit]);
|
|
58
|
+
if (step === "loading") {
|
|
59
|
+
return (_jsx(BorderBox, { title: "Deployments", children: _jsx(Box, { marginY: 1, children: _jsx(Spinner, { label: loadingLabel }) }) }));
|
|
60
|
+
}
|
|
61
|
+
if (step === "empty") {
|
|
62
|
+
return (_jsx(BorderBox, { title: "Deployments", children: _jsx(Box, { marginY: 1, children: _jsx(Text, { color: colors.warning, children: "No deployments found. Run \"rulebricks init\" to create one." }) }) }));
|
|
63
|
+
}
|
|
64
|
+
if (step === "error") {
|
|
65
|
+
return (_jsx(BorderBox, { title: "List Failed", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: colors.error, bold: true, children: "\u2717 Error" }), _jsx(Text, { color: colors.error, children: error })] }) }));
|
|
66
|
+
}
|
|
67
|
+
return (_jsx(BorderBox, { title: "Deployments", children: _jsx(Box, { flexDirection: "column", marginY: 1, children: deployments.map((deployment) => {
|
|
68
|
+
const status = statusText(deployment);
|
|
69
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: status.color, children: status.icon }), _jsxs(Text, { children: [" ", deployment.name, " "] }), _jsx(Text, { color: status.color, children: status.label }), deployment.url && (_jsxs(Text, { color: colors.muted, children: [" ", deployment.url] }))] }, deployment.name));
|
|
70
|
+
}) }) }));
|
|
71
|
+
}
|
|
72
|
+
export function ListCommand() {
|
|
73
|
+
return (_jsxs(ThemeProvider, { theme: "status", children: [_jsx(Logo, {}), _jsx(ListCommandInner, {})] }));
|
|
74
|
+
}
|
package/dist/commands/open.d.ts
CHANGED
package/dist/commands/open.js
CHANGED
|
@@ -5,7 +5,7 @@ import { spawn } from "child_process";
|
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { promises as fs } from "fs";
|
|
7
7
|
import { BorderBox, Spinner, ThemeProvider, useTheme, Logo, } from "../components/common/index.js";
|
|
8
|
-
import { deploymentExists, getDeploymentDir,
|
|
8
|
+
import { deploymentExists, getDeploymentDir, getHelmValuesPath, } from "../lib/config.js";
|
|
9
9
|
/**
|
|
10
10
|
* Resolves the appropriate command to open files/directories based on OS and environment
|
|
11
11
|
*/
|
|
@@ -72,9 +72,6 @@ function OpenCommandInner({ name, target }) {
|
|
|
72
72
|
case "values":
|
|
73
73
|
targetPath = getHelmValuesPath(name);
|
|
74
74
|
break;
|
|
75
|
-
case "terraform":
|
|
76
|
-
targetPath = getTerraformDir(name);
|
|
77
|
-
break;
|
|
78
75
|
case "all":
|
|
79
76
|
default:
|
|
80
77
|
targetPath = deployDir;
|
|
@@ -85,10 +82,7 @@ function OpenCommandInner({ name, target }) {
|
|
|
85
82
|
await fs.access(targetPath);
|
|
86
83
|
}
|
|
87
84
|
catch {
|
|
88
|
-
if (target === "
|
|
89
|
-
setError(`Terraform directory not found. Run "rulebricks deploy ${name}" first to create infrastructure files.`);
|
|
90
|
-
}
|
|
91
|
-
else if (target === "values") {
|
|
85
|
+
if (target === "values") {
|
|
92
86
|
setError(`values.yaml not found. Run "rulebricks init" or "rulebricks deploy ${name}" first.`);
|
|
93
87
|
}
|
|
94
88
|
else {
|
|
@@ -129,10 +123,8 @@ function OpenCommandInner({ name, target }) {
|
|
|
129
123
|
? "deployment directory"
|
|
130
124
|
: target === "config"
|
|
131
125
|
? "config.yaml"
|
|
132
|
-
:
|
|
133
|
-
|
|
134
|
-
: "terraform directory";
|
|
135
|
-
return (_jsx(BorderBox, { title: "Opened", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { color: colors.success, bold: true, children: ["\u2713 Opened ", targetLabel] }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.muted, dimColor: true, children: ["Path: ", openedPath] }) }), target === "all" && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.muted, children: "Available files:" }), _jsxs(Text, { color: colors.muted, children: [" ", "\u2022 config.yaml - Deployment configuration"] }), _jsx(Text, { color: colors.muted, children: " \u2022 values.yaml - Helm chart values" }), _jsxs(Text, { color: colors.muted, children: [" ", "\u2022 terraform/ - Infrastructure files"] })] })), (target === "values" || target === "config") && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.warning, dimColor: true, children: "Note: Manual edits may desync from wizard-managed settings" }) }))] }) }));
|
|
126
|
+
: "values.yaml";
|
|
127
|
+
return (_jsx(BorderBox, { title: "Opened", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsxs(Text, { color: colors.success, bold: true, children: ["\u2713 Opened ", targetLabel] }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.muted, dimColor: true, children: ["Path: ", openedPath] }) }), target === "all" && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.muted, children: "Available files:" }), _jsxs(Text, { color: colors.muted, children: [" ", "\u2022 config.yaml - Deployment configuration"] }), _jsx(Text, { color: colors.muted, children: " \u2022 values.yaml - Helm chart values" })] })), (target === "values" || target === "config") && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.warning, dimColor: true, children: "Note: Manual edits may desync from wizard-managed settings" }) }))] }) }));
|
|
136
128
|
}
|
|
137
129
|
export function OpenCommand(props) {
|
|
138
130
|
return (_jsxs(ThemeProvider, { theme: "status", children: [_jsx(Logo, {}), _jsx(OpenCommandInner, { ...props })] }));
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
import { BorderBox, Logo, Spinner, ThemeProvider, useTheme, } from "../components/common/index.js";
|
|
5
|
+
import { InitWizard } from "./init.js";
|
|
6
|
+
import { DeployCommand } from "./deploy.js";
|
|
7
|
+
import { configToWizardState, } from "../components/Wizard/WizardContext.js";
|
|
8
|
+
import { loadHelmValues, loadProfile, } from "../lib/config.js";
|
|
9
|
+
import { loadDeploymentHealth } from "../lib/deploymentHealth.js";
|
|
10
|
+
import { getInstalledChartVersion } from "../lib/helm.js";
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
function stringValue(value) {
|
|
15
|
+
return typeof value === "string" && value ? value : undefined;
|
|
16
|
+
}
|
|
17
|
+
function numberValue(value) {
|
|
18
|
+
return typeof value === "number" ? value : undefined;
|
|
19
|
+
}
|
|
20
|
+
function booleanValue(value) {
|
|
21
|
+
return typeof value === "boolean" ? value : undefined;
|
|
22
|
+
}
|
|
23
|
+
function secretRefValue(value) {
|
|
24
|
+
if (!isRecord(value))
|
|
25
|
+
return undefined;
|
|
26
|
+
const name = stringValue(value.name);
|
|
27
|
+
const key = stringValue(value.key);
|
|
28
|
+
return name && key ? { name, key } : undefined;
|
|
29
|
+
}
|
|
30
|
+
function applyHelmValuesToConfig(config, values) {
|
|
31
|
+
const next = JSON.parse(JSON.stringify(config));
|
|
32
|
+
if (!values)
|
|
33
|
+
return next;
|
|
34
|
+
const global = isRecord(values.global) ? values.global : null;
|
|
35
|
+
if (global) {
|
|
36
|
+
next.domain = stringValue(global.domain) ?? next.domain;
|
|
37
|
+
next.adminEmail = stringValue(global.email) ?? next.adminEmail;
|
|
38
|
+
next.licenseKey = stringValue(global.licenseKey) ?? next.licenseKey;
|
|
39
|
+
next.version = stringValue(global.version) ?? next.version;
|
|
40
|
+
if (isRecord(global.smtp)) {
|
|
41
|
+
next.smtp = {
|
|
42
|
+
...next.smtp,
|
|
43
|
+
host: stringValue(global.smtp.host) ?? next.smtp.host,
|
|
44
|
+
port: numberValue(global.smtp.port) ?? next.smtp.port,
|
|
45
|
+
user: stringValue(global.smtp.user) ?? next.smtp.user,
|
|
46
|
+
pass: stringValue(global.smtp.pass) ?? next.smtp.pass,
|
|
47
|
+
from: stringValue(global.smtp.from) ?? next.smtp.from,
|
|
48
|
+
fromName: stringValue(global.smtp.fromName) ?? next.smtp.fromName,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (isRecord(global.supabase)) {
|
|
52
|
+
if (next.database.type === "supabase-cloud") {
|
|
53
|
+
next.database.supabaseUrl =
|
|
54
|
+
stringValue(global.supabase.url) ?? next.database.supabaseUrl;
|
|
55
|
+
next.database.supabaseAnonKey =
|
|
56
|
+
stringValue(global.supabase.anonKey) ??
|
|
57
|
+
next.database.supabaseAnonKey;
|
|
58
|
+
next.database.supabaseServiceKey =
|
|
59
|
+
stringValue(global.supabase.serviceKey) ??
|
|
60
|
+
next.database.supabaseServiceKey;
|
|
61
|
+
next.database.supabaseAccessToken =
|
|
62
|
+
stringValue(global.supabase.accessToken) ??
|
|
63
|
+
next.database.supabaseAccessToken;
|
|
64
|
+
next.database.supabaseProjectRef =
|
|
65
|
+
stringValue(global.supabase.projectRef) ??
|
|
66
|
+
next.database.supabaseProjectRef;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
next.database.supabaseJwtSecret =
|
|
70
|
+
stringValue(global.supabase.jwtSecret) ??
|
|
71
|
+
next.database.supabaseJwtSecret;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (isRecord(global.ai)) {
|
|
75
|
+
next.features.ai.enabled =
|
|
76
|
+
booleanValue(global.ai.enabled) ?? next.features.ai.enabled;
|
|
77
|
+
next.features.ai.openaiApiKey =
|
|
78
|
+
stringValue(global.ai.openaiApiKey) ??
|
|
79
|
+
next.features.ai.openaiApiKey;
|
|
80
|
+
}
|
|
81
|
+
if (isRecord(global.sso)) {
|
|
82
|
+
next.features.sso.enabled =
|
|
83
|
+
booleanValue(global.sso.enabled) ?? next.features.sso.enabled;
|
|
84
|
+
next.features.sso.provider =
|
|
85
|
+
stringValue(global.sso.provider) ??
|
|
86
|
+
next.features.sso.provider;
|
|
87
|
+
next.features.sso.url =
|
|
88
|
+
stringValue(global.sso.url) ?? next.features.sso.url;
|
|
89
|
+
next.features.sso.clientId =
|
|
90
|
+
stringValue(global.sso.clientId) ?? next.features.sso.clientId;
|
|
91
|
+
next.features.sso.clientSecret =
|
|
92
|
+
stringValue(global.sso.clientSecret) ??
|
|
93
|
+
next.features.sso.clientSecret;
|
|
94
|
+
}
|
|
95
|
+
if (isRecord(global.storage) && next.storage) {
|
|
96
|
+
const storage = global.storage;
|
|
97
|
+
next.storage.provider =
|
|
98
|
+
stringValue(storage.provider) ??
|
|
99
|
+
next.storage.provider;
|
|
100
|
+
next.storage.bucket =
|
|
101
|
+
stringValue(storage.bucket) ?? next.storage.bucket;
|
|
102
|
+
next.storage.region =
|
|
103
|
+
stringValue(storage.region) ?? next.storage.region;
|
|
104
|
+
if (isRecord(storage.s3)) {
|
|
105
|
+
next.storage.awsIamRoleArn =
|
|
106
|
+
stringValue(storage.s3.iamRoleArn) ?? next.storage.awsIamRoleArn;
|
|
107
|
+
}
|
|
108
|
+
if (isRecord(storage.azure)) {
|
|
109
|
+
next.storage.cloudAuthMode =
|
|
110
|
+
storage.azure.authMode === "connection-string"
|
|
111
|
+
? "secret"
|
|
112
|
+
: next.storage.cloudAuthMode;
|
|
113
|
+
next.storage.azureBlobClientId =
|
|
114
|
+
stringValue(storage.azure.clientId) ??
|
|
115
|
+
next.storage.azureBlobClientId;
|
|
116
|
+
next.storage.azureBlobTenantId =
|
|
117
|
+
stringValue(storage.azure.tenantId) ??
|
|
118
|
+
next.storage.azureBlobTenantId;
|
|
119
|
+
next.storage.azureBlobContainer =
|
|
120
|
+
stringValue(storage.azure.container) ??
|
|
121
|
+
next.storage.azureBlobContainer;
|
|
122
|
+
next.storage.azureBlobConnectionStringSecretRef =
|
|
123
|
+
secretRefValue(storage.azure.connectionStringSecretRef) ??
|
|
124
|
+
next.storage.azureBlobConnectionStringSecretRef;
|
|
125
|
+
}
|
|
126
|
+
if (isRecord(storage.gcp)) {
|
|
127
|
+
next.storage.gcpServiceAccountEmail =
|
|
128
|
+
stringValue(storage.gcp.serviceAccountEmail) ??
|
|
129
|
+
next.storage.gcpServiceAccountEmail;
|
|
130
|
+
}
|
|
131
|
+
if (isRecord(storage.paths)) {
|
|
132
|
+
next.storage.paths = {
|
|
133
|
+
decisionLogs: stringValue(storage.paths.decisionLogs) ??
|
|
134
|
+
next.storage.paths?.decisionLogs,
|
|
135
|
+
dbBackups: stringValue(storage.paths.dbBackups) ??
|
|
136
|
+
next.storage.paths?.dbBackups,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (isRecord(values.clusterIssuer)) {
|
|
142
|
+
next.tlsEmail = stringValue(values.clusterIssuer.email) ?? next.tlsEmail;
|
|
143
|
+
}
|
|
144
|
+
if (isRecord(values.backup)) {
|
|
145
|
+
next.backup = {
|
|
146
|
+
enabled: booleanValue(values.backup.enabled) ?? next.backup?.enabled ?? false,
|
|
147
|
+
schedule: stringValue(values.backup.schedule) ?? next.backup?.schedule ?? "0 2 * * *",
|
|
148
|
+
retentionDays: numberValue(values.backup.retentionDays) ??
|
|
149
|
+
next.backup?.retentionDays ??
|
|
150
|
+
7,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// External services (managed Redis/Kafka). The saved config is authoritative;
|
|
154
|
+
// here we reconcile mode + connection details from the live chart values so a
|
|
155
|
+
// redeploy reflects any drift. Preset/identity fall back to the saved config.
|
|
156
|
+
const rb = isRecord(values.rulebricks) ? values.rulebricks : null;
|
|
157
|
+
const redisLive = rb && isRecord(rb.redis) ? rb.redis : null;
|
|
158
|
+
if (redisLive) {
|
|
159
|
+
const redisEnabled = booleanValue(redisLive.enabled);
|
|
160
|
+
const savedRedis = next.externalServices?.redis;
|
|
161
|
+
if (redisEnabled === false) {
|
|
162
|
+
const ext = isRecord(redisLive.external) ? redisLive.external : {};
|
|
163
|
+
const tls = isRecord(ext.tls) ? booleanValue(ext.tls.enabled) : undefined;
|
|
164
|
+
const httpApiLive = isRecord(ext.httpApi) ? ext.httpApi : null;
|
|
165
|
+
next.externalServices = {
|
|
166
|
+
...next.externalServices,
|
|
167
|
+
redis: {
|
|
168
|
+
mode: "external",
|
|
169
|
+
external: {
|
|
170
|
+
...(savedRedis?.external ?? {}),
|
|
171
|
+
host: stringValue(ext.host) ?? savedRedis?.external?.host,
|
|
172
|
+
port: numberValue(ext.port) ?? savedRedis?.external?.port,
|
|
173
|
+
password: stringValue(ext.password) ?? savedRedis?.external?.password,
|
|
174
|
+
existingSecret: stringValue(ext.existingSecret) ??
|
|
175
|
+
savedRedis?.external?.existingSecret,
|
|
176
|
+
existingSecretKey: stringValue(ext.existingSecretKey) ??
|
|
177
|
+
savedRedis?.external?.existingSecretKey,
|
|
178
|
+
tls: tls ?? savedRedis?.external?.tls,
|
|
179
|
+
httpApi: httpApiLive
|
|
180
|
+
? {
|
|
181
|
+
enabled: booleanValue(httpApiLive.enabled) ?? false,
|
|
182
|
+
url: stringValue(httpApiLive.url),
|
|
183
|
+
token: stringValue(httpApiLive.token),
|
|
184
|
+
}
|
|
185
|
+
: savedRedis?.external?.httpApi,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
else if (redisEnabled === true) {
|
|
191
|
+
next.externalServices = {
|
|
192
|
+
...next.externalServices,
|
|
193
|
+
redis: { mode: "embedded" },
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const kafkaEnabled = isRecord(values.kafka)
|
|
198
|
+
? booleanValue(values.kafka.enabled)
|
|
199
|
+
: undefined;
|
|
200
|
+
const loggingLive = rb && isRecord(rb.app) && isRecord(rb.app.logging) ? rb.app.logging : null;
|
|
201
|
+
if (kafkaEnabled === false && loggingLive) {
|
|
202
|
+
const savedKafka = next.externalServices?.kafka;
|
|
203
|
+
const saslLive = isRecord(loggingLive.kafkaSasl)
|
|
204
|
+
? loggingLive.kafkaSasl
|
|
205
|
+
: null;
|
|
206
|
+
const bridge = isRecord(values.kafkaBridge) ? values.kafkaBridge : null;
|
|
207
|
+
const mechanism = stringValue(saslLive?.mechanism) ?? savedKafka?.external?.sasl?.mechanism;
|
|
208
|
+
next.externalServices = {
|
|
209
|
+
...next.externalServices,
|
|
210
|
+
kafka: {
|
|
211
|
+
mode: "external",
|
|
212
|
+
external: {
|
|
213
|
+
...(savedKafka?.external ?? {}),
|
|
214
|
+
preset: savedKafka?.external?.preset ?? "custom",
|
|
215
|
+
brokers: stringValue(loggingLive.kafkaBrokers) ??
|
|
216
|
+
savedKafka?.external?.brokers,
|
|
217
|
+
topic: stringValue(loggingLive.kafkaTopic) ??
|
|
218
|
+
savedKafka?.external?.topic,
|
|
219
|
+
topicPrefix: stringValue(loggingLive.kafkaTopicPrefix) ??
|
|
220
|
+
savedKafka?.external?.topicPrefix,
|
|
221
|
+
ssl: booleanValue(loggingLive.kafkaSsl) ?? savedKafka?.external?.ssl,
|
|
222
|
+
sasl: mechanism
|
|
223
|
+
? {
|
|
224
|
+
mechanism,
|
|
225
|
+
region: stringValue(saslLive?.region) ??
|
|
226
|
+
savedKafka?.external?.sasl?.region,
|
|
227
|
+
username: stringValue(saslLive?.username) ??
|
|
228
|
+
savedKafka?.external?.sasl?.username,
|
|
229
|
+
password: stringValue(saslLive?.password) ??
|
|
230
|
+
savedKafka?.external?.sasl?.password,
|
|
231
|
+
existingSecret: stringValue(saslLive?.existingSecret) ??
|
|
232
|
+
savedKafka?.external?.sasl?.existingSecret,
|
|
233
|
+
}
|
|
234
|
+
: savedKafka?.external?.sasl,
|
|
235
|
+
identity: {
|
|
236
|
+
...(savedKafka?.external?.identity ?? {}),
|
|
237
|
+
awsRoleArn: stringValue(bridge?.awsRoleArn) ||
|
|
238
|
+
savedKafka?.external?.identity?.awsRoleArn,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
else if (kafkaEnabled === true) {
|
|
245
|
+
next.externalServices = {
|
|
246
|
+
...next.externalServices,
|
|
247
|
+
kafka: { mode: "embedded" },
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return next;
|
|
251
|
+
}
|
|
252
|
+
function RedeployCommandInner({ name, chartVersion }) {
|
|
253
|
+
const { colors } = useTheme();
|
|
254
|
+
const [step, setStep] = useState("loading");
|
|
255
|
+
const [error, setError] = useState(null);
|
|
256
|
+
const [wizardState, setWizardState] = useState(null);
|
|
257
|
+
const [profile, setProfile] = useState(null);
|
|
258
|
+
const [resolvedChartVersion, setResolvedChartVersion] = useState(chartVersion);
|
|
259
|
+
useEffect(() => {
|
|
260
|
+
(async () => {
|
|
261
|
+
try {
|
|
262
|
+
const health = await loadDeploymentHealth(name, {
|
|
263
|
+
refreshKubeconfig: true,
|
|
264
|
+
});
|
|
265
|
+
if (!health.config) {
|
|
266
|
+
setError(health.configError || `Deployment "${name}" is invalid.`);
|
|
267
|
+
setStep("error");
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (health.kind !== "online") {
|
|
271
|
+
setError(`Deployment "${name}" must be installed and reachable before redeploy. Current status: ${health.kind}.`);
|
|
272
|
+
setStep("error");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const [loadedProfile, values] = await Promise.all([
|
|
276
|
+
loadProfile(),
|
|
277
|
+
loadHelmValues(name),
|
|
278
|
+
]);
|
|
279
|
+
const hydratedConfig = applyHelmValuesToConfig(health.config, values);
|
|
280
|
+
const installedChartVersion = chartVersion ||
|
|
281
|
+
(health.state?.application?.chartVersion !== "latest"
|
|
282
|
+
? health.state?.application?.chartVersion
|
|
283
|
+
: undefined) ||
|
|
284
|
+
(await getInstalledChartVersion(health.releaseName, health.namespace)) ||
|
|
285
|
+
undefined;
|
|
286
|
+
setProfile(loadedProfile);
|
|
287
|
+
setResolvedChartVersion(installedChartVersion);
|
|
288
|
+
setWizardState(configToWizardState(hydratedConfig, loadedProfile));
|
|
289
|
+
setStep("wizard");
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
setError(err instanceof Error ? err.message : "Failed to load redeploy");
|
|
293
|
+
setStep("error");
|
|
294
|
+
}
|
|
295
|
+
})();
|
|
296
|
+
}, [name, chartVersion]);
|
|
297
|
+
if (step === "deploy") {
|
|
298
|
+
return (_jsx(DeployCommand, { name: name, version: resolvedChartVersion, regenerateValues: false, assumeDnsConfigured: true }));
|
|
299
|
+
}
|
|
300
|
+
if (step === "wizard" && wizardState) {
|
|
301
|
+
return (_jsx(InitWizard, { initialState: wizardState, mode: "redeploy", profile: profile, onSaveComplete: () => setStep("deploy") }));
|
|
302
|
+
}
|
|
303
|
+
if (step === "error") {
|
|
304
|
+
return (_jsxs(ThemeProvider, { theme: "deploy", children: [_jsx(Logo, {}), _jsx(BorderBox, { title: "Redeploy Failed", children: _jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { color: colors.error, bold: true, children: "\u2717 Error" }), _jsx(Text, { color: colors.error, children: error })] }) })] }));
|
|
305
|
+
}
|
|
306
|
+
return (_jsxs(ThemeProvider, { theme: "deploy", children: [_jsx(Logo, {}), _jsx(BorderBox, { title: "Redeploy", children: _jsx(Box, { marginY: 1, children: _jsx(Spinner, { label: "Checking deployment health..." }) }) })] }));
|
|
307
|
+
}
|
|
308
|
+
export function RedeployCommand(props) {
|
|
309
|
+
return _jsx(RedeployCommandInner, { ...props });
|
|
310
|
+
}
|