@codiac.io/codiac-cli 1.3.262 → 1.3.264

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.
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const core_1 = require("@oclif/core");
5
+ const command_base_exec_tenant_1 = require("../../../command-base-exec-tenant");
6
+ const prettify_1 = require("../../../prettify");
7
+ /**
8
+ * Edits the mutable connection metadata on an existing cluster record (ClusterDef.instance).
9
+ *
10
+ * WHY this exists: `cluster define` refuses to touch a cluster that has a live instance ("destroy it
11
+ * first"), and `cluster capture` is the only other writer of `instance.serverUrl`. So when a cluster's
12
+ * apiserver url was recorded wrong — or drifted, which is what happens when a cluster is destroyed and
13
+ * recreated under the same name — there was no in-CLI fix short of forgetting and re-capturing the
14
+ * cluster, which requires tearing down every cabinet and environment attached to it first.
15
+ *
16
+ * The cluster name is the record's identity (it is the join key that environments, cabinets and the
17
+ * kube-context cache all resolve against), so it is immutable here; renaming a cluster is a capture,
18
+ * not an edit.
19
+ *
20
+ * SIDE EFFECT worth knowing: `instance.serverUrl` is the value the ops kube-context cache stamps its
21
+ * entries with, so changing it here also invalidates the cached kube context for this cluster on every
22
+ * ops replica the next time each one connects. That is the supported way to force a credential
23
+ * re-fetch without restarting pods.
24
+ */
25
+ class NocClusterEdit extends command_base_exec_tenant_1.CommandBaseExecTenant {
26
+ captureArgs() {
27
+ var _a;
28
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
29
+ const { args, flags } = yield this.parse(NocClusterEdit);
30
+ // partial.name identifies WHICH cluster (immutable). The requested edit rides along on
31
+ // partial.instance so that an omitted flag is distinguishable from an explicit clear.
32
+ const partial = { name: args.name };
33
+ if (flags['server-url'] !== undefined) {
34
+ partial.instance = { serverUrl: NocClusterEdit.normalizeServerUrl(flags['server-url']) };
35
+ }
36
+ else if (flags['clear-server-url']) {
37
+ partial.instance = { serverUrl: '' };
38
+ }
39
+ return [partial, (_a = flags['take-defaults']) !== null && _a !== void 0 ? _a : false];
40
+ });
41
+ }
42
+ buildCandidate_silently(partial, _rootMap) {
43
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
44
+ if (!partial.name)
45
+ throw new Error('A cluster name must be provided (run `cod cluster list` to see names).');
46
+ if (partial.instance === undefined) {
47
+ throw new Error('Nothing to edit. Provide --server-url <url>, or --clear-server-url to remove the recorded value.');
48
+ }
49
+ const existing = yield this.readClusterDefOrThrow(partial.name);
50
+ return this.applyEdits(existing, partial);
51
+ });
52
+ }
53
+ buildCandidate_interactively(partial, takeDefaults, _rootMap) {
54
+ var _a, _b, _c, _d, _e;
55
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
56
+ const name = (_a = partial.name) !== null && _a !== void 0 ? _a : yield this.promptForClusterName();
57
+ const existing = yield this.readClusterDefOrThrow(name);
58
+ this._ui.userMessage(`Editing cluster ${this._styler.bold(this._styler.hilite(existing.name))} ` +
59
+ `${this._styler.dim(`(current apiserver url: ${((_b = existing.instance) === null || _b === void 0 ? void 0 : _b.serverUrl) || '<none recorded>'})`)}`);
60
+ if (partial.instance === undefined) {
61
+ const entered = yield this._ui.prompt('server-url', 'Apiserver url:', true, (_d = (_c = existing.instance) === null || _c === void 0 ? void 0 : _c.serverUrl) !== null && _d !== void 0 ? _d : '');
62
+ partial.instance = { serverUrl: NocClusterEdit.normalizeServerUrl(entered !== null && entered !== void 0 ? entered : '') };
63
+ }
64
+ const candidate = this.applyEdits(existing, Object.assign(Object.assign({}, partial), { name }));
65
+ this._ui.userMessage('About to save:');
66
+ this._ui.userMessage((0, prettify_1.prettify)({ name: candidate.name, serverUrl: (_e = candidate.instance) === null || _e === void 0 ? void 0 : _e.serverUrl }));
67
+ this._ui.userMessage(this._styler.dim('This also invalidates the cached kube context for this cluster; credentials will be re-fetched from the cloud provider on next use.'));
68
+ const confirmed = takeDefaults || (yield this._ui.promptConfirm('confirm', 'Save changes?', false));
69
+ if (!confirmed)
70
+ return undefined;
71
+ return candidate;
72
+ });
73
+ }
74
+ buildCommandString(candidate, cmd) {
75
+ var _a;
76
+ cmd.push(candidate.name);
77
+ if ((_a = candidate.instance) === null || _a === void 0 ? void 0 : _a.serverUrl)
78
+ cmd.push('--server-url', candidate.instance.serverUrl);
79
+ else
80
+ cmd.push('--clear-server-url');
81
+ cmd.push('--silent');
82
+ return cmd;
83
+ }
84
+ executeTask(candidate) {
85
+ var _a, _b, _c;
86
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
87
+ const result = yield this._codiacApi.ClusterDef.tryUpdate(candidate);
88
+ if (result.error) {
89
+ const msg = `Error editing cluster [${candidate.name}]: ${result.error.name} ${(_a = result.error.message) !== null && _a !== void 0 ? _a : result.error.stack}`;
90
+ this.logger.error(msg, result.error);
91
+ this._ui.userMessage(`${this._styler.colorCritical('ERROR!')} ${msg}`);
92
+ throw result.error;
93
+ }
94
+ else if (!result.success) {
95
+ this._ui.userMessage(`${this._styler.colorCritical('FAILED!')} Failed to edit cluster [${candidate.name}]. ${(_b = result.message) !== null && _b !== void 0 ? _b : 'Check logs for details.'}`);
96
+ }
97
+ else {
98
+ const url = (_c = candidate.instance) === null || _c === void 0 ? void 0 : _c.serverUrl;
99
+ this._ui.userMessage(`${this._styler.colorGood('SUCCESS!')} Cluster [${this._styler.hilite(candidate.name)}] updated — apiserver url: ` +
100
+ `${this._styler.hilite(url || '<none recorded>')}. The cached kube context for this cluster will be re-fetched on next use.`);
101
+ }
102
+ });
103
+ }
104
+ // ---------------------------------------------------------------------------
105
+ // Helpers
106
+ // ---------------------------------------------------------------------------
107
+ /** Overlays the requested edit onto the FULL existing record.
108
+ *
109
+ * The whole ClusterDef is written back (this is a PUT, not a patch) precisely because the
110
+ * `instance` sub-document is dropped by the backend when it arrives incomplete — so the record has
111
+ * to be read unprojected and returned intact with only serverUrl changed. */
112
+ applyEdits(existing, partial) {
113
+ var _a, _b, _c;
114
+ if (existing.instance == undefined) {
115
+ throw new Error(`Cannot edit the apiserver url for cluster [${existing.name}]: it has no infrastructure record. ` +
116
+ `Run \`cod cluster capture\` to register the live cluster first.`);
117
+ }
118
+ const requested = (_b = (_a = partial.instance) === null || _a === void 0 ? void 0 : _a.serverUrl) !== null && _b !== void 0 ? _b : '';
119
+ const current = (_c = existing.instance.serverUrl) !== null && _c !== void 0 ? _c : '';
120
+ if (requested === current) {
121
+ throw new Error(`Nothing to edit for [${existing.name}]: the apiserver url is already [${current || '<none recorded>'}].`);
122
+ }
123
+ if (requested.length > 0)
124
+ NocClusterEdit.assertUsableServerUrl(requested);
125
+ const candidate = Object.assign({}, existing);
126
+ candidate.instance = Object.assign(Object.assign({}, existing.instance), { serverUrl: requested.length > 0 ? requested : undefined });
127
+ return candidate;
128
+ }
129
+ readClusterDefOrThrow(clusterName) {
130
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
131
+ // Read unprojected: applyEdits writes the whole record back, so every field has to be present.
132
+ const found = yield this._codiacApi.ClusterDef.readMany({ name: { $eq: clusterName } }, { throwNotFound: false });
133
+ const existing = found === null || found === void 0 ? void 0 : found[0];
134
+ if (!existing)
135
+ throw new Error(`No cluster named [${clusterName}] was found. Run \`cod cluster list\` to see the available clusters.`);
136
+ return existing;
137
+ });
138
+ }
139
+ promptForClusterName() {
140
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
141
+ const all = yield this._codiacApi.ClusterDef.readMany({ all: true }, { throwNotFound: false });
142
+ if (!all || all.length === 0)
143
+ throw new Error('Cannot edit: no clusters are defined yet.');
144
+ const chosen = yield this._ui.promptSelect('name', 'Which cluster do you want to edit?', all.map(c => c.name));
145
+ if (!chosen)
146
+ throw new Error('No cluster selected.');
147
+ return chosen;
148
+ });
149
+ }
150
+ static normalizeServerUrl(url) {
151
+ return (url !== null && url !== void 0 ? url : '').trim();
152
+ }
153
+ /** Fails fast on input that would leave the cluster unreachable, rather than storing it and
154
+ * surfacing as a connection error on the next deploy. */
155
+ static assertUsableServerUrl(url) {
156
+ let parsed;
157
+ try {
158
+ parsed = new URL(url);
159
+ }
160
+ catch (_a) {
161
+ throw new Error(`[${url}] is not a valid url. Provide the full apiserver url, eg: https://my-cluster.hcp.centralus.azmk8s.io:443`);
162
+ }
163
+ if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
164
+ throw new Error(`[${url}] must be an http(s) url. The apiserver url is the remote target for kubectl, eg: https://10.110.128.10:443`);
165
+ }
166
+ }
167
+ }
168
+ exports.default = NocClusterEdit;
169
+ NocClusterEdit.description = 'Changes the mutable connection metadata (apiserver url) on an existing cluster record. ' +
170
+ 'DOES NOT modify any infrastructure; it only corrects what Codiac has recorded about the cluster. ' +
171
+ 'The cluster name is immutable — use `cod cluster capture` to register a different cluster. ' +
172
+ 'Changing the apiserver url also invalidates the cached kube context for this cluster, forcing a ' +
173
+ 'fresh credential fetch from the cloud provider on next use.';
174
+ NocClusterEdit.aliases = ['cluster:edit'];
175
+ NocClusterEdit.examples = [
176
+ {
177
+ description: 'Edit a cluster interactively (select it, then change its apiserver url).',
178
+ command: '<%= config.bin %> <%= command.id %>',
179
+ },
180
+ {
181
+ description: "Correct the apiserver url Codiac has recorded for a cluster.",
182
+ command: '<%= config.bin %> <%= command.id %> my-cluster --server-url https://my-cluster.hcp.centralus.azmk8s.io:443 --silent',
183
+ },
184
+ {
185
+ description: 'Point a private cluster at its private-link address.',
186
+ command: '<%= config.bin %> <%= command.id %> my-cluster --server-url https://10.110.128.10:443 --silent',
187
+ },
188
+ {
189
+ description: 'Drop the recorded url so the next capture repopulates it from the cloud provider.',
190
+ command: '<%= config.bin %> <%= command.id %> my-cluster --clear-server-url --silent',
191
+ },
192
+ {
193
+ description: 'Renders the equivalent silent command without executing it.',
194
+ command: '<%= config.bin %> <%= command.id %> my-cluster --server-url https://10.110.128.10:443 --to-script',
195
+ },
196
+ ];
197
+ NocClusterEdit.args = {
198
+ name: core_1.Args.string({ description: 'Name of the cluster whose record you want to edit. Run `cod cluster list` to see names.' }),
199
+ };
200
+ NocClusterEdit.flags = {
201
+ help: core_1.Flags.help({ char: 'h' }),
202
+ 'server-url': core_1.Flags.string({
203
+ exclusive: ['clear-server-url'],
204
+ description: 'The apiserver url Codiac should record for this cluster (the remote target for kubectl), ' +
205
+ 'eg: https://my-cluster.hcp.centralus.azmk8s.io:443. Omit to leave it unchanged.',
206
+ }),
207
+ 'clear-server-url': core_1.Flags.boolean({
208
+ exclusive: ['server-url'],
209
+ description: 'Removes the recorded apiserver url, leaving it for the next `cod cluster capture` to repopulate.',
210
+ }),
211
+ 'take-defaults': core_1.Flags.boolean({ description: 'Prevents prompting for confirmation on parameters that were passed in or defaulted.' }),
212
+ silent: core_1.Flags.boolean({ exclusive: ['echo', 'to-script'], description: 'Executes without any user interaction; fails on missing or invalid arguments.' }),
213
+ echo: core_1.Flags.boolean({ exclusive: ['to-script', 'silent'], description: 'Renders the equivalent non-interactive command for future use before executing.' }),
214
+ 'to-script': core_1.Flags.boolean({ exclusive: ['echo', 'silent'], description: 'Renders the equivalent non-interactive command without executing it.' }),
215
+ };
216
+ //# sourceMappingURL=edit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../../src/commands/noc/cluster/edit.ts"],"names":[],"mappings":"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"}
@@ -360,7 +360,7 @@ let AssetConfigurator = class AssetConfigurator {
360
360
  let output = Number.parseInt(parts[0]);
361
361
  const valid = this.portIsValid(output);
362
362
  if (typeof valid === 'object')
363
- throw new Error("Invalid port number: ".concat((_a = valid.reason) !== null && _a !== void 0 ? _a : "Must be an integer between 0 and ".concat(this.MAX_PORT_NUMBER.toString())));
363
+ throw new Error("Invalid port number: ".concat((_a = valid.reason) !== null && _a !== void 0 ? _a : "Must be an integer between 1 and ".concat(this.MAX_PORT_NUMBER.toString())));
364
364
  return output;
365
365
  }
