@serve.zone/interfaces 32.12.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.
- package/changelog.md +19 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/clusternode.d.ts +11 -4
- package/dist_ts/data/clusternode.js +41 -6
- package/dist_ts/data/fleetcutover.d.ts +453 -0
- package/dist_ts/data/fleetcutover.js +943 -0
- package/dist_ts/data/index.d.ts +1 -0
- package/dist_ts/data/index.js +2 -1
- package/dist_ts/requests/fleetcutover.d.ts +124 -0
- package/dist_ts/requests/fleetcutover.js +2 -0
- package/dist_ts/requests/index.d.ts +2 -1
- package/dist_ts/requests/index.js +3 -2
- package/package.json +1 -1
- package/readme.md +103 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/clusternode.ts +55 -5
- package/ts/data/fleetcutover.ts +1557 -0
- package/ts/data/index.ts +1 -0
- package/ts/requests/fleetcutover.ts +136 -0
- package/ts/requests/index.ts +2 -0
package/dist_ts/data/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from './docker.js';
|
|
|
17
17
|
export * from './domain.js';
|
|
18
18
|
export * from './event.js';
|
|
19
19
|
export * from './externalregistry.js';
|
|
20
|
+
export * from './fleetcutover.js';
|
|
20
21
|
export * from './gateway.js';
|
|
21
22
|
export * from './hostedapp.js';
|
|
22
23
|
export * from './image.js';
|
package/dist_ts/data/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export * from './docker.js';
|
|
|
17
17
|
export * from './domain.js';
|
|
18
18
|
export * from './event.js';
|
|
19
19
|
export * from './externalregistry.js';
|
|
20
|
+
export * from './fleetcutover.js';
|
|
20
21
|
export * from './gateway.js';
|
|
21
22
|
export * from './hostedapp.js';
|
|
22
23
|
export * from './image.js';
|
|
@@ -61,4 +62,4 @@ export * from './traffic.js';
|
|
|
61
62
|
export * from './user.js';
|
|
62
63
|
export * from './version.js';
|
|
63
64
|
export * from './webpush.js';
|
|
64
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
65
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsaUJBQWlCLENBQUM7QUFDaEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLDBCQUEwQixDQUFDO0FBQ3pDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLFVBQVUsQ0FBQztBQUN6QixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLFlBQVksQ0FBQztBQUMzQixjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLFlBQVksQ0FBQztBQUMzQixjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyw2QkFBNkIsQ0FBQztBQUM1QyxjQUFjLFdBQVcsQ0FBQztBQUMxQixjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyx1QkFBdUIsQ0FBQztBQUN0QyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsc0JBQXNCLENBQUM7QUFDckMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsd0JBQXdCLENBQUM7QUFFdkMsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyxlQUFlLENBQUM7QUFDOUIsY0FBYyx3QkFBd0IsQ0FBQztBQUN2QyxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyxxQkFBcUIsQ0FBQztBQUNwQyxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxXQUFXLENBQUM7QUFDMUIsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxjQUFjLENBQUMifQ==
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import type { IIdentityCredential } from '../data/user.js';
|
|
3
|
+
import type { IClusterRuntime } from '../data/clusterruntime.js';
|
|
4
|
+
import type { IServiceRuntimeSpec } from '../data/serviceruntime.js';
|
|
5
|
+
import type { IFleetCutoverAcceptedEvidenceReference, IFleetCutoverCorestoreAdoptionReceipt, IFleetCutoverIngressAuthority, IFleetCutoverScope, IFleetCutoverScopeClassificationRequest, IFleetCutoverVolumeHandoffIntent, TFleetCutoverPhaseAdvance, TFleetCutoverRuntimeSpecRelease, TFleetCutoverVolumeFence } from '../data/fleetcutover.js';
|
|
6
|
+
export interface IReq_Any_Cloudly_GetFleetCutoverScope extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_GetFleetCutoverScope> {
|
|
7
|
+
method: 'getFleetCutoverScope';
|
|
8
|
+
request: {
|
|
9
|
+
identity: IIdentityCredential;
|
|
10
|
+
clusterId: string;
|
|
11
|
+
};
|
|
12
|
+
response: {
|
|
13
|
+
scope: IFleetCutoverScope | null;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The administrator classifies the exact current census candidate. Cloudly compares every entry
|
|
18
|
+
* with its current service, platform-service, credential, and storage authority before it may
|
|
19
|
+
* persist a complete scope; the request itself is no proof of those facts.
|
|
20
|
+
*/
|
|
21
|
+
export interface IReq_Admin_Cloudly_ClassifyFleetCutoverScope extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_Cloudly_ClassifyFleetCutoverScope> {
|
|
22
|
+
method: 'classifyFleetCutoverScope';
|
|
23
|
+
request: {
|
|
24
|
+
identity: IIdentityCredential;
|
|
25
|
+
classification: IFleetCutoverScopeClassificationRequest;
|
|
26
|
+
};
|
|
27
|
+
response: {
|
|
28
|
+
scope: IFleetCutoverScope;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Forward-only legal phase CAS. All receipt references are dereferenced by Cloudly in the same
|
|
33
|
+
* transaction; caller-supplied records or booleans never satisfy a cutover condition.
|
|
34
|
+
*/
|
|
35
|
+
export interface IReq_Admin_Cloudly_AdvanceFleetCutoverPhase extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_Cloudly_AdvanceFleetCutoverPhase> {
|
|
36
|
+
method: 'advanceFleetCutoverPhase';
|
|
37
|
+
request: {
|
|
38
|
+
identity: IIdentityCredential;
|
|
39
|
+
advance: TFleetCutoverPhaseAdvance;
|
|
40
|
+
};
|
|
41
|
+
response: {
|
|
42
|
+
runtime: IClusterRuntime;
|
|
43
|
+
replayed: boolean;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The only cutover-specific hold release. Ingress releases first under an accepted empty public
|
|
48
|
+
* port policy; applications require the accepted ingress/port/route authority assembled later.
|
|
49
|
+
*/
|
|
50
|
+
export interface IReq_Admin_Cloudly_ReleaseFleetCutoverRuntimeSpec extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_Cloudly_ReleaseFleetCutoverRuntimeSpec> {
|
|
51
|
+
method: 'releaseFleetCutoverRuntimeSpec';
|
|
52
|
+
request: {
|
|
53
|
+
identity: IIdentityCredential;
|
|
54
|
+
release: TFleetCutoverRuntimeSpecRelease;
|
|
55
|
+
};
|
|
56
|
+
response: {
|
|
57
|
+
spec: IServiceRuntimeSpec;
|
|
58
|
+
replayed: boolean;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export interface IReq_Any_Cloudly_GetFleetCutoverIngressAuthority extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_GetFleetCutoverIngressAuthority> {
|
|
62
|
+
method: 'getFleetCutoverIngressAuthority';
|
|
63
|
+
request: {
|
|
64
|
+
identity: IIdentityCredential;
|
|
65
|
+
clusterId: string;
|
|
66
|
+
};
|
|
67
|
+
response: {
|
|
68
|
+
authority: IFleetCutoverIngressAuthority | null;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Root-local only. Holding an intent creates negative storage authority and no runtime session. */
|
|
72
|
+
export interface IReq_PalletLocal_Pallet_HoldFleetCutoverVolumeFence extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_PalletLocal_Pallet_HoldFleetCutoverVolumeFence> {
|
|
73
|
+
method: 'holdFleetCutoverVolumeFence';
|
|
74
|
+
request: {
|
|
75
|
+
fenceId: string;
|
|
76
|
+
handoffIntent: IFleetCutoverVolumeHandoffIntent;
|
|
77
|
+
};
|
|
78
|
+
response: {
|
|
79
|
+
fence: Extract<TFleetCutoverVolumeFence, {
|
|
80
|
+
state: 'held';
|
|
81
|
+
}>;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export interface IReq_PalletLocal_Pallet_GetFleetCutoverVolumeFence extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_PalletLocal_Pallet_GetFleetCutoverVolumeFence> {
|
|
85
|
+
method: 'getFleetCutoverVolumeFence';
|
|
86
|
+
request: {
|
|
87
|
+
fenceId: string;
|
|
88
|
+
};
|
|
89
|
+
response: {
|
|
90
|
+
fence: TFleetCutoverVolumeFence | null;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Pallet consumes the local fence only around a current accepted Corestore adoption result. The
|
|
95
|
+
* receipt carries the real ready storage-claim reference; the earlier handoff intent does not.
|
|
96
|
+
*/
|
|
97
|
+
export interface IReq_PalletLocal_Pallet_ConsumeFleetCutoverVolumeFence extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_PalletLocal_Pallet_ConsumeFleetCutoverVolumeFence> {
|
|
98
|
+
method: 'consumeFleetCutoverVolumeFence';
|
|
99
|
+
request: {
|
|
100
|
+
fence: IFleetCutoverAcceptedEvidenceReference;
|
|
101
|
+
adoption: IFleetCutoverCorestoreAdoptionReceipt;
|
|
102
|
+
};
|
|
103
|
+
response: {
|
|
104
|
+
fence: Extract<TFleetCutoverVolumeFence, {
|
|
105
|
+
state: 'consumed';
|
|
106
|
+
}>;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Corestore owns the one-shot initial lineage/RWO CAS. The local caller supplies the held fence
|
|
111
|
+
* and server-owned handoff intent; Corestore returns the claim only after its provider is ready.
|
|
112
|
+
*/
|
|
113
|
+
export interface IReq_Pallet_Corestore_AdoptFleetCutoverVolume extends plugins.typedrequestInterfaces.implementsTR<plugins.typedrequestInterfaces.ITypedRequest, IReq_Pallet_Corestore_AdoptFleetCutoverVolume> {
|
|
114
|
+
method: 'adoptFleetCutoverVolume';
|
|
115
|
+
request: {
|
|
116
|
+
handoffIntent: IFleetCutoverVolumeHandoffIntent;
|
|
117
|
+
palletFence: Extract<TFleetCutoverVolumeFence, {
|
|
118
|
+
state: 'held';
|
|
119
|
+
}>;
|
|
120
|
+
};
|
|
121
|
+
response: {
|
|
122
|
+
adoption: IFleetCutoverCorestoreAdoptionReceipt;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmxlZXRjdXRvdmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvcmVxdWVzdHMvZmxlZXRjdXRvdmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDIn0=
|
|
@@ -14,6 +14,7 @@ import * as deploymentRequests from './deployment.js';
|
|
|
14
14
|
import * as dnsRequests from './dns.js';
|
|
15
15
|
import * as domainRequests from './domain.js';
|
|
16
16
|
import * as externalRegistryRequests from './externalregistry.js';
|
|
17
|
+
import * as fleetCutoverRequests from './fleetcutover.js';
|
|
17
18
|
import * as gatewayRequests from './gateway.js';
|
|
18
19
|
import * as hostedAppRequests from './hostedapp.js';
|
|
19
20
|
import * as identityRequests from './identity.js';
|
|
@@ -35,7 +36,7 @@ import * as statusRequests from './status.js';
|
|
|
35
36
|
import * as taskRequests from './task.js';
|
|
36
37
|
import * as versionRequests from './version.js';
|
|
37
38
|
import * as webPushRequests from './webpush.js';
|
|
38
|
-
export { adminRequests as admin, appStoreRequests as appstore, baremetalRequests as baremetal, baseOsRequests as baseos, backupRequests as backup, certificateRequests as certificate, clusterRequests as cluster, clusterIngressRequests as clusteringress, configRequests as config, coreMailRequests as coremail, coreMailAdminRequests as coremailAdmin, corestoreRequests as corestore, deploymentRequests as deployment, dnsRequests as dns, domainRequests as domain, externalRegistryRequests as externalRegistry, gatewayRequests as gateway, hostedAppRequests as hostedapp, identityRequests as identity, imageRequests as image, informRequests as inform, logRequests as log, mailRequests as mail, migrationRequests as migration, networkRequests as network, nodeRequests as node, palletRequests as pallet, platformRequests as platform, routingRequests as routing, runtimeSessionRequests as runtimesession, secretRequests as secret, serviceRequests as service, settingsRequests as settings, statusRequests as status, taskRequests as task, versionRequests as version, webPushRequests as webpush, };
|
|
39
|
+
export { adminRequests as admin, appStoreRequests as appstore, baremetalRequests as baremetal, baseOsRequests as baseos, backupRequests as backup, certificateRequests as certificate, clusterRequests as cluster, clusterIngressRequests as clusteringress, configRequests as config, coreMailRequests as coremail, coreMailAdminRequests as coremailAdmin, corestoreRequests as corestore, deploymentRequests as deployment, dnsRequests as dns, domainRequests as domain, externalRegistryRequests as externalRegistry, fleetCutoverRequests as fleetcutover, gatewayRequests as gateway, hostedAppRequests as hostedapp, identityRequests as identity, imageRequests as image, informRequests as inform, logRequests as log, mailRequests as mail, migrationRequests as migration, networkRequests as network, nodeRequests as node, palletRequests as pallet, platformRequests as platform, routingRequests as routing, runtimeSessionRequests as runtimesession, secretRequests as secret, serviceRequests as service, settingsRequests as settings, statusRequests as status, taskRequests as task, versionRequests as version, webPushRequests as webpush, };
|
|
39
40
|
export * from './inform.js';
|
|
40
41
|
export * from './hostedapp.js';
|
|
41
42
|
export * from './mail.js';
|
|
@@ -15,6 +15,7 @@ import * as deploymentRequests from './deployment.js';
|
|
|
15
15
|
import * as dnsRequests from './dns.js';
|
|
16
16
|
import * as domainRequests from './domain.js';
|
|
17
17
|
import * as externalRegistryRequests from './externalregistry.js';
|
|
18
|
+
import * as fleetCutoverRequests from './fleetcutover.js';
|
|
18
19
|
import * as gatewayRequests from './gateway.js';
|
|
19
20
|
import * as hostedAppRequests from './hostedapp.js';
|
|
20
21
|
import * as identityRequests from './identity.js';
|
|
@@ -36,9 +37,9 @@ import * as statusRequests from './status.js';
|
|
|
36
37
|
import * as taskRequests from './task.js';
|
|
37
38
|
import * as versionRequests from './version.js';
|
|
38
39
|
import * as webPushRequests from './webpush.js';
|
|
39
|
-
export { adminRequests as admin, appStoreRequests as appstore, baremetalRequests as baremetal, baseOsRequests as baseos, backupRequests as backup, certificateRequests as certificate, clusterRequests as cluster, clusterIngressRequests as clusteringress, configRequests as config, coreMailRequests as coremail, coreMailAdminRequests as coremailAdmin, corestoreRequests as corestore, deploymentRequests as deployment, dnsRequests as dns, domainRequests as domain, externalRegistryRequests as externalRegistry, gatewayRequests as gateway, hostedAppRequests as hostedapp, identityRequests as identity, imageRequests as image, informRequests as inform, logRequests as log, mailRequests as mail, migrationRequests as migration, networkRequests as network, nodeRequests as node, palletRequests as pallet, platformRequests as platform, routingRequests as routing, runtimeSessionRequests as runtimesession, secretRequests as secret, serviceRequests as service, settingsRequests as settings, statusRequests as status, taskRequests as task, versionRequests as version, webPushRequests as webpush, };
|
|
40
|
+
export { adminRequests as admin, appStoreRequests as appstore, baremetalRequests as baremetal, baseOsRequests as baseos, backupRequests as backup, certificateRequests as certificate, clusterRequests as cluster, clusterIngressRequests as clusteringress, configRequests as config, coreMailRequests as coremail, coreMailAdminRequests as coremailAdmin, corestoreRequests as corestore, deploymentRequests as deployment, dnsRequests as dns, domainRequests as domain, externalRegistryRequests as externalRegistry, fleetCutoverRequests as fleetcutover, gatewayRequests as gateway, hostedAppRequests as hostedapp, identityRequests as identity, imageRequests as image, informRequests as inform, logRequests as log, mailRequests as mail, migrationRequests as migration, networkRequests as network, nodeRequests as node, palletRequests as pallet, platformRequests as platform, routingRequests as routing, runtimeSessionRequests as runtimesession, secretRequests as secret, serviceRequests as service, settingsRequests as settings, statusRequests as status, taskRequests as task, versionRequests as version, webPushRequests as webpush, };
|
|
40
41
|
export * from './inform.js';
|
|
41
42
|
export * from './hostedapp.js';
|
|
42
43
|
export * from './mail.js';
|
|
43
44
|
export * from './webpush.js';
|
|
44
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
45
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9yZXF1ZXN0cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUV6QyxPQUFPLEtBQUssYUFBYSxNQUFNLFlBQVksQ0FBQztBQUM1QyxPQUFPLEtBQUssZ0JBQWdCLE1BQU0sZUFBZSxDQUFDO0FBQ2xELE9BQU8sS0FBSyxpQkFBaUIsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwRCxPQUFPLEtBQUssY0FBYyxNQUFNLGFBQWEsQ0FBQztBQUM5QyxPQUFPLEtBQUssY0FBYyxNQUFNLGFBQWEsQ0FBQztBQUM5QyxPQUFPLEtBQUssbUJBQW1CLE1BQU0sa0JBQWtCLENBQUM7QUFDeEQsT0FBTyxLQUFLLGVBQWUsTUFBTSxjQUFjLENBQUM7QUFDaEQsT0FBTyxLQUFLLHNCQUFzQixNQUFNLHFCQUFxQixDQUFDO0FBQzlELE9BQU8sS0FBSyxjQUFjLE1BQU0sYUFBYSxDQUFDO0FBQzlDLE9BQU8sS0FBSyxnQkFBZ0IsTUFBTSxlQUFlLENBQUM7QUFDbEQsT0FBTyxLQUFLLHFCQUFxQixNQUFNLHFCQUFxQixDQUFDO0FBQzdELE9BQU8sS0FBSyxpQkFBaUIsTUFBTSxnQkFBZ0IsQ0FBQztBQUNwRCxPQUFPLEtBQUssa0JBQWtCLE1BQU0saUJBQWlCLENBQUM7QUFDdEQsT0FBTyxLQUFLLFdBQVcsTUFBTSxVQUFVLENBQUM7QUFDeEMsT0FBTyxLQUFLLGNBQWMsTUFBTSxhQUFhLENBQUM7QUFDOUMsT0FBTyxLQUFLLHdCQUF3QixNQUFNLHVCQUF1QixDQUFDO0FBQ2xFLE9BQU8sS0FBSyxvQkFBb0IsTUFBTSxtQkFBbUIsQ0FBQztBQUMxRCxPQUFPLEtBQUssZUFBZSxNQUFNLGNBQWMsQ0FBQztBQUNoRCxPQUFPLEtBQUssaUJBQWlCLE1BQU0sZ0JBQWdCLENBQUM7QUFDcEQsT0FBTyxLQUFLLGdCQUFnQixNQUFNLGVB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
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -173,6 +173,10 @@ bodies and a pallet node posts this one, and the family retires with coreflow
|
|
|
173
173
|
rather than with this release. `ISparkSwarmNodeHeartbeatRequest` is now owned here,
|
|
174
174
|
so Cloudly and Spark no longer carry private copies of it, and every Swarm-era body
|
|
175
175
|
— request and answer alike — carries `protocol` and is judged in the same order.
|
|
176
|
+
For fleet cutover, that same observation may carry a bounded local Docker snapshot from the
|
|
177
|
+
reporting node and, only when control is available, a manager-visible service/task snapshot. The
|
|
178
|
+
existing node-token, reporter-session, sequence, digest and accepted-receipt rules authenticate
|
|
179
|
+
both; no separate fleet-report route exists.
|
|
176
180
|
|
|
177
181
|
Each of the four routes has its validator here, so a server never writes its own
|
|
178
182
|
member checks: `data.validateSparkSwarmNodeHeartbeatRequest`,
|
|
@@ -1035,6 +1039,105 @@ the record. Which phase may follow which belongs to the cutover, whose requests
|
|
|
1035
1039
|
(`service-multi-cluster-scope`, `service-authority-unsupported`, `platform-binding-present`) name
|
|
1036
1040
|
the `serviceId`.
|
|
1037
1041
|
|
|
1042
|
+
### Fleet Runtime Cutover Authority
|
|
1043
|
+
|
|
1044
|
+
`data.IFleetCutoverCensus` is Cloudly's accepted, Spark-authenticated Docker census. It carries
|
|
1045
|
+
only immutable Docker service/spec identity, exact mode and replica count, hashed constraint
|
|
1046
|
+
identity, the ownership labels used by the cutover, exact tasks and value-free mounts. A manager
|
|
1047
|
+
reports only manager-visible `/nodes`, `/services` and `/tasks` state. Every node separately reports
|
|
1048
|
+
its own complete local physical-container list through the existing authenticated
|
|
1049
|
+
`sparkSwarmNodeContracts.swarmObservation` route; a manager never attests remote Docker-daemon
|
|
1050
|
+
contents. The local list is fenced by exact sorted container-ID set digests read before and after
|
|
1051
|
+
all bounded inspect calls, so a container appearing or disappearing during inspection refuses the
|
|
1052
|
+
snapshot. The accepted census references two consecutive manager observations with identical
|
|
1053
|
+
Swarm and inventory digests and one current accepted local observation for every target node.
|
|
1054
|
+
Every reference preserves the authenticating node, credential generation, reporter session,
|
|
1055
|
+
sequence, observation time and fixed `freshUntil`; assembling a later census cannot renew an old
|
|
1056
|
+
observation. It never transports environment, arbitrary labels, mount paths, volume names,
|
|
1057
|
+
registry credentials or secret values.
|
|
1058
|
+
|
|
1059
|
+
Mount identity has three explicit canonical domains. `serve.zone/fleet-cutover-mount-source-identity`
|
|
1060
|
+
hashes `{ type, source }`, where `source` is the exact UTF-8 `Mount.Source` returned by Docker,
|
|
1061
|
+
including an empty string. `serve.zone/fleet-cutover-mount-target-identity` hashes `{ target }`,
|
|
1062
|
+
where `target` is the exact UTF-8 `Mount.Destination`. `serve.zone/fleet-cutover-mount-identity`
|
|
1063
|
+
then hashes `{ type, classification, sourceIdentityDigest, targetIdentityDigest, readOnly }`.
|
|
1064
|
+
All three use strict canonical JSON and no case, slash, path, volume-name or alias normalization.
|
|
1065
|
+
Only the digests and classification cross the wire. `unknown` type/classification remains visible
|
|
1066
|
+
and prevents Cloudly accepting a complete scope; missing, unmanaged or conflicting service/container
|
|
1067
|
+
ownership also prevents completion rather than omitting the container. Structural validation does
|
|
1068
|
+
not establish freshness, authentication, manager consensus, ownership or Docker truth; Cloudly
|
|
1069
|
+
establishes those policy facts while dereferencing the accepted observations.
|
|
1070
|
+
|
|
1071
|
+
`data.IFleetCutoverScope` is the server-owned authoritative service set. It starts `incomplete`;
|
|
1072
|
+
every `complete` entry binds an exact Docker service id to the current service authority and an
|
|
1073
|
+
accepted classification authority. `unknown` cannot appear in a complete structural snapshot.
|
|
1074
|
+
An authenticated administrator may submit `IFleetCutoverScopeClassificationRequest` against the
|
|
1075
|
+
exact current census, including for an unlabeled legacy Coretraffic or Corestore service. Cloudly
|
|
1076
|
+
still compares the declaration with current service, platform-service, credential, storage and
|
|
1077
|
+
census authority before accepting it. A classification is an operator decision, never a client
|
|
1078
|
+
proof boolean or a service-name inference.
|
|
1079
|
+
|
|
1080
|
+
`data.TFleetCutoverPhaseAdvance` permits only `swarm -> draining -> switching -> pallet` and carries
|
|
1081
|
+
opaque references to owner-accepted records. `requests.fleetcutover.advanceFleetCutoverPhase`
|
|
1082
|
+
dereferences and joins them inside Cloudly's phase CAS. Leaving `draining` requires the accepted
|
|
1083
|
+
fresh census/quiescence decision, the complete current scope and target set, every runtime spec
|
|
1084
|
+
held, and the accepted set of root-local volume fences. Entering `pallet` still requires every
|
|
1085
|
+
spec held. `switching` grants session and network preparation only; it runs no service. Structural
|
|
1086
|
+
snapshots enforce the closed forward shape but do not claim the referenced records exist or are
|
|
1087
|
+
current.
|
|
1088
|
+
|
|
1089
|
+
Before the first `swarm -> draining` CAS, Spark starts the replacement Coreflow32 relay as the
|
|
1090
|
+
exact Docker service/spec/image, delivers only its new generation-bearing credential and obtains
|
|
1091
|
+
the live accepted relay registration. Cloudly then revokes the old credential and accepts the
|
|
1092
|
+
current Spark bundle/unit/configuration and old-mode refusal evidence. This is a pre-switch Docker
|
|
1093
|
+
owner; it is never represented as a Pallet assignment. Downstream service holds and storage fences
|
|
1094
|
+
therefore depend on a live relay without requiring assignment authority that cannot exist yet.
|
|
1095
|
+
|
|
1096
|
+
The storage bootstrap has two different authorities. `IFleetCutoverVolumeHandoffIntent` is
|
|
1097
|
+
Cloudly's accepted pre-switch statement of exact service, volume, source-lineage and storage-request
|
|
1098
|
+
identity. It also binds the exact persistent `mountIdentityDigest` and accepted source-node
|
|
1099
|
+
observation. It is not a ready `IRuntimeStorageClaim`. Pallet persists a root-local
|
|
1100
|
+
`TFleetCutoverVolumeFence` in `held` state while the cluster is draining. That state carries no
|
|
1101
|
+
claim, session, assignment, attachment, reservation, confirmation or execution authority, and the
|
|
1102
|
+
storage owner must block all those operations for the volume. After the cluster reaches `pallet`,
|
|
1103
|
+
Corestore performs its one-shot initial lineage/ReadWriteOnce CAS for the same mount identity under
|
|
1104
|
+
that held native fence and returns `IFleetCutoverCorestoreAdoptionReceipt`, which for the first time
|
|
1105
|
+
binds the real ready
|
|
1106
|
+
`IRuntimeStorageClaim` reference. Only that exact accepted receipt can consume the Pallet fence.
|
|
1107
|
+
This separation prevents a pre-switch fence from fabricating provider readiness merely to satisfy
|
|
1108
|
+
cutover ordering.
|
|
1109
|
+
|
|
1110
|
+
`IFleetCutoverCoreflowRetirementEvidence` binds the real pre-switch Docker Coreflow32 relay by exact
|
|
1111
|
+
service ID, container ID, spec version/spec digest and image digest to accepted manager and local
|
|
1112
|
+
node observations. It requires no Pallet assignment. Cloudly dereferences those observations to
|
|
1113
|
+
require a live exact container without Docker/cgroup mounts, then joins its generation-bearing
|
|
1114
|
+
relay credential and accepted live registration to the current Spark credential, bundle, unit and
|
|
1115
|
+
accepted observation. It separately binds invalidation of the
|
|
1116
|
+
legacy credential, refusal of the old callable mode, and Spark's configuration CAS. The legacy
|
|
1117
|
+
source is identified by SHA-256 and may be `retained-inert` or `removed`; deletion and secure
|
|
1118
|
+
erasure are not cutover requirements. Its exact owner generation is retained with that disposition.
|
|
1119
|
+
Retained recovery evidence is valid only while the released
|
|
1120
|
+
owner cannot consume it into live mode and the old credential remains revoked.
|
|
1121
|
+
|
|
1122
|
+
The post-pallet order is represented without a second route or publication model. First Cloudly
|
|
1123
|
+
releases only the new ingress spec under an accepted empty published-port policy. It then accepts
|
|
1124
|
+
the existing cluster-ingress registration and route-table revision, exact Spark evidence that the
|
|
1125
|
+
old ingress is absent, the current source and target publication records and owning port-transfer
|
|
1126
|
+
receipt, and a readback of the current route revision as `IFleetCutoverIngressAuthority`. Only an
|
|
1127
|
+
application release may cite that authority. The legacy Docker Coretraffic instance therefore
|
|
1128
|
+
remains through `switching`; the new ingress runs without public ports before exact port ownership
|
|
1129
|
+
moves, and applications remain held until the new authoritative route is read back.
|
|
1130
|
+
|
|
1131
|
+
The owner methods live under `requests.fleetcutover`: administrator scope classification and
|
|
1132
|
+
forward phase CAS, root-local Pallet volume-fence hold/read/
|
|
1133
|
+
consume, one-shot Corestore adoption, ingress-authority read, and ingress/application spec release.
|
|
1134
|
+
Spark transports local and manager evidence through its existing authenticated Swarm-observation
|
|
1135
|
+
route, and Cloudly assembles census and Coreflow-retirement records from accepted owner state; there
|
|
1136
|
+
is no caller-supplied census or retirement proof endpoint.
|
|
1137
|
+
Accepted evidence references are opaque `{ id, generation, digest }` records. They contain no
|
|
1138
|
+
secret bytes and gain meaning only when the named server owner dereferences them under current
|
|
1139
|
+
authorization and policy.
|
|
1140
|
+
|
|
1038
1141
|
### Service Runtime Specs And Status
|
|
1039
1142
|
|
|
1040
1143
|
`data.IServiceRuntimeSpec` is what Cloudly runs for one service on a Pallet cluster:
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/data/clusternode.ts
CHANGED
|
@@ -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
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
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:
|
|
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
|
-
? [
|
|
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;
|