@flui-cloud/cli 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cli/src/commands/app/list.d.ts +3 -0
- package/lib/cli/src/commands/app/list.js +72 -18
- package/lib/cli/src/commands/app/status.d.ts +1 -0
- package/lib/cli/src/commands/app/status.js +27 -2
- package/lib/cli/src/commands/cluster/destroy.d.ts +1 -1
- package/lib/cli/src/commands/cluster/destroy.js +2 -2
- package/lib/cli/src/commands/deploy.d.ts +3 -0
- package/lib/cli/src/commands/deploy.js +19 -0
- package/lib/cli/src/commands/dev/creds.d.ts +0 -1
- package/lib/cli/src/commands/dev/creds.js +6 -27
- package/lib/cli/src/commands/dev/tunnel.js +8 -8
- package/lib/cli/src/commands/env/capacity.js +4 -4
- package/lib/cli/src/commands/env/create.d.ts +4 -1
- package/lib/cli/src/commands/env/create.js +73 -52
- package/lib/cli/src/commands/env/credentials.js +12 -12
- package/lib/cli/src/commands/env/destroy.d.ts +2 -1
- package/lib/cli/src/commands/env/destroy.js +45 -28
- package/lib/cli/src/commands/env/diag-ca.js +5 -5
- package/lib/cli/src/commands/env/export-config.d.ts +0 -17
- package/lib/cli/src/commands/env/export-config.js +45 -44
- package/lib/cli/src/commands/env/force-ready.d.ts +1 -1
- package/lib/cli/src/commands/env/force-ready.js +8 -8
- package/lib/cli/src/commands/env/inspect.js +5 -5
- package/lib/cli/src/commands/env/refresh-kubeconfig.js +4 -4
- package/lib/cli/src/commands/env/repair-ssh-ca.js +4 -4
- package/lib/cli/src/commands/env/repair-storage.d.ts +9 -0
- package/lib/cli/src/commands/env/repair-storage.js +82 -0
- package/lib/cli/src/commands/env/restart.d.ts +1 -1
- package/lib/cli/src/commands/env/restart.js +9 -9
- package/lib/cli/src/commands/env/scale-master.js +4 -4
- package/lib/cli/src/commands/env/scale-node.js +4 -4
- package/lib/cli/src/commands/env/set-master-protection.d.ts +16 -0
- package/lib/cli/src/commands/env/set-master-protection.js +120 -0
- package/lib/cli/src/commands/env/status.d.ts +1 -1
- package/lib/cli/src/commands/env/status.js +10 -10
- package/lib/cli/src/commands/env/stop.d.ts +1 -1
- package/lib/cli/src/commands/env/stop.js +8 -8
- package/lib/cli/src/commands/env/storage-expand.js +4 -4
- package/lib/cli/src/commands/env/storage.d.ts +1 -1
- package/lib/cli/src/commands/env/storage.js +5 -5
- package/lib/cli/src/commands/env/sync.js +5 -5
- package/lib/cli/src/commands/env/uncordon.js +4 -4
- package/lib/cli/src/commands/env/update-firewall.d.ts +13 -1
- package/lib/cli/src/commands/env/update-firewall.js +232 -126
- package/lib/cli/src/commands/integration/connect.d.ts +1 -0
- package/lib/cli/src/commands/integration/connect.js +19 -1
- package/lib/cli/src/commands/integration/reset.d.ts +13 -0
- package/lib/cli/src/commands/integration/reset.js +95 -0
- package/lib/cli/src/commands/integration/setup.d.ts +18 -0
- package/lib/cli/src/commands/integration/setup.js +320 -0
- package/lib/cli/src/commands/integration/status.d.ts +9 -0
- package/lib/cli/src/commands/integration/status.js +117 -0
- package/lib/cli/src/commands/node/list.d.ts +1 -0
- package/lib/cli/src/commands/node/list.js +19 -2
- package/lib/cli/src/commands/server-types/list.d.ts +3 -0
- package/lib/cli/src/commands/server-types/list.js +84 -0
- package/lib/cli/src/commands/ssh.js +5 -5
- package/lib/cli/src/commands/version.d.ts +18 -0
- package/lib/cli/src/commands/version.js +85 -0
- package/lib/cli/src/config/bootstrap.config.d.ts +10 -1
- package/lib/cli/src/config/bootstrap.config.js +21 -4
- package/lib/cli/src/config/preferences-schema.js +5 -5
- package/lib/cli/src/config/release.config.d.ts +31 -0
- package/lib/cli/src/config/release.config.js +38 -0
- package/lib/cli/src/lib/prompts.d.ts +1 -6
- package/lib/cli/src/lib/prompts.js +33 -13
- package/lib/cli/src/lib/services/cli-app.service.d.ts +33 -0
- package/lib/cli/src/lib/services/cli-app.service.js +9 -0
- package/lib/cli/src/lib/services/reconciliation.service.js +1 -1
- package/lib/cli/src/lib/templates/firewall-rules.d.ts +2 -2
- package/lib/cli/src/lib/templates/firewall-rules.js +3 -3
- package/lib/cli/src/modules/cli-infrastructure.module.js +3 -3
- package/lib/cli/src/services/cli-cluster-creator.service.js +31 -6
- package/lib/cli/src/services/cli-clusters.service.d.ts +3 -3
- package/lib/cli/src/services/cli-clusters.service.js +57 -34
- package/lib/cli/src/services/cli-control-cluster.service.d.ts +129 -0
- package/lib/cli/src/services/cli-control-cluster.service.js +544 -0
- package/lib/cli/src/services/cli-endpoint-resolver.service.d.ts +1 -0
- package/lib/cli/src/services/cli-endpoint-resolver.service.js +8 -2
- package/lib/cli/src/services/cli-k3s-script.service.d.ts +8 -1
- package/lib/cli/src/services/cli-k3s-script.service.js +14 -6
- package/lib/src/config/release.config.d.ts +28 -0
- package/lib/src/config/release.config.js +35 -0
- package/lib/src/modules/applications/entities/application.entity.d.ts +13 -20
- package/lib/src/modules/applications/entities/application.entity.js +12 -0
- package/lib/src/modules/applications/enums/application-exposure.enum.d.ts +2 -1
- package/lib/src/modules/applications/enums/application-exposure.enum.js +1 -0
- package/lib/src/modules/applications/interfaces/source-config.interface.d.ts +1 -0
- package/lib/src/modules/infrastructure/clusters/entities/cluster.entity.d.ts +8 -2
- package/lib/src/modules/infrastructure/clusters/entities/cluster.entity.js +16 -1
- package/lib/src/modules/infrastructure/clusters/services/cluster-node-scaling.service.js +2 -2
- package/lib/src/modules/infrastructure/firewalls/templates/firewall-rules.template.d.ts +3 -2
- package/lib/src/modules/infrastructure/firewalls/templates/firewall-rules.template.js +11 -4
- package/lib/src/modules/infrastructure/shared/services/kubernetes.service.d.ts +26 -0
- package/lib/src/modules/infrastructure/shared/services/kubernetes.service.js +105 -8
- package/lib/src/modules/management/entities/provider-capabilities.entity.d.ts +2 -0
- package/lib/src/modules/providers/implementations/contabo/contabo-capabilities.service.js +2 -0
- package/lib/src/modules/providers/implementations/hetzner/hetzner-capabilities.service.js +3 -6
- package/lib/src/modules/providers/implementations/scaleway/scaleway-capabilities.service.js +2 -1
- package/lib/src/modules/providers/implementations/scaleway/scaleway-firewall.service.js +3 -1
- package/lib/src/modules/providers/implementations/scaleway/scaleway-provider.service.js +3 -1
- package/lib/src/modules/providers/interfaces/provider-capabilities.interface.d.ts +0 -2
- package/lib/src/modules/providers/services/hetzner-firewall.service.d.ts +1 -1
- package/lib/src/modules/providers/services/hetzner-firewall.service.js +2 -1
- package/oclif.manifest.json +1025 -678
- package/package.json +2 -2
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const nest_app_1 = require("../../lib/nest-app");
|
|
10
|
+
const context_banner_1 = require("../../lib/context-banner");
|
|
11
|
+
const cli_control_cluster_service_1 = require("../../services/cli-control-cluster.service");
|
|
12
|
+
const cli_cluster_repository_1 = require("../../lib/repositories/cli-cluster.repository");
|
|
13
|
+
const cli_ssh_service_1 = require("../../services/cli-ssh.service");
|
|
14
|
+
const CP_LABEL = 'node-role.kubernetes.io/control-plane';
|
|
15
|
+
const APPLY_CMD = `kubectl taint nodes -l ${CP_LABEL} ${CP_LABEL}=:NoSchedule --overwrite`;
|
|
16
|
+
const REMOVE_CMD = `kubectl taint nodes -l ${CP_LABEL} ${CP_LABEL}:NoSchedule- 2>/dev/null || true`;
|
|
17
|
+
const TAINT_KEYS_CMD = `kubectl get nodes -l ${CP_LABEL} -o jsonpath='{.items[*].spec.taints[*].key}'`;
|
|
18
|
+
const WORKER_COUNT_CMD = `kubectl get nodes -l '!${CP_LABEL}' --no-headers 2>/dev/null | wc -l`;
|
|
19
|
+
class EnvSetMasterProtection extends core_1.Command {
|
|
20
|
+
async run() {
|
|
21
|
+
const { args } = await this.parse(EnvSetMasterProtection);
|
|
22
|
+
(0, context_banner_1.printContextBanner)();
|
|
23
|
+
const spinner = (0, ora_1.default)('Resolving control cluster...').start();
|
|
24
|
+
try {
|
|
25
|
+
const app = await (0, nest_app_1.getNestApp)();
|
|
26
|
+
const controlService = app.get(cli_control_cluster_service_1.CliControlClusterService);
|
|
27
|
+
const clusterRepo = app.get(cli_cluster_repository_1.CliClusterRepository);
|
|
28
|
+
const ssh = app.get(cli_ssh_service_1.CliSshService);
|
|
29
|
+
const cluster = await controlService.getControlCluster();
|
|
30
|
+
if (!cluster) {
|
|
31
|
+
spinner.fail('No control cluster found');
|
|
32
|
+
this.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const masterIp = cluster.masterIpAddress;
|
|
35
|
+
if (!masterIp) {
|
|
36
|
+
spinner.fail('Control cluster has no masterIpAddress stored');
|
|
37
|
+
this.exit(1);
|
|
38
|
+
}
|
|
39
|
+
// Worker count comes from the live cluster, not the local profile (which
|
|
40
|
+
// can drift out of sync with the backend).
|
|
41
|
+
const workers = await this.countWorkers(ssh, masterIp);
|
|
42
|
+
if (args.action === 'show') {
|
|
43
|
+
await this.showState(spinner, ssh, cluster, masterIp, workers);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (args.action === 'on') {
|
|
47
|
+
await this.turnOn(spinner, ssh, clusterRepo, cluster, masterIp, workers);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
await this.turnOff(spinner, ssh, clusterRepo, cluster, masterIp);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
spinner.fail('set-master-protection failed');
|
|
54
|
+
console.log(chalk_1.default.red(`\n❌ ${error instanceof Error ? error.message : String(error)}\n`));
|
|
55
|
+
this.exit(1);
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
await (0, nest_app_1.closeNestApp)();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async countWorkers(ssh, masterIp) {
|
|
62
|
+
const out = await ssh.sshExec(masterIp, WORKER_COUNT_CMD);
|
|
63
|
+
return Number.parseInt(out.trim(), 10) || 0;
|
|
64
|
+
}
|
|
65
|
+
async masterTainted(ssh, masterIp) {
|
|
66
|
+
const out = await ssh.sshExec(masterIp, TAINT_KEYS_CMD);
|
|
67
|
+
return out.includes(CP_LABEL);
|
|
68
|
+
}
|
|
69
|
+
protectionLabel(workers, tainted) {
|
|
70
|
+
if (workers === 0)
|
|
71
|
+
return chalk_1.default.dim('n/a (single-node)');
|
|
72
|
+
return tainted ? chalk_1.default.green('on (master tainted)') : chalk_1.default.yellow('off');
|
|
73
|
+
}
|
|
74
|
+
async showState(spinner, ssh, cluster, masterIp, workers) {
|
|
75
|
+
const tainted = await this.masterTainted(ssh, masterIp);
|
|
76
|
+
spinner.stop();
|
|
77
|
+
const flag = cluster.metadata?.masterProtection;
|
|
78
|
+
console.log(chalk_1.default.cyan('\n Master protection\n'));
|
|
79
|
+
console.log(` State: ${this.protectionLabel(workers, tainted)}`);
|
|
80
|
+
console.log(` Stored flag: ${flag === undefined ? chalk_1.default.dim('unset') : String(flag)}`);
|
|
81
|
+
console.log(` Workers: ${workers}\n`);
|
|
82
|
+
}
|
|
83
|
+
async turnOn(spinner, ssh, clusterRepo, cluster, masterIp, workers) {
|
|
84
|
+
if (workers === 0) {
|
|
85
|
+
spinner.fail('Cannot protect the master on a single-node cluster — it would block all scheduling. Add a worker first.');
|
|
86
|
+
this.exit(1);
|
|
87
|
+
}
|
|
88
|
+
spinner.text = 'Tainting master via SSH...';
|
|
89
|
+
await ssh.sshExec(masterIp, APPLY_CMD);
|
|
90
|
+
await this.persist(clusterRepo, cluster, true);
|
|
91
|
+
spinner.succeed('Master protection enabled');
|
|
92
|
+
console.log(chalk_1.default.dim('\n New pods will schedule on workers. Existing pods on the master are not evicted.\n'));
|
|
93
|
+
}
|
|
94
|
+
async turnOff(spinner, ssh, clusterRepo, cluster, masterIp) {
|
|
95
|
+
spinner.text = 'Removing master taint via SSH...';
|
|
96
|
+
await ssh.sshExec(masterIp, REMOVE_CMD);
|
|
97
|
+
await this.persist(clusterRepo, cluster, false);
|
|
98
|
+
spinner.succeed('Master protection disabled');
|
|
99
|
+
console.log(chalk_1.default.dim('\n The master is schedulable again for new pods.\n'));
|
|
100
|
+
}
|
|
101
|
+
async persist(clusterRepo, cluster, enabled) {
|
|
102
|
+
cluster.metadata = { ...cluster.metadata, masterProtection: enabled };
|
|
103
|
+
await clusterRepo.save(cluster);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
EnvSetMasterProtection.description = 'Taint the control-cluster master so new pods schedule on workers (on), ' +
|
|
107
|
+
'remove it (off), or report current state (show).';
|
|
108
|
+
EnvSetMasterProtection.examples = [
|
|
109
|
+
'<%= config.bin %> <%= command.id %> on',
|
|
110
|
+
'<%= config.bin %> <%= command.id %> off',
|
|
111
|
+
'<%= config.bin %> <%= command.id %> show',
|
|
112
|
+
];
|
|
113
|
+
EnvSetMasterProtection.args = {
|
|
114
|
+
action: core_1.Args.string({
|
|
115
|
+
description: 'on | off | show',
|
|
116
|
+
required: true,
|
|
117
|
+
options: ['on', 'off', 'show'],
|
|
118
|
+
}),
|
|
119
|
+
};
|
|
120
|
+
exports.default = EnvSetMasterProtection;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
export default class EnvStatus extends Command {
|
|
3
|
-
static readonly description = "Check
|
|
3
|
+
static readonly description = "Check control cluster status";
|
|
4
4
|
static readonly examples: string[];
|
|
5
5
|
run(): Promise<void>;
|
|
6
6
|
private renderObservabilityHealth;
|
|
@@ -7,7 +7,7 @@ const core_1 = require("@oclif/core");
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const ora_1 = __importDefault(require("ora"));
|
|
9
9
|
const nest_app_1 = require("../../lib/nest-app");
|
|
10
|
-
const
|
|
10
|
+
const cli_control_cluster_service_1 = require("../../services/cli-control-cluster.service");
|
|
11
11
|
const cli_endpoint_resolver_service_1 = require("../../services/cli-endpoint-resolver.service");
|
|
12
12
|
const cluster_entity_1 = require("../../../../src/modules/infrastructure/clusters/entities/cluster.entity");
|
|
13
13
|
const context_banner_1 = require("../../lib/context-banner");
|
|
@@ -19,12 +19,12 @@ class EnvStatus extends core_1.Command {
|
|
|
19
19
|
let spinner = (0, ora_1.default)('Checking cluster status...').start();
|
|
20
20
|
try {
|
|
21
21
|
const app = await (0, nest_app_1.getNestApp)();
|
|
22
|
-
const
|
|
22
|
+
const controlService = app.get(cli_control_cluster_service_1.CliControlClusterService);
|
|
23
23
|
const resolver = app.get(cli_endpoint_resolver_service_1.CliEndpointResolverService);
|
|
24
|
-
const cluster = await
|
|
24
|
+
const cluster = await controlService.getControlCluster();
|
|
25
25
|
if (!cluster) {
|
|
26
|
-
spinner.fail('No
|
|
27
|
-
console.log(chalk_1.default.yellow('\n⚠️ No
|
|
26
|
+
spinner.fail('No control cluster found');
|
|
27
|
+
console.log(chalk_1.default.yellow('\n⚠️ No control cluster exists.\n'));
|
|
28
28
|
console.log(chalk_1.default.dim('Create one with:'));
|
|
29
29
|
console.log(` ${chalk_1.default.cyan('flui env create')}\n`);
|
|
30
30
|
return;
|
|
@@ -37,7 +37,7 @@ class EnvStatus extends core_1.Command {
|
|
|
37
37
|
storage.saveApiUrl(derived);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
console.log(chalk_1.default.cyan('\n📋
|
|
40
|
+
console.log(chalk_1.default.cyan('\n📋 Control Cluster Status\n'));
|
|
41
41
|
console.log(` ${chalk_1.default.bold('Name:')} ${cluster.name}`);
|
|
42
42
|
console.log(` ${chalk_1.default.bold('ID:')} ${cluster.id}`);
|
|
43
43
|
console.log(` ${chalk_1.default.bold('Status:')} ${this.formatStatus(cluster.status)}`);
|
|
@@ -58,7 +58,7 @@ class EnvStatus extends core_1.Command {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
if (cluster.status === cluster_entity_1.ClusterStatus.READY && cluster.masterIpAddress) {
|
|
61
|
-
spinner = await this.renderObservabilityHealth(
|
|
61
|
+
spinner = await this.renderObservabilityHealth(controlService, cluster.masterIpAddress, cluster.nipHostnameToken, spinner);
|
|
62
62
|
}
|
|
63
63
|
else if (cluster.status === cluster_entity_1.ClusterStatus.STOPPED) {
|
|
64
64
|
console.log(chalk_1.default.cyan('\n💤 Cluster Status:\n'));
|
|
@@ -88,11 +88,11 @@ class EnvStatus extends core_1.Command {
|
|
|
88
88
|
await (0, nest_app_1.closeNestApp)();
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
async renderObservabilityHealth(
|
|
91
|
+
async renderObservabilityHealth(controlService, masterIp, nipHostnameToken, initialSpinner) {
|
|
92
92
|
initialSpinner.stop();
|
|
93
93
|
const spinner = (0, ora_1.default)('Checking observability services...').start();
|
|
94
94
|
try {
|
|
95
|
-
const servicesHealth = await
|
|
95
|
+
const servicesHealth = await controlService.checkObservabilityServices(masterIp, nipHostnameToken);
|
|
96
96
|
spinner.succeed('Services health checked');
|
|
97
97
|
console.log(chalk_1.default.cyan('\n📊 Observability Services Status:\n'));
|
|
98
98
|
const note = chalk_1.default.dim('(deployment ready)');
|
|
@@ -177,6 +177,6 @@ class EnvStatus extends core_1.Command {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
EnvStatus.description = 'Check
|
|
180
|
+
EnvStatus.description = 'Check control cluster status';
|
|
181
181
|
EnvStatus.examples = ['<%= config.bin %> <%= command.id %>'];
|
|
182
182
|
exports.default = EnvStatus;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
export default class EnvStop extends Command {
|
|
3
|
-
static readonly description = "Shutdown
|
|
3
|
+
static readonly description = "Shutdown control cluster servers (saves costs while preserving data)";
|
|
4
4
|
static readonly examples: string[];
|
|
5
5
|
run(): Promise<void>;
|
|
6
6
|
}
|
|
@@ -7,7 +7,7 @@ const core_1 = require("@oclif/core");
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const ora_1 = __importDefault(require("ora"));
|
|
9
9
|
const nest_app_1 = require("../../lib/nest-app");
|
|
10
|
-
const
|
|
10
|
+
const cli_control_cluster_service_1 = require("../../services/cli-control-cluster.service");
|
|
11
11
|
const hetzner_provider_service_1 = require("../../../../src/modules/providers/services/hetzner-provider.service");
|
|
12
12
|
const cluster_entity_1 = require("../../../../src/modules/infrastructure/clusters/entities/cluster.entity");
|
|
13
13
|
const cli_cluster_repository_1 = require("../../lib/repositories/cli-cluster.repository");
|
|
@@ -20,14 +20,14 @@ class EnvStop extends core_1.Command {
|
|
|
20
20
|
// Bootstrap NestJS and get services
|
|
21
21
|
const app = await (0, nest_app_1.getNestApp)();
|
|
22
22
|
spinner.succeed('Initialized');
|
|
23
|
-
console.log(chalk_1.default.cyan('\n💤 Stopping
|
|
23
|
+
console.log(chalk_1.default.cyan('\n💤 Stopping Control Cluster\n'));
|
|
24
24
|
spinner = (0, ora_1.default)('Finding cluster...').start();
|
|
25
|
-
const
|
|
26
|
-
// Get
|
|
27
|
-
const cluster = await
|
|
25
|
+
const controlService = app.get(cli_control_cluster_service_1.CliControlClusterService);
|
|
26
|
+
// Get control cluster
|
|
27
|
+
const cluster = await controlService.getControlCluster();
|
|
28
28
|
if (!cluster) {
|
|
29
|
-
spinner.fail('No
|
|
30
|
-
console.log(chalk_1.default.yellow('\n⚠️ No
|
|
29
|
+
spinner.fail('No control cluster found');
|
|
30
|
+
console.log(chalk_1.default.yellow('\n⚠️ No control cluster exists.\n'));
|
|
31
31
|
console.log(`Create one with: ${chalk_1.default.cyan('flui env create')}\n`);
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
@@ -142,6 +142,6 @@ class EnvStop extends core_1.Command {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
-
EnvStop.description = 'Shutdown
|
|
145
|
+
EnvStop.description = 'Shutdown control cluster servers (saves costs while preserving data)';
|
|
146
146
|
EnvStop.examples = ['<%= config.bin %> <%= command.id %>'];
|
|
147
147
|
exports.default = EnvStop;
|
|
@@ -8,7 +8,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const ora_1 = __importDefault(require("ora"));
|
|
9
9
|
const nest_app_1 = require("../../lib/nest-app");
|
|
10
10
|
const context_banner_1 = require("../../lib/context-banner");
|
|
11
|
-
const
|
|
11
|
+
const cli_control_cluster_service_1 = require("../../services/cli-control-cluster.service");
|
|
12
12
|
const cluster_node_scaling_service_1 = require("../../../../src/modules/infrastructure/clusters/services/cluster-node-scaling.service");
|
|
13
13
|
const cluster_storage_service_1 = require("../../../../src/modules/infrastructure/clusters/services/cluster-storage.service");
|
|
14
14
|
const cluster_capacity_service_1 = require("../../../../src/modules/infrastructure/clusters/services/cluster-capacity.service");
|
|
@@ -20,13 +20,13 @@ class EnvStorageExpand extends core_1.Command {
|
|
|
20
20
|
const spinner = (0, ora_1.default)('Inspecting current storage...').start();
|
|
21
21
|
try {
|
|
22
22
|
const app = await (0, nest_app_1.getNestApp)();
|
|
23
|
-
const
|
|
23
|
+
const controlService = app.get(cli_control_cluster_service_1.CliControlClusterService);
|
|
24
24
|
const storageService = app.get(cluster_storage_service_1.ClusterStorageService);
|
|
25
25
|
const capacityService = app.get(cluster_capacity_service_1.ClusterCapacityService);
|
|
26
26
|
const scalingService = app.get(cluster_node_scaling_service_1.ClusterNodeScalingService);
|
|
27
|
-
const cluster = await
|
|
27
|
+
const cluster = await controlService.getControlCluster();
|
|
28
28
|
if (!cluster) {
|
|
29
|
-
spinner.fail('No
|
|
29
|
+
spinner.fail('No control cluster found');
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
const storage = await storageService.getStatus(cluster.id);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
export default class EnvStorage extends Command {
|
|
3
|
-
static readonly description = "Show shared storage status (Volume + NFS export + PVC summary) for the current
|
|
3
|
+
static readonly description = "Show shared storage status (Volume + NFS export + PVC summary) for the current control cluster";
|
|
4
4
|
static readonly examples: string[];
|
|
5
5
|
run(): Promise<void>;
|
|
6
6
|
private render;
|
|
@@ -7,7 +7,7 @@ const core_1 = require("@oclif/core");
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const ora_1 = __importDefault(require("ora"));
|
|
9
9
|
const nest_app_1 = require("../../lib/nest-app");
|
|
10
|
-
const
|
|
10
|
+
const cli_control_cluster_service_1 = require("../../services/cli-control-cluster.service");
|
|
11
11
|
const cluster_storage_service_1 = require("../../../../src/modules/infrastructure/clusters/services/cluster-storage.service");
|
|
12
12
|
const cluster_storage_dto_1 = require("../../../../src/modules/infrastructure/clusters/dto/cluster-storage.dto");
|
|
13
13
|
const context_banner_1 = require("../../lib/context-banner");
|
|
@@ -17,11 +17,11 @@ class EnvStorage extends core_1.Command {
|
|
|
17
17
|
const spinner = (0, ora_1.default)('Inspecting shared storage...').start();
|
|
18
18
|
try {
|
|
19
19
|
const app = await (0, nest_app_1.getNestApp)();
|
|
20
|
-
const
|
|
20
|
+
const controlService = app.get(cli_control_cluster_service_1.CliControlClusterService);
|
|
21
21
|
const storageService = app.get(cluster_storage_service_1.ClusterStorageService);
|
|
22
|
-
const cluster = await
|
|
22
|
+
const cluster = await controlService.getControlCluster();
|
|
23
23
|
if (!cluster) {
|
|
24
|
-
spinner.fail('No
|
|
24
|
+
spinner.fail('No control cluster found');
|
|
25
25
|
console.log(chalk_1.default.yellow('\n⚠️ Create a cluster first: ' + chalk_1.default.cyan('flui env create\n')));
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
@@ -87,6 +87,6 @@ class EnvStorage extends core_1.Command {
|
|
|
87
87
|
return (map[status] ?? chalk_1.default.white)(status);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
EnvStorage.description = 'Show shared storage status (Volume + NFS export + PVC summary) for the current
|
|
90
|
+
EnvStorage.description = 'Show shared storage status (Volume + NFS export + PVC summary) for the current control cluster';
|
|
91
91
|
EnvStorage.examples = ['<%= config.bin %> <%= command.id %>'];
|
|
92
92
|
exports.default = EnvStorage;
|
|
@@ -42,7 +42,7 @@ const ora_1 = __importDefault(require("ora"));
|
|
|
42
42
|
const fs = __importStar(require("node:fs"));
|
|
43
43
|
const path = __importStar(require("node:path"));
|
|
44
44
|
const nest_app_1 = require("../../lib/nest-app");
|
|
45
|
-
const
|
|
45
|
+
const cli_control_cluster_service_1 = require("../../services/cli-control-cluster.service");
|
|
46
46
|
const cli_endpoint_resolver_service_1 = require("../../services/cli-endpoint-resolver.service");
|
|
47
47
|
const cli_ssh_service_1 = require("../../services/cli-ssh.service");
|
|
48
48
|
const config_storage_1 = require("../../lib/config-storage");
|
|
@@ -56,13 +56,13 @@ class EnvSync extends core_1.Command {
|
|
|
56
56
|
const spinner = (0, ora_1.default)('Connecting to cluster master via SSH...').start();
|
|
57
57
|
try {
|
|
58
58
|
const app = await (0, nest_app_1.getNestApp)();
|
|
59
|
-
const
|
|
59
|
+
const controlService = app.get(cli_control_cluster_service_1.CliControlClusterService);
|
|
60
60
|
const resolver = app.get(cli_endpoint_resolver_service_1.CliEndpointResolverService);
|
|
61
61
|
const sshService = app.get(cli_ssh_service_1.CliSshService);
|
|
62
|
-
const cluster = await
|
|
62
|
+
const cluster = await controlService.getControlCluster();
|
|
63
63
|
if (!cluster) {
|
|
64
|
-
spinner.fail('No
|
|
65
|
-
console.log(chalk_1.default.yellow('\n⚠️ No
|
|
64
|
+
spinner.fail('No control cluster found');
|
|
65
|
+
console.log(chalk_1.default.yellow('\n⚠️ No control cluster exists.\n'));
|
|
66
66
|
console.log(chalk_1.default.dim('Create one with:'));
|
|
67
67
|
console.log(` ${chalk_1.default.cyan('flui env create')}\n`);
|
|
68
68
|
return;
|
|
@@ -8,7 +8,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const ora_1 = __importDefault(require("ora"));
|
|
9
9
|
const nest_app_1 = require("../../lib/nest-app");
|
|
10
10
|
const context_banner_1 = require("../../lib/context-banner");
|
|
11
|
-
const
|
|
11
|
+
const cli_control_cluster_service_1 = require("../../services/cli-control-cluster.service");
|
|
12
12
|
const cli_node_repository_1 = require("../../lib/repositories/cli-node.repository");
|
|
13
13
|
const cluster_node_entity_1 = require("../../../../src/modules/infrastructure/clusters/entities/cluster-node.entity");
|
|
14
14
|
const cli_ssh_service_1 = require("../../services/cli-ssh.service");
|
|
@@ -19,12 +19,12 @@ class EnvUncordon extends core_1.Command {
|
|
|
19
19
|
const spinner = (0, ora_1.default)('Resolving node...').start();
|
|
20
20
|
try {
|
|
21
21
|
const app = await (0, nest_app_1.getNestApp)();
|
|
22
|
-
const
|
|
22
|
+
const controlService = app.get(cli_control_cluster_service_1.CliControlClusterService);
|
|
23
23
|
const nodeRepo = app.get(cli_node_repository_1.CliNodeRepository);
|
|
24
24
|
const ssh = app.get(cli_ssh_service_1.CliSshService);
|
|
25
|
-
const cluster = await
|
|
25
|
+
const cluster = await controlService.getControlCluster();
|
|
26
26
|
if (!cluster) {
|
|
27
|
-
spinner.fail('No
|
|
27
|
+
spinner.fail('No control cluster found');
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
const nodes = await nodeRepo.find({ where: { clusterId: cluster.id } });
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
export default class EnvUpdateFirewall extends Command {
|
|
3
|
-
static readonly description
|
|
3
|
+
static readonly description: string;
|
|
4
4
|
static readonly examples: string[];
|
|
5
5
|
static readonly flags: {
|
|
6
6
|
ip: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
add: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
remove: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
list: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
10
|
};
|
|
8
11
|
run(): Promise<void>;
|
|
12
|
+
/** Locate the cluster firewall, adopting/disambiguating unlinked ones by master attachment. */
|
|
13
|
+
private findFirewall;
|
|
14
|
+
private sshSourceOf;
|
|
15
|
+
private showAllowlist;
|
|
16
|
+
private resolveSourceCidrs;
|
|
17
|
+
/** Apply add/remove/replace to the SSH allowlist. Returns null when nothing was written. */
|
|
18
|
+
private updateAllowlist;
|
|
19
|
+
private createFirewall;
|
|
20
|
+
private printSummary;
|
|
9
21
|
}
|