@serve.zone/interfaces 32.68.0 → 32.70.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.
@@ -1,4 +1,5 @@
1
1
  import { type IProtocolOffer } from '../protocol.js';
2
+ import type { TNodeActionName } from './clusternode.js';
2
3
  /** Host observations only. Container and workload readiness belong to Pallet. */
3
4
  export interface ISparkNodeReport {
4
5
  observedAt: number;
@@ -27,6 +28,24 @@ export interface ISparkNodeReport {
27
28
  * it made one since it started. Whether the node carries the hostname is `runtime.hostname`.
28
29
  */
29
30
  hostApply?: ISparkNodeHostApply;
31
+ /**
32
+ * The host's boot, stated by a Spark that executes node actions: how Cloudly verifies an action
33
+ * that reboots (`nodeActionVerification`) and whether the host waits for a reboot.
34
+ */
35
+ boot?: ISparkNodeBoot;
36
+ /**
37
+ * The node actions this Spark executes (`sparkNodeActionContracts`), in canonical order. Cloudly
38
+ * admits a node runtime action only for a node whose report states its executor, so an action
39
+ * Spark cannot execute is refused when it is requested rather than left to expire.
40
+ */
41
+ actionExecutors?: TNodeActionName[];
42
+ }
43
+ /** One boot of the host. */
44
+ export interface ISparkNodeBoot {
45
+ /** The kernel's `boot_id` (`/proc/sys/kernel/random/boot_id`), a lowercase UUID; it changes with every boot. */
46
+ id: string;
47
+ /** Whether the host states that a package it installed waits for a reboot (`/var/run/reboot-required`). */
48
+ rebootRequired: boolean;
30
49
  }
31
50
  /** Whether Spark applied a desired hostname: `applied` once the host carries it. */
32
51
  export type TSparkNodeHostApplyOutcome = 'applied' | 'failed';
@@ -3,6 +3,7 @@ import { readDataProperties, readExactDataRecord } from '../private/dataproperti
3
3
  import { isClusterNodeId } from '../private/nodeidentifier.js';
4
4
  import { protocolRefusalHttpStatus, readProtocolOffer } from '../protocol.js';
5
5
  import { isClusterNodeHostname } from './clusternodehostname.js';
6
+ import { isHostBootId, isNodeActionNameList } from './nodeaction.js';
6
7
  /** Bounds of `ISparkNodeHostApply.reason`. */
7
8
  export const sparkNodeHostApplyContract = Object.freeze({
8
9
  maximumReasonLength: 512,
@@ -72,8 +73,10 @@ export const snapshotSparkNodeReport = (valueArg) => {
72
73
  const reportKeys = ['observedAt', 'metrics', 'runtime'];
73
74
  const properties = readDataProperties(valueArg);
74
75
  requireValue(properties !== null);
75
- const hasHostApply = Object.hasOwn(properties, 'hostApply');
76
- const value = record(valueArg, hasHostApply ? [...reportKeys, 'hostApply'] : reportKeys);
76
+ // Each optional member is read exactly when the report states it, so a report without them is
77
+ // the report an earlier Spark sends and is read the way an earlier reader read it.
78
+ const optionalKeys = ['hostApply', 'boot', 'actionExecutors'].filter((keyArg) => Object.hasOwn(properties, keyArg));
79
+ const value = record(valueArg, [...reportKeys, ...optionalKeys]);
77
80
  const metrics = record(value.metrics, ['cpuUsagePercent', 'memoryUsedMB', 'memoryAvailableMB',
78
81
  'diskUsedGB', 'diskAvailableGB']);
79
82
  const runtime = record(value.runtime, ['hostname', 'platform', 'arch', 'osRelease', 'bundle',
@@ -100,9 +103,23 @@ export const snapshotSparkNodeReport = (valueArg) => {
100
103
  }),
101
104
  localRuntimeReady: true, workloadReadiness: 'unverified',
102
105
  }),
103
- ...(hasHostApply ? { hostApply: snapshotSparkNodeHostApply(value.hostApply) } : {}),
106
+ ...(optionalKeys.includes('hostApply') ? { hostApply: snapshotSparkNodeHostApply(value.hostApply) } : {}),
107
+ ...(optionalKeys.includes('boot') ? { boot: snapshotSparkNodeBoot(value.boot) } : {}),
108
+ ...(optionalKeys.includes('actionExecutors')
109
+ ? { actionExecutors: snapshotActionExecutors(value.actionExecutors) } : {}),
104
110
  });
105
111
  };
