@rollupdate/hctl 0.0.0-stage → 3.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/LICENSE +21 -0
- package/README.md +1071 -2
- package/dist/auction/cache.d.ts +6 -0
- package/dist/auction/cache.js +55 -0
- package/dist/auction/client.d.ts +24 -0
- package/dist/auction/client.js +236 -0
- package/dist/auction/commands.d.ts +2 -0
- package/dist/auction/commands.js +440 -0
- package/dist/auction/diff-formatter.d.ts +3 -0
- package/dist/auction/diff-formatter.js +61 -0
- package/dist/auction/diff.d.ts +11 -0
- package/dist/auction/diff.js +28 -0
- package/dist/auction/formatter.d.ts +21 -0
- package/dist/auction/formatter.js +182 -0
- package/dist/auction/store.d.ts +24 -0
- package/dist/auction/store.js +177 -0
- package/dist/auction/types.d.ts +74 -0
- package/dist/auction/types.js +5 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +74 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +4 -0
- package/dist/cloud/browser-bootstrap.d.ts +28 -0
- package/dist/cloud/browser-bootstrap.js +480 -0
- package/dist/cloud/client.d.ts +520 -0
- package/dist/cloud/client.js +755 -0
- package/dist/cloud/commands/certificate.d.ts +2 -0
- package/dist/cloud/commands/certificate.js +108 -0
- package/dist/cloud/commands/context.d.ts +2 -0
- package/dist/cloud/commands/context.js +133 -0
- package/dist/cloud/commands/datacenter.d.ts +2 -0
- package/dist/cloud/commands/datacenter.js +24 -0
- package/dist/cloud/commands/firewall.d.ts +2 -0
- package/dist/cloud/commands/firewall.js +142 -0
- package/dist/cloud/commands/floating-ip.d.ts +2 -0
- package/dist/cloud/commands/floating-ip.js +138 -0
- package/dist/cloud/commands/image.d.ts +2 -0
- package/dist/cloud/commands/image.js +98 -0
- package/dist/cloud/commands/index.d.ts +2 -0
- package/dist/cloud/commands/index.js +47 -0
- package/dist/cloud/commands/inventory.d.ts +2 -0
- package/dist/cloud/commands/inventory.js +13 -0
- package/dist/cloud/commands/iso.d.ts +2 -0
- package/dist/cloud/commands/iso.js +27 -0
- package/dist/cloud/commands/load-balancer-type.d.ts +2 -0
- package/dist/cloud/commands/load-balancer-type.js +24 -0
- package/dist/cloud/commands/load-balancer.d.ts +2 -0
- package/dist/cloud/commands/load-balancer.js +269 -0
- package/dist/cloud/commands/location.d.ts +2 -0
- package/dist/cloud/commands/location.js +24 -0
- package/dist/cloud/commands/network.d.ts +2 -0
- package/dist/cloud/commands/network.js +157 -0
- package/dist/cloud/commands/placement-group.d.ts +2 -0
- package/dist/cloud/commands/placement-group.js +79 -0
- package/dist/cloud/commands/pricing.d.ts +2 -0
- package/dist/cloud/commands/pricing.js +15 -0
- package/dist/cloud/commands/primary-ip.d.ts +2 -0
- package/dist/cloud/commands/primary-ip.js +139 -0
- package/dist/cloud/commands/server-type.d.ts +2 -0
- package/dist/cloud/commands/server-type.js +24 -0
- package/dist/cloud/commands/server.d.ts +2 -0
- package/dist/cloud/commands/server.js +346 -0
- package/dist/cloud/commands/ssh-key.d.ts +2 -0
- package/dist/cloud/commands/ssh-key.js +94 -0
- package/dist/cloud/commands/volume.d.ts +2 -0
- package/dist/cloud/commands/volume.js +138 -0
- package/dist/cloud/context.d.ts +34 -0
- package/dist/cloud/context.js +215 -0
- package/dist/cloud/formatter.d.ts +40 -0
- package/dist/cloud/formatter.js +824 -0
- package/dist/cloud/helpers.d.ts +27 -0
- package/dist/cloud/helpers.js +67 -0
- package/dist/cloud/inventory.d.ts +100 -0
- package/dist/cloud/inventory.js +229 -0
- package/dist/cloud/pricing.d.ts +27 -0
- package/dist/cloud/pricing.js +103 -0
- package/dist/cloud/token-instructions.d.ts +2 -0
- package/dist/cloud/token-instructions.js +21 -0
- package/dist/cloud/types.d.ts +437 -0
- package/dist/cloud/types.js +5 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -0
- package/dist/formatter.d.ts +3 -0
- package/dist/formatter.js +6 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +21 -0
- package/dist/robot/client.d.ts +256 -0
- package/dist/robot/client.js +745 -0
- package/dist/robot/commands/auth.d.ts +2 -0
- package/dist/robot/commands/auth.js +54 -0
- package/dist/robot/commands/boot.d.ts +2 -0
- package/dist/robot/commands/boot.js +76 -0
- package/dist/robot/commands/cancel.d.ts +2 -0
- package/dist/robot/commands/cancel.js +37 -0
- package/dist/robot/commands/failover.d.ts +2 -0
- package/dist/robot/commands/failover.js +46 -0
- package/dist/robot/commands/firewall.d.ts +2 -0
- package/dist/robot/commands/firewall.js +72 -0
- package/dist/robot/commands/index.d.ts +2 -0
- package/dist/robot/commands/index.js +36 -0
- package/dist/robot/commands/interactive.d.ts +2 -0
- package/dist/robot/commands/interactive.js +152 -0
- package/dist/robot/commands/ip.d.ts +2 -0
- package/dist/robot/commands/ip.js +55 -0
- package/dist/robot/commands/key.d.ts +2 -0
- package/dist/robot/commands/key.js +68 -0
- package/dist/robot/commands/order.d.ts +2 -0
- package/dist/robot/commands/order.js +33 -0
- package/dist/robot/commands/rdns.d.ts +2 -0
- package/dist/robot/commands/rdns.js +41 -0
- package/dist/robot/commands/reset.d.ts +2 -0
- package/dist/robot/commands/reset.js +77 -0
- package/dist/robot/commands/server.d.ts +2 -0
- package/dist/robot/commands/server.js +32 -0
- package/dist/robot/commands/storagebox.d.ts +2 -0
- package/dist/robot/commands/storagebox.js +126 -0
- package/dist/robot/commands/subnet.d.ts +2 -0
- package/dist/robot/commands/subnet.js +24 -0
- package/dist/robot/commands/traffic.d.ts +2 -0
- package/dist/robot/commands/traffic.js +23 -0
- package/dist/robot/commands/vswitch.d.ts +2 -0
- package/dist/robot/commands/vswitch.js +81 -0
- package/dist/robot/commands/wol.d.ts +2 -0
- package/dist/robot/commands/wol.js +20 -0
- package/dist/robot/formatter.d.ts +57 -0
- package/dist/robot/formatter.js +582 -0
- package/dist/robot/types.d.ts +359 -0
- package/dist/robot/types.js +5 -0
- package/dist/shared/config.d.ts +86 -0
- package/dist/shared/config.js +289 -0
- package/dist/shared/formatter.d.ts +29 -0
- package/dist/shared/formatter.js +121 -0
- package/dist/shared/helpers.d.ts +39 -0
- package/dist/shared/helpers.js +86 -0
- package/dist/shared/init.d.ts +2 -0
- package/dist/shared/init.js +107 -0
- package/dist/shared/reference.d.ts +5 -0
- package/dist/shared/reference.js +689 -0
- package/dist/shared/schemas.d.ts +1 -0
- package/dist/shared/schemas.js +1031 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.js +2 -0
- package/package.json +127 -4
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { success } from "../../shared/formatter.js";
|
|
2
|
+
import { confirmAction, output } from "../../shared/helpers.js";
|
|
3
|
+
import { formatImageDetails, formatImageList } from "../formatter.js";
|
|
4
|
+
import { cloudAction, resolveIdOrName, } from "../helpers.js";
|
|
5
|
+
export function registerImageCommands(parent) {
|
|
6
|
+
const image = parent.command("image").description("Image management");
|
|
7
|
+
image
|
|
8
|
+
.command("list")
|
|
9
|
+
.alias("ls")
|
|
10
|
+
.description("List all images")
|
|
11
|
+
.option("-l, --label-selector <selector>", "Label selector")
|
|
12
|
+
.option("-s, --sort <field>", "Sort by field")
|
|
13
|
+
.option("--type <type>", "Filter by type (system, snapshot, backup, app)")
|
|
14
|
+
.option("--architecture <arch>", "Filter by architecture (x86, arm)")
|
|
15
|
+
.option("--status <status>", "Filter by status")
|
|
16
|
+
.action(cloudAction(async (client, options) => {
|
|
17
|
+
const images = await client.listImages({
|
|
18
|
+
label_selector: options.labelSelector,
|
|
19
|
+
sort: options.sort,
|
|
20
|
+
type: options.type,
|
|
21
|
+
architecture: options.architecture,
|
|
22
|
+
status: options.status,
|
|
23
|
+
});
|
|
24
|
+
output(images, formatImageList, options);
|
|
25
|
+
}));
|
|
26
|
+
image
|
|
27
|
+
.command("describe <id-or-name>")
|
|
28
|
+
.description("Show image details")
|
|
29
|
+
.action(cloudAction(async (client, idOrName, options) => {
|
|
30
|
+
const id = await resolveIdOrName(idOrName, "image", (name) => client.listImages({ name }));
|
|
31
|
+
const img = await client.getImage(id);
|
|
32
|
+
output(img, formatImageDetails, options);
|
|
33
|
+
}));
|
|
34
|
+
image
|
|
35
|
+
.command("update <id-or-name>")
|
|
36
|
+
.description("Update image")
|
|
37
|
+
.option("--description <desc>", "New description")
|
|
38
|
+
.option("--type <type>", "New type (snapshot)")
|
|
39
|
+
.action(cloudAction(async (client, idOrName, options) => {
|
|
40
|
+
const id = await resolveIdOrName(idOrName, "image", (name) => client.listImages({ name }));
|
|
41
|
+
await client.updateImage(id, {
|
|
42
|
+
description: options.description,
|
|
43
|
+
type: options.type,
|
|
44
|
+
});
|
|
45
|
+
console.log(success(`Image ${id} updated.`));
|
|
46
|
+
}));
|
|
47
|
+
image
|
|
48
|
+
.command("delete <id-or-name>")
|
|
49
|
+
.description("Delete an image")
|
|
50
|
+
.option("-y, --yes", "Skip confirmation")
|
|
51
|
+
.action(cloudAction(async (client, idOrName, options) => {
|
|
52
|
+
const id = await resolveIdOrName(idOrName, "image", (name) => client.listImages({ name }));
|
|
53
|
+
const img = await client.getImage(id);
|
|
54
|
+
if (!(await confirmAction(`Delete image '${img.description}' (ID: ${id})?`, options))) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
await client.deleteImage(id);
|
|
58
|
+
console.log(success(`Image '${img.description}' (ID: ${id}) deleted.`));
|
|
59
|
+
}));
|
|
60
|
+
image
|
|
61
|
+
.command("enable-protection <id-or-name>")
|
|
62
|
+
.description("Enable delete protection")
|
|
63
|
+
.action(cloudAction(async (client, idOrName) => {
|
|
64
|
+
const id = await resolveIdOrName(idOrName, "image", (name) => client.listImages({ name }));
|
|
65
|
+
await client.changeImageProtection(id, true);
|
|
66
|
+
console.log(success(`Protection enabled for image ${id}.`));
|
|
67
|
+
}));
|
|
68
|
+
image
|
|
69
|
+
.command("disable-protection <id-or-name>")
|
|
70
|
+
.description("Disable delete protection")
|
|
71
|
+
.action(cloudAction(async (client, idOrName) => {
|
|
72
|
+
const id = await resolveIdOrName(idOrName, "image", (name) => client.listImages({ name }));
|
|
73
|
+
await client.changeImageProtection(id, false);
|
|
74
|
+
console.log(success(`Protection disabled for image ${id}.`));
|
|
75
|
+
}));
|
|
76
|
+
image
|
|
77
|
+
.command("add-label <id-or-name> <label>")
|
|
78
|
+
.description("Add a label (key=value)")
|
|
79
|
+
.action(cloudAction(async (client, idOrName, label) => {
|
|
80
|
+
const id = await resolveIdOrName(idOrName, "image", (name) => client.listImages({ name }));
|
|
81
|
+
const img = await client.getImage(id);
|
|
82
|
+
const [key, value] = label.split("=");
|
|
83
|
+
await client.updateImage(id, {
|
|
84
|
+
labels: { ...img.labels, [key]: value || "" },
|
|
85
|
+
});
|
|
86
|
+
console.log(success(`Label '${key}' added.`));
|
|
87
|
+
}));
|
|
88
|
+
image
|
|
89
|
+
.command("remove-label <id-or-name> <key>")
|
|
90
|
+
.description("Remove a label")
|
|
91
|
+
.action(cloudAction(async (client, idOrName, key) => {
|
|
92
|
+
const id = await resolveIdOrName(idOrName, "image", (name) => client.listImages({ name }));
|
|
93
|
+
const img = await client.getImage(id);
|
|
94
|
+
const labels = Object.fromEntries(Object.entries(img.labels).filter(([k]) => k !== key));
|
|
95
|
+
await client.updateImage(id, { labels });
|
|
96
|
+
console.log(success(`Label '${key}' removed.`));
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { registerCertificateCommands } from "./certificate.js";
|
|
2
|
+
import { registerContextCommands } from "./context.js";
|
|
3
|
+
import { registerDatacenterCommands } from "./datacenter.js";
|
|
4
|
+
import { registerCloudFirewallCommands } from "./firewall.js";
|
|
5
|
+
import { registerFloatingIpCommands } from "./floating-ip.js";
|
|
6
|
+
import { registerImageCommands } from "./image.js";
|
|
7
|
+
import { registerInventoryCommands } from "./inventory.js";
|
|
8
|
+
import { registerIsoCommands } from "./iso.js";
|
|
9
|
+
import { registerLoadBalancerCommands } from "./load-balancer.js";
|
|
10
|
+
import { registerLoadBalancerTypeCommands } from "./load-balancer-type.js";
|
|
11
|
+
import { registerLocationCommands } from "./location.js";
|
|
12
|
+
import { registerNetworkCommands } from "./network.js";
|
|
13
|
+
import { registerPlacementGroupCommands } from "./placement-group.js";
|
|
14
|
+
import { registerPricingCommands } from "./pricing.js";
|
|
15
|
+
import { registerPrimaryIpCommands } from "./primary-ip.js";
|
|
16
|
+
import { registerCloudServerCommands } from "./server.js";
|
|
17
|
+
import { registerServerTypeCommands } from "./server-type.js";
|
|
18
|
+
import { registerCloudSshKeyCommands } from "./ssh-key.js";
|
|
19
|
+
import { registerVolumeCommands } from "./volume.js";
|
|
20
|
+
export function registerCloudCommands(parent) {
|
|
21
|
+
const cloud = parent
|
|
22
|
+
.command("cloud")
|
|
23
|
+
.description("Hetzner Cloud API management");
|
|
24
|
+
cloud.option("--token <token>", "Cloud API token (overrides context)");
|
|
25
|
+
registerContextCommands(cloud);
|
|
26
|
+
// Read-only resources
|
|
27
|
+
registerDatacenterCommands(cloud);
|
|
28
|
+
registerLocationCommands(cloud);
|
|
29
|
+
registerServerTypeCommands(cloud);
|
|
30
|
+
registerLoadBalancerTypeCommands(cloud);
|
|
31
|
+
registerIsoCommands(cloud);
|
|
32
|
+
registerPricingCommands(cloud);
|
|
33
|
+
registerInventoryCommands(cloud);
|
|
34
|
+
// Core resources
|
|
35
|
+
registerCloudServerCommands(cloud);
|
|
36
|
+
registerNetworkCommands(cloud);
|
|
37
|
+
registerCloudFirewallCommands(cloud);
|
|
38
|
+
registerFloatingIpCommands(cloud);
|
|
39
|
+
registerPrimaryIpCommands(cloud);
|
|
40
|
+
registerVolumeCommands(cloud);
|
|
41
|
+
registerLoadBalancerCommands(cloud);
|
|
42
|
+
registerImageCommands(cloud);
|
|
43
|
+
// Ancillary resources
|
|
44
|
+
registerCloudSshKeyCommands(cloud);
|
|
45
|
+
registerCertificateCommands(cloud);
|
|
46
|
+
registerPlacementGroupCommands(cloud);
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { output } from "../../shared/helpers.js";
|
|
2
|
+
import { formatInventoryReport } from "../formatter.js";
|
|
3
|
+
import { cloudAction } from "../helpers.js";
|
|
4
|
+
import { buildInventory } from "../inventory.js";
|
|
5
|
+
export function registerInventoryCommands(parent) {
|
|
6
|
+
parent
|
|
7
|
+
.command("inventory")
|
|
8
|
+
.description("Full fleet inventory with estimated monthly costs (list prices x live resources)")
|
|
9
|
+
.action(cloudAction(async (client, options) => {
|
|
10
|
+
const report = await buildInventory(client);
|
|
11
|
+
output(report, formatInventoryReport, options);
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { output } from "../../shared/helpers.js";
|
|
2
|
+
import { formatIsoDetails, formatIsoList } from "../formatter.js";
|
|
3
|
+
import { cloudAction, resolveIdOrName, } from "../helpers.js";
|
|
4
|
+
export function registerIsoCommands(parent) {
|
|
5
|
+
const iso = parent.command("iso").description("ISO image management");
|
|
6
|
+
iso
|
|
7
|
+
.command("list")
|
|
8
|
+
.alias("ls")
|
|
9
|
+
.description("List all ISOs")
|
|
10
|
+
.option("-n, --name <name>", "Filter by name")
|
|
11
|
+
.option("-a, --architecture <arch>", "Filter by architecture")
|
|
12
|
+
.action(cloudAction(async (client, options) => {
|
|
13
|
+
const isos = await client.listIsos({
|
|
14
|
+
name: options.name,
|
|
15
|
+
architecture: options.architecture,
|
|
16
|
+
});
|
|
17
|
+
output(isos, formatIsoList, options);
|
|
18
|
+
}));
|
|
19
|
+
iso
|
|
20
|
+
.command("describe <id-or-name>")
|
|
21
|
+
.description("Show ISO details")
|
|
22
|
+
.action(cloudAction(async (client, idOrName, options) => {
|
|
23
|
+
const id = await resolveIdOrName(idOrName, "ISO", (name) => client.listIsos({ name }));
|
|
24
|
+
const iso = await client.getIso(id);
|
|
25
|
+
output(iso, formatIsoDetails, options);
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { output } from "../../shared/helpers.js";
|
|
2
|
+
import { formatLoadBalancerTypeDetails, formatLoadBalancerTypeList, } from "../formatter.js";
|
|
3
|
+
import { cloudAction, resolveIdOrName, } from "../helpers.js";
|
|
4
|
+
export function registerLoadBalancerTypeCommands(parent) {
|
|
5
|
+
const lbType = parent
|
|
6
|
+
.command("load-balancer-type")
|
|
7
|
+
.description("Load balancer type information");
|
|
8
|
+
lbType
|
|
9
|
+
.command("list")
|
|
10
|
+
.alias("ls")
|
|
11
|
+
.description("List all load balancer types")
|
|
12
|
+
.action(cloudAction(async (client, options) => {
|
|
13
|
+
const types = await client.listLoadBalancerTypes();
|
|
14
|
+
output(types, formatLoadBalancerTypeList, options);
|
|
15
|
+
}));
|
|
16
|
+
lbType
|
|
17
|
+
.command("describe <id-or-name>")
|
|
18
|
+
.description("Show load balancer type details")
|
|
19
|
+
.action(cloudAction(async (client, idOrName, options) => {
|
|
20
|
+
const id = await resolveIdOrName(idOrName, "load balancer type", (name) => client.listLoadBalancerTypes({ name }));
|
|
21
|
+
const type = await client.getLoadBalancerType(id);
|
|
22
|
+
output(type, formatLoadBalancerTypeDetails, options);
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { success } from "../../shared/formatter.js";
|
|
2
|
+
import { confirmAction, output } from "../../shared/helpers.js";
|
|
3
|
+
import { formatLoadBalancerDetails, formatLoadBalancerList, } from "../formatter.js";
|
|
4
|
+
import { cloudAction, resolveIdOrName, } from "../helpers.js";
|
|
5
|
+
function resolveLbId(client, idOrName) {
|
|
6
|
+
return resolveIdOrName(idOrName, "load balancer", (name) => client.listLoadBalancers({ name }));
|
|
7
|
+
}
|
|
8
|
+
async function handleLbList(client, options) {
|
|
9
|
+
const lbs = await client.listLoadBalancers({
|
|
10
|
+
label_selector: options.labelSelector,
|
|
11
|
+
sort: options.sort,
|
|
12
|
+
});
|
|
13
|
+
output(lbs, formatLoadBalancerList, options);
|
|
14
|
+
}
|
|
15
|
+
async function handleLbDescribe(client, idOrName, options) {
|
|
16
|
+
const id = await resolveLbId(client, idOrName);
|
|
17
|
+
const loadBalancer = await client.getLoadBalancer(id);
|
|
18
|
+
output(loadBalancer, formatLoadBalancerDetails, options);
|
|
19
|
+
}
|
|
20
|
+
async function handleLbCreate(client, options) {
|
|
21
|
+
const { load_balancer: created } = await client.createLoadBalancer({
|
|
22
|
+
name: options.name,
|
|
23
|
+
load_balancer_type: options.type,
|
|
24
|
+
location: options.location,
|
|
25
|
+
network_zone: options.networkZone,
|
|
26
|
+
algorithm: options.algorithm ? { type: options.algorithm } : undefined,
|
|
27
|
+
});
|
|
28
|
+
console.log(success(`Load balancer '${created.name}' created (ID: ${created.id})`));
|
|
29
|
+
}
|
|
30
|
+
async function handleLbDelete(client, idOrName, options) {
|
|
31
|
+
const id = await resolveLbId(client, idOrName);
|
|
32
|
+
const loadBalancer = await client.getLoadBalancer(id);
|
|
33
|
+
if (!(await confirmAction(`Delete load balancer '${loadBalancer.name}' (ID: ${id})?`, options))) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
await client.deleteLoadBalancer(id);
|
|
37
|
+
console.log(success(`Load balancer '${loadBalancer.name}' (ID: ${id}) deleted.`));
|
|
38
|
+
}
|
|
39
|
+
async function handleLbUpdate(client, idOrName, options) {
|
|
40
|
+
const id = await resolveLbId(client, idOrName);
|
|
41
|
+
await client.updateLoadBalancer(id, { name: options.name });
|
|
42
|
+
console.log(success(`Load balancer ${id} updated.`));
|
|
43
|
+
}
|
|
44
|
+
async function handleLbAddTarget(client, idOrName, options) {
|
|
45
|
+
const id = await resolveLbId(client, idOrName);
|
|
46
|
+
const target = {
|
|
47
|
+
type: options.type,
|
|
48
|
+
use_private_ip: !!options.usePrivateIp,
|
|
49
|
+
};
|
|
50
|
+
if (options.server) {
|
|
51
|
+
target.server = { id: Number.parseInt(options.server, 10) };
|
|
52
|
+
}
|
|
53
|
+
if (options.labelSelector) {
|
|
54
|
+
target.label_selector = { selector: options.labelSelector };
|
|
55
|
+
}
|
|
56
|
+
if (options.ip) {
|
|
57
|
+
target.ip = { ip: options.ip };
|
|
58
|
+
}
|
|
59
|
+
await client.addTargetToLoadBalancer(id, target);
|
|
60
|
+
console.log(success(`Target added to load balancer ${id}.`));
|
|
61
|
+
}
|
|
62
|
+
async function handleLbRemoveTarget(client, idOrName, options) {
|
|
63
|
+
const id = await resolveLbId(client, idOrName);
|
|
64
|
+
const target = { type: options.type };
|
|
65
|
+
if (options.server) {
|
|
66
|
+
target.server = { id: Number.parseInt(options.server, 10) };
|
|
67
|
+
}
|
|
68
|
+
if (options.labelSelector) {
|
|
69
|
+
target.label_selector = { selector: options.labelSelector };
|
|
70
|
+
}
|
|
71
|
+
if (options.ip) {
|
|
72
|
+
target.ip = { ip: options.ip };
|
|
73
|
+
}
|
|
74
|
+
await client.removeTargetFromLoadBalancer(id, target);
|
|
75
|
+
console.log(success(`Target removed from load balancer ${id}.`));
|
|
76
|
+
}
|
|
77
|
+
async function handleLbAddService(client, idOrName, options) {
|
|
78
|
+
const id = await resolveLbId(client, idOrName);
|
|
79
|
+
await client.addServiceToLoadBalancer(id, {
|
|
80
|
+
protocol: options.protocol,
|
|
81
|
+
listen_port: Number.parseInt(options.listenPort, 10),
|
|
82
|
+
destination_port: Number.parseInt(options.destinationPort, 10),
|
|
83
|
+
proxyprotocol: !!options.proxyprotocol,
|
|
84
|
+
health_check: {
|
|
85
|
+
protocol: options.protocol,
|
|
86
|
+
port: Number.parseInt(options.destinationPort, 10),
|
|
87
|
+
interval: 15,
|
|
88
|
+
timeout: 10,
|
|
89
|
+
retries: 3,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
console.log(success(`Service added to load balancer ${id}.`));
|
|
93
|
+
}
|
|
94
|
+
async function handleLbUpdateService(client, idOrName, options) {
|
|
95
|
+
const id = await resolveLbId(client, idOrName);
|
|
96
|
+
const service = {
|
|
97
|
+
listen_port: Number.parseInt(options.listenPort, 10),
|
|
98
|
+
};
|
|
99
|
+
if (options.protocol) {
|
|
100
|
+
service.protocol = options.protocol;
|
|
101
|
+
}
|
|
102
|
+
if (options.destinationPort) {
|
|
103
|
+
service.destination_port = Number.parseInt(options.destinationPort, 10);
|
|
104
|
+
}
|
|
105
|
+
if (options.proxyprotocol !== undefined) {
|
|
106
|
+
service.proxyprotocol = options.proxyprotocol === "true";
|
|
107
|
+
}
|
|
108
|
+
await client.updateServiceOnLoadBalancer(id, service);
|
|
109
|
+
console.log(success(`Service on load balancer ${id} updated.`));
|
|
110
|
+
}
|
|
111
|
+
async function handleLbDeleteService(client, idOrName, options) {
|
|
112
|
+
const id = await resolveLbId(client, idOrName);
|
|
113
|
+
await client.deleteServiceFromLoadBalancer(id, Number.parseInt(options.listenPort, 10));
|
|
114
|
+
console.log(success(`Service on port ${options.listenPort} deleted from load balancer ${id}.`));
|
|
115
|
+
}
|
|
116
|
+
async function handleLbChangeAlgorithm(client, idOrName, options) {
|
|
117
|
+
const id = await resolveLbId(client, idOrName);
|
|
118
|
+
await client.changeLoadBalancerAlgorithm(id, options.algorithm);
|
|
119
|
+
console.log(success(`Algorithm changed for load balancer ${id}.`));
|
|
120
|
+
}
|
|
121
|
+
async function handleLbChangeType(client, idOrName, options) {
|
|
122
|
+
const id = await resolveLbId(client, idOrName);
|
|
123
|
+
await client.changeLoadBalancerType(id, options.type);
|
|
124
|
+
console.log(success(`Type changed for load balancer ${id}.`));
|
|
125
|
+
}
|
|
126
|
+
async function handleLbAttachToNetwork(client, idOrName, options) {
|
|
127
|
+
const id = await resolveLbId(client, idOrName);
|
|
128
|
+
await client.attachLoadBalancerToNetwork(id, Number.parseInt(options.network, 10), options.ip);
|
|
129
|
+
console.log(success(`Load balancer ${id} attached to network ${options.network}.`));
|
|
130
|
+
}
|
|
131
|
+
async function handleLbDetachFromNetwork(client, idOrName, options) {
|
|
132
|
+
const id = await resolveLbId(client, idOrName);
|
|
133
|
+
await client.detachLoadBalancerFromNetwork(id, Number.parseInt(options.network, 10));
|
|
134
|
+
console.log(success(`Load balancer ${id} detached from network ${options.network}.`));
|
|
135
|
+
}
|
|
136
|
+
async function handleLbEnablePublicInterface(client, idOrName) {
|
|
137
|
+
const id = await resolveLbId(client, idOrName);
|
|
138
|
+
await client.enableLoadBalancerPublicInterface(id);
|
|
139
|
+
console.log(success(`Public interface enabled for load balancer ${id}.`));
|
|
140
|
+
}
|
|
141
|
+
async function handleLbDisablePublicInterface(client, idOrName) {
|
|
142
|
+
const id = await resolveLbId(client, idOrName);
|
|
143
|
+
await client.disableLoadBalancerPublicInterface(id);
|
|
144
|
+
console.log(success(`Public interface disabled for load balancer ${id}.`));
|
|
145
|
+
}
|
|
146
|
+
async function handleLbEnableProtection(client, idOrName) {
|
|
147
|
+
const id = await resolveLbId(client, idOrName);
|
|
148
|
+
await client.changeLoadBalancerProtection(id, true);
|
|
149
|
+
console.log(success(`Protection enabled for load balancer ${id}.`));
|
|
150
|
+
}
|
|
151
|
+
async function handleLbDisableProtection(client, idOrName) {
|
|
152
|
+
const id = await resolveLbId(client, idOrName);
|
|
153
|
+
await client.changeLoadBalancerProtection(id, false);
|
|
154
|
+
console.log(success(`Protection disabled for load balancer ${id}.`));
|
|
155
|
+
}
|
|
156
|
+
async function handleLbAddLabel(client, idOrName, label) {
|
|
157
|
+
const id = await resolveLbId(client, idOrName);
|
|
158
|
+
const loadBalancer = await client.getLoadBalancer(id);
|
|
159
|
+
const [key, value] = label.split("=");
|
|
160
|
+
await client.updateLoadBalancer(id, {
|
|
161
|
+
labels: { ...loadBalancer.labels, [key]: value || "" },
|
|
162
|
+
});
|
|
163
|
+
console.log(success(`Label '${key}' added.`));
|
|
164
|
+
}
|
|
165
|
+
async function handleLbRemoveLabel(client, idOrName, key) {
|
|
166
|
+
const id = await resolveLbId(client, idOrName);
|
|
167
|
+
const loadBalancer = await client.getLoadBalancer(id);
|
|
168
|
+
const labels = Object.fromEntries(Object.entries(loadBalancer.labels).filter(([k]) => k !== key));
|
|
169
|
+
await client.updateLoadBalancer(id, { labels });
|
|
170
|
+
console.log(success(`Label '${key}' removed.`));
|
|
171
|
+
}
|
|
172
|
+
export function registerLoadBalancerCommands(parent) {
|
|
173
|
+
const lb = parent
|
|
174
|
+
.command("load-balancer")
|
|
175
|
+
.description("Load balancer management");
|
|
176
|
+
lb.command("list")
|
|
177
|
+
.alias("ls")
|
|
178
|
+
.description("List all load balancers")
|
|
179
|
+
.option("-l, --label-selector <selector>", "Label selector")
|
|
180
|
+
.option("-s, --sort <field>", "Sort by field")
|
|
181
|
+
.action(cloudAction(handleLbList));
|
|
182
|
+
lb.command("describe <id-or-name>")
|
|
183
|
+
.description("Show load balancer details")
|
|
184
|
+
.action(cloudAction(handleLbDescribe));
|
|
185
|
+
lb.command("create")
|
|
186
|
+
.description("Create a load balancer")
|
|
187
|
+
.requiredOption("--name <name>", "Load balancer name")
|
|
188
|
+
.requiredOption("--type <type>", "Load balancer type")
|
|
189
|
+
.option("--location <loc>", "Location")
|
|
190
|
+
.option("--network-zone <zone>", "Network zone")
|
|
191
|
+
.option("--algorithm <algo>", "Algorithm (round_robin, least_connections)", "round_robin")
|
|
192
|
+
.action(cloudAction(handleLbCreate));
|
|
193
|
+
lb.command("delete <id-or-name>")
|
|
194
|
+
.description("Delete a load balancer")
|
|
195
|
+
.option("-y, --yes", "Skip confirmation")
|
|
196
|
+
.action(cloudAction(handleLbDelete));
|
|
197
|
+
lb.command("update <id-or-name>")
|
|
198
|
+
.description("Update load balancer")
|
|
199
|
+
.option("--name <name>", "New name")
|
|
200
|
+
.action(cloudAction(handleLbUpdate));
|
|
201
|
+
lb.command("add-target <id-or-name>")
|
|
202
|
+
.description("Add target to load balancer")
|
|
203
|
+
.requiredOption("--type <type>", "Target type (server, label_selector, ip)")
|
|
204
|
+
.option("--server <server>", "Server ID")
|
|
205
|
+
.option("--label-selector <selector>", "Label selector")
|
|
206
|
+
.option("--ip <ip>", "IP address")
|
|
207
|
+
.option("--use-private-ip", "Use private IP")
|
|
208
|
+
.action(cloudAction(handleLbAddTarget));
|
|
209
|
+
lb.command("remove-target <id-or-name>")
|
|
210
|
+
.description("Remove target from load balancer")
|
|
211
|
+
.requiredOption("--type <type>", "Target type (server, label_selector, ip)")
|
|
212
|
+
.option("--server <server>", "Server ID")
|
|
213
|
+
.option("--label-selector <selector>", "Label selector")
|
|
214
|
+
.option("--ip <ip>", "IP address")
|
|
215
|
+
.action(cloudAction(handleLbRemoveTarget));
|
|
216
|
+
lb.command("add-service <id-or-name>")
|
|
217
|
+
.description("Add service to load balancer")
|
|
218
|
+
.requiredOption("--protocol <protocol>", "Protocol (tcp, http, https)")
|
|
219
|
+
.requiredOption("--listen-port <port>", "Listen port")
|
|
220
|
+
.requiredOption("--destination-port <port>", "Destination port")
|
|
221
|
+
.option("--proxyprotocol", "Enable proxy protocol")
|
|
222
|
+
.action(cloudAction(handleLbAddService));
|
|
223
|
+
lb.command("update-service <id-or-name>")
|
|
224
|
+
.description("Update a service on load balancer")
|
|
225
|
+
.requiredOption("--listen-port <port>", "Listen port of the service to update")
|
|
226
|
+
.option("--protocol <protocol>", "New protocol")
|
|
227
|
+
.option("--destination-port <port>", "New destination port")
|
|
228
|
+
.option("--proxyprotocol <bool>", "Enable/disable proxy protocol (true/false)")
|
|
229
|
+
.action(cloudAction(handleLbUpdateService));
|
|
230
|
+
lb.command("delete-service <id-or-name>")
|
|
231
|
+
.description("Delete a service from load balancer")
|
|
232
|
+
.requiredOption("--listen-port <port>", "Listen port of the service to delete")
|
|
233
|
+
.action(cloudAction(handleLbDeleteService));
|
|
234
|
+
lb.command("change-algorithm <id-or-name>")
|
|
235
|
+
.description("Change load balancer algorithm")
|
|
236
|
+
.requiredOption("--algorithm <type>", "Algorithm type (round_robin, least_connections)")
|
|
237
|
+
.action(cloudAction(handleLbChangeAlgorithm));
|
|
238
|
+
lb.command("change-type <id-or-name>")
|
|
239
|
+
.description("Change load balancer type")
|
|
240
|
+
.requiredOption("--type <type>", "New load balancer type")
|
|
241
|
+
.action(cloudAction(handleLbChangeType));
|
|
242
|
+
lb.command("attach-to-network <id-or-name>")
|
|
243
|
+
.description("Attach load balancer to network")
|
|
244
|
+
.requiredOption("--network <network>", "Network ID")
|
|
245
|
+
.option("--ip <ip>", "IP address in network")
|
|
246
|
+
.action(cloudAction(handleLbAttachToNetwork));
|
|
247
|
+
lb.command("detach-from-network <id-or-name>")
|
|
248
|
+
.description("Detach load balancer from network")
|
|
249
|
+
.requiredOption("--network <network>", "Network ID")
|
|
250
|
+
.action(cloudAction(handleLbDetachFromNetwork));
|
|
251
|
+
lb.command("enable-public-interface <id-or-name>")
|
|
252
|
+
.description("Enable public interface")
|
|
253
|
+
.action(cloudAction(handleLbEnablePublicInterface));
|
|
254
|
+
lb.command("disable-public-interface <id-or-name>")
|
|
255
|
+
.description("Disable public interface")
|
|
256
|
+
.action(cloudAction(handleLbDisablePublicInterface));
|
|
257
|
+
lb.command("enable-protection <id-or-name>")
|
|
258
|
+
.description("Enable delete protection")
|
|
259
|
+
.action(cloudAction(handleLbEnableProtection));
|
|
260
|
+
lb.command("disable-protection <id-or-name>")
|
|
261
|
+
.description("Disable delete protection")
|
|
262
|
+
.action(cloudAction(handleLbDisableProtection));
|
|
263
|
+
lb.command("add-label <id-or-name> <label>")
|
|
264
|
+
.description("Add a label (key=value)")
|
|
265
|
+
.action(cloudAction(handleLbAddLabel));
|
|
266
|
+
lb.command("remove-label <id-or-name> <key>")
|
|
267
|
+
.description("Remove a label")
|
|
268
|
+
.action(cloudAction(handleLbRemoveLabel));
|
|
269
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { output } from "../../shared/helpers.js";
|
|
2
|
+
import { formatLocationDetails, formatLocationList } from "../formatter.js";
|
|
3
|
+
import { cloudAction, resolveIdOrName, } from "../helpers.js";
|
|
4
|
+
export function registerLocationCommands(parent) {
|
|
5
|
+
const location = parent
|
|
6
|
+
.command("location")
|
|
7
|
+
.description("Location information");
|
|
8
|
+
location
|
|
9
|
+
.command("list")
|
|
10
|
+
.alias("ls")
|
|
11
|
+
.description("List all locations")
|
|
12
|
+
.action(cloudAction(async (client, options) => {
|
|
13
|
+
const locations = await client.listLocations();
|
|
14
|
+
output(locations, formatLocationList, options);
|
|
15
|
+
}));
|
|
16
|
+
location
|
|
17
|
+
.command("describe <id-or-name>")
|
|
18
|
+
.description("Show location details")
|
|
19
|
+
.action(cloudAction(async (client, idOrName, options) => {
|
|
20
|
+
const id = await resolveIdOrName(idOrName, "location", (name) => client.listLocations({ name }));
|
|
21
|
+
const location = await client.getLocation(id);
|
|
22
|
+
output(location, formatLocationDetails, options);
|
|
23
|
+
}));
|
|
24
|
+
}
|