@highstate/k8s 0.14.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/chunk-22GOWZQP.js +286 -0
  2. package/dist/chunk-22GOWZQP.js.map +1 -0
  3. package/dist/{chunk-VJL2BFKO.js → chunk-4G6LLC2X.js} +13 -24
  4. package/dist/chunk-4G6LLC2X.js.map +1 -0
  5. package/dist/{chunk-C6WHUOC3.js → chunk-BR2CLUUD.js} +15 -26
  6. package/dist/chunk-BR2CLUUD.js.map +1 -0
  7. package/dist/{chunk-EACAK6W4.js → chunk-DCUMJSO6.js} +17 -28
  8. package/dist/chunk-DCUMJSO6.js.map +1 -0
  9. package/dist/{chunk-NWXKLVBC.js → chunk-HJKJHTJM.js} +20 -30
  10. package/dist/chunk-HJKJHTJM.js.map +1 -0
  11. package/dist/{chunk-7H4L3DFC.js → chunk-KMLRI5UZ.js} +57 -70
  12. package/dist/chunk-KMLRI5UZ.js.map +1 -0
  13. package/dist/{chunk-6ACIPGW4.js → chunk-LGHFSXNT.js} +12 -13
  14. package/dist/chunk-LGHFSXNT.js.map +1 -0
  15. package/dist/{chunk-SEWB4FUB.js → chunk-OBDQONMV.js} +64 -23
  16. package/dist/chunk-OBDQONMV.js.map +1 -0
  17. package/dist/chunk-SL5CBM3A.js +301 -0
  18. package/dist/chunk-SL5CBM3A.js.map +1 -0
  19. package/dist/{chunk-3CKMDTYK.js → chunk-TWBMG6TD.js} +68 -91
  20. package/dist/chunk-TWBMG6TD.js.map +1 -0
  21. package/dist/{chunk-YTRQ6JRU.js → chunk-XRIC6EJ3.js} +159 -94
  22. package/dist/chunk-XRIC6EJ3.js.map +1 -0
  23. package/dist/{chunk-O64YZLA4.js → chunk-ZBFWQHE4.js} +21 -30
  24. package/dist/chunk-ZBFWQHE4.js.map +1 -0
  25. package/dist/{chunk-4VGISFL4.js → chunk-ZHVKK2U6.js} +12 -11
  26. package/dist/chunk-ZHVKK2U6.js.map +1 -0
  27. package/dist/cron-job-LX35I6HG.js +8 -0
  28. package/dist/cron-job-LX35I6HG.js.map +1 -0
  29. package/dist/deployment-HRJGAEJR.js +8 -0
  30. package/dist/{deployment-THUD5QUH.js.map → deployment-HRJGAEJR.js.map} +1 -1
  31. package/dist/highstate.manifest.json +2 -3
  32. package/dist/impl/gateway-route.js +10 -10
  33. package/dist/impl/gateway-route.js.map +1 -1
  34. package/dist/impl/tls-certificate.js +3 -3
  35. package/dist/index.js +39 -627
  36. package/dist/index.js.map +1 -1
  37. package/dist/job-J4BKBVQD.js +8 -0
  38. package/dist/job-J4BKBVQD.js.map +1 -0
  39. package/dist/stateful-set-LAJR5RL4.js +8 -0
  40. package/dist/{stateful-set-ABCZML4L.js.map → stateful-set-LAJR5RL4.js.map} +1 -1
  41. package/dist/units/cert-manager/index.js +7 -7
  42. package/dist/units/cluster-patch/index.js +9 -18
  43. package/dist/units/cluster-patch/index.js.map +1 -1
  44. package/dist/units/dns01-issuer/index.js +6 -6
  45. package/dist/units/dns01-issuer/index.js.map +1 -1
  46. package/dist/units/existing-cluster/index.js +19 -9
  47. package/dist/units/existing-cluster/index.js.map +1 -1
  48. package/dist/units/gateway-api/index.js +2 -2
  49. package/dist/units/gateway-api/index.js.map +1 -1
  50. package/dist/units/reduced-access-cluster/index.js +18 -25
  51. package/dist/units/reduced-access-cluster/index.js.map +1 -1
  52. package/package.json +7 -12
  53. package/src/cluster.ts +14 -14
  54. package/src/config-map.ts +16 -30
  55. package/src/container.ts +1 -1
  56. package/src/cron-job.ts +23 -41
  57. package/src/deployment.ts +23 -30
  58. package/src/gateway/gateway.ts +21 -29
  59. package/src/helm.ts +7 -8
  60. package/src/impl/gateway-route.ts +5 -13
  61. package/src/job.ts +20 -38
  62. package/src/namespace.ts +18 -22
  63. package/src/network-policy.ts +37 -36
  64. package/src/network.ts +18 -10
  65. package/src/pvc.ts +12 -28
  66. package/src/rbac.ts +75 -97
  67. package/src/scripting/bundle.ts +3 -3
  68. package/src/scripting/environment.ts +3 -3
  69. package/src/secret.ts +16 -30
  70. package/src/service.ts +86 -105
  71. package/src/shared.ts +82 -20
  72. package/src/stateful-set.ts +17 -28
  73. package/src/tls.ts +20 -31
  74. package/src/units/cluster-patch/index.ts +9 -19
  75. package/src/units/dns01-issuer/index.ts +6 -6
  76. package/src/units/existing-cluster/index.ts +28 -10
  77. package/src/units/gateway-api/index.ts +1 -1
  78. package/src/units/reduced-access-cluster/index.ts +16 -24
  79. package/src/worker.ts +7 -5
  80. package/src/workload.ts +172 -28
  81. package/dist/chunk-3CKMDTYK.js.map +0 -1
  82. package/dist/chunk-4VGISFL4.js.map +0 -1
  83. package/dist/chunk-6ACIPGW4.js.map +0 -1
  84. package/dist/chunk-7H4L3DFC.js.map +0 -1
  85. package/dist/chunk-C6WHUOC3.js.map +0 -1
  86. package/dist/chunk-EACAK6W4.js.map +0 -1
  87. package/dist/chunk-NWXKLVBC.js.map +0 -1
  88. package/dist/chunk-O64YZLA4.js.map +0 -1
  89. package/dist/chunk-SEWB4FUB.js.map +0 -1
  90. package/dist/chunk-VJL2BFKO.js.map +0 -1
  91. package/dist/chunk-YTRQ6JRU.js.map +0 -1
  92. package/dist/deployment-THUD5QUH.js +0 -8
  93. package/dist/stateful-set-ABCZML4L.js +0 -8
  94. package/dist/units/cluster-dns/index.js +0 -37
  95. package/dist/units/cluster-dns/index.js.map +0 -1
  96. package/src/units/cluster-dns/index.ts +0 -37
@@ -1,33 +1,23 @@
1
- import { l3EndpointToString, l4EndpointToString, updateEndpoints } from "@highstate/common"
1
+ import { l3EndpointToString, l4EndpointToString, parseEndpoints } from "@highstate/common"
2
2
  import { k8s } from "@highstate/library"
3
- import { forUnit } from "@highstate/pulumi"
3
+ import { forUnit, toPromise } from "@highstate/pulumi"
4
4
 
5
5
  const { args, inputs, outputs } = forUnit(k8s.clusterPatch)
6
6
 
7
- const endpoints = await updateEndpoints(
8
- inputs.k8sCluster.endpoints,
9
- args.endpoints,
10
- inputs.endpoints,
11
- args.endpointsPatchMode,
12
- )
7
+ const cluster = await toPromise(inputs.k8sCluster)
8
+ const endpoints = await parseEndpoints(args.endpoints, inputs.endpoints, 3)
9
+ const apiEndpoints = await parseEndpoints(args.apiEndpoints, inputs.apiEndpoints, 4)
13
10
 