112
+ /** One `boot`: exactly its keys. */
113
+ const snapshotSparkNodeBoot = (valueArg) => {
114
+ const value = record(valueArg, ['id', 'rebootRequired']);
115
+ requireValue(isHostBootId(value.id) && typeof value.rebootRequired === 'boolean');
116
+ return Object.freeze({ id: value.id, rebootRequired: value.rebootRequired });
117
+ };
118
+ /** One `actionExecutors`: a canonical list of at least one action name, detached and frozen. */
119
+ const snapshotActionExecutors = (valueArg) => {
120
+ requireValue(isNodeActionNameList(valueArg));
121
+ return Object.freeze([...valueArg]);
122
+ };
106
123
  export const snapshotSparkNodeHeartbeatRequest = (valueArg) => {
107
124
  const value = record(valueArg, ['nodeId', 'nodeToken', 'protocol', 'report']);
108
125
  return Object.freeze({
@@ -163,4 +180,4 @@ export const snapshotSparkNodeDesiredHost = (valueArg) => {
163
180
  protocol: readProtocolOffer(value),
164
181
  });
165
182
  };
166
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Bhcmtub2RlcmVwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvZGF0YS9zcGFya25vZGVyZXBvcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQy9ELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxpQkFBaUIsRUFBdUIsTUFBTSxnQkFBZ0IsQ0FBQztBQUNuRyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQTBDakUsOENBQThDO0FBQzlDLE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDdEQsbUJBQW1CLEVBQUUsR0FBRztDQUNoQixDQUFDLENBQUM7QUE0Qlo7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3RELFFBQVEsRUFBRSx3QkFBd0I7SUFDbEMsZUFBZSxFQUFFLElBQUk7SUFDckIsZ0JBQWdCLEVBQUUsSUFBSTtJQUN0QixxQkFBcUIsRUFBRSx5QkFBeUI7Q0FDeEMsQ0FBQyxDQUFDO0FBRVosTUFBTSxJQUFJLEdBQUcsR0FBVSxFQUFFLEdBQUcsTUFBTSxJQUFJLEtBQUssQ0FBQyx5Q0FBeUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzFGLFNBQVMsWUFBWSxDQUFDLFFBQWlCO0lBQ3JDLElBQUksQ0FBQyxRQUFRO1FBQUUsSUFBSSxFQUFFLENBQUM7QUFDeEIsQ0FBQztBQUNELHNHQUFzRztBQUN0RyxNQUFNLE1BQU0sR0FBRyxDQUFDLFFBQWlCLEVBQUUsT0FBMEIsRUFBMkIsRUFBRTtJQUN4RixNQUFN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
183
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Bhcmtub2RlcmVwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvZGF0YS9zcGFya25vZGVyZXBvcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLG1CQUFtQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQy9ELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxpQkFBaUIsRUFBdUIsTUFBTSxnQkFBZ0IsQ0FBQztBQUNuRyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUVqRSxPQUFPLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUE2RHJFLDhDQUE4QztBQUM5QyxNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQ3RELG1CQUFtQixFQUFFLEdBQUc7Q0FDaEIsQ0FBQyxDQUFDO0FBNEJaOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sMEJBQTBCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUN0RCxRQUFRLEVBQUUsd0JBQXdCO0lBQ2xDLGVBQWUsRUFBRSxJQUFJO0lBQ3JCLGdCQUFnQixFQUFFLElBQUk7SUFDdEIscUJBQXFCLEVBQUUseUJBQXlCO0NBQ3hDLENBQUMsQ0FBQztBQUVaLE1BQU0sSUFBSSxHQUFHLEdBQVUsRUFBRSxHQUFHLE1BQU0sSUFBSSxLQUFLLENBQUMseUNBQXlDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUMxRixTQUFTLFlBQVksQ0FBQyxRQUFpQjtJQUNyQyxJQUFJLENBQUMsUUFBUTtRQUFFLElBQUksRUFBRSxDQUFDO0FBQ3hCLENBQUM7QUFDRCxzR0FBc0c7QUFDdEcsTUFB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
@@ -45,6 +45,14 @@ export interface IReq_Any_Cloudly_RestoreServiceBackup extends plugins.typedrequ
45
45
  backupId: string;
46
46
  clear?: boolean;
47
47
  resourceTypes?: Array<TBackupSnapshot['type']>;
48
+ /**
49
+ * Must be `true` to restore a `failed` backup whose failure is `incomplete`, and is refused for
50
+ * any other backup. Such a restore restores what the backup captured: `resourceTypes` is
51
+ * required and names only types it captured, none of the resources it did not capture
52
+ * (`failure.uncaptured`) is restored, so the service then holds data from two points in time,
53
+ * and the backup stays `failed`.
54
+ */
55
+ confirmPartialRestore?: boolean;
48
56
  };
