@highstate/k8s 0.9.7 → 0.9.9

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.
@@ -0,0 +1,766 @@
1
+ import {
2
+ commonExtraArgs,
3
+ getProvider,
4
+ mapMetadata,
5
+ mapNamespaceLikeToNamespaceName,
6
+ mapNamespaceNameToSelector,
7
+ mapSelectorLikeToSelector,
8
+ resourceIdToString
9
+ } from "./chunk-HTQP2NB4.js";
10
+
11
+ // src/service.ts
12
+ import { core } from "@pulumi/kubernetes";
13
+ import {
14
+ ComponentResource,
15
+ normalize,
16
+ output
17
+ } from "@highstate/pulumi";
18
+ import { omit, uniqueBy } from "remeda";
19
+ import { deepmerge } from "deepmerge-ts";
20
+ import { filterEndpoints, l4EndpointToString, parseL3Endpoint } from "@highstate/common";
21
+ var serviceExtraArgs = [...commonExtraArgs, "port", "ports", "external"];
22
+ function hasServiceMetadata(endpoint) {
23
+ return endpoint.metadata?.k8sService !== void 0;
24
+ }
25
+ function getServiceMetadata(endpoint) {
26
+ return endpoint.metadata?.k8sService;
27
+ }
28
+ function withServiceMetadata(endpoint, metadata) {
29
+ return {
30
+ ...endpoint,
31
+ metadata: {
32
+ ...endpoint.metadata,
33
+ k8sService: metadata
34
+ }
35
+ };
36
+ }
37
+ function isFromCluster(endpoint, cluster) {
38
+ return getServiceMetadata(endpoint)?.clusterId === cluster.id;
39
+ }
40
+ var Service = class extends ComponentResource {
41
+ constructor(type, name, args, opts, cluster, metadata, spec, status) {
42
+ super(type, name, args, opts);
43
+ this.cluster = cluster;
44
+ this.metadata = metadata;
45
+ this.spec = spec;
46
+ this.status = status;
47
+ }
48
+ /**
49
+ * The Highstate service entity.
50
+ */
51
+ get entity() {
52
+ return output({
53
+ type: "k8s.service",
54
+ clusterId: this.cluster.id,
55
+ metadata: this.metadata,
56
+ endpoints: this.endpoints
57
+ });
58
+ }
59
+ static create(name, args, opts) {
60
+ return new CreatedService(name, args, opts);
61
+ }
62
+ static wrap(name, service, cluster, opts) {
63
+ return new WrappedService(name, service, cluster, opts);
64
+ }
65
+ static external(name, id, cluster, opts) {
66
+ return new ExternalService(name, id, cluster, opts);
67
+ }
68
+ static of(name, entity, cluster, opts) {
69
+ return new ExternalService(
70
+ name,
71
+ output(entity).metadata,
72
+ output({ cluster, entity }).apply(({ cluster: cluster2, entity: entity2 }) => {
73
+ if (cluster2.id !== entity2.clusterId) {
74
+ throw new Error(
75
+ `Cluster mismatch when wrapping service "${name}": "${cluster2.id}" != "${entity2.clusterId}"`
76
+ );
77
+ }
78
+ return cluster2;
79
+ }),
80
+ opts
81
+ );
82
+ }
83
+ /**
84
+ * Returns the endpoints of the service applying the given filter.
85
+ *
86
+ * If no filter is specified, the default behavior of `filterEndpoints` is used.
87
+ *
88
+ * @param filter If specified, the endpoints are filtered based on the given filter.
89
+ * @returns The endpoints of the service.
90
+ */
91
+ filterEndpoints(filter) {
92
+ return output({ endpoints: this.endpoints }).apply(({ endpoints }) => {
93
+ return filterEndpoints(endpoints, filter);
94
+ });
95
+ }
96
+ /**
97
+ * Returns the endpoints of the service including both internal and external endpoints.
98
+ */
99
+ get endpoints() {
100
+ return output({
101
+ cluster: this.cluster,
102
+ metadata: this.metadata,
103
+ spec: this.spec,
104
+ status: this.status
105
+ }).apply(({ cluster, metadata, spec, status }) => {
106
+ const endpointMetadata = {
107
+ k8sService: {
108
+ clusterId: cluster.id,
109
+ name: metadata.name,
110
+ namespace: metadata.namespace,
111
+ selector: spec.selector,
112
+ targetPort: spec.ports[0].targetPort ?? spec.ports[0].port
113
+ }
114
+ };
115
+ const clusterIpEndpoints = spec.clusterIPs?.map((ip) => ({
116
+ ...parseL3Endpoint(ip),
117
+ visibility: "internal",
118
+ port: spec.ports[0].port,
119
+ protocol: spec.ports[0].protocol?.toLowerCase(),
120
+ metadata: endpointMetadata
121
+ }));
122
+ if (clusterIpEndpoints.length > 0) {
123
+ clusterIpEndpoints.unshift({
124
+ type: "hostname",
125
+ visibility: "internal",
126
+ hostname: `${metadata.name}.${metadata.namespace}.svc.cluster.local`,
127
+ port: spec.ports[0].port,
128
+ protocol: spec.ports[0].protocol?.toLowerCase(),
129
+ metadata: endpointMetadata
130
+ });
131
+ }
132
+ const nodePortEndpoints = spec.type === "NodePort" ? cluster.endpoints.map((endpoint) => ({
133
+ ...endpoint,
134
+ port: spec.ports[0].nodePort,
135
+ protocol: spec.ports[0].protocol?.toLowerCase(),
136
+ metadata: endpointMetadata
137
+ })) : [];
138
+ const loadBalancerEndpoints = spec.type === "LoadBalancer" ? status.loadBalancer?.ingress?.map((endpoint) => ({
139
+ ...parseL3Endpoint(endpoint.ip ?? endpoint.hostname),
140
+ port: spec.ports[0].port,
141
+ protocol: spec.ports[0].protocol?.toLowerCase(),
142
+ metadata: endpointMetadata
143
+ })) : [];
144
+ return uniqueBy(
145
+ [
146
+ ...clusterIpEndpoints ?? [],
147
+ ...loadBalancerEndpoints ?? [],
148
+ ...nodePortEndpoints ?? []
149
+ ],
150
+ (endpoint) => l4EndpointToString(endpoint)
151
+ );
152
+ });
153
+ }
154
+ };
155
+ var CreatedService = class extends Service {
156
+ constructor(name, args, opts) {
157
+ const service = output(args).apply((args2) => {
158
+ return new core.v1.Service(
159
+ name,
160
+ {
161
+ metadata: mapMetadata(args2, name),
162
+ spec: deepmerge(
163
+ {
164
+ ports: normalize(args2.port, args2.ports),
165
+ externalIPs: args2.external ? args2.externalIPs ?? args2.cluster.externalIps : args2.cluster.externalIps,
166
+ type: getServiceType(args2, args2.cluster)
167
+ },
168
+ omit(args2, serviceExtraArgs)
169
+ )
170
+ },
171
+ { parent: this, ...opts }
172
+ );
173
+ });
174
+ super(
175
+ "highstate:k8s:Service",
176
+ name,
177
+ args,
178
+ opts,
179
+ output(args.cluster),
180
+ service.metadata,
181
+ service.spec,
182
+ service.status
183
+ );
184
+ }
185
+ };
186
+ var WrappedService = class extends Service {
187
+ constructor(name, service, cluster, opts) {
188
+ super(
189
+ "highstate:k8s:WrappedService",
190
+ name,
191
+ { service, clusterInfo: cluster },
192
+ opts,
193
+ output(cluster),
194
+ output(service).metadata,
195
+ output(service).spec,
196
+ output(service).status
197
+ );
198
+ }
199
+ };
200
+ var ExternalService = class extends Service {
201
+ constructor(name, id, cluster, opts) {
202
+ const service = output(id).apply((id2) => {
203
+ return core.v1.Service.get(
204
+ //
205
+ name,
206
+ resourceIdToString(id2),
207
+ { ...opts, parent: this }
208
+ );
209
+ });
210
+ super(
211
+ "highstate:k8s:ExternalService",
212
+ name,
213
+ { id, cluster },
214
+ opts,
215
+ output(cluster),
216
+ service.metadata,
217
+ service.spec,
218
+ service.status
219
+ );
220
+ }
221
+ };
222
+ function mapContainerPortToServicePort(port) {
223
+ return {
224
+ name: port.name,
225
+ port: port.containerPort,
226
+ targetPort: port.containerPort,
227
+ protocol: port.protocol
228
+ };
229
+ }
230
+ function mapServiceToLabelSelector(service) {
231
+ return {
232
+ matchLabels: service.spec.selector
233
+ };
234
+ }
235
+ function getServiceType(service, cluster) {
236
+ if (service?.type) {
237
+ return service.type;
238
+ }
239
+ if (!service?.external) {
240
+ return "ClusterIP";
241
+ }
242
+ return cluster.quirks?.externalServiceType === "LoadBalancer" ? "LoadBalancer" : "NodePort";
243
+ }
244
+
245
+ // src/gateway/http-route.ts
246
+ import {
247
+ ComponentResource as ComponentResource2,
248
+ normalize as normalize2,
249
+ output as output3
250
+ } from "@highstate/pulumi";
251
+ import { gateway } from "@highstate/gateway-api";
252
+ import { map, pipe } from "remeda";
253
+
254
+ // src/gateway/backend.ts
255
+ import "@pulumi/kubernetes";
256
+ import { output as output2 } from "@highstate/pulumi";
257
+ function resolveBackendRef(ref) {
258
+ if (Service.isInstance(ref)) {
259
+ return output2({
260
+ name: ref.metadata.name,
261
+ namespace: ref.metadata.namespace,
262
+ port: ref.spec.ports[0].port
263
+ });
264
+ }
265
+ if ("service" in ref) {
266
+ const service = output2(ref.service);
267
+ return output2({
268
+ name: service.metadata.name,
269
+ namespace: service.metadata.namespace,
270
+ port: ref.port
271
+ });
272
+ }
273
+ return output2({
274
+ name: ref.name,
275
+ namespace: ref.namespace,
276
+ port: ref.port
277
+ });
278
+ }
279
+
280
+ // src/gateway/http-route.ts
281
+ var HttpRoute = class extends ComponentResource2 {
282
+ /**
283
+ * The underlying Kubernetes resource.
284
+ */
285
+ route;
286
+ constructor(name, args, opts) {
287
+ super("highstate:k8s:HttpRoute", name, args, opts);
288
+ this.route = output3({
289
+ args,
290
+ gatewayNamespace: output3(args.gateway).metadata.namespace
291
+ }).apply(async ({ args: args2, gatewayNamespace }) => {
292
+ return new gateway.v1.HTTPRoute(
293
+ name,
294
+ {
295
+ metadata: mapMetadata(
296
+ {
297
+ ...args2,
298
+ namespace: gatewayNamespace
299
+ },
300
+ name
301
+ ),
302
+ spec: {
303
+ hostnames: normalize2(args2.hostname, args2.hostnames),
304
+ parentRefs: [
305
+ {
306
+ name: args2.gateway.metadata.name
307
+ }
308
+ ],
309
+ rules: normalize2(args2.rule, args2.rules).map((rule) => ({
310
+ timeouts: rule.timeouts,
311
+ matches: pipe(
312
+ normalize2(rule.match, rule.matches),
313
+ map(mapHttpRouteRuleMatch),
314
+ addDefaultPathMatch
315
+ ),
316
+ filters: normalize2(rule.filter, rule.filters),
317
+ backendRefs: rule.backend ? [resolveBackendRef(rule.backend)] : void 0
318
+ }))
319
+ }
320
+ },
321
+ {
322
+ ...opts,
323
+ parent: this,
324
+ provider: await getProvider(args2.cluster)
325
+ }
326
+ );
327
+ });
328
+ }
329
+ };
330
+ function addDefaultPathMatch(matches) {
331
+ return matches.length ? matches : [{ path: { type: "PathPrefix", value: "/" } }];
332
+ }
333
+ function mapHttpRouteRuleMatch(match) {
334
+ if (typeof match === "string") {
335
+ return { path: { type: "PathPrefix", value: match } };
336
+ }
337
+ return match;
338
+ }
339
+
340
+ // src/network-policy.ts
341
+ import { networking } from "@pulumi/kubernetes";
342
+ import {
343
+ ComponentResource as ComponentResource3,
344
+ interpolate,
345
+ normalize as normalize3,
346
+ output as output4
347
+ } from "@highstate/pulumi";
348
+ import { capitalize, flat, groupBy, merge, mergeDeep, uniqueBy as uniqueBy2 } from "remeda";
349
+ import "@highstate/library";
350
+ import {
351
+ l34EndpointToString,
352
+ l3EndpointToCidr,
353
+ parseL34Endpoint
354
+ } from "@highstate/common";
355
+ var NetworkPolicy = class _NetworkPolicy extends ComponentResource3 {
356
+ /**
357
+ * The underlying network policy resource.
358
+ */
359
+ networkPolicy;
360
+ constructor(name, args, opts) {
361
+ super("k8s:network-policy", name, args, opts);
362
+ const normalizedArgs = output4(args).apply((args2) => {
363
+ const ingressRules = normalize3(args2.ingressRule, args2.ingressRules);
364
+ const egressRules = normalize3(args2.egressRule, args2.egressRules);
365
+ const extraEgressRules = [];
366
+ if (args2.allowKubeDns) {
367
+ extraEgressRules.push({
368
+ namespaces: ["kube-system"],
369
+ selectors: [{ matchLabels: { "k8s-app": "kube-dns" } }],
370
+ ports: [{ port: 53, protocol: "UDP" }],
371
+ all: false,
372
+ cidrs: [],
373
+ fqdns: [],
374
+ services: []
375
+ });
376
+ }
377
+ return {
378
+ ...args2,
379
+ podSelector: args2.selector ? mapSelectorLikeToSelector(args2.selector) : {},
380
+ isolateEgress: args2.isolateEgress ?? false,
381
+ isolateIngress: args2.isolateIngress ?? false,
382
+ allowKubeApiServer: args2.allowKubeApiServer ?? false,
383
+ ingressRules: ingressRules.flatMap((rule) => {
384
+ const endpoints = normalize3(
385
+ args2.ingressRule?.fromEndpoint,
386
+ args2.ingressRule?.fromEndpoints
387
+ );
388
+ const parsedEndpoints = endpoints.map(parseL34Endpoint);
389
+ const endpointsByPortsAndNamespaces = groupBy(parsedEndpoints, (endpoint) => {
390
+ const namespace = isFromCluster(endpoint, args2.cluster) ? endpoint.metadata.k8sService.namespace : "";
391
+ const port = isFromCluster(endpoint, args2.cluster) ? endpoint.metadata.k8sService.targetPort : endpoint.port;
392
+ return `${port ?? "0"}:${namespace}`;
393
+ });
394
+ const l3OnlyRule = endpointsByPortsAndNamespaces["0:"] ? _NetworkPolicy.getRuleFromEndpoint(
395
+ void 0,
396
+ endpointsByPortsAndNamespaces["0:"],
397
+ args2.cluster
398
+ ) : void 0;
399
+ const otherRules = Object.entries(endpointsByPortsAndNamespaces).filter(([key]) => key !== "0:").map(([key, endpoints2]) => {
400
+ const [port] = key.split(":");
401
+ const portNumber = parseInt(port, 10);
402
+ const portValue = isNaN(portNumber) ? port : portNumber;
403
+ return _NetworkPolicy.getRuleFromEndpoint(portValue, endpoints2, args2.cluster);
404
+ });
405
+ return [
406
+ {
407
+ all: rule.fromAll ?? false,
408
+ cidrs: normalize3(rule.fromCidr, rule.fromCidrs).concat(l3OnlyRule?.cidrs ?? []),
409
+ fqdns: [],
410
+ services: normalize3(rule.fromService, rule.fromServices),
411
+ namespaces: normalize3(rule.fromNamespace, rule.fromNamespaces),
412
+ selectors: normalize3(rule.fromSelector, rule.fromSelectors),
413
+ ports: normalize3(rule.toPort, rule.toPorts)
414
+ },
415
+ ...otherRules
416
+ ].filter((rule2) => !_NetworkPolicy.isEmptyRule(rule2));
417
+ }),
418
+ egressRules: egressRules.flatMap((rule) => {
419
+ const endpoints = normalize3(args2.egressRule?.toEndpoint, args2.egressRule?.toEndpoints);
420
+ const parsedEndpoints = endpoints.map(parseL34Endpoint);
421
+ const endpointsByPortsAnsNamespaces = groupBy(parsedEndpoints, (endpoint) => {
422
+ const namespace = isFromCluster(endpoint, args2.cluster) ? endpoint.metadata.k8sService.namespace : "";
423
+ const port = isFromCluster(endpoint, args2.cluster) ? endpoint.metadata.k8sService.targetPort : endpoint.port;
424
+ return `${port ?? "0"}:${namespace}`;
425
+ });
426
+ const l3OnlyRule = endpointsByPortsAnsNamespaces["0:"] ? _NetworkPolicy.getRuleFromEndpoint(
427
+ void 0,
428
+ endpointsByPortsAnsNamespaces["0:"],
429
+ args2.cluster
430
+ ) : void 0;
431
+ const otherRules = Object.entries(endpointsByPortsAnsNamespaces).filter(([key]) => key !== "0:").map(([key, endpoints2]) => {
432
+ const [port] = key.split(":");
433
+ const portNumber = parseInt(port, 10);
434
+ const portValue = isNaN(portNumber) ? port : portNumber;
435
+ return _NetworkPolicy.getRuleFromEndpoint(portValue, endpoints2, args2.cluster);
436
+ });
437
+ return [
438
+ {
439
+ all: rule.toAll ?? false,
440
+ cidrs: normalize3(rule.toCidr, rule.toCidrs).concat(l3OnlyRule?.cidrs ?? []),
441
+ fqdns: normalize3(rule.toFqdn, rule.toFqdns).concat(l3OnlyRule?.fqdns ?? []),
442
+ services: normalize3(rule.toService, rule.toServices),
443
+ namespaces: normalize3(rule.toNamespace, rule.toNamespaces),
444
+ selectors: normalize3(rule.toSelector, rule.toSelectors),
445
+ ports: normalize3(rule.toPort, rule.toPorts)
446
+ },
447
+ ...otherRules
448
+ ].filter((rule2) => !_NetworkPolicy.isEmptyRule(rule2));
449
+ }).concat(extraEgressRules)
450
+ };
451
+ });
452
+ this.networkPolicy = output4(
453
+ normalizedArgs.apply(async (args2) => {
454
+ return output4(
455
+ this.create(name, args2, {
456
+ ...opts,
457
+ parent: this,
458
+ provider: await getProvider(args2.cluster)
459
+ })
460
+ );
461
+ })
462
+ );
463
+ }
464
+ static mapCidrFromEndpoint(result) {
465
+ if (result.type === "ipv4") {
466
+ return `${result.address}/32`;
467
+ }
468
+ return `${result.address}/128`;
469
+ }
470
+ static getRuleFromEndpoint(port, endpoints, cluster) {
471
+ const ports = port ? [{ port, protocol: endpoints[0].protocol?.toUpperCase() }] : [];
472
+ const cidrs = endpoints.filter((endpoint) => !isFromCluster(endpoint, cluster)).filter((endpoint) => endpoint.type === "ipv4" || endpoint.type === "ipv6").map(_NetworkPolicy.mapCidrFromEndpoint);
473
+ const fqdns = endpoints.filter((endpoint) => endpoint.type === "hostname").map((endpoint) => endpoint.hostname);
474
+ const selectors = endpoints.filter((endpoint) => isFromCluster(endpoint, cluster)).map((endpoint) => endpoint.metadata.k8sService.selector);
475
+ const namespace = endpoints.filter((endpoint) => isFromCluster(endpoint, cluster)).map((endpoint) => getServiceMetadata(endpoint)?.namespace)[0];
476
+ return {
477
+ all: false,
478
+ cidrs,
479
+ fqdns,
480
+ services: [],
481
+ namespaces: namespace ? [namespace] : [],
482
+ selectors,
483
+ ports
484
+ };
485
+ }
486
+ static isEmptyRule(rule) {
487
+ return !rule.all && rule.cidrs.length === 0 && rule.fqdns.length === 0 && rule.services.length === 0 && rule.namespaces.length === 0 && rule.selectors.length === 0 && rule.ports.length === 0;
488
+ }
489
+ static create(name, args, opts) {
490
+ return output4(args).apply(async (args2) => {
491
+ const cni = args2.cluster.cni;
492
+ if (cni === "other") {
493
+ return new NativeNetworkPolicy(name, args2, opts);
494
+ }
495
+ const implName = `${capitalize(cni)}NetworkPolicy`;
496
+ const implModule = await import(`@highstate/${cni}`);
497
+ const implClass = implModule[implName];
498
+ if (!implClass) {
499
+ throw new Error(`No implementation found for ${cni}`);
500
+ }
501
+ return new implClass(name, args2, opts);
502
+ });
503
+ }
504
+ static isolate(namespace, cluster, opts) {
505
+ return _NetworkPolicy.create(
506
+ "isolate",
507
+ {
508
+ namespace,
509
+ cluster,
510
+ description: "By default, deny all traffic to/from the namespace.",
511
+ isolateEgress: true,
512
+ isolateIngress: true
513
+ },
514
+ opts
515
+ );
516
+ }
517
+ static allowInsideNamespace(namespace, cluster, opts) {
518
+ return _NetworkPolicy.create(
519
+ "allow-inside-namespace",
520
+ {
521
+ namespace,
522
+ cluster,
523
+ description: "Allow all traffic inside the namespace.",
524
+ selector: {},
525
+ ingressRule: { fromNamespace: namespace },
526
+ egressRule: { toNamespace: namespace }
527
+ },
528
+ opts
529
+ );
530
+ }
531
+ static allowKubeApiServer(namespace, cluster, opts) {
532
+ return _NetworkPolicy.create(
533
+ "allow-kube-api-server",
534
+ {
535
+ namespace,
536
+ cluster,
537
+ description: "Allow all traffic to the Kubernetes API server from the namespace.",
538
+ allowKubeApiServer: true
539
+ },
540
+ opts
541
+ );
542
+ }
543
+ static allowKubeDns(namespace, cluster, opts) {
544
+ return _NetworkPolicy.create(
545
+ "allow-kube-dns",
546
+ {
547
+ namespace,
548
+ cluster,
549
+ description: "Allow all traffic to the Kubernetes DNS server from the namespace.",
550
+ allowKubeDns: true
551
+ },
552
+ opts
553
+ );
554
+ }
555
+ static allowAllEgress(namespace, cluster, opts) {
556
+ return _NetworkPolicy.create(
557
+ "allow-all-egress",
558
+ {
559
+ namespace,
560
+ cluster,
561
+ description: "Allow all egress traffic from the namespace.",
562
+ egressRule: { toAll: true }
563
+ },
564
+ opts
565
+ );
566
+ }
567
+ static allowAllIngress(namespace, cluster, opts) {
568
+ return _NetworkPolicy.create(
569
+ "allow-all-ingress",
570
+ {
571
+ namespace,
572
+ cluster,
573
+ description: "Allow all ingress traffic to the namespace.",
574
+ ingressRule: { fromAll: true }
575
+ },
576
+ opts
577
+ );
578
+ }
579
+ static allowEgressToEndpoint(endpoint, namespace, cluster, opts) {
580
+ const parsedEndpoint = parseL34Endpoint(endpoint);
581
+ return _NetworkPolicy.create(
582
+ `allow-egress-to-${l34EndpointToString(parsedEndpoint)}`,
583
+ {
584
+ namespace,
585
+ cluster,
586
+ description: interpolate`Allow egress traffic to "${l34EndpointToString(parsedEndpoint)}" from the namespace.`,
587
+ egressRule: { toEndpoint: endpoint }
588
+ },
589
+ opts
590
+ );
591
+ }
592
+ static allowIngressFromEndpoint(endpoint, namespace, cluster, opts) {
593
+ const parsedEndpoint = parseL34Endpoint(endpoint);
594
+ return _NetworkPolicy.create(
595
+ `allow-ingress-from-${l34EndpointToString(parsedEndpoint)}`,
596
+ {
597
+ namespace,
598
+ cluster,
599
+ description: interpolate`Allow ingress traffic from "${l34EndpointToString(parsedEndpoint)}" to the namespace.`,
600
+ ingressRule: { fromEndpoint: endpoint }
601
+ },
602
+ opts
603
+ );
604
+ }
605
+ };
606
+ var NativeNetworkPolicy = class _NativeNetworkPolicy extends NetworkPolicy {
607
+ create(name, args, opts) {
608
+ const ingress = _NativeNetworkPolicy.createIngressRules(args);
609
+ const egress = _NativeNetworkPolicy.createEgressRules(args);
610
+ const policyTypes = [];
611
+ if (ingress.length > 0 || args.isolateIngress) {
612
+ policyTypes.push("Ingress");
613
+ }
614
+ if (egress.length > 0 || args.isolateEgress) {
615
+ policyTypes.push("Egress");
616
+ }
617
+ return new networking.v1.NetworkPolicy(
618
+ name,
619
+ {
620
+ metadata: mergeDeep(mapMetadata(args, name), {
621
+ annotations: args.description ? { "kubernetes.io/description": args.description } : void 0
622
+ }),
623
+ spec: {
624
+ podSelector: args.podSelector,
625
+ ingress,
626
+ egress,
627
+ policyTypes
628
+ }
629
+ },
630
+ opts
631
+ );
632
+ }
633
+ static fallbackIpBlock = {
634
+ cidr: "0.0.0.0/0",
635
+ except: ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
636
+ };
637
+ static fallbackDnsRule = {
638
+ to: [
639
+ {
640
+ namespaceSelector: { matchLabels: { "kubernetes.io/metadata.name": "kube-system" } },
641
+ podSelector: { matchLabels: { "k8s-app": "kube-dns" } }
642
+ }
643
+ ],
644
+ ports: [{ port: 53, protocol: "UDP" }]
645
+ };
646
+ static createIngressRules(args) {
647
+ return uniqueBy2(
648
+ args.ingressRules.map((rule) => ({
649
+ from: rule.all ? [] : _NativeNetworkPolicy.createRulePeers(rule),
650
+ ports: _NativeNetworkPolicy.mapPorts(rule.ports)
651
+ })),
652
+ (rule) => JSON.stringify(rule)
653
+ );
654
+ }
655
+ static createEgressRules(args) {
656
+ const extraRules = [];
657
+ const needKubeDns = args.egressRules.some((rule) => rule.fqdns.length > 0);
658
+ if (needKubeDns) {
659
+ extraRules.push(_NativeNetworkPolicy.fallbackDnsRule);
660
+ }
661
+ const needFallback = args.egressRules.some(
662
+ (rule) => rule.fqdns.some((fqdn) => !fqdn.endsWith(".cluster.local"))
663
+ );
664
+ if (needFallback) {
665
+ extraRules.push({ to: [{ ipBlock: _NativeNetworkPolicy.fallbackIpBlock }] });
666
+ }
667
+ if (args.allowKubeApiServer) {
668
+ const { quirks, apiEndpoints } = args.cluster;
669
+ if (quirks?.fallbackKubeApiAccess) {
670
+ extraRules.push({
671
+ to: [{ ipBlock: { cidr: `${quirks?.fallbackKubeApiAccess.serverIp}/32` } }],
672
+ ports: [{ port: quirks?.fallbackKubeApiAccess.serverPort, protocol: "TCP" }]
673
+ });
674
+ } else {
675
+ const rules = apiEndpoints.filter((endpoint) => endpoint.type !== "hostname").map((endpoint) => ({
676
+ to: [{ ipBlock: { cidr: l3EndpointToCidr(endpoint) } }],
677
+ ports: [{ port: endpoint.port, protocol: "TCP" }]
678
+ }));
679
+ extraRules.push(...rules);
680
+ }
681
+ }
682
+ return uniqueBy2(
683
+ args.egressRules.map((rule) => {
684
+ return {
685
+ to: rule.all ? [] : _NativeNetworkPolicy.createRulePeers(rule),
686
+ ports: _NativeNetworkPolicy.mapPorts(rule.ports)
687
+ };
688
+ }).filter((rule) => rule.to !== void 0).concat(extraRules),
689
+ (rule) => JSON.stringify(rule)
690
+ );
691
+ }
692
+ static createRulePeers(args) {
693
+ const peers = uniqueBy2(
694
+ [
695
+ ..._NativeNetworkPolicy.createCidrPeers(args),
696
+ ..._NativeNetworkPolicy.createServicePeers(args),
697
+ ..._NativeNetworkPolicy.createSelectorPeers(args)
698
+ ],
699
+ (peer) => JSON.stringify(peer)
700
+ );
701
+ return peers.length > 0 ? peers : void 0;
702
+ }
703
+ static createCidrPeers(args) {
704
+ return args.cidrs.map((cidr) => ({ ipBlock: { cidr } }));
705
+ }
706
+ static createServicePeers(args) {
707
+ return args.services.map((service) => {
708
+ const selector = mapServiceToLabelSelector(service);
709
+ return {
710
+ namespaceSelector: mapNamespaceNameToSelector(service.metadata.namespace),
711
+ podSelector: selector
712
+ };
713
+ });
714
+ }
715
+ static createSelectorPeers(args) {
716
+ const selectorPeers = args.selectors.map((selector) => ({
717
+ podSelector: mapSelectorLikeToSelector(selector)
718
+ }));
719
+ const namespacePeers = args.namespaces.map(_NativeNetworkPolicy.createNamespacePeer);
720
+ if (namespacePeers.length === 0) {
721
+ return selectorPeers;
722
+ }
723
+ if (selectorPeers.length === 0) {
724
+ return namespacePeers;
725
+ }
726
+ return flat(
727
+ selectorPeers.map((selectorPeer) => {
728
+ return namespacePeers.map((namespacePeer) => merge(selectorPeer, namespacePeer));
729
+ })
730
+ );
731
+ }
732
+ static createNamespacePeer(namespace) {
733
+ const namespaceName = mapNamespaceLikeToNamespaceName(namespace);
734
+ const namespaceSelector = mapNamespaceNameToSelector(namespaceName);
735
+ return { namespaceSelector };
736
+ }
737
+ static mapPorts(ports) {
738
+ return ports.map((port) => {
739
+ if ("port" in port) {
740
+ return {
741
+ port: port.port,
742
+ protocol: port.protocol ?? "TCP"
743
+ };
744
+ }
745
+ return {
746
+ port: port.range[0],
747
+ endPort: port.range[1],
748
+ protocol: port.protocol ?? "TCP"
749
+ };
750
+ });
751
+ }
752
+ };
753
+
754
+ export {
755
+ hasServiceMetadata,
756
+ getServiceMetadata,
757
+ withServiceMetadata,
758
+ isFromCluster,
759
+ Service,
760
+ mapContainerPortToServicePort,
761
+ mapServiceToLabelSelector,
762
+ getServiceType,
763
+ HttpRoute,
764
+ NetworkPolicy
765
+ };
766
+ //# sourceMappingURL=chunk-OP75IMU7.js.map