@serve.zone/interfaces 32.11.0 → 32.13.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,6 +1,12 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import type { TSha256Digest, TImmutableContainerPlatform } from './immutableimage.js';
3
3
  import type { ISparkNodeReportRecord } from './sparknodereport.js';
4
+ import {
5
+ validateFleetCutoverLocalNodeSnapshot,
6
+ validateFleetCutoverManagerSnapshot,
7
+ type IFleetCutoverLocalNodeSnapshot,
8
+ type IFleetCutoverManagerSnapshot,
9
+ } from './fleetcutover.js';
4
10
  import { protocolRefusalHttpStatus, validateProtocolOfferOn, type IProtocolOffer } from '../protocol.js';
5
11
  import {
6
12
  canonicalizeStrictJson,
@@ -119,13 +125,13 @@ export const sparkSwarmNodeContracts = Object.freeze({
119
125
  maxResponseBytes: 2048,
120
126
  } as const),
121
127
  /**
122
- * By far the largest of the four: a manager snapshot carries up to the 1024 observed nodes
123
- * `validateSparkSwarmObservationRequest` admits, each with two identifiers of up to 200
124
- * characters, which is close to 600 KiB of body this route must still be able to read.
128
+ * The largest route: beside 1024 observed nodes, a cutover observation may carry independently
129
+ * bounded local-container and manager-service snapshots. Four MiB covers those validators while
130
+ * preserving one transport-level refusal before JSON is accepted.
125
131
  */
126
132
  swarmObservation: Object.freeze({
127
133
  endpoint: '/spark/swarm-nodes/swarm-observation',
128
- maxRequestBytes: 786_432,
134
+ maxRequestBytes: 4_194_304,
129
135
  maxResponseBytes: 2048,
130
136
  } as const),
131
137
  protocolRefusalStatus: protocolRefusalHttpStatus,
@@ -229,6 +235,8 @@ export type TSparkSwarmObservation =
229
235
  state: 'member';
230
236
  localSwarmNodeId: string;
231
237
  controlAvailable: false;
238
+ /** Local Docker-daemon evidence; it is accepted under this node's own credential. */
239
+ fleetCutoverLocalSnapshot?: IFleetCutoverLocalNodeSnapshot;
232
240
  })
233
241
  | (ISparkSwarmObservationBase & {
234
242
  state: 'member';
@@ -236,6 +244,10 @@ export type TSparkSwarmObservation =
236
244
  localSwarmNodeId: string;
237
245
  controlAvailable: true;
238
246
  managerSnapshot?: ISwarmManagerSnapshot;
247
+ /** A manager still reports physical containers only from its own local Docker daemon. */
248
+ fleetCutoverLocalSnapshot?: IFleetCutoverLocalNodeSnapshot;
249
+ /** Manager-visible services/tasks only; it never claims remote physical containers. */
250
+ fleetCutoverManagerSnapshot?: IFleetCutoverManagerSnapshot;
239
251
  });
240
252
 
241
253
  export type TSparkSwarmObservationRejectionCode =
@@ -573,7 +585,13 @@ export const validateSparkSwarmObservation = async (
573
585
  : observation.state === 'not-member'
574
586
  ? commonKeys
575
587
  : observation.state === 'member' && observation.controlAvailable === false
576
- ? [...commonKeys, 'localSwarmNodeId', 'controlAvailable']
588
+ ? [
589
+ ...commonKeys,
590
+ 'localSwarmNodeId',
591
+ 'controlAvailable',
592
+ ...(observation.fleetCutoverLocalSnapshot === undefined
593
+ ? [] : ['fleetCutoverLocalSnapshot']),
594
+ ]
577
595
  : observation.state === 'member' && observation.controlAvailable === true
578
596
  ? [
579
597
  ...commonKeys,
@@ -581,6 +599,10 @@ export const validateSparkSwarmObservation = async (
581
599
  'localSwarmNodeId',
582
600
  'controlAvailable',
583
601
  ...(observation.managerSnapshot === undefined ? [] : ['managerSnapshot']),
602
+ ...(observation.fleetCutoverLocalSnapshot === undefined
603
+ ? [] : ['fleetCutoverLocalSnapshot']),
604
+ ...(observation.fleetCutoverManagerSnapshot === undefined
605
+ ? [] : ['fleetCutoverManagerSnapshot']),
584
606
  ]
585
607
  : [];
586
608
  if (expectedKeys.length === 0 || !hasExactKeys(observation, expectedKeys)) {
@@ -602,6 +624,17 @@ export const validateSparkSwarmObservation = async (
602
624
  || typeof observation.controlAvailable !== 'boolean') {
603
625
  errors.push('Spark Swarm member observation must have canonical local authority');
604
626
  }
627
+ if (observation.fleetCutoverLocalSnapshot !== undefined) {
628
+ const localErrors = await validateFleetCutoverLocalNodeSnapshot(
629
+ observation.fleetCutoverLocalSnapshot,
630
+ );
631
+ errors.push(...localErrors.map(errorArg => `Spark Swarm observation ${errorArg}`));
632
+ if (isRuntimeRecord(observation.fleetCutoverLocalSnapshot)
633
+ && observation.fleetCutoverLocalSnapshot.swarmNodeId
634
+ !== observation.localSwarmNodeId) {
635
+ errors.push('Spark Swarm cutover local snapshot must name the local Swarm node');
636
+ }
637
+ }
605
638
  if (observation.controlAvailable === true) {
606
639
  if (!isRuntimeIdentifier(observation.swarmClusterId)) {
607
640
  errors.push('Spark Swarm manager observation must have canonical cluster authority');
@@ -613,6 +646,23 @@ export const validateSparkSwarmObservation = async (
613
646
  observation.managerSnapshot,
614
647
  ));
615
648
  }
649
+ if (observation.fleetCutoverManagerSnapshot !== undefined) {
650
+ if (observation.managerSnapshot === undefined) {
651
+ errors.push('Spark Swarm cutover manager snapshot requires the same manager observation');
652
+ }
653
+ const managerErrors = await validateFleetCutoverManagerSnapshot(
654
+ observation.fleetCutoverManagerSnapshot,
655
+ );
656
+ errors.push(...managerErrors.map(errorArg => `Spark Swarm observation ${errorArg}`));
657
+ if (isRuntimeRecord(observation.fleetCutoverManagerSnapshot)
658
+ && isRuntimeRecord(observation.fleetCutoverManagerSnapshot.inventory)) {
659
+ const cutoverInventory = observation.fleetCutoverManagerSnapshot.inventory;
660
+ if (cutoverInventory.swarmClusterId !== observation.swarmClusterId
661
+ || cutoverInventory.managerSwarmNodeId !== observation.localSwarmNodeId) {
662
+ errors.push('Spark Swarm cutover manager snapshot must name the observed authority');
663
+ }
664
+ }
665
+ }
616
666
  }
617
667
  }
618
668
  return errors;