redkite 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +819 -0
- package/bin/redkite.mjs +12 -0
- package/dist/build.d.ts +27 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +132 -0
- package/dist/build.js.map +1 -0
- package/dist/checks.d.ts +4 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +49 -0
- package/dist/checks.js.map +1 -0
- package/dist/cli/agent.d.ts +2 -0
- package/dist/cli/agent.d.ts.map +1 -0
- package/dist/cli/agent.js +24 -0
- package/dist/cli/agent.js.map +1 -0
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +217 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +11 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +438 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/log.d.ts +9 -0
- package/dist/cli/log.d.ts.map +1 -0
- package/dist/cli/log.js +128 -0
- package/dist/cli/log.js.map +1 -0
- package/dist/cli/screen.d.ts +34 -0
- package/dist/cli/screen.d.ts.map +1 -0
- package/dist/cli/screen.js +298 -0
- package/dist/cli/screen.js.map +1 -0
- package/dist/cli/viewer.d.ts +9 -0
- package/dist/cli/viewer.d.ts.map +1 -0
- package/dist/cli/viewer.js +139 -0
- package/dist/cli/viewer.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +79 -0
- package/dist/config.js.map +1 -0
- package/dist/deploy.d.ts +19 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +275 -0
- package/dist/deploy.js.map +1 -0
- package/dist/docker.d.ts +96 -0
- package/dist/docker.d.ts.map +1 -0
- package/dist/docker.js +325 -0
- package/dist/docker.js.map +1 -0
- package/dist/dockerfile.d.ts +14 -0
- package/dist/dockerfile.d.ts.map +1 -0
- package/dist/dockerfile.js +160 -0
- package/dist/dockerfile.js.map +1 -0
- package/dist/health.d.ts +13 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +54 -0
- package/dist/health.js.map +1 -0
- package/dist/host.d.ts +21 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +27 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +5 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +45 -0
- package/dist/layout.js.map +1 -0
- package/dist/localHost.d.ts +7 -0
- package/dist/localHost.d.ts.map +1 -0
- package/dist/localHost.js +32 -0
- package/dist/localHost.js.map +1 -0
- package/dist/log.d.ts +14 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +15 -0
- package/dist/log.js.map +1 -0
- package/dist/nginx.d.ts +4 -0
- package/dist/nginx.d.ts.map +1 -0
- package/dist/nginx.js +53 -0
- package/dist/nginx.js.map +1 -0
- package/dist/pipeline.d.ts +103 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +142 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/presets/index.d.ts +3 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +3 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/nextApp.d.ts +15 -0
- package/dist/presets/nextApp.d.ts.map +1 -0
- package/dist/presets/nextApp.js +53 -0
- package/dist/presets/nextApp.js.map +1 -0
- package/dist/presets/nodeApp.d.ts +19 -0
- package/dist/presets/nodeApp.d.ts.map +1 -0
- package/dist/presets/nodeApp.js +29 -0
- package/dist/presets/nodeApp.js.map +1 -0
- package/dist/secrets/bitwarden.d.ts +3 -0
- package/dist/secrets/bitwarden.d.ts.map +1 -0
- package/dist/secrets/bitwarden.js +6 -0
- package/dist/secrets/bitwarden.js.map +1 -0
- package/dist/secrets/refs.d.ts +9 -0
- package/dist/secrets/refs.d.ts.map +1 -0
- package/dist/secrets/refs.js +20 -0
- package/dist/secrets/refs.js.map +1 -0
- package/dist/secrets/store.d.ts +9 -0
- package/dist/secrets/store.d.ts.map +1 -0
- package/dist/secrets/store.js +104 -0
- package/dist/secrets/store.js.map +1 -0
- package/dist/services/ensure.d.ts +18 -0
- package/dist/services/ensure.d.ts.map +1 -0
- package/dist/services/ensure.js +93 -0
- package/dist/services/ensure.js.map +1 -0
- package/dist/services/index.d.ts +19 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +27 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/planned.d.ts +20 -0
- package/dist/services/planned.d.ts.map +1 -0
- package/dist/services/planned.js +77 -0
- package/dist/services/planned.js.map +1 -0
- package/dist/shell.d.ts +11 -0
- package/dist/shell.d.ts.map +1 -0
- package/dist/shell.js +65 -0
- package/dist/shell.js.map +1 -0
- package/dist/source.d.ts +16 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +108 -0
- package/dist/source.js.map +1 -0
- package/dist/sshHost.d.ts +15 -0
- package/dist/sshHost.d.ts.map +1 -0
- package/dist/sshHost.js +91 -0
- package/dist/sshHost.js.map +1 -0
- package/dist/steps.d.ts +27 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +69 -0
- package/dist/steps.js.map +1 -0
- package/dist/topology.d.ts +40 -0
- package/dist/topology.d.ts.map +1 -0
- package/dist/topology.js +113 -0
- package/dist/topology.js.map +1 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
- package/src/build.ts +236 -0
- package/src/checks.ts +65 -0
- package/src/cli/agent.ts +28 -0
- package/src/cli/config.ts +275 -0
- package/src/cli/index.ts +559 -0
- package/src/cli/log.ts +168 -0
- package/src/cli/screen.ts +409 -0
- package/src/cli/viewer.ts +192 -0
- package/src/config.ts +90 -0
- package/src/deploy.ts +409 -0
- package/src/docker.ts +433 -0
- package/src/dockerfile.ts +228 -0
- package/src/health.ts +83 -0
- package/src/host.ts +54 -0
- package/src/index.ts +25 -0
- package/src/layout.ts +41 -0
- package/src/localHost.ts +50 -0
- package/src/log.ts +38 -0
- package/src/nginx.ts +63 -0
- package/src/pipeline.ts +335 -0
- package/src/presets/index.ts +2 -0
- package/src/presets/nextApp.ts +70 -0
- package/src/presets/nodeApp.ts +46 -0
- package/src/secrets/bitwarden.ts +7 -0
- package/src/secrets/refs.ts +32 -0
- package/src/secrets/store.ts +147 -0
- package/src/services/ensure.ts +160 -0
- package/src/services/index.ts +48 -0
- package/src/services/planned.ts +119 -0
- package/src/shell.ts +95 -0
- package/src/source.ts +171 -0
- package/src/sshHost.ts +145 -0
- package/src/steps.ts +101 -0
- package/src/topology.ts +199 -0
- package/src/types.ts +243 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { environmentOf } from "../config.js";
|
|
2
|
+
import { deploy, verify } from "../deploy.js";
|
|
3
|
+
import { Docker } from "../docker.js";
|
|
4
|
+
import { localHost } from "../localHost.js";
|
|
5
|
+
import { silent } from "../log.js";
|
|
6
|
+
import { renderNginx } from "../nginx.js";
|
|
7
|
+
import { addressOf, RUNS, SLOTS } from "../pipeline.js";
|
|
8
|
+
import { listRefs } from "../secrets/refs.js";
|
|
9
|
+
import { bitwardenStore } from "../secrets/store.js";
|
|
10
|
+
import { driftOf, plannedServices } from "../services/planned.js";
|
|
11
|
+
import { sshHost } from "../sshHost.js";
|
|
12
|
+
import { topologyFor } from "../topology.js";
|
|
13
|
+
import { requireAgent } from "./agent.js";
|
|
14
|
+
import { loadConfig } from "./config.js";
|
|
15
|
+
import { createLog, describeFailure } from "./log.js";
|
|
16
|
+
// One command that reads the config and does everything under it: the agent,
|
|
17
|
+
// the vault, the checkout, the build, the swap and the cleanup.
|
|
18
|
+
const USAGE = `redkite <command> [environment]
|
|
19
|
+
|
|
20
|
+
plan [environment] Print the derived topology, the pipeline and the nginx
|
|
21
|
+
deploy [environment] Build, swap, health check, and revert on failure
|
|
22
|
+
verify [environment] Bring the services up, build, and run each app's checks
|
|
23
|
+
|
|
24
|
+
--config <path> Defaults to redkite.config.ts at the root of the project
|
|
25
|
+
--local Build the images here and ship them to the host
|
|
26
|
+
--full No step view: every line of every step, in full
|
|
27
|
+
--verbose Every host command, and every line a build printed
|
|
28
|
+
--version Print the version and exit
|
|
29
|
+
|
|
30
|
+
Environment defaults to staging. A deployment is one redkite.config.ts at the root
|
|
31
|
+
of the project, and everything below it is derived.
|
|
32
|
+
`;
|
|
33
|
+
// Wraps a host rather than living inside one, so both implementations are
|
|
34
|
+
// measured the same way and neither knows it is being timed
|
|
35
|
+
function measured(host, log) {
|
|
36
|
+
const totals = { commands: 0, commandMs: 0, files: 0 };
|
|
37
|
+
const wrapped = {
|
|
38
|
+
directory: host.directory,
|
|
39
|
+
cache: host.cache,
|
|
40
|
+
pipe: host.pipe.bind(host),
|
|
41
|
+
stop: host.stop.bind(host),
|
|
42
|
+
sh: async (command, onLine) => {
|
|
43
|
+
const started = Date.now();
|
|
44
|
+
const result = await host.sh(command, onLine);
|
|
45
|
+
totals.commands += 1;
|
|
46
|
+
totals.commandMs += Date.now() - started;
|
|
47
|
+
// The exit code matters: several of these are allowed to fail, and a
|
|
48
|
+
// deploy reading verbose output is one where somebody wants to know which
|
|
49
|
+
log?.(` $ ${command} ${Date.now() - started}ms exit ${result.code}`);
|
|
50
|
+
return result;
|
|
51
|
+
},
|
|
52
|
+
write: async (name, contents) => {
|
|
53
|
+
totals.files += 1;
|
|
54
|
+
return await host.write(name, contents);
|
|
55
|
+
},
|
|
56
|
+
close: host.close?.bind(host),
|
|
57
|
+
};
|
|
58
|
+
const summary = () => `${totals.commands} commands in ${seconds(totals.commandMs)}, ` +
|
|
59
|
+
`${totals.files} files written`;
|
|
60
|
+
return { host: wrapped, summary };
|
|
61
|
+
}
|
|
62
|
+
function seconds(ms) {
|
|
63
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
64
|
+
}
|
|
65
|
+
// Read rather than generated into the build, so a published package and a
|
|
66
|
+
// linked checkout answer with the same thing
|
|
67
|
+
async function version() {
|
|
68
|
+
const manifest = new URL("../../package.json", import.meta.url);
|
|
69
|
+
const { readFile } = await import("node:fs/promises");
|
|
70
|
+
const { version: found } = JSON.parse(await readFile(manifest, "utf8"));
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
// Flags that take a value, so the value is not mistaken for the environment
|
|
74
|
+
const VALUED = new Set(["--config"]);
|
|
75
|
+
function flag(argv, name) {
|
|
76
|
+
const joined = argv.find((arg) => arg.startsWith(`${name}=`));
|
|
77
|
+
if (joined)
|
|
78
|
+
return joined.slice(name.length + 1);
|
|
79
|
+
const at = argv.indexOf(name);
|
|
80
|
+
return at === -1 ? undefined : argv[at + 1];
|
|
81
|
+
}
|
|
82
|
+
export function positional(argv) {
|
|
83
|
+
const args = [];
|
|
84
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
85
|
+
const arg = argv[index];
|
|
86
|
+
if (!arg.startsWith("--")) {
|
|
87
|
+
args.push(arg);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
// Only the two-word form consumes the next item. --flag=value does not
|
|
91
|
+
if (VALUED.has(arg))
|
|
92
|
+
index += 1;
|
|
93
|
+
}
|
|
94
|
+
return args;
|
|
95
|
+
}
|
|
96
|
+
export async function main(argv) {
|
|
97
|
+
try {
|
|
98
|
+
return await dispatch(argv);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
// A deploy reports its own failure through the live view. Everything before
|
|
102
|
+
// one has started, a config that will not load above all, lands here
|
|
103
|
+
process.stderr.write(`${describeFailure(error)}\n`);
|
|
104
|
+
process.exitCode = 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function dispatch(argv) {
|
|
108
|
+
const args = positional(argv);
|
|
109
|
+
const command = args[0] ?? "";
|
|
110
|
+
const environment = args[1] ?? "staging";
|
|
111
|
+
if (argv.includes("--version") || command === "version") {
|
|
112
|
+
return process.stdout.write(`${await version()}\n`);
|
|
113
|
+
}
|
|
114
|
+
const configPath = flag(argv, "--config");
|
|
115
|
+
if (command === "plan")
|
|
116
|
+
return await plan(environment, configPath);
|
|
117
|
+
if (command === "deploy" || command === "verify") {
|
|
118
|
+
return await run(command, environment, configPath, {
|
|
119
|
+
verbose: argv.includes("--verbose"),
|
|
120
|
+
full: argv.includes("--full"),
|
|
121
|
+
local: argv.includes("--local"),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
process.stdout.write(USAGE);
|
|
125
|
+
process.exitCode = command ? 1 : 0;
|
|
126
|
+
}
|
|
127
|
+
async function plan(environment, configPath) {
|
|
128
|
+
const config = await loadConfig(configPath);
|
|
129
|
+
const topology = topologyFor(config, environment);
|
|
130
|
+
const say = (message = "") => process.stdout.write(`${message}\n`);
|
|
131
|
+
say(`# ${config.project} · ${environment}\n`);
|
|
132
|
+
say(`network ${topology.network} ${topology.cidr}`);
|
|
133
|
+
say(`branch ${topology.branch}`);
|
|
134
|
+
// A verify environment publishes nothing, because nothing in one serves
|
|
135
|
+
say(topology.publicPort
|
|
136
|
+
? `published ${topology.publicPort} -> ${topology.router.container} ${topology.router.address}\n`
|
|
137
|
+
: "published nothing, this environment has no publicPort\n");
|
|
138
|
+
const sources = new Map(config.apps.map((app) => [app.name, app.path ?? app.repo]));
|
|
139
|
+
for (const app of topology.apps) {
|
|
140
|
+
say(`app ${app.name}`);
|
|
141
|
+
say(` source ${sources.get(app.name) ?? "?"}`);
|
|
142
|
+
say(` current ${app.container} ${app.currentAddress}:${app.port}`);
|
|
143
|
+
say(` retired ${app.retired} ${app.retiredAddress}`);
|
|
144
|
+
say(` route ${app.route}`);
|
|
145
|
+
for (const volume of app.volumes) {
|
|
146
|
+
say(` volume ${volume.volume} -> ${volume.mountPath}`);
|
|
147
|
+
}
|
|
148
|
+
for (const [name, key] of Object.entries(app.caches)) {
|
|
149
|
+
say(` cache ${name} -> ${key}`);
|
|
150
|
+
}
|
|
151
|
+
say();
|
|
152
|
+
}
|
|
153
|
+
for (const service of topology.services) {
|
|
154
|
+
say(`service ${service.name} ${service.container} ${service.address}`);
|
|
155
|
+
for (const volume of service.volumes) {
|
|
156
|
+
say(` volume ${volume.volume} -> ${volume.mountPath}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// An environment that publishes nothing cannot serve, so verify is the only
|
|
160
|
+
// run it supports. Nothing declares that: the missing port is what says it
|
|
161
|
+
const serves = Boolean(topology.publicPort);
|
|
162
|
+
sayPipeline(config, serves, say);
|
|
163
|
+
await sayDrift(config, topology, serves ? "deploy" : "verify", say);
|
|
164
|
+
if (!serves)
|
|
165
|
+
return;
|
|
166
|
+
say(`\n# rendered nginx ${"-".repeat(44)}\n`);
|
|
167
|
+
say(renderNginx(topology, config.maxBodySize));
|
|
168
|
+
}
|
|
169
|
+
// What is running against what this file says should be. Services outlive a
|
|
170
|
+
// deploy, so this is the only part of a plan that cannot be answered from the
|
|
171
|
+
// config alone, and the only part that needs the host
|
|
172
|
+
async function sayDrift(config, topology, run, say) {
|
|
173
|
+
say(`\nservices on the host (${run})`);
|
|
174
|
+
const bastion = environmentOf(config, topology.environment)?.host;
|
|
175
|
+
let host;
|
|
176
|
+
try {
|
|
177
|
+
host = await hostFor(bastion, silent);
|
|
178
|
+
const planned = plannedServices(config, topology, run);
|
|
179
|
+
const drifted = await driftOf(planned, topology, new Docker(host));
|
|
180
|
+
if (drifted.length === 0)
|
|
181
|
+
return say(" every service is what this file says");
|
|
182
|
+
for (const drift of drifted)
|
|
183
|
+
say(` ${drift.container.padEnd(34)}${DRIFT[drift.reason]}`);
|
|
184
|
+
say(`\n a ${run} converges these`);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
// A plan is worth printing without a host. Saying so beats printing
|
|
188
|
+
// nothing, and beats printing a clean bill of health nobody checked
|
|
189
|
+
say(` not checked: ${describeFailure(error).split("\n")[0]}`);
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
await host?.close?.();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const DRIFT = {
|
|
196
|
+
missing: "not there, will be created",
|
|
197
|
+
stopped: "created from this file, but not running",
|
|
198
|
+
changed: "created from an earlier version of this file",
|
|
199
|
+
unrecognised: "not created by redkite, will be recreated",
|
|
200
|
+
};
|
|
201
|
+
// What each run will actually do, in the order it will do it. A step is
|
|
202
|
+
// addressed rather than called, so this is the only place a sequence is visible
|
|
203
|
+
function sayPipeline(config, serves, say) {
|
|
204
|
+
const steps = config.steps ?? [];
|
|
205
|
+
const added = new Set(steps.map((step) => step.point));
|
|
206
|
+
const at = (phase, slot) => steps.filter((step) => {
|
|
207
|
+
const address = addressOf(step.point);
|
|
208
|
+
return address.phase === phase && address.slot === slot && step.point !== phase;
|
|
209
|
+
});
|
|
210
|
+
const checked = config.apps.filter((app) => app.verify).map((app) => app.name);
|
|
211
|
+
// Both refusals live on a step's check, so a run printed here is one this
|
|
212
|
+
// environment can actually be asked for
|
|
213
|
+
const runs = Object.entries(RUNS).filter(([run]) => (run === "verify" ? checked.length > 0 : serves));
|
|
214
|
+
if (runs.length === 0) {
|
|
215
|
+
return say("\nno pipeline. This environment publishes nothing, so it cannot deploy, " +
|
|
216
|
+
"and no app declares verify");
|
|
217
|
+
}
|
|
218
|
+
for (const [run, phases] of runs) {
|
|
219
|
+
say(`\npipeline (${run})`);
|
|
220
|
+
for (const phase of phases) {
|
|
221
|
+
for (const slot of SLOTS) {
|
|
222
|
+
// Redkite's own step leads its phase's slot. A deployment that puts one
|
|
223
|
+
// at the same point replaces it, and this is where that shows
|
|
224
|
+
if (slot === "main") {
|
|
225
|
+
const who = added.has(phase) ? "replaced" : "redkite";
|
|
226
|
+
const what = phase === "verify" ? ` ${checked.join(", ")}` : "";
|
|
227
|
+
say(` ${phase.padEnd(26)}${who}${what}`);
|
|
228
|
+
}
|
|
229
|
+
for (const step of at(phase, slot))
|
|
230
|
+
say(` ${step.point}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Five presses is a build that has ignored SIGKILL, which is a process nothing
|
|
236
|
+
// here can end. The way out is offered rather than taken, because taking it is
|
|
237
|
+
// the one thing that leaves work running with nothing watching it
|
|
238
|
+
const ASK_AT = 5;
|
|
239
|
+
// The first ask is polite, every one after it is not. What a press does is
|
|
240
|
+
// choose the signal the wait keeps sending, and only the last one leaves
|
|
241
|
+
export function stopper(on) {
|
|
242
|
+
let presses = 0;
|
|
243
|
+
return () => {
|
|
244
|
+
presses += 1;
|
|
245
|
+
if (presses === 1) {
|
|
246
|
+
on.say("Stopping the build (SIGTERM). Press again to kill it");
|
|
247
|
+
on.abort();
|
|
248
|
+
return on.signal("TERM");
|
|
249
|
+
}
|
|
250
|
+
if (presses < ASK_AT) {
|
|
251
|
+
on.say("Killing the build (SIGKILL). Nothing exits until it is gone");
|
|
252
|
+
return on.signal("KILL");
|
|
253
|
+
}
|
|
254
|
+
if (presses === ASK_AT) {
|
|
255
|
+
for (const line of REFUSING)
|
|
256
|
+
on.say(line);
|
|
257
|
+
return on.signal("KILL");
|
|
258
|
+
}
|
|
259
|
+
on.leave();
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
// What leaving costs, said before it is offered rather than after it is done
|
|
263
|
+
const REFUSING = [
|
|
264
|
+
"This is not stopping. It has had SIGKILL and is still there.",
|
|
265
|
+
"Press again to leave redkite. That does not stop it: the build keeps running",
|
|
266
|
+
"on the host, may finish and tag an image no deploy is waiting for, and holds",
|
|
267
|
+
"the CPU and disk it is using. Nothing will clean up after it but you.",
|
|
268
|
+
];
|
|
269
|
+
// A stopped deploy is not over until what it started is gone. The host is asked
|
|
270
|
+
// again and again because the answer is a count, and zero is the only one that
|
|
271
|
+
// ends this
|
|
272
|
+
async function gone(host, hardest, say) {
|
|
273
|
+
let said = 0;
|
|
274
|
+
for (let left = await host.stop(hardest()); left > 0; left = await host.stop(hardest())) {
|
|
275
|
+
if (left !== said) {
|
|
276
|
+
say(`Waiting for ${left} still running`);
|
|
277
|
+
said = left;
|
|
278
|
+
}
|
|
279
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_MS));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const POLL_MS = 400;
|
|
283
|
+
// --local says it for this run alone, without the config having to change. It
|
|
284
|
+
// lands wherever the environment came from, so an inline one moves too
|
|
285
|
+
export function buildingHere(config, environment) {
|
|
286
|
+
if (config.environment) {
|
|
287
|
+
return { ...config, environment: { ...config.environment, buildOn: "local" } };
|
|
288
|
+
}
|
|
289
|
+
const declared = config.environments?.[environment];
|
|
290
|
+
if (!declared)
|
|
291
|
+
return config;
|
|
292
|
+
return {
|
|
293
|
+
...config,
|
|
294
|
+
environments: {
|
|
295
|
+
...config.environments,
|
|
296
|
+
[environment]: { ...declared, buildOn: "local" },
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
// Without a bastion the containers are on this machine, and every command the
|
|
301
|
+
// deploy issues is one this process can run itself
|
|
302
|
+
async function hostFor(host, log, signal) {
|
|
303
|
+
if (!host?.bastion)
|
|
304
|
+
return await localHost({ signal });
|
|
305
|
+
const task = log.step(`Opening a connection to ${host.bastion}`);
|
|
306
|
+
try {
|
|
307
|
+
const opened = await sshHost(host.bastion, { signal });
|
|
308
|
+
task.done();
|
|
309
|
+
return opened;
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
task.fail(`Could not reach ${host.bastion}`);
|
|
313
|
+
throw error;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Only the stores the config actually names. A deployment that keeps its
|
|
317
|
+
// environment somewhere else, or nowhere, needs no credentials to deploy
|
|
318
|
+
async function openStores(config, log) {
|
|
319
|
+
// Services name refs too, and a deployment whose only secret is a database
|
|
320
|
+
// password opened no store at all until this counted them
|
|
321
|
+
const refs = [
|
|
322
|
+
...config.apps.flatMap((app) => [
|
|
323
|
+
...listRefs(app.secrets),
|
|
324
|
+
...Object.values(app.files ?? {}),
|
|
325
|
+
]),
|
|
326
|
+
...config.services.flatMap((service) => listRefs(service.secrets)),
|
|
327
|
+
];
|
|
328
|
+
const providers = new Set(refs.map((ref) => ref.provider));
|
|
329
|
+
if (!providers.has("bitwarden"))
|
|
330
|
+
return {};
|
|
331
|
+
const vault = log.step("Reading the vault");
|
|
332
|
+
try {
|
|
333
|
+
const bitwarden = await bitwardenStore({
|
|
334
|
+
detail: vault.detail,
|
|
335
|
+
clientId: required("BW_CLIENT_ID"),
|
|
336
|
+
clientSecret: required("BW_CLIENT_SECRET"),
|
|
337
|
+
password: required("BW_PASSWORD"),
|
|
338
|
+
});
|
|
339
|
+
vault.done();
|
|
340
|
+
return { bitwarden };
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
vault.fail("Could not read the vault");
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function required(name) {
|
|
348
|
+
const value = process.env[name];
|
|
349
|
+
if (value)
|
|
350
|
+
return value;
|
|
351
|
+
throw new Error(`${name} is not set, and this deployment reads its environment from Bitwarden`);
|
|
352
|
+
}
|
|
353
|
+
async function run(kind, environment, configPath, options) {
|
|
354
|
+
const config = await loadConfig(configPath);
|
|
355
|
+
// Fail on a missing environment before opening anything for it
|
|
356
|
+
const topology = topologyFor(config, environment);
|
|
357
|
+
const deployHost = environmentOf(config, environment)?.host;
|
|
358
|
+
// The host clones the repositories over this, so it has to exist before the
|
|
359
|
+
// connection that forwards it is opened. Before the view too: ssh-add asks
|
|
360
|
+
// for a passphrase on the terminal, and by then the view owns it
|
|
361
|
+
requireAgent((message) => process.stderr.write(`${message}\n`));
|
|
362
|
+
// Whatever is in flight is killed, the pipeline unwinds through its own
|
|
363
|
+
// failure path, and the finally below removes the scratch directory
|
|
364
|
+
const stopping = new AbortController();
|
|
365
|
+
const log = createLog({
|
|
366
|
+
...options,
|
|
367
|
+
onQuit: () => stop(),
|
|
368
|
+
});
|
|
369
|
+
// Read by the wait below, so a press during it hardens what that is sending
|
|
370
|
+
let hardest = "TERM";
|
|
371
|
+
const stop = stopper({
|
|
372
|
+
say: log.warn,
|
|
373
|
+
abort: () => stopping.abort(),
|
|
374
|
+
signal: (name) => {
|
|
375
|
+
hardest = name;
|
|
376
|
+
// Nothing waits on this: the wait is in the finally, and this is what
|
|
377
|
+
// makes the command in flight answer so the run can get there
|
|
378
|
+
void host?.stop(name);
|
|
379
|
+
},
|
|
380
|
+
leave: () => {
|
|
381
|
+
log.warn("Leaving. What is still running on the host is yours to stop");
|
|
382
|
+
log.close();
|
|
383
|
+
process.exit(130);
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
// The viewer reads ctrl+c as a key, because it holds the terminal in raw
|
|
387
|
+
// mode. Everything else arrives here as a signal
|
|
388
|
+
process.on("SIGINT", stop);
|
|
389
|
+
let host;
|
|
390
|
+
try {
|
|
391
|
+
const meter = measured(await hostFor(deployHost, log, stopping.signal), options.verbose ? log : undefined);
|
|
392
|
+
host = meter.host;
|
|
393
|
+
const start = kind === "verify" ? verify : deploy;
|
|
394
|
+
const result = await start({
|
|
395
|
+
config: options.local ? buildingHere(config, environment) : config,
|
|
396
|
+
environment,
|
|
397
|
+
host,
|
|
398
|
+
secrets: await openStores(config, log),
|
|
399
|
+
verbose: options.verbose,
|
|
400
|
+
signal: stopping.signal,
|
|
401
|
+
log,
|
|
402
|
+
});
|
|
403
|
+
log(`Host: ${meter.summary()}`);
|
|
404
|
+
if (kind === "verify") {
|
|
405
|
+
log.done(`Checked ${result.checked.join(", ")} in ${topology.environment}`);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (result.ok) {
|
|
409
|
+
log.done(`Deployed ${result.released.join(", ")} to ${topology.environment}`);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
log.fail(`Reverted ${result.reverted.join(", ")}`);
|
|
413
|
+
process.exitCode = 1;
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
// Whatever the command in flight said about being killed is noise: what
|
|
417
|
+
// happened is that somebody asked for it to stop
|
|
418
|
+
if (stopping.signal.aborted) {
|
|
419
|
+
log.fail("Stopped");
|
|
420
|
+
process.exitCode = 130;
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
log.fail(describeFailure(error));
|
|
424
|
+
process.exitCode = 1;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
finally {
|
|
428
|
+
// Nothing leaves while the build is still running. The signal a press
|
|
429
|
+
// chose is resent every time round, so pressing again hardens it
|
|
430
|
+
if (stopping.signal.aborted && host)
|
|
431
|
+
await gone(host, () => hardest, log.warn);
|
|
432
|
+
await host?.close?.();
|
|
433
|
+
// Leaves the alternate screen and writes the run out on the screen the
|
|
434
|
+
// person keeps, which is also what lets the process exit
|
|
435
|
+
log.close();
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Viewer } from "./viewer.js";
|
|
2
|
+
export type LogOptions = {
|
|
3
|
+
verbose?: boolean;
|
|
4
|
+
full?: boolean;
|
|
5
|
+
onQuit?: () => void;
|
|
6
|
+
};
|
|
7
|
+
export declare function createLog(options?: LogOptions): Viewer;
|
|
8
|
+
export declare function describeFailure(error: unknown): string;
|
|
9
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/cli/log.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAYxD,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAIF,wBAAgB,SAAS,CAAC,OAAO,GAAE,UAAe,GAAG,MAAM,CAU1D;AAqGD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,UAU7C"}
|
package/dist/cli/log.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { elapsed as took } from "./screen.js";
|
|
2
|
+
import { createViewer } from "./viewer.js";
|
|
3
|
+
// What a deploy prints. The engine's own trace is a build graph with span ids
|
|
4
|
+
// and manifest resolution in it, which answers a question nobody deploying has.
|
|
5
|
+
const STAMP = 90;
|
|
6
|
+
const WARN = 33;
|
|
7
|
+
const FAIL = 31;
|
|
8
|
+
const DONE = 32;
|
|
9
|
+
const started = Date.now();
|
|
10
|
+
// A terminal gets the step viewer. Anything else, a pipe, a CI log or --full,
|
|
11
|
+
// gets one line per event, because there is nothing there to redraw
|
|
12
|
+
export function createLog(options = {}) {
|
|
13
|
+
if (viewable(process.stdout, process.stdin, options)) {
|
|
14
|
+
return createViewer(process.stdout, process.stdin, { onQuit: options.onQuit });
|
|
15
|
+
}
|
|
16
|
+
// --full is the reason to print a step's own output without asking for the
|
|
17
|
+
// host commands beside it, which is what --verbose adds
|
|
18
|
+
return Object.assign(plainLog(options.verbose === true || options.full === true), {
|
|
19
|
+
close: () => { },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function viewable(stream, input, options) {
|
|
23
|
+
if (options.full || process.env["REDKITE_PLAIN"])
|
|
24
|
+
return false;
|
|
25
|
+
return stream.isTTY === true && input.isTTY === true;
|
|
26
|
+
}
|
|
27
|
+
function plainLog(lines) {
|
|
28
|
+
const live = { write: (line) => process.stdout.write(line) };
|
|
29
|
+
const write = (stream, message, colour) => {
|
|
30
|
+
const painted = colours(stream);
|
|
31
|
+
const stamp = painted ? paint(elapsed(), STAMP) : elapsed();
|
|
32
|
+
const body = painted && colour ? paint(message, colour) : message;
|
|
33
|
+
const line = `${stamp} ${body}\n`;
|
|
34
|
+
// Both streams share one terminal, so the block has to come down for a
|
|
35
|
+
// failure on stderr just as it does for progress on stdout
|
|
36
|
+
if (stream === process.stdout)
|
|
37
|
+
return live.write(line);
|
|
38
|
+
live.write("");
|
|
39
|
+
stream.write(line);
|
|
40
|
+
};
|
|
41
|
+
const info = (message) => write(process.stdout, message);
|
|
42
|
+
const step = (label) => {
|
|
43
|
+
write(process.stdout, label);
|
|
44
|
+
const started = Date.now();
|
|
45
|
+
let current;
|
|
46
|
+
// A sub-step leaves the block when the next one starts, and lands here with
|
|
47
|
+
// what it cost. The live view stays short without the run losing its record
|
|
48
|
+
const settle = () => {
|
|
49
|
+
if (!current)
|
|
50
|
+
return;
|
|
51
|
+
write(process.stdout, ` ${label}: ${current.text} (${since(current.at)})`);
|
|
52
|
+
current = undefined;
|
|
53
|
+
};
|
|
54
|
+
const trace = (message) => {
|
|
55
|
+
settle();
|
|
56
|
+
current = { text: message, at: Date.now() };
|
|
57
|
+
write(process.stdout, ` ${label}: ${message}`);
|
|
58
|
+
};
|
|
59
|
+
return {
|
|
60
|
+
detail: trace,
|
|
61
|
+
// In full, never clipped: this is the view for reading what a build said
|
|
62
|
+
line: (message) => {
|
|
63
|
+
if (lines)
|
|
64
|
+
write(process.stdout, ` ${label} | ${message}`);
|
|
65
|
+
},
|
|
66
|
+
done: (message) => {
|
|
67
|
+
settle();
|
|
68
|
+
const suffix = message ? `: ${message}` : "";
|
|
69
|
+
write(process.stdout, `${label}${suffix} (${since(started)})`, DONE);
|
|
70
|
+
},
|
|
71
|
+
fail: (message) => {
|
|
72
|
+
settle();
|
|
73
|
+
write(process.stderr, `${message} (${since(started)})`, FAIL);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
return Object.assign(info, {
|
|
78
|
+
warn: (message) => write(process.stdout, message, WARN),
|
|
79
|
+
// Failures go to stderr, so a piped log still carries the progress alone
|
|
80
|
+
fail: (message) => write(process.stderr, message, FAIL),
|
|
81
|
+
done: (message) => write(process.stdout, message, DONE),
|
|
82
|
+
step,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function paint(text, colour) {
|
|
86
|
+
return `\u001b[${colour}m${text}\u001b[0m`;
|
|
87
|
+
}
|
|
88
|
+
// A file or a pipe takes the text without the escapes, and NO_COLOR is a
|
|
89
|
+
// standing instruction rather than a preference to re-ask about
|
|
90
|
+
function colours(stream) {
|
|
91
|
+
if (process.env["NO_COLOR"])
|
|
92
|
+
return false;
|
|
93
|
+
return stream.isTTY === true;
|
|
94
|
+
}
|
|
95
|
+
function elapsed() {
|
|
96
|
+
return `[${took(Date.now(), started, true)}]`;
|
|
97
|
+
}
|
|
98
|
+
function since(at) {
|
|
99
|
+
return took(Date.now(), at);
|
|
100
|
+
}
|
|
101
|
+
const TAIL = 20;
|
|
102
|
+
// A failure carries the tail of whatever the command wrote, and a build writes
|
|
103
|
+
// a lot. The chain matters because a step wraps the command it ran
|
|
104
|
+
export function describeFailure(error) {
|
|
105
|
+
if (!(error instanceof Error))
|
|
106
|
+
return String(error);
|
|
107
|
+
// A wrapper that already quotes what it wrapped must not say it twice
|
|
108
|
+
const chain = causes(error).map((link) => link.message);
|
|
109
|
+
const said = chain.filter((message, index) => !chain.slice(0, index).some((earlier) => earlier.includes(message)));
|
|
110
|
+
return tail(said.join("\n"));
|
|
111
|
+
}
|
|
112
|
+
const DEPTH = 8;
|
|
113
|
+
function causes(error) {
|
|
114
|
+
const chain = [];
|
|
115
|
+
let current = error;
|
|
116
|
+
while (current instanceof Error && chain.length < DEPTH) {
|
|
117
|
+
chain.push(current);
|
|
118
|
+
current = current.cause;
|
|
119
|
+
}
|
|
120
|
+
return chain;
|
|
121
|
+
}
|
|
122
|
+
function tail(body) {
|
|
123
|
+
const lines = body.split("\n");
|
|
124
|
+
if (lines.length <= TAIL)
|
|
125
|
+
return body;
|
|
126
|
+
return [`... ${lines.length - TAIL} earlier lines`, ...lines.slice(-TAIL)].join("\n");
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/cli/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type StepState = "running" | "done" | "failed";
|
|
2
|
+
export type Step = {
|
|
3
|
+
label: string;
|
|
4
|
+
started: number;
|
|
5
|
+
ended?: number;
|
|
6
|
+
state: StepState;
|
|
7
|
+
note?: string;
|
|
8
|
+
detail?: string;
|
|
9
|
+
lines: string[];
|
|
10
|
+
expanded: boolean;
|
|
11
|
+
held: boolean;
|
|
12
|
+
offset: number;
|
|
13
|
+
};
|
|
14
|
+
export type Model = {
|
|
15
|
+
steps: Step[];
|
|
16
|
+
messages: string[];
|
|
17
|
+
cursor: number;
|
|
18
|
+
following: boolean;
|
|
19
|
+
minimal: boolean;
|
|
20
|
+
rows: number;
|
|
21
|
+
columns: number;
|
|
22
|
+
started: number;
|
|
23
|
+
now: number;
|
|
24
|
+
};
|
|
25
|
+
export type Key = "up" | "down" | "latest" | "first" | "toggle" | "expand" | "collapse" | "quit";
|
|
26
|
+
export declare function emptyModel(rows: number, columns: number, now: number): Model;
|
|
27
|
+
export declare function keysOf(data: string): Key[];
|
|
28
|
+
export declare function keyOf(data: string): Key | undefined;
|
|
29
|
+
export declare function apply(model: Model, key: Key): Model;
|
|
30
|
+
export declare const HELP = "\u2191\u2193 move \u00B7 enter open \u00B7 shift+\u2191 latest \u00B7 + open \u00B7 - collapse all \u00B7 q quit";
|
|
31
|
+
export declare function render(model: Model, colour?: boolean): string[];
|
|
32
|
+
export declare function clip(text: string, room: number): string;
|
|
33
|
+
export declare function elapsed(now: number, started: number, clock?: boolean): string;
|
|
34
|
+
//# sourceMappingURL=screen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/cli/screen.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEtD,MAAM,MAAM,IAAI,GAAG;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IAEjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAElB,IAAI,EAAE,OAAO,CAAC;IAEd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IAEf,SAAS,EAAE,OAAO,CAAC;IAEnB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,GAAG,GACX,IAAI,GACJ,MAAM,GACN,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,MAAM,CAAC;AAEX,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,CAY5E;AAOD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,EAAE,CAe1C;AAID,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAWnD;AAID,wBAAgB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,KAAK,CAgEnD;AA6DD,eAAO,MAAM,IAAI,qHACmG,CAAC;AAErH,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,UAAQ,GAAG,MAAM,EAAE,CAyC7D;AAyDD,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAG9C;AAqDD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,UAAQ,UAQlE"}
|