@highstate/k8s 0.6.2 → 0.7.1
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/assets/charts.json +8 -0
- package/dist/helm-wPTgVV1N.js +413 -0
- package/dist/index.d.ts +412 -52
- package/dist/index.js +518 -335
- package/dist/shared-Clzbl5K-.js +89 -0
- package/dist/units/cert-manager/index.js +25 -7
- package/dist/units/dns01-issuer/index.js +3 -5
- package/dist/units/existing-cluster/index.js +21 -5
- package/package.json +12 -8
- package/assets/cert-manager-v1.16.3.tgz +0 -0
- package/assets/gateway-api.yaml +0 -14974
- package/dist/shared-hajqPzR4.js +0 -64
package/dist/index.js
CHANGED
@@ -1,149 +1,111 @@
|
|
1
|
-
import { m as mapMetadata, c as commonExtraArgs, a as mapSelectorLikeToSelector, b as mapNamespaceNameToSelector, d as mapNamespaceLikeToNamespaceName } from './shared-
|
2
|
-
export {
|
3
|
-
import { ComponentResource, output, normalize,
|
1
|
+
import { m as mapMetadata, c as commonExtraArgs, v as verifyProvider, r as resourceIdToString, a as mapSelectorLikeToSelector, b as mapNamespaceNameToSelector, d as mapNamespaceLikeToNamespaceName, g as getAppDisplayName, e as getAppName } from './shared-Clzbl5K-.js';
|
2
|
+
export { h as createNamespace, f as createProvider, i as getNamespace } from './shared-Clzbl5K-.js';
|
3
|
+
import { ComponentResource, output, normalize, toPromise, apply } from '@highstate/pulumi';
|
4
4
|
import { core, apps, networking, batch } from '@pulumi/kubernetes';
|
5
|
-
import {
|
6
|
-
import { mergeDeep, omit, pipe, map, concat, capitalize, flat, merge } from 'remeda';
|
7
|
-
import { DnsRecord } from '@highstate/common';
|
8
|
-
import { ComponentResource as ComponentResource$1, output as output$1 } from '@pulumi/pulumi';
|
5
|
+
import { omit, concat, map, uniqueBy, capitalize, mergeDeep, flat, merge, pipe } from 'remeda';
|
9
6
|
import { deepmerge } from 'deepmerge-ts';
|
7
|
+
import { output as output$1, ComponentResource as ComponentResource$1 } from '@pulumi/pulumi';
|
8
|
+
import { S as Service, m as mapContainerPortToServicePort, H as HttpRoute, a as mapServiceToLabelSelector } from './helm-wPTgVV1N.js';
|
9
|
+
export { C as Chart, R as RenderedChart, b as getChartService, g as getChartServiceOutput, r as resolveHelmChart } from './helm-wPTgVV1N.js';
|
10
|
+
import { parseDomain, ParseResultType } from 'parse-domain';
|
11
|
+
import '@highstate/library';
|
12
|
+
import { DnsRecord } from '@highstate/common';
|
13
|
+
import { gateway } from '@highstate/gateway-api';
|
10
14
|
import { trimIndentation, text } from '@highstate/contract';
|
11
|
-
import '
|
12
|
-
import 'node:
|
15
|
+
import 'path';
|
16
|
+
import 'node:fs/promises';
|
17
|
+
import 'nano-spawn';
|
18
|
+
import 'crypto-hash';
|
19
|
+
import '@pulumi/command';
|
20
|
+
import 'glob';
|
13
21
|
|
14
|
-
const
|
15
|
-
class
|
22
|
+
const extraPersistentVolumeClaimArgs = [...commonExtraArgs, "size", "cluster"];
|
23
|
+
class PersistentVolumeClaim extends ComponentResource {
|
24
|
+
constructor(type, name, args, opts, clusterInfo, metadata, spec, status) {
|
25
|
+
super(type, name, args, opts);
|
26
|
+
this.clusterInfo = clusterInfo;
|
27
|
+
this.metadata = metadata;
|
28
|
+
this.spec = spec;
|
29
|
+
this.status = status;
|
30
|
+
}
|
16
31
|
/**
|
17
|
-
* The
|
32
|
+
* The Highstate service entity.
|
18
33
|
*/
|
19
|
-
|
20
|
-
constructor(name, args, opts) {
|
21
|
-
super("highstate:k8s:Service", name, args, opts);
|
22
|
-
this.service = output(args).apply((args2) => {
|
23
|
-
return new core.v1.Service(
|
24
|
-
name,
|
25
|
-
{
|
26
|
-
metadata: mapMetadata(args2, name),
|
27
|
-
spec: mergeDeep(
|
28
|
-
{
|
29
|
-
ports: normalize(args2.port, args2.ports)
|
30
|
-
},
|
31
|
-
omit(args2, serviceExtraArgs)
|
32
|
-
)
|
33
|
-
},
|
34
|
-
{ ...opts, parent: this }
|
35
|
-
);
|
36
|
-
});
|
37
|
-
this.registerOutputs({
|
38
|
-
service: this.service
|
39
|
-
});
|
40
|
-
}
|
41
|
-
}
|
42
|
-
function mapContainerPortToServicePort(port) {
|
43
|
-
return {
|
44
|
-
port: port.containerPort,
|
45
|
-
targetPort: port.containerPort,
|
46
|
-
protocol: port.protocol
|
47
|
-
};
|
48
|
-
}
|
49
|
-
function mapServiceToLabelSelector(service) {
|
50
|
-
return {
|
51
|
-
matchLabels: service.spec.selector
|
52
|
-
};
|
53
|
-
}
|
54
|
-
function getServiceHost(service) {
|
55
|
-
return interpolate`${service.metadata.name}.${service.metadata.namespace}.svc`;
|
56
|
-
}
|
57
|
-
function getRequiredServicePortByName(service, name) {
|
58
|
-
return service.spec.ports.apply((ports) => {
|
59
|
-
const port = ports.find((p) => p.name === name);
|
60
|
-
if (!port) {
|
61
|
-
throw new Error(`Service does not have a port with name ${name}`);
|
62
|
-
}
|
63
|
-
return port.port;
|
64
|
-
});
|
65
|
-
}
|
66
|
-
|
67
|
-
function resolveBackendRef(ref) {
|
68
|
-
if (core.v1.Service.isInstance(ref)) {
|
34
|
+
get entity() {
|
69
35
|
return output({
|
70
|
-
|
71
|
-
|
72
|
-
|
36
|
+
type: "k8s.persistent-volume-claim",
|
37
|
+
clusterInfo: this.clusterInfo,
|
38
|
+
metadata: this.metadata
|
73
39
|
});
|
74
40
|
}
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
41
|
+
static create(name, args, opts) {
|
42
|
+
return new CreatedPersistentVolumeClaim(name, args, opts);
|
43
|
+
}
|
44
|
+
static of(name, entity, opts) {
|
45
|
+
return new ExternalPersistentVolumeClaim(
|
46
|
+
name,
|
47
|
+
output(entity).metadata,
|
48
|
+
output(entity).clusterInfo,
|
49
|
+
opts
|
50
|
+
);
|
84
51
|
}
|
85
|
-
return output({
|
86
|
-
name: ref.name,
|
87
|
-
namespace: ref.namespace,
|
88
|
-
port: ref.port
|
89
|
-
});
|
90
52
|
}
|
91
|
-
|
92
|
-
class HttpRoute extends ComponentResource {
|
93
|
-
/**
|
94
|
-
* The underlying Kubernetes resource.
|
95
|
-
*/
|
96
|
-
route;
|
53
|
+
class CreatedPersistentVolumeClaim extends PersistentVolumeClaim {
|
97
54
|
constructor(name, args, opts) {
|
98
|
-
|
99
|
-
|
100
|
-
args,
|
101
|
-
gatewayNamespace: output(args.gateway).metadata.namespace
|
102
|
-
}).apply(({ args: args2, gatewayNamespace }) => {
|
103
|
-
return new gateway.v1.HTTPRoute(
|
55
|
+
const pvc = output(args).apply((args2) => {
|
56
|
+
return new core.v1.PersistentVolumeClaim(
|
104
57
|
name,
|
105
58
|
{
|
106
|
-
metadata: mapMetadata(
|
59
|
+
metadata: mapMetadata(args2, name),
|
60
|
+
spec: deepmerge(
|
107
61
|
{
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
spec: {
|
114
|
-
hostnames: normalize(args2.hostname, args2.hostnames),
|
115
|
-
parentRefs: [
|
116
|
-
{
|
117
|
-
name: args2.gateway.metadata.name
|
62
|
+
accessModes: ["ReadWriteOnce"],
|
63
|
+
resources: {
|
64
|
+
requests: {
|
65
|
+
storage: args2.size ?? "100Mi"
|
66
|
+
}
|
118
67
|
}
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
timeouts: rule.timeouts,
|
123
|
-
matches: pipe(
|
124
|
-
normalize(rule.match, rule.matches),
|
125
|
-
map(mapHttpRouteRuleMatch),
|
126
|
-
addDefaultPathMatch
|
127
|
-
),
|
128
|
-
filters: normalize(rule.filter, rule.filters),
|
129
|
-
backendRefs: rule.backend ? [resolveBackendRef(rule.backend)] : void 0
|
130
|
-
}))
|
131
|
-
}
|
68
|
+
},
|
69
|
+
omit(args2, extraPersistentVolumeClaimArgs)
|
70
|
+
)
|
132
71
|
},
|
133
|
-
|
72
|
+
opts
|
134
73
|
);
|
135
74
|
});
|
136
|
-
|
75
|
+
super(
|
76
|
+
"k8s:PersistentVolumeClaim",
|
77
|
+
name,
|
78
|
+
args,
|
79
|
+
opts,
|
80
|
+
output(args.cluster).info,
|
81
|
+
pvc.metadata,
|
82
|
+
pvc.spec,
|
83
|
+
pvc.status
|
84
|
+
);
|
137
85
|
}
|
138
86
|
}
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
87
|
+
class ExternalPersistentVolumeClaim extends PersistentVolumeClaim {
|
88
|
+
constructor(name, id, clusterInfo, opts) {
|
89
|
+
const pvc = output(id).apply(async (id2) => {
|
90
|
+
await verifyProvider(opts.provider, this.clusterInfo);
|
91
|
+
return core.v1.PersistentVolumeClaim.get(
|
92
|
+
//
|
93
|
+
name,
|
94
|
+
resourceIdToString(id2),
|
95
|
+
{ parent: this, provider: opts.provider }
|
96
|
+
);
|
97
|
+
});
|
98
|
+
super(
|
99
|
+
"highstate:k8s:ExternalPersistentVolumeClaim",
|
100
|
+
name,
|
101
|
+
{ id, clusterInfo },
|
102
|
+
opts,
|
103
|
+
output(clusterInfo),
|
104
|
+
pvc.metadata,
|
105
|
+
pvc.spec,
|
106
|
+
pvc.status
|
107
|
+
);
|
145
108
|
}
|
146
|
-
return match;
|
147
109
|
}
|
148
110
|
|
149
111
|
const containerExtraArgs = [
|
@@ -154,10 +116,11 @@ const containerExtraArgs = [
|
|
154
116
|
"environmentSource",
|
155
117
|
"environmentSources"
|
156
118
|
];
|
157
|
-
function mapContainerToRaw(
|
119
|
+
function mapContainerToRaw(container, fallbackName) {
|
120
|
+
const containerName = container.name ?? fallbackName;
|
158
121
|
return {
|
159
122
|
...omit(container, containerExtraArgs),
|
160
|
-
name:
|
123
|
+
name: containerName,
|
161
124
|
ports: normalize(container.port, container.ports),
|
162
125
|
volumeMounts: map(normalize(container.volumeMount, container.volumeMounts), mapVolumeMount),
|
163
126
|
env: concat(
|
@@ -221,7 +184,10 @@ function mapVolumeMount(volumeMount) {
|
|
221
184
|
["volume"]
|
222
185
|
);
|
223
186
|
}
|
224
|
-
return
|
187
|
+
return {
|
188
|
+
...volumeMount,
|
189
|
+
name: volumeMount.name
|
190
|
+
};
|
225
191
|
}
|
226
192
|
function mapEnvironmentSource(envFrom) {
|
227
193
|
if (envFrom instanceof core.v1.ConfigMap) {
|
@@ -241,6 +207,14 @@ function mapEnvironmentSource(envFrom) {
|
|
241
207
|
return envFrom;
|
242
208
|
}
|
243
209
|
function mapWorkloadVolume(volume) {
|
210
|
+
if (volume instanceof PersistentVolumeClaim) {
|
211
|
+
return {
|
212
|
+
name: volume.metadata.name,
|
213
|
+
persistentVolumeClaim: {
|
214
|
+
claimName: volume.metadata.name
|
215
|
+
}
|
216
|
+
};
|
217
|
+
}
|
244
218
|
if (volume instanceof core.v1.PersistentVolumeClaim) {
|
245
219
|
return {
|
246
220
|
name: volume.metadata.name,
|
@@ -268,182 +242,272 @@ function mapWorkloadVolume(volume) {
|
|
268
242
|
return volume;
|
269
243
|
}
|
270
244
|
|
271
|
-
const
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
245
|
+
const workloadExtraArgs = [...commonExtraArgs, "container", "containers"];
|
246
|
+
const publicWorkloadExtraArgs = [...workloadExtraArgs, "service", "httpRoute"];
|
247
|
+
function getWorkloadComponents(name, args) {
|
248
|
+
const labels = {
|
249
|
+
"app.kubernetes.io/name": name
|
250
|
+
};
|
251
|
+
const containers = output$1(args).apply((args2) => normalize(args2.container, args2.containers));
|
252
|
+
const volumes = containers.apply((containers2) => {
|
253
|
+
const containerVolumes = containers2.flatMap((container) => normalize(container.volume, container.volumes)).map(mapWorkloadVolume);
|
254
|
+
const containerVolumeMounts = containers2.flatMap((container) => {
|
255
|
+
return normalize(container.volumeMount, container.volumeMounts).map((volumeMount) => {
|
256
|
+
return "volume" in volumeMount ? volumeMount.volume : void 0;
|
257
|
+
}).filter(Boolean);
|
258
|
+
}).map(mapWorkloadVolume);
|
259
|
+
return uniqueBy([...containerVolumes, ...containerVolumeMounts], (volume) => volume.name);
|
260
|
+
});
|
261
|
+
return { labels, containers, volumes };
|
262
|
+
}
|
263
|
+
function getPublicWorkloadComponents(name, args, parent, opts) {
|
264
|
+
const { labels, containers, volumes } = getWorkloadComponents(name, args);
|
265
|
+
const service = output$1({ args, containers }).apply(({ args: args2, containers: containers2 }) => {
|
266
|
+
if (!args2.service && !args2.httpRoute) {
|
267
|
+
return void 0;
|
268
|
+
}
|
269
|
+
if (args2.patch?.service) {
|
270
|
+
return Service.of(name, args2.patch.service, { parent: parent(), ...opts });
|
271
|
+
}
|
272
|
+
if (args2.patch) {
|
273
|
+
return void 0;
|
274
|
+
}
|
275
|
+
const ports = containers2.flatMap((container) => normalize(container.port, container.ports));
|
276
|
+
return Service.create(
|
277
|
+
name,
|
278
|
+
{
|
279
|
+
...args2.service,
|
280
|
+
selector: labels,
|
281
|
+
cluster: args2.cluster,
|
282
|
+
namespace: args2.namespace,
|
283
|
+
ports: (
|
284
|
+
// allow to completely override the ports
|
285
|
+
!args2.service?.port && !args2.service?.ports ? ports.map(mapContainerPortToServicePort) : args2.service?.ports
|
286
|
+
)
|
287
|
+
},
|
288
|
+
{ parent: parent(), ...opts }
|
289
|
+
);
|
290
|
+
});
|
291
|
+
const httpRoute = output$1({
|
292
|
+
args,
|
293
|
+
service
|
294
|
+
}).apply(({ args: args2, service: service2 }) => {
|
295
|
+
if (!args2.httpRoute || !service2) {
|
296
|
+
return void 0;
|
297
|
+
}
|
298
|
+
if (args2.patch) {
|
299
|
+
return void 0;
|
300
|
+
}
|
301
|
+
return new HttpRoute(
|
302
|
+
name,
|
303
|
+
{
|
304
|
+
...args2.httpRoute,
|
305
|
+
rule: {
|
306
|
+
backend: service2
|
307
|
+
}
|
308
|
+
},
|
309
|
+
{ parent: parent(), ...opts }
|
310
|
+
);
|
311
|
+
});
|
312
|
+
return { labels, containers, volumes, service, httpRoute };
|
313
|
+
}
|
314
|
+
|
279
315
|
class Deployment extends ComponentResource {
|
316
|
+
constructor(type, name, args, opts, clusterInfo, metadata, spec, status, _service, _httpRoute, resources) {
|
317
|
+
super(type, name, args, opts);
|
318
|
+
this.clusterInfo = clusterInfo;
|
319
|
+
this.metadata = metadata;
|
320
|
+
this.spec = spec;
|
321
|
+
this.status = status;
|
322
|
+
this._service = _service;
|
323
|
+
this._httpRoute = _httpRoute;
|
324
|
+
this.resources = resources;
|
325
|
+
}
|
280
326
|
/**
|
281
|
-
* The
|
327
|
+
* The Highstate deployment entity.
|
282
328
|
*/
|
283
|
-
|
329
|
+
get entity() {
|
330
|
+
return output({
|
331
|
+
type: "k8s.deployment",
|
332
|
+
clusterInfo: this.clusterInfo,
|
333
|
+
metadata: this.metadata,
|
334
|
+
spec: this.spec,
|
335
|
+
service: this._service.apply((service) => service?.entity)
|
336
|
+
});
|
337
|
+
}
|
284
338
|
/**
|
285
339
|
* The service associated with the deployment.
|
286
340
|
*/
|
287
|
-
service
|
341
|
+
get service() {
|
342
|
+
return this._service.apply((service) => {
|
343
|
+
if (!service) {
|
344
|
+
throw new Error("The service is not available.");
|
345
|
+
}
|
346
|
+
return service;
|
347
|
+
});
|
348
|
+
}
|
288
349
|
/**
|
289
350
|
* The HTTP route associated with the deployment.
|
290
351
|
*/
|
291
|
-
httpRoute
|
352
|
+
get httpRoute() {
|
353
|
+
return this._httpRoute.apply((httpRoute) => {
|
354
|
+
if (!httpRoute) {
|
355
|
+
throw new Error("The HTTP route is not available.");
|
356
|
+
}
|
357
|
+
return httpRoute;
|
358
|
+
});
|
359
|
+
}
|
360
|
+
static create(name, args, opts) {
|
361
|
+
return new CreatedDeployment(name, args, opts);
|
362
|
+
}
|
363
|
+
}
|
364
|
+
class CreatedDeployment extends Deployment {
|
292
365
|
constructor(name, args, opts) {
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
366
|
+
const { labels, containers, volumes, service, httpRoute } = getPublicWorkloadComponents(
|
367
|
+
name,
|
368
|
+
args,
|
369
|
+
() => this,
|
370
|
+
opts
|
371
|
+
);
|
372
|
+
const deployment = output({ args, containers, volumes }).apply(
|
373
|
+
async ({ args: args2, containers: containers2, volumes: volumes2 }) => {
|
374
|
+
await verifyProvider(opts.provider, args2.cluster.info);
|
375
|
+
return new (args2.patch ? apps.v1.DeploymentPatch : apps.v1.Deployment)(
|
376
|
+
name,
|
377
|
+
{
|
378
|
+
metadata: mapMetadata(args2.patch?.metadata ?? args2, name),
|
379
|
+
spec: deepmerge(
|
380
|
+
{
|
381
|
+
template: {
|
382
|
+
metadata: {
|
383
|
+
labels
|
384
|
+
},
|
385
|
+
spec: {
|
386
|
+
containers: containers2.map((container) => mapContainerToRaw(container, name)),
|
387
|
+
volumes: volumes2
|
388
|
+
}
|
308
389
|
},
|
309
|
-
|
310
|
-
|
311
|
-
volumes: containers.flatMap((container) => normalize(container.volume, container.volumes)).map(mapWorkloadVolume)
|
390
|
+
selector: {
|
391
|
+
matchLabels: labels
|
312
392
|
}
|
313
393
|
},
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
)
|
320
|
-
},
|
321
|
-
{
|
322
|
-
...opts,
|
323
|
-
parent: this
|
324
|
-
}
|
325
|
-
);
|
326
|
-
});
|
327
|
-
this.service = output({
|
328
|
-
args: args.service,
|
329
|
-
httpRouteArgs: args.httpRoute,
|
330
|
-
namespace: this.deployment.metadata.namespace,
|
331
|
-
containers: this.deployment.spec.template.spec.containers
|
332
|
-
}).apply(({ args: args2, httpRouteArgs, namespace, containers }) => {
|
333
|
-
if (!args2 && !httpRouteArgs) {
|
334
|
-
return void 0;
|
335
|
-
}
|
336
|
-
const ports = containers.flatMap((container) => container.ports ?? []);
|
337
|
-
return new Service(
|
338
|
-
args2?.name ?? name,
|
339
|
-
{
|
340
|
-
...args2,
|
341
|
-
namespace,
|
342
|
-
ports: (
|
343
|
-
// allow to completely override the ports
|
344
|
-
!args2?.port && !args2?.ports ? ports.map(mapContainerPortToServicePort) : args2?.ports
|
345
|
-
),
|
346
|
-
selector: labels
|
347
|
-
},
|
348
|
-
{
|
349
|
-
...opts,
|
350
|
-
parent: this
|
351
|
-
}
|
352
|
-
);
|
353
|
-
});
|
354
|
-
this.httpRoute = output({
|
355
|
-
args: args.httpRoute,
|
356
|
-
service: this.service
|
357
|
-
}).apply(({ args: args2, service }) => {
|
358
|
-
if (!args2 || !service) {
|
359
|
-
return void 0;
|
360
|
-
}
|
361
|
-
return new HttpRoute(
|
362
|
-
name,
|
363
|
-
{
|
364
|
-
...args2,
|
365
|
-
gateway: args2.gateway,
|
366
|
-
rule: {
|
367
|
-
backend: service.service
|
368
|
-
}
|
369
|
-
},
|
370
|
-
{
|
371
|
-
...opts,
|
372
|
-
parent: this
|
373
|
-
}
|
374
|
-
);
|
375
|
-
});
|
376
|
-
this.registerOutputs({
|
377
|
-
deployment: this.deployment,
|
378
|
-
service: this.service
|
379
|
-
});
|
380
|
-
}
|
381
|
-
getRequiredService() {
|
382
|
-
return this.service.apply((service) => {
|
383
|
-
if (!service) {
|
384
|
-
throw new Error("The service is not available for this deployment.");
|
394
|
+
omit(args2, publicWorkloadExtraArgs)
|
395
|
+
)
|
396
|
+
},
|
397
|
+
{ parent: this, ...opts }
|
398
|
+
);
|
385
399
|
}
|
386
|
-
|
387
|
-
|
400
|
+
);
|
401
|
+
super(
|
402
|
+
"highstate:k8s:Deployment",
|
403
|
+
name,
|
404
|
+
args,
|
405
|
+
opts,
|
406
|
+
output(args.cluster).info,
|
407
|
+
deployment.metadata,
|
408
|
+
deployment.spec,
|
409
|
+
deployment.status,
|
410
|
+
service,
|
411
|
+
httpRoute,
|
412
|
+
[deployment]
|
413
|
+
);
|
388
414
|
}
|
389
415
|
}
|
390
416
|
|
391
|
-
function mapPersistentVolumeClaimToRaw(args) {
|
392
|
-
return {
|
393
|
-
metadata: mapMetadata(args),
|
394
|
-
spec: args
|
395
|
-
};
|
396
|
-
}
|
397
|
-
|
398
417
|
class StatefulSet extends ComponentResource {
|
418
|
+
constructor(type, name, args, opts, clusterInfo, metadata, spec, status, _service, _httpRoute) {
|
419
|
+
super(type, name, args, opts);
|
420
|
+
this.clusterInfo = clusterInfo;
|
421
|
+
this.metadata = metadata;
|
422
|
+
this.spec = spec;
|
423
|
+
this.status = status;
|
424
|
+
this._service = _service;
|
425
|
+
this._httpRoute = _httpRoute;
|
426
|
+
}
|
399
427
|
/**
|
400
|
-
* The
|
428
|
+
* The Highstate stateful set entity.
|
401
429
|
*/
|
402
|
-
|
430
|
+
get entity() {
|
431
|
+
return output({
|
432
|
+
type: "k8s.stateful-set",
|
433
|
+
clusterInfo: this.clusterInfo,
|
434
|
+
metadata: this.metadata,
|
435
|
+
service: this.service.entity
|
436
|
+
});
|
437
|
+
}
|
403
438
|
/**
|
404
439
|
* The service associated with the stateful set.
|
405
440
|
*/
|
406
|
-
service
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
this.service = output(args.service).apply((service) => {
|
413
|
-
return new Service(
|
414
|
-
service?.name ?? name,
|
415
|
-
{
|
416
|
-
...service,
|
417
|
-
clusterIP: "None"
|
418
|
-
},
|
419
|
-
{ ...opts, parent: this }
|
420
|
-
);
|
421
|
-
});
|
422
|
-
this.statefulSet = output(args).apply((args2) => {
|
423
|
-
return new apps.v1.StatefulSet(name, {
|
424
|
-
metadata: mapMetadata(args2),
|
425
|
-
spec: mergeDeep(args2, {
|
426
|
-
serviceName: this.service.service.metadata.name,
|
427
|
-
template: {
|
428
|
-
metadata: {
|
429
|
-
labels
|
430
|
-
},
|
431
|
-
spec: {
|
432
|
-
containers: normalize(args2.container, args2.containers).map((container) => mapContainerToRaw(name, container))
|
433
|
-
}
|
434
|
-
},
|
435
|
-
selector: {
|
436
|
-
matchLabels: labels
|
437
|
-
},
|
438
|
-
volumeClaimTemplates: normalize(args2.volumeClaim, args2.volumeClaims).map(mapPersistentVolumeClaimToRaw)
|
439
|
-
})
|
440
|
-
});
|
441
|
+
get service() {
|
442
|
+
return this._service.apply((service) => {
|
443
|
+
if (!service) {
|
444
|
+
throw new Error("The service is not available.");
|
445
|
+
}
|
446
|
+
return service;
|
441
447
|
});
|
442
|
-
|
443
|
-
|
444
|
-
|
448
|
+
}
|
449
|
+
/**
|
450
|
+
* The HTTP route associated with the stateful set.
|
451
|
+
*/
|
452
|
+
get httpRoute() {
|
453
|
+
return this._httpRoute.apply((httpRoute) => {
|
454
|
+
if (!httpRoute) {
|
455
|
+
throw new Error("The HTTP route is not available.");
|
456
|
+
}
|
457
|
+
return httpRoute;
|
445
458
|
});
|
446
459
|
}
|
460
|
+
static create(name, args, opts) {
|
461
|
+
return new CreatedStatefulSet(name, args, opts);
|
462
|
+
}
|
463
|
+
}
|
464
|
+
class CreatedStatefulSet extends StatefulSet {
|
465
|
+
constructor(name, args, opts) {
|
466
|
+
const { containers, volumes, labels, service, httpRoute } = getPublicWorkloadComponents(
|
467
|
+
name,
|
468
|
+
args,
|
469
|
+
() => this,
|
470
|
+
opts
|
471
|
+
);
|
472
|
+
const statefulSet = output({ args, containers, volumes, service }).apply(
|
473
|
+
async ({ args: args2, containers: containers2, volumes: volumes2, service: service2 }) => {
|
474
|
+
await verifyProvider(opts.provider, args2.cluster?.info);
|
475
|
+
return new (args2.patch ? apps.v1.StatefulSetPatch : apps.v1.StatefulSet)(
|
476
|
+
name,
|
477
|
+
{
|
478
|
+
metadata: mapMetadata(args2.patch?.metadata ?? args2, name),
|
479
|
+
spec: deepmerge(
|
480
|
+
{
|
481
|
+
serviceName: service2?.metadata.name || name,
|
482
|
+
template: {
|
483
|
+
metadata: !args2.patch ? { labels } : void 0,
|
484
|
+
spec: {
|
485
|
+
containers: containers2.map((container) => mapContainerToRaw(container, name)),
|
486
|
+
volumes: volumes2
|
487
|
+
}
|
488
|
+
},
|
489
|
+
selector: !args2.patch ? { matchLabels: labels } : void 0
|
490
|
+
},
|
491
|
+
omit(args2, publicWorkloadExtraArgs)
|
492
|
+
)
|
493
|
+
},
|
494
|
+
{ parent: this, ...opts }
|
495
|
+
);
|
496
|
+
}
|
497
|
+
);
|
498
|
+
super(
|
499
|
+
"highstate:k8s:StatefulSet",
|
500
|
+
name,
|
501
|
+
args,
|
502
|
+
opts,
|
503
|
+
output(args.cluster).info,
|
504
|
+
statefulSet.metadata,
|
505
|
+
statefulSet.spec,
|
506
|
+
statefulSet.status,
|
507
|
+
service,
|
508
|
+
httpRoute
|
509
|
+
);
|
510
|
+
}
|
447
511
|
}
|
448
512
|
|
449
513
|
class NetworkPolicy extends ComponentResource {
|
@@ -456,11 +520,28 @@ class NetworkPolicy extends ComponentResource {
|
|
456
520
|
const normalizedArgs = output(args).apply((args2) => {
|
457
521
|
const ingressRules = normalize(args2.ingressRule, args2.ingressRules);
|
458
522
|
const egressRules = normalize(args2.egressRule, args2.egressRules);
|
523
|
+
const endpoints = normalize(args2.egressRule?.toEndpoint, args2.egressRule?.toEndpoints);
|
524
|
+
const parsedEndpoints = endpoints.map((endpoint) => parseDomain(endpoint));
|
525
|
+
const cidrsFromEndpoints = parsedEndpoints.filter((result) => result.type === ParseResultType.Ip).map((result) => NetworkPolicy.mapCidrFromEndpoint(result));
|
526
|
+
const fqdnsFromEndpoints = parsedEndpoints.filter((result) => result.type !== ParseResultType.Invalid).map((result) => result.hostname);
|
527
|
+
const extraEgressRules = [];
|
528
|
+
if (args2.allowKubeDns) {
|
529
|
+
extraEgressRules.push({
|
530
|
+
namespaces: ["kube-system"],
|
531
|
+
selectors: [{ matchLabels: { "k8s-app": "kube-dns" } }],
|
532
|
+
ports: [{ port: 53, protocol: "UDP" }],
|
533
|
+
all: false,
|
534
|
+
cidrs: [],
|
535
|
+
fqdns: [],
|
536
|
+
services: []
|
537
|
+
});
|
538
|
+
}
|
459
539
|
return {
|
460
540
|
...args2,
|
461
541
|
podSelector: args2.selector ? mapSelectorLikeToSelector(args2.selector) : {},
|
462
542
|
isolateEgress: args2.isolateEgress ?? false,
|
463
543
|
isolateIngress: args2.isolateIngress ?? false,
|
544
|
+
allowKubeApiServer: args2.allowKubeApiServer ?? false,
|
464
545
|
ingressRules: ingressRules.map((rule) => ({
|
465
546
|
all: rule.fromAll ?? false,
|
466
547
|
cidrs: normalize(rule.fromCidr, rule.fromCidrs),
|
@@ -470,15 +551,17 @@ class NetworkPolicy extends ComponentResource {
|
|
470
551
|
selectors: normalize(rule.fromSelector, rule.fromSelectors),
|
471
552
|
ports: normalize(rule.toPort, rule.toPorts)
|
472
553
|
})),
|
473
|
-
egressRules: egressRules.map((rule) =>
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
554
|
+
egressRules: egressRules.map((rule) => {
|
555
|
+
return {
|
556
|
+
all: rule.toAll ?? false,
|
557
|
+
cidrs: normalize(rule.toCidr, rule.toCidrs).concat(cidrsFromEndpoints),
|
558
|
+
fqdns: normalize(rule.toFqdn, rule.toFqdns).concat(fqdnsFromEndpoints),
|
559
|
+
services: normalize(rule.toService, rule.toServices),
|
560
|
+
namespaces: normalize(rule.toNamespace, rule.toNamespaces),
|
561
|
+
selectors: normalize(rule.toSelector, rule.toSelectors),
|
562
|
+
ports: normalize(rule.toPort, rule.toPorts)
|
563
|
+
};
|
564
|
+
}).concat(extraEgressRules)
|
482
565
|
};
|
483
566
|
});
|
484
567
|
this.networkPolicy = normalizedArgs.apply((args2) => {
|
@@ -488,9 +571,16 @@ class NetworkPolicy extends ComponentResource {
|
|
488
571
|
});
|
489
572
|
this.registerOutputs({ networkPolicy: this.networkPolicy });
|
490
573
|
}
|
574
|
+
static mapCidrFromEndpoint(result) {
|
575
|
+
if (result.ipVersion === 4) {
|
576
|
+
return `${result.hostname}/32`;
|
577
|
+
}
|
578
|
+
return `${result.hostname}/128`;
|
579
|
+
}
|
580
|
+
static supportedCNIs = ["cilium"];
|
491
581
|
static create(name, args, opts) {
|
492
582
|
return output(args).apply(async (args2) => {
|
493
|
-
if (!args2.cni || args2.cni
|
583
|
+
if (!args2.cni || !NetworkPolicy.supportedCNIs.includes(args2.cni)) {
|
494
584
|
return new NativeNetworkPolicy(name, args2, opts);
|
495
585
|
}
|
496
586
|
const implName = `${capitalize(args2.cni)}NetworkPolicy`;
|
@@ -502,6 +592,56 @@ class NetworkPolicy extends ComponentResource {
|
|
502
592
|
return new implClass(name, args2, opts);
|
503
593
|
});
|
504
594
|
}
|
595
|
+
static allowInsideNamespace(namespace, k8sCluster, opts) {
|
596
|
+
return NetworkPolicy.create(
|
597
|
+
"allow-inside-namespace",
|
598
|
+
{
|
599
|
+
namespace,
|
600
|
+
cni: output(k8sCluster).info.cni,
|
601
|
+
description: "Allow all traffic inside the namespace.",
|
602
|
+
selector: {},
|
603
|
+
ingressRule: { fromNamespace: namespace },
|
604
|
+
egressRule: { toNamespace: namespace }
|
605
|
+
},
|
606
|
+
opts
|
607
|
+
);
|
608
|
+
}
|
609
|
+
static allowKubeApiServer(namespace, k8sCluster, opts) {
|
610
|
+
return NetworkPolicy.create(
|
611
|
+
"allow-kube-api-server",
|
612
|
+
{
|
613
|
+
namespace,
|
614
|
+
cni: output(k8sCluster).info.cni,
|
615
|
+
description: "Allow all traffic to the Kubernetes API server from the namespace.",
|
616
|
+
allowKubeApiServer: true
|
617
|
+
},
|
618
|
+
opts
|
619
|
+
);
|
620
|
+
}
|
621
|
+
static allowKubeDns(namespace, k8sCluster, opts) {
|
622
|
+
return NetworkPolicy.create(
|
623
|
+
"allow-kube-dns",
|
624
|
+
{
|
625
|
+
namespace,
|
626
|
+
cni: output(k8sCluster).info.cni,
|
627
|
+
description: "Allow all traffic to the Kubernetes DNS server from the namespace.",
|
628
|
+
allowKubeDns: true
|
629
|
+
},
|
630
|
+
opts
|
631
|
+
);
|
632
|
+
}
|
633
|
+
static allowAllEgress(namespace, k8sCluster, opts) {
|
634
|
+
return NetworkPolicy.create(
|
635
|
+
"allow-all-egress",
|
636
|
+
{
|
637
|
+
namespace,
|
638
|
+
cni: output(k8sCluster).info.cni,
|
639
|
+
description: "Allow all egress traffic from the namespace.",
|
640
|
+
egressRule: { toAll: true }
|
641
|
+
},
|
642
|
+
opts
|
643
|
+
);
|
644
|
+
}
|
505
645
|
}
|
506
646
|
class NativeNetworkPolicy extends NetworkPolicy {
|
507
647
|
create(name, args, opts) {
|
@@ -545,10 +685,16 @@ class NativeNetworkPolicy extends NetworkPolicy {
|
|
545
685
|
if (needFallback) {
|
546
686
|
return [{ to: [{ ipBlock: NativeNetworkPolicy.fallbackIpBlock }] }];
|
547
687
|
}
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
}
|
688
|
+
const extraRules = [];
|
689
|
+
if (args.allowKubeApiServer) {
|
690
|
+
extraRules.push({ to: [{ ipBlock: { cidr: "10.96.0.1" } }] });
|
691
|
+
}
|
692
|
+
return args.egressRules.map((rule) => {
|
693
|
+
return {
|
694
|
+
to: rule.all ? void 0 : NativeNetworkPolicy.createRulePeers(rule),
|
695
|
+
ports: NativeNetworkPolicy.mapPorts(rule.ports)
|
696
|
+
};
|
697
|
+
}).concat(extraRules);
|
552
698
|
}
|
553
699
|
static createRulePeers(args) {
|
554
700
|
return [
|
@@ -609,28 +755,80 @@ class NativeNetworkPolicy extends NetworkPolicy {
|
|
609
755
|
}
|
610
756
|
|
611
757
|
function useAccessPoint(args) {
|
612
|
-
const result = output(args).apply(
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
758
|
+
const result = output({ args, namespaceName: output(args.namespace).metadata.name }).apply(
|
759
|
+
({ args: args2, namespaceName }) => {
|
760
|
+
const gateway2 = createGateway({
|
761
|
+
...args2,
|
762
|
+
annotations: {
|
763
|
+
"cert-manager.io/cluster-issuer": args2.accessPoint.tlsIssuer.clusterIssuerName
|
764
|
+
},
|
765
|
+
gateway: args2.accessPoint.gateway
|
766
|
+
});
|
767
|
+
const dnsRecords = normalize(args2.fqdn, args2.fqdns).map((fqdn) => {
|
768
|
+
return DnsRecord.create(fqdn, {
|
769
|
+
provider: args2.accessPoint.dnsProvider,
|
770
|
+
type: "A",
|
771
|
+
value: args2.accessPoint.gateway.ip
|
772
|
+
});
|
773
|
+
});
|
774
|
+
const networkPolicies = [];
|
775
|
+
if (args2.accessPoint.gateway.service) {
|
776
|
+
const displayName = getAppDisplayName(args2.accessPoint.gateway.service.metadata);
|
777
|
+
networkPolicies.push(
|
778
|
+
NetworkPolicy.create(
|
779
|
+
`allow-ingress-from-${getAppName(args2.accessPoint.gateway.service.metadata)}`,
|
780
|
+
{
|
781
|
+
cni: args2.accessPoint.gateway.service.clusterInfo.cni,
|
782
|
+
namespace: args2.namespace,
|
783
|
+
description: `Allow ingress traffic from the gateway "${displayName}".`,
|
784
|
+
ingressRule: {
|
785
|
+
fromNamespace: args2.accessPoint.gateway.service.metadata.namespace,
|
786
|
+
fromSelector: args2.accessPoint.gateway.service.spec.selector
|
787
|
+
}
|
788
|
+
},
|
789
|
+
{ provider: args2.provider }
|
790
|
+
),
|
791
|
+
NetworkPolicy.create(
|
792
|
+
`allow-egress-to-${namespaceName}`,
|
793
|
+
{
|
794
|
+
cni: args2.accessPoint.gateway.service.clusterInfo.cni,
|
795
|
+
namespace: args2.accessPoint.gateway.service.metadata.namespace,
|
796
|
+
selector: args2.accessPoint.gateway.service.spec.selector,
|
797
|
+
description: `Allow egress traffic to the namespace "${namespaceName}".`,
|
798
|
+
egressRule: {
|
799
|
+
toNamespace: args2.namespace
|
800
|
+
}
|
801
|
+
},
|
802
|
+
{ provider: args2.provider }
|
803
|
+
)
|
804
|
+
);
|
805
|
+
}
|
806
|
+
return output({
|
807
|
+
gateway: gateway2,
|
808
|
+
dnsRecords,
|
809
|
+
networkPolicies
|
810
|
+
});
|
811
|
+
}
|
812
|
+
);
|
630
813
|
return toPromise(result);
|
631
814
|
}
|
815
|
+
function useStandardAcessPoint(appName, namespace, args, inputs, provider) {
|
816
|
+
return useAccessPoint({
|
817
|
+
name: appName,
|
818
|
+
namespace,
|
819
|
+
fqdn: args.fqdn,
|
820
|
+
accessPoint: inputs.accessPoint,
|
821
|
+
clusterInfo: inputs.k8sCluster.info,
|
822
|
+
provider
|
823
|
+
});
|
824
|
+
}
|
632
825
|
function createGateway(args) {
|
633
826
|
return output(args).apply((args2) => {
|
827
|
+
if (args2.clusterInfo.id !== args2.gateway.clusterInfo.id) {
|
828
|
+
throw new Error(
|
829
|
+
"The provided Kubernetes cluster is different from the one where the gateway controller is deployed."
|
830
|
+
);
|
831
|
+
}
|
634
832
|
return new gateway.v1.Gateway(
|
635
833
|
args2.name,
|
636
834
|
{
|
@@ -641,18 +839,19 @@ function createGateway(args) {
|
|
641
839
|
},
|
642
840
|
spec: {
|
643
841
|
gatewayClassName: output(args2.gateway).gatewayClassName,
|
644
|
-
listeners:
|
645
|
-
|
646
|
-
|
842
|
+
listeners: normalize(args2.fqdn, args2.fqdns).map((fqdn) => {
|
843
|
+
const normalizedName = fqdn.replace(/\*/g, "wildcard");
|
844
|
+
return {
|
845
|
+
name: `https-${normalizedName}`,
|
647
846
|
port: output(args2.gateway).httpsListenerPort,
|
648
847
|
protocol: "HTTPS",
|
649
|
-
hostname:
|
848
|
+
hostname: fqdn,
|
650
849
|
tls: {
|
651
850
|
mode: "Terminate",
|
652
|
-
certificateRefs: [{ name:
|
851
|
+
certificateRefs: [{ name: normalizedName }]
|
653
852
|
}
|
654
|
-
}
|
655
|
-
|
853
|
+
};
|
854
|
+
})
|
656
855
|
}
|
657
856
|
},
|
658
857
|
{ provider: args2.provider, deletedWith: args2.namespace }
|
@@ -882,7 +1081,7 @@ class Job extends ComponentResource {
|
|
882
1081
|
{
|
883
1082
|
template: {
|
884
1083
|
spec: {
|
885
|
-
containers: containers.map((container) => mapContainerToRaw(
|
1084
|
+
containers: containers.map((container) => mapContainerToRaw(container, name)),
|
886
1085
|
volumes: containers.flatMap((container) => normalize(container.volume, container.volumes)).map(mapWorkloadVolume),
|
887
1086
|
restartPolicy: "Never"
|
888
1087
|
}
|
@@ -918,7 +1117,7 @@ class CronJob extends ComponentResource {
|
|
918
1117
|
spec: {
|
919
1118
|
template: {
|
920
1119
|
spec: {
|
921
|
-
containers: containers.map((container) => mapContainerToRaw(
|
1120
|
+
containers: containers.map((container) => mapContainerToRaw(container, name)),
|
922
1121
|
volumes: containers.flatMap((container) => normalize(container.volume, container.volumes)).map(mapWorkloadVolume)
|
923
1122
|
}
|
924
1123
|
}
|
@@ -936,20 +1135,4 @@ class CronJob extends ComponentResource {
|
|
936
1135
|
}
|
937
1136
|
}
|
938
1137
|
|
939
|
-
|
940
|
-
const services = chart.resources.apply((resources) => {
|
941
|
-
return resources.filter((r) => core.v1.Service.isInstance(r)).map((service) => ({ name: service.metadata.name, service }));
|
942
|
-
});
|
943
|
-
return output$1(services).apply((services2) => {
|
944
|
-
const service = services2.find((s) => s.name === name)?.service;
|
945
|
-
if (!service) {
|
946
|
-
throw new Error(`Service with name '${name}' not found in the chart resources`);
|
947
|
-
}
|
948
|
-
return service;
|
949
|
-
});
|
950
|
-
}
|
951
|
-
function getChartService(chart, name) {
|
952
|
-
return toPromise(getChartServiceOutput(chart, name));
|
953
|
-
}
|
954
|
-
|
955
|
-
export { CronJob, Deployment, HttpRoute, Job, NetworkPolicy, ScriptBundle, Service, StatefulSet, createScriptContainer, getChartService, getChartServiceOutput, getServiceHost, mapContainerPortToServicePort, mapMetadata, mapNamespaceLikeToNamespaceName, mapNamespaceNameToSelector, mapSelectorLikeToSelector, mapServiceToLabelSelector, useAccessPoint };
|
1138
|
+
export { CronJob, Deployment, HttpRoute, Job, NetworkPolicy, PersistentVolumeClaim, ScriptBundle, Service, StatefulSet, createScriptContainer, getAppDisplayName, getAppName, mapContainerPortToServicePort, mapMetadata, mapNamespaceLikeToNamespaceName, mapNamespaceNameToSelector, mapSelectorLikeToSelector, mapServiceToLabelSelector, useAccessPoint, useStandardAcessPoint };
|