49
57
  response: {
50
58
  backup: IBackupRecord;
@@ -3,6 +3,8 @@ import type { IBareMetal } from '../data/baremetal.js';
3
3
  import type { ICluster } from '../data/cluster.js';
4
4
  import type { IClusterNode, INodeAction, INodeMetricsSample, TNodeActionName } from '../data/clusternode.js';
5
5
  import type { IDeployment } from '../data/deployment.js';
6
+ import type { INodeActionConfirmation, INodeActionPreview } from '../data/nodeaction.js';
7
+ import type { ISparkFleetTarget, ISparkFleetTargetChange, ISparkNodeTargetHold } from '../data/sparkfleettarget.js';
6
8
  import type { IIdentity } from '../data/user.js';
7
9
  import type { IPlatformObjectStorageEndpoint } from '../platform/objectstorage.js';
8
10
  import type { IPlatformDatabaseEndpoint } from '../platform/database.js';
@@ -342,6 +344,18 @@ export interface IReq_Any_Cloudly_ResetClusterNodeHostname extends plugins.typed
342
344
  node: IClusterNode;
343
345
  };
344
346
  }
347
+ /**
348
+ * An administrator requests one action on one node.
349
+ *
350
+ * A node whose Swarm-era daemon reports last receives it as before, in the metrics-sample answer;
351
+ * `confirmation` is not read for it. A node that reports through the node runtime is sent the
352
+ * action only with a `confirmation` (`data.validateNodeActionConfirmation`) of the preview the
353
+ * administrator read (`getNodeActionPreview`): the typed hostname, the impact digest, when the
354
+ * impact names a Corestore on the node the consent to restart it, and for an update the fleet Spark
355
+ * target revision the preview showed. The action then carries
356
+ * `lifecycle`, with the confirmation, the impact and, for an update, the fleet target frozen in it.
357
+ * Every refusal is one of `data.nodeActionRefusals` and changes nothing.
358
+ */
345
359
  export interface IReq_Any_Cloudly_CreateNodeAction extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_CreateNodeAction> {
346
360
  method: 'createNodeAction';
347
361
  request: {
@@ -349,11 +363,97 @@ export interface IReq_Any_Cloudly_CreateNodeAction extends plugins.typedrequestI
349
363
  nodeId: string;
350
364
  actionName: TNodeActionName;
351
365
  payload?: INodeAction['payload'];
366
+ confirmation?: INodeActionConfirmation;
367
+ };
368
+ response: {
369
+ action: INodeAction;
370
+ };
371
+ }
372
+ /**
373
+ * An administrator previews one action on one node that reports through the node runtime: what it
374
+ * interrupts, read from Cloudly's database, the digest a confirmation names, and every reason a
375
+ * request would be refused now. A preview changes nothing.
376
+ */
377
+ export interface IReq_Any_Cloudly_GetNodeActionPreview extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_GetNodeActionPreview> {
378
+ method: 'getNodeActionPreview';
379
+ request: {
380
+ identity: IIdentity;
381
+ nodeId: string;
382
+ actionName: TNodeActionName;
383
+ };
384
+ response: {
385
+ preview: INodeActionPreview;
386
+ };
387
+ }
388
+ /**
389
+ * An administrator withdraws one node runtime action while it is still `pending`, at the revision
390
+ * they read. A claimed action is never withdrawn: Spark may already have stopped the node.
391
+ */
392
+ export interface IReq_Any_Cloudly_CancelNodeAction extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_CancelNodeAction> {
393
+ method: 'cancelNodeAction';
394
+ request: {
395
+ identity: IIdentity;
396
+ nodeId: string;
397
+ actionId: string;
398
+ expectedRevision: number;
352
399
  };
353
400
  response: {
354
401
  action: INodeAction;
355
402
  };
356
403
  }
