@flui-cloud/cli 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/lib/cli/src/commands/app/list.d.ts +3 -0
  2. package/lib/cli/src/commands/app/list.js +72 -18
  3. package/lib/cli/src/commands/app/status.d.ts +1 -0
  4. package/lib/cli/src/commands/app/status.js +27 -2
  5. package/lib/cli/src/commands/cluster/destroy.d.ts +1 -1
  6. package/lib/cli/src/commands/cluster/destroy.js +2 -2
  7. package/lib/cli/src/commands/deploy.d.ts +3 -0
  8. package/lib/cli/src/commands/deploy.js +19 -0
  9. package/lib/cli/src/commands/dev/creds.d.ts +0 -1
  10. package/lib/cli/src/commands/dev/creds.js +6 -27
  11. package/lib/cli/src/commands/dev/tunnel.js +8 -8
  12. package/lib/cli/src/commands/env/capacity.js +4 -4
  13. package/lib/cli/src/commands/env/create.d.ts +4 -1
  14. package/lib/cli/src/commands/env/create.js +78 -52
  15. package/lib/cli/src/commands/env/credentials.js +12 -12
  16. package/lib/cli/src/commands/env/destroy.d.ts +2 -1
  17. package/lib/cli/src/commands/env/destroy.js +45 -28
  18. package/lib/cli/src/commands/env/diag-ca.js +5 -5
  19. package/lib/cli/src/commands/env/export-config.d.ts +0 -17
  20. package/lib/cli/src/commands/env/export-config.js +50 -47
  21. package/lib/cli/src/commands/env/force-ready.d.ts +1 -1
  22. package/lib/cli/src/commands/env/force-ready.js +8 -8
  23. package/lib/cli/src/commands/env/inspect.js +5 -5
  24. package/lib/cli/src/commands/env/refresh-kubeconfig.js +4 -4
  25. package/lib/cli/src/commands/env/repair-ssh-ca.js +4 -4
  26. package/lib/cli/src/commands/env/repair-storage.d.ts +9 -0
  27. package/lib/cli/src/commands/env/repair-storage.js +82 -0
  28. package/lib/cli/src/commands/env/restart.d.ts +1 -1
  29. package/lib/cli/src/commands/env/restart.js +9 -9
  30. package/lib/cli/src/commands/env/scale-master.js +4 -4
  31. package/lib/cli/src/commands/env/scale-node.js +4 -4
  32. package/lib/cli/src/commands/env/set-master-protection.d.ts +16 -0
  33. package/lib/cli/src/commands/env/set-master-protection.js +120 -0
  34. package/lib/cli/src/commands/env/status.d.ts +1 -1
  35. package/lib/cli/src/commands/env/status.js +10 -10
  36. package/lib/cli/src/commands/env/stop.d.ts +1 -1
  37. package/lib/cli/src/commands/env/stop.js +8 -8
  38. package/lib/cli/src/commands/env/storage-expand.js +4 -4
  39. package/lib/cli/src/commands/env/storage.d.ts +1 -1
  40. package/lib/cli/src/commands/env/storage.js +5 -5
  41. package/lib/cli/src/commands/env/sync.js +5 -5
  42. package/lib/cli/src/commands/env/uncordon.js +4 -4
  43. package/lib/cli/src/commands/env/update-firewall.d.ts +13 -1
  44. package/lib/cli/src/commands/env/update-firewall.js +232 -126
  45. package/lib/cli/src/commands/integration/connect.d.ts +1 -0
  46. package/lib/cli/src/commands/integration/connect.js +19 -1
  47. package/lib/cli/src/commands/integration/reset.d.ts +13 -0
  48. package/lib/cli/src/commands/integration/reset.js +95 -0
  49. package/lib/cli/src/commands/integration/setup.d.ts +18 -0
  50. package/lib/cli/src/commands/integration/setup.js +320 -0
  51. package/lib/cli/src/commands/integration/status.d.ts +9 -0
  52. package/lib/cli/src/commands/integration/status.js +117 -0
  53. package/lib/cli/src/commands/node/list.d.ts +1 -0
  54. package/lib/cli/src/commands/node/list.js +19 -2
  55. package/lib/cli/src/commands/server-types/list.d.ts +3 -0
  56. package/lib/cli/src/commands/server-types/list.js +84 -0
  57. package/lib/cli/src/commands/ssh.js +5 -5
  58. package/lib/cli/src/commands/version.d.ts +18 -0
  59. package/lib/cli/src/commands/version.js +100 -0
  60. package/lib/cli/src/config/bootstrap.config.d.ts +10 -1
  61. package/lib/cli/src/config/bootstrap.config.js +24 -4
  62. package/lib/cli/src/config/preferences-schema.js +5 -5
  63. package/lib/cli/src/config/release-override.d.ts +43 -0
  64. package/lib/cli/src/config/release-override.js +203 -0
  65. package/lib/cli/src/config/release.config.d.ts +31 -0
  66. package/lib/cli/src/config/release.config.js +38 -0
  67. package/lib/cli/src/lib/prompts.d.ts +1 -6
  68. package/lib/cli/src/lib/prompts.js +33 -13
  69. package/lib/cli/src/lib/services/cli-app.service.d.ts +33 -0
  70. package/lib/cli/src/lib/services/cli-app.service.js +9 -0
  71. package/lib/cli/src/lib/services/reconciliation.service.js +1 -1
  72. package/lib/cli/src/lib/templates/firewall-rules.d.ts +2 -2
  73. package/lib/cli/src/lib/templates/firewall-rules.js +3 -3
  74. package/lib/cli/src/modules/cli-infrastructure.module.js +3 -3
  75. package/lib/cli/src/services/cli-cluster-creator.service.js +31 -6
  76. package/lib/cli/src/services/cli-clusters.service.d.ts +3 -3
  77. package/lib/cli/src/services/cli-clusters.service.js +57 -34
  78. package/lib/cli/src/services/cli-control-cluster.service.d.ts +129 -0
  79. package/lib/cli/src/services/cli-control-cluster.service.js +545 -0
  80. package/lib/cli/src/services/cli-endpoint-resolver.service.d.ts +1 -0
  81. package/lib/cli/src/services/cli-endpoint-resolver.service.js +25 -11
  82. package/lib/cli/src/services/cli-k3s-script.service.d.ts +8 -1
  83. package/lib/cli/src/services/cli-k3s-script.service.js +14 -6
  84. package/lib/src/config/release.config.d.ts +28 -0
  85. package/lib/src/config/release.config.js +35 -0
  86. package/lib/src/modules/applications/entities/application.entity.d.ts +13 -20
  87. package/lib/src/modules/applications/entities/application.entity.js +12 -0
  88. package/lib/src/modules/applications/enums/application-exposure.enum.d.ts +2 -1
  89. package/lib/src/modules/applications/enums/application-exposure.enum.js +1 -0
  90. package/lib/src/modules/applications/interfaces/source-config.interface.d.ts +1 -0
  91. package/lib/src/modules/infrastructure/clusters/entities/cluster.entity.d.ts +8 -2
  92. package/lib/src/modules/infrastructure/clusters/entities/cluster.entity.js +16 -1
  93. package/lib/src/modules/infrastructure/clusters/services/cluster-node-scaling.service.js +2 -2
  94. package/lib/src/modules/infrastructure/firewalls/templates/firewall-rules.template.d.ts +3 -2
  95. package/lib/src/modules/infrastructure/firewalls/templates/firewall-rules.template.js +11 -4
  96. package/lib/src/modules/infrastructure/shared/services/kubernetes.service.d.ts +26 -0
  97. package/lib/src/modules/infrastructure/shared/services/kubernetes.service.js +105 -8
  98. package/lib/src/modules/management/entities/provider-capabilities.entity.d.ts +2 -0
  99. package/lib/src/modules/providers/implementations/contabo/contabo-capabilities.service.js +2 -0
  100. package/lib/src/modules/providers/implementations/hetzner/hetzner-capabilities.service.js +3 -6
  101. package/lib/src/modules/providers/implementations/scaleway/scaleway-capabilities.service.js +2 -1
  102. package/lib/src/modules/providers/implementations/scaleway/scaleway-firewall.service.js +3 -1
  103. package/lib/src/modules/providers/implementations/scaleway/scaleway-provider.service.js +3 -1
  104. package/lib/src/modules/providers/interfaces/provider-capabilities.interface.d.ts +0 -2
  105. package/lib/src/modules/providers/services/hetzner-firewall.service.d.ts +1 -1
  106. package/lib/src/modules/providers/services/hetzner-firewall.service.js +2 -1
  107. package/oclif.manifest.json +1201 -854
  108. 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 observability cluster status";
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 cli_observability_cluster_service_1 = require("../../services/cli-observability-cluster.service");
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 observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
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 observabilityService.getObservabilityCluster();
24
+ const cluster = await controlService.getControlCluster();
25
25
  if (!cluster) {
26
- spinner.fail('No observability cluster found');
27
- console.log(chalk_1.default.yellow('\n⚠️ No observability cluster exists.\n'));
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📋 Observability Cluster Status\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(observabilityService, cluster.masterIpAddress, cluster.nipHostnameToken, spinner);
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(observabilityService, masterIp, nipHostnameToken, initialSpinner) {
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 observabilityService.checkObservabilityServices(masterIp, nipHostnameToken);
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 observability cluster status';
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 observability cluster servers (saves costs while preserving data)";
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 cli_observability_cluster_service_1 = require("../../services/cli-observability-cluster.service");
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 Observability Cluster\n'));
23
+ console.log(chalk_1.default.cyan('\n💤 Stopping Control Cluster\n'));
24
24
  spinner = (0, ora_1.default)('Finding cluster...').start();
25
- const observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
26
- // Get observability cluster
27
- const cluster = await observabilityService.getObservabilityCluster();
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 observability cluster found');
30
- console.log(chalk_1.default.yellow('\n⚠️ No observability cluster exists.\n'));
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 observability cluster servers (saves costs while preserving data)';
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 cli_observability_cluster_service_1 = require("../../services/cli-observability-cluster.service");
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 observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
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 observabilityService.getObservabilityCluster();
27
+ const cluster = await controlService.getControlCluster();
28
28
  if (!cluster) {
29
- spinner.fail('No observability cluster found');
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 observability cluster";
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 cli_observability_cluster_service_1 = require("../../services/cli-observability-cluster.service");
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 observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
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 observabilityService.getObservabilityCluster();
22
+ const cluster = await controlService.getControlCluster();
23
23
  if (!cluster) {
24
- spinner.fail('No observability cluster found');
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 observability cluster';
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 cli_observability_cluster_service_1 = require("../../services/cli-observability-cluster.service");
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 observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
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 observabilityService.getObservabilityCluster();
62
+ const cluster = await controlService.getControlCluster();
63
63
  if (!cluster) {
64
- spinner.fail('No observability cluster found');
65
- console.log(chalk_1.default.yellow('\n⚠️ No observability cluster exists.\n'));
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 cli_observability_cluster_service_1 = require("../../services/cli-observability-cluster.service");
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 observabilityService = app.get(cli_observability_cluster_service_1.CliObservabilityClusterService);
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 observabilityService.getObservabilityCluster();
25
+ const cluster = await controlService.getControlCluster();
26
26
  if (!cluster) {
27
- spinner.fail('No observability cluster found');
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 = "Create or update firewall IP ranges for observability cluster";
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
  }