366
366
  else {
@@ -369,9 +369,9 @@ let AssetConfigurator = class AssetConfigurator {
369
369
  const extValid = this.portIsValid(output.external);
370
370
  const intValid = this.portIsValid(output.internal);
371
371
  if (typeof extValid === 'object')
372
- throw new Error("Invalid external port number: ".concat((_b = extValid.reason) !== null && _b !== void 0 ? _b : "Must be an integer between 0 and ", this.MAX_PORT_NUMBER.toString()));
372
+ throw new Error("Invalid external port number: ".concat((_b = extValid.reason) !== null && _b !== void 0 ? _b : "Must be an integer between 1 and ", this.MAX_PORT_NUMBER.toString()));
373
373
  if (typeof intValid === 'object')
374
- throw new Error("Invalid internal port number: ".concat((_c = intValid.reason) !== null && _c !== void 0 ? _c : "Must be an integer between 0 and ", this.MAX_PORT_NUMBER.toString()));
374
+ throw new Error("Invalid internal port number: ".concat((_c = intValid.reason) !== null && _c !== void 0 ? _c : "Must be an integer between 1 and ", this.MAX_PORT_NUMBER.toString()));
375
375
  return output;
376
376
  }
377
377
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.262",
2
+ "version": "1.3.264",
3
3
  "commands": {
4
4
  "branch": {
5
5
  "id": "branch",
@@ -1681,7 +1681,7 @@
1681
1681
  "name": "port",
1682
1682
  "type": "option",
1683
1683
  "char": "p",
1684
- "description": "The default port number (from 0 to 65535) to assign the asset when deployed to a cabinet (optional). To specify port forwarding (betw the service and container), use format: `<service-port>:<container-port>`, eg: `3555:80`",
1684
+ "description": "The default port number (from 1 to 65535) to assign the asset when deployed to a cabinet (optional). To specify port forwarding (betw the service and container), use format: `<service-port>:<container-port>`, eg: `3555:80`",
1685
1685
  "required": false,
1686
1686
  "multiple": true
1687
1687
  },
@@ -7222,6 +7222,86 @@
7222
7222
  }
7223
7223
  }
