@highstate/k8s 0.9.3 → 0.9.5
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/dist/chunk-DQSCJM5S.js +183 -0
- package/dist/chunk-DQSCJM5S.js.map +1 -0
- package/dist/chunk-FKNHHKOL.js +260 -0
- package/dist/chunk-FKNHHKOL.js.map +1 -0
- package/dist/chunk-HW3NS3MC.js +347 -0
- package/dist/chunk-HW3NS3MC.js.map +1 -0
- package/dist/chunk-OQ7UXASD.js +193 -0
- package/dist/chunk-OQ7UXASD.js.map +1 -0
- package/dist/chunk-QGHMLKTW.js +1123 -0
- package/dist/chunk-QGHMLKTW.js.map +1 -0
- package/dist/chunk-UNVSWG6D.js +214 -0
- package/dist/chunk-UNVSWG6D.js.map +1 -0
- package/dist/deployment-ZP3ASKPT.js +10 -0
- package/dist/deployment-ZP3ASKPT.js.map +1 -0
- package/dist/highstate.manifest.json +8 -6
- package/dist/index.js +291 -954
- package/dist/index.js.map +1 -1
- package/dist/stateful-set-2AH7RAF7.js +10 -0
- package/dist/stateful-set-2AH7RAF7.js.map +1 -0
- package/dist/units/access-point/index.js +6 -1
- package/dist/units/access-point/index.js.map +1 -1
- package/dist/units/cert-manager/index.js +19 -24
- package/dist/units/cert-manager/index.js.map +1 -1
- package/dist/units/cluster-dns/index.js +36 -0
- package/dist/units/cluster-dns/index.js.map +1 -0
- package/dist/units/cluster-patch/index.js +34 -0
- package/dist/units/cluster-patch/index.js.map +1 -0
- package/dist/units/dns01-issuer/index.js +2 -2
- package/dist/units/dns01-issuer/index.js.map +1 -1
- package/dist/units/existing-cluster/index.js +23 -15
- package/dist/units/existing-cluster/index.js.map +1 -1
- package/dist/units/gateway-api/index.js +1 -1
- package/package.json +12 -10
- package/src/access-point.ts +44 -39
- package/src/container.ts +54 -5
- package/src/cron-job.ts +14 -30
- package/src/deployment.ts +170 -127
- package/src/gateway/http-route.ts +7 -5
- package/src/helm.ts +57 -8
- package/src/index.ts +11 -4
- package/src/job.ts +14 -32
- package/src/namespace.ts +241 -0
- package/src/network-policy.ts +371 -87
- package/src/network.ts +41 -0
- package/src/pvc.ts +43 -25
- package/src/scripting/bundle.ts +125 -22
- package/src/scripting/container.ts +16 -11
- package/src/scripting/environment.ts +56 -6
- package/src/secret.ts +195 -0
- package/src/service.ts +209 -89
- package/src/shared.ts +42 -51
- package/src/stateful-set.ts +193 -88
- package/src/units/access-point/index.ts +8 -1
- package/src/units/cert-manager/index.ts +15 -20
- package/src/units/cluster-dns/index.ts +37 -0
- package/src/units/cluster-patch/index.ts +35 -0
- package/src/units/dns01-issuer/index.ts +1 -1
- package/src/units/existing-cluster/index.ts +26 -15
- package/src/workload.ts +342 -44
- package/dist/chunk-K4WKJ4L5.js +0 -455
- package/dist/chunk-K4WKJ4L5.js.map +0 -1
- package/dist/chunk-T5Z2M4JE.js +0 -103
- package/dist/chunk-T5Z2M4JE.js.map +0 -1
package/dist/index.js
CHANGED
@@ -1,861 +1,66 @@
|
|
1
|
+
import {
|
2
|
+
StatefulSet
|
3
|
+
} from "./chunk-OQ7UXASD.js";
|
4
|
+
import {
|
5
|
+
Deployment
|
6
|
+
} from "./chunk-DQSCJM5S.js";
|
7
|
+
import {
|
8
|
+
ExposableWorkload,
|
9
|
+
NetworkPolicy,
|
10
|
+
PersistentVolumeClaim,
|
11
|
+
Secret,
|
12
|
+
Workload,
|
13
|
+
getWorkloadComponents
|
14
|
+
} from "./chunk-QGHMLKTW.js";
|
1
15
|
import {
|
2
16
|
Chart,
|
3
|
-
HttpRoute,
|
4
17
|
RenderedChart,
|
5
|
-
Service,
|
6
18
|
getChartService,
|
7
19
|
getChartServiceOutput,
|
20
|
+
resolveHelmChart
|
21
|
+
} from "./chunk-UNVSWG6D.js";
|
22
|
+
import {
|
23
|
+
HttpRoute,
|
24
|
+
Service,
|
25
|
+
getServiceMetadata,
|
26
|
+
hasServiceMetadata,
|
27
|
+
isFromCluster,
|
8
28
|
mapContainerPortToServicePort,
|
9
29
|
mapServiceToLabelSelector,
|
10
|
-
|
11
|
-
} from "./chunk-
|
30
|
+
withServiceMetadata
|
31
|
+
} from "./chunk-HW3NS3MC.js";
|
12
32
|
import {
|
13
33
|
createK8sTerminal,
|
14
34
|
detectExternalIps
|
15
35
|
} from "./chunk-QLQ3QVGT.js";
|
16
36
|
import {
|
37
|
+
Namespace,
|
17
38
|
commonExtraArgs,
|
18
|
-
createNamespace,
|
19
39
|
getAppDisplayName,
|
20
40
|
getAppName,
|
21
|
-
getNamespace,
|
22
41
|
getProvider,
|
23
42
|
mapMetadata,
|
24
43
|
mapNamespaceLikeToNamespaceName,
|
25
44
|
mapNamespaceNameToSelector,
|
26
|
-
mapSelectorLikeToSelector
|
27
|
-
|
28
|
-
verifyProvider
|
29
|
-
} from "./chunk-T5Z2M4JE.js";
|
30
|
-
|
31
|
-
// src/deployment.ts
|
32
|
-
import {
|
33
|
-
output as output4,
|
34
|
-
ComponentResource as ComponentResource3,
|
35
|
-
interpolate
|
36
|
-
} from "@highstate/pulumi";
|
37
|
-
import { apps } from "@pulumi/kubernetes";
|
38
|
-
import { omit as omit3 } from "remeda";
|
39
|
-
import { deepmerge as deepmerge2 } from "deepmerge-ts";
|
40
|
-
import { trimIndentation } from "@highstate/contract";
|
41
|
-
|
42
|
-
// src/container.ts
|
43
|
-
import { core as core2 } from "@pulumi/kubernetes";
|
44
|
-
import { normalize, output as output2 } from "@highstate/pulumi";
|
45
|
-
import { concat, map, omit as omit2 } from "remeda";
|
46
|
-
|
47
|
-
// src/pvc.ts
|
48
|
-
import { core } from "@pulumi/kubernetes";
|
49
|
-
import {
|
50
|
-
ComponentResource,
|
51
|
-
output
|
52
|
-
} from "@highstate/pulumi";
|
53
|
-
import { deepmerge } from "deepmerge-ts";
|
54
|
-
import { omit } from "remeda";
|
55
|
-
var extraPersistentVolumeClaimArgs = [...commonExtraArgs, "size", "cluster"];
|
56
|
-
var PersistentVolumeClaim = class extends ComponentResource {
|
57
|
-
constructor(type, name, args, opts, clusterInfo, metadata, spec, status) {
|
58
|
-
super(type, name, args, opts);
|
59
|
-
this.clusterInfo = clusterInfo;
|
60
|
-
this.metadata = metadata;
|
61
|
-
this.spec = spec;
|
62
|
-
this.status = status;
|
63
|
-
}
|
64
|
-
/**
|
65
|
-
* The Highstate service entity.
|
66
|
-
*/
|
67
|
-
get entity() {
|
68
|
-
return output({
|
69
|
-
type: "k8s.persistent-volume-claim",
|
70
|
-
clusterInfo: this.clusterInfo,
|
71
|
-
metadata: this.metadata
|
72
|
-
});
|
73
|
-
}
|
74
|
-
static create(name, args, opts) {
|
75
|
-
return new CreatedPersistentVolumeClaim(name, args, opts);
|
76
|
-
}
|
77
|
-
static of(name, entity, opts) {
|
78
|
-
return new ExternalPersistentVolumeClaim(
|
79
|
-
name,
|
80
|
-
output(entity).metadata,
|
81
|
-
output(entity).clusterInfo,
|
82
|
-
opts
|
83
|
-
);
|
84
|
-
}
|
85
|
-
};
|
86
|
-
var CreatedPersistentVolumeClaim = class extends PersistentVolumeClaim {
|
87
|
-
constructor(name, args, opts) {
|
88
|
-
const pvc = output(args).apply((args2) => {
|
89
|
-
return new core.v1.PersistentVolumeClaim(
|
90
|
-
name,
|
91
|
-
{
|
92
|
-
metadata: mapMetadata(args2, name),
|
93
|
-
spec: deepmerge(
|
94
|
-
{
|
95
|
-
accessModes: ["ReadWriteOnce"],
|
96
|
-
resources: {
|
97
|
-
requests: {
|
98
|
-
storage: args2.size ?? "100Mi"
|
99
|
-
}
|
100
|
-
}
|
101
|
-
},
|
102
|
-
omit(args2, extraPersistentVolumeClaimArgs)
|
103
|
-
)
|
104
|
-
},
|
105
|
-
opts
|
106
|
-
);
|
107
|
-
});
|
108
|
-
super(
|
109
|
-
"k8s:PersistentVolumeClaim",
|
110
|
-
name,
|
111
|
-
args,
|
112
|
-
opts,
|
113
|
-
output(args.cluster).info,
|
114
|
-
pvc.metadata,
|
115
|
-
pvc.spec,
|
116
|
-
pvc.status
|
117
|
-
);
|
118
|
-
}
|
119
|
-
};
|
120
|
-
var ExternalPersistentVolumeClaim = class extends PersistentVolumeClaim {
|
121
|
-
constructor(name, id, clusterInfo, opts) {
|
122
|
-
const pvc = output(id).apply(async (id2) => {
|
123
|
-
await verifyProvider(opts.provider, this.clusterInfo);
|
124
|
-
return core.v1.PersistentVolumeClaim.get(
|
125
|
-
//
|
126
|
-
name,
|
127
|
-
resourceIdToString(id2),
|
128
|
-
{ parent: this, provider: opts.provider }
|
129
|
-
);
|
130
|
-
});
|
131
|
-
super(
|
132
|
-
"highstate:k8s:ExternalPersistentVolumeClaim",
|
133
|
-
name,
|
134
|
-
{ id, clusterInfo },
|
135
|
-
opts,
|
136
|
-
output(clusterInfo),
|
137
|
-
pvc.metadata,
|
138
|
-
pvc.spec,
|
139
|
-
pvc.status
|
140
|
-
);
|
141
|
-
}
|
142
|
-
};
|
143
|
-
|
144
|
-
// src/container.ts
|
145
|
-
var containerExtraArgs = [
|
146
|
-
"port",
|
147
|
-
"volumeMount",
|
148
|
-
"volume",
|
149
|
-
"environment",
|
150
|
-
"environmentSource",
|
151
|
-
"environmentSources"
|
152
|
-
];
|
153
|
-
function mapContainerToRaw(container, fallbackName) {
|
154
|
-
const containerName = container.name ?? fallbackName;
|
155
|
-
return {
|
156
|
-
...omit2(container, containerExtraArgs),
|
157
|
-
name: containerName,
|
158
|
-
ports: normalize(container.port, container.ports),
|
159
|
-
volumeMounts: map(normalize(container.volumeMount, container.volumeMounts), mapVolumeMount),
|
160
|
-
env: concat(
|
161
|
-
container.environment ? mapContainerEnvironment(container.environment) : [],
|
162
|
-
container.env ?? []
|
163
|
-
),
|
164
|
-
envFrom: concat(
|
165
|
-
map(
|
166
|
-
normalize(container.environmentSource, container.environmentSources),
|
167
|
-
mapEnvironmentSource
|
168
|
-
),
|
169
|
-
container.envFrom ?? []
|
170
|
-
)
|
171
|
-
};
|
172
|
-
}
|
173
|
-
function mapContainerEnvironment(environment) {
|
174
|
-
const envVars = [];
|
175
|
-
for (const [name, value] of Object.entries(environment)) {
|
176
|
-
if (!value) {
|
177
|
-
continue;
|
178
|
-
}
|
179
|
-
if (typeof value === "string") {
|
180
|
-
envVars.push({ name, value });
|
181
|
-
continue;
|
182
|
-
}
|
183
|
-
if ("secret" in value) {
|
184
|
-
envVars.push({
|
185
|
-
name,
|
186
|
-
valueFrom: {
|
187
|
-
secretKeyRef: {
|
188
|
-
name: value.secret.metadata.name,
|
189
|
-
key: value.key
|
190
|
-
}
|
191
|
-
}
|
192
|
-
});
|
193
|
-
continue;
|
194
|
-
}
|
195
|
-
if ("configMap" in value) {
|
196
|
-
envVars.push({
|
197
|
-
name,
|
198
|
-
valueFrom: {
|
199
|
-
configMapKeyRef: {
|
200
|
-
name: value.configMap.metadata.name,
|
201
|
-
key: value.key
|
202
|
-
}
|
203
|
-
}
|
204
|
-
});
|
205
|
-
continue;
|
206
|
-
}
|
207
|
-
envVars.push({ name, valueFrom: value });
|
208
|
-
}
|
209
|
-
return envVars;
|
210
|
-
}
|
211
|
-
function mapVolumeMount(volumeMount) {
|
212
|
-
if ("volume" in volumeMount) {
|
213
|
-
return omit2(
|
214
|
-
{
|
215
|
-
...volumeMount,
|
216
|
-
name: output2(volumeMount.volume).apply(mapWorkloadVolume).apply((volume) => output2(volume.name))
|
217
|
-
},
|
218
|
-
["volume"]
|
219
|
-
);
|
220
|
-
}
|
221
|
-
return {
|
222
|
-
...volumeMount,
|
223
|
-
name: volumeMount.name
|
224
|
-
};
|
225
|
-
}
|
226
|
-
function mapEnvironmentSource(envFrom) {
|
227
|
-
if (envFrom instanceof core2.v1.ConfigMap) {
|
228
|
-
return {
|
229
|
-
configMapRef: {
|
230
|
-
name: envFrom.metadata.name
|
231
|
-
}
|
232
|
-
};
|
233
|
-
}
|
234
|
-
if (envFrom instanceof core2.v1.Secret) {
|
235
|
-
return {
|
236
|
-
secretRef: {
|
237
|
-
name: envFrom.metadata.name
|
238
|
-
}
|
239
|
-
};
|
240
|
-
}
|
241
|
-
return envFrom;
|
242
|
-
}
|
243
|
-
function mapWorkloadVolume(volume) {
|
244
|
-
if (volume instanceof PersistentVolumeClaim) {
|
245
|
-
return {
|
246
|
-
name: volume.metadata.name,
|
247
|
-
persistentVolumeClaim: {
|
248
|
-
claimName: volume.metadata.name
|
249
|
-
}
|
250
|
-
};
|
251
|
-
}
|
252
|
-
if (volume instanceof core2.v1.PersistentVolumeClaim) {
|
253
|
-
return {
|
254
|
-
name: volume.metadata.name,
|
255
|
-
persistentVolumeClaim: {
|
256
|
-
claimName: volume.metadata.name
|
257
|
-
}
|
258
|
-
};
|
259
|
-
}
|
260
|
-
if (volume instanceof core2.v1.ConfigMap) {
|
261
|
-
return {
|
262
|
-
name: volume.metadata.name,
|
263
|
-
configMap: {
|
264
|
-
name: volume.metadata.name
|
265
|
-
}
|
266
|
-
};
|
267
|
-
}
|
268
|
-
if (volume instanceof core2.v1.Secret) {
|
269
|
-
return {
|
270
|
-
name: volume.metadata.name,
|
271
|
-
secret: {
|
272
|
-
secretName: volume.metadata.name
|
273
|
-
}
|
274
|
-
};
|
275
|
-
}
|
276
|
-
return volume;
|
277
|
-
}
|
278
|
-
|
279
|
-
// src/workload.ts
|
280
|
-
import { normalize as normalize2 } from "@highstate/pulumi";
|
281
|
-
import { ComponentResource as ComponentResource2, output as output3 } from "@pulumi/pulumi";
|
282
|
-
import { uniqueBy } from "remeda";
|
283
|
-
var workloadExtraArgs = [...commonExtraArgs, "container", "containers"];
|
284
|
-
var publicWorkloadExtraArgs = [...workloadExtraArgs, "service", "httpRoute"];
|
285
|
-
function getWorkloadComponents(name, args) {
|
286
|
-
const labels = {
|
287
|
-
"app.kubernetes.io/name": name
|
288
|
-
};
|
289
|
-
const containers = output3(args).apply((args2) => normalize2(args2.container, args2.containers));
|
290
|
-
const volumes = containers.apply((containers2) => {
|
291
|
-
const containerVolumes = containers2.flatMap((container) => normalize2(container.volume, container.volumes)).map(mapWorkloadVolume);
|
292
|
-
const containerVolumeMounts = containers2.flatMap((container) => {
|
293
|
-
return normalize2(container.volumeMount, container.volumeMounts).map((volumeMount) => {
|
294
|
-
return "volume" in volumeMount ? volumeMount.volume : void 0;
|
295
|
-
}).filter(Boolean);
|
296
|
-
}).map(mapWorkloadVolume);
|
297
|
-
return uniqueBy([...containerVolumes, ...containerVolumeMounts], (volume) => volume.name);
|
298
|
-
});
|
299
|
-
return { labels, containers, volumes };
|
300
|
-
}
|
301
|
-
function getPublicWorkloadComponents(name, args, parent, opts) {
|
302
|
-
const { labels, containers, volumes } = getWorkloadComponents(name, args);
|
303
|
-
const service = output3({ args, containers }).apply(({ args: args2, containers: containers2 }) => {
|
304
|
-
if (!args2.service && !args2.httpRoute) {
|
305
|
-
return void 0;
|
306
|
-
}
|
307
|
-
if (args2.patch?.service) {
|
308
|
-
return Service.of(name, args2.patch.service, { parent: parent(), ...opts });
|
309
|
-
}
|
310
|
-
if (args2.patch) {
|
311
|
-
return void 0;
|
312
|
-
}
|
313
|
-
const ports = containers2.flatMap((container) => normalize2(container.port, container.ports));
|
314
|
-
return Service.create(
|
315
|
-
name,
|
316
|
-
{
|
317
|
-
...args2.service,
|
318
|
-
selector: labels,
|
319
|
-
cluster: args2.cluster,
|
320
|
-
namespace: args2.namespace,
|
321
|
-
ports: (
|
322
|
-
// allow to completely override the ports
|
323
|
-
!args2.service?.port && !args2.service?.ports ? ports.map(mapContainerPortToServicePort) : args2.service?.ports
|
324
|
-
)
|
325
|
-
},
|
326
|
-
{ parent: parent(), ...opts }
|
327
|
-
);
|
328
|
-
});
|
329
|
-
const httpRoute = output3({
|
330
|
-
args,
|
331
|
-
service
|
332
|
-
}).apply(({ args: args2, service: service2 }) => {
|
333
|
-
if (!args2.httpRoute || !service2) {
|
334
|
-
return void 0;
|
335
|
-
}
|
336
|
-
if (args2.patch) {
|
337
|
-
return void 0;
|
338
|
-
}
|
339
|
-
return new HttpRoute(
|
340
|
-
name,
|
341
|
-
{
|
342
|
-
...args2.httpRoute,
|
343
|
-
rule: {
|
344
|
-
backend: service2
|
345
|
-
}
|
346
|
-
},
|
347
|
-
{ parent: parent(), ...opts }
|
348
|
-
);
|
349
|
-
});
|
350
|
-
return { labels, containers, volumes, service, httpRoute };
|
351
|
-
}
|
352
|
-
|
353
|
-
// src/deployment.ts
|
354
|
-
var Deployment = class extends ComponentResource3 {
|
355
|
-
constructor(type, name, args, opts, cluster, metadata, spec, status, _service, _httpRoute, resources) {
|
356
|
-
super(type, name, args, opts);
|
357
|
-
this.args = args;
|
358
|
-
this.cluster = cluster;
|
359
|
-
this.metadata = metadata;
|
360
|
-
this.spec = spec;
|
361
|
-
this.status = status;
|
362
|
-
this._service = _service;
|
363
|
-
this._httpRoute = _httpRoute;
|
364
|
-
this.resources = resources;
|
365
|
-
}
|
366
|
-
/**
|
367
|
-
* The Highstate deployment entity.
|
368
|
-
*/
|
369
|
-
get entity() {
|
370
|
-
return output4({
|
371
|
-
type: "k8s.deployment",
|
372
|
-
clusterInfo: this.cluster.info,
|
373
|
-
metadata: this.metadata,
|
374
|
-
spec: this.spec,
|
375
|
-
service: this._service.apply((service) => service?.entity)
|
376
|
-
});
|
377
|
-
}
|
378
|
-
get optionalService() {
|
379
|
-
return this._service;
|
380
|
-
}
|
381
|
-
/**
|
382
|
-
* The service associated with the deployment.
|
383
|
-
*/
|
384
|
-
get service() {
|
385
|
-
return this._service.apply((service) => {
|
386
|
-
if (!service) {
|
387
|
-
throw new Error("The service is not available.");
|
388
|
-
}
|
389
|
-
return service;
|
390
|
-
});
|
391
|
-
}
|
392
|
-
/**
|
393
|
-
* The HTTP route associated with the deployment.
|
394
|
-
*/
|
395
|
-
get httpRoute() {
|
396
|
-
return this._httpRoute.apply((httpRoute) => {
|
397
|
-
if (!httpRoute) {
|
398
|
-
throw new Error("The HTTP route is not available.");
|
399
|
-
}
|
400
|
-
return httpRoute;
|
401
|
-
});
|
402
|
-
}
|
403
|
-
/**
|
404
|
-
* The instance terminal to interact with the deployment.
|
405
|
-
*/
|
406
|
-
get terminal() {
|
407
|
-
return output4({
|
408
|
-
name: this.metadata.name,
|
409
|
-
title: this.metadata.name,
|
410
|
-
image: "ghcr.io/exeteres/highstate/terminal-kubectl",
|
411
|
-
command: ["script", "-q", "-c", "/enter-container.sh", "/dev/null"],
|
412
|
-
files: {
|
413
|
-
"/kubeconfig": this.cluster.kubeconfig,
|
414
|
-
"/enter-container.sh": {
|
415
|
-
mode: 493,
|
416
|
-
content: interpolate`
|
417
|
-
#!/bin/bash
|
418
|
-
|
419
|
-
exec kubectl exec -it -n ${this.metadata.namespace} deployment/${this.metadata.name} -- ${this.args.terminalShell ?? "bash"}
|
420
|
-
`.apply(trimIndentation)
|
421
|
-
}
|
422
|
-
},
|
423
|
-
env: {
|
424
|
-
KUBECONFIG: "/kubeconfig"
|
425
|
-
}
|
426
|
-
});
|
427
|
-
}
|
428
|
-
static create(name, args, opts) {
|
429
|
-
return new CreatedDeployment(name, args, opts);
|
430
|
-
}
|
431
|
-
};
|
432
|
-
var CreatedDeployment = class extends Deployment {
|
433
|
-
constructor(name, args, opts) {
|
434
|
-
const { labels, containers, volumes, service, httpRoute } = getPublicWorkloadComponents(
|
435
|
-
name,
|
436
|
-
args,
|
437
|
-
() => this,
|
438
|
-
opts
|
439
|
-
);
|
440
|
-
const deployment = output4({ args, containers, volumes }).apply(
|
441
|
-
async ({ args: args2, containers: containers2, volumes: volumes2 }) => {
|
442
|
-
await verifyProvider(opts.provider, args2.cluster.info);
|
443
|
-
return new (args2.patch ? apps.v1.DeploymentPatch : apps.v1.Deployment)(
|
444
|
-
name,
|
445
|
-
{
|
446
|
-
metadata: mapMetadata(args2.patch?.metadata ?? args2, name),
|
447
|
-
spec: deepmerge2(
|
448
|
-
{
|
449
|
-
template: {
|
450
|
-
metadata: !args2.patch ? { labels } : void 0,
|
451
|
-
spec: {
|
452
|
-
containers: containers2.map((container) => mapContainerToRaw(container, name)),
|
453
|
-
volumes: volumes2
|
454
|
-
}
|
455
|
-
},
|
456
|
-
selector: !args2.patch ? { matchLabels: labels } : void 0
|
457
|
-
},
|
458
|
-
omit3(args2, publicWorkloadExtraArgs)
|
459
|
-
)
|
460
|
-
},
|
461
|
-
{ parent: this, ...opts }
|
462
|
-
);
|
463
|
-
}
|
464
|
-
);
|
465
|
-
super(
|
466
|
-
"highstate:k8s:Deployment",
|
467
|
-
name,
|
468
|
-
args,
|
469
|
-
opts,
|
470
|
-
output4(args.cluster),
|
471
|
-
deployment.metadata,
|
472
|
-
deployment.spec,
|
473
|
-
deployment.status,
|
474
|
-
service,
|
475
|
-
httpRoute,
|
476
|
-
[deployment]
|
477
|
-
);
|
478
|
-
}
|
479
|
-
};
|
480
|
-
|
481
|
-
// src/stateful-set.ts
|
482
|
-
import {
|
483
|
-
output as output5,
|
484
|
-
ComponentResource as ComponentResource4
|
485
|
-
} from "@highstate/pulumi";
|
486
|
-
import { apps as apps2 } from "@pulumi/kubernetes";
|
487
|
-
import { omit as omit4 } from "remeda";
|
488
|
-
import { deepmerge as deepmerge3 } from "deepmerge-ts";
|
489
|
-
var StatefulSet = class extends ComponentResource4 {
|
490
|
-
constructor(type, name, args, opts, clusterInfo, metadata, spec, status, _service, _httpRoute) {
|
491
|
-
super(type, name, args, opts);
|
492
|
-
this.clusterInfo = clusterInfo;
|
493
|
-
this.metadata = metadata;
|
494
|
-
this.spec = spec;
|
495
|
-
this.status = status;
|
496
|
-
this._service = _service;
|
497
|
-
this._httpRoute = _httpRoute;
|
498
|
-
}
|
499
|
-
/**
|
500
|
-
* The Highstate stateful set entity.
|
501
|
-
*/
|
502
|
-
get entity() {
|
503
|
-
return output5({
|
504
|
-
type: "k8s.stateful-set",
|
505
|
-
clusterInfo: this.clusterInfo,
|
506
|
-
metadata: this.metadata,
|
507
|
-
service: this.service.entity
|
508
|
-
});
|
509
|
-
}
|
510
|
-
get optionalService() {
|
511
|
-
return this._service;
|
512
|
-
}
|
513
|
-
/**
|
514
|
-
* The service associated with the stateful set.
|
515
|
-
*/
|
516
|
-
get service() {
|
517
|
-
return this._service.apply((service) => {
|
518
|
-
if (!service) {
|
519
|
-
throw new Error("The service is not available.");
|
520
|
-
}
|
521
|
-
return service;
|
522
|
-
});
|
523
|
-
}
|
524
|
-
/**
|
525
|
-
* The HTTP route associated with the stateful set.
|
526
|
-
*/
|
527
|
-
get httpRoute() {
|
528
|
-
return this._httpRoute.apply((httpRoute) => {
|
529
|
-
if (!httpRoute) {
|
530
|
-
throw new Error("The HTTP route is not available.");
|
531
|
-
}
|
532
|
-
return httpRoute;
|
533
|
-
});
|
534
|
-
}
|
535
|
-
static create(name, args, opts) {
|
536
|
-
return new CreatedStatefulSet(name, args, opts);
|
537
|
-
}
|
538
|
-
};
|
539
|
-
var CreatedStatefulSet = class extends StatefulSet {
|
540
|
-
constructor(name, args, opts) {
|
541
|
-
const { containers, volumes, labels, service, httpRoute } = getPublicWorkloadComponents(
|
542
|
-
name,
|
543
|
-
args,
|
544
|
-
() => this,
|
545
|
-
opts
|
546
|
-
);
|
547
|
-
const statefulSet = output5({ args, containers, volumes, service }).apply(
|
548
|
-
async ({ args: args2, containers: containers2, volumes: volumes2, service: service2 }) => {
|
549
|
-
await verifyProvider(opts.provider, args2.cluster?.info);
|
550
|
-
return new (args2.patch ? apps2.v1.StatefulSetPatch : apps2.v1.StatefulSet)(
|
551
|
-
name,
|
552
|
-
{
|
553
|
-
metadata: mapMetadata(args2.patch?.metadata ?? args2, name),
|
554
|
-
spec: deepmerge3(
|
555
|
-
{
|
556
|
-
serviceName: service2?.metadata.name || name,
|
557
|
-
template: {
|
558
|
-
metadata: !args2.patch ? { labels } : void 0,
|
559
|
-
spec: {
|
560
|
-
containers: containers2.map((container) => mapContainerToRaw(container, name)),
|
561
|
-
volumes: volumes2
|
562
|
-
}
|
563
|
-
},
|
564
|
-
selector: !args2.patch ? { matchLabels: labels } : void 0
|
565
|
-
},
|
566
|
-
omit4(args2, publicWorkloadExtraArgs)
|
567
|
-
)
|
568
|
-
},
|
569
|
-
{ parent: this, ...opts }
|
570
|
-
);
|
571
|
-
}
|
572
|
-
);
|
573
|
-
super(
|
574
|
-
"highstate:k8s:StatefulSet",
|
575
|
-
name,
|
576
|
-
args,
|
577
|
-
opts,
|
578
|
-
output5(args.cluster).info,
|
579
|
-
statefulSet.metadata,
|
580
|
-
statefulSet.spec,
|
581
|
-
statefulSet.status,
|
582
|
-
service,
|
583
|
-
httpRoute
|
584
|
-
);
|
585
|
-
}
|
586
|
-
};
|
587
|
-
|
588
|
-
// src/network-policy.ts
|
589
|
-
import { networking } from "@pulumi/kubernetes";
|
590
|
-
import {
|
591
|
-
ComponentResource as ComponentResource5,
|
592
|
-
normalize as normalize3,
|
593
|
-
output as output6
|
594
|
-
} from "@highstate/pulumi";
|
595
|
-
import { capitalize, flat, merge, mergeDeep } from "remeda";
|
596
|
-
import { parseDomain, ParseResultType } from "parse-domain";
|
597
|
-
import "@highstate/library";
|
598
|
-
var NetworkPolicy = class _NetworkPolicy extends ComponentResource5 {
|
599
|
-
/**
|
600
|
-
* The underlying network policy resource.
|
601
|
-
*/
|
602
|
-
networkPolicy;
|
603
|
-
constructor(name, args, opts) {
|
604
|
-
super("k8s:network-policy", name, args, opts);
|
605
|
-
const normalizedArgs = output6(args).apply((args2) => {
|
606
|
-
const ingressRules = normalize3(args2.ingressRule, args2.ingressRules);
|
607
|
-
const egressRules = normalize3(args2.egressRule, args2.egressRules);
|
608
|
-
const endpoints = normalize3(args2.egressRule?.toEndpoint, args2.egressRule?.toEndpoints);
|
609
|
-
const parsedEndpoints = endpoints.map((endpoint) => parseDomain(endpoint));
|
610
|
-
const cidrsFromEndpoints = parsedEndpoints.filter((result) => result.type === ParseResultType.Ip).map((result) => _NetworkPolicy.mapCidrFromEndpoint(result));
|
611
|
-
const fqdnsFromEndpoints = parsedEndpoints.filter((result) => result.type !== ParseResultType.Invalid).map((result) => result.hostname);
|
612
|
-
const extraEgressRules = [];
|
613
|
-
if (args2.allowKubeDns) {
|
614
|
-
extraEgressRules.push({
|
615
|
-
namespaces: ["kube-system"],
|
616
|
-
selectors: [{ matchLabels: { "k8s-app": "kube-dns" } }],
|
617
|
-
ports: [{ port: 53, protocol: "UDP" }],
|
618
|
-
all: false,
|
619
|
-
cidrs: [],
|
620
|
-
fqdns: [],
|
621
|
-
services: []
|
622
|
-
});
|
623
|
-
}
|
624
|
-
return {
|
625
|
-
...args2,
|
626
|
-
podSelector: args2.selector ? mapSelectorLikeToSelector(args2.selector) : {},
|
627
|
-
isolateEgress: args2.isolateEgress ?? false,
|
628
|
-
isolateIngress: args2.isolateIngress ?? false,
|
629
|
-
allowKubeApiServer: args2.allowKubeApiServer ?? false,
|
630
|
-
ingressRules: ingressRules.map((rule) => ({
|
631
|
-
all: rule.fromAll ?? false,
|
632
|
-
cidrs: normalize3(rule.fromCidr, rule.fromCidrs),
|
633
|
-
fqdns: [],
|
634
|
-
services: normalize3(rule.fromService, rule.fromServices),
|
635
|
-
namespaces: normalize3(rule.fromNamespace, rule.fromNamespaces),
|
636
|
-
selectors: normalize3(rule.fromSelector, rule.fromSelectors),
|
637
|
-
ports: normalize3(rule.toPort, rule.toPorts)
|
638
|
-
})),
|
639
|
-
egressRules: egressRules.map((rule) => {
|
640
|
-
return {
|
641
|
-
all: rule.toAll ?? false,
|
642
|
-
cidrs: normalize3(rule.toCidr, rule.toCidrs).concat(cidrsFromEndpoints),
|
643
|
-
fqdns: normalize3(rule.toFqdn, rule.toFqdns).concat(fqdnsFromEndpoints),
|
644
|
-
services: normalize3(rule.toService, rule.toServices),
|
645
|
-
namespaces: normalize3(rule.toNamespace, rule.toNamespaces),
|
646
|
-
selectors: normalize3(rule.toSelector, rule.toSelectors),
|
647
|
-
ports: normalize3(rule.toPort, rule.toPorts)
|
648
|
-
};
|
649
|
-
}).concat(extraEgressRules)
|
650
|
-
};
|
651
|
-
});
|
652
|
-
this.networkPolicy = normalizedArgs.apply((args2) => {
|
653
|
-
return output6(
|
654
|
-
this.create(name, args2, { ...opts, parent: this })
|
655
|
-
);
|
656
|
-
});
|
657
|
-
this.registerOutputs({ networkPolicy: this.networkPolicy });
|
658
|
-
}
|
659
|
-
static mapCidrFromEndpoint(result) {
|
660
|
-
if (result.ipVersion === 4) {
|
661
|
-
return `${result.hostname}/32`;
|
662
|
-
}
|
663
|
-
return `${result.hostname}/128`;
|
664
|
-
}
|
665
|
-
static supportedCNIs = ["cilium"];
|
666
|
-
static create(name, args, opts) {
|
667
|
-
return output6(args).apply(async (args2) => {
|
668
|
-
const cni = args2.cluster.info.cni;
|
669
|
-
if (!cni || !_NetworkPolicy.supportedCNIs.includes(cni)) {
|
670
|
-
return new NativeNetworkPolicy(name, args2, opts);
|
671
|
-
}
|
672
|
-
const implName = `${capitalize(cni)}NetworkPolicy`;
|
673
|
-
const implModule = await import(`@highstate/${cni}`);
|
674
|
-
const implClass = implModule[implName];
|
675
|
-
if (!implClass) {
|
676
|
-
throw new Error(`No implementation found for ${cni}`);
|
677
|
-
}
|
678
|
-
return new implClass(name, args2, opts);
|
679
|
-
});
|
680
|
-
}
|
681
|
-
static allowInsideNamespace(namespace, cluster, opts) {
|
682
|
-
return _NetworkPolicy.create(
|
683
|
-
"allow-inside-namespace",
|
684
|
-
{
|
685
|
-
namespace,
|
686
|
-
cluster,
|
687
|
-
description: "Allow all traffic inside the namespace.",
|
688
|
-
selector: {},
|
689
|
-
ingressRule: { fromNamespace: namespace },
|
690
|
-
egressRule: { toNamespace: namespace }
|
691
|
-
},
|
692
|
-
opts
|
693
|
-
);
|
694
|
-
}
|
695
|
-
static allowKubeApiServer(namespace, cluster, opts) {
|
696
|
-
return _NetworkPolicy.create(
|
697
|
-
"allow-kube-api-server",
|
698
|
-
{
|
699
|
-
namespace,
|
700
|
-
cluster,
|
701
|
-
description: "Allow all traffic to the Kubernetes API server from the namespace.",
|
702
|
-
allowKubeApiServer: true
|
703
|
-
},
|
704
|
-
opts
|
705
|
-
);
|
706
|
-
}
|
707
|
-
static allowKubeDns(namespace, cluster, opts) {
|
708
|
-
return _NetworkPolicy.create(
|
709
|
-
"allow-kube-dns",
|
710
|
-
{
|
711
|
-
namespace,
|
712
|
-
cluster,
|
713
|
-
description: "Allow all traffic to the Kubernetes DNS server from the namespace.",
|
714
|
-
allowKubeDns: true
|
715
|
-
},
|
716
|
-
opts
|
717
|
-
);
|
718
|
-
}
|
719
|
-
static allowAllEgress(namespace, cluster, opts) {
|
720
|
-
return _NetworkPolicy.create(
|
721
|
-
"allow-all-egress",
|
722
|
-
{
|
723
|
-
namespace,
|
724
|
-
cluster,
|
725
|
-
description: "Allow all egress traffic from the namespace.",
|
726
|
-
egressRule: { toAll: true }
|
727
|
-
},
|
728
|
-
opts
|
729
|
-
);
|
730
|
-
}
|
731
|
-
};
|
732
|
-
var NativeNetworkPolicy = class _NativeNetworkPolicy extends NetworkPolicy {
|
733
|
-
create(name, args, opts) {
|
734
|
-
const ingress = _NativeNetworkPolicy.createIngressRules(args);
|
735
|
-
const egress = _NativeNetworkPolicy.createEgressRules(args);
|
736
|
-
const policyTypes = [];
|
737
|
-
if (ingress.length > 0 || args.isolateIngress) {
|
738
|
-
policyTypes.push("Ingress");
|
739
|
-
}
|
740
|
-
if (egress.length > 0 || args.isolateEgress) {
|
741
|
-
policyTypes.push("Egress");
|
742
|
-
}
|
743
|
-
return new networking.v1.NetworkPolicy(
|
744
|
-
name,
|
745
|
-
{
|
746
|
-
metadata: mergeDeep(mapMetadata(args, name), {
|
747
|
-
annotations: args.description ? { "kubernetes.io/description": args.description } : void 0
|
748
|
-
}),
|
749
|
-
spec: {
|
750
|
-
podSelector: args.podSelector,
|
751
|
-
ingress,
|
752
|
-
egress,
|
753
|
-
policyTypes
|
754
|
-
}
|
755
|
-
},
|
756
|
-
opts
|
757
|
-
);
|
758
|
-
}
|
759
|
-
static fallbackIpBlock = {
|
760
|
-
cidr: "0.0.0.0/0",
|
761
|
-
except: ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
|
762
|
-
};
|
763
|
-
static createIngressRules(args) {
|
764
|
-
return args.ingressRules.map((rule) => ({
|
765
|
-
from: rule.all ? void 0 : _NativeNetworkPolicy.createRulePeers(rule),
|
766
|
-
ports: _NativeNetworkPolicy.mapPorts(rule.ports)
|
767
|
-
}));
|
768
|
-
}
|
769
|
-
static createEgressRules(args) {
|
770
|
-
const needFallback = args.egressRules.some((rule) => rule.fqdns.length > 0);
|
771
|
-
if (needFallback) {
|
772
|
-
return [{ to: [{ ipBlock: _NativeNetworkPolicy.fallbackIpBlock }] }];
|
773
|
-
}
|
774
|
-
const extraRules = [];
|
775
|
-
if (args.allowKubeApiServer) {
|
776
|
-
const apiServerIp = args.cluster.info.kubeApiServerIp ?? "10.96.0.1";
|
777
|
-
const apiServerPort = args.cluster.info.kubeApiServerPort ?? 443;
|
778
|
-
extraRules.push({
|
779
|
-
to: [{ ipBlock: { cidr: `${apiServerIp}/32` } }],
|
780
|
-
ports: [{ port: apiServerPort, protocol: "TCP" }]
|
781
|
-
});
|
782
|
-
}
|
783
|
-
return args.egressRules.map((rule) => {
|
784
|
-
return {
|
785
|
-
to: rule.all ? void 0 : _NativeNetworkPolicy.createRulePeers(rule),
|
786
|
-
ports: _NativeNetworkPolicy.mapPorts(rule.ports)
|
787
|
-
};
|
788
|
-
}).concat(extraRules);
|
789
|
-
}
|
790
|
-
static createRulePeers(args) {
|
791
|
-
return [
|
792
|
-
..._NativeNetworkPolicy.createCidrPeers(args),
|
793
|
-
..._NativeNetworkPolicy.createServicePeers(args),
|
794
|
-
..._NativeNetworkPolicy.createSelectorPeers(args)
|
795
|
-
];
|
796
|
-
}
|
797
|
-
static createCidrPeers(args) {
|
798
|
-
return args.cidrs.map((cidr) => ({ ipBlock: { cidr } }));
|
799
|
-
}
|
800
|
-
static createServicePeers(args) {
|
801
|
-
return args.services.map((service) => {
|
802
|
-
const selector = mapServiceToLabelSelector(service);
|
803
|
-
return {
|
804
|
-
namespaceSelector: mapNamespaceNameToSelector(service.metadata.namespace),
|
805
|
-
podSelector: selector
|
806
|
-
};
|
807
|
-
});
|
808
|
-
}
|
809
|
-
static createSelectorPeers(args) {
|
810
|
-
const selectorPeers = args.selectors.map((selector) => ({
|
811
|
-
podSelector: mapSelectorLikeToSelector(selector)
|
812
|
-
}));
|
813
|
-
const namespacePeers = args.namespaces.map(_NativeNetworkPolicy.createNamespacePeer);
|
814
|
-
if (namespacePeers.length === 0) {
|
815
|
-
return selectorPeers;
|
816
|
-
}
|
817
|
-
if (selectorPeers.length === 0) {
|
818
|
-
return namespacePeers;
|
819
|
-
}
|
820
|
-
return flat(
|
821
|
-
selectorPeers.map((selectorPeer) => {
|
822
|
-
return namespacePeers.map((namespacePeer) => merge(selectorPeer, namespacePeer));
|
823
|
-
})
|
824
|
-
);
|
825
|
-
}
|
826
|
-
static createNamespacePeer(namespace) {
|
827
|
-
const namespaceName = mapNamespaceLikeToNamespaceName(namespace);
|
828
|
-
const namespaceSelector = mapNamespaceNameToSelector(namespaceName);
|
829
|
-
return { namespaceSelector };
|
830
|
-
}
|
831
|
-
static mapPorts(ports) {
|
832
|
-
return ports.map((port) => {
|
833
|
-
if ("port" in port) {
|
834
|
-
return {
|
835
|
-
port: port.port,
|
836
|
-
protocol: port.protocol ?? "TCP"
|
837
|
-
};
|
838
|
-
}
|
839
|
-
return {
|
840
|
-
port: port.range[0],
|
841
|
-
endPort: port.range[1],
|
842
|
-
protocol: port.protocol ?? "TCP"
|
843
|
-
};
|
844
|
-
});
|
845
|
-
}
|
846
|
-
};
|
45
|
+
mapSelectorLikeToSelector
|
46
|
+
} from "./chunk-FKNHHKOL.js";
|
847
47
|
|
848
48
|
// src/access-point.ts
|
849
|
-
import {
|
49
|
+
import { DnsRecordSet, filterEndpoints, l3EndpointToString } from "@highstate/common";
|
850
50
|
import { gateway } from "@highstate/gateway-api";
|
851
51
|
import {
|
852
|
-
normalize
|
853
|
-
output
|
52
|
+
normalize,
|
53
|
+
output,
|
854
54
|
toPromise
|
855
55
|
} from "@highstate/pulumi";
|
856
56
|
function useAccessPoint(args) {
|
857
|
-
const result =
|
57
|
+
const result = output({ args, namespaceName: output(args.namespace).metadata.name }).apply(
|
858
58
|
({ args: args2, namespaceName }) => {
|
59
|
+
if (args2.accessPoint.clusterId !== args2.cluster.id) {
|
60
|
+
throw new Error(
|
61
|
+
"The provided Kubernetes cluster is different from the one where the access point is deployed."
|
62
|
+
);
|
63
|
+
}
|
859
64
|
const gateway2 = createGateway({
|
860
65
|
...args2,
|
861
66
|
annotations: {
|
@@ -863,36 +68,36 @@ function useAccessPoint(args) {
|
|
863
68
|
},
|
864
69
|
gateway: args2.accessPoint.gateway
|
865
70
|
});
|
866
|
-
const
|
867
|
-
return
|
71
|
+
const dnsRecordSets = normalize(args2.fqdn, args2.fqdns).flatMap((fqdn) => {
|
72
|
+
return DnsRecordSet.create(fqdn, {
|
868
73
|
providers: args2.accessPoint.dnsProviders,
|
869
|
-
|
870
|
-
|
74
|
+
values: filterEndpoints(
|
75
|
+
args2.accessPoint.gateway.endpoints.filter((endpoint) => endpoint.type !== "hostname")
|
76
|
+
)
|
871
77
|
});
|
872
78
|
});
|
873
|
-
const networkPolicies = [
|
874
|
-
|
875
|
-
|
79
|
+
const networkPolicies = [
|
80
|
+
NetworkPolicy.create(
|
81
|
+
`allow-ingress-from-${l3EndpointToString(args2.accessPoint.gateway.endpoints[0])}`,
|
82
|
+
{
|
83
|
+
namespace: args2.namespace,
|
84
|
+
cluster: args2.cluster,
|
85
|
+
description: `Allow ingress traffic from the gateway at "${l3EndpointToString(args2.accessPoint.gateway.endpoints[0])}".`,
|
86
|
+
ingressRule: {
|
87
|
+
fromEndpoints: args2.accessPoint.gateway.endpoints
|
88
|
+
}
|
89
|
+
},
|
90
|
+
{ provider: args2.provider }
|
91
|
+
)
|
92
|
+
];
|
93
|
+
if (isFromCluster(args2.accessPoint.gateway.endpoints[0], args2.cluster)) {
|
876
94
|
networkPolicies.push(
|
877
|
-
NetworkPolicy.create(
|
878
|
-
`allow-ingress-from-${getAppName(args2.accessPoint.gateway.service.metadata)}`,
|
879
|
-
{
|
880
|
-
namespace: args2.namespace,
|
881
|
-
cluster: args2.cluster,
|
882
|
-
description: `Allow ingress traffic from the gateway "${displayName}".`,
|
883
|
-
ingressRule: {
|
884
|
-
fromNamespace: args2.accessPoint.gateway.service.metadata.namespace,
|
885
|
-
fromSelector: args2.accessPoint.gateway.service.spec.selector
|
886
|
-
}
|
887
|
-
},
|
888
|
-
{ provider: args2.provider }
|
889
|
-
),
|
890
95
|
NetworkPolicy.create(
|
891
96
|
`allow-egress-to-${namespaceName}`,
|
892
97
|
{
|
893
|
-
namespace: args2.accessPoint.gateway.
|
98
|
+
namespace: args2.accessPoint.gateway.endpoints[0].metadata.k8sService.namespace,
|
894
99
|
cluster: args2.cluster,
|
895
|
-
selector: args2.accessPoint.gateway.
|
100
|
+
selector: args2.accessPoint.gateway.endpoints[0].metadata.k8sService.selector,
|
896
101
|
description: `Allow egress traffic to the namespace "${namespaceName}".`,
|
897
102
|
egressRule: {
|
898
103
|
toNamespace: args2.namespace
|
@@ -902,28 +107,28 @@ function useAccessPoint(args) {
|
|
902
107
|
)
|
903
108
|
);
|
904
109
|
}
|
905
|
-
return
|
110
|
+
return output({
|
906
111
|
gateway: gateway2,
|
907
|
-
|
112
|
+
dnsRecordSets,
|
908
113
|
networkPolicies
|
909
114
|
});
|
910
115
|
}
|
911
116
|
);
|
912
117
|
return toPromise(result);
|
913
118
|
}
|
914
|
-
function useStandardAcessPoint(
|
915
|
-
return useAccessPoint({
|
916
|
-
name: appName,
|
119
|
+
async function useStandardAcessPoint(namespace, args, inputs) {
|
120
|
+
return await useAccessPoint({
|
121
|
+
name: args.appName,
|
917
122
|
namespace,
|
918
123
|
fqdn: args.fqdn,
|
919
124
|
accessPoint: inputs.accessPoint,
|
920
125
|
cluster: inputs.k8sCluster,
|
921
|
-
provider
|
126
|
+
provider: await getProvider(inputs.k8sCluster)
|
922
127
|
});
|
923
128
|
}
|
924
129
|
function createGateway(args) {
|
925
|
-
return
|
926
|
-
if (args2.cluster.
|
130
|
+
return output(args).apply((args2) => {
|
131
|
+
if (args2.cluster.id !== args2.gateway.clusterId) {
|
927
132
|
throw new Error(
|
928
133
|
"The provided Kubernetes cluster is different from the one where the gateway controller is deployed."
|
929
134
|
);
|
@@ -937,12 +142,12 @@ function createGateway(args) {
|
|
937
142
|
annotations: args2.annotations
|
938
143
|
},
|
939
144
|
spec: {
|
940
|
-
gatewayClassName:
|
941
|
-
listeners:
|
145
|
+
gatewayClassName: output(args2.gateway).gatewayClassName,
|
146
|
+
listeners: normalize(args2.fqdn, args2.fqdns).map((fqdn) => {
|
942
147
|
const normalizedName = fqdn.replace(/\*/g, "wildcard");
|
943
148
|
return {
|
944
149
|
name: `https-${normalizedName}`,
|
945
|
-
port:
|
150
|
+
port: output(args2.gateway).httpsListenerPort,
|
946
151
|
protocol: "HTTPS",
|
947
152
|
hostname: fqdn,
|
948
153
|
tls: {
|
@@ -959,15 +164,18 @@ function createGateway(args) {
|
|
959
164
|
}
|
960
165
|
|
961
166
|
// src/scripting/bundle.ts
|
962
|
-
import { core
|
963
|
-
import { apply, normalize as
|
167
|
+
import { core } from "@pulumi/kubernetes";
|
168
|
+
import { apply, normalize as normalize2 } from "@highstate/pulumi";
|
964
169
|
import {
|
965
|
-
ComponentResource
|
966
|
-
output as
|
170
|
+
ComponentResource,
|
171
|
+
output as output2
|
967
172
|
} from "@pulumi/pulumi";
|
968
|
-
import { pipe } from "remeda";
|
969
|
-
import { deepmerge
|
970
|
-
import {
|
173
|
+
import { mapValues, omitBy, pipe } from "remeda";
|
174
|
+
import { deepmerge } from "deepmerge-ts";
|
175
|
+
import { readPackageJSON } from "pkg-types";
|
176
|
+
import { text, trimIndentation } from "@highstate/contract";
|
177
|
+
import { parseL34Endpoint } from "@highstate/common";
|
178
|
+
import { serializeFunction } from "@pulumi/pulumi/runtime/index.js";
|
971
179
|
|
972
180
|
// src/scripting/environment.ts
|
973
181
|
var emptyDistributionEnvironment = {
|
@@ -976,18 +184,41 @@ var emptyDistributionEnvironment = {
|
|
976
184
|
packages: []
|
977
185
|
};
|
978
186
|
var emptyScriptEnvironment = {
|
979
|
-
alpine:
|
980
|
-
|
187
|
+
alpine: {
|
188
|
+
...emptyDistributionEnvironment,
|
189
|
+
image: "alpine@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c",
|
190
|
+
allowedEndpoints: [
|
191
|
+
//
|
192
|
+
"tcp://dl-cdn.alpinelinux.org:443",
|
193
|
+
"tcp://dl-cdn.alpinelinux.org:80"
|
194
|
+
]
|
195
|
+
},
|
196
|
+
ubuntu: {
|
197
|
+
...emptyDistributionEnvironment,
|
198
|
+
image: "ubuntu@sha256:72297848456d5d37d1262630108ab308d3e9ec7ed1c3286a32fe09856619a782",
|
199
|
+
allowedEndpoints: [
|
200
|
+
//
|
201
|
+
"tcp://archive.ubuntu.com:80",
|
202
|
+
"tcp://archive.ubuntu.com:443",
|
203
|
+
"tcp://security.ubuntu.com:80",
|
204
|
+
"tcp://security.ubuntu.com:443"
|
205
|
+
]
|
206
|
+
},
|
981
207
|
setupScripts: {},
|
982
208
|
cleanupScripts: {},
|
983
|
-
|
209
|
+
files: {},
|
984
210
|
volumes: [],
|
985
211
|
volumeMounts: [],
|
986
|
-
environment: {}
|
212
|
+
environment: {},
|
213
|
+
allowedEndpoints: []
|
214
|
+
};
|
215
|
+
var functionScriptImages = {
|
216
|
+
alpine: "oven/bun@sha256:6b14922b0885c3890cdb0b396090af1da486ba941df5ee94391eef64f7113c61",
|
217
|
+
ubuntu: "oven/bun@sha256:66b431441dc4c36d7e8164bfc61e6348ec1d7ce2862fc3a29f5dc9856e8205e4"
|
987
218
|
};
|
988
219
|
|
989
220
|
// src/scripting/bundle.ts
|
990
|
-
var ScriptBundle = class extends
|
221
|
+
var ScriptBundle = class extends ComponentResource {
|
991
222
|
/**
|
992
223
|
* The config map containing the scripts.
|
993
224
|
*/
|
@@ -1004,21 +235,49 @@ var ScriptBundle = class extends ComponentResource6 {
|
|
1004
235
|
* The environment variables that should be defined in the container.
|
1005
236
|
*/
|
1006
237
|
environment;
|
238
|
+
/**
|
239
|
+
* The image to use for the scripts.
|
240
|
+
*/
|
241
|
+
image;
|
1007
242
|
/**
|
1008
243
|
* The distribution to use for the scripts.
|
1009
244
|
*/
|
1010
245
|
distribution;
|
246
|
+
/**
|
247
|
+
* The list of endpoints that the script is allowed to access.
|
248
|
+
*/
|
249
|
+
allowedEndpoints;
|
1011
250
|
constructor(name, args, opts) {
|
1012
251
|
super("highstate:k8s:ScriptBundle", name, args, opts);
|
1013
252
|
const scriptEnvironment = pipe(
|
1014
|
-
|
1015
|
-
apply((args2) =>
|
1016
|
-
apply((args2) =>
|
253
|
+
output2(args),
|
254
|
+
apply((args2) => normalize2(args2.environment, args2.environments)),
|
255
|
+
apply((args2) => deepmerge(emptyScriptEnvironment, ...args2))
|
1017
256
|
);
|
257
|
+
const hasFunctionScripts = scriptEnvironment.apply((scriptEnvironment2) => {
|
258
|
+
return Object.values(scriptEnvironment2.files).some((file) => typeof file === "function");
|
259
|
+
});
|
1018
260
|
this.distribution = args.distribution;
|
1019
261
|
this.environment = scriptEnvironment.environment;
|
1020
|
-
this.
|
1021
|
-
|
262
|
+
this.image = hasFunctionScripts.apply(
|
263
|
+
(hasFunctionScripts2) => output2(
|
264
|
+
hasFunctionScripts2 ? functionScriptImages[args.distribution] : scriptEnvironment[args.distribution].image
|
265
|
+
)
|
266
|
+
);
|
267
|
+
this.allowedEndpoints = output2({ scriptEnvironment, hasFunctionScripts }).apply(
|
268
|
+
({ scriptEnvironment: scriptEnvironment2, hasFunctionScripts: hasFunctionScripts2 }) => {
|
269
|
+
const allowedEndpoints = [
|
270
|
+
...scriptEnvironment2.allowedEndpoints,
|
271
|
+
...scriptEnvironment2[args.distribution].allowedEndpoints
|
272
|
+
];
|
273
|
+
if (hasFunctionScripts2) {
|
274
|
+
allowedEndpoints.push("tcp://registry.npmjs.org:443");
|
275
|
+
}
|
276
|
+
return allowedEndpoints.map(parseL34Endpoint);
|
277
|
+
}
|
278
|
+
);
|
279
|
+
this.configMap = output2({ scriptEnvironment, args }).apply(({ scriptEnvironment: scriptEnvironment2, args: args2 }) => {
|
280
|
+
return new core.v1.ConfigMap(
|
1022
281
|
name,
|
1023
282
|
{
|
1024
283
|
metadata: mapMetadata(args2, name),
|
@@ -1027,40 +286,92 @@ var ScriptBundle = class extends ComponentResource6 {
|
|
1027
286
|
{ ...opts, parent: this }
|
1028
287
|
);
|
1029
288
|
});
|
1030
|
-
this.volumes = scriptEnvironment.volumes.apply(
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
configMap: {
|
289
|
+
this.volumes = output2({ hasFunctionScripts, volumes: scriptEnvironment.volumes }).apply(
|
290
|
+
({ hasFunctionScripts: hasFunctionScripts2, volumes }) => {
|
291
|
+
return [
|
292
|
+
...volumes,
|
293
|
+
{
|
1036
294
|
name: this.configMap.metadata.name,
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
295
|
+
configMap: {
|
296
|
+
name: this.configMap.metadata.name,
|
297
|
+
defaultMode: 360
|
298
|
+
// read and execute permissions
|
299
|
+
}
|
300
|
+
},
|
301
|
+
...hasFunctionScripts2 ? [{ name: "node-modules", emptyDir: {} }] : []
|
302
|
+
];
|
303
|
+
}
|
304
|
+
);
|
305
|
+
this.volumeMounts = output2({
|
306
|
+
hasFunctionScripts,
|
307
|
+
volumeMounts: scriptEnvironment.volumeMounts
|
308
|
+
}).apply(({ hasFunctionScripts: hasFunctionScripts2, volumeMounts }) => {
|
1044
309
|
return [
|
1045
310
|
...volumeMounts,
|
1046
311
|
{
|
1047
312
|
volume: this.configMap,
|
1048
313
|
mountPath: "/scripts"
|
1049
|
-
}
|
314
|
+
},
|
315
|
+
...hasFunctionScripts2 ? [{ name: "node-modules", mountPath: "/scripts/node_modules" }] : []
|
1050
316
|
];
|
1051
317
|
});
|
1052
318
|
this.registerOutputs({
|
1053
319
|
configMap: this.configMap,
|
1054
320
|
volumes: this.volumes,
|
1055
321
|
volumeMounts: this.volumeMounts,
|
1056
|
-
environment: this.environment
|
322
|
+
environment: this.environment,
|
323
|
+
distribution: this.distribution,
|
324
|
+
allowedEndpoints: this.allowedEndpoints,
|
325
|
+
image: this.image
|
1057
326
|
});
|
1058
327
|
}
|
1059
328
|
};
|
1060
|
-
function
|
329
|
+
function stripWorkspacePrefix(value) {
|
330
|
+
if (value.startsWith("workspace:")) {
|
331
|
+
return value.replace("workspace:", "");
|
332
|
+
}
|
333
|
+
return value;
|
334
|
+
}
|
335
|
+
async function createScriptData(distribution, environment) {
|
1061
336
|
const scriptData = {};
|
1062
337
|
const actions = [];
|
1063
338
|
const distributionEnvironment = environment[distribution];
|
339
|
+
const setupScripts = { ...environment.setupScripts };
|
340
|
+
let hasFunctionScripts = false;
|
341
|
+
for (const key in environment.files) {
|
342
|
+
if (typeof environment.files[key] === "function") {
|
343
|
+
const serialized = await serializeFunction(environment.files[key]);
|
344
|
+
scriptData[key] = text`
|
345
|
+
#!/usr/local/bin/bun
|
346
|
+
|
347
|
+
${serialized.text}
|
348
|
+
|
349
|
+
exports.${serialized.exportName}()
|
350
|
+
`;
|
351
|
+
hasFunctionScripts = true;
|
352
|
+
} else {
|
353
|
+
scriptData[key] = environment.files[key];
|
354
|
+
}
|
355
|
+
}
|
356
|
+
if (hasFunctionScripts) {
|
357
|
+
const packageJson = await readPackageJSON();
|
358
|
+
packageJson.dependencies = omitBy(
|
359
|
+
mapValues(packageJson.dependencies ?? {}, stripWorkspacePrefix),
|
360
|
+
(_, key) => key.startsWith("@highstate/")
|
361
|
+
);
|
362
|
+
packageJson.devDependencies = omitBy(
|
363
|
+
mapValues(packageJson.devDependencies ?? {}, stripWorkspacePrefix),
|
364
|
+
(_, key) => key.startsWith("@highstate/")
|
365
|
+
);
|
366
|
+
scriptData["package.json"] = JSON.stringify(packageJson, null, 2);
|
367
|
+
setupScripts["resolve-dependencies.sh"] = text`
|
368
|
+
#!/usr/local/bin/bun
|
369
|
+
set -e
|
370
|
+
|
371
|
+
cd /scripts
|
372
|
+
bun install --production
|
373
|
+
`;
|
374
|
+
}
|
1064
375
|
if (distributionEnvironment.preInstallPackages.length > 0) {
|
1065
376
|
scriptData["pre-install-packages.sh"] = getInstallPackagesScript(
|
1066
377
|
distribution,
|
@@ -1093,9 +404,9 @@ function createScriptData(distribution, environment) {
|
|
1093
404
|
echo "+ Packages installed successfully"
|
1094
405
|
`);
|
1095
406
|
}
|
1096
|
-
if (Object.keys(
|
1097
|
-
for (const key in
|
1098
|
-
scriptData[`setup-${key}`] =
|
407
|
+
if (Object.keys(setupScripts).length > 0) {
|
408
|
+
for (const key in setupScripts) {
|
409
|
+
scriptData[`setup-${key}`] = setupScripts[key];
|
1099
410
|
actions.push(`
|
1100
411
|
echo "+ Running setup script '${key}'..."
|
1101
412
|
/scripts/setup-${key}
|
@@ -1122,10 +433,7 @@ function createScriptData(distribution, environment) {
|
|
1122
433
|
trap cleanup SIGTERM
|
1123
434
|
`);
|
1124
435
|
}
|
1125
|
-
|
1126
|
-
scriptData[key] = environment.scripts[key];
|
1127
|
-
}
|
1128
|
-
scriptData["entrypoint.sh"] = trimIndentation2(`
|
436
|
+
scriptData["entrypoint.sh"] = trimIndentation(`
|
1129
437
|
#!/bin/sh
|
1130
438
|
set -e
|
1131
439
|
|
@@ -1162,139 +470,168 @@ function getInstallPackagesScript(distribution, packages) {
|
|
1162
470
|
}
|
1163
471
|
|
1164
472
|
// src/scripting/container.ts
|
1165
|
-
import {
|
1166
|
-
import {
|
473
|
+
import { merge } from "remeda";
|
474
|
+
import { output as output3 } from "@pulumi/pulumi";
|
1167
475
|
function createScriptContainer(options) {
|
1168
|
-
|
1169
|
-
|
476
|
+
const bundle = output3(options.bundle);
|
477
|
+
return output3({
|
478
|
+
options,
|
479
|
+
image: bundle.image,
|
480
|
+
volumeMounts: bundle.volumeMounts,
|
481
|
+
volumes: bundle.volumes,
|
482
|
+
environment: bundle.environment,
|
483
|
+
allowedEndpoints: bundle.allowedEndpoints
|
484
|
+
}).apply(({ options: options2, image, volumeMounts, volumes, environment, allowedEndpoints }) => {
|
1170
485
|
return {
|
1171
486
|
image,
|
1172
487
|
command: ["/scripts/entrypoint.sh", `/scripts/${options2.main}`],
|
1173
488
|
...options2,
|
1174
|
-
volumeMounts:
|
1175
|
-
volumes:
|
1176
|
-
environment:
|
489
|
+
volumeMounts: [...volumeMounts, ...options2.volumeMounts ?? []],
|
490
|
+
volumes: [...volumes, ...options2.volumes ?? []],
|
491
|
+
environment: merge(environment, options2.environment),
|
492
|
+
allowedEndpoints: [...allowedEndpoints, ...options2.allowedEndpoints ?? []]
|
1177
493
|
};
|
1178
494
|
});
|
1179
495
|
}
|
1180
496
|
|
1181
497
|
// src/job.ts
|
1182
498
|
import { batch } from "@pulumi/kubernetes";
|
1183
|
-
import {
|
1184
|
-
|
1185
|
-
normalize as normalize6,
|
1186
|
-
output as output10
|
1187
|
-
} from "@highstate/pulumi";
|
1188
|
-
import { mergeDeep as mergeDeep2, omit as omit5 } from "remeda";
|
499
|
+
import { ComponentResource as ComponentResource2, output as output4 } from "@highstate/pulumi";
|
500
|
+
import { mergeDeep, omit } from "remeda";
|
1189
501
|
var jobExtraArgs = [...commonExtraArgs, "container", "containers"];
|
1190
|
-
var Job = class extends
|
502
|
+
var Job = class extends ComponentResource2 {
|
1191
503
|
/**
|
1192
504
|
* The underlying Kubernetes job.
|
1193
505
|
*/
|
1194
506
|
job;
|
1195
507
|
constructor(name, args, opts) {
|
1196
508
|
super("highstate:k8s:Job", name, args, opts);
|
1197
|
-
|
1198
|
-
|
509
|
+
const { podTemplate } = getWorkloadComponents(name, args, () => this, opts);
|
510
|
+
this.job = output4({ args, podTemplate }).apply(async ({ args: args2, podTemplate: podTemplate2 }) => {
|
1199
511
|
return new batch.v1.Job(
|
1200
512
|
name,
|
1201
513
|
{
|
1202
514
|
metadata: mapMetadata(args2, name),
|
1203
|
-
spec:
|
515
|
+
spec: mergeDeep(
|
1204
516
|
{
|
1205
|
-
template:
|
1206
|
-
spec: {
|
1207
|
-
containers: containers.map((container) => mapContainerToRaw(container, name)),
|
1208
|
-
volumes: containers.flatMap((container) => normalize6(container.volume, container.volumes)).map(mapWorkloadVolume),
|
1209
|
-
restartPolicy: "Never"
|
1210
|
-
}
|
1211
|
-
}
|
517
|
+
template: podTemplate2
|
1212
518
|
},
|
1213
|
-
|
519
|
+
omit(args2, jobExtraArgs)
|
1214
520
|
)
|
1215
521
|
},
|
1216
|
-
{
|
522
|
+
{
|
523
|
+
...opts,
|
524
|
+
parent: this,
|
525
|
+
provider: await getProvider(args2.cluster)
|
526
|
+
}
|
1217
527
|
);
|
1218
528
|
});
|
1219
|
-
this.registerOutputs({ job: this.job });
|
1220
529
|
}
|
1221
530
|
};
|
1222
531
|
|
1223
532
|
// src/cron-job.ts
|
1224
533
|
import { batch as batch2 } from "@pulumi/kubernetes";
|
1225
|
-
import {
|
1226
|
-
|
1227
|
-
normalize as normalize7,
|
1228
|
-
output as output11
|
1229
|
-
} from "@highstate/pulumi";
|
1230
|
-
import { mergeDeep as mergeDeep3, omit as omit6 } from "remeda";
|
534
|
+
import { ComponentResource as ComponentResource3, output as output5 } from "@highstate/pulumi";
|
535
|
+
import { mergeDeep as mergeDeep2, omit as omit2 } from "remeda";
|
1231
536
|
var cronJobExtraArgs = [...commonExtraArgs, "container", "containers"];
|
1232
|
-
var CronJob = class extends
|
537
|
+
var CronJob = class extends ComponentResource3 {
|
1233
538
|
/**
|
1234
539
|
* The underlying Kubernetes job.
|
1235
540
|
*/
|
1236
541
|
cronJob;
|
1237
542
|
constructor(name, args, opts) {
|
1238
543
|
super("highstate:k8s:CronJob", name, args, opts);
|
1239
|
-
|
1240
|
-
|
544
|
+
const { podTemplate } = getWorkloadComponents(name, args, () => this, opts);
|
545
|
+
this.cronJob = output5({ args, podTemplate }).apply(async ({ args: args2, podTemplate: podTemplate2 }) => {
|
1241
546
|
return new batch2.v1.CronJob(
|
1242
547
|
name,
|
1243
548
|
{
|
1244
549
|
metadata: mapMetadata(args2, name),
|
1245
|
-
spec:
|
550
|
+
spec: mergeDeep2(
|
1246
551
|
{
|
1247
552
|
jobTemplate: {
|
1248
553
|
spec: {
|
1249
|
-
template:
|
1250
|
-
spec: {
|
1251
|
-
containers: containers.map((container) => mapContainerToRaw(container, name)),
|
1252
|
-
volumes: containers.flatMap((container) => normalize7(container.volume, container.volumes)).map(mapWorkloadVolume)
|
1253
|
-
}
|
1254
|
-
}
|
554
|
+
template: podTemplate2
|
1255
555
|
}
|
1256
556
|
},
|
1257
557
|
schedule: args2.schedule
|
1258
558
|
},
|
1259
|
-
|
559
|
+
omit2(args2, cronJobExtraArgs)
|
1260
560
|
)
|
1261
561
|
},
|
1262
|
-
{
|
562
|
+
{
|
563
|
+
...opts,
|
564
|
+
parent: this,
|
565
|
+
provider: await getProvider(args2.cluster)
|
566
|
+
}
|
1263
567
|
);
|
1264
568
|
});
|
1265
|
-
this.registerOutputs({ cronJob: this.cronJob });
|
1266
569
|
}
|
1267
570
|
};
|
571
|
+
|
572
|
+
// src/network.ts
|
573
|
+
import { filterEndpoints as filterEndpoints2 } from "@highstate/common";
|
574
|
+
function getBestEndpoint(endpoints, cluster) {
|
575
|
+
if (!endpoints.length) {
|
576
|
+
return void 0;
|
577
|
+
}
|
578
|
+
if (endpoints.length === 1) {
|
579
|
+
return endpoints[0];
|
580
|
+
}
|
581
|
+
if (!cluster) {
|
582
|
+
return filterEndpoints2(endpoints)[0];
|
583
|
+
}
|
584
|
+
const clusterEndpoint = endpoints.find((endpoint) => isFromCluster(endpoint, cluster));
|
585
|
+
if (clusterEndpoint) {
|
586
|
+
return clusterEndpoint;
|
587
|
+
}
|
588
|
+
return filterEndpoints2(endpoints)[0];
|
589
|
+
}
|
590
|
+
function requireBestEndpoint(endpoints, cluster) {
|
591
|
+
const endpoint = getBestEndpoint(endpoints, cluster);
|
592
|
+
if (!endpoint) {
|
593
|
+
throw new Error(`No best endpoint found for cluster "${cluster.name}" (${cluster.id})`);
|
594
|
+
}
|
595
|
+
return endpoint;
|
596
|
+
}
|
1268
597
|
export {
|
1269
598
|
Chart,
|
1270
599
|
CronJob,
|
1271
600
|
Deployment,
|
601
|
+
ExposableWorkload,
|
1272
602
|
HttpRoute,
|
1273
603
|
Job,
|
604
|
+
Namespace,
|
1274
605
|
NetworkPolicy,
|
1275
606
|
PersistentVolumeClaim,
|
1276
607
|
RenderedChart,
|
1277
608
|
ScriptBundle,
|
609
|
+
Secret,
|
1278
610
|
Service,
|
1279
611
|
StatefulSet,
|
612
|
+
Workload,
|
1280
613
|
createK8sTerminal,
|
1281
|
-
createNamespace,
|
1282
|
-
getProvider as createProvider,
|
1283
614
|
createScriptContainer,
|
1284
615
|
detectExternalIps,
|
1285
616
|
getAppDisplayName,
|
1286
617
|
getAppName,
|
618
|
+
getBestEndpoint,
|
1287
619
|
getChartService,
|
1288
620
|
getChartServiceOutput,
|
1289
|
-
|
621
|
+
getProvider,
|
622
|
+
getServiceMetadata,
|
623
|
+
hasServiceMetadata,
|
624
|
+
isFromCluster,
|
1290
625
|
mapContainerPortToServicePort,
|
1291
626
|
mapMetadata,
|
1292
627
|
mapNamespaceLikeToNamespaceName,
|
1293
628
|
mapNamespaceNameToSelector,
|
1294
629
|
mapSelectorLikeToSelector,
|
1295
630
|
mapServiceToLabelSelector,
|
631
|
+
requireBestEndpoint,
|
1296
632
|
resolveHelmChart,
|
1297
633
|
useAccessPoint,
|
1298
|
-
useStandardAcessPoint
|
634
|
+
useStandardAcessPoint,
|
635
|
+
withServiceMetadata
|
1299
636
|
};
|
1300
637
|
//# sourceMappingURL=index.js.map
|