@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,31 +1,29 @@
1
- import { commonExtraArgs, ScopedResource, Namespace, mapMetadata, getProvider } from './chunk-SEWB4FUB.js';
2
- import { filterEndpoints, parseL3Endpoint, l4EndpointToString } from '@highstate/common';
1
+ import { commonExtraArgs, NamespacedResource, Namespace, mapMetadata, getProvider } from './chunk-OBDQONMV.js';
2
+ import { parseEndpoint, l3EndpointToL4, parseL4Protocol, addEndpointMetadata, mergeEndpoints } from '@highstate/common';
3
3
  import { check, getOrCreate } from '@highstate/contract';
4
4
  import { k8s } from '@highstate/library';
5
- import { output, toPromise, interpolate, normalize } from '@highstate/pulumi';
5
+ import { output, toPromise, normalize, interpolate } from '@highstate/pulumi';
6
6
  import { core } from '@pulumi/kubernetes';
7
- import { deepmerge } from 'deepmerge-ts';
8
- import { uniqueBy, omit } from 'remeda';
7
+ import { pipe, omit } from 'remeda';
9
8
 
10
9
  var serviceExtraArgs = [...commonExtraArgs, "port", "ports", "external"];
11
10
  function isEndpointFromCluster(endpoint, cluster) {
12
11
  return check(k8s.serviceEndpointSchema, endpoint) && endpoint.metadata["k8s.service"].clusterId === cluster.id;
13
12
  }