7224
7224
  },
7225
+ "host:recapture": {
7226
+ "id": "host:recapture",
7227
+ "description": "Re-reads a cluster's ingress (LoadBalancer) IP from the cluster and updates the cluster record, clearing a !MISSING! ingress IP in the host-naming map.",
7228
+ "strict": true,
7229
+ "pluginName": "@codiac.io/codiac-cli",
7230
+ "pluginAlias": "@codiac.io/codiac-cli",
7231
+ "pluginType": "core",
7232
+ "aliases": [
7233
+ "ingress:recapture"
7234
+ ],
7235
+ "hiddenAliases": [],
7236
+ "examples": [
7237
+ {
7238
+ "description": "Recapture interactively (prompts for the cluster).",
7239
+ "command": "<%= config.bin %> <%= command.id %>"
7240
+ },
7241
+ {
7242
+ "description": "Recapture a specific cluster non-interactively.",
7243
+ "command": "<%= config.bin %> <%= command.id %> my-cluster -e myEnterprise --silent"
7244
+ },
7245
+ {
7246
+ "description": "Renders the equivalent silent command without executing.",
7247
+ "command": "<%= config.bin %> <%= command.id %> my-cluster --to-script"
7248
+ }
7249
+ ],
7250
+ "flags": {
7251
+ "help": {
7252
+ "name": "help",
7253
+ "type": "boolean",
7254
+ "char": "h",
7255
+ "description": "Show CLI help.",
7256
+ "allowNo": false
7257
+ },
7258
+ "enterprise": {
7259
+ "name": "enterprise",
7260
+ "type": "option",
7261
+ "char": "e",
7262
+ "description": "The enterprise whose rootmap contains the cluster (optional when there is only one enterprise).",
7263
+ "required": false,
7264
+ "multiple": false
7265
+ },
7266
+ "silent": {
7267
+ "name": "silent",
7268
+ "type": "boolean",
7269
+ "description": "Executes without any user interaction; fails on missing or invalid arguments.",
7270
+ "allowNo": false,
7271
+ "exclusive": [
7272
+ "echo",
7273
+ "to-script"
7274
+ ]
7275
+ },
7276
+ "echo": {
7277
+ "name": "echo",
7278
+ "type": "boolean",
7279
+ "description": "Renders the equivalent non-interactive command for future use before executing.",
7280
+ "allowNo": false,
7281
+ "exclusive": [
7282
+ "to-script",
7283
+ "silent"
7284
+ ]
7285
+ },
7286
+ "to-script": {
7287
+ "name": "to-script",
7288
+ "type": "boolean",
7289
+ "description": "Renders the equivalent non-interactive command without executing it.",
7290
+ "allowNo": false,
7291
+ "exclusive": [
7292
+ "echo",
7293
+ "silent"
7294
+ ]
7295
+ }
7296
+ },
7297
+ "args": {
7298
+ "cluster": {
7299
+ "name": "cluster",
7300
+ "description": "Name of the cluster whose ingress IP to recapture (optional when there is only one cluster).",
7301
+ "required": false
7302
+ }
7303
+ }
7304
+ },
7225
7305
  "host:view": {
7226
7306
  "id": "host:view",
7227
7307
  "description": "Retrieves the overall map of domain routes for the given enterprise, resulting from the current host mapping strategies, environments, and assets.",
@@ -10938,6 +11018,13 @@
10938
11018
  "required": false,
10939
11019
  "multiple": false
10940
11020
  },
