@peerbit/server 6.0.41 → 7.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.
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +161 -352
- package/dist/src/cli.js.map +1 -1
- package/dist/src/client.d.ts +1 -1
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +2 -5
- package/dist/src/client.js.map +1 -1
- package/dist/src/docker.d.ts +70 -1
- package/dist/src/docker.d.ts.map +1 -1
- package/dist/src/docker.js +559 -14
- package/dist/src/docker.js.map +1 -1
- package/dist/src/domain-lease.d.ts +126 -0
- package/dist/src/domain-lease.d.ts.map +1 -0
- package/dist/src/domain-lease.js +800 -0
- package/dist/src/domain-lease.js.map +1 -0
- package/dist/src/domain.d.ts +50 -2
- package/dist/src/domain.d.ts.map +1 -1
- package/dist/src/domain.js +484 -67
- package/dist/src/domain.js.map +1 -1
- package/dist/src/hetzner.d.ts +4 -21
- package/dist/src/hetzner.d.ts.map +1 -1
- package/dist/src/hetzner.js +4 -116
- package/dist/src/hetzner.js.map +1 -1
- package/dist/src/nginx-template.conf +19 -1
- package/dist/src/remotes.browser.d.ts +4 -1
- package/dist/src/remotes.browser.d.ts.map +1 -1
- package/dist/src/remotes.browser.js +1 -2
- package/dist/src/remotes.browser.js.map +1 -1
- package/dist/src/remotes.d.ts +2 -1
- package/dist/src/remotes.d.ts.map +1 -1
- package/dist/src/remotes.js +1 -0
- package/dist/src/remotes.js.map +1 -1
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +3 -5
- package/dist/src/server.js.map +1 -1
- package/dist/test/api.spec.js +2 -1
- package/dist/test/api.spec.js.map +1 -1
- package/dist/test/cli.spec.js +48 -1
- package/dist/test/cli.spec.js.map +1 -1
- package/dist/test/docker.spec.d.ts +2 -0
- package/dist/test/docker.spec.d.ts.map +1 -0
- package/dist/test/docker.spec.js +822 -0
- package/dist/test/docker.spec.js.map +1 -0
- package/dist/test/domain-lease.spec.d.ts +2 -0
- package/dist/test/domain-lease.spec.d.ts.map +1 -0
- package/dist/test/domain-lease.spec.js +530 -0
- package/dist/test/domain-lease.spec.js.map +1 -0
- package/dist/test/domain.integration.spec.js +358 -75
- package/dist/test/domain.integration.spec.js.map +1 -1
- package/dist/test/remotes.spec.d.ts +2 -0
- package/dist/test/remotes.spec.d.ts.map +1 -0
- package/dist/test/remotes.spec.js +15 -0
- package/dist/test/remotes.spec.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/assets/index-CjZwCewh.js +10 -0
- package/dist/ui/assets/index-e3g42MbC.js +9 -0
- package/dist/ui/index.html +1 -1
- package/package.json +14 -19
- package/src/cli.ts +204 -408
- package/src/client.ts +2 -6
- package/src/docker.ts +841 -20
- package/src/domain-lease.ts +1118 -0
- package/src/domain.ts +650 -90
- package/src/hetzner.ts +4 -184
- package/src/nginx-template.conf +19 -1
- package/src/remotes.browser.ts +7 -1
- package/src/remotes.ts +6 -1
- package/src/server.ts +3 -5
- package/dist/src/aws.browser.d.ts +0 -2
- package/dist/src/aws.browser.d.ts.map +0 -1
- package/dist/src/aws.browser.js +0 -3
- package/dist/src/aws.browser.js.map +0 -1
- package/dist/src/aws.d.ts +0 -30
- package/dist/src/aws.d.ts.map +0 -1
- package/dist/src/aws.js +0 -240
- package/dist/src/aws.js.map +0 -1
- package/dist/test/launch.spec.d.ts +0 -2
- package/dist/test/launch.spec.d.ts.map +0 -1
- package/dist/test/launch.spec.js +0 -23
- package/dist/test/launch.spec.js.map +0 -1
- package/dist/ui/assets/index-BBTKOM0z.js +0 -6
- package/dist/ui/assets/index-DVtj_GOf.js +0 -13
- package/src/aws.browser.ts +0 -1
- package/src/aws.ts +0 -327
package/dist/src/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AA+HA,eAAO,MAAM,GAAG,GAAU,OAAO,MAAM,EAAE;;;;;;;;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AA+HA,eAAO,MAAM,GAAG,GAAU,OAAO,MAAM,EAAE;;;;;;;;EA8lCxC,CAAC"}
|
package/dist/src/cli.js
CHANGED
|
@@ -4,15 +4,14 @@ import chalk from "chalk";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import sodium from "libsodium-wrappers";
|
|
6
6
|
import path from "path";
|
|
7
|
-
import { exit } from "process";
|
|
8
7
|
import readline from "readline";
|
|
9
8
|
import Table from "tty-table";
|
|
10
|
-
import {
|
|
11
|
-
import { createClient, waitForDomain } from "./client.js";
|
|
9
|
+
import { createClient } from "./client.js";
|
|
12
10
|
import { getHomeConfigDir, getKeypair, getPackageName, getRemotesPath, } from "./config.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
11
|
+
import { DNS_LEASE_ACCESS_TOKEN_ENV, DNS_LEASE_SERVICE_URL_ENV, DNS_LEASE_STATE_FILE_ENV, getDnsLeaseStatePath, provisionDnsLease, readDnsLeaseState, releaseDnsLease, renewDnsLease, startDnsLeaseRenewal, } from "./domain-lease.js";
|
|
12
|
+
import { getDomainFromConfig, loadConfig, startCertbot } from "./domain.js";
|
|
13
|
+
import { terminateNode as terminateHetznerNode } from "./hetzner.js";
|
|
14
|
+
import { DEFAULT_REMOTE_GROUP, Remotes, getRetiredAWSManagementError, } from "./remotes.js";
|
|
16
15
|
import { LOCAL_API_PORT } from "./routes.js";
|
|
17
16
|
import { startServerWithNode } from "./server.js";
|
|
18
17
|
await sodium.ready;
|
|
@@ -139,18 +138,40 @@ export const cli = async (args) => {
|
|
|
139
138
|
describe: "Set Libp2p listen port. Only modify this when testing locally, since NGINX config depends on the default value",
|
|
140
139
|
type: "number",
|
|
141
140
|
default: undefined,
|
|
141
|
+
})
|
|
142
|
+
.option("dns-lease-state-file", {
|
|
143
|
+
describe: `Managed DNS lease state file (or ${DNS_LEASE_STATE_FILE_ENV})`,
|
|
144
|
+
type: "string",
|
|
142
145
|
});
|
|
143
146
|
return yargs;
|
|
144
147
|
},
|
|
145
148
|
handler: async (args) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
149
|
+
let stopDnsLeaseRenewal = () => undefined;
|
|
150
|
+
try {
|
|
151
|
+
stopDnsLeaseRenewal = await startDnsLeaseRenewal({
|
|
152
|
+
statePath: args["dns-lease-state-file"] ||
|
|
153
|
+
process.env[DNS_LEASE_STATE_FILE_ENV],
|
|
154
|
+
onError: (message) => console.warn(message),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
console.warn("Managed DNS lease renewal could not start; use 'peerbit domain lease renew' to inspect it");
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const started = await startServerWithNode({
|
|
162
|
+
directory: args.directory,
|
|
163
|
+
domain: await loadConfig().then((config) => config ? getDomainFromConfig(config) : undefined),
|
|
164
|
+
ports: { api: args["port-api"], node: args["port-node"] },
|
|
165
|
+
bootstrap: args.bootstrap,
|
|
166
|
+
newSession: args.reset,
|
|
167
|
+
grantAccess: args["grant-access"],
|
|
168
|
+
});
|
|
169
|
+
started.server.once("close", stopDnsLeaseRenewal);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
stopDnsLeaseRenewal();
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
154
175
|
},
|
|
155
176
|
})
|
|
156
177
|
.command({
|
|
@@ -171,96 +192,133 @@ export const cli = async (args) => {
|
|
|
171
192
|
console.log((await kp.toPeerId()).toString());
|
|
172
193
|
},
|
|
173
194
|
})
|
|
174
|
-
.command("domain", "
|
|
195
|
+
.command("domain", "Configure a domain and certificate for this node", (yargs) => {
|
|
175
196
|
yargs
|
|
176
197
|
.command({
|
|
177
|
-
command: "
|
|
178
|
-
describe: "
|
|
179
|
-
builder:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
198
|
+
command: "lease [operation]",
|
|
199
|
+
describe: "Manage a temporary peerchecker.com DNS lease",
|
|
200
|
+
builder: (leaseArgs) => leaseArgs
|
|
201
|
+
.positional("operation", {
|
|
202
|
+
choices: ["claim", "renew", "release", "status"],
|
|
203
|
+
default: "claim",
|
|
204
|
+
describe: "Lease operation",
|
|
205
|
+
type: "string",
|
|
206
|
+
})
|
|
207
|
+
.option("service-url", {
|
|
208
|
+
describe: `Lease service URL (or ${DNS_LEASE_SERVICE_URL_ENV})`,
|
|
209
|
+
type: "string",
|
|
210
|
+
})
|
|
211
|
+
.option("access-token", {
|
|
212
|
+
describe: `Claim access token (prefer ${DNS_LEASE_ACCESS_TOKEN_ENV} to avoid shell history)`,
|
|
213
|
+
type: "string",
|
|
214
|
+
})
|
|
215
|
+
.option("address", {
|
|
216
|
+
describe: "Public IPv4 or IPv6 address for a new lease",
|
|
217
|
+
type: "string",
|
|
218
|
+
})
|
|
219
|
+
.option("email", {
|
|
220
|
+
describe: "Email for Let's Encrypt security messages",
|
|
221
|
+
type: "string",
|
|
222
|
+
})
|
|
223
|
+
.option("configure", {
|
|
224
|
+
default: true,
|
|
225
|
+
describe: "Configure NGINX and Let's Encrypt after claiming",
|
|
226
|
+
type: "boolean",
|
|
227
|
+
})
|
|
228
|
+
.option("wait", {
|
|
229
|
+
alias: "w",
|
|
230
|
+
default: true,
|
|
231
|
+
describe: "Wait for HTTPS setup to succeed",
|
|
232
|
+
type: "boolean",
|
|
233
|
+
})
|
|
234
|
+
.option("state-file", {
|
|
235
|
+
default: getDnsLeaseStatePath(),
|
|
236
|
+
describe: "Managed DNS lease state file",
|
|
237
|
+
type: "string",
|
|
238
|
+
}),
|
|
197
239
|
handler: async (args) => {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
240
|
+
const operation = args.operation || "claim";
|
|
241
|
+
const statePath = args["state-file"];
|
|
242
|
+
const serviceUrl = args["service-url"] ||
|
|
243
|
+
process.env[DNS_LEASE_SERVICE_URL_ENV];
|
|
244
|
+
if (operation === "status") {
|
|
245
|
+
const state = readDnsLeaseState(statePath);
|
|
246
|
+
console.log(JSON.stringify(state
|
|
247
|
+
? {
|
|
248
|
+
address: state.address,
|
|
249
|
+
configuredAt: state.configuredAt,
|
|
250
|
+
domain: state.domain,
|
|
251
|
+
expiresAt: state.expiresAt,
|
|
252
|
+
status: state.status,
|
|
253
|
+
}
|
|
254
|
+
: { status: "none" }, undefined, 2));
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (operation === "renew") {
|
|
258
|
+
const active = await renewDnsLease({ statePath, serviceUrl });
|
|
259
|
+
console.log(`DNS lease renewed until ${active.expiresAt}`);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (operation === "release") {
|
|
263
|
+
await releaseDnsLease({ statePath, serviceUrl });
|
|
264
|
+
console.log("DNS lease released");
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (args.configure && !args.email) {
|
|
268
|
+
throw new Error("--email is required when configuring the leased domain");
|
|
269
|
+
}
|
|
270
|
+
const active = await provisionDnsLease({
|
|
271
|
+
accessToken: args["access-token"] ||
|
|
272
|
+
process.env[DNS_LEASE_ACCESS_TOKEN_ENV],
|
|
273
|
+
address: args.address,
|
|
274
|
+
configure: args.configure
|
|
275
|
+
? (domain) => startCertbot(domain, args.email, args.wait)
|
|
276
|
+
: undefined,
|
|
277
|
+
serviceUrl,
|
|
278
|
+
statePath,
|
|
279
|
+
});
|
|
280
|
+
console.log(`DNS lease active until ${active.expiresAt}`);
|
|
201
281
|
},
|
|
202
282
|
})
|
|
203
283
|
.command({
|
|
204
|
-
command: "
|
|
205
|
-
describe: "
|
|
284
|
+
command: "configure <domain>",
|
|
285
|
+
describe: "Configure NGINX and Let's Encrypt for a domain you control",
|
|
206
286
|
builder: {
|
|
207
287
|
domain: {
|
|
208
|
-
describe: "
|
|
209
|
-
alias: "d",
|
|
288
|
+
describe: "Domain whose DNS record already points to this server",
|
|
210
289
|
type: "string",
|
|
211
290
|
demandOption: true,
|
|
212
291
|
},
|
|
213
|
-
|
|
214
|
-
describe:
|
|
215
|
-
alias: "hz",
|
|
216
|
-
type: "string",
|
|
217
|
-
require: true,
|
|
218
|
-
},
|
|
219
|
-
accessKeyId: {
|
|
220
|
-
describe: "Access key id of the AWS user",
|
|
221
|
-
alias: "ak",
|
|
222
|
-
type: "string",
|
|
223
|
-
},
|
|
224
|
-
region: {
|
|
225
|
-
describe: "AWS region",
|
|
226
|
-
alias: "r",
|
|
227
|
-
type: "string",
|
|
228
|
-
},
|
|
229
|
-
secretAccessKey: {
|
|
230
|
-
describe: "Secret key id of the AWS user",
|
|
231
|
-
alias: "sk",
|
|
232
|
-
type: "string",
|
|
233
|
-
},
|
|
234
|
-
outdir: {
|
|
235
|
-
describe: "Output path for Nginx config",
|
|
292
|
+
email: {
|
|
293
|
+
describe: "Email for Let's Encrypt security messages",
|
|
236
294
|
type: "string",
|
|
237
|
-
|
|
295
|
+
demandOption: true,
|
|
238
296
|
},
|
|
239
297
|
wait: {
|
|
240
298
|
alias: "w",
|
|
241
|
-
describe: "Wait for setup to succeed (
|
|
299
|
+
describe: "Wait for HTTPS setup to succeed (use --no-wait to return early)",
|
|
242
300
|
type: "boolean",
|
|
243
|
-
default:
|
|
301
|
+
default: true,
|
|
244
302
|
},
|
|
245
303
|
},
|
|
246
304
|
handler: async (args) => {
|
|
247
|
-
if (!!args.accessKeyId !== !!args.secretAccessKey ||
|
|
248
|
-
!!args.region !== !!args.secretAccessKey) {
|
|
249
|
-
throw new Error("Expecting either all 'accessKeyId', 'region' and 'secretAccessKey' to be provided or none");
|
|
250
|
-
}
|
|
251
|
-
await createRecord({
|
|
252
|
-
domain: args.domain,
|
|
253
|
-
hostedZoneId: args.hostedZoneId,
|
|
254
|
-
region: args.region,
|
|
255
|
-
credentials: args.accessKeyId
|
|
256
|
-
? {
|
|
257
|
-
accessKeyId: args.accessKeyId,
|
|
258
|
-
secretAccessKey: args.secretAccessKey,
|
|
259
|
-
}
|
|
260
|
-
: undefined,
|
|
261
|
-
});
|
|
262
305
|
await startCertbot(args.domain, args.email, args.wait);
|
|
263
|
-
|
|
306
|
+
},
|
|
307
|
+
})
|
|
308
|
+
.command({
|
|
309
|
+
command: "test",
|
|
310
|
+
describe: false,
|
|
311
|
+
builder: (retiredArgs) => retiredArgs.strict(false),
|
|
312
|
+
handler: () => {
|
|
313
|
+
throw new Error("Automatic test domains have been retired. Point a domain you control to this server, then run 'peerbit domain configure <domain> --email <email>'.");
|
|
314
|
+
},
|
|
315
|
+
})
|
|
316
|
+
.command({
|
|
317
|
+
command: "aws",
|
|
318
|
+
describe: false,
|
|
319
|
+
builder: (retiredArgs) => retiredArgs.strict(false),
|
|
320
|
+
handler: () => {
|
|
321
|
+
throw new Error("Automatic AWS DNS configuration has been retired. Configure DNS with your provider, then run 'peerbit domain configure <domain> --email <email>'.");
|
|
264
322
|
},
|
|
265
323
|
})
|
|
266
324
|
.strict()
|
|
@@ -268,263 +326,17 @@ export const cli = async (args) => {
|
|
|
268
326
|
})
|
|
269
327
|
.command("remote", "Handle remote nodes", (innerYargs) => {
|
|
270
328
|
innerYargs
|
|
271
|
-
.command(
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
describe: "Amount of nodes to spawn",
|
|
279
|
-
defaultDescription: "One node",
|
|
280
|
-
type: "number",
|
|
281
|
-
alias: "c",
|
|
282
|
-
default: 1,
|
|
283
|
-
});
|
|
284
|
-
awsArgs.option("region", {
|
|
285
|
-
describe: "Region",
|
|
286
|
-
type: "string",
|
|
287
|
-
defaultDescription: "Region defined in ~.aws/config",
|
|
288
|
-
choices: Object.keys(AWS_LINUX_ARM_AMIs),
|
|
289
|
-
});
|
|
290
|
-
awsArgs.option("group", {
|
|
291
|
-
describe: "Remote group to launch nodes in",
|
|
292
|
-
type: "string",
|
|
293
|
-
alias: "g",
|
|
294
|
-
default: DEFAULT_REMOTE_GROUP,
|
|
295
|
-
});
|
|
296
|
-
awsArgs.option("size", {
|
|
297
|
-
describe: "Instance size",
|
|
298
|
-
type: "string",
|
|
299
|
-
alias: "s",
|
|
300
|
-
choices: [
|
|
301
|
-
"micro",
|
|
302
|
-
"small",
|
|
303
|
-
"medium",
|
|
304
|
-
"large",
|
|
305
|
-
"xlarge",
|
|
306
|
-
"2xlarge",
|
|
307
|
-
],
|
|
308
|
-
default: "micro",
|
|
309
|
-
});
|
|
310
|
-
awsArgs.option("name", {
|
|
311
|
-
describe: "Name prefix for spawned nodes",
|
|
312
|
-
type: "string",
|
|
313
|
-
alias: "n",
|
|
314
|
-
default: "peerbit-node",
|
|
315
|
-
});
|
|
316
|
-
awsArgs.option("grant-access", {
|
|
317
|
-
describe: "Grant access to public keys on start",
|
|
318
|
-
defaultDescription: "The publickey of this device located in 'directory'",
|
|
319
|
-
type: "string",
|
|
320
|
-
array: true,
|
|
321
|
-
alias: "ga",
|
|
322
|
-
});
|
|
323
|
-
awsArgs.option("directory", {
|
|
324
|
-
describe: "Peerbit directory",
|
|
325
|
-
defaultDescription: "~.peerbit",
|
|
326
|
-
type: "string",
|
|
327
|
-
alias: "d",
|
|
328
|
-
default: getHomeConfigDir(),
|
|
329
|
-
});
|
|
330
|
-
awsArgs.option("email", {
|
|
331
|
-
describe: "Email for Let's security messages",
|
|
332
|
-
type: "string",
|
|
333
|
-
alias: "e",
|
|
334
|
-
demandOption: true,
|
|
335
|
-
});
|
|
336
|
-
awsArgs.option("server-version", {
|
|
337
|
-
describe: "@peerbit/server version or tag to install on the instance (e.g. 5.7.0-58d3d09)",
|
|
338
|
-
type: "string",
|
|
339
|
-
alias: ["sv"],
|
|
340
|
-
});
|
|
341
|
-
return awsArgs;
|
|
342
|
-
},
|
|
343
|
-
handler: async (args) => {
|
|
344
|
-
const self = (await getKeypair(args.directory)).publicKey.toPeerId();
|
|
345
|
-
const accessGrant = args["grant-access"]?.length > 0
|
|
346
|
-
? args["grant-access"].map((x) => peerIdFromString(x))
|
|
347
|
-
: [];
|
|
348
|
-
accessGrant.push(self);
|
|
349
|
-
const nodes = await launchNodes({
|
|
350
|
-
email: args.email,
|
|
351
|
-
count: args.count,
|
|
352
|
-
namePrefix: args.name,
|
|
353
|
-
region: args.region,
|
|
354
|
-
grantAccess: accessGrant,
|
|
355
|
-
size: args.size,
|
|
356
|
-
serverVersion: args["server-version"] || undefined,
|
|
357
|
-
});
|
|
358
|
-
console.log(`Waiting for ${args.count} ${args.count > 1 ? "nodes" : "node"} to spawn. This might take a few minutes. You can watch the progress in your AWS console.`);
|
|
359
|
-
const twirlTimer = (function () {
|
|
360
|
-
const P = ["\\", "|", "/", "-"];
|
|
361
|
-
let x = 0;
|
|
362
|
-
return setInterval(function () {
|
|
363
|
-
process.stdout.write("\r" + "Loading: " + chalk.hex(colors[x])(P[x++]));
|
|
364
|
-
x &= 3;
|
|
365
|
-
}, 250);
|
|
366
|
-
})();
|
|
367
|
-
for (const node of nodes) {
|
|
368
|
-
try {
|
|
369
|
-
const domain = await waitForDomain(node.publicIp);
|
|
370
|
-
const remotes = new Remotes(getRemotesPath(args.directory));
|
|
371
|
-
remotes.add({
|
|
372
|
-
name: node.name,
|
|
373
|
-
address: domain,
|
|
374
|
-
group: args.group,
|
|
375
|
-
origin: {
|
|
376
|
-
type: "aws",
|
|
377
|
-
instanceId: node.instanceId,
|
|
378
|
-
region: node.region,
|
|
379
|
-
},
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
catch (error) {
|
|
383
|
-
process.stdout.write("\r");
|
|
384
|
-
console.error(`Error waiting for domain for ip: ${node.publicIp} to be available: ${error?.toString()}`);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
process.stdout.write("\r");
|
|
388
|
-
clearInterval(twirlTimer);
|
|
389
|
-
console.log(`New nodes available (${nodes.length}):`);
|
|
390
|
-
for (const node of nodes) {
|
|
391
|
-
console.log(chalk.green(node.name));
|
|
392
|
-
}
|
|
393
|
-
},
|
|
394
|
-
})
|
|
395
|
-
.command({
|
|
396
|
-
command: "hetzner",
|
|
397
|
-
describe: "Spawn remote nodes on Hetzner Cloud",
|
|
398
|
-
builder: (hetznerArgs) => {
|
|
399
|
-
hetznerArgs.option("count", {
|
|
400
|
-
describe: "Amount of nodes to spawn",
|
|
401
|
-
defaultDescription: "One node",
|
|
402
|
-
type: "number",
|
|
403
|
-
alias: "c",
|
|
404
|
-
default: 1,
|
|
405
|
-
});
|
|
406
|
-
hetznerArgs.option("location", {
|
|
407
|
-
describe: "Location (e.g. fsn1, nbg1, hel1, ash, hil)",
|
|
408
|
-
type: "string",
|
|
409
|
-
alias: "l",
|
|
410
|
-
default: "fsn1",
|
|
411
|
-
});
|
|
412
|
-
hetznerArgs.option("group", {
|
|
413
|
-
describe: "Remote group to launch nodes in",
|
|
414
|
-
type: "string",
|
|
415
|
-
alias: "g",
|
|
416
|
-
default: DEFAULT_REMOTE_GROUP,
|
|
417
|
-
});
|
|
418
|
-
hetznerArgs.option("server-type", {
|
|
419
|
-
describe: "Server type",
|
|
420
|
-
type: "string",
|
|
421
|
-
alias: "t",
|
|
422
|
-
choices: [...HETZNER_SERVER_TYPES],
|
|
423
|
-
default: "cx11",
|
|
424
|
-
});
|
|
425
|
-
hetznerArgs.option("name", {
|
|
426
|
-
describe: "Name prefix for spawned nodes",
|
|
427
|
-
type: "string",
|
|
428
|
-
alias: "n",
|
|
429
|
-
default: "peerbit-node",
|
|
430
|
-
});
|
|
431
|
-
hetznerArgs.option("grant-access", {
|
|
432
|
-
describe: "Grant access to public keys on start",
|
|
433
|
-
defaultDescription: "The publickey of this device located in 'directory'",
|
|
434
|
-
type: "string",
|
|
435
|
-
array: true,
|
|
436
|
-
alias: "ga",
|
|
437
|
-
});
|
|
438
|
-
hetznerArgs.option("directory", {
|
|
439
|
-
describe: "Peerbit directory",
|
|
440
|
-
defaultDescription: "~.peerbit",
|
|
441
|
-
type: "string",
|
|
442
|
-
alias: "d",
|
|
443
|
-
default: getHomeConfigDir(),
|
|
444
|
-
});
|
|
445
|
-
hetznerArgs.option("email", {
|
|
446
|
-
describe: "Email for Let's security messages",
|
|
447
|
-
type: "string",
|
|
448
|
-
alias: "e",
|
|
449
|
-
demandOption: true,
|
|
450
|
-
});
|
|
451
|
-
hetznerArgs.option("token", {
|
|
452
|
-
describe: "Hetzner Cloud API token (or set HCLOUD_TOKEN)",
|
|
453
|
-
type: "string",
|
|
454
|
-
alias: ["tok"],
|
|
455
|
-
});
|
|
456
|
-
hetznerArgs.option("image", {
|
|
457
|
-
describe: "Image to use (e.g. ubuntu-22.04)",
|
|
458
|
-
type: "string",
|
|
459
|
-
default: "ubuntu-22.04",
|
|
460
|
-
});
|
|
461
|
-
hetznerArgs.option("server-version", {
|
|
462
|
-
describe: "@peerbit/server version or tag to install on the instance (e.g. 5.7.0-58d3d09)",
|
|
463
|
-
type: "string",
|
|
464
|
-
alias: ["sv"],
|
|
465
|
-
});
|
|
466
|
-
return hetznerArgs;
|
|
467
|
-
},
|
|
468
|
-
handler: async (args) => {
|
|
469
|
-
const self = (await getKeypair(args.directory)).publicKey.toPeerId();
|
|
470
|
-
const accessGrant = args["grant-access"]?.length > 0
|
|
471
|
-
? args["grant-access"].map((x) => peerIdFromString(x))
|
|
472
|
-
: [];
|
|
473
|
-
accessGrant.push(self);
|
|
474
|
-
const nodes = await launchHetznerNodes({
|
|
475
|
-
token: args.token || undefined,
|
|
476
|
-
email: args.email,
|
|
477
|
-
count: args.count,
|
|
478
|
-
namePrefix: args.name,
|
|
479
|
-
location: args.location,
|
|
480
|
-
serverType: args["server-type"],
|
|
481
|
-
grantAccess: accessGrant,
|
|
482
|
-
image: args.image,
|
|
483
|
-
serverVersion: args["server-version"] || undefined,
|
|
484
|
-
});
|
|
485
|
-
console.log(`Waiting for ${args.count} ${args.count > 1 ? "nodes" : "node"} to spawn. This might take a few minutes. You can watch the progress in your Hetzner Cloud console.`);
|
|
486
|
-
const twirlTimer = (function () {
|
|
487
|
-
const P = ["\\", "|", "/", "-"];
|
|
488
|
-
let x = 0;
|
|
489
|
-
return setInterval(function () {
|
|
490
|
-
process.stdout.write("\r" + "Loading: " + chalk.hex(colors[x])(P[x++]));
|
|
491
|
-
x &= 3;
|
|
492
|
-
}, 250);
|
|
493
|
-
})();
|
|
494
|
-
for (const node of nodes) {
|
|
495
|
-
try {
|
|
496
|
-
const domain = await waitForDomain(node.publicIp);
|
|
497
|
-
const remotes = new Remotes(getRemotesPath(args.directory));
|
|
498
|
-
remotes.add({
|
|
499
|
-
name: node.name,
|
|
500
|
-
address: domain,
|
|
501
|
-
group: args.group,
|
|
502
|
-
origin: {
|
|
503
|
-
type: "hetzner",
|
|
504
|
-
serverId: node.serverId,
|
|
505
|
-
location: node.location,
|
|
506
|
-
},
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
catch (error) {
|
|
510
|
-
process.stdout.write("\r");
|
|
511
|
-
console.error(`Error waiting for domain for ip: ${node.publicIp} to be available: ${error?.toString()}`);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
process.stdout.write("\r");
|
|
515
|
-
clearInterval(twirlTimer);
|
|
516
|
-
console.log(`New nodes available (${nodes.length}):`);
|
|
517
|
-
for (const node of nodes) {
|
|
518
|
-
console.log(chalk.green(node.name));
|
|
519
|
-
}
|
|
520
|
-
},
|
|
521
|
-
})
|
|
522
|
-
.strict()
|
|
523
|
-
.demandCommand();
|
|
329
|
+
.command({
|
|
330
|
+
command: "spawn [provider]",
|
|
331
|
+
describe: false,
|
|
332
|
+
builder: (spawnArgs) => spawnArgs.positional("provider", { type: "string" }).strict(false),
|
|
333
|
+
handler: () => {
|
|
334
|
+
throw new Error("Automatic cloud provisioning has been retired. Provision a server with your provider, configure a domain you control, then register it with 'peerbit remote add <name> <address>'.");
|
|
335
|
+
},
|
|
524
336
|
})
|
|
525
337
|
.command({
|
|
526
338
|
command: "terminate [name...]",
|
|
527
|
-
describe: "Terminate
|
|
339
|
+
describe: "Terminate legacy Hetzner instances recorded by older releases",
|
|
528
340
|
builder: (killArgs) => {
|
|
529
341
|
killArgs.option("all", {
|
|
530
342
|
describe: "Kill all nodes",
|
|
@@ -555,20 +367,17 @@ export const cli = async (args) => {
|
|
|
555
367
|
handler: async (args) => {
|
|
556
368
|
const remotes = new Remotes(getRemotesPath(args.directory));
|
|
557
369
|
const allRemotes = await remotes.all();
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
token: args.token || undefined,
|
|
570
|
-
});
|
|
571
|
-
}
|
|
370
|
+
const selectedRemotes = allRemotes.filter((remote) => args.all || args.name.includes(remote.name));
|
|
371
|
+
const retiredAWSRemote = selectedRemotes.find((remote) => remote.origin?.type === "aws");
|
|
372
|
+
if (retiredAWSRemote?.origin?.type === "aws") {
|
|
373
|
+
throw getRetiredAWSManagementError(retiredAWSRemote.origin);
|
|
374
|
+
}
|
|
375
|
+
for (const remote of selectedRemotes) {
|
|
376
|
+
if (remote.origin?.type === "hetzner") {
|
|
377
|
+
await terminateHetznerNode({
|
|
378
|
+
serverId: remote.origin.serverId,
|
|
379
|
+
token: args.token || undefined,
|
|
380
|
+
});
|
|
572
381
|
}
|
|
573
382
|
}
|
|
574
383
|
},
|