14
- var Service = class _Service extends ScopedResource {
15
- constructor(type, name, args, opts, apiVersion, kind, namespace, metadata, spec, status) {
16
- super(type, name, args, opts, apiVersion, kind, namespace, metadata);
13
+ var Service = class _Service extends NamespacedResource {
14
+ constructor(type, name, args, opts, metadata, namespace, spec, status) {
15
+ super(type, name, args, opts, metadata, namespace);
17
16
  this.spec = spec;
18
17
  this.status = status;
19
18
  }
19
+ static apiVersion = "v1";
20
+ static kind = "Service";
20
21
  /**
21
22
  * The Highstate service entity.
22
23
  */
23
24
  get entity() {
24
25
  return output({
25
- type: "service",
26
- clusterId: this.cluster.id,
27
- clusterName: this.cluster.name,
28
- metadata: this.metadata,
26
+ ...this.entityBase,
29
27
  endpoints: this.endpoints
30
28
  });
31
29
  }
@@ -130,17 +128,6 @@ var Service = class _Service extends ScopedResource {
130
128
  const resolvedEntity = await toPromise(entity);
131
129
  return _Service.for(resolvedEntity, output(cluster));
132
130
  }
133
- /**
134
- * Returns the endpoints of the service applying the given filter.
135
- *
136
- * If no filter is specified, the default behavior of `filterEndpoints` is used.
137
- *
138
- * @param filter If specified, the endpoints are filtered based on the given filter.
139
- * @returns The endpoints of the service.
140
- */
141
- filterEndpoints(filter) {
142
- return output(this.endpoints).apply((endpoints) => filterEndpoints(endpoints, filter));
143
- }
144
131
  /**
145
132
  * Returns the endpoints of the service including both internal and external endpoints.
146
133
  */
@@ -151,66 +138,64 @@ var Service = class _Service extends ScopedResource {
151
138
  spec: this.spec,
152
139
  status: this.status
153
140
  }).apply(({ cluster, metadata, spec, status }) => {
154
- const endpointMetadata = {
155
- "k8s.service": {
156
- clusterId: cluster.id,
157
- clusterName: cluster.name,
158
- name: metadata.name,
159
- namespace: metadata.namespace,
160
- selector: spec.selector,
161
- targetPort: spec.ports[0].targetPort ?? spec.ports[0].port
162
- }
163
- };
164
- const clusterIpEndpoints = spec.clusterIPs?.map((ip) => ({
165
- ...parseL3Endpoint(ip),
166
- visibility: "internal",
167
- port: spec.ports[0].port,
168
- protocol: spec.ports[0].protocol?.toLowerCase(),
169
- metadata: endpointMetadata
170
- }));
171
- if (clusterIpEndpoints.length > 0) {
172
- clusterIpEndpoints.unshift({
173
- type: "hostname",
174
- visibility: "internal",
175
- hostname: `${metadata.name}.${metadata.namespace}.svc.cluster.local`,
176
- port: spec.ports[0].port,
177
- protocol: spec.ports[0].protocol?.toLowerCase(),
178
- metadata: endpointMetadata
179
- });
141
+ function createMetadata(isInternal) {
142
+ return {
143
+ "k8s.service": {
144
+ clusterId: cluster.id,
145
+ clusterName: cluster.name,
146
+ name: metadata.name,
147
+ namespace: metadata.namespace,
148
+ isInternal,
149
+ selector: spec.selector,
150
+ targetPort: spec.ports[0].targetPort ?? spec.ports[0].port
151
+ }
152
+ };
180
153
  }
181
- const nodePortEndpoints = spec.type === "NodePort" ? cluster.endpoints.map((endpoint) => ({
182
- ...endpoint,
183
- port: spec.ports[0].nodePort,
184
- protocol: spec.ports[0].protocol?.toLowerCase(),
185
- metadata: endpointMetadata
186
- })) : [];
187
- const loadBalancerEndpoints = spec.type === "LoadBalancer" ? status.loadBalancer?.ingress?.map((endpoint) => ({
188
- ...parseL3Endpoint(endpoint.ip ?? endpoint.hostname),
189
- port: spec.ports[0].port,
190
- protocol: spec.ports[0].protocol?.toLowerCase(),
191
- metadata: endpointMetadata
192
- })) : [];
193
- return uniqueBy(
194
- [
195
- ...clusterIpEndpoints ?? [],
196
- ...loadBalancerEndpoints ?? [],
197
- ...nodePortEndpoints ?? []
198
- ],
199
- l4EndpointToString
154
+ const internalHosts = spec.clusterIPs.length ? [...spec.clusterIPs, `${metadata.name}.${metadata.namespace}.svc.cluster.local`] : [];
155
+ const internalEndpoints = internalHosts.flatMap(
156
+ (ip) => spec.ports.map(
157
+ (port) => pipe(
158
+ ip,
159
+ parseEndpoint,
160
+ (endpoint) => l3EndpointToL4(endpoint, port.port, parseL4Protocol(port.protocol)),
161
+ (endpoint) => addEndpointMetadata(endpoint, createMetadata(true))
162
+ )
163
+ )
200
164
  );
165
+ const externalHosts = spec.type === "NodePort" || spec.type === "LoadBalancer" ? [
166
+ ...spec.externalIPs,
167
+ ...cluster.endpoints,
168
+ ...status.loadBalancer?.ingress?.map((ingress) => ingress.ip ?? ingress.hostname) ?? []
169
+ ] : [];
170
+ const externalEndpoints = externalHosts.flatMap(
171
+ (ip) => spec.ports.map(
172
+ (port) => pipe(
173
+ ip,
174
+ parseEndpoint,
175
+ (endpoint) => l3EndpointToL4(endpoint, port.port, parseL4Protocol(port.protocol)),
176
+ (endpoint) => addEndpointMetadata(endpoint, createMetadata(false))
177
+ )
178
+ )
179
+ );
180
+ return mergeEndpoints([...internalEndpoints, ...externalEndpoints]);
201
181
  });
202
182
  }
203
183
  };
204
184
  function createServiceSpec(args, cluster) {
205
185
  return output(args).apply((args2) => {
206
- return deepmerge(
207
- {
208
- ports: normalize(args2.port, args2.ports),
209
- externalIPs: args2.external ? args2.externalIPs ? args2.externalIPs : cluster.externalIps : normalize(void 0, args2.externalIPs),
210
- type: getServiceType(args2, cluster)
211
- },
212
- omit(args2, serviceExtraArgs)
213
- );
186
+ return {
187
+ ...omit(args2, serviceExtraArgs),
188
+ ports: normalize(args2.port, args2.ports),
189
+ // externalIPs: args.external
190
+ // ? args.externalIPs
191
+ // ? args.externalIPs
192
+ // : cluster.externalIps.map(ip => ip.value)
193
+ // : normalize(undefined, args.externalIPs),
194
+ // TODO: check for args.external being falsey
195
+ // for now we always set externalIPs since it for some reason fails if its empty
196
+ externalIPs: args2.externalIPs && args2.externalIPs.length > 0 ? args2.externalIPs : cluster.externalIps.map((ip) => ip.value),
197
+ type: getServiceType(args2, cluster)
198
+ };
214
199
  });
215
200
  }
216
201
  var CreatedService = class extends Service {
@@ -230,10 +215,8 @@ var CreatedService = class extends Service {
230
215
  name,
231
216
  args,
232
217
  opts,
233
- service.apiVersion,
234
- service.kind,
235
- output(args.namespace),
236
218
  service.metadata,
219
+ output(args.namespace),
237
220
  service.spec,
238
221
  service.status
239
222
  );
@@ -256,10 +239,8 @@ var ServicePatch = class extends Service {
256
239
  name,
257
240
  args,
258
241
  opts,
259
- service.apiVersion,
260
- service.kind,
261
- output(args.namespace),
262
242
  service.metadata,
243
+ output(args.namespace),
263
244
  service.spec,
264
245
  service.status
265
246
  );
@@ -272,10 +253,8 @@ var WrappedService = class extends Service {
272
253
  name,
273
254
  args,
274
255
  opts,
275
- output(args.service).apiVersion,
276
- output(args.service).kind,
277
- output(args.namespace),
278
256
  output(args.service).metadata,
257
+ output(args.namespace),
279
258
  output(args.service).spec,
280
259
  output(args.service).status
281
260
  );
@@ -295,10 +274,8 @@ var ExternalService = class extends Service {
295
274
  name,
296
275
  args,
297
276
  opts,
298
- service.apiVersion,
299
- service.kind,
300
- output(args.namespace),
301
277
  service.metadata,
278
+ output(args.namespace),
302
279
  service.spec,
303
280
  service.status
304
281
  );
@@ -333,6 +310,6 @@ function l4EndpointToServicePort(endpoint) {
333
310
  };
334
311
  }
335
312
 
336
- export { Service, getServiceType, isEndpointFromCluster, l4EndpointToServicePort, mapContainerPortToServicePort, mapServiceToLabelSelector };
337
- //# sourceMappingURL=chunk-3CKMDTYK.js.map
338
- //# sourceMappingURL=chunk-3CKMDTYK.js.map
313
+ export { Service, createServiceSpec, getServiceType, isEndpointFromCluster, l4EndpointToServicePort, mapContainerPortToServicePort, mapServiceToLabelSelector };
314
+ //# sourceMappingURL=chunk-TWBMG6TD.js.map
315
+ //# sourceMappingURL=chunk-TWBMG6TD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/service.ts"],"names":["args"],"mappings":"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","file":"chunk-TWBMG6TD.js","sourcesContent":["import {\n addEndpointMetadata,\n l3EndpointToL4,\n mergeEndpoints,\n parseEndpoint,\n parseL4Protocol,\n} 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 { omit, pipe } from \"remeda\"\nimport { Namespace } from \"./namespace\"\nimport {\n commonExtraArgs,\n getProvider,\n mapMetadata,\n NamespacedResource,\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 NamespacedResource {\n static apiVersion = \"v1\"\n static kind = \"Service\"\n\n protected constructor(\n type: string,\n name: string,\n args: Inputs,\n opts: ComponentResourceOptions | undefined,\n\n metadata: Output<types.output.meta.v1.ObjectMeta>,\n namespace: Output<Namespace>,\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, metadata, namespace)\n }\n\n /**\n * The Highstate service entity.\n */\n get entity(): Output<k8s.Service> {\n return output({\n ...this.entityBase,\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 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 function createMetadata(isInternal: boolean): k8s.EndpointServiceMetadata {\n return {\n \"k8s.service\": {\n clusterId: cluster.id,\n clusterName: cluster.name,\n name: metadata.name,\n namespace: metadata.namespace,\n isInternal,\n selector: spec.selector,\n targetPort: spec.ports[0].targetPort ?? spec.ports[0].port,\n },\n }\n }\n\n const internalHosts = spec.clusterIPs.length\n ? [...spec.clusterIPs, `${metadata.name}.${metadata.namespace}.svc.cluster.local`]\n : []\n\n const internalEndpoints = internalHosts.flatMap(ip =>\n spec.ports.map(port =>\n pipe(\n ip,\n parseEndpoint,\n endpoint => l3EndpointToL4(endpoint, port.port, parseL4Protocol(port.protocol)),\n endpoint => addEndpointMetadata(endpoint, createMetadata(true)),\n ),\n ),\n )\n\n const externalHosts =\n spec.type === \"NodePort\" || spec.type === \"LoadBalancer\"\n ? [\n ...spec.externalIPs,\n ...cluster.endpoints,\n ...(status.loadBalancer?.ingress?.map(ingress => ingress.ip ?? ingress.hostname) ??\n []),\n ]\n : []\n\n const externalEndpoints = externalHosts.flatMap(ip =>\n spec.ports.map(port =>\n pipe(\n ip,\n parseEndpoint,\n endpoint => l3EndpointToL4(endpoint, port.port, parseL4Protocol(port.protocol)),\n endpoint => addEndpointMetadata(endpoint, createMetadata(false)),\n ),\n ),\n )\n\n return mergeEndpoints([...internalEndpoints, ...externalEndpoints])\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 */\nexport function createServiceSpec(\n args: Partial<ServiceArgs>,\n cluster: k8s.Cluster,\n): Output<types.input.core.v1.ServiceSpec> {\n return output(args).apply(args => {\n return {\n ...omit(args, serviceExtraArgs),\n\n ports: normalize(args.port, args.ports),\n\n // externalIPs: args.external\n // ? args.externalIPs\n // ? args.externalIPs\n // : cluster.externalIps.map(ip => ip.value)\n // : normalize(undefined, args.externalIPs),\n\n // TODO: check for args.external being falsey\n // for now we always set externalIPs since it for some reason fails if its empty\n externalIPs:\n args.externalIPs && args.externalIPs.length > 0\n ? args.externalIPs\n : cluster.externalIps.map(ip => ip.value),\n\n type: getServiceType(args, cluster),\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 service.metadata,\n output(args.namespace),\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 service.metadata,\n output(args.namespace),\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 output(args.service).metadata,\n output(args.namespace),\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 service.metadata,\n output(args.namespace),\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"]}