@inquir/compute-cli 0.3.0 → 0.4.1
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/README.md +528 -406
- package/dist/commands/admin-tenants.d.ts +11 -0
- package/dist/commands/admin-tenants.d.ts.map +1 -0
- package/dist/commands/admin-tenants.js +318 -0
- package/dist/commands/admin-tenants.js.map +1 -0
- package/dist/commands/admin.d.ts +2 -0
- package/dist/commands/admin.d.ts.map +1 -0
- package/dist/commands/admin.js +445 -0
- package/dist/commands/admin.js.map +1 -0
- package/dist/commands/apps-describe.d.ts +9 -0
- package/dist/commands/apps-describe.d.ts.map +1 -0
- package/dist/commands/apps-describe.js +125 -0
- package/dist/commands/apps-describe.js.map +1 -0
- package/dist/commands/apps-instances.d.ts +18 -0
- package/dist/commands/apps-instances.d.ts.map +1 -0
- package/dist/commands/apps-instances.js +87 -0
- package/dist/commands/apps-instances.js.map +1 -0
- package/dist/commands/apps-observability.d.ts +15 -0
- package/dist/commands/apps-observability.d.ts.map +1 -0
- package/dist/commands/apps-observability.js +310 -0
- package/dist/commands/apps-observability.js.map +1 -0
- package/dist/commands/apps-promote.d.ts +31 -0
- package/dist/commands/apps-promote.d.ts.map +1 -0
- package/dist/commands/apps-promote.js +115 -0
- package/dist/commands/apps-promote.js.map +1 -0
- package/dist/commands/apps-resources.d.ts +6 -0
- package/dist/commands/apps-resources.d.ts.map +1 -0
- package/dist/commands/apps-resources.js +107 -0
- package/dist/commands/apps-resources.js.map +1 -0
- package/dist/commands/apps.d.ts +118 -2
- package/dist/commands/apps.d.ts.map +1 -1
- package/dist/commands/apps.js +999 -110
- package/dist/commands/apps.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +7 -3
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +10 -2
- package/dist/commands/delete.js.map +1 -1
- package/dist/commands/deploy.js +3 -3
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/init.js +15 -15
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +78 -33
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +37 -5
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/mcp.d.ts +13 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +184 -77
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/projects.d.ts.map +1 -1
- package/dist/commands/projects.js +107 -11
- package/dist/commands/projects.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/finite-source-command-client.d.ts +3 -0
- package/dist/lib/finite-source-command-client.d.ts.map +1 -0
- package/dist/lib/finite-source-command-client.js +3 -0
- package/dist/lib/finite-source-command-client.js.map +1 -0
- package/dist/lib/mcp-io.d.ts +23 -0
- package/dist/lib/mcp-io.d.ts.map +1 -0
- package/dist/lib/mcp-io.js +185 -0
- package/dist/lib/mcp-io.js.map +1 -0
- package/dist/lib/mcp-source-commands.d.ts +17 -0
- package/dist/lib/mcp-source-commands.d.ts.map +1 -0
- package/dist/lib/mcp-source-commands.js +345 -0
- package/dist/lib/mcp-source-commands.js.map +1 -0
- package/dist/utils/api.d.ts +39 -14
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/api.js +43 -6
- package/dist/utils/api.js.map +1 -1
- package/dist/utils/apps-presentation.d.ts +8 -1
- package/dist/utils/apps-presentation.d.ts.map +1 -1
- package/dist/utils/apps-presentation.js +35 -1
- package/dist/utils/apps-presentation.js.map +1 -1
- package/dist/utils/auth.d.ts +21 -1
- package/dist/utils/auth.d.ts.map +1 -1
- package/dist/utils/auth.js +119 -22
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/browser.d.ts +12 -0
- package/dist/utils/browser.d.ts.map +1 -1
- package/dist/utils/browser.js +37 -16
- package/dist/utils/browser.js.map +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +41 -0
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/msys-path.d.ts +14 -0
- package/dist/utils/msys-path.d.ts.map +1 -0
- package/dist/utils/msys-path.js +55 -0
- package/dist/utils/msys-path.js.map +1 -0
- package/dist/utils/package-metadata.js +1 -1
- package/dist/utils/project-context.d.ts.map +1 -1
- package/dist/utils/project-context.js +7 -5
- package/dist/utils/project-context.js.map +1 -1
- package/dist/utils/project-lookup.d.ts +10 -0
- package/dist/utils/project-lookup.d.ts.map +1 -0
- package/dist/utils/project-lookup.js +52 -0
- package/dist/utils/project-lookup.js.map +1 -0
- package/dist/utils/source-pack.d.ts +24 -0
- package/dist/utils/source-pack.d.ts.map +1 -0
- package/dist/utils/source-pack.js +63 -0
- package/dist/utils/source-pack.js.map +1 -0
- package/package.json +26 -26
- package/skill/SKILL.md +73 -67
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type AppInstance } from '../sdk.js';
|
|
2
|
+
import { type ApiRequestOptions } from '../utils/api.js';
|
|
3
|
+
export declare const INSTANCES_HELP: Record<string, string[]>;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve `--replica <name|index|allocation>` to one allocation id of the
|
|
6
|
+
* application. A full allocation id is accepted without a lookup, so logs of
|
|
7
|
+
* attempts the instances list no longer holds stay reachable. Anything else
|
|
8
|
+
* must match exactly one listed replica (of `releaseId` when given) or it is
|
|
9
|
+
* a usage error: the server filters by exact id, so a guess would silently
|
|
10
|
+
* stream nothing.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveReplicaAllocationId(applicationId: string, selector: string, options: ApiRequestOptions, scope?: {
|
|
13
|
+
releaseId?: string;
|
|
14
|
+
}): Promise<string>;
|
|
15
|
+
export declare function instanceRows(instances: readonly AppInstance[], now?: number): Array<Record<string, string>>;
|
|
16
|
+
/** `apps instances <app>`: the kubectl get pods analog. */
|
|
17
|
+
export declare function instancesSubcommand(args: string[], positionals: string[], options: ApiRequestOptions): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=apps-instances.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps-instances.d.ts","sourceRoot":"","sources":["../../src/commands/apps-instances.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EAAoD,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAM3G,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAOnD,CAAC;AAKF;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,iBAAiB,EAC1B,KAAK,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACjC,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAYD,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,WAAW,EAAE,EAAE,GAAG,SAAa,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAa/G;AAED,2DAA2D;AAC3D,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1H"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { listAppInstances, matchAppInstance } from '../sdk.js';
|
|
2
|
+
import { createApiClient, requireAuth, resolveApplication } from '../utils/api.js';
|
|
3
|
+
import { readJsonFlag } from '../utils/args.js';
|
|
4
|
+
import { usageError } from '../utils/errors.js';
|
|
5
|
+
import { formatBytes } from '../utils/apps-presentation.js';
|
|
6
|
+
import { formatTable, printInfo, printLine } from '../utils/output.js';
|
|
7
|
+
export const INSTANCES_HELP = {
|
|
8
|
+
instances: [
|
|
9
|
+
'Usage: inquir apps instances <app> [--json]',
|
|
10
|
+
' The application\'s replicas (like pods): name, state, ready, restarts, runner,',
|
|
11
|
+
' region, CPU and memory now. Use a name or a replica index with',
|
|
12
|
+
' apps exec --replica, apps logs --replica and apps log-history --replica.',
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
/** A full allocation id: passed through as is even when the attempt is too old to be listed. */
|
|
16
|
+
const ALLOCATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve `--replica <name|index|allocation>` to one allocation id of the
|
|
19
|
+
* application. A full allocation id is accepted without a lookup, so logs of
|
|
20
|
+
* attempts the instances list no longer holds stay reachable. Anything else
|
|
21
|
+
* must match exactly one listed replica (of `releaseId` when given) or it is
|
|
22
|
+
* a usage error: the server filters by exact id, so a guess would silently
|
|
23
|
+
* stream nothing.
|
|
24
|
+
*/
|
|
25
|
+
export async function resolveReplicaAllocationId(applicationId, selector, options, scope = {}) {
|
|
26
|
+
const value = selector.trim();
|
|
27
|
+
if (!value)
|
|
28
|
+
throw usageError('Missing --replica value', 'inquir apps instances <app>');
|
|
29
|
+
if (ALLOCATION_ID.test(value))
|
|
30
|
+
return value;
|
|
31
|
+
const client = await createApiClient(options);
|
|
32
|
+
const { instances } = await listAppInstances(client, applicationId);
|
|
33
|
+
const candidates = scope.releaseId ? instances.filter((instance) => instance.releaseId === scope.releaseId) : instances;
|
|
34
|
+
const match = matchAppInstance(value, candidates);
|
|
35
|
+
if (match?.allocationId)
|
|
36
|
+
return match.allocationId;
|
|
37
|
+
const names = candidates.filter((instance) => instance.allocationId).map((instance) => instance.name);
|
|
38
|
+
const where = scope.releaseId ? ` of release ${scope.releaseId.slice(0, 8)}` : '';
|
|
39
|
+
throw usageError(`No single replica${where} matches '${value}'${names.length ? ` (replicas: ${names.slice(0, 8).join(', ')})` : ''}; ` +
|
|
40
|
+
'an attempt no longer listed needs its full allocation id', 'inquir apps instances <app>');
|
|
41
|
+
}
|
|
42
|
+
function age(from, now) {
|
|
43
|
+
if (!from)
|
|
44
|
+
return '-';
|
|
45
|
+
const seconds = Math.max(0, Math.round((now - Date.parse(from)) / 1000));
|
|
46
|
+
if (!Number.isFinite(seconds))
|
|
47
|
+
return '-';
|
|
48
|
+
if (seconds < 120)
|
|
49
|
+
return `${seconds}s`;
|
|
50
|
+
if (seconds < 7200)
|
|
51
|
+
return `${Math.round(seconds / 60)}m`;
|
|
52
|
+
if (seconds < 172800)
|
|
53
|
+
return `${Math.round(seconds / 3600)}h`;
|
|
54
|
+
return `${Math.round(seconds / 86400)}d`;
|
|
55
|
+
}
|
|
56
|
+
export function instanceRows(instances, now = Date.now()) {
|
|
57
|
+
return instances.map((instance) => ({
|
|
58
|
+
name: instance.name,
|
|
59
|
+
state: instance.state,
|
|
60
|
+
ready: instance.ready ? 'yes' : 'no',
|
|
61
|
+
restarts: String(instance.restarts),
|
|
62
|
+
runner: instance.runner ? instance.runner.id : '-',
|
|
63
|
+
region: instance.runner?.region ?? '-',
|
|
64
|
+
cpu: instance.usage?.cpuUsedCores == null ? '-' : `${instance.usage.cpuUsedCores.toFixed(2)} vCPU`,
|
|
65
|
+
memory: instance.usage?.memoryWorkingSetBytes == null ? '-' : formatBytes(instance.usage.memoryWorkingSetBytes),
|
|
66
|
+
age: age(instance.readyAt ?? instance.startedAt ?? instance.createdAt, now),
|
|
67
|
+
release: `${instance.releaseId.slice(0, 8)}${instance.production ? '' : ' (not production)'}`,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
/** `apps instances <app>`: the kubectl get pods analog. */
|
|
71
|
+
export async function instancesSubcommand(args, positionals, options) {
|
|
72
|
+
const [identifier, ...extra] = positionals;
|
|
73
|
+
if (!identifier || extra.length > 0)
|
|
74
|
+
throw usageError('Specify one application', 'inquir apps instances <app>');
|
|
75
|
+
await requireAuth(options);
|
|
76
|
+
const app = await resolveApplication(identifier, options);
|
|
77
|
+
const client = await createApiClient(options);
|
|
78
|
+
const result = await listAppInstances(client, app.id);
|
|
79
|
+
if (readJsonFlag(args))
|
|
80
|
+
return printLine(JSON.stringify(result, null, 2));
|
|
81
|
+
if (!result.instances.length) {
|
|
82
|
+
printInfo('No replicas. Deploy a release or scale the application up.');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
printLine(formatTable(instanceRows(result.instances), ['name', 'state', 'ready', 'restarts', 'runner', 'region', 'cpu', 'memory', 'age', 'release']));
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=apps-instances.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps-instances.js","sourceRoot":"","sources":["../../src/commands/apps-instances.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AppObservationRange } from '../sdk.js';
|
|
2
|
+
import { type ApiRequestOptions } from '../utils/api.js';
|
|
3
|
+
export declare const OBSERVATION_VALUE_FLAGS: string[];
|
|
4
|
+
export declare const OBSERVATION_HELP: Record<string, string[]>;
|
|
5
|
+
/**
|
|
6
|
+
* `--since` as a duration back from now: `30m`, `2h`, `1h30m`, `7d`, `1w`
|
|
7
|
+
* (s, m, h, d, w). An ISO 8601 timestamp with a timezone is accepted by
|
|
8
|
+
* observationRange itself and means "from then until now".
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseSinceSpan(raw: string): number;
|
|
11
|
+
export declare function observationRange(args: string[], retentionDays?: number, now?: number): Required<AppObservationRange>;
|
|
12
|
+
export declare function metricsSubcommand(args: string[], positionals: string[], options: ApiRequestOptions): Promise<void>;
|
|
13
|
+
export declare function logHistorySubcommand(args: string[], positionals: string[], options: ApiRequestOptions): Promise<void>;
|
|
14
|
+
export declare function alertsSubcommand(args: string[], positionals: string[], options: ApiRequestOptions): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=apps-observability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps-observability.d.ts","sourceRoot":"","sources":["../../src/commands/apps-observability.ts"],"names":[],"mappings":"AAEA,OAAO,EAIyC,KAAK,mBAAmB,EAEvE,MAAM,WAAW,CAAC;AACnB,OAAO,EAAoD,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAQ3G,eAAO,MAAM,uBAAuB,UAInC,CAAC;AACF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAiCrD,CAAC;AAwBF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBlD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,aAAa,SAAK,EAAE,GAAG,SAAa,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAoBpH;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCxH;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC3H;AAsCD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CvH"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ApiError, createAppAlertRule, deleteAppAlertRule, getAppHttpLogHistory, getAppHttpMetrics, getAppLogHistory, getAppMetrics, listAppAlertIncidents, listAppAlertRules, updateAppAlertRule, } from '../sdk.js';
|
|
4
|
+
import { createApiClient, requireAuth, resolveApplication } from '../utils/api.js';
|
|
5
|
+
import { resolveReplicaAllocationId } from './apps-instances.js';
|
|
6
|
+
import { hasFlag, readFlagValue, readJsonFlag, readWorkspaceDir } from '../utils/args.js';
|
|
7
|
+
import { CliError, ExitCode, usageError } from '../utils/errors.js';
|
|
8
|
+
import { formatBytes } from '../utils/apps-presentation.js';
|
|
9
|
+
import { formatTable, printInfo, printLine, printSuccess } from '../utils/output.js';
|
|
10
|
+
import { redact, registerSecret } from '../utils/redact.js';
|
|
11
|
+
export const OBSERVATION_VALUE_FLAGS = [
|
|
12
|
+
'--since', '--from', '--to', '--release', '--replica', '--allocation-fence',
|
|
13
|
+
'--runner', '--runner-epoch', '--container', '--stream', '--level', '--search',
|
|
14
|
+
'--status', '--file',
|
|
15
|
+
];
|
|
16
|
+
export const OBSERVATION_HELP = {
|
|
17
|
+
metrics: [
|
|
18
|
+
'Usage: inquir apps metrics <app> [--since <duration|ISO>] [--http] [--json]',
|
|
19
|
+
' CPU, RAM, network and disk I/O history by release and replica; --http reads gateway requests.',
|
|
20
|
+
' --since <d> Back from now: 30m, 2h, 1h30m, 7d (default 1h), or an ISO timestamp.',
|
|
21
|
+
' --from <ISO> --to <ISO> Use an explicit window (at most 30 days).',
|
|
22
|
+
' --json All measured points and deployment markers; null means unavailable.',
|
|
23
|
+
],
|
|
24
|
+
'log-history': [
|
|
25
|
+
'Usage: inquir apps log-history <app> [--since <duration|ISO>] [--http] [--json]',
|
|
26
|
+
' Also: inquir apps logs <app> --history [options]',
|
|
27
|
+
' --since <d> Back from now: 30m, 2h, 1h30m, 7d (default 1h), or an ISO',
|
|
28
|
+
' timestamp such as 2026-10-06T15:00:00Z (until now).',
|
|
29
|
+
' --from <ISO> --to <ISO> Fixed window; retain both values when using --cursor.',
|
|
30
|
+
' --limit <n> --cursor <c> One page, newest first (runtime <= 200; HTTP <= 500).',
|
|
31
|
+
' --release <id> Exact release id, including old releases.',
|
|
32
|
+
' --replica <r> Replica name, index or allocation id (apps instances <app>);',
|
|
33
|
+
' --allocation-fence <n> narrows its generation.',
|
|
34
|
+
' --runner <id> --runner-epoch <n> --container <id> Exact runtime identity.',
|
|
35
|
+
' --stream stdout|stderr|system --level trace|debug|info|warn|error|fatal',
|
|
36
|
+
' --search <text> Runtime message search; with --http, literal URL path search.',
|
|
37
|
+
' --status <100..599> HTTP status filter (requires --http).',
|
|
38
|
+
' Runtime retention: 7 days. HTTP retention: 30 days. This command does not follow.',
|
|
39
|
+
],
|
|
40
|
+
alerts: [
|
|
41
|
+
'Usage: inquir apps alerts <app> [list|incidents|create|update <rule-id>|delete <rule-id>]',
|
|
42
|
+
' create / update --file <path|-> JSON input; - reads stdin. Destinations are write-only.',
|
|
43
|
+
' list (default) / incidents Rules or incident delivery status; --json for full output.',
|
|
44
|
+
' incidents --limit <1..100> Number of recent incidents (default 50).',
|
|
45
|
+
' update preserves channels when omitted; channels: [] removes them.',
|
|
46
|
+
' delete disables a rule and resolves its incidents; retained history remains available.',
|
|
47
|
+
' Metrics: cpu_percent, memory_percent, deployment_failed. See the CLI README for rule JSON.',
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
function value(args, flag) {
|
|
51
|
+
const result = readFlagValue(args, flag);
|
|
52
|
+
if (hasFlag(args, flag) && !result?.trim())
|
|
53
|
+
throw usageError(`Missing ${flag} value`);
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
function integer(args, flag, min, max) {
|
|
57
|
+
const raw = value(args, flag);
|
|
58
|
+
if (raw === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
if (!/^\d+$/.test(raw) || Number(raw) < min || Number(raw) > max) {
|
|
61
|
+
throw usageError(`${flag} must be an integer between ${min} and ${max}`);
|
|
62
|
+
}
|
|
63
|
+
return Number(raw);
|
|
64
|
+
}
|
|
65
|
+
function choice(args, flag, choices) {
|
|
66
|
+
const raw = value(args, flag);
|
|
67
|
+
if (raw === undefined)
|
|
68
|
+
return undefined;
|
|
69
|
+
if (!choices.includes(raw))
|
|
70
|
+
throw usageError(`${flag} must be ${choices.join(', ')}`);
|
|
71
|
+
return raw;
|
|
72
|
+
}
|
|
73
|
+
const ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T.+(?:Z|[+-]\d{2}:\d{2})$/;
|
|
74
|
+
const SPAN_UNIT_MS = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000 };
|
|
75
|
+
/**
|
|
76
|
+
* `--since` as a duration back from now: `30m`, `2h`, `1h30m`, `7d`, `1w`
|
|
77
|
+
* (s, m, h, d, w). An ISO 8601 timestamp with a timezone is accepted by
|
|
78
|
+
* observationRange itself and means "from then until now".
|
|
79
|
+
*/
|
|
80
|
+
export function parseSinceSpan(raw) {
|
|
81
|
+
const component = /(\d+)([smhdw])/gy;
|
|
82
|
+
let position = 0;
|
|
83
|
+
let span = 0;
|
|
84
|
+
while (position < raw.length) {
|
|
85
|
+
component.lastIndex = position;
|
|
86
|
+
const match = component.exec(raw);
|
|
87
|
+
if (!match) {
|
|
88
|
+
throw usageError(`Invalid --since '${raw}'`, 'Use a duration such as 30m, 2h, 1h30m or 7d, or an ISO 8601 timestamp such as 2026-10-06T15:00:00Z');
|
|
89
|
+
}
|
|
90
|
+
span += Number(match[1]) * SPAN_UNIT_MS[match[2]];
|
|
91
|
+
position = component.lastIndex;
|
|
92
|
+
}
|
|
93
|
+
if (raw.length === 0 || span <= 0) {
|
|
94
|
+
throw usageError(`Invalid --since '${raw}'`, 'Use a duration such as 30m, 2h, 1h30m or 7d');
|
|
95
|
+
}
|
|
96
|
+
return span;
|
|
97
|
+
}
|
|
98
|
+
export function observationRange(args, retentionDays = 30, now = Date.now()) {
|
|
99
|
+
const since = value(args, '--since');
|
|
100
|
+
const from = value(args, '--from');
|
|
101
|
+
const to = value(args, '--to');
|
|
102
|
+
if (since && (from || to))
|
|
103
|
+
throw usageError('Use --since or --from/--to, not both');
|
|
104
|
+
if (hasFlag(args, '--cursor') && (!from || !to)) {
|
|
105
|
+
throw usageError('--cursor requires the original --from and --to values');
|
|
106
|
+
}
|
|
107
|
+
const parse = (raw) => {
|
|
108
|
+
if (!ISO_TIMESTAMP.test(raw) || !Number.isFinite(Date.parse(raw))) {
|
|
109
|
+
throw usageError('Dates must be ISO 8601 timestamps with a timezone');
|
|
110
|
+
}
|
|
111
|
+
return Date.parse(raw);
|
|
112
|
+
};
|
|
113
|
+
const end = to ? parse(to) : now;
|
|
114
|
+
const start = from ? parse(from) : since && ISO_TIMESTAMP.test(since) ? parse(since) : end - parseSinceSpan(since ?? '1h');
|
|
115
|
+
if (start >= end || end - start > retentionDays * 86_400_000 || end > now + 5000 || end < now - retentionDays * 86_400_000) {
|
|
116
|
+
throw usageError(`Choose a window of at most ${retentionDays} days within retained history`);
|
|
117
|
+
}
|
|
118
|
+
return { from: new Date(start).toISOString(), to: new Date(end).toISOString() };
|
|
119
|
+
}
|
|
120
|
+
export async function metricsSubcommand(args, positionals, options) {
|
|
121
|
+
const [identifier] = positionals;
|
|
122
|
+
if (!identifier || positionals.length > 1)
|
|
123
|
+
throw usageError('Specify one application', 'inquir apps metrics <app>');
|
|
124
|
+
const range = observationRange(args);
|
|
125
|
+
await requireAuth(options);
|
|
126
|
+
const app = await resolveApplication(identifier, options);
|
|
127
|
+
const client = await createApiClient(options);
|
|
128
|
+
if (hasFlag(args, '--http')) {
|
|
129
|
+
const result = await getAppHttpMetrics(client, app.id, range);
|
|
130
|
+
if (readJsonFlag(args))
|
|
131
|
+
return printLine(JSON.stringify(result, null, 2));
|
|
132
|
+
printInfo(`HTTP metrics: ${result.from} to ${result.to} (${result.status})`);
|
|
133
|
+
printLine(formatTable(result.points.map(point => ({
|
|
134
|
+
time: point.timestamp, requests: point.requests, '5xx': point.serverErrors,
|
|
135
|
+
'error %': point.errorRate.toFixed(2), 'p95 ms': point.latencyP95Ms.toFixed(2),
|
|
136
|
+
bytes: formatBytes(point.responseBytes),
|
|
137
|
+
})), ['time', 'requests', '5xx', 'error %', 'p95 ms', 'bytes']));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const result = await getAppMetrics(client, app.id, range);
|
|
141
|
+
if (readJsonFlag(args))
|
|
142
|
+
return printLine(JSON.stringify(result, null, 2));
|
|
143
|
+
const number = (input) => input === null ? 'unavailable' : input.toFixed(2);
|
|
144
|
+
printInfo(`Resource metrics: ${result.from} to ${result.to} (${result.status}); latest point per replica`);
|
|
145
|
+
printLine(formatTable(result.series.flatMap(series => {
|
|
146
|
+
const point = series.points.at(-1);
|
|
147
|
+
return point ? [{ release: series.releaseId, replica: series.allocationId ?? series.containerId,
|
|
148
|
+
time: point.sampledAt, 'CPU %': number(point.cpuPercent), 'RAM %': number(point.memoryPercent),
|
|
149
|
+
RAM: point.memoryWorkingSetBytes === null ? 'unavailable' : formatBytes(point.memoryWorkingSetBytes),
|
|
150
|
+
'RX B/s': number(point.networkRxBytesPerSecond), 'TX B/s': number(point.networkTxBytesPerSecond),
|
|
151
|
+
'read B/s': number(point.blockReadBytesPerSecond), 'write B/s': number(point.blockWriteBytesPerSecond),
|
|
152
|
+
}] : [];
|
|
153
|
+
}), ['release', 'replica', 'time', 'CPU %', 'RAM %', 'RAM', 'RX B/s', 'TX B/s', 'read B/s', 'write B/s']));
|
|
154
|
+
if (result.truncated)
|
|
155
|
+
printInfo('The server truncated this range. Narrow --from/--to for complete history.');
|
|
156
|
+
}
|
|
157
|
+
export async function logHistorySubcommand(args, positionals, options) {
|
|
158
|
+
const [identifier] = positionals;
|
|
159
|
+
if (!identifier || positionals.length > 1)
|
|
160
|
+
throw usageError('Specify one application', 'inquir apps log-history <app>');
|
|
161
|
+
if (hasFlag(args, '--follow') || hasFlag(args, '--tail'))
|
|
162
|
+
throw usageError('History is paginated; use apps logs <app> for a live stream');
|
|
163
|
+
const http = hasFlag(args, '--http');
|
|
164
|
+
const range = observationRange(args, http ? 30 : 7);
|
|
165
|
+
const common = { ...range, limit: integer(args, '--limit', 1, http ? 500 : 200) ?? 100,
|
|
166
|
+
cursor: value(args, '--cursor'), releaseId: value(args, '--release') };
|
|
167
|
+
const runtimeFlags = ['--replica', '--allocation-fence', '--runner', '--runner-epoch', '--container', '--stream', '--level'];
|
|
168
|
+
if (http && runtimeFlags.some(flag => hasFlag(args, flag)))
|
|
169
|
+
throw usageError('Replica, stream and level filters apply to runtime logs only');
|
|
170
|
+
if (!http && hasFlag(args, '--status'))
|
|
171
|
+
throw usageError('--status requires --http');
|
|
172
|
+
const runtimeQuery = http ? common : {
|
|
173
|
+
...common, allocationId: value(args, '--replica'), allocationFence: integer(args, '--allocation-fence', 1, Number.MAX_SAFE_INTEGER),
|
|
174
|
+
runnerId: value(args, '--runner'), runnerEpoch: integer(args, '--runner-epoch', 0, Number.MAX_SAFE_INTEGER),
|
|
175
|
+
containerId: value(args, '--container'), stream: choice(args, '--stream', ['stdout', 'stderr', 'system']),
|
|
176
|
+
level: choice(args, '--level', ['trace', 'debug', 'info', 'warn', 'error', 'fatal']), search: value(args, '--search'),
|
|
177
|
+
};
|
|
178
|
+
if (runtimeQuery.containerId && !/^[a-f0-9]{64}$/.test(runtimeQuery.containerId))
|
|
179
|
+
throw usageError('--container requires the full 64-character container id');
|
|
180
|
+
const search = value(args, '--search');
|
|
181
|
+
if ((search?.length ?? 0) > 200)
|
|
182
|
+
throw usageError('--search must contain at most 200 characters');
|
|
183
|
+
const statusCode = integer(args, '--status', 100, 599);
|
|
184
|
+
await requireAuth(options);
|
|
185
|
+
const app = await resolveApplication(identifier, options);
|
|
186
|
+
if (!http && runtimeQuery.allocationId) {
|
|
187
|
+
runtimeQuery.allocationId = await resolveReplicaAllocationId(app.id, runtimeQuery.allocationId, options, runtimeQuery.releaseId ? { releaseId: runtimeQuery.releaseId } : {});
|
|
188
|
+
}
|
|
189
|
+
const client = await createApiClient(options);
|
|
190
|
+
const result = http
|
|
191
|
+
? await getAppHttpLogHistory(client, app.id, { ...common, query: search, statusCode })
|
|
192
|
+
: await getAppLogHistory(client, app.id, runtimeQuery);
|
|
193
|
+
if (readJsonFlag(args))
|
|
194
|
+
return printLine(redact(JSON.stringify(result, null, 2)));
|
|
195
|
+
for (const entry of result.entries) {
|
|
196
|
+
printLine('message' in entry
|
|
197
|
+
? `${entry.occurredAt} ${entry.releaseId} ${entry.allocationId ?? entry.containerId} ${entry.stream} ${entry.message}`
|
|
198
|
+
: `${entry.occurredAt} ${entry.statusCode} ${entry.method} ${entry.path} ${entry.durationMs.toFixed(2)}ms`);
|
|
199
|
+
}
|
|
200
|
+
if (!result.entries.length)
|
|
201
|
+
printInfo('No logs in this window.');
|
|
202
|
+
if (result.nextCursor)
|
|
203
|
+
printInfo(`Older page: --from ${result.from} --to ${result.to} --cursor ${result.nextCursor} (keep the same filters)`);
|
|
204
|
+
}
|
|
205
|
+
async function readRuleInput(args) {
|
|
206
|
+
const filename = value(args, '--file');
|
|
207
|
+
if (!filename)
|
|
208
|
+
throw usageError('Provide rule JSON with --file <path|->');
|
|
209
|
+
const maxBytes = 64 * 1024;
|
|
210
|
+
let raw;
|
|
211
|
+
if (filename === '-') {
|
|
212
|
+
const parts = [];
|
|
213
|
+
let bytes = 0;
|
|
214
|
+
for await (const chunk of process.stdin) {
|
|
215
|
+
const part = Buffer.from(chunk);
|
|
216
|
+
bytes += part.length;
|
|
217
|
+
if (bytes > maxBytes)
|
|
218
|
+
throw usageError('Rule JSON must be at most 64 KiB');
|
|
219
|
+
parts.push(part);
|
|
220
|
+
}
|
|
221
|
+
raw = Buffer.concat(parts).toString('utf8');
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
try {
|
|
225
|
+
raw = await readFile(path.resolve(readWorkspaceDir(args), filename), 'utf8');
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
throw usageError('Cannot read the rule JSON file');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (Buffer.byteLength(raw) > maxBytes)
|
|
232
|
+
throw usageError('Rule JSON must be at most 64 KiB');
|
|
233
|
+
let data;
|
|
234
|
+
try {
|
|
235
|
+
data = JSON.parse(raw);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
throw usageError('Rule file must contain valid JSON');
|
|
239
|
+
}
|
|
240
|
+
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
241
|
+
throw usageError('Rule JSON must be an object');
|
|
242
|
+
const input = data;
|
|
243
|
+
if (Array.isArray(input.channels))
|
|
244
|
+
for (const channel of input.channels) {
|
|
245
|
+
if (channel && typeof channel.url === 'string')
|
|
246
|
+
registerSecret(channel.url);
|
|
247
|
+
}
|
|
248
|
+
return input;
|
|
249
|
+
}
|
|
250
|
+
/** Extra fields from a server/proxy must never echo a write-only channel URL. */
|
|
251
|
+
function safeRule(rule) {
|
|
252
|
+
return { ...rule, channels: rule.channels.map(channel => ({ id: channel.id, type: channel.type, configured: true })) };
|
|
253
|
+
}
|
|
254
|
+
export async function alertsSubcommand(args, positionals, options) {
|
|
255
|
+
const [identifier, action = 'list', ruleId] = positionals;
|
|
256
|
+
if (!identifier || positionals.length > 3)
|
|
257
|
+
throw usageError('Specify an application and alert action', 'inquir apps alerts <app> --help');
|
|
258
|
+
if (!['list', 'incidents', 'create', 'update', 'delete'].includes(action))
|
|
259
|
+
throw usageError('Unknown alert action', 'inquir apps alerts <app> --help');
|
|
260
|
+
if (['update', 'delete'].includes(action) !== Boolean(ruleId))
|
|
261
|
+
throw usageError('Only update and delete require a rule id');
|
|
262
|
+
if (!['create', 'update'].includes(action) && hasFlag(args, '--file'))
|
|
263
|
+
throw usageError('--file applies to create or update only');
|
|
264
|
+
const limit = integer(args, '--limit', 1, 100);
|
|
265
|
+
const input = ['create', 'update'].includes(action) ? await readRuleInput(args) : undefined;
|
|
266
|
+
await requireAuth(options);
|
|
267
|
+
const app = await resolveApplication(identifier, options);
|
|
268
|
+
const client = await createApiClient(options);
|
|
269
|
+
try {
|
|
270
|
+
if (action === 'delete') {
|
|
271
|
+
await deleteAppAlertRule(client, app.id, ruleId);
|
|
272
|
+
if (readJsonFlag(args))
|
|
273
|
+
printLine(JSON.stringify({ deleted: true, ruleId }));
|
|
274
|
+
else
|
|
275
|
+
printSuccess(`Alert rule ${ruleId} disabled; incident history retained.`);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (action === 'incidents') {
|
|
279
|
+
const response = await listAppAlertIncidents(client, app.id, { limit: limit ?? 50 });
|
|
280
|
+
if (readJsonFlag(args))
|
|
281
|
+
printLine(JSON.stringify(response, null, 2));
|
|
282
|
+
else
|
|
283
|
+
printLine(formatTable(response.incidents.map(incident => ({
|
|
284
|
+
id: incident.id, rule: incident.ruleName, metric: incident.metric, status: incident.status,
|
|
285
|
+
started: incident.startedAt, deliveries: incident.deliveries.map(item => `${item.type}:${item.status}`).join(', '),
|
|
286
|
+
})), ['id', 'rule', 'metric', 'status', 'started', 'deliveries']));
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const response = action === 'create'
|
|
290
|
+
? { rule: safeRule((await createAppAlertRule(client, app.id, input)).rule) }
|
|
291
|
+
: action === 'update'
|
|
292
|
+
? { rule: safeRule((await updateAppAlertRule(client, app.id, ruleId, input)).rule) }
|
|
293
|
+
: { rules: (await listAppAlertRules(client, app.id)).rules.map(safeRule) };
|
|
294
|
+
if (readJsonFlag(args))
|
|
295
|
+
return printLine(redact(JSON.stringify(response, null, 2)));
|
|
296
|
+
const rules = response.rule ? [response.rule] : response.rules;
|
|
297
|
+
printLine(formatTable(rules.map(rule => ({ id: rule.id, name: rule.name, metric: rule.metric,
|
|
298
|
+
threshold: rule.threshold, state: rule.evaluationState, channels: rule.channels.map(item => item.type).join(', ') || 'incidents only',
|
|
299
|
+
})), ['id', 'name', 'metric', 'threshold', 'state', 'channels']));
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
// A validation/proxy response can contain submitted webhook credentials. Keep it out of --debug too.
|
|
303
|
+
throw new CliError(error instanceof ApiError ? `Alert request failed (HTTP ${error.status})` : 'Alert request failed', {
|
|
304
|
+
code: error instanceof ApiError ? `HTTP_${error.status}` : 'ALERT_REQUEST_FAILED',
|
|
305
|
+
exitCode: error instanceof ApiError && [401, 403].includes(error.status) ? ExitCode.AUTH : ExitCode.ERROR,
|
|
306
|
+
fix: 'Check workspace access and rule fields. Notification destinations must be public HTTPS URLs.',
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=apps-observability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps-observability.js","sourceRoot":"","sources":["../../src/commands/apps-observability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ApiRequestOptions, type AppRollout, type PromoteAccepted } from '../utils/api.js';
|
|
2
|
+
/**
|
|
3
|
+
* A promote the server runs as a rolling rollout (K2, COMPUTE_ROLLOUT_STRATEGY
|
|
4
|
+
* =enforce) answers 202 and goes on in the background. The CLI follows it the
|
|
5
|
+
* way the old synchronous promote behaved: until production switches to the
|
|
6
|
+
* release (or the rollout ends without switching), printing progress.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PROMOTE_POLL_MS = 2000;
|
|
9
|
+
export interface RolloutWaitOptions {
|
|
10
|
+
intervalMs?: number;
|
|
11
|
+
/** How long to follow it; default: what the rollout's progress deadline allows, plus a minute. */
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
sleep?: (ms: number) => Promise<void>;
|
|
14
|
+
now?: () => number;
|
|
15
|
+
onProgress?: (rollout: AppRollout) => void;
|
|
16
|
+
}
|
|
17
|
+
export type RolloutWaitResult = {
|
|
18
|
+
status: 'switched' | 'ended';
|
|
19
|
+
rollout: AppRollout;
|
|
20
|
+
} | {
|
|
21
|
+
status: 'timeout';
|
|
22
|
+
rollout: AppRollout | undefined;
|
|
23
|
+
};
|
|
24
|
+
/** Polls the rollout until it leaves WARMING: production switched, or the rollout ended before it could. */
|
|
25
|
+
export declare function waitForPromoteRollout(accepted: PromoteAccepted, apiOptions: ApiRequestOptions, options?: RolloutWaitOptions): Promise<RolloutWaitResult>;
|
|
26
|
+
/** `inquir apps promote` once the server answered 202. */
|
|
27
|
+
export declare function followPromoteRollout(releaseId: string, accepted: PromoteAccepted, flags: {
|
|
28
|
+
json: boolean;
|
|
29
|
+
wait: boolean;
|
|
30
|
+
}, apiOptions: ApiRequestOptions, options?: Omit<RolloutWaitOptions, 'onProgress'>): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=apps-promote.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps-promote.d.ts","sourceRoot":"","sources":["../../src/commands/apps-promote.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AAIzB;;;;;GAKG;AAEH,eAAO,MAAM,eAAe,OAAQ,CAAC;AAMrC,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;IAAC,OAAO,EAAE,UAAU,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAAA;CAAE,CAAC;AAY3D,4GAA4G;AAC5G,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,iBAAiB,EAC7B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAoB5B;AAOD,0DAA0D;AAC1D,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,EACvC,UAAU,EAAE,iBAAiB,EAC7B,OAAO,GAAE,IAAI,CAAC,kBAAkB,EAAE,YAAY,CAAM,GACnD,OAAO,CAAC,IAAI,CAAC,CAyDf"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { getApplicationRollout, } from '../utils/api.js';
|
|
2
|
+
import { ExitCode } from '../utils/errors.js';
|
|
3
|
+
import { dim, printError, printInfo, printLine, printSuccess } from '../utils/output.js';
|
|
4
|
+
/**
|
|
5
|
+
* A promote the server runs as a rolling rollout (K2, COMPUTE_ROLLOUT_STRATEGY
|
|
6
|
+
* =enforce) answers 202 and goes on in the background. The CLI follows it the
|
|
7
|
+
* way the old synchronous promote behaved: until production switches to the
|
|
8
|
+
* release (or the rollout ends without switching), printing progress.
|
|
9
|
+
*/
|
|
10
|
+
export const PROMOTE_POLL_MS = 2_000;
|
|
11
|
+
/** Consecutive failed polls (network, a proxy 502) tolerated before giving up. */
|
|
12
|
+
const MAX_POLL_FAILURES = 5;
|
|
13
|
+
/** When the 202 carries no figures to bound the wait by. */
|
|
14
|
+
const FALLBACK_WAIT_MS = 2 * 60 * 60_000;
|
|
15
|
+
/**
|
|
16
|
+
* The longest a rollout can stay before its switch: its progress deadline
|
|
17
|
+
* restarts with every replica that comes up, at most once per replica.
|
|
18
|
+
*/
|
|
19
|
+
function defaultTimeoutMs(accepted) {
|
|
20
|
+
const figures = accepted.rollout;
|
|
21
|
+
if (!figures)
|
|
22
|
+
return FALLBACK_WAIT_MS;
|
|
23
|
+
return (Math.max(1, figures.desiredReplicas) + 1) * figures.progressDeadlineSeconds * 1000 + 60_000;
|
|
24
|
+
}
|
|
25
|
+
/** Polls the rollout until it leaves WARMING: production switched, or the rollout ended before it could. */
|
|
26
|
+
export async function waitForPromoteRollout(accepted, apiOptions, options = {}) {
|
|
27
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
28
|
+
const now = options.now ?? Date.now;
|
|
29
|
+
const deadline = now() + (options.timeoutMs ?? defaultTimeoutMs(accepted));
|
|
30
|
+
let latest = accepted.rollout;
|
|
31
|
+
let failures = 0;
|
|
32
|
+
for (;;) {
|
|
33
|
+
try {
|
|
34
|
+
latest = await getApplicationRollout(accepted.applicationId, accepted.rolloutId, apiOptions);
|
|
35
|
+
failures = 0;
|
|
36
|
+
options.onProgress?.(latest);
|
|
37
|
+
if (latest.phase !== 'WARMING') {
|
|
38
|
+
return { status: latest.flippedAt && latest.phase !== 'ROLLED_BACK' ? 'switched' : 'ended', rollout: latest };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (++failures >= MAX_POLL_FAILURES)
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
if (now() >= deadline)
|
|
46
|
+
return { status: 'timeout', rollout: latest };
|
|
47
|
+
await sleep(options.intervalMs ?? PROMOTE_POLL_MS);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function progressLine(rollout) {
|
|
51
|
+
return ` ${rollout.observedHealthy} of ${rollout.desiredReplicas} replicas serve; ` +
|
|
52
|
+
`production switches at ${rollout.flipAtReplicas}`;
|
|
53
|
+
}
|
|
54
|
+
/** `inquir apps promote` once the server answered 202. */
|
|
55
|
+
export async function followPromoteRollout(releaseId, accepted, flags, apiOptions, options = {}) {
|
|
56
|
+
const short = releaseId.slice(0, 8);
|
|
57
|
+
if (!flags.wait) {
|
|
58
|
+
if (flags.json) {
|
|
59
|
+
printLine(JSON.stringify(accepted, null, 2));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
printInfo(`Rolling out ${short}: production switches once enough replicas serve`);
|
|
63
|
+
printInfo(dim(` it goes on on the server; follow it: GET ${accepted.pollUrl}`));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!flags.json) {
|
|
67
|
+
printInfo(`Rolling out ${short}: production switches once enough replicas serve`);
|
|
68
|
+
if (accepted.rollout)
|
|
69
|
+
printInfo(dim(progressLine(accepted.rollout)));
|
|
70
|
+
}
|
|
71
|
+
let shown = accepted.rollout?.observedHealthy ?? -1;
|
|
72
|
+
const result = await waitForPromoteRollout(accepted, apiOptions, {
|
|
73
|
+
...options,
|
|
74
|
+
onProgress: (rollout) => {
|
|
75
|
+
if (flags.json || rollout.phase !== 'WARMING' || rollout.observedHealthy === shown)
|
|
76
|
+
return;
|
|
77
|
+
shown = rollout.observedHealthy;
|
|
78
|
+
printInfo(dim(progressLine(rollout)));
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
if (flags.json) {
|
|
82
|
+
printLine(JSON.stringify({ ...accepted, status: result.rollout?.phase ?? accepted.status, rollout: result.rollout ?? null,
|
|
83
|
+
servingProduction: result.status === 'switched' }, null, 2));
|
|
84
|
+
if (result.status !== 'switched')
|
|
85
|
+
process.exitCode = ExitCode.ERROR;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (result.status === 'timeout') {
|
|
89
|
+
printError(`Release ${short} has not taken production yet; the CLI stopped waiting, the rollout goes on. ` +
|
|
90
|
+
`Follow it: GET ${accepted.pollUrl}`);
|
|
91
|
+
process.exitCode = ExitCode.ERROR;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const { rollout } = result;
|
|
95
|
+
if (result.status === 'ended') {
|
|
96
|
+
printError(`Rollout ${rollout.phase.toLowerCase().replace('_', ' ')}: ${rollout.reason ?? 'production did not switch'}`);
|
|
97
|
+
process.exitCode = ExitCode.ERROR;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
printSuccess(`Production now serves ${short}`);
|
|
101
|
+
if (rollout.phase === 'PROGRESSING') {
|
|
102
|
+
printInfo(dim(` ${rollout.observedHealthy} of ${rollout.desiredReplicas} replicas serve; the rest roll out in the background`));
|
|
103
|
+
}
|
|
104
|
+
if (rollout.predecessorReleaseId && rollout.phase !== 'COMPLETE') {
|
|
105
|
+
printInfo(dim(` previous release ${rollout.predecessorReleaseId.slice(0, 8)} is kept running as the rollback until then`));
|
|
106
|
+
}
|
|
107
|
+
else if (rollout.predecessorReleaseId) {
|
|
108
|
+
printInfo(dim(` previous release ${rollout.predecessorReleaseId.slice(0, 8)} kept for rollback`));
|
|
109
|
+
}
|
|
110
|
+
if (rollout.phase === 'FAILED') {
|
|
111
|
+
printError(` ${rollout.reason ?? 'the rollout stopped making progress'}`);
|
|
112
|
+
process.exitCode = ExitCode.ERROR;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=apps-promote.js.map
|