404
+ /**
405
+ * An administrator reads the fleet Spark target (`data.ISparkFleetTarget`, `null` while there is
406
+ * none), its newest changes and every node hold.
407
+ */
408
+ export interface IReq_Any_Cloudly_GetSparkFleetTarget extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_GetSparkFleetTarget> {
409
+ method: 'getSparkFleetTarget';
410
+ request: {
411
+ identity: IIdentity;
412
+ };
413
+ response: {
414
+ target: ISparkFleetTarget | null;
415
+ /** Newest first, at most `data.sparkFleetTargetContract.historyLimit`. */
416
+ history: ISparkFleetTargetChange[];
417
+ /** Sorted by node id. */
418
+ holds: ISparkNodeTargetHold[];
419
+ };
420
+ }
421
+ /**
422
+ * An administrator sets the fleet Spark target to one release version, at the revision they read
423
+ * (`0` while there is none). Cloudly reads the release's `SHA256SUMS.txt` and `install.sh`, refuses
424
+ * any mismatch between them, and stores the version with the SHA-256 it checked. Every refusal is
425
+ * one of `data.sparkFleetTargetRefusals`.
426
+ */
427
+ export interface IReq_Any_Cloudly_SetSparkFleetTarget extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_SetSparkFleetTarget> {
428
+ method: 'setSparkFleetTarget';
429
+ request: {
430
+ identity: IIdentity;
431
+ /** `data.validateSetSparkFleetTargetInput` judges these two. */
432
+ version: string;
433
+ expectedRevision: number;
434
+ };
435
+ response: {
436
+ target: ISparkFleetTarget;
437
+ };
438
+ }
439
+ /**
440
+ * An administrator holds one node at the release it runs (`hold: { reason }`) or releases it
441
+ * (`hold: null`). Answers the hold as it now stands.
442
+ */
443
+ export interface IReq_Any_Cloudly_SetSparkNodeTargetHold extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_SetSparkNodeTargetHold> {
444
+ method: 'setSparkNodeTargetHold';
445
+ request: {
446
+ identity: IIdentity;
447
+ nodeId: string;
448
+ /** `data.validateSparkNodeTargetHoldInput` judges it. */
449
+ hold: {
450
+ reason: string;
451
+ } | null;
452
+ };
453
+ response: {
454
+ hold: ISparkNodeTargetHold | null;
455
+ };
456
+ }
357
457
  export interface IReq_Any_Cloudly_GetNodeActions extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_GetNodeActions> {
358
458
  method: 'getNodeActions';
359
459
  request: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serve.zone/interfaces",
3
- "version": "32.68.0",
3
+ "version": "32.70.0",
4
4
  "private": false,
5
5
  "description": "Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.",
6
6
  "exports": {
package/readme.md CHANGED
@@ -216,6 +216,53 @@ next heartbeat; the node has converged when `runtime.hostname` states the intent
216
216
  hostname. A Spark that sends `hostApply` raises its `minimumPeerVersion` so it
217
217
  reaches only a Cloudly that reads it.
218
218
 
219
+ ### Node Actions
220
+
221
+ A node action (`INodeAction`: reboot, serve.zone service update, system upgrade)
222
+ that a node runtime executes carries `lifecycle` (`INodeActionLifecycle`): the
223
+ administrator's confirmation (`INodeActionConfirmation`: the typed hostname, the
224
+ digest of the impact preview they read, when the impact names a Corestore on the
225
+ node the consent to restart it, and for an update the fleet Spark target revision
226
+ the preview showed, refused `target-changed` once the target moved), the impact (`INodeActionImpact`), the fleet
227
+ Spark target an update moves the node to, a revision, the current deadline, the
228
+ claim, a failure with its remedy and a timeline. A Swarm-era record carries none of
229
+ it and travels only in the Swarm-era metrics-sample answer. `TNodeActionStatus`
230
+ keeps the four shipped values (`pending` is the requested state) and adds
231
+ `claimed`, `executing`, `draining`, `rebooting`, `verifying`, `expired`,
232
+ `cancelled` and `unverified`; `data.nodeActionStatusKinds` states which are open.
233
+
234
+ `data.sparkNodeActionContracts` defines the node runtime's two action routes,
235
+ authenticated and judged in the heartbeat's order: `offer` (`/spark/nodes/action`)
236
+ answers the node's one open action (`ISparkNodeActionAssignment`) or `null`, and
237
+ `transition` (`/spark/nodes/action/transition`) takes one step at the revision the
238
+ assignment states — `claim` with the host's boot id, a forward `phase`
239
+ (`sparkNodeActionPhaseOrder`), `complete` (a host upgrade without a reboot) or
240
+ `fail` with one of `sparkNodeActionFailureCodes` — and answers `applied`,
241
+ `replayed` (the same step again at the same revision) or a named refusal.
242
+ `data.admitsSparkNodeActionTransition` states which step an action admits.
243
+ Cloudly verifies every action from what the node reports
244
+ (`data.nodeActionVerification`): a new `boot.id`, the target bundle version, or a
245
+ completed host upgrade; a heartbeat stating `boot.rebootRequired` after a host
246
+ upgrade fails it `reboot-required` rather than rebooting. A deadline
247
+ (`data.nodeActionCompletionBudgetMs`, `nodeActionContract`) that passes ends an
248
+ action `unverified`.
249
+
250
+ A Spark that executes actions states `ISparkNodeReport.boot` (the kernel boot id
251
+ and whether the host waits for a reboot) and `actionExecutors`, the canonical list
252
+ of action names it executes; Cloudly admits an action only for a node that states
253
+ its executor. Both are optional members an earlier reader refuses, so a Spark sends
254
+ them only to a Cloudly that reads them, like `hostApply`.
255
+
256
+ `data.ISparkFleetTarget` is the one fleet Spark target: a version and the SHA-256
257
+ its release's `SHA256SUMS.txt` states for `install.sh`, with a revision, who set
258
+ it and when, an append-only history (`ISparkFleetTargetChange`) and per-node
259
+ holds (`ISparkNodeTargetHold`). `data.readSparkNodeTargetStanding` places a node
260
+ at, behind or ahead of it, held, unreported or untargeted. The admin requests
261
+ (`getNodeActionPreview`, `createNodeAction` with `confirmation`,
262
+ `cancelNodeAction`, `getSparkFleetTarget`, `setSparkFleetTarget`,
263
+ `setSparkNodeTargetHold`) answer refusals by name from `data.nodeActionRefusals`
264
+ and `data.sparkFleetTargetRefusals`.
265
+
219
266
  The snapshot functions reject unknown keys, accessors, malformed identities and
220
267
  nonfinite/out-of-range numbers, then return detached frozen records. Transports
221
268
  own byte limits, timeouts and cancellation. These contracts do not implement a
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/interfaces',
6
- version: '32.68.0',
6
+ version: '32.70.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  }
package/ts/data/backup.ts CHANGED
@@ -72,10 +72,46 @@ export interface IBackupReplicationResult {
72
72
  completedAt: number;
73
73
  }
74
74
 
75
+ /**
76
+ * One resource a service declares that a backup of it did not capture, with why; each kind of
77
+ * resource has its own reason.
78
+ *
79
+ * `volume-capture-unavailable`: a service volume is a node-local storage claim on its Pallet node,
80
+ * which no relay can capture yet; a `volume` snapshot is a Corestore Docker volume and captures no
81
+ * service volume. `binding-not-snapshotted`: the backup holds no snapshot of the Corestore resource
82
+ * the binding names.
83
+ */
84
+ export type TBackupUncapturedResource =
85
+ | { type: 'volume'; mountPath: string; reason: 'volume-capture-unavailable' }
86
+ | { type: 'database' | 'objectstorage'; bindingId: string; reason: 'binding-not-snapshotted' };
87
+
88
+ /** Why a resource a service declares is not in one of its backups (`TBackupUncapturedResource`). */
89
+ export type TBackupUncapturedReason = TBackupUncapturedResource['reason'];
90
+
91
+ /**
92
+ * The named kind of a `failed` backup's failure; a failure without one is named only in `errorText`.
93
+ *
94
+ * `incomplete`: the backup did not capture every resource its service declares, and `uncaptured`
95
+ * names each one it missed. What it did capture is restored only by a partial restore an
96
+ * administrator confirms (`IReq_Any_Cloudly_RestoreServiceBackup` `confirmPartialRestore`), which
97
+ * restores none of `uncaptured`, and the backup stays `failed`.
98
+ * `archive-unreadable`: its stored archive is missing or damaged, so it restores nothing.
99
+ */
100
+ export type TBackupFailure =
101
+ | { kind: 'incomplete'; uncaptured: TBackupUncapturedResource[] }
102
+ | { kind: 'archive-unreadable' };
103
+
75
104
  export interface IBackupRestoreEvent {
76
105
  restoredAt: number;
77
106
  status: 'restored' | 'failed';
78
107
  errorText?: string;
108
+ /** The resource types the restore was limited to; absent when it restored every snapshot. */
109
+ resourceTypes?: TBackupResourceType[];
110
+ /**
111
+ * A confirmed partial restore of an `incomplete` backup: it restored only `resourceTypes`, and
112
+ * none of the backup's `failure.uncaptured`.
113
+ */
114
+ partial?: true;
79
115
  }
80
116
 
81
117
  /**
@@ -114,6 +150,8 @@ export interface IBackupRecord {
114
150
  completedAt?: number;
115
151
  requestedBy?: string;
116
152
  errorText?: string;
153
+ /** The named kind of a `failed` backup's failure (`TBackupFailure`). */
154
+ failure?: TBackupFailure;
117
155
  restoreHistory?: IBackupRestoreEvent[];
118
156
  /**
119
157
  * Authoritative isolated-restore holds. Cloudly atomically appends the
@@ -124,6 +162,25 @@ export interface IBackupRecord {
124
162
  tags?: Record<string, string>;
125
163
  }
126
164
 
165
+ /**
166
+ * The resource types a partial restore of a backup may name (`confirmPartialRestore`).
167
+ *
168
+ * For a `failed` backup whose failure is `incomplete`: every type it holds a snapshot of, except
169
+ * `volume` (a `volume` snapshot is a Corestore Docker volume and captures no service volume) and the
170
+ * type of any resource it did not capture, so a partial restore never restores a snapshot standing
171
+ * for a resource the backup missed. For every other backup: none. Database before object storage.
172
+ */
173
+ export const readPartialRestoreResourceTypes = (
174
+ backupArg: Pick<IBackupRecord, 'status' | 'failure'> & { snapshots: ReadonlyArray<Pick<TBackupSnapshot, 'type'>> },
175
+ ): Array<Exclude<TBackupResourceType, 'volume'>> => {
176
+ const failure = backupArg.failure;
177
+ if (backupArg.status !== 'failed' || failure?.kind !== 'incomplete') return [];
178
+ const uncapturedTypes = new Set<TBackupResourceType>(failure.uncaptured.map((resourceArg) => resourceArg.type));
179
+ return (['database', 'objectstorage'] as const).filter((typeArg) => (
180
+ !uncapturedTypes.has(typeArg) && backupArg.snapshots.some((snapshotArg) => snapshotArg.type === typeArg)
181
+ ));
182
+ };
183
+
127
184
  /** Retention policy understood by containerarchive prune. */
128
185
  export interface IArchiveRetentionPolicy {
129
186
  keepLast?: number;
@@ -1,6 +1,7 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import { isSha256Digest, type TSha256Digest, type TImmutableContainerPlatform } from './immutableimage.js';
3
3
  import type { ISparkNodeReportRecord } from './sparknodereport.js';
4
+ import type { INodeActionExpiry, INodeActionLifecycle } from './nodeaction.js';
4
5
  import type { IClusterNodeHostnameIntent } from './clusternodehostname.js';
5
6
  import type { IPlatformObjectStorageEndpoint } from '../platform/objectstorage.js';
6
7
  import type { IPlatformDatabaseEndpoint } from '../platform/database.js';
@@ -74,11 +75,21 @@ export interface INodeMetricsSample {
74
75
 
75
76
  export type TNodeActionName = 'systemUpgrade' | 'reboot' | 'serveZoneServiceUpdate';
76
77
 
77
- export type TNodeActionStatus = 'pending' | 'running' | 'succeeded' | 'failed';
78
+ /**
79
+ * Every state of a node action; `nodeActionStatusKinds` states which are open and what each means.
80
+ * The first four are the ones the Swarm-era carrier shipped and keep their meaning.
81
+ */
82
+ export type TNodeActionStatus = 'pending' | 'running' | 'succeeded' | 'failed'
83
+ | 'claimed' | 'executing' | 'draining' | 'rebooting' | 'verifying'
84
+ | 'expired' | 'cancelled' | 'unverified';
78
85
 
79
86
  /**
80
87
  * An operator-requested action executed by spark on a node.
81
- * Delivered to spark in metrics-sample responses; results posted back.
88
+ *
89
+ * A Swarm-era record is delivered to the Swarm-era daemon in metrics-sample responses, which
90
+ * posts results back; it carries no `lifecycle`. A node runtime action carries `lifecycle`: Spark
91
+ * takes it from `sparkNodeActionContracts.offer` and states each step on
92
+ * `sparkNodeActionContracts.transition`, and Cloudly verifies it from the node's reports.
82
93
  */
83
94
  export interface INodeAction {
84
95
  id: string;
@@ -94,6 +105,10 @@ export interface INodeAction {
94
105
  startedAt?: number;
95
106
  finishedAt?: number;
96
107
  resultText?: string;
108
+ /** The node runtime's lifecycle; absent on a Swarm-era record. */
109
+ lifecycle?: INodeActionLifecycle;
110
+ /** Why the action ended `expired`; present exactly then. */
111
+ expiry?: INodeActionExpiry;
97
112
  }
98
113
 
99
114
  export interface IServeZoneServiceRuntimeInfo {
package/ts/data/index.ts CHANGED
@@ -81,6 +81,8 @@ export * from './clusternodehostname.js';
81
81
  export * from './settings.js';
82
82
  export * from './sparklegacyretirement.js';
83
83
  export * from './sparknodereport.js';
84
+ export * from './nodeaction.js';
85
+ export * from './sparkfleettarget.js';
84
86
  export * from './service.js';
85
87
  export * from './servicecredential.js';
86
88
  export * from './serviceplatformownership.js';