@serve.zone/interfaces 32.31.0 → 32.33.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 +40 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/data/deploymentmachineuser.d.ts +94 -0
- package/dist_ts/data/deploymentmachineuser.js +121 -0
- package/dist_ts/data/deploymentpreflight.d.ts +1 -1
- package/dist_ts/data/deploymentpreflight.js +7 -1
- package/dist_ts/data/index.d.ts +1 -0
- package/dist_ts/data/index.js +2 -1
- package/dist_ts/data/networkprojection.d.ts +27 -4
- package/dist_ts/data/networkprojection.js +34 -2
- package/dist_ts/requests/admin.d.ts +35 -0
- package/dist_ts/requests/service.d.ts +8 -0
- package/package.json +1 -1
- package/readme.md +28 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/data/deploymentmachineuser.ts +174 -0
- package/ts/data/deploymentpreflight.ts +6 -0
- package/ts/data/index.ts +1 -0
- package/ts/data/networkprojection.ts +49 -6
- package/ts/requests/admin.ts +37 -0
- package/ts/requests/service.ts +8 -0
|
@@ -87,7 +87,9 @@ export interface IRuntimeNetworkPublishedPort {
|
|
|
87
87
|
* Outbound flows the workload originates from a published target port leave the node from the
|
|
88
88
|
* matching host port, so a peer sees one address and port in both directions (SIP, RTP). Only
|
|
89
89
|
* `true` is ever stated; omitted, outbound flows keep the handoff lease's translation. It grants
|
|
90
|
-
* no egress: an endpoint carrying a symmetric entry has `publicEgress: true`.
|
|
90
|
+
* no egress: an endpoint carrying a symmetric entry has `publicEgress: true`. Its target ports
|
|
91
|
+
* are its own: no other entry of the list publishes to any of them
|
|
92
|
+
* (`findRuntimeNetworkPublishedPortInsideOverlap`).
|
|
91
93
|
*/
|
|
92
94
|
symmetric?: true;
|
|
93
95
|
/**
|
|
@@ -115,7 +117,10 @@ export interface IRuntimeNetworkPublishedPortRequest {
|
|
|
115
117
|
/** The last port of a range; `targetPort` then equals `hostPort`. */
|
|
116
118
|
hostPortEnd?: number;
|
|
117
119
|
targetPort: number;
|
|
118
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Same-port outbound; valid only while the service's policy document grants public egress, and
|
|
122
|
+
* only on target ports no other entry of the list publishes to.
|
|
123
|
+
*/
|
|
119
124
|
symmetric?: true;
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -132,7 +137,8 @@ export interface IServicePublishedPorts {
|
|
|
132
137
|
/**
|
|
133
138
|
* Sorted by protocol and host port, never overlapping, at most
|
|
134
139
|
* `runtimeNetworkPublishedPortContract.maximumEntries` entries covering at most its
|
|
135
|
-
* `maximumPortsPerService` ports
|
|
140
|
+
* `maximumPortsPerService` ports, and no symmetric entry sharing a target port with another
|
|
141
|
+
* entry of its protocol. Empty means the service publishes nothing.
|
|
136
142
|
*/
|
|
137
143
|
publishedPorts: IRuntimeNetworkPublishedPortRequest[];
|
|
138
144
|
}
|
|
@@ -235,7 +241,8 @@ export interface IRuntimeNetworkEndpoint {
|
|
|
235
241
|
/**
|
|
236
242
|
* Sorted by protocol and host port and never overlapping, within the bounds of
|
|
237
243
|
* `runtimeNetworkPublishedPortContract`. Absent publishes nothing; a present member is never
|
|
238
|
-
* empty. A `symmetric` entry is admitted only while `publicEgress` is true
|
|
244
|
+
* empty. A `symmetric` entry is admitted only while `publicEgress` is true and only on target
|
|
245
|
+
* ports no other entry of the endpoint publishes to.
|
|
239
246
|
*/
|
|
240
247
|
publishedPorts?: IRuntimeNetworkPublishedPort[];
|
|
241
248
|
}
|
|
@@ -414,6 +421,38 @@ export const isRuntimeNetworkPublishedPortReserved = (value: TPublishedPortSpan)
|
|
|
414
421
|
value.hostPort < runtimeNetworkPublishedPortContract.publishablePorts.first
|
|
415
422
|
|| publishedPortLast(value) > runtimeNetworkPublishedPortContract.publishablePorts.last;
|
|
416
423
|
|
|
424
|
+
type TPublishedPortInside = Pick<IRuntimeNetworkPublishedPortRequest, 'protocol' | 'hostPort' | 'hostPortEnd' | 'targetPort' | 'symmetric'>;
|
|
425
|
+
/** The last workload port an entry publishes to; its inside span starts at `targetPort`. */
|
|
426
|
+
const publishedPortInsideLast = (value: TPublishedPortInside): number =>
|
|
427
|
+
value.targetPort + publishedPortLast(value) - value.hostPort;
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* The first pair of one list in which a `symmetric` entry's inside ports (`targetPort` onwards, a
|
|
431
|
+
* range's every port) share a port with another entry of the same protocol, or `null`: Cloudly's
|
|
432
|
+
* `published-port-symmetric-inside-overlap`.
|
|
433
|
+
*
|
|
434
|
+
* A symmetric entry translates the flows its workload opens from those ports back to its own host
|
|
435
|
+
* ports, so no other entry of the workload may publish to any of them, symmetric or not: the flows
|
|
436
|
+
* would have two published sources. The lists of one service's policy document and of each of its
|
|
437
|
+
* projection endpoints are judged alike, and their snapshots refuse any pair. Distinct protocols
|
|
438
|
+
* never conflict. It judges entries their snapshot already accepted.
|
|
439
|
+
*/
|
|
440
|
+
export const findRuntimeNetworkPublishedPortInsideOverlap = <T extends TPublishedPortInside>(
|
|
441
|
+
ports: readonly T[],
|
|
442
|
+
): { symmetric: T; other: T } | null => {
|
|
443
|
+
for (let index = 0; index < ports.length; index++) {
|
|
444
|
+
const symmetric = ports[index];
|
|
445
|
+
if (symmetric.symmetric !== true) continue;
|
|
446
|
+
const first = symmetric.targetPort, last = publishedPortInsideLast(symmetric);
|
|
447
|
+
for (let other = 0; other < ports.length; other++) {
|
|
448
|
+
const candidate = ports[other];
|
|
449
|
+
if (other !== index && candidate.protocol === symmetric.protocol
|
|
450
|
+
&& candidate.targetPort <= last && first <= publishedPortInsideLast(candidate)) return { symmetric, other: candidate };
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return null;
|
|
454
|
+
};
|
|
455
|
+
|
|
417
456
|
/** The members every published-port entry shares; an optional member is stated only when present. */
|
|
418
457
|
const publishedPortSpan = (item: Record<string, unknown>): IRuntimeNetworkPublishedPortRequest => {
|
|
419
458
|
requireNetwork(item.protocol === 'tcp' || item.protocol === 'udp');
|
|
@@ -426,8 +465,11 @@ const publishedPortSpan = (item: Record<string, unknown>): IRuntimeNetworkPublis
|
|
|
426
465
|
return { protocol: item.protocol, hostPort, ...(hasEnd ? { hostPortEnd } : {}), targetPort,
|
|
427
466
|
...(hasSymmetric ? { symmetric: true as const } : {}) };
|
|
428
467
|
};
|
|
429
|
-
/**
|
|
430
|
-
|
|
468
|
+
/**
|
|
469
|
+
* Sorted, never overlapping within a protocol, bounded in entries and in covered ports, and no
|
|
470
|
+
* symmetric entry sharing an inside port with another entry.
|
|
471
|
+
*/
|
|
472
|
+
const publishedPortList = <T extends TPublishedPortInside>(value: unknown, read: (item: unknown) => T): T[] => {
|
|
431
473
|
const ports = networkSorted(networkList(value, runtimeNetworkPublishedPortContract.maximumEntries, read), publishedPortKey);
|
|
432
474
|
let covered = 0;
|
|
433
475
|
ports.forEach((port, index) => {
|
|
@@ -436,6 +478,7 @@ const publishedPortList = <T extends TPublishedPortSpan>(value: unknown, read: (
|
|
|
436
478
|
covered += publishedPortLast(port) - port.hostPort + 1;
|
|
437
479
|
});
|
|
438
480
|
requireNetwork(covered <= runtimeNetworkPublishedPortContract.maximumPortsPerService);
|
|
481
|
+
requireNetwork(findRuntimeNetworkPublishedPortInsideOverlap(ports) === null);
|
|
439
482
|
return ports;
|
|
440
483
|
};
|
|
441
484
|
const publishedPort = (value: unknown): IRuntimeNetworkPublishedPort => {
|
package/ts/requests/admin.ts
CHANGED
|
@@ -4,6 +4,10 @@ import type {
|
|
|
4
4
|
IServiceMachineCredentialMetadata, IServiceMachineCredentialMutationResult,
|
|
5
5
|
TServiceMachineCredentialMutation,
|
|
6
6
|
} from '../data/servicecredential.js';
|
|
7
|
+
import type {
|
|
8
|
+
IDeploymentMachineUserMetadata, IDeploymentMachineUserMutationResult,
|
|
9
|
+
TDeploymentMachineUserMutation,
|
|
10
|
+
} from '../data/deploymentmachineuser.js';
|
|
7
11
|
|
|
8
12
|
export interface IReq_Admin_GetServiceMachineCredential extends plugins.typedrequestInterfaces.implementsTR<
|
|
9
13
|
plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_GetServiceMachineCredential
|
|
@@ -84,6 +88,39 @@ export interface IReq_Admin_LoginWithUsernameAndPassword extends plugins.typedre
|
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Lists every deployment machine user, value-free: no token value is ever answered here.
|
|
93
|
+
* Requires an administrator; refusals travel as `IDeploymentMachineUserErrorData`.
|
|
94
|
+
*/
|
|
95
|
+
export interface IReq_Admin_GetDeploymentMachineUsers extends plugins.typedrequestInterfaces.implementsTR<
|
|
96
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_GetDeploymentMachineUsers
|
|
97
|
+
> {
|
|
98
|
+
method: 'getDeploymentMachineUsers';
|
|
99
|
+
request: { identity: IIdentityCredential };
|
|
100
|
+
response: { users: IDeploymentMachineUserMetadata[] };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a deployment machine user, or rotates or revokes its token.
|
|
105
|
+
*
|
|
106
|
+
* Requires an administrator. The token is answered exactly once, on the first answer to `create`
|
|
107
|
+
* or `rotate-token`; a replay of the same mutation ID by the same administrator answers the
|
|
108
|
+
* historical metadata with `token: null` and never issues another token. Grants are attached with
|
|
109
|
+
* `configureServiceDeploymentMachineUser`. Refusals travel as `IDeploymentMachineUserErrorData`.
|
|
110
|
+
*/
|
|
111
|
+
export interface IReq_Admin_MutateDeploymentMachineUser extends plugins.typedrequestInterfaces.implementsTR<
|
|
112
|
+
plugins.typedrequestInterfaces.ITypedRequest, IReq_Admin_MutateDeploymentMachineUser
|
|
113
|
+
> {
|
|
114
|
+
method: 'mutateDeploymentMachineUser';
|
|
115
|
+
request: { identity: IIdentityCredential; mutation: TDeploymentMachineUserMutation };
|
|
116
|
+
response: IDeploymentMachineUserMutationResult;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Attaches one deployment grant to a deployment machine user that holds a token, replacing the
|
|
121
|
+
* grant it held for the same organization and service. `mutateDeploymentMachineUser` creates such
|
|
122
|
+
* a user.
|
|
123
|
+
*/
|
|
87
124
|
export interface IReq_Admin_ConfigureServiceDeploymentMachineUser
|
|
88
125
|
extends plugins.typedrequestInterfaces.implementsTR<
|
|
89
126
|
plugins.typedrequestInterfaces.ITypedRequest,
|
package/ts/requests/service.ts
CHANGED
|
@@ -231,6 +231,14 @@ extends plugins.typedrequestInterfaces.implementsTR<
|
|
|
231
231
|
};
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Reserves one immutable deployment for the authenticated deployment machine user.
|
|
236
|
+
*
|
|
237
|
+
* Only an API machine user can complete the operation it reserves, because only its registry
|
|
238
|
+
* push is bound to that operation. An actor that is not an API machine user, an administrator
|
|
239
|
+
* included, is refused with the code `DEPLOYMENT_MACHINE_IDENTITY_REQUIRED` before anything is
|
|
240
|
+
* reserved.
|
|
241
|
+
*/
|
|
234
242
|
export interface IRequest_Any_Cloudly_ReserveServiceDeployment
|
|
235
243
|
extends plugins.typedrequestInterfaces.implementsTR<
|
|
236
244
|
plugins.typedrequestInterfaces.ITypedRequest,
|