@serve.zone/interfaces 31.8.0 → 31.9.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 +45 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/clusterruntime.d.ts +39 -0
- package/dist_ts/data/clusterruntime.js +11 -0
- package/dist_ts/data/index.d.ts +4 -0
- package/dist_ts/data/index.js +5 -1
- package/dist_ts/data/networkaddressplan.d.ts +78 -0
- package/dist_ts/data/networkaddressplan.js +114 -0
- package/dist_ts/data/networkauthority.js +5 -17
- package/dist_ts/data/networknode.d.ts +37 -0
- package/dist_ts/data/networknode.js +6 -0
- package/dist_ts/data/runtimeconfig.js +14 -77
- package/dist_ts/data/serviceruntime.d.ts +128 -0
- package/dist_ts/data/serviceruntime.js +92 -0
- package/dist_ts/private/networkcontract.d.ts +4 -0
- package/dist_ts/private/networkcontract.js +15 -1
- package/dist_ts/private/producercontract.d.ts +11 -0
- package/dist_ts/private/producercontract.js +21 -0
- package/dist_ts/private/runtimepolicy.d.ts +31 -0
- package/dist_ts/private/runtimepolicy.js +90 -0
- package/dist_ts/requests/cluster.d.ts +37 -0
- package/dist_ts/requests/cluster.js +1 -1
- package/dist_ts/requests/network.d.ts +57 -1
- package/dist_ts/requests/service.d.ts +60 -0
- package/package.json +1 -1
- package/readme.md +120 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/clusterruntime.ts +45 -0
- package/ts/data/index.ts +4 -0
- package/ts/data/networkaddressplan.ts +175 -0
- package/ts/data/networkauthority.ts +4 -16
- package/ts/data/networknode.ts +37 -0
- package/ts/data/runtimeconfig.ts +17 -76
- package/ts/data/serviceruntime.ts +208 -0
- package/ts/private/networkcontract.ts +14 -0
- package/ts/private/producercontract.ts +19 -0
- package/ts/private/runtimepolicy.ts +105 -0
- package/ts/requests/cluster.ts +45 -0
- package/ts/requests/network.ts +50 -1
- package/ts/requests/service.ts +81 -0
|
@@ -149,6 +149,20 @@ export const networkPrefixBounds = (value: string): [number, number] => {
|
|
|
149
149
|
const [address, bits] = value.split('/'), first = networkIpv4Number(address);
|
|
150
150
|
return [first, first + 2 ** (32 - Number(bits)) - 1];
|
|
151
151
|
};
|
|
152
|
+
/** A canonical IPv4 prefix: a dotted quad whose host bits are zero. */
|
|
153
|
+
export const networkPrefix = (value: unknown): string => {
|
|
154
|
+
requireNetwork(typeof value === 'string' && value.length <= 18);
|
|
155
|
+
const parts = value.split('/');
|
|
156
|
+
requireNetwork(parts.length === 2 && /^(?:[0-9]|[12][0-9]|3[0-2])$/.test(parts[1]));
|
|
157
|
+
requireNetwork(networkIpv4Number(networkIpv4(parts[0])) % 2 ** (32 - Number(parts[1])) === 0);
|
|
158
|
+
return value;
|
|
159
|
+
};
|
|
160
|
+
/** A canonical prefix inside the RFC 1918 private ranges. */
|
|
161
|
+
export const networkPrivatePrefix = (value: unknown): string => {
|
|
162
|
+
const prefix = networkPrefix(value);
|
|
163
|
+
requireNetwork(['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'].some(range => networkContains(range, prefix)));
|
|
164
|
+
return prefix;
|
|
165
|
+
};
|
|
152
166
|
export const networkContains = (outer: string, inner: string): boolean => {
|
|
153
167
|
const [a, b] = networkPrefixBounds(outer), [c, d] = networkPrefixBounds(inner); return a <= c && b >= d;
|
|
154
168
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { requireNetwork } from './networkcontract.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The runtime producer records read decoded input with the network family's strict JSON readers,
|
|
5
|
+
* and every producer snapshot runs inside `producerSafe`: whichever rule refused, a caller sees
|
|
6
|
+
* this one rejection and learns nothing about which field failed.
|
|
7
|
+
*/
|
|
8
|
+
export const failProducer = (): never => { throw new Error('Runtime producer contract rejected.'); };
|
|
9
|
+
export const producerSafe = <T>(operation: () => T): T => { try { return operation(); } catch { return failProducer(); } };
|
|
10
|
+
|
|
11
|
+
/** Membership in a closed union whose members are listed once, as the array the union is derived from. */
|
|
12
|
+
export const isOneOf = <T extends string>(members: readonly T[], value: unknown): value is T =>
|
|
13
|
+
(members as readonly unknown[]).includes(value);
|
|
14
|
+
|
|
15
|
+
/** The tag of a captured tagged record, read before the record's exact keys are known. */
|
|
16
|
+
export const variantOf = (value: unknown, tag: string): unknown => {
|
|
17
|
+
requireNetwork(value !== null && typeof value === 'object' && !Array.isArray(value));
|
|
18
|
+
return (value as Record<string, unknown>)[tag];
|
|
19
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { IRuntimeConfigLogPolicyV1 } from '../data/runtimeconfig.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The execution policy a runtime config seals and a service runtime profile states ahead of it.
|
|
5
|
+
* Both validators apply these timing, HTTP request, CPU, memory, identity and log rules. Only the
|
|
6
|
+
* service's target ports decide whether a readiness target exists, which a profile cannot know.
|
|
7
|
+
*
|
|
8
|
+
* Every check here reads captured plain data only, the output of `snapshotBoundedJson` or
|
|
9
|
+
* `captureNetwork`: on live input a getter could pass a check and then hand the caller another value.
|
|
10
|
+
*/
|
|
11
|
+
export const runtimePolicyLimits = Object.freeze({
|
|
12
|
+
minimumMemoryBytes: 16 * 1024 * 1024,
|
|
13
|
+
maximumMemoryBytes: 2 ** 50,
|
|
14
|
+
maximumCpuMillis: 1_000_000,
|
|
15
|
+
maximumIdentityNumber: 2 ** 31 - 1,
|
|
16
|
+
maximumReadinessDurationMs: 3_600_000,
|
|
17
|
+
maximumLogRetentionMs: 31_536_000_000,
|
|
18
|
+
} as const);
|
|
19
|
+
|
|
20
|
+
export type TRuntimePolicyFailure = (messageArg: string) => never;
|
|
21
|
+
|
|
22
|
+
export const isBoundedInteger = (valueArg: unknown, minimumArg: number, maximumArg: number): valueArg is number =>
|
|
23
|
+
typeof valueArg === 'number' && Number.isSafeInteger(valueArg) && !Object.is(valueArg, -0)
|
|
24
|
+
&& valueArg >= minimumArg && valueArg <= maximumArg;
|
|
25
|
+
export const isRuntimePortName = (valueArg: unknown): valueArg is string =>
|
|
26
|
+
typeof valueArg === 'string' && /^[a-z0-9][a-z0-9_.-]{0,62}$/.test(valueArg);
|
|
27
|
+
export const isExactRecord = (
|
|
28
|
+
valueArg: unknown, keysArg: readonly string[],
|
|
29
|
+
): valueArg is Record<string, unknown> => {
|
|
30
|
+
if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) return false;
|
|
31
|
+
const keys = Object.keys(valueArg);
|
|
32
|
+
return keys.length === keysArg.length && keys.every((keyArg) => keysArg.includes(keyArg));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** null explicitly requests no CPU quota; zero is never a quota. */
|
|
36
|
+
export const isRuntimeCpuMillis = (valueArg: unknown): valueArg is number | null =>
|
|
37
|
+
valueArg === null || isBoundedInteger(valueArg, 1, runtimePolicyLimits.maximumCpuMillis);
|
|
38
|
+
export const isRuntimeMemoryBytes = (valueArg: unknown): valueArg is number =>
|
|
39
|
+
isBoundedInteger(valueArg, runtimePolicyLimits.minimumMemoryBytes, runtimePolicyLimits.maximumMemoryBytes);
|
|
40
|
+
export const isRuntimeIdentityNumber = (valueArg: unknown): valueArg is number =>
|
|
41
|
+
isBoundedInteger(valueArg, 0, runtimePolicyLimits.maximumIdentityNumber);
|
|
42
|
+
|
|
43
|
+
export const isRuntimeLogPolicy = (valueArg: unknown): valueArg is IRuntimeConfigLogPolicyV1 =>
|
|
44
|
+
isExactRecord(valueArg, ['maximumLineBytes', 'maximumBufferedBytes', 'retentionMs'])
|
|
45
|
+
&& isBoundedInteger(valueArg.maximumLineBytes, 1, 1_048_576)
|
|
46
|
+
&& isBoundedInteger(valueArg.maximumBufferedBytes, 1, 67_108_864)
|
|
47
|
+
&& valueArg.maximumBufferedBytes >= valueArg.maximumLineBytes
|
|
48
|
+
&& isBoundedInteger(valueArg.retentionMs, 1, runtimePolicyLimits.maximumLogRetentionMs);
|
|
49
|
+
|
|
50
|
+
const timingKeys = ['initialDelayMs', 'startupGraceMs', 'intervalMs', 'timeoutMs',
|
|
51
|
+
'successThreshold', 'failureThreshold'] as const;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Readiness policy. `selectsTcpTargetArg` decides whether a probe's named target and port exist:
|
|
55
|
+
* a config answers from its own target ports, a profile ahead of any config cannot know them.
|
|
56
|
+
*/
|
|
57
|
+
export const assertRuntimeReadiness = (
|
|
58
|
+
valueArg: unknown,
|
|
59
|
+
selectsTcpTargetArg: (targetPortArg: string, portArg: number) => boolean,
|
|
60
|
+
failArg: TRuntimePolicyFailure,
|
|
61
|
+
): void => {
|
|
62
|
+
if (!valueArg || typeof valueArg !== 'object') failArg('runtime config readiness is required');
|
|
63
|
+
const value = valueArg as Record<string, unknown>;
|
|
64
|
+
const keys = value.kind === 'process' ? ['kind', ...timingKeys]
|
|
65
|
+
: value.kind === 'tcp' ? ['kind', ...timingKeys, 'targetPort', 'port']
|
|
66
|
+
: value.kind === 'http' ? ['kind', ...timingKeys, 'targetPort', 'port',
|
|
67
|
+
'scheme', 'host', 'path', 'expectedStatusCodes', 'followRedirects'] : [];
|
|
68
|
+
const maximumDurationMs = runtimePolicyLimits.maximumReadinessDurationMs;
|
|
69
|
+
if (keys.length === 0 || !isExactRecord(value, keys)
|
|
70
|
+
|| !isBoundedInteger(value.initialDelayMs, 0, maximumDurationMs)
|
|
71
|
+
|| !isBoundedInteger(value.startupGraceMs, 0, maximumDurationMs)
|
|
72
|
+
|| !isBoundedInteger(value.intervalMs, 100, maximumDurationMs)
|
|
73
|
+
|| !isBoundedInteger(value.timeoutMs, 1, 60_000)
|
|
74
|
+
|| !isBoundedInteger(value.successThreshold, 1, 100)
|
|
75
|
+
|| !isBoundedInteger(value.failureThreshold, 1, 100)
|
|
76
|
+
|| value.timeoutMs > value.intervalMs || value.initialDelayMs > value.startupGraceMs) {
|
|
77
|
+
failArg('runtime config readiness must use explicit bounded timing and exact schema');
|
|
78
|
+
}
|
|
79
|
+
if (value.kind === 'process') return;
|
|
80
|
+
if (!isRuntimePortName(value.targetPort) || !isBoundedInteger(value.port, 1, 65535)
|
|
81
|
+
|| !selectsTcpTargetArg(value.targetPort, value.port)) {
|
|
82
|
+
failArg('runtime config readiness must select a declared TCP target and port');
|
|
83
|
+
}
|
|
84
|
+
if (value.kind === 'tcp') return;
|
|
85
|
+
if ((value.scheme !== 'http' && value.scheme !== 'https') || value.followRedirects !== false
|
|
86
|
+
|| typeof value.host !== 'string' || value.host.length > 253
|
|
87
|
+
|| !/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/.test(value.host)
|
|
88
|
+
|| typeof value.path !== 'string' || value.path.length > 4096
|
|
89
|
+
|| !value.path.startsWith('/') || value.path.startsWith('//')
|
|
90
|
+
|| /[^\x21-\x7e]|[\\#]/.test(value.path)
|
|
91
|
+
|| /%(?![0-9A-F]{2})/.test(value.path)
|
|
92
|
+
|| !Array.isArray(value.expectedStatusCodes) || value.expectedStatusCodes.length === 0
|
|
93
|
+
|| value.expectedStatusCodes.length > 32) {
|
|
94
|
+
failArg('runtime config HTTP readiness must use an exact bounded request policy');
|
|
95
|
+
}
|
|
96
|
+
const parsed = new URL(value.path, 'http://runtime.invalid');
|
|
97
|
+
if (`${parsed.pathname}${parsed.search}` !== value.path) failArg('runtime config HTTP path must be canonical');
|
|
98
|
+
let previousCode = 0;
|
|
99
|
+
for (const code of value.expectedStatusCodes) {
|
|
100
|
+
if (!isBoundedInteger(code, 200, 599) || code <= previousCode) {
|
|
101
|
+
failArg('runtime config HTTP status expectations must be sorted unique final codes');
|
|
102
|
+
}
|
|
103
|
+
previousCode = code;
|
|
104
|
+
}
|
|
105
|
+
};
|
package/ts/requests/cluster.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as userInterfaces from '../data/user.js';
|
|
2
2
|
import * as clusterInterfaces from '../data/cluster.js';
|
|
3
|
+
import type { IClusterRuntime, TClusterRuntimeBlocker } from '../data/clusterruntime.js';
|
|
4
|
+
import type { IServiceRuntimeAssignmentView } from '../data/serviceruntime.js';
|
|
3
5
|
import type * as leaseInterfaces from '../data/networklease.js';
|
|
4
6
|
import * as plugins from '../plugins.js';
|
|
5
7
|
|
|
@@ -182,3 +184,46 @@ export interface IReq_Any_Cloudly_DeleteClusterById extends plugins.typedrequest
|
|
|
182
184
|
ok: boolean;
|
|
183
185
|
};
|
|
184
186
|
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* A cluster's runtime phase, and what still blocks it from leaving `swarm`.
|
|
190
|
+
*
|
|
191
|
+
* Cloudly refuses a cluster without a phase record as `cluster-runtime-missing` rather than
|
|
192
|
+
* assuming one. `blockers` is empty once nothing blocks the cutover.
|
|
193
|
+
*/
|
|
194
|
+
export interface IReq_Any_Cloudly_GetClusterRuntime extends plugins.typedrequestInterfaces.implementsTR<
|
|
195
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
196
|
+
IReq_Any_Cloudly_GetClusterRuntime
|
|
197
|
+
> {
|
|
198
|
+
method: 'getClusterRuntime';
|
|
199
|
+
request: {
|
|
200
|
+
identity: userInterfaces.IIdentity;
|
|
201
|
+
clusterId: string;
|
|
202
|
+
};
|
|
203
|
+
response: {
|
|
204
|
+
runtime: IClusterRuntime;
|
|
205
|
+
blockers: TClusterRuntimeBlocker[];
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Every current runtime assignment on one cluster's nodes, a page at a time: a cluster carries
|
|
211
|
+
* every node's slots of every service, which no single response bounds. `limit` runs from 1 to
|
|
212
|
+
* `serviceRuntimeContract.maximumAssignmentPageSize`; Cloudly refuses any other.
|
|
213
|
+
*/
|
|
214
|
+
export interface IReq_Any_Cloudly_GetClusterRuntimeAssignments extends plugins.typedrequestInterfaces.implementsTR<
|
|
215
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
216
|
+
IReq_Any_Cloudly_GetClusterRuntimeAssignments
|
|
217
|
+
> {
|
|
218
|
+
method: 'getClusterRuntimeAssignments';
|
|
219
|
+
request: {
|
|
220
|
+
identity: userInterfaces.IIdentity;
|
|
221
|
+
clusterId: string;
|
|
222
|
+
cursor: string | null;
|
|
223
|
+
limit: number;
|
|
224
|
+
};
|
|
225
|
+
response: {
|
|
226
|
+
assignments: IServiceRuntimeAssignmentView[];
|
|
227
|
+
nextCursor: string | null;
|
|
228
|
+
};
|
|
229
|
+
}
|
package/ts/requests/network.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as plugins from '../plugins.js';
|
|
2
|
-
import type { IIdentityCredential } from '../data/user.js';
|
|
2
|
+
import type { IIdentity, IIdentityCredential } from '../data/user.js';
|
|
3
|
+
import type { IRuntimeNetworkAddressPlan, TRuntimeNetworkAddressPlanWritableData } from '../data/networkaddressplan.js';
|
|
4
|
+
import type { IRuntimeNetworkNodeReadiness, IRuntimeRouterIncarnation } from '../data/networknode.js';
|
|
3
5
|
import type {
|
|
4
6
|
IPrivateNetworkV1, IServicePrivateNetworksV1, ISetServicePrivateNetworksV1,
|
|
5
7
|
TPrivateNetworkMutationV1,
|
|
@@ -98,3 +100,50 @@ export interface IRequest_Any_Cloudly_GetNetworkNodes {
|
|
|
98
100
|
networkNodes: plugins.tsclass.network.INetworkNode[];
|
|
99
101
|
};
|
|
100
102
|
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Writes the runtime network's address plan.
|
|
106
|
+
*
|
|
107
|
+
* `expectedRevision` is the revision the caller read, or `null` when no plan exists yet. Cloudly
|
|
108
|
+
* validates the plan with `snapshotRuntimeNetworkAddressPlan`, decides the change with
|
|
109
|
+
* `admitRuntimeNetworkAddressPlanChange`, refuses the change while a resolver or platform endpoint
|
|
110
|
+
* it removes or changes is still referenced, and answers with the stored plan: at its new revision,
|
|
111
|
+
* or unchanged.
|
|
112
|
+
*/
|
|
113
|
+
export interface IReq_Any_Cloudly_SetRuntimeNetworkAddressPlan extends plugins.typedrequestInterfaces.implementsTR<
|
|
114
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_SetRuntimeNetworkAddressPlan
|
|
115
|
+
> {
|
|
116
|
+
method: 'setRuntimeNetworkAddressPlan';
|
|
117
|
+
request: { identity: IIdentity; expectedRevision: number | null; plan: TRuntimeNetworkAddressPlanWritableData };
|
|
118
|
+
response: { plan: IRuntimeNetworkAddressPlan };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** `null` until an administrator sets the first plan; the runtime network stays unconfigured until then. */
|
|
122
|
+
export interface IReq_Any_Cloudly_GetRuntimeNetworkAddressPlan extends plugins.typedrequestInterfaces.implementsTR<
|
|
123
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_GetRuntimeNetworkAddressPlan
|
|
124
|
+
> {
|
|
125
|
+
method: 'getRuntimeNetworkAddressPlan';
|
|
126
|
+
request: { identity: IIdentity };
|
|
127
|
+
response: { plan: IRuntimeNetworkAddressPlan | null };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Whether one node's runtime network is ready for workloads, and every condition still missing. */
|
|
131
|
+
export interface IReq_Any_Cloudly_GetRuntimeNetworkNodeReadiness extends plugins.typedrequestInterfaces.implementsTR<
|
|
132
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_GetRuntimeNetworkNodeReadiness
|
|
133
|
+
> {
|
|
134
|
+
method: 'getRuntimeNetworkNodeReadiness';
|
|
135
|
+
request: { identity: IIdentity; nodeId: string };
|
|
136
|
+
response: IRuntimeNetworkNodeReadiness;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Advances one node's router incarnation, so the node producer reserves the router a fresh handoff.
|
|
141
|
+
* `expectedIncarnation` is the incarnation the caller read; any other refuses the request.
|
|
142
|
+
*/
|
|
143
|
+
export interface IReq_Any_Cloudly_ReincarnateRuntimeNetworkRouter extends plugins.typedrequestInterfaces.implementsTR<
|
|
144
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Any_Cloudly_ReincarnateRuntimeNetworkRouter
|
|
145
|
+
> {
|
|
146
|
+
method: 'reincarnateRuntimeNetworkRouter';
|
|
147
|
+
request: { identity: IIdentity; nodeId: string; expectedIncarnation: number };
|
|
148
|
+
response: { incarnation: IRuntimeRouterIncarnation };
|
|
149
|
+
}
|
package/ts/requests/service.ts
CHANGED
|
@@ -16,6 +16,12 @@ import type {
|
|
|
16
16
|
IServiceDeploymentStatus,
|
|
17
17
|
} from '../data/deploymentoperation.js';
|
|
18
18
|
import type { TSha256Digest } from '../data/immutableimage.js';
|
|
19
|
+
import type {
|
|
20
|
+
IServiceRuntimeAssignmentView,
|
|
21
|
+
IServiceRuntimeSpec,
|
|
22
|
+
IServiceRuntimeStatus,
|
|
23
|
+
TServiceRuntimeSpecWritableData,
|
|
24
|
+
} from '../data/serviceruntime.js';
|
|
19
25
|
import type {
|
|
20
26
|
IServiceDeploymentAdoptionInput,
|
|
21
27
|
IServiceDeploymentAdoptionImagePromotionInput,
|
|
@@ -370,3 +376,78 @@ extends plugins.typedrequestInterfaces.implementsTR<
|
|
|
370
376
|
success: boolean;
|
|
371
377
|
};
|
|
372
378
|
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Writes the complete runtime spec of one service.
|
|
382
|
+
*
|
|
383
|
+
* `expectedRevision` is the revision the caller read, or `null` when the service has never had a
|
|
384
|
+
* spec; any other stored revision refuses the write. Cloudly copies the organization from the
|
|
385
|
+
* service and answers with the stored spec at its new revision.
|
|
386
|
+
*/
|
|
387
|
+
export interface IRequest_Any_Cloudly_SetServiceRuntimeSpec
|
|
388
|
+
extends plugins.typedrequestInterfaces.implementsTR<
|
|
389
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
390
|
+
IRequest_Any_Cloudly_SetServiceRuntimeSpec
|
|
391
|
+
> {
|
|
392
|
+
method: 'setServiceRuntimeSpec';
|
|
393
|
+
request: {
|
|
394
|
+
identity: IIdentity;
|
|
395
|
+
serviceId: string;
|
|
396
|
+
expectedRevision: number | null;
|
|
397
|
+
spec: TServiceRuntimeSpecWritableData;
|
|
398
|
+
};
|
|
399
|
+
response: {
|
|
400
|
+
spec: IServiceRuntimeSpec;
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* A service's runtime spec and the producer's verdict on it. Both are `null` before the first spec;
|
|
406
|
+
* a spec's status is `null` until the producer first decides it.
|
|
407
|
+
*/
|
|
408
|
+
export interface IRequest_Any_Cloudly_GetServiceRuntimeSpec
|
|
409
|
+
extends plugins.typedrequestInterfaces.implementsTR<
|
|
410
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
411
|
+
IRequest_Any_Cloudly_GetServiceRuntimeSpec
|
|
412
|
+
> {
|
|
413
|
+
method: 'getServiceRuntimeSpec';
|
|
414
|
+
request: {
|
|
415
|
+
identity: IIdentity;
|
|
416
|
+
serviceId: string;
|
|
417
|
+
};
|
|
418
|
+
response:
|
|
419
|
+
| { spec: null; status: null }
|
|
420
|
+
| { spec: IServiceRuntimeSpec; status: IServiceRuntimeStatus | null };
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** Every current runtime assignment of one service, one per replica slot. */
|
|
424
|
+
export interface IRequest_Any_Cloudly_GetServiceRuntimeAssignments
|
|
425
|
+
extends plugins.typedrequestInterfaces.implementsTR<
|
|
426
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
427
|
+
IRequest_Any_Cloudly_GetServiceRuntimeAssignments
|
|
428
|
+
> {
|
|
429
|
+
method: 'getServiceRuntimeAssignments';
|
|
430
|
+
request: {
|
|
431
|
+
identity: IIdentity;
|
|
432
|
+
serviceId: string;
|
|
433
|
+
};
|
|
434
|
+
response: {
|
|
435
|
+
assignments: IServiceRuntimeAssignmentView[];
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Cloudly -> admin UIs: a service's runtime spec, status or assignments changed. It carries no
|
|
441
|
+
* state, so a late or repeated push can never overwrite a newer read; the UI reads the views again.
|
|
442
|
+
*/
|
|
443
|
+
export interface IReq_Cloudly_Any_PushServiceRuntimeChanged
|
|
444
|
+
extends plugins.typedrequestInterfaces.implementsTR<
|
|
445
|
+
plugins.typedrequestInterfaces.ITypedRequest,
|
|
446
|
+
IReq_Cloudly_Any_PushServiceRuntimeChanged
|
|
447
|
+
> {
|
|
448
|
+
method: 'pushServiceRuntimeChanged';
|
|
449
|
+
request: {
|
|
450
|
+
serviceId: string;
|
|
451
|
+
};
|
|
452
|
+
response: Record<string, never>;
|
|
453
|
+
}
|