@stacksjs/ts-cloud 0.12.10 → 0.12.12
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/aws/index.js +1 -1
- package/dist/bin/{chunk-d7ke90zt.js → chunk-0b49jjgr.js} +1 -1
- package/dist/bin/chunk-0xnnkeb1.js +1 -0
- package/dist/bin/{chunk-9a88fp00.js → chunk-227jmf2b.js} +2 -2
- package/dist/bin/chunk-2nyyg44g.js +1 -0
- package/dist/bin/{chunk-e2bybahr.js → chunk-2ztr119n.js} +1 -1
- package/dist/bin/chunk-43xj5cny.js +1 -0
- package/dist/bin/chunk-5w6y9pmz.js +1 -0
- package/dist/bin/{chunk-8ewncfce.js → chunk-5x4rdx8k.js} +1 -1
- package/dist/bin/chunk-6zc6a6t3.js +725 -0
- package/dist/bin/chunk-7aagqqr9.js +1 -0
- package/dist/{chunk-pb47hr0h.js → bin/chunk-85qrgshq.js} +1 -1
- package/dist/bin/{chunk-c0bdafbx.js → chunk-8zk8msx0.js} +1 -1
- package/dist/bin/chunk-9j83q0r4.js +1 -0
- package/dist/bin/{chunk-b4wt9jcg.js → chunk-9nhqbes6.js} +2 -2
- package/dist/bin/chunk-a4js49mx.js +1 -0
- package/dist/bin/{chunk-6tfwm33r.js → chunk-a9e0hvwe.js} +3 -3
- package/dist/bin/{chunk-cd0ps58j.js → chunk-a9tgxf2h.js} +1 -1
- package/dist/bin/chunk-aahrv359.js +1 -0
- package/dist/bin/{chunk-zpe64t4r.js → chunk-bfx23be3.js} +1 -1
- package/dist/bin/{chunk-tfbs8k8v.js → chunk-bpps61am.js} +1 -1
- package/dist/bin/{chunk-ja1vjdn1.js → chunk-bzth6d1s.js} +1 -1
- package/dist/bin/{chunk-0zwknfwp.js → chunk-ca3taw2m.js} +1 -1
- package/dist/bin/chunk-cgzp0328.js +1 -0
- package/dist/{chunk-w2ddj42w.js → bin/chunk-d2aaef9v.js} +1 -1
- package/dist/bin/{chunk-xk08030d.js → chunk-e0z2t4mf.js} +2 -2
- package/dist/bin/{chunk-btsyjhk7.js → chunk-e2dnxp8d.js} +2 -2
- package/dist/bin/{chunk-s4yzes15.js → chunk-empfsmdk.js} +1 -1
- package/dist/bin/chunk-er3mww4m.js +1 -0
- package/dist/bin/{chunk-azymqbcy.js → chunk-fmp5bv0j.js} +1 -1
- package/dist/bin/{chunk-71t1gmsq.js → chunk-g3kp5ddx.js} +1 -1
- package/dist/bin/{chunk-q5cmfpzt.js → chunk-grepda40.js} +1 -1
- package/dist/{chunk-c8cadhgc.js → bin/chunk-h6xqtypj.js} +2 -2
- package/dist/bin/{chunk-3aph4c1w.js → chunk-hwk9ahms.js} +1 -1
- package/dist/bin/{chunk-dz1ec589.js → chunk-jxd3j00s.js} +2 -2
- package/dist/bin/{chunk-my3ewh3a.js → chunk-k1xw3zbm.js} +2 -2
- package/dist/bin/{chunk-ehc63fvs.js → chunk-m07s5esk.js} +1 -1
- package/dist/bin/{chunk-e5ab5twy.js → chunk-m9r5jype.js} +2 -2
- package/dist/bin/{chunk-4q6tad44.js → chunk-n20kbxwb.js} +91 -91
- package/dist/bin/{chunk-kg61p5hw.js → chunk-n2fnav53.js} +2 -2
- package/dist/bin/{chunk-w32xv8n4.js → chunk-nv211m42.js} +2 -2
- package/dist/bin/chunk-psgjy3z4.js +1 -0
- package/dist/bin/chunk-qmnr82da.js +1 -0
- package/dist/bin/{chunk-mcr0r4at.js → chunk-qqpb82ty.js} +2 -2
- package/dist/bin/{chunk-xhwqpgwq.js → chunk-rqc8btkj.js} +1 -1
- package/dist/bin/chunk-rs85xvt7.js +1 -0
- package/dist/bin/{chunk-hq9x489e.js → chunk-t5ngva49.js} +1 -1
- package/dist/bin/{chunk-82mj52xr.js → chunk-t7rcfwqc.js} +1 -1
- package/dist/bin/{chunk-vj2dp0nh.js → chunk-tjgy10zm.js} +6 -6
- package/dist/bin/chunk-v0beqdna.js +1 -0
- package/dist/bin/chunk-vf2s3tba.js +1 -0
- package/dist/bin/{chunk-0thy7q96.js → chunk-vzkfjrx2.js} +74 -75
- package/dist/bin/{chunk-rtecnmts.js → chunk-wcem4cqb.js} +2 -2
- package/dist/bin/chunk-wsh5ervz.js +1 -0
- package/dist/bin/chunk-xenhbdmr.js +1 -0
- package/dist/bin/chunk-xrdpxwbf.js +1 -0
- package/dist/bin/{chunk-mfrf9q4b.js → chunk-y68m9bx7.js} +1 -1
- package/dist/bin/cli.js +143 -143
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-982rye5b.js → chunk-2ybcnrte.js} +1 -1
- package/dist/chunk-4884der5.js +1 -0
- package/dist/{bin/chunk-9kf0np8j.js → chunk-4wdxsnn2.js} +1 -1
- package/dist/{bin/chunk-xkfrqqcs.js → chunk-5hhyyhjt.js} +1 -1
- package/dist/chunk-5zkacdw1.js +1 -0
- package/dist/{chunk-557qj7q9.js → chunk-6cxb8d6y.js} +2 -2
- package/dist/chunk-6f68caq0.js +1 -0
- package/dist/{chunk-2qm3rw8b.js → chunk-7z50g5xz.js} +2 -2
- package/dist/chunk-8fh4m5ge.js +1 -0
- package/dist/chunk-97pb7wb1.js +1 -0
- package/dist/{chunk-a368cs92.js → chunk-ac87ds1k.js} +1 -1
- package/dist/{chunk-qrte4gy2.js → chunk-dndxwssj.js} +1 -1
- package/dist/{chunk-y3tbcxb7.js → chunk-ea7tn8nn.js} +89 -90
- package/dist/{bin/chunk-a7w13qfm.js → chunk-ess6vxfj.js} +2 -2
- package/dist/{chunk-rg7d67xk.js → chunk-j06r5rwv.js} +1 -1
- package/dist/{chunk-70v77sqv.js → chunk-j1g67djb.js} +2 -2
- package/dist/{chunk-fbwpm0zm.js → chunk-k8x8mrkr.js} +1 -1
- package/dist/{chunk-82gezmen.js → chunk-mnmz8t7q.js} +1 -1
- package/dist/{chunk-7j100g7w.js → chunk-n1fyryha.js} +1 -1
- package/dist/{chunk-c1hr34a5.js → chunk-n1hg0jxs.js} +2 -2
- package/dist/{chunk-bcffjsnj.js → chunk-n5xmh0ma.js} +1 -1
- package/dist/chunk-q22qfwsc.js +22 -0
- package/dist/{chunk-5hkq5081.js → chunk-q9a1z53k.js} +2 -2
- package/dist/{chunk-fsssdd5k.js → chunk-r8t25tbm.js} +91 -91
- package/dist/chunk-t8hzekmk.js +585 -0
- package/dist/{chunk-2k0mt6j5.js → chunk-whyttetx.js} +1 -1
- package/dist/{chunk-gkj1tpsn.js → chunk-yf8stygs.js} +1 -1
- package/dist/{chunk-jphewtbx.js → chunk-ze5x2bpm.js} +1 -1
- package/dist/{chunk-jxrs1219.js → chunk-zh0apedk.js} +2 -2
- package/dist/{chunk-0hw5wjjg.js → chunk-zjyz926j.js} +1 -1
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/hetzner/cloud-init.d.ts +14 -1
- package/dist/drivers/hetzner/driver.d.ts +2 -15
- package/dist/drivers/hetzner/state.d.ts +17 -2
- package/dist/drivers/index.d.ts +17 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/local-box/driver.d.ts +1 -1
- package/dist/drivers/shared/compute-deploy.d.ts +0 -12
- package/dist/drivers/shared/compute-provision.d.ts +7 -0
- package/dist/drivers/shared/driver-state.d.ts +68 -0
- package/dist/drivers/shared/remote-exec.d.ts +10 -1
- package/dist/drivers/shared/remote-failure.d.ts +41 -0
- package/dist/drivers/shared/rpx-gateway.d.ts +124 -4
- package/dist/drivers/shared/ssh-transport.d.ts +121 -0
- package/dist/drivers/ssh/bootstrap.d.ts +71 -0
- package/dist/drivers/ssh/config.d.ts +94 -0
- package/dist/drivers/ssh/config.test.d.ts +1 -0
- package/dist/drivers/ssh/driver.d.ts +107 -0
- package/dist/drivers/ssh/factory-wiring.test.d.ts +1 -0
- package/dist/drivers/ssh/first-boot.d.ts +38 -0
- package/dist/drivers/ssh/preflight.d.ts +76 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +7 -7
- package/dist/operations/index.js +1 -1
- package/dist/operations/inventory.d.ts +46 -1
- package/dist/protection/index.js +1 -1
- package/dist/push/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +5 -5
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +5 -5
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +5 -5
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +2 -2
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +5 -5
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +5 -5
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +5 -5
- package/dist/ui/server/activity.html +2 -2
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +5 -5
- package/dist/ui/server/deployments.html +5 -5
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +5 -5
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +5 -5
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +1 -1
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +1 -1
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +1 -1
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +6 -6
- package/dist/ui-src/src/charts.ts +1 -1
- package/dist/ui-src/src/topology.ts +1 -1
- package/package.json +3 -3
- package/dist/bin/chunk-04dkwaqp.js +0 -1
- package/dist/bin/chunk-5nkqza92.js +0 -1
- package/dist/bin/chunk-64vczwwt.js +0 -1
- package/dist/bin/chunk-7g2ahkse.js +0 -1
- package/dist/bin/chunk-aw8bhggq.js +0 -594
- package/dist/bin/chunk-cxt74wsj.js +0 -1
- package/dist/bin/chunk-djg4zyqk.js +0 -1
- package/dist/bin/chunk-dkaz333b.js +0 -1
- package/dist/bin/chunk-edvvx3hg.js +0 -1
- package/dist/bin/chunk-f06c5np9.js +0 -1
- package/dist/bin/chunk-gq8794k6.js +0 -1
- package/dist/bin/chunk-k3120rx6.js +0 -1
- package/dist/bin/chunk-nw3d4k52.js +0 -1
- package/dist/bin/chunk-p70bc9yr.js +0 -1
- package/dist/bin/chunk-sg1g92cf.js +0 -1
- package/dist/bin/chunk-tvz9c388.js +0 -1
- package/dist/bin/chunk-y1h63vpm.js +0 -1
- package/dist/bin/chunk-zdt2rjk6.js +0 -1
- package/dist/bin/chunk-zh2d4704.js +0 -1
- package/dist/chunk-1bj94sc2.js +0 -1
- package/dist/chunk-3swnmwfc.js +0 -454
- package/dist/chunk-5pbtmy2k.js +0 -1
- package/dist/chunk-7sc8t7v1.js +0 -1
- package/dist/chunk-gny5s4kp.js +0 -1
- package/dist/chunk-qpjcd415.js +0 -22
- package/dist/chunk-xkw7h4pw.js +0 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type SshHostKeyPolicy = 'pin' | 'accept-new' | 'insecure';
|
|
2
|
+
export interface SshTransportOptions {
|
|
3
|
+
user: string;
|
|
4
|
+
/** @default 22 */
|
|
5
|
+
port?: number;
|
|
6
|
+
/** Private key passed as `-i`. */
|
|
7
|
+
identityFile: string;
|
|
8
|
+
/**
|
|
9
|
+
* `'insecure'` disables host-key checking (the cloud drivers' behaviour).
|
|
10
|
+
* Otherwise the policy plus the known_hosts file it reads and writes.
|
|
11
|
+
*/
|
|
12
|
+
hostKey: 'insecure' | {
|
|
13
|
+
policy: 'pin' | 'accept-new';
|
|
14
|
+
knownHostsFile: string;
|
|
15
|
+
};
|
|
16
|
+
/** @default 30 */
|
|
17
|
+
connectTimeoutSec?: number;
|
|
18
|
+
/**
|
|
19
|
+
* How a script is executed on the host once it arrives over stdin. Defaults
|
|
20
|
+
* to {@link remoteScriptRunner} without sudo; `exec` can pick the sudo
|
|
21
|
+
* variant per call.
|
|
22
|
+
*/
|
|
23
|
+
runner?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface SshExecOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Run the script through `sudo -n`. Unset: the transport's configured
|
|
28
|
+
* runner. A deploy user that is not root needs it for everything except
|
|
29
|
+
* the preflight, which must run as the user to find out whether sudo works.
|
|
30
|
+
*/
|
|
31
|
+
sudo?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface SshHostKeyResult {
|
|
34
|
+
/** `SHA256:...`, empty when the key could not be learned (insecure policy, scan failed). */
|
|
35
|
+
fingerprint: string;
|
|
36
|
+
/** True when this call is what recorded the key. */
|
|
37
|
+
pinnedNow: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface SshTransport {
|
|
40
|
+
/** Run `script` on `host`; resolves with stdout, rejects with a redacted failure. */
|
|
41
|
+
exec(host: string, script: string, options?: SshExecOptions): Promise<string>;
|
|
42
|
+
/** Copy one local file to `remotePath` on `host`. */
|
|
43
|
+
scp(host: string, localPath: string, remotePath: string): Promise<void>;
|
|
44
|
+
/** Whether sshd on `host` accepts a connection right now. */
|
|
45
|
+
probe(host: string): Promise<boolean>;
|
|
46
|
+
/** Learn (and, when pinning, record) the host key before the first real command. */
|
|
47
|
+
ensureHostKey(host: string): Promise<SshHostKeyResult>;
|
|
48
|
+
}
|
|
49
|
+
export interface CommandResult {
|
|
50
|
+
code: number;
|
|
51
|
+
signal?: string | null;
|
|
52
|
+
stdout: string;
|
|
53
|
+
stderr: string;
|
|
54
|
+
}
|
|
55
|
+
/** Runs a command; `input`, when given, is piped to stdin. Injectable for tests. */
|
|
56
|
+
export type CommandRunner = (command: string[], input?: string) => Promise<CommandResult>;
|
|
57
|
+
export declare const runCommand: CommandRunner;
|
|
58
|
+
/**
|
|
59
|
+
* Host-key options for a box the provider API identifies: never check, never
|
|
60
|
+
* remember. Byte-for-byte what the Hetzner driver passes.
|
|
61
|
+
*/
|
|
62
|
+
export declare const SSH_INSECURE_HOST_KEY_OPTS: readonly string[];
|
|
63
|
+
/**
|
|
64
|
+
* Keepalive + connect timeout for every ssh/scp. Without these a connection
|
|
65
|
+
* that stalls mid-transfer (a flaky network, an sshd hiccup) hangs the deploy
|
|
66
|
+
* FOREVER. ServerAlive probes abort a silent connection after ~60s (15s x 4)
|
|
67
|
+
* so the transfer fails loudly (and, for scp, is retried) instead of wedging.
|
|
68
|
+
*/
|
|
69
|
+
export declare const SSH_KEEPALIVE_OPTS: readonly string[];
|
|
70
|
+
/**
|
|
71
|
+
* The `ssh` arguments (everything after the binary, ending in `user@host`)
|
|
72
|
+
* for `options`. `extra` is spliced in before the destination so a caller can
|
|
73
|
+
* add a one-off `-o`. Pure, for tests.
|
|
74
|
+
*/
|
|
75
|
+
export declare function buildSshArgsFor(options: SshTransportOptions, host: string, extra?: string[]): string[];
|
|
76
|
+
/** The `scp` arguments for copying `localPath` to `host:remotePath`. Pure, for tests. */
|
|
77
|
+
export declare function buildScpArgsFor(options: SshTransportOptions, host: string, localPath: string, remotePath: string): string[];
|
|
78
|
+
/** `SHA256:...` fingerprint of a base64 host key, as `ssh-keygen -l` prints it. */
|
|
79
|
+
export declare function sshHostKeyFingerprint(key: string): string;
|
|
80
|
+
export interface ScannedHostKey {
|
|
81
|
+
algorithm: string;
|
|
82
|
+
key: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Ask the host for its ed25519 key with `ssh-keyscan`. Bounded (`-T 10`) so an
|
|
86
|
+
* unreachable host fails in seconds rather than at the TCP timeout.
|
|
87
|
+
*/
|
|
88
|
+
export declare function scanHostKey(host: string, port?: number, run?: CommandRunner): Promise<ScannedHostKey>;
|
|
89
|
+
/** The host field ssh looks up in known_hosts: `host` on port 22, `[host]:port` otherwise. */
|
|
90
|
+
export declare function knownHostsToken(host: string, port?: number): string;
|
|
91
|
+
/** The known_hosts entry recorded for `host` (one line, no trailing newline). */
|
|
92
|
+
export declare function knownHostsLine(host: string, port: number, key: ScannedHostKey): string;
|
|
93
|
+
/**
|
|
94
|
+
* The recorded key for `host`, or null when the file has no plain entry for
|
|
95
|
+
* it. Hashed entries (`|1|...`) cannot be matched and are ignored, which is
|
|
96
|
+
* fine: this transport only ever writes plain ones.
|
|
97
|
+
*/
|
|
98
|
+
export declare function findKnownHostKey(content: string, host: string, port?: number): ScannedHostKey | null;
|
|
99
|
+
/** Where the ssh driver keeps the host keys it pinned: `<stateDir>/ssh/known_hosts`. */
|
|
100
|
+
export declare function sshKnownHostsPath(cwd?: string): string;
|
|
101
|
+
export interface SystemSshTransportDeps {
|
|
102
|
+
run?: CommandRunner;
|
|
103
|
+
scan?: typeof scanHostKey;
|
|
104
|
+
readKnownHosts?: (file: string) => Promise<string>;
|
|
105
|
+
appendKnownHosts?: (file: string, line: string) => Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
/** {@link SshTransport} on the system `ssh`, `scp` and `ssh-keyscan` binaries. */
|
|
108
|
+
export declare class SystemSshTransport implements SshTransport {
|
|
109
|
+
private readonly options;
|
|
110
|
+
private readonly run;
|
|
111
|
+
private readonly scan;
|
|
112
|
+
private readonly readKnownHosts;
|
|
113
|
+
private readonly appendKnownHosts;
|
|
114
|
+
constructor(options: SshTransportOptions, deps?: SystemSshTransportDeps);
|
|
115
|
+
/** The runner a script is fed to; see {@link SshExecOptions.sudo}. */
|
|
116
|
+
runnerFor(options?: SshExecOptions): string;
|
|
117
|
+
exec(host: string, script: string, options?: SshExecOptions): Promise<string>;
|
|
118
|
+
scp(host: string, localPath: string, remotePath: string): Promise<void>;
|
|
119
|
+
probe(host: string): Promise<boolean>;
|
|
120
|
+
ensureHostKey(host: string): Promise<SshHostKeyResult>;
|
|
121
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The bootstrap for a bring-your-own host.
|
|
3
|
+
*
|
|
4
|
+
* The recipe is the Hetzner driver's, composed the same way from the same
|
|
5
|
+
* builders (the rpx gateway, the machine provisioning, the Ubuntu bootstrap),
|
|
6
|
+
* so an adopted Pi and a cloud box end up running the same stack from the
|
|
7
|
+
* same code. What differs is the machine it lands on:
|
|
8
|
+
*
|
|
9
|
+
* - It may run MORE than once. cloud-init on a Pi has an upstream bug that
|
|
10
|
+
* reruns modules on every boot, an operator may `cloud ssh:bootstrap` twice,
|
|
11
|
+
* and a deploy calls the adopt on every run. So the whole script is guarded
|
|
12
|
+
* by a version marker: once `/var/lib/ts-cloud/bootstrap.v<N>` exists, only
|
|
13
|
+
* the gateway fragment is refreshed. Bumping {@link SSH_BOOTSTRAP_VERSION}
|
|
14
|
+
* is how a changed recipe gets applied to hosts bootstrapped by an older one.
|
|
15
|
+
* - It may run before the clock is right. A Pi 5 has no battery-backed RTC,
|
|
16
|
+
* and apt refuses Release files "from the future" while ACME refuses a
|
|
17
|
+
* skewed clock outright. Time sync is awaited before anything touches apt.
|
|
18
|
+
* - It may run as a user that is not root. The scripts arrive through the
|
|
19
|
+
* sudo runner, so they ARE root, but the deploy user still has to be able
|
|
20
|
+
* to scp into the artifact and staging directories, and the operator keys
|
|
21
|
+
* belong in that user's `authorized_keys`, not root's.
|
|
22
|
+
* - It may run on a small SD card. The raspberry-pi profile halves the
|
|
23
|
+
* swapfile and bounds the journal.
|
|
24
|
+
*/
|
|
25
|
+
import type { CloudConfig, EnvironmentType } from '@ts-cloud/core';
|
|
26
|
+
import type { SshLanConfig, SshProfile } from './config';
|
|
27
|
+
import type { SshPreflightFacts } from './preflight';
|
|
28
|
+
/** Bump when the recipe changes in a way an already-bootstrapped host must pick up. */
|
|
29
|
+
export declare const SSH_BOOTSTRAP_VERSION = 1;
|
|
30
|
+
/** Where the bootstrap records that it ran. */
|
|
31
|
+
export declare const SSH_BOOTSTRAP_MARKER_DIR = "/var/lib/ts-cloud";
|
|
32
|
+
export declare function sshBootstrapMarkerPath(version?: number): string;
|
|
33
|
+
/** Swap the raspberry-pi profile provisions when `compute.swapGb` is unset. */
|
|
34
|
+
export declare const RASPBERRY_PI_DEFAULT_SWAP_GB = 1;
|
|
35
|
+
export interface SshBootstrapOptions {
|
|
36
|
+
config: CloudConfig;
|
|
37
|
+
environment: EnvironmentType;
|
|
38
|
+
profile: SshProfile;
|
|
39
|
+
/**
|
|
40
|
+
* Preflight facts, when the host has been probed. `arch` gates x86_64-only
|
|
41
|
+
* services; `lanIp` becomes the LAN certificate's iPAddress SAN.
|
|
42
|
+
*/
|
|
43
|
+
facts?: Pick<SshPreflightFacts, 'arch'> & Partial<Pick<SshPreflightFacts, 'lanIp'>>;
|
|
44
|
+
/**
|
|
45
|
+
* The non-root deploy user, when there is one. Makes the artifact and
|
|
46
|
+
* staging directories group-writable for it and manages its
|
|
47
|
+
* `authorized_keys` rather than root's.
|
|
48
|
+
*/
|
|
49
|
+
sudoUser?: string;
|
|
50
|
+
/** LAN settings; recorded in the script header and wired into the gateway's local CA. */
|
|
51
|
+
lan?: SshLanConfig;
|
|
52
|
+
/**
|
|
53
|
+
* The box's LAN address, when the caller knows one that is not in `facts`
|
|
54
|
+
* (the configured ssh host, when that host is an IP literal). Wins over
|
|
55
|
+
* `facts.lanIp`. Never guessed: an address absent here is simply left off
|
|
56
|
+
* the certificate.
|
|
57
|
+
*/
|
|
58
|
+
lanIp?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Refuse a config that asks for something this host's architecture cannot
|
|
62
|
+
* run. Vitess publishes x86_64 release tarballs only, so on an arm64 host the
|
|
63
|
+
* provision would fail minutes in on a download URL; say so before contact.
|
|
64
|
+
* The raspberry-pi profile is arm64 by definition, so it needs no facts.
|
|
65
|
+
*/
|
|
66
|
+
export declare function assertArchSupported(config: CloudConfig, profile: SshProfile, arch?: string): void;
|
|
67
|
+
/**
|
|
68
|
+
* Build the bootstrap script for an adopted host. See the module comment for
|
|
69
|
+
* what makes it different from the cloud drivers' first-boot script.
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildSshBootstrapScript(options: SshBootstrapOptions): string;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single place ssh-provider settings are resolved.
|
|
3
|
+
*
|
|
4
|
+
* Same shape and the same precedence as `../hetzner/config`, for the same
|
|
5
|
+
* reason: every value can come from several sources, and resolving them
|
|
6
|
+
* ad-hoc at each call site is how the driver, a CLI command and the dashboard
|
|
7
|
+
* end up disagreeing about which host a deploy goes to.
|
|
8
|
+
*
|
|
9
|
+
* 1. an explicit argument (a driver option or CLI flag: the caller means it)
|
|
10
|
+
* 2. `cloud.config.ts` -> `ssh.*` (checked into the repo, reviewable)
|
|
11
|
+
* 3. environment (`TS_CLOUD_SSH_*`) for per-machine overrides
|
|
12
|
+
* 4. the documented default in {@link SSH_DEFAULTS}
|
|
13
|
+
*
|
|
14
|
+
* Config beats environment deliberately: a value written in `cloud.config.ts`
|
|
15
|
+
* is the reviewed intent for the project, and a stray shell export must not
|
|
16
|
+
* silently redirect a deploy to another machine.
|
|
17
|
+
*/
|
|
18
|
+
import type { CloudConfig, SshConfig, SshHostConfig } from '@ts-cloud/core';
|
|
19
|
+
export type SshProfile = NonNullable<SshConfig['profile']>;
|
|
20
|
+
export type SshHostKeyPolicyName = NonNullable<SshConfig['hostKey']>;
|
|
21
|
+
export type SshLanConfig = NonNullable<SshConfig['lan']>;
|
|
22
|
+
/** The documented defaults. These are the only place an ssh default lives. */
|
|
23
|
+
export declare const SSH_DEFAULTS: {
|
|
24
|
+
readonly user: 'root';
|
|
25
|
+
readonly port: 22;
|
|
26
|
+
readonly privateKeyPath: '~/.ssh/id_ed25519';
|
|
27
|
+
readonly hostKey: 'pin';
|
|
28
|
+
readonly profile: 'generic';
|
|
29
|
+
readonly publicIp: 'auto';
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The hosts to deploy to: explicit, else `ssh.hosts`, else the single host
|
|
33
|
+
* named by `TS_CLOUD_SSH_HOST`. Throws when none is configured, because a
|
|
34
|
+
* driver without a host has nothing it can honestly do.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveSshHosts(config?: CloudConfig, explicit?: SshHostConfig[]): SshHostConfig[];
|
|
37
|
+
/** SSH user for deploy commands. Per host: the value lives on the `ssh.hosts[]` entry. */
|
|
38
|
+
export declare function resolveSshUser(host?: SshHostConfig, explicit?: string): string;
|
|
39
|
+
/** SSH port. A non-numeric or out-of-range value is a configuration error, not port 22. */
|
|
40
|
+
export declare function resolveSshPort(host?: SshHostConfig, explicit?: number): number;
|
|
41
|
+
/** Absolute path to the SSH private key used for deploy commands. */
|
|
42
|
+
export declare function resolveSshPrivateKeyPath(host?: SshHostConfig, explicit?: string): string;
|
|
43
|
+
/** How the host key is trusted; see `SshConfig.hostKey`. */
|
|
44
|
+
export declare function resolveSshHostKeyPolicy(config?: CloudConfig, explicit?: string): SshHostKeyPolicyName;
|
|
45
|
+
/**
|
|
46
|
+
* Whether remote scripts run through `sudo -n`. Explicit, else `ssh.sudo`,
|
|
47
|
+
* else on for any user that is not root: a deploy user that cannot become
|
|
48
|
+
* root cannot install the stack.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveSshSudo(config?: CloudConfig, user?: string, explicit?: boolean): boolean;
|
|
51
|
+
/** Host profile; see `SshConfig.profile`. */
|
|
52
|
+
export declare function resolveSshProfile(config?: CloudConfig, explicit?: string): SshProfile;
|
|
53
|
+
/** The public IP DNS should point at: `'auto'` or a literal address. */
|
|
54
|
+
export declare function resolveSshPublicIp(config?: CloudConfig, explicit?: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* LAN access settings, or `undefined` when the project configured none.
|
|
57
|
+
*
|
|
58
|
+
* This used to answer `{}` for "unset", which reads as a LAN with defaults
|
|
59
|
+
* once anything acts on it: with the gateway now wired to `lan`, that sentinel
|
|
60
|
+
* would give every adopted host a local certificate authority for
|
|
61
|
+
* `<slug>.local` that nobody asked for. Absent has to be absent.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveSshLan(config?: CloudConfig, explicit?: SshLanConfig): SshLanConfig | undefined;
|
|
64
|
+
/** One host with every per-host value resolved. */
|
|
65
|
+
export interface ResolvedSshHost {
|
|
66
|
+
host: string;
|
|
67
|
+
user: string;
|
|
68
|
+
port: number;
|
|
69
|
+
privateKeyPath: string;
|
|
70
|
+
role: 'app';
|
|
71
|
+
}
|
|
72
|
+
/** Every resolved ssh setting, for a driver or a diagnostic to read at once. */
|
|
73
|
+
export interface ResolvedSshSettings {
|
|
74
|
+
hosts: ResolvedSshHost[];
|
|
75
|
+
hostKey: SshHostKeyPolicyName;
|
|
76
|
+
sudo: boolean;
|
|
77
|
+
profile: SshProfile;
|
|
78
|
+
publicIp: string;
|
|
79
|
+
/** LAN access settings, or `undefined` when this project configured none. */
|
|
80
|
+
lan?: SshLanConfig;
|
|
81
|
+
}
|
|
82
|
+
export interface SshOverrides {
|
|
83
|
+
hosts?: SshHostConfig[];
|
|
84
|
+
user?: string;
|
|
85
|
+
port?: number;
|
|
86
|
+
privateKeyPath?: string;
|
|
87
|
+
hostKey?: string;
|
|
88
|
+
sudo?: boolean;
|
|
89
|
+
profile?: string;
|
|
90
|
+
publicIp?: string;
|
|
91
|
+
lan?: SshLanConfig;
|
|
92
|
+
}
|
|
93
|
+
/** Resolve the full ssh settings for `config`, applying `overrides` first. */
|
|
94
|
+
export declare function resolveSshSettings(config?: CloudConfig, overrides?: SshOverrides): ResolvedSshSettings;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ssh compute driver: deploy to a Linux host you already own.
|
|
3
|
+
*
|
|
4
|
+
* Where the cloud drivers CREATE a box and then deploy to it, this one ADOPTS
|
|
5
|
+
* one. `provisionComputeInfrastructure` therefore means: trust the host key,
|
|
6
|
+
* wait for sshd, run the preflight and refuse a host that cannot work, wait
|
|
7
|
+
* out a cloud-init first boot if one is still going, run the bootstrap (which
|
|
8
|
+
* is idempotent, so a deploy can call this every time), and record what was
|
|
9
|
+
* done. `destroyCompute` forgets the host and touches nothing on it.
|
|
10
|
+
*
|
|
11
|
+
* Everything after adoption is the Hetzner driver's SSH deploy path verbatim
|
|
12
|
+
* (the content-addressed artifact cache, the nonce-scoped staging upload, the
|
|
13
|
+
* per-target deploy with redacted failures), on an injectable transport.
|
|
14
|
+
*/
|
|
15
|
+
import type { CloudConfig, CloudDriver, ComputeStackOutputs, ComputeTarget, FindComputeTargetsOptions, ProvisionComputeOptions, RemoteDeployResult, RunRemoteDeployOptions, SshHostConfig, UploadReleaseOptions, UploadReleaseResult } from '@ts-cloud/core';
|
|
16
|
+
import type { ValidationFinding } from '../../fleet';
|
|
17
|
+
import type { SshTransport } from '../shared/ssh-transport';
|
|
18
|
+
import type { ResolvedSshSettings, SshLanConfig } from './config';
|
|
19
|
+
import type { SshPreflightFacts } from './preflight';
|
|
20
|
+
/** Where releases are staged and cached on the host; the same paths as every other SSH-style driver. */
|
|
21
|
+
export declare const SSH_DEPLOY_STORAGE_PATH = "/var/ts-cloud/staging";
|
|
22
|
+
/** Set to `1` to skip the bootstrap when local state says the current version already ran. */
|
|
23
|
+
export declare const SSH_SKIP_BOOTSTRAP_ENV = "TS_CLOUD_SSH_SKIP_BOOTSTRAP";
|
|
24
|
+
export interface SshDriverOptions {
|
|
25
|
+
hosts?: SshHostConfig[];
|
|
26
|
+
user?: string;
|
|
27
|
+
port?: number;
|
|
28
|
+
privateKeyPath?: string;
|
|
29
|
+
hostKey?: string;
|
|
30
|
+
sudo?: boolean;
|
|
31
|
+
profile?: string;
|
|
32
|
+
publicIp?: string;
|
|
33
|
+
lan?: SshLanConfig;
|
|
34
|
+
/** Injected transport (tests, or a caller with its own SSH stack). */
|
|
35
|
+
transport?: SshTransport;
|
|
36
|
+
/** Tunables for the SSH-readiness / cloud-init wait loops; tiny in tests. */
|
|
37
|
+
bootWait?: {
|
|
38
|
+
/** @default 5000 */
|
|
39
|
+
sshIntervalMs?: number;
|
|
40
|
+
/** @default 300000 */
|
|
41
|
+
sshTimeoutMs?: number;
|
|
42
|
+
/** @default 5000 */
|
|
43
|
+
cloudInitIntervalMs?: number;
|
|
44
|
+
/** @default 600000 */
|
|
45
|
+
cloudInitTimeoutMs?: number;
|
|
46
|
+
};
|
|
47
|
+
/** Project root: where state and the pinned host keys live. @default process.cwd() */
|
|
48
|
+
cwd?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The config problems the ssh provider refuses, and the keys it merely ignores.
|
|
52
|
+
*
|
|
53
|
+
* Throws for anything that would make the deploy mean something other than
|
|
54
|
+
* what the config says; returns a warning per sizing key that has no effect
|
|
55
|
+
* here, so an operator who copied a Hetzner config learns which lines are
|
|
56
|
+
* inert instead of wondering why the box did not grow.
|
|
57
|
+
*/
|
|
58
|
+
export declare function assertSshComputeConfig(config: CloudConfig, settings: Pick<ResolvedSshSettings, 'hosts' | 'profile'>): string[];
|
|
59
|
+
export declare class SshDriver implements CloudDriver {
|
|
60
|
+
readonly name: 'ssh';
|
|
61
|
+
readonly usesCloudFormation = false;
|
|
62
|
+
private readonly settings;
|
|
63
|
+
private readonly cwd;
|
|
64
|
+
private readonly bootWait;
|
|
65
|
+
private transportInstance?;
|
|
66
|
+
constructor(options?: SshDriverOptions);
|
|
67
|
+
/** The one host this driver deploys to. */
|
|
68
|
+
private get host();
|
|
69
|
+
private get transport();
|
|
70
|
+
/** Run a script on the host as root (through sudo when the user is not root). */
|
|
71
|
+
private exec;
|
|
72
|
+
findComputeTargets(options: FindComputeTargetsOptions): Promise<ComputeTarget[]>;
|
|
73
|
+
getComputeOutputs(): Promise<ComputeStackOutputs>;
|
|
74
|
+
uploadRelease(options: UploadReleaseOptions): Promise<UploadReleaseResult>;
|
|
75
|
+
runRemoteDeploy(options: RunRemoteDeployOptions): Promise<RemoteDeployResult>;
|
|
76
|
+
/** The configured host name or address, for a caller that wants to print it. */
|
|
77
|
+
targetHost(): string;
|
|
78
|
+
/** Learn (and, when pinning, record) the host key. The adopt does this first; the preflight command too. */
|
|
79
|
+
ensureHostKey(host?: string): Promise<{
|
|
80
|
+
fingerprint: string;
|
|
81
|
+
pinnedNow: boolean;
|
|
82
|
+
}>;
|
|
83
|
+
/**
|
|
84
|
+
* Probe the host as the deploy user and judge the result. Public so the
|
|
85
|
+
* `ssh:preflight` command and the adopt share one definition of "ready".
|
|
86
|
+
*/
|
|
87
|
+
preflight(host?: string): Promise<{
|
|
88
|
+
facts: SshPreflightFacts;
|
|
89
|
+
findings: ValidationFinding[];
|
|
90
|
+
}>;
|
|
91
|
+
/**
|
|
92
|
+
* Adopt the host: pin, wait, check, bootstrap, record. Idempotent, and
|
|
93
|
+
* cheap after the first run because the bootstrap guards itself.
|
|
94
|
+
*/
|
|
95
|
+
provisionComputeInfrastructure(options: ProvisionComputeOptions): Promise<ComputeStackOutputs>;
|
|
96
|
+
/**
|
|
97
|
+
* Forget the host. Nothing on it is removed: it was never ts-cloud's to
|
|
98
|
+
* remove, and a teardown that wiped an operator's Pi would be a much worse
|
|
99
|
+
* surprise than one that left a gateway running.
|
|
100
|
+
*/
|
|
101
|
+
destroyCompute(options: ProvisionComputeOptions): Promise<{
|
|
102
|
+
destroyed: string[];
|
|
103
|
+
}>;
|
|
104
|
+
private sleep;
|
|
105
|
+
private waitForSshReady;
|
|
106
|
+
private waitForCloudInit;
|
|
107
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type FirstBootOs = 'raspberry-pi-os' | 'ubuntu';
|
|
2
|
+
export interface FirstBootWifi {
|
|
3
|
+
ssid: string;
|
|
4
|
+
passphrase: string;
|
|
5
|
+
/** ISO 3166-1 alpha-2 regulatory domain, e.g. `DE`. Required: without it the radio stays off. */
|
|
6
|
+
country: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FirstBootIdentity {
|
|
9
|
+
/** The hostname; also the mDNS name (`<hostname>.local`) the instructions point at. */
|
|
10
|
+
hostname: string;
|
|
11
|
+
/** The deploy user cloud-init creates, with passwordless sudo and the key below. */
|
|
12
|
+
user: string;
|
|
13
|
+
/** One public key line (`ssh-ed25519 AAAA... comment`). */
|
|
14
|
+
publicKey: string;
|
|
15
|
+
/** IANA timezone, e.g. `Europe/Berlin`. */
|
|
16
|
+
timezone?: string;
|
|
17
|
+
/** System locale, e.g. `en_US.UTF-8`. */
|
|
18
|
+
locale?: string;
|
|
19
|
+
wifi?: FirstBootWifi;
|
|
20
|
+
}
|
|
21
|
+
export interface FirstBootBundle {
|
|
22
|
+
/** File name (as it must appear on the boot partition) to content. */
|
|
23
|
+
files: Record<string, string>;
|
|
24
|
+
/** What to do with the files, for the terminal. */
|
|
25
|
+
instructions: string;
|
|
26
|
+
}
|
|
27
|
+
export interface FirstBootOptions {
|
|
28
|
+
os: FirstBootOs;
|
|
29
|
+
}
|
|
30
|
+
/** Where the bootstrap is written on the host; the same place the adopt flow's marker lives beside. */
|
|
31
|
+
export declare const FIRST_BOOT_SCRIPT_PATH = "/var/lib/ts-cloud/bootstrap.sh";
|
|
32
|
+
/** The boot partition label each OS uses, so the instructions can name the volume. */
|
|
33
|
+
export declare const BOOT_PARTITION_LABEL: Record<FirstBootOs, string>;
|
|
34
|
+
/**
|
|
35
|
+
* Build the three cloud-init files for `identity`, embedding `bootstrapScript`
|
|
36
|
+
* (from `buildSshBootstrapScript`) so it runs at the end of the first boot.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildCloudInitFirstBoot(identity: FirstBootIdentity, bootstrapScript: string, options: FirstBootOptions): FirstBootBundle;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What ts-cloud checks about a bring-your-own host before touching it.
|
|
3
|
+
*
|
|
4
|
+
* The cloud drivers never need this: they chose the image, the size and the
|
|
5
|
+
* region, so they know what they are logging into. An adopted host is
|
|
6
|
+
* whatever the operator installed, and the bootstrap's failure modes on the
|
|
7
|
+
* wrong machine are slow and misleading (an apt run that never finishes on
|
|
8
|
+
* an unsynced clock, a 404 from an x86_64-only download on an ARM board).
|
|
9
|
+
* One probe, run as the deploy user, answers every question the bootstrap
|
|
10
|
+
* would otherwise discover the hard way.
|
|
11
|
+
*/
|
|
12
|
+
import type { ValidationFinding } from '../../fleet';
|
|
13
|
+
import type { SshProfile } from './config';
|
|
14
|
+
/** The facts the preflight script reports, as JSON on its last line. */
|
|
15
|
+
export interface SshPreflightFacts {
|
|
16
|
+
/** `PRETTY_NAME` from /etc/os-release. */
|
|
17
|
+
os: string;
|
|
18
|
+
/** `ID` from /etc/os-release, e.g. `debian`, `ubuntu`, `raspbian`. */
|
|
19
|
+
osId: string;
|
|
20
|
+
/** `ID_LIKE` from /etc/os-release, e.g. `debian` on Ubuntu. */
|
|
21
|
+
osIdLike: string;
|
|
22
|
+
/** `VERSION_ID` from /etc/os-release, e.g. `13`, `24.04`. */
|
|
23
|
+
osVersionId: string;
|
|
24
|
+
/** `uname -m`: `aarch64`, `x86_64`, `armv7l`, ... */
|
|
25
|
+
arch: string;
|
|
26
|
+
cpuCores: number;
|
|
27
|
+
memoryBytes: number;
|
|
28
|
+
diskBytes: number;
|
|
29
|
+
diskFreeBytes: number;
|
|
30
|
+
dnsOk: boolean;
|
|
31
|
+
/** Whether the `cloud-init` binary exists on the host. */
|
|
32
|
+
cloudInitPresent: boolean;
|
|
33
|
+
/** First line of `cloud-init status`, empty when absent. */
|
|
34
|
+
cloudInitStatus: string;
|
|
35
|
+
/** `timedatectl` reports the clock as NTP-synchronised. */
|
|
36
|
+
timeSynced: boolean;
|
|
37
|
+
/** An HTTPS request to github.com succeeded (downloads will work). */
|
|
38
|
+
httpsOk: boolean;
|
|
39
|
+
/** `sudo -n true` succeeded for the deploy user. */
|
|
40
|
+
sudoOk: boolean;
|
|
41
|
+
/** `getconf LONG_BIT`: 64 on every supported host. */
|
|
42
|
+
kernelBits: number;
|
|
43
|
+
/** `/proc/device-tree/model`, e.g. `Raspberry Pi 5 Model B Rev 1.0`; empty elsewhere. */
|
|
44
|
+
piModel: string;
|
|
45
|
+
/** First address from `hostname -I`. */
|
|
46
|
+
lanIp: string;
|
|
47
|
+
tools: {
|
|
48
|
+
curl: boolean;
|
|
49
|
+
tar: boolean;
|
|
50
|
+
};
|
|
51
|
+
privilege: 'sudo' | 'user';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The probe. Runs as the deploy user WITHOUT sudo, on purpose: `sudoOk` is a
|
|
55
|
+
* question, and a script that already needed sudo to run could not ask it.
|
|
56
|
+
* Every command tolerates absence (a `false`, a `0`, an empty string) so the
|
|
57
|
+
* JSON is always complete and the findings, not a shell error, say what is
|
|
58
|
+
* missing. The last line of stdout is the JSON document.
|
|
59
|
+
*/
|
|
60
|
+
export declare const SSH_PREFLIGHT_SCRIPT: string;
|
|
61
|
+
/** Parse the probe's stdout: the last non-empty line is the JSON document. */
|
|
62
|
+
export declare function parsePreflightFacts(output: string): SshPreflightFacts;
|
|
63
|
+
export interface PreflightContext {
|
|
64
|
+
/** The deploy user; root needs no sudo. */
|
|
65
|
+
user: string;
|
|
66
|
+
profile: SshProfile;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Turn facts into findings. An `error` finding stops the adopt; a `warning`
|
|
70
|
+
* is printed and the adopt continues; `info` is context worth showing.
|
|
71
|
+
*/
|
|
72
|
+
export declare function evaluatePreflight(facts: SshPreflightFacts, context: PreflightContext): ValidationFinding[];
|
|
73
|
+
/** True when any finding is an error. */
|
|
74
|
+
export declare function preflightFailed(findings: readonly ValidationFinding[]): boolean;
|
|
75
|
+
/** A plain-text table of findings, one per line, for a terminal or an error message. */
|
|
76
|
+
export declare function formatPreflightFindings(findings: readonly ValidationFinding[]): string;
|
package/dist/index.d.ts
CHANGED
|
@@ -39,8 +39,9 @@ export { collectServerDnsDomains, hostAcceptsIpv6, IPV6_EXCLUDED_HOST_LABELS, no
|
|
|
39
39
|
export type { AddressRecordReport } from './deploy/server-dns';
|
|
40
40
|
export * from './cdn';
|
|
41
41
|
export type { EnsureDashboardLogger, ResolvedDashboardAuth, StaticSiteConfig, DeployResult, UploadOptions, ExternalDnsStaticSiteConfig, ExternalDnsDeployResult, DeploySiteConfig, DeploySiteResult, StaticSiteDnsProvider, SiteDeployKind, DeploymentValidationResult, BuildImageOptions, BuiltImage, CodeSource, DeployServerlessOptions, ResolvedContext, } from './deploy';
|
|
42
|
-
export { createCloudDriver, CloudDriverFactory, cloudDrivers, AwsDriver, HetznerDriver, HetznerClient, resolveHetznerApiToken, normalizeSshPublicKey, ensureFirewall, ensureServer, ensureSshKey, serverPublicIpv4, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, buildSshArgs, generateUbuntuAppCloudInit, wrapCloudInitUserData, buildHostCleanupScript, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, deployAllComputeSites, deploySiteRelease, reloadRpxGateway, renewRpxCertificates, gatewayHostnames, hasAutoWwwVariant, } from './drivers';
|
|
42
|
+
export { createCloudDriver, CloudDriverFactory, cloudDrivers, AwsDriver, HetznerDriver, SshDriver, SystemSshTransport, resolveSshSettings, buildSshBootstrapScript, SSH_BOOTSTRAP_VERSION, evaluatePreflight, formatPreflightFindings, parsePreflightFacts, preflightFailed, SSH_PREFLIGHT_SCRIPT, buildCloudInitFirstBoot, driverStatePath, readDriverState, writeDriverState, HetznerClient, resolveHetznerApiToken, normalizeSshPublicKey, ensureFirewall, ensureServer, ensureSshKey, serverPublicIpv4, sshExec, sshExecOrThrow, scpUpload, waitForSsh, waitForCloudInit, buildSshArgs, generateUbuntuAppCloudInit, wrapCloudInitUserData, buildHostCleanupScript, buildSiteDeployScript, buildStaticSiteDeployScript, resolveExecStart, deployAllComputeSites, deploySiteRelease, reloadRpxGateway, renewRpxCertificates, gatewayHostnames, hasAutoWwwVariant, } from './drivers';
|
|
43
43
|
export type { CreateCloudDriverOptions } from './drivers/factory';
|
|
44
|
+
export type { DriverState, FirstBootBundle, FirstBootIdentity, FirstBootOs, ResolvedSshSettings, SshDriverOptions, SshDriverState, SshPreflightFacts, SshTransport, SshTransportOptions, } from './drivers';
|
|
44
45
|
export { dashboardActions, resolveDashboardAction, sanitizeCloudConfig, startLocalDashboardServer, } from './deploy/local-dashboard-server';
|
|
45
46
|
export type { DashboardAction, LocalDashboardServer, LocalDashboardServerOptions, } from './deploy/local-dashboard-server';
|
|
46
47
|
export { createDnsProvider, detectDnsProvider, DnsProviderFactory, dnsProviders, PorkbunProvider, GoDaddyProvider, Route53Provider, CloudflareProvider, policyTag, qualifyName, reconcileDeclaredRecords, resolveDeclaredRecords, UnifiedDnsValidator, createPorkbunValidator, createGoDaddyValidator, createRoute53Validator, } from './dns';
|