hetzner-cli 2.0.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 (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +907 -0
  3. package/dist/auction/client.d.ts +4 -0
  4. package/dist/auction/client.js +103 -0
  5. package/dist/auction/commands.d.ts +2 -0
  6. package/dist/auction/commands.js +138 -0
  7. package/dist/auction/formatter.d.ts +3 -0
  8. package/dist/auction/formatter.js +87 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +39 -0
  11. package/dist/client.d.ts +2 -0
  12. package/dist/client.js +4 -0
  13. package/dist/cloud/client.d.ts +511 -0
  14. package/dist/cloud/client.js +706 -0
  15. package/dist/cloud/commands/certificate.d.ts +2 -0
  16. package/dist/cloud/commands/certificate.js +77 -0
  17. package/dist/cloud/commands/context.d.ts +2 -0
  18. package/dist/cloud/commands/context.js +78 -0
  19. package/dist/cloud/commands/datacenter.d.ts +2 -0
  20. package/dist/cloud/commands/datacenter.js +20 -0
  21. package/dist/cloud/commands/firewall.d.ts +2 -0
  22. package/dist/cloud/commands/firewall.js +77 -0
  23. package/dist/cloud/commands/floating-ip.d.ts +2 -0
  24. package/dist/cloud/commands/floating-ip.js +83 -0
  25. package/dist/cloud/commands/image.d.ts +2 -0
  26. package/dist/cloud/commands/image.js +60 -0
  27. package/dist/cloud/commands/index.d.ts +2 -0
  28. package/dist/cloud/commands/index.js +41 -0
  29. package/dist/cloud/commands/iso.d.ts +2 -0
  30. package/dist/cloud/commands/iso.js +22 -0
  31. package/dist/cloud/commands/load-balancer-type.d.ts +2 -0
  32. package/dist/cloud/commands/load-balancer-type.js +20 -0
  33. package/dist/cloud/commands/load-balancer.d.ts +2 -0
  34. package/dist/cloud/commands/load-balancer.js +177 -0
  35. package/dist/cloud/commands/location.d.ts +2 -0
  36. package/dist/cloud/commands/location.js +20 -0
  37. package/dist/cloud/commands/network.d.ts +2 -0
  38. package/dist/cloud/commands/network.js +96 -0
  39. package/dist/cloud/commands/placement-group.d.ts +2 -0
  40. package/dist/cloud/commands/placement-group.js +53 -0
  41. package/dist/cloud/commands/primary-ip.d.ts +2 -0
  42. package/dist/cloud/commands/primary-ip.js +83 -0
  43. package/dist/cloud/commands/server-type.d.ts +2 -0
  44. package/dist/cloud/commands/server-type.js +20 -0
  45. package/dist/cloud/commands/server.d.ts +2 -0
  46. package/dist/cloud/commands/server.js +260 -0
  47. package/dist/cloud/commands/ssh-key.d.ts +2 -0
  48. package/dist/cloud/commands/ssh-key.js +63 -0
  49. package/dist/cloud/commands/volume.d.ts +2 -0
  50. package/dist/cloud/commands/volume.js +92 -0
  51. package/dist/cloud/context.d.ts +28 -0
  52. package/dist/cloud/context.js +172 -0
  53. package/dist/cloud/formatter.d.ts +37 -0
  54. package/dist/cloud/formatter.js +413 -0
  55. package/dist/cloud/helpers.d.ts +18 -0
  56. package/dist/cloud/helpers.js +48 -0
  57. package/dist/cloud/types.d.ts +398 -0
  58. package/dist/cloud/types.js +5 -0
  59. package/dist/config.d.ts +1 -0
  60. package/dist/config.js +2 -0
  61. package/dist/formatter.d.ts +3 -0
  62. package/dist/formatter.js +6 -0
  63. package/dist/index.d.ts +10 -0
  64. package/dist/index.js +17 -0
  65. package/dist/robot/client.d.ts +256 -0
  66. package/dist/robot/client.js +656 -0
  67. package/dist/robot/commands/auth.d.ts +2 -0
  68. package/dist/robot/commands/auth.js +54 -0
  69. package/dist/robot/commands/boot.d.ts +2 -0
  70. package/dist/robot/commands/boot.js +72 -0
  71. package/dist/robot/commands/cancel.d.ts +2 -0
  72. package/dist/robot/commands/cancel.js +36 -0
  73. package/dist/robot/commands/failover.d.ts +2 -0
  74. package/dist/robot/commands/failover.js +42 -0
  75. package/dist/robot/commands/firewall.d.ts +2 -0
  76. package/dist/robot/commands/firewall.js +66 -0
  77. package/dist/robot/commands/index.d.ts +2 -0
  78. package/dist/robot/commands/index.js +36 -0
  79. package/dist/robot/commands/interactive.d.ts +2 -0
  80. package/dist/robot/commands/interactive.js +134 -0
  81. package/dist/robot/commands/ip.d.ts +2 -0
  82. package/dist/robot/commands/ip.js +52 -0
  83. package/dist/robot/commands/key.d.ts +2 -0
  84. package/dist/robot/commands/key.js +64 -0
  85. package/dist/robot/commands/order.d.ts +2 -0
  86. package/dist/robot/commands/order.js +33 -0
  87. package/dist/robot/commands/rdns.d.ts +2 -0
  88. package/dist/robot/commands/rdns.js +41 -0
  89. package/dist/robot/commands/reset.d.ts +2 -0
  90. package/dist/robot/commands/reset.js +77 -0
  91. package/dist/robot/commands/server.d.ts +2 -0
  92. package/dist/robot/commands/server.js +29 -0
  93. package/dist/robot/commands/storagebox.d.ts +2 -0
  94. package/dist/robot/commands/storagebox.js +116 -0
  95. package/dist/robot/commands/subnet.d.ts +2 -0
  96. package/dist/robot/commands/subnet.js +21 -0
  97. package/dist/robot/commands/traffic.d.ts +2 -0
  98. package/dist/robot/commands/traffic.js +20 -0
  99. package/dist/robot/commands/vswitch.d.ts +2 -0
  100. package/dist/robot/commands/vswitch.js +64 -0
  101. package/dist/robot/commands/wol.d.ts +2 -0
  102. package/dist/robot/commands/wol.js +20 -0
  103. package/dist/robot/formatter.d.ts +58 -0
  104. package/dist/robot/formatter.js +500 -0
  105. package/dist/robot/types.d.ts +352 -0
  106. package/dist/robot/types.js +5 -0
  107. package/dist/shared/config.d.ts +86 -0
  108. package/dist/shared/config.js +273 -0
  109. package/dist/shared/formatter.d.ts +29 -0
  110. package/dist/shared/formatter.js +118 -0
  111. package/dist/shared/helpers.d.ts +17 -0
  112. package/dist/shared/helpers.js +72 -0
  113. package/dist/shared/reference.d.ts +2 -0
  114. package/dist/shared/reference.js +626 -0
  115. package/dist/types.d.ts +75 -0
  116. package/dist/types.js +1 -0
  117. package/package.json +112 -0
@@ -0,0 +1,177 @@
1
+ import { cloudAction, cloudOutput, cloudConfirm } from '../helpers.js';
2
+ import * as fmt from '../../shared/formatter.js';
3
+ import * as cloudFmt from '../formatter.js';
4
+ export function registerLoadBalancerCommands(parent) {
5
+ const lb = parent.command('load-balancer').description('Load balancer management');
6
+ lb.command('list').alias('ls').description('List all load balancers')
7
+ .option('-l, --label-selector <selector>', 'Label selector')
8
+ .option('-s, --sort <field>', 'Sort by field')
9
+ .action(cloudAction(async (client, options) => {
10
+ const lbs = await client.listLoadBalancers({ label_selector: options.labelSelector, sort: options.sort });
11
+ cloudOutput(lbs, cloudFmt.formatLoadBalancerList, options);
12
+ }));
13
+ lb.command('describe <id>').description('Show load balancer details')
14
+ .action(cloudAction(async (client, id, options) => {
15
+ const loadBalancer = await client.getLoadBalancer(parseInt(id));
16
+ cloudOutput(loadBalancer, cloudFmt.formatLoadBalancerDetails, options);
17
+ }));
18
+ lb.command('create').description('Create a load balancer')
19
+ .requiredOption('--name <name>', 'Load balancer name')
20
+ .requiredOption('--type <type>', 'Load balancer type')
21
+ .option('--location <loc>', 'Location')
22
+ .option('--network-zone <zone>', 'Network zone')
23
+ .option('--algorithm <algo>', 'Algorithm (round_robin, least_connections)', 'round_robin')
24
+ .action(cloudAction(async (client, options) => {
25
+ const { load_balancer: created } = await client.createLoadBalancer({
26
+ name: options.name,
27
+ load_balancer_type: options.type,
28
+ location: options.location,
29
+ network_zone: options.networkZone,
30
+ algorithm: options.algorithm ? { type: options.algorithm } : undefined,
31
+ });
32
+ console.log(fmt.success(`Load balancer '${created.name}' created (ID: ${created.id})`));
33
+ }));
34
+ lb.command('delete <id>').description('Delete a load balancer')
35
+ .option('-y, --yes', 'Skip confirmation')
36
+ .action(cloudAction(async (client, id, options) => {
37
+ if (!await cloudConfirm(`Delete load balancer ${id}?`, options))
38
+ return;
39
+ await client.deleteLoadBalancer(parseInt(id));
40
+ console.log(fmt.success(`Load balancer ${id} deleted.`));
41
+ }));
42
+ lb.command('update <id>').description('Update load balancer')
43
+ .option('--name <name>', 'New name')
44
+ .action(cloudAction(async (client, id, options) => {
45
+ await client.updateLoadBalancer(parseInt(id), { name: options.name });
46
+ console.log(fmt.success(`Load balancer ${id} updated.`));
47
+ }));
48
+ lb.command('add-target <id>').description('Add target to load balancer')
49
+ .requiredOption('--type <type>', 'Target type (server, label_selector, ip)')
50
+ .option('--server <server>', 'Server ID')
51
+ .option('--label-selector <selector>', 'Label selector')
52
+ .option('--ip <ip>', 'IP address')
53
+ .option('--use-private-ip', 'Use private IP')
54
+ .action(cloudAction(async (client, id, options) => {
55
+ const target = { type: options.type, use_private_ip: !!options.usePrivateIp };
56
+ if (options.server)
57
+ target.server = { id: parseInt(options.server) };
58
+ if (options.labelSelector)
59
+ target.label_selector = { selector: options.labelSelector };
60
+ if (options.ip)
61
+ target.ip = { ip: options.ip };
62
+ await client.addTargetToLoadBalancer(parseInt(id), target);
63
+ console.log(fmt.success(`Target added to load balancer ${id}.`));
64
+ }));
65
+ lb.command('remove-target <id>').description('Remove target from load balancer')
66
+ .requiredOption('--type <type>', 'Target type (server, label_selector, ip)')
67
+ .option('--server <server>', 'Server ID')
68
+ .option('--label-selector <selector>', 'Label selector')
69
+ .option('--ip <ip>', 'IP address')
70
+ .action(cloudAction(async (client, id, options) => {
71
+ const target = { type: options.type };
72
+ if (options.server)
73
+ target.server = { id: parseInt(options.server) };
74
+ if (options.labelSelector)
75
+ target.label_selector = { selector: options.labelSelector };
76
+ if (options.ip)
77
+ target.ip = { ip: options.ip };
78
+ await client.removeTargetFromLoadBalancer(parseInt(id), target);
79
+ console.log(fmt.success(`Target removed from load balancer ${id}.`));
80
+ }));
81
+ lb.command('add-service <id>').description('Add service to load balancer')
82
+ .requiredOption('--protocol <protocol>', 'Protocol (tcp, http, https)')
83
+ .requiredOption('--listen-port <port>', 'Listen port')
84
+ .requiredOption('--destination-port <port>', 'Destination port')
85
+ .option('--proxyprotocol', 'Enable proxy protocol')
86
+ .action(cloudAction(async (client, id, options) => {
87
+ await client.addServiceToLoadBalancer(parseInt(id), {
88
+ protocol: options.protocol,
89
+ listen_port: parseInt(options.listenPort),
90
+ destination_port: parseInt(options.destinationPort),
91
+ proxyprotocol: !!options.proxyprotocol,
92
+ health_check: { protocol: options.protocol, port: parseInt(options.destinationPort), interval: 15, timeout: 10, retries: 3 },
93
+ });
94
+ console.log(fmt.success(`Service added to load balancer ${id}.`));
95
+ }));
96
+ lb.command('update-service <id>').description('Update a service on load balancer')
97
+ .requiredOption('--listen-port <port>', 'Listen port of the service to update')
98
+ .option('--protocol <protocol>', 'New protocol')
99
+ .option('--destination-port <port>', 'New destination port')
100
+ .option('--proxyprotocol <bool>', 'Enable/disable proxy protocol (true/false)')
101
+ .action(cloudAction(async (client, id, options) => {
102
+ const service = { listen_port: parseInt(options.listenPort) };
103
+ if (options.protocol)
104
+ service.protocol = options.protocol;
105
+ if (options.destinationPort)
106
+ service.destination_port = parseInt(options.destinationPort);
107
+ if (options.proxyprotocol !== undefined)
108
+ service.proxyprotocol = options.proxyprotocol === 'true';
109
+ await client.updateServiceOnLoadBalancer(parseInt(id), service);
110
+ console.log(fmt.success(`Service on load balancer ${id} updated.`));
111
+ }));
112
+ lb.command('delete-service <id>').description('Delete a service from load balancer')
113
+ .requiredOption('--listen-port <port>', 'Listen port of the service to delete')
114
+ .action(cloudAction(async (client, id, options) => {
115
+ await client.deleteServiceFromLoadBalancer(parseInt(id), parseInt(options.listenPort));
116
+ console.log(fmt.success(`Service on port ${options.listenPort} deleted from load balancer ${id}.`));
117
+ }));
118
+ lb.command('change-algorithm <id>').description('Change load balancer algorithm')
119
+ .requiredOption('--algorithm <type>', 'Algorithm type (round_robin, least_connections)')
120
+ .action(cloudAction(async (client, id, options) => {
121
+ await client.changeLoadBalancerAlgorithm(parseInt(id), options.algorithm);
122
+ console.log(fmt.success(`Algorithm changed for load balancer ${id}.`));
123
+ }));
124
+ lb.command('change-type <id>').description('Change load balancer type')
125
+ .requiredOption('--type <type>', 'New load balancer type')
126
+ .action(cloudAction(async (client, id, options) => {
127
+ await client.changeLoadBalancerType(parseInt(id), options.type);
128
+ console.log(fmt.success(`Type changed for load balancer ${id}.`));
129
+ }));
130
+ lb.command('attach-to-network <id>').description('Attach load balancer to network')
131
+ .requiredOption('--network <network>', 'Network ID')
132
+ .option('--ip <ip>', 'IP address in network')
133
+ .action(cloudAction(async (client, id, options) => {
134
+ await client.attachLoadBalancerToNetwork(parseInt(id), parseInt(options.network), options.ip);
135
+ console.log(fmt.success(`Load balancer ${id} attached to network ${options.network}.`));
136
+ }));
137
+ lb.command('detach-from-network <id>').description('Detach load balancer from network')
138
+ .requiredOption('--network <network>', 'Network ID')
139
+ .action(cloudAction(async (client, id, options) => {
140
+ await client.detachLoadBalancerFromNetwork(parseInt(id), parseInt(options.network));
141
+ console.log(fmt.success(`Load balancer ${id} detached from network ${options.network}.`));
142
+ }));
143
+ lb.command('enable-public-interface <id>').description('Enable public interface')
144
+ .action(cloudAction(async (client, id) => {
145
+ await client.enableLoadBalancerPublicInterface(parseInt(id));
146
+ console.log(fmt.success(`Public interface enabled for load balancer ${id}.`));
147
+ }));
148
+ lb.command('disable-public-interface <id>').description('Disable public interface')
149
+ .action(cloudAction(async (client, id) => {
150
+ await client.disableLoadBalancerPublicInterface(parseInt(id));
151
+ console.log(fmt.success(`Public interface disabled for load balancer ${id}.`));
152
+ }));
153
+ lb.command('enable-protection <id>').description('Enable delete protection')
154
+ .action(cloudAction(async (client, id) => {
155
+ await client.changeLoadBalancerProtection(parseInt(id), true);
156
+ console.log(fmt.success(`Protection enabled for load balancer ${id}.`));
157
+ }));
158
+ lb.command('disable-protection <id>').description('Disable delete protection')
159
+ .action(cloudAction(async (client, id) => {
160
+ await client.changeLoadBalancerProtection(parseInt(id), false);
161
+ console.log(fmt.success(`Protection disabled for load balancer ${id}.`));
162
+ }));
163
+ lb.command('add-label <id> <label>').description('Add a label (key=value)')
164
+ .action(cloudAction(async (client, id, label) => {
165
+ const loadBalancer = await client.getLoadBalancer(parseInt(id));
166
+ const [key, value] = label.split('=');
167
+ await client.updateLoadBalancer(parseInt(id), { labels: { ...loadBalancer.labels, [key]: value || '' } });
168
+ console.log(fmt.success(`Label '${key}' added.`));
169
+ }));
170
+ lb.command('remove-label <id> <key>').description('Remove a label')
171
+ .action(cloudAction(async (client, id, key) => {
172
+ const loadBalancer = await client.getLoadBalancer(parseInt(id));
173
+ const labels = Object.fromEntries(Object.entries(loadBalancer.labels).filter(([k]) => k !== key));
174
+ await client.updateLoadBalancer(parseInt(id), { labels });
175
+ console.log(fmt.success(`Label '${key}' removed.`));
176
+ }));
177
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerLocationCommands(parent: Command): void;
@@ -0,0 +1,20 @@
1
+ import { cloudAction, cloudOutput } from '../helpers.js';
2
+ import * as cloudFmt from '../formatter.js';
3
+ export function registerLocationCommands(parent) {
4
+ const location = parent.command('location').description('Location information');
5
+ location
6
+ .command('list')
7
+ .alias('ls')
8
+ .description('List all locations')
9
+ .action(cloudAction(async (client, options) => {
10
+ const locations = await client.listLocations();
11
+ cloudOutput(locations, cloudFmt.formatLocationList, options);
12
+ }));
13
+ location
14
+ .command('describe <id>')
15
+ .description('Show location details')
16
+ .action(cloudAction(async (client, id, options) => {
17
+ const location = await client.getLocation(parseInt(id));
18
+ cloudOutput(location, cloudFmt.formatLocationDetails, options);
19
+ }));
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerNetworkCommands(parent: Command): void;
@@ -0,0 +1,96 @@
1
+ import { cloudAction, cloudOutput, cloudConfirm } from '../helpers.js';
2
+ import * as fmt from '../../shared/formatter.js';
3
+ import * as cloudFmt from '../formatter.js';
4
+ export function registerNetworkCommands(parent) {
5
+ const network = parent.command('network').description('Network management');
6
+ network.command('list').alias('ls').description('List all networks')
7
+ .option('-l, --label-selector <selector>', 'Label selector')
8
+ .action(cloudAction(async (client, options) => {
9
+ const networks = await client.listNetworks({ label_selector: options.labelSelector });
10
+ cloudOutput(networks, cloudFmt.formatNetworkList, options);
11
+ }));
12
+ network.command('describe <id>').description('Show network details')
13
+ .action(cloudAction(async (client, id, options) => {
14
+ const net = await client.getNetwork(parseInt(id));
15
+ cloudOutput(net, cloudFmt.formatNetworkDetails, options);
16
+ }));
17
+ network.command('create').description('Create a network')
18
+ .requiredOption('--name <name>', 'Network name')
19
+ .requiredOption('--ip-range <range>', 'IP range (CIDR)')
20
+ .action(cloudAction(async (client, options) => {
21
+ const { network: net } = await client.createNetwork({ name: options.name, ip_range: options.ipRange });
22
+ console.log(fmt.success(`Network '${net.name}' created (ID: ${net.id})`));
23
+ }));
24
+ network.command('delete <id>').description('Delete a network')
25
+ .option('-y, --yes', 'Skip confirmation')
26
+ .action(cloudAction(async (client, id, options) => {
27
+ if (!await cloudConfirm(`Delete network ${id}?`, options))
28
+ return;
29
+ await client.deleteNetwork(parseInt(id));
30
+ console.log(fmt.success(`Network ${id} deleted.`));
31
+ }));
32
+ network.command('update <id>').description('Update a network')
33
+ .option('--name <name>', 'New name')
34
+ .action(cloudAction(async (client, id, options) => {
35
+ await client.updateNetwork(parseInt(id), { name: options.name });
36
+ console.log(fmt.success(`Network ${id} updated.`));
37
+ }));
38
+ network.command('add-subnet <id>').description('Add subnet to network')
39
+ .requiredOption('--ip-range <range>', 'Subnet IP range')
40
+ .requiredOption('--type <type>', 'Subnet type (cloud, server, vswitch)')
41
+ .requiredOption('--network-zone <zone>', 'Network zone')
42
+ .action(cloudAction(async (client, id, options) => {
43
+ await client.addSubnetToNetwork(parseInt(id), { ip_range: options.ipRange, type: options.type, network_zone: options.networkZone });
44
+ console.log(fmt.success('Subnet added.'));
45
+ }));
46
+ network.command('delete-subnet <id>').description('Delete subnet from network')
47
+ .requiredOption('--ip-range <range>', 'Subnet IP range to delete')
48
+ .action(cloudAction(async (client, id, options) => {
49
+ await client.deleteSubnetFromNetwork(parseInt(id), options.ipRange);
50
+ console.log(fmt.success('Subnet deleted.'));
51
+ }));
52
+ network.command('add-route <id>').description('Add route to network')
53
+ .requiredOption('--destination <cidr>', 'Destination CIDR')
54
+ .requiredOption('--gateway <ip>', 'Gateway IP')
55
+ .action(cloudAction(async (client, id, options) => {
56
+ await client.addRouteToNetwork(parseInt(id), { destination: options.destination, gateway: options.gateway });
57
+ console.log(fmt.success('Route added.'));
58
+ }));
59
+ network.command('delete-route <id>').description('Delete route from network')
60
+ .requiredOption('--destination <cidr>', 'Destination CIDR')
61
+ .requiredOption('--gateway <ip>', 'Gateway IP')
62
+ .action(cloudAction(async (client, id, options) => {
63
+ await client.deleteRouteFromNetwork(parseInt(id), { destination: options.destination, gateway: options.gateway });
64
+ console.log(fmt.success('Route deleted.'));
65
+ }));
66
+ network.command('change-ip-range <id>').description('Change network IP range')
67
+ .requiredOption('--ip-range <range>', 'New IP range')
68
+ .action(cloudAction(async (client, id, options) => {
69
+ await client.changeNetworkIpRange(parseInt(id), options.ipRange);
70
+ console.log(fmt.success('IP range changed.'));
71
+ }));
72
+ network.command('enable-protection <id>').description('Enable delete protection')
73
+ .action(cloudAction(async (client, id) => {
74
+ await client.changeNetworkProtection(parseInt(id), true);
75
+ console.log(fmt.success(`Protection enabled for network ${id}.`));
76
+ }));
77
+ network.command('disable-protection <id>').description('Disable delete protection')
78
+ .action(cloudAction(async (client, id) => {
79
+ await client.changeNetworkProtection(parseInt(id), false);
80
+ console.log(fmt.success(`Protection disabled for network ${id}.`));
81
+ }));
82
+ network.command('add-label <id> <label>').description('Add a label (key=value)')
83
+ .action(cloudAction(async (client, id, label) => {
84
+ const net = await client.getNetwork(parseInt(id));
85
+ const [key, value] = label.split('=');
86
+ await client.updateNetwork(parseInt(id), { labels: { ...net.labels, [key]: value || '' } });
87
+ console.log(fmt.success(`Label '${key}' added.`));
88
+ }));
89
+ network.command('remove-label <id> <key>').description('Remove a label')
90
+ .action(cloudAction(async (client, id, key) => {
91
+ const net = await client.getNetwork(parseInt(id));
92
+ const labels = Object.fromEntries(Object.entries(net.labels).filter(([k]) => k !== key));
93
+ await client.updateNetwork(parseInt(id), { labels });
94
+ console.log(fmt.success(`Label '${key}' removed.`));
95
+ }));
96
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerPlacementGroupCommands(parent: Command): void;
@@ -0,0 +1,53 @@
1
+ import { cloudAction, cloudOutput, cloudConfirm } from '../helpers.js';
2
+ import * as fmt from '../../shared/formatter.js';
3
+ import * as cloudFmt from '../formatter.js';
4
+ export function registerPlacementGroupCommands(parent) {
5
+ const pg = parent.command('placement-group').description('Placement group management');
6
+ pg.command('list').alias('ls').description('List all placement groups')
7
+ .option('-l, --label-selector <selector>', 'Label selector')
8
+ .option('-s, --sort <field>', 'Sort by field')
9
+ .action(cloudAction(async (client, options) => {
10
+ const groups = await client.listPlacementGroups({ label_selector: options.labelSelector, sort: options.sort });
11
+ cloudOutput(groups, cloudFmt.formatPlacementGroupList, options);
12
+ }));
13
+ pg.command('describe <id>').description('Show placement group details')
14
+ .action(cloudAction(async (client, id, options) => {
15
+ const group = await client.getPlacementGroup(parseInt(id));
16
+ cloudOutput(group, cloudFmt.formatPlacementGroupDetails, options);
17
+ }));
18
+ pg.command('create').description('Create a placement group')
19
+ .requiredOption('--name <name>', 'Placement group name')
20
+ .option('--type <type>', 'Placement group type', 'spread')
21
+ .action(cloudAction(async (client, options) => {
22
+ const { placement_group: group } = await client.createPlacementGroup({ name: options.name, type: (options.type || 'spread') });
23
+ console.log(fmt.success(`Placement group '${group.name}' created (ID: ${group.id})`));
24
+ }));
25
+ pg.command('delete <id>').description('Delete a placement group')
26
+ .option('-y, --yes', 'Skip confirmation')
27
+ .action(cloudAction(async (client, id, options) => {
28
+ if (!await cloudConfirm(`Delete placement group ${id}?`, options))
29
+ return;
30
+ await client.deletePlacementGroup(parseInt(id));
31
+ console.log(fmt.success(`Placement group ${id} deleted.`));
32
+ }));
33
+ pg.command('update <id>').description('Update placement group')
34
+ .option('--name <name>', 'New name')
35
+ .action(cloudAction(async (client, id, options) => {
36
+ await client.updatePlacementGroup(parseInt(id), { name: options.name });
37
+ console.log(fmt.success(`Placement group ${id} updated.`));
38
+ }));
39
+ pg.command('add-label <id> <label>').description('Add a label (key=value)')
40
+ .action(cloudAction(async (client, id, label) => {
41
+ const group = await client.getPlacementGroup(parseInt(id));
42
+ const [key, value] = label.split('=');
43
+ await client.updatePlacementGroup(parseInt(id), { labels: { ...group.labels, [key]: value || '' } });
44
+ console.log(fmt.success(`Label '${key}' added.`));
45
+ }));
46
+ pg.command('remove-label <id> <key>').description('Remove a label')
47
+ .action(cloudAction(async (client, id, key) => {
48
+ const group = await client.getPlacementGroup(parseInt(id));
49
+ const labels = Object.fromEntries(Object.entries(group.labels).filter(([k]) => k !== key));
50
+ await client.updatePlacementGroup(parseInt(id), { labels });
51
+ console.log(fmt.success(`Label '${key}' removed.`));
52
+ }));
53
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerPrimaryIpCommands(parent: Command): void;
@@ -0,0 +1,83 @@
1
+ import { cloudAction, cloudOutput, cloudConfirm } from '../helpers.js';
2
+ import * as fmt from '../../shared/formatter.js';
3
+ import * as cloudFmt from '../formatter.js';
4
+ export function registerPrimaryIpCommands(parent) {
5
+ const pip = parent.command('primary-ip').description('Primary IP management');
6
+ pip.command('list').alias('ls').description('List all primary IPs')
7
+ .option('-l, --label-selector <selector>', 'Label selector')
8
+ .action(cloudAction(async (client, options) => {
9
+ const ips = await client.listPrimaryIps({ label_selector: options.labelSelector });
10
+ cloudOutput(ips, cloudFmt.formatPrimaryIpList, options);
11
+ }));
12
+ pip.command('describe <id>').description('Show primary IP details')
13
+ .action(cloudAction(async (client, id, options) => {
14
+ const ip = await client.getPrimaryIp(parseInt(id));
15
+ cloudOutput(ip, cloudFmt.formatPrimaryIpDetails, options);
16
+ }));
17
+ pip.command('create').description('Create a primary IP')
18
+ .requiredOption('--type <type>', 'IP type (ipv4, ipv6)')
19
+ .requiredOption('--name <name>', 'Name')
20
+ .option('--datacenter <dc>', 'Datacenter')
21
+ .option('--assignee-id <id>', 'Server to assign to')
22
+ .option('--auto-delete', 'Auto-delete with server')
23
+ .action(cloudAction(async (client, options) => {
24
+ const { primary_ip: ip } = await client.createPrimaryIp({ type: options.type, name: options.name, assignee_type: 'server', datacenter: options.datacenter, assignee_id: options.assigneeId ? parseInt(options.assigneeId) : undefined, auto_delete: options.autoDelete });
25
+ console.log(fmt.success(`Primary IP created (ID: ${ip.id}, IP: ${ip.ip})`));
26
+ }));
27
+ pip.command('delete <id>').description('Delete a primary IP')
28
+ .option('-y, --yes', 'Skip confirmation')
29
+ .action(cloudAction(async (client, id, options) => {
30
+ if (!await cloudConfirm(`Delete primary IP ${id}?`, options))
31
+ return;
32
+ await client.deletePrimaryIp(parseInt(id));
33
+ console.log(fmt.success(`Primary IP ${id} deleted.`));
34
+ }));
35
+ pip.command('update <id>').description('Update primary IP')
36
+ .option('--name <name>', 'New name')
37
+ .option('--auto-delete <bool>', 'Auto-delete with server (true/false)')
38
+ .action(cloudAction(async (client, id, options) => {
39
+ await client.updatePrimaryIp(parseInt(id), { name: options.name, auto_delete: options.autoDelete ? options.autoDelete === 'true' : undefined });
40
+ console.log(fmt.success(`Primary IP ${id} updated.`));
41
+ }));
42
+ pip.command('assign <id> <server>').description('Assign primary IP to server')
43
+ .action(cloudAction(async (client, id, server) => {
44
+ await client.assignPrimaryIp(parseInt(id), parseInt(server));
45
+ console.log(fmt.success(`Primary IP ${id} assigned to server ${server}.`));
46
+ }));
47
+ pip.command('unassign <id>').description('Unassign primary IP')
48
+ .action(cloudAction(async (client, id) => {
49
+ await client.unassignPrimaryIp(parseInt(id));
50
+ console.log(fmt.success(`Primary IP ${id} unassigned.`));
51
+ }));
52
+ pip.command('enable-protection <id>').description('Enable delete protection')
53
+ .action(cloudAction(async (client, id) => {
54
+ await client.changePrimaryIpProtection(parseInt(id), true);
55
+ console.log(fmt.success(`Protection enabled for primary IP ${id}.`));
56
+ }));
57
+ pip.command('disable-protection <id>').description('Disable delete protection')
58
+ .action(cloudAction(async (client, id) => {
59
+ await client.changePrimaryIpProtection(parseInt(id), false);
60
+ console.log(fmt.success(`Protection disabled for primary IP ${id}.`));
61
+ }));
62
+ pip.command('set-rdns <id>').description('Set reverse DNS')
63
+ .requiredOption('--ip <ip>', 'IP address')
64
+ .requiredOption('--dns-ptr <ptr>', 'DNS pointer (empty to reset)')
65
+ .action(cloudAction(async (client, id, options) => {
66
+ await client.changePrimaryIpDnsPtr(parseInt(id), options.ip, options.dnsPtr || null);
67
+ console.log(fmt.success('rDNS updated.'));
68
+ }));
69
+ pip.command('add-label <id> <label>').description('Add a label (key=value)')
70
+ .action(cloudAction(async (client, id, label) => {
71
+ const ip = await client.getPrimaryIp(parseInt(id));
72
+ const [key, value] = label.split('=');
73
+ await client.updatePrimaryIp(parseInt(id), { labels: { ...ip.labels, [key]: value || '' } });
74
+ console.log(fmt.success(`Label '${key}' added.`));
75
+ }));
76
+ pip.command('remove-label <id> <key>').description('Remove a label')
77
+ .action(cloudAction(async (client, id, key) => {
78
+ const ip = await client.getPrimaryIp(parseInt(id));
79
+ const labels = Object.fromEntries(Object.entries(ip.labels).filter(([k]) => k !== key));
80
+ await client.updatePrimaryIp(parseInt(id), { labels });
81
+ console.log(fmt.success(`Label '${key}' removed.`));
82
+ }));
83
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerServerTypeCommands(parent: Command): void;
@@ -0,0 +1,20 @@
1
+ import { cloudAction, cloudOutput } from '../helpers.js';
2
+ import * as cloudFmt from '../formatter.js';
3
+ export function registerServerTypeCommands(parent) {
4
+ const serverType = parent.command('server-type').description('Server type information');
5
+ serverType
6
+ .command('list')
7
+ .alias('ls')
8
+ .description('List all server types')
9
+ .action(cloudAction(async (client, options) => {
10
+ const types = await client.listServerTypes();
11
+ cloudOutput(types, cloudFmt.formatServerTypeList, options);
12
+ }));
13
+ serverType
14
+ .command('describe <id>')
15
+ .description('Show server type details')
16
+ .action(cloudAction(async (client, id, options) => {
17
+ const type = await client.getServerType(parseInt(id));
18
+ cloudOutput(type, cloudFmt.formatServerTypeDetails, options);
19
+ }));
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerCloudServerCommands(parent: Command): void;