14
- const apiEndpoints = await updateEndpoints(
15
- inputs.k8sCluster.apiEndpoints,
16
- args.apiEndpoints,
17
- inputs.apiEndpoints,
18
- args.apiEndpointsPatchMode,
19
- )
11
+ const newEndpoints = endpoints.length > 0 ? endpoints : cluster.endpoints
12
+ const newApiEndpoints = apiEndpoints.length > 0 ? apiEndpoints : cluster.apiEndpoints
20
13
 
21
14
  export default outputs({
22
15
  k8sCluster: inputs.k8sCluster.apply(k8sCluster => ({
23
16
  ...k8sCluster,
24
- endpoints,
25
- apiEndpoints,
17
+ endpoints: newEndpoints,
18
+ apiEndpoints: newApiEndpoints,
26
19
  })),
27
20
 
28
- endpoints,
29
- apiEndpoints,
30
-
31
21
  $statusFields: {
32
22
  endpoints: endpoints.map(l3EndpointToString),
33
23
  apiEndpoints: apiEndpoints.map(l4EndpointToString),
@@ -28,7 +28,7 @@ new cert_manager.v1.ClusterIssuer(
28
28
  dns01: dns01SolverMediator.callOutput(inputs.dnsProvider.implRef, {
29
29
  namespace: certManagerNs,
30
30
  }),
31
- selector: { dnsZones: [inputs.dnsProvider.domain] },
31
+ selector: { dnsZones: inputs.dnsProvider.zones },
32
32
  },
33
33
  ],
34
34
  privateKeySecretRef: {
@@ -41,12 +41,8 @@ new cert_manager.v1.ClusterIssuer(
41
41
  )
42
42
 
43
43
  export default outputs({
44
- $statusFields: {
45
- domain: inputs.dnsProvider.domain,
46
- },
47
-
48
44
  tlsIssuer: {
49
- domain: inputs.dnsProvider.domain,
45
+ zones: inputs.dnsProvider.zones,
50
46
  implRef: {
51
47
  package: "@highstate/k8s",
52
48
  data: {
@@ -55,4 +51,8 @@ export default outputs({
55
51
  },
56
52
  },
57
53
  },
54
+
55
+ $statusFields: {
56
+ zones: inputs.dnsProvider.zones,
57
+ },
58
58
  })
@@ -1,8 +1,11 @@
1
1
  import {
2
2
  l3EndpointToString,
3
3
  l4EndpointToString,
4
- parseL3Endpoint,
5
- parseL4Endpoint,
4
+ mergeAddresses,
5
+ mergeEndpoints,
6
+ parseAddress,
7
+ parseEndpoint,
8
+ parseEndpoints,
6
9
  } from "@highstate/common"
7
10
  import { type ImplementationReference, k8s } from "@highstate/library"
8
11
  import { forUnit, secret, toPromise } from "@highstate/pulumi"
@@ -10,7 +13,7 @@ import { AppsV1Api, KubeConfig } from "@kubernetes/client-node"
10
13
  import { core, Provider } from "@pulumi/kubernetes"
11
14
  import { createK8sTerminal, detectExternalIps } from "../../cluster"
12
15
 
13
- const { name, args, secrets, outputs } = forUnit(k8s.existingCluster)
16
+ const { name, args, inputs, secrets, outputs } = forUnit(k8s.existingCluster)
14
17
 
15
18
  const kubeconfigContent = await toPromise(secrets.kubeconfig.apply(JSON.stringify))
16
19
 
@@ -35,11 +38,29 @@ if (hasCilium) {
35
38
  }
36
39
  }
37
40
 
38
- const externalIps =
39
- args.externalIps ?? (await detectExternalIps(kubeConfig, args.internalIpsPolicy))
41
+ // calculate external IPs
42
+ let externalIps = args.externalIps.map(parseAddress)
40
43
 
41
- const endpoints = externalIps.map(parseL3Endpoint)
42
- const apiEndpoints = [parseL4Endpoint(kubeConfig.clusters[0].server.replace("https://", ""))]
44
+ if (args.autoDetectExternalIps) {
45
+ const detectedIps = await detectExternalIps(kubeConfig, args.internalIpsPolicy)
46
+ externalIps = mergeAddresses([...externalIps, ...detectedIps])
47
+ }
48
+
49
+ // calculate endpoints
50
+ let endpoints = await parseEndpoints(args.endpoints, inputs.endpoints)
51
+
52
+ if (args.useExternalIpsAsEndpoints) {
53
+ const ipEndpoints = externalIps.map(ip => parseEndpoint(ip))
54
+ endpoints = mergeEndpoints([...endpoints, ...ipEndpoints])
55
+ }
56
+
57
+ // calculate api endpoints
58
+ let apiEndpoints = await parseEndpoints(args.apiEndpoints, inputs.endpoints, 4)
59
+
60
+ if (args.useKubeconfigApiEndpoint) {
61
+ const configEndpoint = parseEndpoint(kubeConfig.clusters[0].server.replace("https://", ""), 4)
62
+ apiEndpoints = mergeEndpoints([configEndpoint, ...apiEndpoints])
63
+ }
43
64
 
44
65
  const kubeSystem = core.v1.Namespace.get("kube-system", "kube-system", { provider })
45
66
 
@@ -56,9 +77,6 @@ export default outputs({
56
77
  kubeconfig: secret(kubeconfigContent),
57
78
  },
58
79
 
59
- endpoints,
60
- apiEndpoints,
61
-
62
80
  $terminals: [createK8sTerminal(kubeconfigContent)],
63
81
 
64
82
  $statusFields: {
@@ -10,7 +10,7 @@ const provider = await getProviderAsync(inputs.k8sCluster)
10
10
  new yaml.v2.ConfigFile(
11
11
  "gateway-api",
12
12
  {
13
- file: "https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/experimental-install.yaml",
13
+ file: "https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml",
14
14
  },
15
15
  { provider },
16
16
  )
@@ -3,39 +3,31 @@ import { k8s } from "@highstate/library"
3
3
  import { fileFromString, forUnit, interpolate, output, secret, toPromise } from "@highstate/pulumi"
4
4
  import { join } from "remeda"
5
5
  import { createK8sTerminal } from "../../cluster"
6
- import { ConfigMap } from "../../config-map"
7
- import { Deployment } from "../../deployment"
8
6
  import { Namespace } from "../../namespace"
9
- import { PersistentVolumeClaim } from "../../pvc"
10
7
  import { ClusterAccessScope } from "../../rbac"
11
- import { Secret } from "../../secret"
12
- import { Service } from "../../service"
13
- import { StatefulSet } from "../../stateful-set"
14
8
 
15
- const { name, args, inputs, outputs } = forUnit(k8s.reducedAccessCluster)
9
+ const { args, inputs, outputs } = forUnit(k8s.reducedAccessCluster)
16
10
 
17
11
  const resolvedInputs = await toPromise(inputs)
18
12
 
19
- const resources = [
20
- ...resolvedInputs.deployments.map(r => Deployment.for(r, inputs.k8sCluster)),
21
- ...resolvedInputs.statefulSets.map(r => StatefulSet.for(r, inputs.k8sCluster)),
22
- ...resolvedInputs.services.map(r => Service.for(r, inputs.k8sCluster)),
23
- ...resolvedInputs.persistentVolumeClaims.map(r =>
24
- PersistentVolumeClaim.for(r, inputs.k8sCluster),
25
- ),
26
- ...resolvedInputs.secrets.map(r => Secret.for(r, inputs.k8sCluster)),
27
- ...resolvedInputs.configMaps.map(r => ConfigMap.for(r, inputs.k8sCluster)),
28
- ]
29
-
30
- const accessScope = await ClusterAccessScope.forResources(args.serviceAccountName ?? name, {
31
- namespace: Namespace.for(resolvedInputs.namespace, inputs.k8sCluster),
32
- verbs: args.verbs,
33
- resources,
34
- })
13
+ const accessScope = new ClusterAccessScope(
14
+ "scope",
15
+ {
16
+ namespace: Namespace.for(resolvedInputs.namespace, inputs.k8sCluster),
17
+ extraNamespaces: resolvedInputs.extraNamespaces.map(ns => Namespace.for(ns, inputs.k8sCluster)),
18
+ rules: args.rules,
19
+ resources: resolvedInputs.resources,
20
+ },
21
+ {},
22
+ )
35
23
 
36
24
  const resourceLines = await toPromise(
37
25
  output(
38
- resources.map(r => interpolate`- ${r.kind} "${r.metadata.namespace}/${r.metadata.name}"`),
26
+ resolvedInputs.resources.map(r =>
27
+ r.isNamespaced
28
+ ? interpolate`- ${r.kind} "${r.metadata.namespace}/${r.metadata.name}"`
29
+ : interpolate`- ${r.kind} "${r.metadata.name}"`,
30
+ ),
39
31
  ).apply(join("\n")),
40
32
  )
41
33
 
package/src/worker.ts CHANGED
@@ -4,17 +4,19 @@ import type { DeepInput, Input, InputArray, Unwrap } from "@highstate/pulumi"
4
4
  import type { Namespace } from "./namespace"
5
5
  import { type Output, output } from "@pulumi/pulumi"
6
6
  import { ClusterAccessScope } from "./rbac"
7
- import { images, type ScopedResource } from "./shared"
7
+ import { images, type NamespacedResource } from "./shared"
8
8
 
9
9
  export async function createMonitorWorker(
10
10
  namespace: Input<Namespace>,
11
- resources: InputArray<ScopedResource>,
11
+ resources: InputArray<NamespacedResource>,
12
12
  ): Promise<Output<Unwrap<UnitWorker>>> {
13
- const scope = await ClusterAccessScope.forResources("monitor", {
13
+ const scope = new ClusterAccessScope("monitor", {
14
+ rule: {
15
+ verbs: ["get", "list", "watch"],
16
+ },
17
+
14
18
  namespace,
15
19
  resources,
16
- verbs: ["get", "list", "watch"],
17
- collectionAccess: true,
18
20
  })
19
21
 
20
22
  return output({
package/src/workload.ts CHANGED
@@ -1,9 +1,10 @@
1
- import type { k8s } from "@highstate/library"
1
+ import type { k8s, network } from "@highstate/library"
2
2
  import type { types } from "@pulumi/kubernetes"
3
3
  import type { Except } from "type-fest"
4
4
  import type { DeploymentArgs } from "./deployment"
5
+ import type { JobArgs } from "./job"
5
6
  import type { StatefulSetArgs } from "./stateful-set"
6
- import { AccessPointRoute, type AccessPointRouteArgs } from "@highstate/common"
7
+ import { AccessPointRoute, type AccessPointRouteArgs, mergeEndpoints } from "@highstate/common"
7
8
  import { type TerminalSpec, trimIndentation, type UnitTerminal } from "@highstate/contract"
8
9
  import {
9
10
  type ComponentResourceOptions,
@@ -25,7 +26,7 @@ import {
25
26
  } from "@pulumi/pulumi"
26
27
  import { sha256 } from "crypto-hash"
27
28
  import { deepmerge } from "deepmerge-ts"
28
- import { filter, isNonNullish, unique, uniqueBy } from "remeda"
29
+ import { filter, flat, isNonNullish, unique, uniqueBy } from "remeda"
29
30
  import {
30
31
  type Container,
31
32
  getFallbackContainerName,
@@ -38,7 +39,7 @@ import { Namespace } from "./namespace"
38
39
  import { NetworkPolicy, type NetworkPolicyArgs } from "./network-policy"
39
40
  import { podSpecDefaults } from "./pod"
40
41
  import { mapContainerPortToServicePort, Service, type ServiceArgs } from "./service"
41
- import { commonExtraArgs, images, ScopedResource, type ScopedResourceArgs } from "./shared"
42
+ import { commonExtraArgs, images, NamespacedResource, type ScopedResourceArgs } from "./shared"
42
43
 
43
44
  export type WorkloadTerminalArgs = {
44
45
  /**
@@ -114,15 +115,58 @@ export const exposableWorkloadExtraArgs = [
114
115
  "routes",
115
116
  ] as const
116
117
 
118
+ export type WorkloadType = "Deployment" | "StatefulSet" | "Job" | "CronJob"
117
119
  export type ExposableWorkloadType = "Deployment" | "StatefulSet"
118
120
 
121
+ export type GenericWorkloadArgs = Omit<ExposableWorkloadArgs, "existing"> & {
122
+ /**
123
+ * The type of workload to create.
124
+ *
125
+ * Will be ignored if the `existing` argument is provided.
126
+ */
127
+ defaultType: WorkloadType
128
+
129
+ /**
130
+ * The existing workload to patch.
131
+ */
132
+ existing: Input<k8s.Workload | undefined>
133
+
134
+ /**
135
+ * The args specific to the "Deployment" workload type.
136
+ *
137
+ * Will be ignored for other workload types.
138
+ */
139
+ deployment?: Input<DeploymentArgs>
140
+
141
+ /**
142
+ * The args specific to the "StatefulSet" workload type.
143
+ *
144
+ * Will be ignored for other workload types.
145
+ */
146
+ statefulSet?: Input<StatefulSetArgs>
147
+
148
+ /**
149
+ * The args specific to the "Job" workload type.
150
+ *
151
+ * Will be ignored for other workload types.
152
+ */
153
+ job?: Input<JobArgs>
154
+
155
+ /**
156
+ * The args specific to the "CronJob" workload type.
157
+ *
158
+ * Will be ignored for other workload types.
159
+ */
160
+ cronJob?: Input<JobArgs>
161
+ }
162
+
119
163
  export type GenericExposableWorkloadArgs = Omit<ExposableWorkloadArgs, "existing"> & {
120
164
  /**
121
165
  * The type of workload to create.
122
166
  *
123
167
  * Will be ignored if the `existing` argument is provided.
124
168
  */
125
- type: ExposableWorkloadType
169
+ defaultType: ExposableWorkloadType
126
170
 
127
171
  /**
128
172
  * The existing workload to patch.
@@ -341,19 +385,18 @@ export function getExposableWorkloadComponents(
341
385
  return { labels, containers, volumes, podSpec, podTemplate, networkPolicy, service, routes }
342
386
  }
343
387
 
344
- export abstract class Workload extends ScopedResource {
388
+ export abstract class Workload extends NamespacedResource {
345
389
  protected constructor(
346
390
  type: string,
347
391
  protected readonly name: string,
348
392
  args: Inputs,
349
393
  opts: ComponentResourceOptions | undefined,
350
394
 
351
- apiVersion: Output<string>,
352
- kind: Output<string>,
395
+ metadata: Output<types.output.meta.v1.ObjectMeta>,
396
+ namespace: Output<Namespace>,
397
+
353
398
  protected readonly terminalArgs: Output<Unwrap<WorkloadTerminalArgs>>,
354
399
  protected readonly containers: Output<Container[]>,
355
- namespace: Output<Namespace>,
356
- metadata: Output<types.output.meta.v1.ObjectMeta>,
357
400
 
358
401
  /**
359
402
  * The rendered pod template of the workload.
@@ -367,7 +410,7 @@ export abstract class Workload extends ScopedResource {
367
410
  */
368
411
  readonly networkPolicy: Output<NetworkPolicy | undefined>,
369
412
  ) {
370
- super(type, name, args, opts, apiVersion, kind, namespace, metadata)
413
+ super(type, name, args, opts, metadata, namespace)
371
414
  }
372
415
 
373
416
  protected abstract get templateMetadata(): Output<types.output.meta.v1.ObjectMeta>
@@ -378,7 +421,7 @@ export abstract class Workload extends ScopedResource {
378
421
  private set terminal(_value: never) {}
379
422
 
380
423
  /**
381
- * The instance terminal to interact with the deployment.
424
+ * The instance terminal to interact with the workload's pods.
382
425
  */
383
426
  get terminal(): Output<UnitTerminal> {
384
427
  const containerName = this.podTemplate.spec.containers.apply(containers => containers[0].name)
@@ -411,7 +454,7 @@ export abstract class Workload extends ScopedResource {
411
454
  set -euo pipefail
412
455
 
413
456
  NAMESPACE="${this.metadata.namespace}"
414
- RESOURCE_TYPE="${this.kind.apply(k => k.toLowerCase())}"
457
+ RESOURCE_TYPE="${this.kind.toLowerCase()}"
415
458
  RESOURCE_NAME="${this.metadata.name}"
416
459
  CONTAINER_NAME="${containerName}"
417
460
  SHELL="${shell}"
@@ -496,7 +539,7 @@ export abstract class Workload extends ScopedResource {
496
539
  "-it",
497
540
  "-n",
498
541
  this.metadata.namespace,
499
- interpolate`${this.kind.apply(k => k.toLowerCase())}/${this.metadata.name}`,
542
+ `${this.kind.toLowerCase()}/${this.metadata.name}`,
500
543
  "-c",
501
544
  containerName,
502
545
  "--",
@@ -515,6 +558,99 @@ export abstract class Workload extends ScopedResource {
515
558
  },
516
559
  })
517
560
  }
561
+
562
+ /**
563
+ * Creates a generic workload or patches the existing one.
564
+ */
565
+ static createOrPatchGeneric(
566
+ name: string,
567
+ args: GenericWorkloadArgs,
568
+ opts?: CustomResourceOptions,
569
+ ): Output<Workload> {
570
+ return output(args).apply(async args => {
571
+ if (args.existing?.kind === "Deployment") {
572
+ const { Deployment } = await import("./deployment")
573
+
574
+ return Deployment.patch(
575
+ name,
576
+ {
577
+ ...deepmerge(args, args.deployment),
578
+ name: args.existing.metadata.name,
579
+ namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
580
+ },
581
+ opts,
582
+ )
583
+ }
584
+
585
+ if (args.existing?.kind === "StatefulSet") {
586
+ const { StatefulSet } = await import("./stateful-set")
587
+
588
+ return StatefulSet.patch(
589
+ name,
590
+ {
591
+ ...deepmerge(args, args.statefulSet),
592
+ name: args.existing.metadata.name,
593
+ namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
594
+ },
595
+ opts,
596
+ )
597
+ }
598
+
599
+ if (args.existing?.kind === "Job") {
600
+ const { Job } = await import("./job")
601
+
602
+ return Job.patch(
603
+ name,
604
+ {
605
+ ...deepmerge(args, args.job),
606
+ name: args.existing.metadata.name,
607
+ namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
608
+ },
609
+ opts,
610
+ )
611
+ }
612
+
613
+ if (args.existing?.kind === "CronJob") {
614
+ const { CronJob } = await import("./cron-job")
615
+
616
+ return CronJob.patch(
617
+ name,
618
+ {
619
+ ...deepmerge(args, args.cronJob),
620
+ name: args.existing.metadata.name,
621
+ namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
622
+ },
623
+ opts,
624
+ )
625
+ }
626
+
627
+ if (args.defaultType === "Deployment") {
628
+ const { Deployment } = await import("./deployment")
629
+
630
+ return Deployment.create(name, deepmerge(args, args.deployment), opts)
631
+ }
632
+
633
+ if (args.defaultType === "StatefulSet") {
634
+ const { StatefulSet } = await import("./stateful-set")
635
+
636
+ return StatefulSet.create(name, deepmerge(args, args.statefulSet), opts)
637
+ }
638
+
639
+ if (args.defaultType === "Job") {
640
+ const { Job } = await import("./job")
641
+
642
+ return Job.create(name, deepmerge(args, args.job), opts)
643
+ }
644
+
645
+ if (args.defaultType === "CronJob") {
646
+ const { CronJob } = await import("./cron-job")
647
+
648
+ return CronJob.create(name, deepmerge(args, args.cronJob), opts)
649
+ }
650
+
651
+ throw new Error(`Unknown workload type: ${args.defaultType as string}`)
652
+ })
653
+ }
518
654
  }
519
655
 
520
656
  export abstract class ExposableWorkload extends Workload {
@@ -524,12 +660,11 @@ export abstract class ExposableWorkload extends Workload {
524
660
  args: Inputs,
525
661
  opts: ComponentResourceOptions | undefined,
526
662
 
527
- apiVersion: Output<string>,
528
- kind: Output<string>,
663
+ metadata: Output<types.output.meta.v1.ObjectMeta>,
664
+ namespace: Output<Namespace>,
665
+
529
666
  terminalArgs: Output<Unwrap<WorkloadTerminalArgs>>,
530
667
  containers: Output<Container[]>,
531
- namespace: Output<Namespace>,
532
- metadata: Output<types.output.meta.v1.ObjectMeta>,
533
668
  podTemplate: Output<types.output.core.v1.PodTemplateSpec>,
534
669
  networkPolicy: Output<NetworkPolicy | undefined>,
535
670
 
@@ -545,12 +680,10 @@ export abstract class ExposableWorkload extends Workload {
545
680
  name,
546
681
  args,
547
682
  opts,
548
- apiVersion,
549
- kind,
683
+ metadata,
684
+ namespace,
550
685
  terminalArgs,
551
686
  containers,
552
- namespace,
553
- metadata,
554
687
  podTemplate,
555
688
  networkPolicy,
556
689
  )
@@ -584,6 +717,17 @@ export abstract class ExposableWorkload extends Workload {
584
717
  })
585
718
  }
586
719
 
720
+ /**
721
+ * The merged and deduplicated L3 endpoints of all routes.
722
+ */
723
+ get endpoints(): Output<network.L3Endpoint[]> {
724
+ return this.routes.apply(routes =>
725
+ output(routes.map(route => route.route.endpoints))
726
+ .apply(endpoints => flat(endpoints))
727
+ .apply(mergeEndpoints),
728
+ )
729
+ }
730
+
587
731
  /**
588
732
  * The entity of the workload.
589
733
  */
@@ -597,7 +741,7 @@ export abstract class ExposableWorkload extends Workload {
597
741
  >
598
742
 
599
743
  /**
600
- * Creates a generic workload or patches the existing one.
744
+ * Creates a generic exposable workload or patches the existing one.
601
745
  */
602
746
  static createOrPatchGeneric(
603
747
  name: string,
@@ -605,7 +749,7 @@ export abstract class ExposableWorkload extends Workload {
605
749
  opts?: CustomResourceOptions,
606
750
  ): Output<ExposableWorkload> {
607
751
  return output(args).apply(async args => {
608
- if (args.existing?.type === "deployment") {
752
+ if (args.existing?.kind === "Deployment") {
609
753
  const { Deployment } = await import("./deployment")
610
754
 
611
755
  return Deployment.patch(
@@ -619,7 +763,7 @@ export abstract class ExposableWorkload extends Workload {
619
763
  )
620
764
  }
621
765
 
622
- if (args.existing?.type === "stateful-set") {
766
+ if (args.existing?.kind === "StatefulSet") {
623
767
  const { StatefulSet } = await import("./stateful-set")
624
768
 
625
769
  return StatefulSet.patch(
@@ -633,19 +777,19 @@ export abstract class ExposableWorkload extends Workload {
633
777
  )
634
778
  }
635
779
 
636
- if (args.type === "Deployment") {
780
+ if (args.defaultType === "Deployment") {
637
781
  const { Deployment } = await import("./deployment")
638
782
 
639
783
  return Deployment.create(name, deepmerge(args, args.deployment), opts)
640
784
  }
641
785
 
642
- if (args.type === "StatefulSet") {
786
+ if (args.defaultType === "StatefulSet") {
643
787
  const { StatefulSet } = await import("./stateful-set")
644
788
 
645
789
  return StatefulSet.create(name, deepmerge(args, args.statefulSet), opts)
646
790
  }
647
791
 
648
- throw new Error(`Unknown workload type: ${args.type as string}`)
792
+ throw new Error(`Unknown workload type: ${args.defaultType as string}`)
649
793
  })
650
794
  }
651
795
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/service.ts"],"names":["args"],"mappings":";;;;;;;;;AA8CA,IAAM,mBAAmB,CAAC,GAAG,eAAA,EAAiB,MAAA,EAAQ,SAAS,UAAU,CAAA;AASlE,SAAS,qBAAA,CACd,UACA,OAAA,EACiC;AACjC,EAAA,OACE,KAAA,CAAM,GAAA,CAAI,qBAAA,EAAuB,QAAQ,CAAA,IACzC,SAAS,QAAA,CAAS,aAAa,CAAA,CAAE,SAAA,KAAc,OAAA,CAAQ,EAAA;AAE3D;AAKO,IAAe,OAAA,GAAf,MAAe,QAAA,SAAgB,cAAA,CAAe;AAAA,EACzC,WAAA,CACR,IAAA,EACA,IAAA,EACA,IAAA,EACA,IAAA,EAEA,YACA,IAAA,EACA,SAAA,EACA,QAAA,EAKS,IAAA,EAKA,MAAA,EACT;AACA,IAAA,KAAA,CAAM,MAAM,IAAA,EAAM,IAAA,EAAM,MAAM,UAAA,EAAY,IAAA,EAAM,WAAW,QAAQ,CAAA;AAP1D,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAKA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAGX;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAA,GAA8B;AAChC,IAAA,OAAO,MAAA,CAAO;AAAA,MACZ,IAAA,EAAM,SAAA;AAAA,MACN,SAAA,EAAW,KAAK,OAAA,CAAQ,EAAA;AAAA,MACxB,WAAA,EAAa,KAAK,OAAA,CAAQ,IAAA;AAAA,MAC1B,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,WAAW,IAAA,CAAK;AAAA,KACjB,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAA,CAAO,IAAA,EAAc,IAAA,EAAmB,IAAA,EAA0C;AACvF,IAAA,OAAO,IAAI,cAAA,CAAe,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,aAAA,CACL,IAAA,EACA,IAAA,EACA,IAAA,EACS;AACT,IAAA,IAAI,KAAK,QAAA,EAAU;AACjB,MAAA,OAAO,IAAI,aAAa,IAAA,EAAM;AAAA,QAC5B,GAAG,IAAA;AAAA,QACH,IAAA,EAAM,MAAA,CAAO,IAAA,CAAK,QAAQ,EAAE,QAAA,CAAS,IAAA;AAAA,QACrC,SAAA,EAAW,UAAU,gBAAA,CAAiB,IAAA,CAAK,UAAU,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,OAAO;AAAA,OACpF,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,IAAI,cAAA,CAAe,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,aAAa,WAAA,CACX,IAAA,EACA,IAAA,EACA,IAAA,EACkB;AAClB,IAAA,IAAI,KAAK,QAAA,EAAU;AACjB,MAAA,OAAO,MAAM,SAAQ,QAAA,CAAS,IAAA,CAAK,UAAU,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,OAAO,CAAA;AAAA,IAC7E;AAEA,IAAA,OAAO,IAAI,cAAA,CAAe,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,KAAA,CAAM,IAAA,EAAc,IAAA,EAAmB,IAAA,EAA0C;AACtF,IAAA,OAAO,IAAI,YAAA,CAAa,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,IAAA,CAAK,IAAA,EAAc,IAAA,EAA0B,IAAA,EAA0C;AAC5F,IAAA,OAAO,IAAI,cAAA,CAAe,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,GAAA,CAAI,IAAA,EAAc,IAAA,EAA2B,IAAA,EAA0C;AAC5F,IAAA,OAAO,IAAI,eAAA,CAAgB,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAAA,EAC7C;AAAA,EAEA,OAAwB,YAAA,mBAAe,IAAI,GAAA,EAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAahE,OAAO,GAAA,CAAI,MAAA,EAAqB,OAAA,EAAsC;AACpE,IAAA,OAAO,WAAA;AAAA,MACL,QAAA,CAAQ,YAAA;AAAA,MACR,CAAA,EAAG,MAAA,CAAO,WAAW,CAAA,CAAA,EAAI,MAAA,CAAO,QAAA,CAAS,SAAS,CAAA,CAAA,EAAI,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,CAAA,EAAI,OAAO,SAAS,CAAA,CAAA;AAAA,MAC9F,CAAA,IAAA,KAAQ;AACN,QAAA,OAAO,QAAA,CAAQ,IAAI,IAAA,EAAM;AAAA,UACvB,IAAA,EAAM,OAAO,QAAA,CAAS,IAAA;AAAA,UACtB,SAAA,EAAW,SAAA,CAAU,gBAAA,CAAiB,MAAA,EAAQ,OAAO;AAAA,SACtD,CAAA;AAAA,MACH;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,aAAa,QAAA,CAAS,MAAA,EAA4B,OAAA,EAA+C;AAC/F,IAAA,MAAM,cAAA,GAAiB,MAAM,SAAA,CAAU,MAAM,CAAA;AAE7C,IAAA,OAAO,QAAA,CAAQ,GAAA,CAAI,cAAA,EAAgB,MAAA,CAAO,OAAO,CAAC,CAAA;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,gBAAgB,MAAA,EAAgE;AAC9E,IAAA,OAAO,MAAA,CAAO,KAAK,SAAS,CAAA,CAAE,MAAM,CAAA,SAAA,KAAa,eAAA,CAAgB,SAAA,EAAW,MAAM,CAAC,CAAA;AAAA,EACrF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAA,GAA2C;AAC7C,IAAA,OAAO,MAAA,CAAO;AAAA,MACZ,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,QAAQ,IAAA,CAAK;AAAA,KACd,EAAE,KAAA,CAAM,CAAC,EAAE,OAAA,EAAS,QAAA,EAAU,IAAA,EAAM,MAAA,EAAO,KAAM;AAChD,MAAA,MAAM,gBAAA,GAAgD;AAAA,QACpD,aAAA,EAAe;AAAA,UACb,WAAW,OAAA,CAAQ,EAAA;AAAA,UACnB,aAAa,OAAA,CAAQ,IAAA;AAAA,UACrB,MAAM,QAAA,CAAS,IAAA;AAAA,UACf,WAAW,QAAA,CAAS,SAAA;AAAA,UACpB,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,UAAA,EAAY,KAAK,KAAA,CAAM,CAAC,EAAE,UAAA,IAAc,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE;AAAA;AACxD,OACF;AAEA,MAAA,MAAM,kBAAA,GAAqB,IAAA,CAAK,UAAA,EAAY,GAAA,CAAI,CAAA,EAAA,MAAO;AAAA,QACrD,GAAG,gBAAgB,EAAE,CAAA;AAAA,QACrB,UAAA,EAAY,UAAA;AAAA,QACZ,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA;AAAA,QACpB,UAAU,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,UAAU,WAAA,EAAY;AAAA,QAC9C,QAAA,EAAU;AAAA,OACZ,CAAE,CAAA;AAEF,MAAA,IAAI,kBAAA,CAAmB,SAAS,CAAA,EAAG;AACjC,QAAA,kBAAA,CAAmB,OAAA,CAAQ;AAAA,UACzB,IAAA,EAAM,UAAA;AAAA,UACN,UAAA,EAAY,UAAA;AAAA,UACZ,UAAU,CAAA,EAAG,QAAA,CAAS,IAAI,CAAA,CAAA,EAAI,SAAS,SAAS,CAAA,kBAAA,CAAA;AAAA,UAChD,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA;AAAA,UACpB,UAAU,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,UAAU,WAAA,EAAY;AAAA,UAC9C,QAAA,EAAU;AAAA,SACX,CAAA;AAAA,MACH;AAEA,MAAA,MAAM,oBACJ,IAAA,CAAK,IAAA,KAAS,aACV,OAAA,CAAQ,SAAA,CAAU,IAAI,CAAA,QAAA,MAAa;AAAA,QACjC,GAAI,QAAA;AAAA,QACJ,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,QAAA;AAAA,QACpB,UAAU,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,UAAU,WAAA,EAAY;AAAA,QAC9C,QAAA,EAAU;AAAA,OACZ,CAAE,IACF,EAAC;AAEP,MAAA,MAAM,qBAAA,GACJ,KAAK,IAAA,KAAS,cAAA,GACV,OAAO,YAAA,EAAc,OAAA,EAAS,IAAI,CAAA,QAAA,MAAa;AAAA,QAC7C,GAAG,eAAA,CAAgB,QAAA,CAAS,EAAA,IAAM,SAAS,QAAQ,CAAA;AAAA,QACnD,IAAA,EAAM,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA;AAAA,QACpB,UAAU,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,UAAU,WAAA,EAAY;AAAA,QAC9C,QAAA,EAAU;AAAA,OACZ,CAAE,IACF,EAAC;AAEP,MAAA,OAAO,QAAA;AAAA,QACL;AAAA,UACE,GAAI,sBAAsB,EAAC;AAAA,UAC3B,GAAI,yBAAyB,EAAC;AAAA,UAC9B,GAAI,qBAAqB;AAAC,SAC5B;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AACF;AASA,SAAS,iBAAA,CAAkB,MAAmB,OAAA,EAAsB;AAClE,EAAA,OAAO,MAAA,CAAO,IAAI,CAAA,CAAE,KAAA,CAAM,CAAAA,KAAAA,KAAQ;AAChC,IAAA,OAAO,SAAA;AAAA,MACL;AAAA,QACE,KAAA,EAAO,SAAA,CAAUA,KAAAA,CAAK,IAAA,EAAMA,MAAK,KAAK,CAAA;AAAA,QAEtC,WAAA,EAAaA,KAAAA,CAAK,QAAA,GACdA,KAAAA,CAAK,WAAA,GACHA,KAAAA,CAAK,WAAA,GACL,OAAA,CAAQ,WAAA,GACV,SAAA,CAAU,MAAA,EAAWA,KAAAA,CAAK,WAAW,CAAA;AAAA,QAEzC,IAAA,EAAM,cAAA,CAAeA,KAAAA,EAAM,OAAO;AAAA,OACpC;AAAA,MACA,IAAA,CAAKA,OAAM,gBAAgB;AAAA,KAC7B;AAAA,EACF,CAAC,CAAA;AACH;AAEA,IAAM,cAAA,GAAN,cAA6B,OAAA,CAAQ;AAAA,EACnC,WAAA,CAAY,IAAA,EAAc,IAAA,EAAmB,IAAA,EAAiC;AAC5E,IAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA,OAAA,KAAW;AAC9D,MAAA,OAAO,IAAI,KAAK,EAAA,CAAG,OAAA;AAAA,QACjB,IAAA;AAAA,QACA;AAAA,UACE,QAAA,EAAU,WAAA,CAAY,IAAA,EAAM,IAAI,CAAA;AAAA,UAChC,IAAA,EAAM,iBAAA,CAAkB,IAAA,EAAM,OAAO;AAAA,SACvC;AAAA,QACA,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,MAAM,QAAA,EAAU,WAAA,CAAY,OAAO,CAAA;AAAE,OAC1D;AAAA,IACF,CAAC,CAAA;AAED,IAAA,KAAA;AAAA,MACE,uBAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MAEA,OAAA,CAAQ,UAAA;AAAA,MACR,OAAA,CAAQ,IAAA;AAAA,MACR,MAAA,CAAO,KAAK,SAAS,CAAA;AAAA,MACrB,OAAA,CAAQ,QAAA;AAAA,MACR,OAAA,CAAQ,IAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACV;AAAA,EACF;AACF,CAAA;AAEA,IAAM,YAAA,GAAN,cAA2B,OAAA,CAAQ;AAAA,EACjC,WAAA,CAAY,IAAA,EAAc,IAAA,EAAmB,IAAA,EAAiC;AAC5E,IAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA,OAAA,KAAW;AAC9D,MAAA,OAAO,IAAI,KAAK,EAAA,CAAG,YAAA;AAAA,QACjB,IAAA;AAAA,QACA;AAAA,UACE,QAAA,EAAU,WAAA,CAAY,IAAA,EAAM,IAAI,CAAA;AAAA,UAChC,IAAA,EAAM,iBAAA,CAAkB,IAAA,EAAM,OAAO;AAAA,SACvC;AAAA,QACA,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,MAAM,QAAA,EAAU,WAAA,CAAY,OAAO,CAAA;AAAE,OAC1D;AAAA,IACF,CAAC,CAAA;AAED,IAAA,KAAA;AAAA,MACE,4BAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MAEA,OAAA,CAAQ,UAAA;AAAA,MACR,OAAA,CAAQ,IAAA;AAAA,MACR,MAAA,CAAO,KAAK,SAAS,CAAA;AAAA,MACrB,OAAA,CAAQ,QAAA;AAAA,MACR,OAAA,CAAQ,IAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACV;AAAA,EACF;AACF,CAAA;AAcA,IAAM,cAAA,GAAN,cAA6B,OAAA,CAAQ;AAAA,EACnC,WAAA,CAAY,IAAA,EAAc,IAAA,EAA0B,IAAA,EAAiC;AACnF,IAAA,KAAA;AAAA,MACE,8BAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MAEA,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,UAAA;AAAA,MACrB,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,IAAA;AAAA,MACrB,MAAA,CAAO,KAAK,SAAS,CAAA;AAAA,MACrB,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,QAAA;AAAA,MACrB,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,IAAA;AAAA,MACrB,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE;AAAA,KACvB;AAAA,EACF;AACF,CAAA;AAcA,IAAM,eAAA,GAAN,cAA8B,OAAA,CAAQ;AAAA,EACpC,WAAA,CAAY,IAAA,EAAc,IAAA,EAA2B,IAAA,EAAiC;AACpF,IAAA,MAAM,UAAU,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA,OAAA,KAAW;AAC9D,MAAA,OAAO,IAAA,CAAK,GAAG,OAAA,CAAQ,GAAA;AAAA,QACrB,IAAA;AAAA,QACA,WAAA,CAAA,EAAc,OAAO,IAAA,CAAK,SAAS,EAAE,QAAA,CAAS,IAAI,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,QAC/D,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,MAAM,QAAA,EAAU,WAAA,CAAY,OAAO,CAAA;AAAE,OAC1D;AAAA,IACF,CAAC,CAAA;AAED,IAAA,KAAA;AAAA,MACE,+BAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MACA,IAAA;AAAA,MAEA,OAAA,CAAQ,UAAA;AAAA,MACR,OAAA,CAAQ,IAAA;AAAA,MACR,MAAA,CAAO,KAAK,SAAS,CAAA;AAAA,MACrB,OAAA,CAAQ,QAAA;AAAA,MACR,OAAA,CAAQ,IAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACV;AAAA,EACF;AACF,CAAA;AAQO,SAAS,8BACd,IAAA,EACiC;AACjC,EAAA,OAAO;AAAA,IACL,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,MAAM,IAAA,CAAK,aAAA;AAAA,IACX,YAAY,IAAA,CAAK,aAAA;AAAA,IACjB,UAAU,IAAA,CAAK;AAAA,GACjB;AACF;AAQO,SAAS,0BACd,OAAA,EACmC;AACnC,EAAA,OAAO;AAAA,IACL,WAAA,EAAa,QAAQ,IAAA,CAAK;AAAA,GAC5B;AACF;AASO,SAAS,cAAA,CACd,SACA,OAAA,EACe;AACf,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,OAAO,OAAA,CAAQ,IAAA;AAAA,EACjB;AAEA,EAAA,IAAI,CAAC,SAAS,QAAA,EAAU;AACtB,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,OAAO,OAAA,CAAQ,MAAA,EAAQ,mBAAA,KAAwB,cAAA,GAAiB,cAAA,GAAiB,UAAA;AACnF;AAQO,SAAS,wBACd,QAAA,EACiC;AACjC,EAAA,OAAO;AAAA,IACL,MAAM,QAAA,CAAS,IAAA;AAAA,IACf,QAAA,EAAU,QAAA,CAAS,QAAA,CAAS,WAAA;AAAY,GAC1C;AACF","file":"chunk-3CKMDTYK.js","sourcesContent":["import { filterEndpoints, l4EndpointToString, parseL3Endpoint } from \"@highstate/common\"\nimport { check, getOrCreate } from \"@highstate/contract\"\nimport { k8s, type network } from \"@highstate/library\"\nimport {\n type ComponentResourceOptions,\n type Input,\n type Inputs,\n interpolate,\n normalize,\n type Output,\n output,\n toPromise,\n} from \"@highstate/pulumi\"\nimport { core, type types } from \"@pulumi/kubernetes\"\nimport { deepmerge } from \"deepmerge-ts\"\nimport { omit, uniqueBy } from \"remeda\"\nimport { Namespace } from \"./namespace\"\nimport {\n commonExtraArgs,\n getProvider,\n mapMetadata,\n ScopedResource,\n type ScopedResourceArgs,\n} from \"./shared\"\n\nexport type ServiceArgs = ScopedResourceArgs & {\n /**\n * The port to expose the service on.\n */\n port?: Input<types.input.core.v1.ServicePort>\n\n /**\n * Whether the service should be exposed by `NodePort` or `LoadBalancer`.\n *\n * The type of the service will be determined automatically based on the cluster.\n */\n external?: Input<boolean>\n} & types.input.core.v1.ServiceSpec\n\nexport type CreateOrGetServiceArgs = ServiceArgs & {\n /**\n * The service entity to patch/retrieve.\n */\n existing: Input<k8s.Service> | undefined\n}\n\nconst serviceExtraArgs = [...commonExtraArgs, \"port\", \"ports\", \"external\"] as const\n\n/**\n * Checks if the endpoint is from the given cluster.\n *\n * @param endpoint The endpoint to check.\n * @param cluster The cluster to check against.\n * @returns True if the endpoint is from the cluster, false otherwise.\n */\nexport function isEndpointFromCluster(\n endpoint: network.L3Endpoint,\n cluster: k8s.Cluster,\n): endpoint is k8s.ServiceEndpoint {\n return (\n check(k8s.serviceEndpointSchema, endpoint) &&\n endpoint.metadata[\"k8s.service\"].clusterId === cluster.id\n )\n}\n\n/**\n * Represents a Kubernetes Service resource with endpoints and metadata.\n */\nexport abstract class Service extends ScopedResource {\n protected constructor(\n type: string,\n name: string,\n args: Inputs,\n opts: ComponentResourceOptions | undefined,\n\n apiVersion: Output<string>,\n kind: Output<string>,\n namespace: Output<Namespace>,\n metadata: Output<types.output.meta.v1.ObjectMeta>,\n\n /**\n * The spec of the underlying Kubernetes service.\n */\n readonly spec: Output<types.output.core.v1.ServiceSpec>,\n\n /**\n * The status of the underlying Kubernetes service.\n */\n readonly status: Output<types.output.core.v1.ServiceStatus>,\n ) {\n super(type, name, args, opts, apiVersion, kind, namespace, metadata)\n }\n\n /**\n * The Highstate service entity.\n */\n get entity(): Output<k8s.Service> {\n return output({\n type: \"service\",\n clusterId: this.cluster.id,\n clusterName: this.cluster.name,\n metadata: this.metadata,\n endpoints: this.endpoints,\n })\n }\n\n /**\n * Creates a new service.\n */\n static create(name: string, args: ServiceArgs, opts?: ComponentResourceOptions): Service {\n return new CreatedService(name, args, opts)\n }\n\n /**\n * Creates a new service or patches an existing one.\n *\n * @param name The name of the resource. May not be the same as the service name.\n * @param args The arguments to create or patch the service with.\n * @param opts Optional resource options.\n */\n static createOrPatch(\n name: string,\n args: CreateOrGetServiceArgs,\n opts?: ComponentResourceOptions,\n ): Service {\n if (args.existing) {\n return new ServicePatch(name, {\n ...args,\n name: output(args.existing).metadata.name,\n namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),\n })\n }\n\n return new CreatedService(name, args, opts)\n }\n\n /**\n * Creates a new service or gets an existing one.\n *\n * @param name The name of the resource. May not be the same as the service name. Will not be used when existing service is retrieved.\n * @param args The arguments to create or get the service with.\n * @param opts Optional resource options.\n */\n static async createOrGet(\n name: string,\n args: CreateOrGetServiceArgs,\n opts?: ComponentResourceOptions,\n ): Promise<Service> {\n if (args.existing) {\n return await Service.forAsync(args.existing, output(args.namespace).cluster)\n }\n\n return new CreatedService(name, args, opts)\n }\n\n /**\n * Patches an existing service.\n *\n * Will throw an error if the service does not exist.\n *\n * @param name The name of the resource. May not be the same as the service name.\n * @param args The arguments to patch the service with.\n * @param opts Optional resource options.\n */\n static patch(name: string, args: ServiceArgs, opts?: ComponentResourceOptions): Service {\n return new ServicePatch(name, args, opts)\n }\n\n /**\n * Wraps an existing Kubernetes service.\n */\n static wrap(name: string, args: WrappedServiceArgs, opts?: ComponentResourceOptions): Service {\n return new WrappedService(name, args, opts)\n }\n\n /**\n * Gets an existing service.\n *\n * Will throw an error if the service does not exist.\n */\n static get(name: string, args: ExternalServiceArgs, opts?: ComponentResourceOptions): Service {\n return new ExternalService(name, args, opts)\n }\n\n private static readonly serviceCache = new Map<string, Service>()\n\n /**\n * Gets an existing service for a given entity.\n * Prefer this method over `get` when possible.\n *\n * It automatically names the resource with the following format: `{clusterName}.{namespace}.{name}.{clusterId}`.\n *\n * This method is idempotent and will return the same instance for the same entity.\n *\n * @param entity The entity to get the service for.\n * @param cluster The cluster where the service is located.\n */\n static for(entity: k8s.Service, cluster: Input<k8s.Cluster>): Service {\n return getOrCreate(\n Service.serviceCache,\n `${entity.clusterName}.${entity.metadata.namespace}.${entity.metadata.name}.${entity.clusterId}`,\n name => {\n return Service.get(name, {\n name: entity.metadata.name,\n namespace: Namespace.forResourceAsync(entity, cluster),\n })\n },\n )\n }\n\n /**\n * Gets an existing service for a given entity.\n * Prefer this method over `get` when possible.\n *\n * It automatically names the resource with the following format: `{clusterName}.{namespace}.{name}.{clusterId}`.\n *\n * This method is idempotent and will return the same instance for the same entity.\n *\n * @param entity The entity to get the service for.\n * @param cluster The cluster where the service is located.\n */\n static async forAsync(entity: Input<k8s.Service>, cluster: Input<k8s.Cluster>): Promise<Service> {\n const resolvedEntity = await toPromise(entity)\n\n return Service.for(resolvedEntity, output(cluster))\n }\n\n /**\n * Returns the endpoints of the service applying the given filter.\n *\n * If no filter is specified, the default behavior of `filterEndpoints` is used.\n *\n * @param filter If specified, the endpoints are filtered based on the given filter.\n * @returns The endpoints of the service.\n */\n filterEndpoints(filter?: network.EndpointFilter): Output<k8s.ServiceEndpoint[]> {\n return output(this.endpoints).apply(endpoints => filterEndpoints(endpoints, filter))\n }\n\n /**\n * Returns the endpoints of the service including both internal and external endpoints.\n */\n get endpoints(): Output<k8s.ServiceEndpoint[]> {\n return output({\n cluster: this.cluster,\n metadata: this.metadata,\n spec: this.spec,\n status: this.status,\n }).apply(({ cluster, metadata, spec, status }) => {\n const endpointMetadata: k8s.EndpointServiceMetadata = {\n \"k8s.service\": {\n clusterId: cluster.id,\n clusterName: cluster.name,\n name: metadata.name,\n namespace: metadata.namespace,\n selector: spec.selector,\n targetPort: spec.ports[0].targetPort ?? spec.ports[0].port,\n },\n }\n\n const clusterIpEndpoints = spec.clusterIPs?.map(ip => ({\n ...parseL3Endpoint(ip),\n visibility: \"internal\" as network.EndpointVisibility,\n port: spec.ports[0].port,\n protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,\n metadata: endpointMetadata,\n }))\n\n if (clusterIpEndpoints.length > 0) {\n clusterIpEndpoints.unshift({\n type: \"hostname\",\n visibility: \"internal\",\n hostname: `${metadata.name}.${metadata.namespace}.svc.cluster.local`,\n port: spec.ports[0].port,\n protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,\n metadata: endpointMetadata,\n })\n }\n\n const nodePortEndpoints =\n spec.type === \"NodePort\"\n ? cluster.endpoints.map(endpoint => ({\n ...(endpoint as network.L3Endpoint),\n port: spec.ports[0].nodePort,\n protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,\n metadata: endpointMetadata,\n }))\n : []\n\n const loadBalancerEndpoints =\n spec.type === \"LoadBalancer\"\n ? status.loadBalancer?.ingress?.map(endpoint => ({\n ...parseL3Endpoint(endpoint.ip ?? endpoint.hostname),\n port: spec.ports[0].port,\n protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,\n metadata: endpointMetadata,\n }))\n : []\n\n return uniqueBy(\n [\n ...(clusterIpEndpoints ?? []),\n ...(loadBalancerEndpoints ?? []),\n ...(nodePortEndpoints ?? []),\n ],\n l4EndpointToString,\n )\n })\n }\n}\n\n/**\n * Creates the service spec configuration based on arguments and cluster settings.\n *\n * @param args The service arguments containing port and external configuration.\n * @param cluster The cluster where the service will be created.\n * @returns The service spec configuration.\n */\nfunction createServiceSpec(args: ServiceArgs, cluster: k8s.Cluster) {\n return output(args).apply(args => {\n return deepmerge(\n {\n ports: normalize(args.port, args.ports),\n\n externalIPs: args.external\n ? args.externalIPs\n ? args.externalIPs\n : cluster.externalIps\n : normalize(undefined, args.externalIPs),\n\n type: getServiceType(args, cluster),\n },\n omit(args, serviceExtraArgs),\n )\n })\n}\n\nclass CreatedService extends Service {\n constructor(name: string, args: ServiceArgs, opts?: ComponentResourceOptions) {\n const service = output(args.namespace).cluster.apply(cluster => {\n return new core.v1.Service(\n name,\n {\n metadata: mapMetadata(args, name),\n spec: createServiceSpec(args, cluster),\n },\n { ...opts, parent: this, provider: getProvider(cluster) },\n )\n })\n\n super(\n \"highstate:k8s:Service\",\n name,\n args,\n opts,\n\n service.apiVersion,\n service.kind,\n output(args.namespace),\n service.metadata,\n service.spec,\n service.status,\n )\n }\n}\n\nclass ServicePatch extends Service {\n constructor(name: string, args: ServiceArgs, opts?: ComponentResourceOptions) {\n const service = output(args.namespace).cluster.apply(cluster => {\n return new core.v1.ServicePatch(\n name,\n {\n metadata: mapMetadata(args, name),\n spec: createServiceSpec(args, cluster),\n },\n { ...opts, parent: this, provider: getProvider(cluster) },\n )\n })\n\n super(\n \"highstate:k8s:ServicePatch\",\n name,\n args,\n opts,\n\n service.apiVersion,\n service.kind,\n output(args.namespace),\n service.metadata,\n service.spec,\n service.status,\n )\n }\n}\n\nexport type WrappedServiceArgs = {\n /**\n * The underlying Kubernetes service to wrap.\n */\n service: Input<core.v1.Service>\n\n /**\n * The namespace where the service is located.\n */\n namespace: Input<Namespace>\n}\n\nclass WrappedService extends Service {\n constructor(name: string, args: WrappedServiceArgs, opts?: ComponentResourceOptions) {\n super(\n \"highstate:k8s:WrappedService\",\n name,\n args,\n opts,\n\n output(args.service).apiVersion,\n output(args.service).kind,\n output(args.namespace),\n output(args.service).metadata,\n output(args.service).spec,\n output(args.service).status,\n )\n }\n}\n\nexport type ExternalServiceArgs = {\n /**\n * The name of the service to get.\n */\n name: Input<string>\n\n /**\n * The namespace of the service to get.\n */\n namespace: Input<Namespace>\n}\n\nclass ExternalService extends Service {\n constructor(name: string, args: ExternalServiceArgs, opts?: ComponentResourceOptions) {\n const service = output(args.namespace).cluster.apply(cluster => {\n return core.v1.Service.get(\n name,\n interpolate`${output(args.namespace).metadata.name}/${args.name}`,\n { ...opts, parent: this, provider: getProvider(cluster) },\n )\n })\n\n super(\n \"highstate:k8s:ExternalService\",\n name,\n args,\n opts,\n\n service.apiVersion,\n service.kind,\n output(args.namespace),\n service.metadata,\n service.spec,\n service.status,\n )\n }\n}\n\n/**\n * Maps a container port to a service port.\n *\n * @param port The container port to map.\n * @returns The corresponding service port configuration.\n */\nexport function mapContainerPortToServicePort(\n port: types.input.core.v1.ContainerPort,\n): types.input.core.v1.ServicePort {\n return {\n name: port.name,\n port: port.containerPort,\n targetPort: port.containerPort,\n protocol: port.protocol,\n }\n}\n\n/**\n * Maps a service to a label selector.\n *\n * @param service The service to extract the label selector from.\n * @returns The label selector based on the service's selector.\n */\nexport function mapServiceToLabelSelector(\n service: core.v1.Service,\n): types.input.meta.v1.LabelSelector {\n return {\n matchLabels: service.spec.selector,\n }\n}\n\n/**\n * Determines the appropriate service type based on the service arguments and cluster configuration.\n *\n * @param service The service configuration containing type and external properties.\n * @param cluster The cluster where the service will be created.\n * @returns The service type to use.\n */\nexport function getServiceType(\n service: Pick<ServiceArgs, \"type\" | \"external\"> | undefined,\n cluster: k8s.Cluster,\n): Input<string> {\n if (service?.type) {\n return service.type\n }\n\n if (!service?.external) {\n return \"ClusterIP\"\n }\n\n return cluster.quirks?.externalServiceType === \"LoadBalancer\" ? \"LoadBalancer\" : \"NodePort\"\n}\n\n/**\n * Converts a network L4 endpoint to a Kubernetes service port.\n *\n * @param endpoint The L4 endpoint to convert.\n * @returns The corresponding Kubernetes service port configuration.\n */\nexport function l4EndpointToServicePort(\n endpoint: network.L4Endpoint,\n): types.input.core.v1.ServicePort {\n return {\n port: endpoint.port,\n protocol: endpoint.protocol.toUpperCase(),\n }\n}\n"]}