11021
+ "disabled": {
11022
+ "name": "disabled",
11023
+ "type": "boolean",
11024
+ "description": "Keeps the definition on record but stops it being applied to the asset at deploy time. Pass --disabled to park a probe without deleting it; omit to leave it active.",
11025
+ "required": false,
11026
+ "allowNo": true
11027
+ },
10941
11028
  "predefined": {
10942
11029
  "name": "predefined",
10943
11030
  "type": "option",
@@ -14991,6 +15078,109 @@
14991
15078
  }
14992
15079
  }
14993
15080
  },
15081
+ "noc:cluster:edit": {
15082
+ "id": "noc:cluster:edit",
15083
+ "description": "Changes the mutable connection metadata (apiserver url) on an existing cluster record. DOES NOT modify any infrastructure; it only corrects what Codiac has recorded about the cluster. The cluster name is immutable — use `cod cluster capture` to register a different cluster. Changing the apiserver url also invalidates the cached kube context for this cluster, forcing a fresh credential fetch from the cloud provider on next use.",
15084
+ "strict": true,
15085
+ "pluginName": "@codiac.io/codiac-cli",
15086
+ "pluginAlias": "@codiac.io/codiac-cli",
15087
+ "pluginType": "core",
15088
+ "aliases": [
15089
+ "cluster:edit"
15090
+ ],
15091
+ "hiddenAliases": [],
15092
+ "examples": [
15093
+ {
15094
+ "description": "Edit a cluster interactively (select it, then change its apiserver url).",
15095
+ "command": "<%= config.bin %> <%= command.id %>"
15096
+ },
15097
+ {
15098
+ "description": "Correct the apiserver url Codiac has recorded for a cluster.",
15099
+ "command": "<%= config.bin %> <%= command.id %> my-cluster --server-url https://my-cluster.hcp.centralus.azmk8s.io:443 --silent"
15100
+ },
15101
+ {
15102
+ "description": "Point a private cluster at its private-link address.",
15103
+ "command": "<%= config.bin %> <%= command.id %> my-cluster --server-url https://10.110.128.10:443 --silent"
15104
+ },
15105
+ {
15106
+ "description": "Drop the recorded url so the next capture repopulates it from the cloud provider.",
15107
+ "command": "<%= config.bin %> <%= command.id %> my-cluster --clear-server-url --silent"
15108
+ },
15109
+ {
15110
+ "description": "Renders the equivalent silent command without executing it.",
15111
+ "command": "<%= config.bin %> <%= command.id %> my-cluster --server-url https://10.110.128.10:443 --to-script"
15112
+ }
15113
+ ],
15114
+ "flags": {
15115
+ "help": {
15116
+ "name": "help",
15117
+ "type": "boolean",
15118
+ "char": "h",
15119
+ "description": "Show CLI help.",
15120
+ "allowNo": false
15121
+ },
15122
+ "server-url": {
15123
+ "name": "server-url",
15124
+ "type": "option",
15125
+ "description": "The apiserver url Codiac should record for this cluster (the remote target for kubectl), eg: https://my-cluster.hcp.centralus.azmk8s.io:443. Omit to leave it unchanged.",
15126
+ "multiple": false,
15127
+ "exclusive": [
15128
+ "clear-server-url"
15129
+ ]
15130
+ },
15131
+ "clear-server-url": {
15132
+ "name": "clear-server-url",
15133
+ "type": "boolean",
15134
+ "description": "Removes the recorded apiserver url, leaving it for the next `cod cluster capture` to repopulate.",
15135
+ "allowNo": false,
15136
+ "exclusive": [
15137
+ "server-url"
15138
+ ]
15139
+ },
15140
+ "take-defaults": {
15141
+ "name": "take-defaults",
15142
+ "type": "boolean",
15143
+ "description": "Prevents prompting for confirmation on parameters that were passed in or defaulted.",
15144
+ "allowNo": false
15145
+ },
15146
+ "silent": {
15147
+ "name": "silent",
15148
+ "type": "boolean",
15149
+ "description": "Executes without any user interaction; fails on missing or invalid arguments.",
15150
+ "allowNo": false,
15151
+ "exclusive": [
15152
+ "echo",
15153
+ "to-script"
15154
+ ]
15155
+ },
15156
+ "echo": {
15157
+ "name": "echo",
15158
+ "type": "boolean",
15159
+ "description": "Renders the equivalent non-interactive command for future use before executing.",
15160
+ "allowNo": false,
15161
+ "exclusive": [
15162
+ "to-script",
15163
+ "silent"
15164
+ ]
15165
+ },
15166
+ "to-script": {
15167
+ "name": "to-script",
15168
+ "type": "boolean",
15169
+ "description": "Renders the equivalent non-interactive command without executing it.",
15170
+ "allowNo": false,
15171
+ "exclusive": [
15172
+ "echo",
15173
+ "silent"
15174
+ ]
15175
+ }
15176
+ },
15177
+ "args": {
15178
+ "name": {
15179
+ "name": "name",
15180
+ "description": "Name of the cluster whose record you want to edit. Run `cod cluster list` to see names."
15181
+ }
15182
+ }
15183
+ },
14994
15184
  "noc:cluster:forget": {
14995
15185
  "id": "noc:cluster:forget",
14996
15186
  "description": "Permanently removes the record of a cluster. This command does NOT affect any infrastructure; it simply removes the cluster from the Codiac consciousness. You must remove all cabinets and environments in a cluster before forgetting it.",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@codiac.io/codiac-cli",
3
3
  "description": "Local command line interface for managing enterprise assets and environments.",
4
- "version": "1.3.262",
4
+ "version": "1.3.264",
5
5
  "author": "Codiac",
6
6
  "bin": {
7
7
  "codiac": "./bin/run",
@@ -173,6 +173,9 @@
173
173
  "@oclif/plugin-update"
174
174
  ],
175
175
  "update": {
176
+ "node": {
177
+ "version": "22.15.1"
178
+ },
176
179
  "s3": {
177
180
  "bucket": "installers-for-cli",
178
181
  "host": "https://installers-for-cli.s3.amazonaws.com"