@statuser/cli 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +448 -2
- package/dist/client.js +163 -0
- package/dist/client.js.map +1 -0
- package/dist/commander-i18n.js +52 -0
- package/dist/commander-i18n.js.map +1 -0
- package/dist/commands/api.js +104 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/auth.js +104 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/catalog.js +72 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/config.js +302 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/heartbeat.js +199 -0
- package/dist/commands/heartbeat.js.map +1 -0
- package/dist/commands/incidents.js +265 -0
- package/dist/commands/incidents.js.map +1 -0
- package/dist/commands/maintenance.js +211 -0
- package/dist/commands/maintenance.js.map +1 -0
- package/dist/commands/reports.js +170 -0
- package/dist/commands/reports.js.map +1 -0
- package/dist/commands/scenarios.js +361 -0
- package/dist/commands/scenarios.js.map +1 -0
- package/dist/commands/servers-add.js +152 -0
- package/dist/commands/servers-add.js.map +1 -0
- package/dist/commands/servers-checks.js +56 -0
- package/dist/commands/servers-checks.js.map +1 -0
- package/dist/commands/servers.js +424 -0
- package/dist/commands/servers.js.map +1 -0
- package/dist/config.js +107 -0
- package/dist/config.js.map +1 -0
- package/dist/confirm.js +34 -0
- package/dist/confirm.js.map +1 -0
- package/dist/context.js +27 -0
- package/dist/context.js.map +1 -0
- package/dist/duration.js +20 -0
- package/dist/duration.js.map +1 -0
- package/dist/errors.js +73 -0
- package/dist/errors.js.map +1 -0
- package/dist/files.js +36 -0
- package/dist/files.js.map +1 -0
- package/dist/generated/openapi.js +6 -0
- package/dist/generated/openapi.js.map +1 -0
- package/dist/i18n.js +757 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/json-error.js +10 -0
- package/dist/json-error.js.map +1 -0
- package/dist/output.js +43 -0
- package/dist/output.js.map +1 -0
- package/dist/scenarios/config.js +228 -0
- package/dist/scenarios/config.js.map +1 -0
- package/dist/scenarios/plan.js +159 -0
- package/dist/scenarios/plan.js.map +1 -0
- package/dist/servers-config/export.js +72 -0
- package/dist/servers-config/export.js.map +1 -0
- package/dist/servers-config/fields.js +172 -0
- package/dist/servers-config/fields.js.map +1 -0
- package/dist/servers-config/forbidden-host.js +75 -0
- package/dist/servers-config/forbidden-host.js.map +1 -0
- package/dist/servers-config/host-pattern.js +6 -0
- package/dist/servers-config/host-pattern.js.map +1 -0
- package/dist/servers-config/parse.js +260 -0
- package/dist/servers-config/parse.js.map +1 -0
- package/dist/servers-config/plan.js +492 -0
- package/dist/servers-config/plan.js.map +1 -0
- package/dist/servers-update.js +157 -0
- package/dist/servers-update.js.map +1 -0
- package/dist/status-page.js +15 -0
- package/dist/status-page.js.map +1 -0
- package/dist/text-length.js +8 -0
- package/dist/text-length.js.map +1 -0
- package/dist/write-failure.js +37 -0
- package/dist/write-failure.js.map +1 -0
- package/package.json +70 -4
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { inspect } from 'node:util';
|
|
3
|
+
import { authedClient, globalOptions } from '../context.js';
|
|
4
|
+
import { CliError, ExitCode } from '../errors.js';
|
|
5
|
+
import { t } from '../i18n.js';
|
|
6
|
+
import { printErr, printJson, printLine } from '../output.js';
|
|
7
|
+
import { loadScenarioConfig, resolveEnvValue, scenarioEnvProblem, SCENARIO_DEFAULT_LOCATION, SCENARIO_DEFAULT_TIMEOUT, SCENARIO_LOCATIONS, SCENARIO_TIMEOUTS, } from '../scenarios/config.js';
|
|
8
|
+
import { buildDeployPlan } from '../scenarios/plan.js';
|
|
9
|
+
import { checkScenarioLimits } from '../servers-config/plan.js';
|
|
10
|
+
import { describeWriteFailure } from '../write-failure.js';
|
|
11
|
+
import { listServers, parseId } from './servers.js';
|
|
12
|
+
// The sandbox may wait up to 30 s for a free slot on top of the run itself,
|
|
13
|
+
// then uploads artifacts.
|
|
14
|
+
const PREVIEW_OVERHEAD_MS = 90_000;
|
|
15
|
+
const collect = (value, previous) => [...previous, value];
|
|
16
|
+
export function registerScenariosCommands(program) {
|
|
17
|
+
const scenarios = program.command('scenarios').description(t.cmdScenarios);
|
|
18
|
+
scenarios
|
|
19
|
+
.command('test')
|
|
20
|
+
.description(t.cmdScenariosTest)
|
|
21
|
+
.argument('<file>')
|
|
22
|
+
.option('--timeout <seconds>', t.optTimeout, String(SCENARIO_DEFAULT_TIMEOUT))
|
|
23
|
+
.option('--location <code>', t.optLocation, SCENARIO_DEFAULT_LOCATION)
|
|
24
|
+
.option('--env <KEY=VALUE>', t.optEnv, collect, [])
|
|
25
|
+
.action(async (file, opts, command) => {
|
|
26
|
+
const timeout = Number(opts.timeout);
|
|
27
|
+
if (!SCENARIO_TIMEOUTS.includes(timeout)) {
|
|
28
|
+
throw new CliError(t.optTimeout, ExitCode.Usage);
|
|
29
|
+
}
|
|
30
|
+
if (!SCENARIO_LOCATIONS.includes(opts.location)) {
|
|
31
|
+
throw new CliError(t.optLocation, ExitCode.Usage);
|
|
32
|
+
}
|
|
33
|
+
const env = Object.create(null);
|
|
34
|
+
for (const [position, raw] of opts.env.entries()) {
|
|
35
|
+
const index = raw.indexOf('=');
|
|
36
|
+
// The argument may be a bare value: it is never quoted back.
|
|
37
|
+
// A bad name may be part of a secret passed by mistake
|
|
38
|
+
// (`--env 'YWJj=='`): the problem is named by position only.
|
|
39
|
+
if (index <= 0 ||
|
|
40
|
+
scenarioEnvProblem({ [raw.slice(0, index)]: '' }) !== null) {
|
|
41
|
+
throw new CliError(t.argInvalid('--env', position + 1), ExitCode.Usage);
|
|
42
|
+
}
|
|
43
|
+
env[raw.slice(0, index)] = resolveEnvValue(raw.slice(index + 1), file, process.env);
|
|
44
|
+
}
|
|
45
|
+
const envProblem = scenarioEnvProblem(env);
|
|
46
|
+
if (envProblem)
|
|
47
|
+
throw new CliError(envProblem, ExitCode.Usage);
|
|
48
|
+
let script;
|
|
49
|
+
try {
|
|
50
|
+
script = await readFile(file, 'utf8');
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new CliError(t.configNotFound(file), ExitCode.Usage);
|
|
54
|
+
}
|
|
55
|
+
const json = globalOptions(command).json;
|
|
56
|
+
if (!json)
|
|
57
|
+
printErr(t.scenarioRunning);
|
|
58
|
+
const { client } = await authedClient(command);
|
|
59
|
+
// Not retried on a dropped connection: the run may have happened, and
|
|
60
|
+
// the account allows one on-demand run at a time.
|
|
61
|
+
const result = await client.call({
|
|
62
|
+
method: 'POST',
|
|
63
|
+
path: '/v1/scenario-runs/preview',
|
|
64
|
+
body: {
|
|
65
|
+
scenario_script: script,
|
|
66
|
+
// Both checked against the spec enums above.
|
|
67
|
+
request_timeout: timeout,
|
|
68
|
+
locations: [
|
|
69
|
+
opts.location,
|
|
70
|
+
],
|
|
71
|
+
...(Object.keys(env).length ? { scenario_env: env } : {}),
|
|
72
|
+
},
|
|
73
|
+
timeoutMs: timeout * 1000 + PREVIEW_OVERHEAD_MS,
|
|
74
|
+
});
|
|
75
|
+
// The test may print or compare its passwords; the run result comes
|
|
76
|
+
// back verbatim, so the values passed here are masked before output.
|
|
77
|
+
const masked = maskSecrets(result, Object.values(env));
|
|
78
|
+
if (json)
|
|
79
|
+
printJson(masked);
|
|
80
|
+
else
|
|
81
|
+
printRunResult(masked);
|
|
82
|
+
process.exitCode = runExitCode(result.status);
|
|
83
|
+
});
|
|
84
|
+
scenarios
|
|
85
|
+
.command('run')
|
|
86
|
+
.description(t.cmdScenariosRun)
|
|
87
|
+
.argument('<id>', 'id', parseId)
|
|
88
|
+
.action(async (id, _opts, command) => {
|
|
89
|
+
const { client } = await authedClient(command);
|
|
90
|
+
const server = await client.call({
|
|
91
|
+
method: 'GET',
|
|
92
|
+
path: `/v1/servers/${id}`,
|
|
93
|
+
});
|
|
94
|
+
if (server.protocol !== 'scenario') {
|
|
95
|
+
throw new CliError(t.scenarioNotScenario(id, server.protocol), ExitCode.Usage);
|
|
96
|
+
}
|
|
97
|
+
// The answer comes when the run ends: up to the scenario's timeout
|
|
98
|
+
// plus the start. Not retried on a dropped connection — the run may
|
|
99
|
+
// have happened, and it counts like a scheduled one.
|
|
100
|
+
const result = await client.call({
|
|
101
|
+
method: 'POST',
|
|
102
|
+
path: `/v1/servers/${id}/scenario-run`,
|
|
103
|
+
timeoutMs: server.request_timeout * 1000 + PREVIEW_OVERHEAD_MS,
|
|
104
|
+
});
|
|
105
|
+
// The API returns the saved run's console and error verbatim, and the
|
|
106
|
+
// values of its variables are not readable. In CI they usually sit in
|
|
107
|
+
// the environment under the same names (the config refers to them as
|
|
108
|
+
// `$NAME`): those are masked, the rest are named in a warning.
|
|
109
|
+
const keys = server.scenario_env_keys ?? [];
|
|
110
|
+
const known = keys.filter((key) => process.env[key]);
|
|
111
|
+
const unknown = keys.filter((key) => !process.env[key]);
|
|
112
|
+
if (unknown.length)
|
|
113
|
+
printErr(t.scenarioEnvUnmasked(unknown.join(', ')));
|
|
114
|
+
const masked = maskSecrets(result, known.map((key) => process.env[key]));
|
|
115
|
+
if (globalOptions(command).json)
|
|
116
|
+
printJson(masked);
|
|
117
|
+
else
|
|
118
|
+
printRunResult(masked);
|
|
119
|
+
process.exitCode = runExitCode(result.status);
|
|
120
|
+
});
|
|
121
|
+
scenarios
|
|
122
|
+
.command('deploy')
|
|
123
|
+
.description(t.cmdScenariosDeploy)
|
|
124
|
+
.option('-c, --config <path>', t.optConfig, 'statuser.json')
|
|
125
|
+
.option('--dry-run', t.optDryRun)
|
|
126
|
+
.action(async (opts, command) => {
|
|
127
|
+
const config = await loadScenarioConfig(opts.config);
|
|
128
|
+
const { client } = await authedClient(command);
|
|
129
|
+
// The whole account: duplicate scripts are checked account-wide.
|
|
130
|
+
const [servers, current] = await Promise.all([
|
|
131
|
+
listServers(client),
|
|
132
|
+
client.call({
|
|
133
|
+
method: 'GET',
|
|
134
|
+
path: '/v1/billing/current-plan',
|
|
135
|
+
}),
|
|
136
|
+
]);
|
|
137
|
+
const plan = buildDeployPlan(config, servers);
|
|
138
|
+
// Plan limits before the first write, as `apply` does.
|
|
139
|
+
const creates = plan.steps.filter((s) => s.kind === 'create').length;
|
|
140
|
+
checkScenarioLimits(plan.steps, servers.filter((s) => s.protocol === 'scenario').length, current.features);
|
|
141
|
+
if (creates &&
|
|
142
|
+
servers.length + creates > current.features.servers_limit) {
|
|
143
|
+
throw new CliError(t.applyServersLimit(current.features.servers_limit, servers.length, creates), ExitCode.Usage);
|
|
144
|
+
}
|
|
145
|
+
const json = globalOptions(command).json;
|
|
146
|
+
const pending = plan.steps.filter((s) => s.kind !== 'unchanged');
|
|
147
|
+
if (!json) {
|
|
148
|
+
printLine(t.deployPlanTitle(plan.projectId));
|
|
149
|
+
for (const step of plan.steps)
|
|
150
|
+
printLine(describeStep(step));
|
|
151
|
+
for (const item of plan.unmanaged) {
|
|
152
|
+
printLine(t.deployUnmanaged(item.name ?? '', item.id));
|
|
153
|
+
}
|
|
154
|
+
if (pending.some((s) => s.kind === 'update' && s.fields.includes('env'))) {
|
|
155
|
+
printErr(t.deployEnvAlwaysSent);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const applied = [];
|
|
159
|
+
const summary = () => ({
|
|
160
|
+
project_id: plan.projectId,
|
|
161
|
+
dry_run: !!opts.dryRun,
|
|
162
|
+
// Bodies are left out: they carry scenario env values.
|
|
163
|
+
steps: plan.steps.map((step) => ({
|
|
164
|
+
name: step.scenario.name,
|
|
165
|
+
action: step.kind,
|
|
166
|
+
id: step.kind === 'create' ? null : step.serverId,
|
|
167
|
+
fields: step.kind === 'update' ? step.fields : undefined,
|
|
168
|
+
})),
|
|
169
|
+
unmanaged: plan.unmanaged,
|
|
170
|
+
applied,
|
|
171
|
+
});
|
|
172
|
+
if (opts.dryRun || !pending.length) {
|
|
173
|
+
if (json)
|
|
174
|
+
printJson(summary());
|
|
175
|
+
else
|
|
176
|
+
printLine(opts.dryRun ? t.deployDryRunDone : t.deployNothing);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
for (const step of pending) {
|
|
180
|
+
try {
|
|
181
|
+
if (step.kind === 'create') {
|
|
182
|
+
const created = await client.call({
|
|
183
|
+
method: 'POST',
|
|
184
|
+
path: '/v1/servers',
|
|
185
|
+
body: step.body,
|
|
186
|
+
});
|
|
187
|
+
applied.push({
|
|
188
|
+
name: step.scenario.name,
|
|
189
|
+
action: 'create',
|
|
190
|
+
id: created.id,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
else if (step.kind === 'update') {
|
|
194
|
+
await client.call({
|
|
195
|
+
method: 'PATCH',
|
|
196
|
+
path: `/v1/servers/${step.serverId}`,
|
|
197
|
+
body: step.body,
|
|
198
|
+
});
|
|
199
|
+
applied.push({
|
|
200
|
+
name: step.scenario.name,
|
|
201
|
+
action: 'update',
|
|
202
|
+
id: step.serverId,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (!json)
|
|
206
|
+
printLine(t.deployApplied(step.scenario.name));
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
const failure = describeWriteFailure(step.scenario.name, error);
|
|
210
|
+
if (json)
|
|
211
|
+
printJson({ ...summary(), error: failure });
|
|
212
|
+
throw new CliError(failure.message, failure.exitCode);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (json)
|
|
216
|
+
printJson(summary());
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
export function describeStep(step) {
|
|
220
|
+
switch (step.kind) {
|
|
221
|
+
case 'create':
|
|
222
|
+
return t.deployCreate(step.scenario.name);
|
|
223
|
+
case 'update':
|
|
224
|
+
return t.deployUpdate(step.scenario.name, step.serverId, step.fields.join(', '));
|
|
225
|
+
case 'unchanged':
|
|
226
|
+
return t.deployUnchanged(step.scenario.name, step.serverId);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function printRunResult(result) {
|
|
230
|
+
if (result.status === 'passed') {
|
|
231
|
+
printLine(t.scenarioPassed(((result.duration_ms ?? 0) / 1000).toFixed(1)));
|
|
232
|
+
}
|
|
233
|
+
else if (result.status === 'runner_error') {
|
|
234
|
+
printLine(t.scenarioRunnerError);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
printLine(t.scenarioFailed(result.status));
|
|
238
|
+
if (result.failed_test)
|
|
239
|
+
printLine(t.scenarioFailedTest(result.failed_test));
|
|
240
|
+
if (result.error)
|
|
241
|
+
printLine(t.scenarioError(result.error));
|
|
242
|
+
}
|
|
243
|
+
for (const [kind, url] of Object.entries(result.artifact_urls ?? {})) {
|
|
244
|
+
if (url)
|
|
245
|
+
printLine(t.scenarioArtifact(kind, url));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/** passed → 0, a site-side failure → 4, our sandbox failing → 1. */
|
|
249
|
+
function runExitCode(status) {
|
|
250
|
+
if (status === 'passed')
|
|
251
|
+
return ExitCode.Ok;
|
|
252
|
+
if (status === 'runner_error')
|
|
253
|
+
return ExitCode.Failure;
|
|
254
|
+
return ExitCode.ScenarioFailed;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Masks the given secret values in the diagnostic fields of a run result:
|
|
258
|
+
* the error, the failed test title and the console. Structural fields
|
|
259
|
+
* (status, location, links) are left intact — they are the contract.
|
|
260
|
+
*/
|
|
261
|
+
export function maskSecrets(result, secrets) {
|
|
262
|
+
const values = secretForms(secrets);
|
|
263
|
+
if (!values.length)
|
|
264
|
+
return result;
|
|
265
|
+
const mask = (text) => typeof text === 'string' ? maskText(text, values) : text;
|
|
266
|
+
return {
|
|
267
|
+
...result,
|
|
268
|
+
error: mask(result.error),
|
|
269
|
+
failed_test: mask(result.failed_test),
|
|
270
|
+
console: result.console?.map((entry) => ({
|
|
271
|
+
...entry,
|
|
272
|
+
text: mask(entry.text) ?? '',
|
|
273
|
+
})) ?? null,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Every form a value may take in the run's output: as given, escaped by
|
|
278
|
+
* `JSON.stringify` in the script, and without trailing whitespace, which
|
|
279
|
+
* the runner trims from console lines.
|
|
280
|
+
*/
|
|
281
|
+
function secretForms(secrets) {
|
|
282
|
+
const forms = new Set();
|
|
283
|
+
for (const secret of secrets) {
|
|
284
|
+
// util.inspect (`console.log({ password })`) breaks a long multiline
|
|
285
|
+
// string into one literal per line, joined with `+` and indented by
|
|
286
|
+
// nesting: each line of the value is masked on its own too. Lines
|
|
287
|
+
// shorter than four characters are left, so as not to mask everywhere.
|
|
288
|
+
const lines = secret.includes('\n')
|
|
289
|
+
? secret.split('\n').filter((line) => line.length >= 4)
|
|
290
|
+
: [];
|
|
291
|
+
for (const part of [secret, ...lines]) {
|
|
292
|
+
addForms(forms, part);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return [...forms];
|
|
296
|
+
}
|
|
297
|
+
function addForms(forms, secret) {
|
|
298
|
+
// util.inspect has its own escaping and quote choice.
|
|
299
|
+
for (const form of [
|
|
300
|
+
secret,
|
|
301
|
+
JSON.stringify(secret).slice(1, -1),
|
|
302
|
+
inspect(secret).slice(1, -1),
|
|
303
|
+
]) {
|
|
304
|
+
for (const variant of [form, form.trimEnd()]) {
|
|
305
|
+
if (variant)
|
|
306
|
+
forms.add(variant);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Finds every place a value occupies in the original text first and only
|
|
312
|
+
* then replaces them: masking one value before searching for the next
|
|
313
|
+
* would break an overlapping one. The backend cuts long lines and appends
|
|
314
|
+
* `…`, so the start of a value at the cut is masked too.
|
|
315
|
+
*/
|
|
316
|
+
function maskText(text, values) {
|
|
317
|
+
const cut = text.endsWith('…');
|
|
318
|
+
const body = cut ? text.slice(0, -1) : text;
|
|
319
|
+
const ranges = [];
|
|
320
|
+
for (const value of values) {
|
|
321
|
+
for (let at = body.indexOf(value); at >= 0; at = body.indexOf(value, at + 1)) {
|
|
322
|
+
ranges.push([at, at + value.length]);
|
|
323
|
+
}
|
|
324
|
+
// The runner keeps only the last part of a long error, without a mark:
|
|
325
|
+
// a value cut at the start shows as its tail. Four characters at least,
|
|
326
|
+
// so a common last letter does not mask the start of every line.
|
|
327
|
+
for (let length = Math.min(value.length - 1, body.length); length >= 4; length -= 1) {
|
|
328
|
+
if (body.startsWith(value.slice(-length))) {
|
|
329
|
+
ranges.push([0, length]);
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (cut) {
|
|
334
|
+
for (let length = Math.min(value.length - 1, body.length); length > 0; length -= 1) {
|
|
335
|
+
if (body.endsWith(value.slice(0, length))) {
|
|
336
|
+
ranges.push([body.length - length, body.length]);
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (!ranges.length)
|
|
343
|
+
return text;
|
|
344
|
+
ranges.sort((a, b) => a[0] - b[0]);
|
|
345
|
+
const merged = [];
|
|
346
|
+
for (const [start, end] of ranges) {
|
|
347
|
+
const last = merged.at(-1);
|
|
348
|
+
if (last && start <= last[1])
|
|
349
|
+
last[1] = Math.max(last[1], end);
|
|
350
|
+
else
|
|
351
|
+
merged.push([start, end]);
|
|
352
|
+
}
|
|
353
|
+
let out = '';
|
|
354
|
+
let pos = 0;
|
|
355
|
+
for (const [start, end] of merged) {
|
|
356
|
+
out += `${body.slice(pos, start)}***`;
|
|
357
|
+
pos = end;
|
|
358
|
+
}
|
|
359
|
+
return `${out}${body.slice(pos)}${cut ? '…' : ''}`;
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=scenarios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenarios.js","sourceRoot":"","sources":["../../src/commands/scenarios.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { isIP } from 'node:net';
|
|
2
|
+
import { authedClient, globalOptions } from '../context.js';
|
|
3
|
+
import { CliError, ExitCode } from '../errors.js';
|
|
4
|
+
import { t } from '../i18n.js';
|
|
5
|
+
import { printErr, printJson, printLine } from '../output.js';
|
|
6
|
+
import { SCENARIO_LOCATIONS } from '../scenarios/config.js';
|
|
7
|
+
import { parseServersSection } from '../servers-config/parse.js';
|
|
8
|
+
import { buildServersPlan } from '../servers-config/plan.js';
|
|
9
|
+
import { listServers, parseId, redactServer } from './servers.js';
|
|
10
|
+
const ADD_PROTOCOLS = ['http', 'keyword', 'ping', 'tcp', 'dns', 'heartbeat'];
|
|
11
|
+
/**
|
|
12
|
+
* One server, with the panel defaults for everything not given. The entry
|
|
13
|
+
* goes through the same parser and plan as `apply`, so the same checks run
|
|
14
|
+
* before the write: ranges, the host gate, account-wide duplicates and the
|
|
15
|
+
* plan. Settings without a flag here are changed later by `servers update`.
|
|
16
|
+
*/
|
|
17
|
+
export function registerServersAdd(servers) {
|
|
18
|
+
servers
|
|
19
|
+
.command('add')
|
|
20
|
+
.description(t.cmdServersAdd)
|
|
21
|
+
.argument('[host]', t.argServerHost)
|
|
22
|
+
.option('--name <name>', t.optServerName)
|
|
23
|
+
.option('--protocol <protocol>', t.optAddProtocol)
|
|
24
|
+
.option('--project <id>', t.optProject, parseId)
|
|
25
|
+
.option('--port <port>', t.optPort)
|
|
26
|
+
.option('--keyword <word>', t.optKeyword)
|
|
27
|
+
.option('--keyword-absent', t.optKeywordAbsent)
|
|
28
|
+
.option('--dns-types <types>', t.optDnsTypes)
|
|
29
|
+
.option('--interval <seconds>', t.optInterval)
|
|
30
|
+
.option('--timeout <seconds>', t.optRequestTimeout)
|
|
31
|
+
.option('--regions <codes>', t.optRegions)
|
|
32
|
+
.option('--dry-run', t.optDryRun)
|
|
33
|
+
.action(async (host, opts, command) => {
|
|
34
|
+
const entry = buildEntry(host, opts);
|
|
35
|
+
// The parser names the place as in a file, `servers[0].port`; here
|
|
36
|
+
// the field name alone says which flag to fix.
|
|
37
|
+
const desired = parseServersSection([entry], process.env, (problem) => usage(problem.replace(/^servers\[0\]\.?/, '')), { allowUnnamed: true });
|
|
38
|
+
const label = entry.name ?? host ?? '';
|
|
39
|
+
desired[0].at = label;
|
|
40
|
+
const { client } = await authedClient(command);
|
|
41
|
+
const [account, current, projectId] = await Promise.all([
|
|
42
|
+
listServers(client),
|
|
43
|
+
client.call({
|
|
44
|
+
method: 'GET',
|
|
45
|
+
path: '/v1/billing/current-plan',
|
|
46
|
+
}),
|
|
47
|
+
opts.project ?? defaultProject(client),
|
|
48
|
+
]);
|
|
49
|
+
const plan = buildServersPlan(desired, projectId, account, current.features, 0, { createOnly: true });
|
|
50
|
+
const step = plan.steps[0];
|
|
51
|
+
if (step.kind !== 'create')
|
|
52
|
+
throw new Error('expected a create step');
|
|
53
|
+
for (const warning of step.warnings)
|
|
54
|
+
printErr(warning);
|
|
55
|
+
const json = globalOptions(command).json;
|
|
56
|
+
if (opts.dryRun) {
|
|
57
|
+
if (json)
|
|
58
|
+
printJson({ dry_run: true, body: step.body });
|
|
59
|
+
else
|
|
60
|
+
printLine(t.addDryRun(label));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const created = await client.call({
|
|
64
|
+
method: 'POST',
|
|
65
|
+
path: '/v1/servers',
|
|
66
|
+
body: step.body,
|
|
67
|
+
});
|
|
68
|
+
if (json)
|
|
69
|
+
printJson(redactServer(created));
|
|
70
|
+
else
|
|
71
|
+
printLine(t.addCreated(created.id, created.name || label));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function buildEntry(host, opts) {
|
|
75
|
+
const protocol = opts.protocol ?? guessProtocol(host);
|
|
76
|
+
if (!ADD_PROTOCOLS.includes(protocol)) {
|
|
77
|
+
usage(`--protocol: ${t.cfgOneOf(ADD_PROTOCOLS.join(', '))}`);
|
|
78
|
+
}
|
|
79
|
+
if (protocol === 'heartbeat') {
|
|
80
|
+
if (host)
|
|
81
|
+
usage(t.addHostNotUsed);
|
|
82
|
+
// A heartbeat is told apart by its name: the API requires one.
|
|
83
|
+
if (!opts.name?.trim())
|
|
84
|
+
usage(`--name: ${t.cfgNonEmptyString}`);
|
|
85
|
+
}
|
|
86
|
+
else if (!host) {
|
|
87
|
+
usage(t.addHostNeeded);
|
|
88
|
+
}
|
|
89
|
+
const entry = { protocol };
|
|
90
|
+
if (host)
|
|
91
|
+
entry.host = host;
|
|
92
|
+
if (opts.name !== undefined)
|
|
93
|
+
entry.name = opts.name;
|
|
94
|
+
if (opts.port !== undefined)
|
|
95
|
+
entry.port = integer('--port', opts.port);
|
|
96
|
+
if (opts.keyword !== undefined)
|
|
97
|
+
entry.keyword = opts.keyword;
|
|
98
|
+
if (opts.keywordAbsent)
|
|
99
|
+
entry.keyword_mode = 'absent';
|
|
100
|
+
if (opts.dnsTypes !== undefined)
|
|
101
|
+
entry.dns_record_types = list(opts.dnsTypes);
|
|
102
|
+
if (opts.interval !== undefined) {
|
|
103
|
+
entry.check_interval = integer('--interval', opts.interval);
|
|
104
|
+
}
|
|
105
|
+
if (opts.timeout !== undefined) {
|
|
106
|
+
entry.request_timeout = integer('--timeout', opts.timeout);
|
|
107
|
+
}
|
|
108
|
+
if (opts.regions !== undefined) {
|
|
109
|
+
const regions = list(opts.regions);
|
|
110
|
+
for (const region of regions) {
|
|
111
|
+
if (!SCENARIO_LOCATIONS.includes(region)) {
|
|
112
|
+
usage(t.regionInvalid(region));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
entry.locations = regions;
|
|
116
|
+
}
|
|
117
|
+
return entry;
|
|
118
|
+
}
|
|
119
|
+
/** A URL is an HTTP check, an address literal a ping; anything else is asked. */
|
|
120
|
+
function guessProtocol(host) {
|
|
121
|
+
if (!host)
|
|
122
|
+
return 'heartbeat';
|
|
123
|
+
if (/^https?:\/\//i.test(host.trim()))
|
|
124
|
+
return 'http';
|
|
125
|
+
if (isIP(host.trim().replace(/^\[|\]$/g, '')))
|
|
126
|
+
return 'ping';
|
|
127
|
+
return usage(t.addProtocolNeeded(host));
|
|
128
|
+
}
|
|
129
|
+
/** Where the API puts a server without `project_id`: the oldest project. */
|
|
130
|
+
async function defaultProject(client) {
|
|
131
|
+
const projects = await client.call({
|
|
132
|
+
method: 'GET',
|
|
133
|
+
path: '/v1/projects',
|
|
134
|
+
});
|
|
135
|
+
return Math.min(...projects.map((project) => project.id));
|
|
136
|
+
}
|
|
137
|
+
function integer(flag, raw) {
|
|
138
|
+
const value = Number(raw);
|
|
139
|
+
if (!Number.isInteger(value))
|
|
140
|
+
usage(`${flag}: ${t.numberInvalid(raw)}`);
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
function list(raw) {
|
|
144
|
+
return raw
|
|
145
|
+
.split(',')
|
|
146
|
+
.map((item) => item.trim())
|
|
147
|
+
.filter(Boolean);
|
|
148
|
+
}
|
|
149
|
+
function usage(message) {
|
|
150
|
+
throw new CliError(message, ExitCode.Usage);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=servers-add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servers-add.js","sourceRoot":"","sources":["../../src/commands/servers-add.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { authedClient, globalOptions } from '../context.js';
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { formatTime, printJson, printLine, printTable } from '../output.js';
|
|
4
|
+
import { parseWhen } from './incidents.js';
|
|
5
|
+
import { parseId } from './servers.js';
|
|
6
|
+
/**
|
|
7
|
+
* Checks of a server as the panel's chart gets them: points over the
|
|
8
|
+
* period, each with the status and latency per location. Longer periods
|
|
9
|
+
* come aggregated into time buckets by the API.
|
|
10
|
+
*/
|
|
11
|
+
export function registerServersChecks(servers) {
|
|
12
|
+
servers
|
|
13
|
+
.command('checks')
|
|
14
|
+
.description(t.cmdServersChecks)
|
|
15
|
+
.argument('<id>', 'id', parseId)
|
|
16
|
+
.option('--since <when>', t.optChecksSince)
|
|
17
|
+
.option('--until <when>', t.optChecksUntil)
|
|
18
|
+
.action(async (id, opts, command) => {
|
|
19
|
+
const query = {
|
|
20
|
+
startDate: opts.since ? parseWhen(opts.since) : undefined,
|
|
21
|
+
endDate: opts.until ? parseWhen(opts.until) : undefined,
|
|
22
|
+
};
|
|
23
|
+
const { client } = await authedClient(command);
|
|
24
|
+
const groups = await client.call({
|
|
25
|
+
method: 'GET',
|
|
26
|
+
path: `/v1/servers/${id}/checks`,
|
|
27
|
+
query,
|
|
28
|
+
});
|
|
29
|
+
if (globalOptions(command).json) {
|
|
30
|
+
printJson(groups);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// For a day the API adds the last raw checks (`raw:…`) on top of the
|
|
34
|
+
// aggregated points, so the panel's chart keeps moving between them;
|
|
35
|
+
// in a table they repeat the points next to them.
|
|
36
|
+
const points = groups.some((g) => !g.group_id.startsWith('raw:'))
|
|
37
|
+
? groups.filter((g) => !g.group_id.startsWith('raw:'))
|
|
38
|
+
: groups;
|
|
39
|
+
if (!points.length) {
|
|
40
|
+
printLine(t.checksEmpty);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
printTable([t.colTime, t.colStatus, t.colLocations], points.map((group) => [
|
|
44
|
+
formatTime(group.group_checked_at),
|
|
45
|
+
group.locations.some((l) => l.status === 'offline')
|
|
46
|
+
? 'offline'
|
|
47
|
+
: 'online',
|
|
48
|
+
group.locations
|
|
49
|
+
.map((l) => l.status === 'online'
|
|
50
|
+
? `${l.location} ${Math.round(l.latency)} ms`
|
|
51
|
+
: `${l.location} ${l.status}`)
|
|
52
|
+
.join(', '),
|
|
53
|
+
]));
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=servers-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servers-checks.js","sourceRoot":"","sources":["../../src/commands/servers-checks.ts"],"names":[],"mappings":"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"}
|