@highstate/k8s 0.9.4 → 0.9.6

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 (63) hide show
  1. package/dist/chunk-DQSCJM5S.js +183 -0
  2. package/dist/chunk-DQSCJM5S.js.map +1 -0
  3. package/dist/chunk-FKNHHKOL.js +260 -0
  4. package/dist/chunk-FKNHHKOL.js.map +1 -0
  5. package/dist/chunk-HW3NS3MC.js +347 -0
  6. package/dist/chunk-HW3NS3MC.js.map +1 -0
  7. package/dist/chunk-OQ7UXASD.js +193 -0
  8. package/dist/chunk-OQ7UXASD.js.map +1 -0
  9. package/dist/chunk-QGHMLKTW.js +1123 -0
  10. package/dist/chunk-QGHMLKTW.js.map +1 -0
  11. package/dist/chunk-UNVSWG6D.js +214 -0
  12. package/dist/chunk-UNVSWG6D.js.map +1 -0
  13. package/dist/deployment-ZP3ASKPT.js +10 -0
  14. package/dist/deployment-ZP3ASKPT.js.map +1 -0
  15. package/dist/highstate.manifest.json +8 -6
  16. package/dist/index.js +291 -954
  17. package/dist/index.js.map +1 -1
  18. package/dist/stateful-set-2AH7RAF7.js +10 -0
  19. package/dist/stateful-set-2AH7RAF7.js.map +1 -0
  20. package/dist/units/access-point/index.js +6 -1
  21. package/dist/units/access-point/index.js.map +1 -1
  22. package/dist/units/cert-manager/index.js +19 -24
  23. package/dist/units/cert-manager/index.js.map +1 -1
  24. package/dist/units/cluster-dns/index.js +36 -0
  25. package/dist/units/cluster-dns/index.js.map +1 -0
  26. package/dist/units/cluster-patch/index.js +34 -0
  27. package/dist/units/cluster-patch/index.js.map +1 -0
  28. package/dist/units/dns01-issuer/index.js +2 -2
  29. package/dist/units/dns01-issuer/index.js.map +1 -1
  30. package/dist/units/existing-cluster/index.js +22 -14
  31. package/dist/units/existing-cluster/index.js.map +1 -1
  32. package/dist/units/gateway-api/index.js +1 -1
  33. package/package.json +12 -10
  34. package/src/access-point.ts +44 -39
  35. package/src/container.ts +54 -5
  36. package/src/cron-job.ts +14 -30
  37. package/src/deployment.ts +170 -127
  38. package/src/gateway/http-route.ts +7 -5
  39. package/src/helm.ts +57 -8
  40. package/src/index.ts +11 -4
  41. package/src/job.ts +14 -32
  42. package/src/namespace.ts +241 -0
  43. package/src/network-policy.ts +371 -87
  44. package/src/network.ts +41 -0
  45. package/src/pvc.ts +43 -25
  46. package/src/scripting/bundle.ts +125 -22
  47. package/src/scripting/container.ts +16 -11
  48. package/src/scripting/environment.ts +56 -6
  49. package/src/secret.ts +195 -0
  50. package/src/service.ts +209 -89
  51. package/src/shared.ts +42 -51
  52. package/src/stateful-set.ts +193 -88
  53. package/src/units/access-point/index.ts +8 -1
  54. package/src/units/cert-manager/index.ts +15 -20
  55. package/src/units/cluster-dns/index.ts +37 -0
  56. package/src/units/cluster-patch/index.ts +35 -0
  57. package/src/units/dns01-issuer/index.ts +1 -1
  58. package/src/units/existing-cluster/index.ts +24 -14
  59. package/src/workload.ts +342 -44
  60. package/dist/chunk-K4WKJ4L5.js +0 -455
  61. package/dist/chunk-K4WKJ4L5.js.map +0 -1
  62. package/dist/chunk-T5Z2M4JE.js +0 -103
  63. package/dist/chunk-T5Z2M4JE.js.map +0 -1
package/src/deployment.ts CHANGED
@@ -1,62 +1,49 @@
1
1
  import type { k8s } from "@highstate/library"
2
2
  import type { HttpRoute } from "./gateway"
3
3
  import type { Service } from "./service"
4
- import {
5
- output,
6
- type ComponentResourceOptions,
7
- Output,
8
- type Inputs,
9
- ComponentResource,
10
- type InputArray,
11
- Resource,
12
- type Input,
13
- type InstanceTerminal,
14
- interpolate,
15
- } from "@highstate/pulumi"
4
+ import type { NetworkPolicy } from "./network-policy"
5
+ import { output, type ComponentResourceOptions, Output, type Input } from "@highstate/pulumi"
16
6
  import { apps, types } from "@pulumi/kubernetes"
17
7
  import { omit } from "remeda"
18
8
  import { deepmerge } from "deepmerge-ts"
19
- import { trimIndentation } from "@highstate/contract"
20
- import { mapMetadata, verifyProvider } from "./shared"
21
- import { mapContainerToRaw } from "./container"
22
9
  import {
23
- getPublicWorkloadComponents,
24
- publicWorkloadExtraArgs,
25
- type PublicWorkloadArgs,
10
+ getProvider,
11
+ mapMetadata,
12
+ resourceIdToString,
13
+ withPatchName,
14
+ type ResourceId,
15
+ } from "./shared"
16
+ import {
17
+ exposableWorkloadExtraArgs,
18
+ ExposableWorkload,
19
+ type ExposableWorkloadArgs,
20
+ getExposableWorkloadComponents,
26
21
  } from "./workload"
27
22
 
28
- export type DeploymentArgs = Omit<PublicWorkloadArgs, "patch"> & {
29
- patch?: Input<k8s.Deployment>
30
-
31
- /**
32
- * The shell to use in the terminal.
33
- *
34
- * By default, `bash` is used.
35
- */
36
- terminalShell?: string
37
- } & Omit<Partial<types.input.apps.v1.DeploymentSpec>, "template"> & {
23
+ export type DeploymentArgs = Omit<ExposableWorkloadArgs, "existing"> &
24
+ Omit<Partial<types.input.apps.v1.DeploymentSpec>, "template"> & {
38
25
  template?: {
39
26
  metadata?: types.input.meta.v1.ObjectMeta
40
27
  spec?: Partial<types.input.core.v1.PodSpec>
41
28
  }
42
29
  }
43
30
 
44
- export abstract class Deployment extends ComponentResource {
31
+ export type CreateOrGetDeploymentArgs = DeploymentArgs & {
32
+ /**
33
+ * The entity to use to determine the deployment to patch.
34
+ */
35
+ existing: Input<k8s.Deployment> | undefined
36
+ }
37
+
38
+ export abstract class Deployment extends ExposableWorkload {
45
39
  protected constructor(
46
40
  type: string,
47
41
  name: string,
48
- private readonly args: Inputs,
49
- opts: ComponentResourceOptions,
50
-
51
- /**
52
- * The cluster where the deployment is created.
53
- */
54
- readonly cluster: Output<k8s.Cluster>,
42
+ args: ExposableWorkloadArgs,
43
+ opts: ComponentResourceOptions | undefined,
55
44
 
56
- /**
57
- * The metadata of the underlying Kubernetes deployment.
58
- */
59
- readonly metadata: Output<types.output.meta.v1.ObjectMeta>,
45
+ cluster: Output<k8s.Cluster>,
46
+ metadata: Output<types.output.meta.v1.ObjectMeta>,
60
47
 
61
48
  /**
62
49
  * The spec of the underlying Kubernetes deployment.
@@ -68,15 +55,23 @@ export abstract class Deployment extends ComponentResource {
68
55
  */
69
56
  readonly status: Output<types.output.apps.v1.DeploymentStatus>,
70
57
 
71
- private readonly _service: Output<Service | undefined>,
72
- private readonly _httpRoute: Output<HttpRoute | undefined>,
58
+ networkPolicy: Output<NetworkPolicy | undefined>,
73
59
 
74
- /**
75
- * The resources associated with the deployment.
76
- */
77
- readonly resources: InputArray<Resource>,
60
+ service: Output<Service | undefined>,
61
+ httpRoute: Output<HttpRoute | undefined>,
78
62
  ) {
79
- super(type, name, args, opts)
63
+ super(
64
+ type,
65
+ name,
66
+ args,
67
+ opts,
68
+ "deployment",
69
+ cluster,
70
+ metadata,
71
+ networkPolicy,
72
+ service,
73
+ httpRoute,
74
+ )
80
75
  }
81
76
 
82
77
  /**
@@ -85,113 +80,130 @@ export abstract class Deployment extends ComponentResource {
85
80
  get entity(): Output<k8s.Deployment> {
86
81
  return output({
87
82
  type: "k8s.deployment",
88
- clusterInfo: this.cluster.info,
83
+ clusterId: this.cluster.id,
89
84
  metadata: this.metadata,
90
- spec: this.spec,
91
85
  service: this._service.apply(service => service?.entity),
92
86
  })
93
87
  }
94
88
 
95
- get optionalService(): Output<Service | undefined> {
96
- return this._service
89
+ static create(name: string, args: DeploymentArgs, opts?: ComponentResourceOptions): Deployment {
90
+ return new CreatedDeployment(name, args, opts)
97
91
  }
98
92
 
99
- /**
100
- * The service associated with the deployment.
101
- */
102
- get service(): Output<Service> {
103
- return this._service.apply(service => {
104
- if (!service) {
105
- throw new Error("The service is not available.")
106
- }
93
+ static createOrPatch(
94
+ name: string,
95
+ args: CreateOrGetDeploymentArgs,
96
+ opts?: ComponentResourceOptions,
97
+ ): Deployment {
98
+ if (!args.existing) {
99
+ return new CreatedDeployment(name, args, opts)
100
+ }
107
101
 
108
- return service
109
- })
102
+ return new DeploymentPatch(
103
+ name,
104
+ {
105
+ ...args,
106
+ name: withPatchName("deployment", args.existing, args.cluster),
107
+ namespace: output(args.existing).metadata.namespace,
108
+ },
109
+ opts,
110
+ )
110
111
  }
111
112
 
112
- /**
113
- * The HTTP route associated with the deployment.
114
- */
115
- get httpRoute(): Output<HttpRoute> {
116
- return this._httpRoute.apply(httpRoute => {
117
- if (!httpRoute) {
118
- throw new Error("The HTTP route is not available.")
119
- }
113
+ static patch(name: string, args: DeploymentArgs, opts?: ComponentResourceOptions): Deployment {
114
+ return new DeploymentPatch(name, args, opts)
115
+ }
120
116
 
121
- return httpRoute
122
- })
117
+ static createOrGet(
118
+ name: string,
119
+ args: CreateOrGetDeploymentArgs,
120
+ opts?: ComponentResourceOptions,
121
+ ): Deployment {
122
+ if (!args.existing) {
123
+ return new CreatedDeployment(name, args, opts)
124
+ }
125
+
126
+ return new ExternalDeployment(name, output(args.existing).metadata, args.cluster, opts)
123
127
  }
128
+ }
124
129
 
125
- /**
126
- * The instance terminal to interact with the deployment.
127
- */
128
- get terminal(): Output<InstanceTerminal> {
129
- return output({
130
- name: this.metadata.name,
131
- title: this.metadata.name,
132
- image: "ghcr.io/exeteres/highstate/terminal-kubectl",
133
- command: ["script", "-q", "-c", "/enter-container.sh", "/dev/null"],
134
- files: {
135
- "/kubeconfig": this.cluster.kubeconfig,
136
-
137
- "/enter-container.sh": {
138
- mode: 0o755,
139
- content: interpolate`
140
- #!/bin/bash
141
-
142
- exec kubectl exec -it -n ${this.metadata.namespace} deployment/${this.metadata.name} -- ${this.args.terminalShell ?? "bash"}
143
- `.apply(trimIndentation),
130
+ class CreatedDeployment extends Deployment {
131
+ constructor(name: string, args: DeploymentArgs, opts?: ComponentResourceOptions) {
132
+ const { labels, podTemplate, networkPolicy, service, httpRoute } =
133
+ getExposableWorkloadComponents(name, args, () => this, opts)
134
+
135
+ const deployment = output({ args, podTemplate }).apply(async ({ args, podTemplate }) => {
136
+ return new apps.v1.Deployment(
137
+ name,
138
+ {
139
+ metadata: mapMetadata(args, name),
140
+ spec: deepmerge(
141
+ {
142
+ template: podTemplate,
143
+ selector: { matchLabels: labels },
144
+ },
145
+ omit(args, exposableWorkloadExtraArgs),
146
+ ) as types.input.apps.v1.DeploymentSpec,
144
147
  },
145
- },
146
- env: {
147
- KUBECONFIG: "/kubeconfig",
148
- },
148
+ {
149
+ ...opts,
150
+ parent: this,
151
+ provider: await getProvider(args.cluster),
152
+ },
153
+ )
149
154
  })
150
- }
151
155
 
152
- static create(name: string, args: DeploymentArgs, opts: ComponentResourceOptions): Deployment {
153
- return new CreatedDeployment(name, args, opts)
156
+ super(
157
+ "highstate:k8s:Deployment",
158
+ name,
159
+ args,
160
+ opts,
161
+
162
+ output(args.cluster),
163
+ deployment.metadata,
164
+ deployment.spec,
165
+ deployment.status,
166
+
167
+ networkPolicy,
168
+ service,
169
+ httpRoute,
170
+ )
154
171
  }
155
172
  }
156
173
 
157
- class CreatedDeployment extends Deployment {
158
- constructor(name: string, args: DeploymentArgs, opts: ComponentResourceOptions) {
159
- const { labels, containers, volumes, service, httpRoute } = getPublicWorkloadComponents(
174
+ class DeploymentPatch extends Deployment {
175
+ constructor(name: string, args: DeploymentArgs, opts?: ComponentResourceOptions) {
176
+ const { podSpec, networkPolicy, service, httpRoute } = getExposableWorkloadComponents(
160
177
  name,
161
178
  args,
162
179
  () => this,
163
180
  opts,
164
181
  )
165
182
 
166
- const deployment = output({ args, containers, volumes }).apply(
167
- async ({ args, containers, volumes }) => {
168
- await verifyProvider(opts.provider, args.cluster.info)
169
-
170
- return new (args.patch ? apps.v1.DeploymentPatch : apps.v1.Deployment)(
171
- name,
172
- {
173
- metadata: mapMetadata(args.patch?.metadata ?? args, name),
174
- spec: deepmerge(
175
- {
176
- template: {
177
- metadata: !args.patch ? { labels } : undefined,
178
- spec: {
179
- containers: containers.map(container => mapContainerToRaw(container, name)),
180
- volumes,
181
- },
182
- },
183
- selector: !args.patch ? { matchLabels: labels } : undefined,
183
+ const deployment = output({ args, podSpec }).apply(async ({ args, podSpec }) => {
184
+ return new apps.v1.DeploymentPatch(
185
+ name,
186
+ {
187
+ metadata: mapMetadata(args, name),
188
+ spec: deepmerge(
189
+ {
190
+ template: {
191
+ spec: podSpec,
184
192
  },
185
- omit(args, publicWorkloadExtraArgs),
186
- ),
187
- },
188
- { parent: this, ...opts },
189
- )
190
- },
191
- )
193
+ },
194
+ omit(args, exposableWorkloadExtraArgs),
195
+ ) as types.input.apps.v1.DeploymentSpec,
196
+ },
197
+ {
198
+ ...opts,
199
+ parent: this,
200
+ provider: await getProvider(args.cluster),
201
+ },
202
+ )
203
+ })
192
204
 
193
205
  super(
194
- "highstate:k8s:Deployment",
206
+ "highstate:k8s:DeploymentPatch",
195
207
  name,
196
208
  args,
197
209
  opts,
@@ -201,10 +213,41 @@ class CreatedDeployment extends Deployment {
201
213
  deployment.spec,
202
214
  deployment.status,
203
215
 
216
+ networkPolicy,
204
217
  service,
205
218
  httpRoute,
219
+ )
220
+ }
221
+ }
222
+
223
+ class ExternalDeployment extends Deployment {
224
+ constructor(
225
+ name: string,
226
+ id: Input<ResourceId>,
227
+ cluster: Input<k8s.Cluster>,
228
+ opts?: ComponentResourceOptions,
229
+ ) {
230
+ const deployment = output(id).apply(async id => {
231
+ return apps.v1.Deployment.get(name, resourceIdToString(id), {
232
+ ...opts,
233
+ parent: this,
234
+ provider: await getProvider(cluster),
235
+ })
236
+ })
237
+
238
+ super(
239
+ "highstate:k8s:ExternalDeployment",
240
+ name,
241
+ { namespace: output(id).namespace, cluster },
242
+ opts,
243
+ output(cluster),
244
+ deployment.metadata,
245
+ deployment.spec,
246
+ deployment.status,
206
247
 
207
- [deployment],
248
+ output(undefined),
249
+ output(undefined),
250
+ output(undefined),
208
251
  )
209
252
  }
210
253
  }
@@ -9,7 +9,7 @@ import {
9
9
  } from "@highstate/pulumi"
10
10
  import { gateway, types } from "@highstate/gateway-api"
11
11
  import { map, pipe } from "remeda"
12
- import { mapMetadata, type CommonArgs } from "../shared"
12
+ import { getProvider, mapMetadata, type CommonArgs } from "../shared"
13
13
  import { resolveBackendRef, type BackendRef } from "./backend"
14
14
 
15
15
  export type HttpRouteArgs = Omit<CommonArgs, "namespace"> & {
@@ -80,7 +80,7 @@ export class HttpRoute extends ComponentResource {
80
80
  this.route = output({
81
81
  args,
82
82
  gatewayNamespace: output(args.gateway).metadata.namespace,
83
- }).apply(({ args, gatewayNamespace }) => {
83
+ }).apply(async ({ args, gatewayNamespace }) => {
84
84
  return new gateway.v1.HTTPRoute(
85
85
  name,
86
86
  {
@@ -114,11 +114,13 @@ export class HttpRoute extends ComponentResource {
114
114
  })),
115
115
  } satisfies types.input.gateway.v1.HTTPRouteSpec,
116
116
  },
117
- { parent: this, ...opts },
117
+ {
118
+ ...opts,
119
+ parent: this,
120
+ provider: await getProvider(args.cluster),
121
+ },
118
122
  )
119
123
  })
120
-
121
- this.registerOutputs({ route: this.route })
122
124
  }
123
125
  }
124
126
 
package/src/helm.ts CHANGED
@@ -2,7 +2,7 @@ import type { k8s } from "@highstate/library"
2
2
  import { resolve } from "node:path"
3
3
  import { mkdir, readFile, unlink } from "node:fs/promises"
4
4
  import { toPromise, type InputMap } from "@highstate/pulumi"
5
- import { core, helm } from "@pulumi/kubernetes"
5
+ import { core, helm, types } from "@pulumi/kubernetes"
6
6
  import {
7
7
  ComponentResource,
8
8
  output,
@@ -16,8 +16,8 @@ import { omit } from "remeda"
16
16
  import { local } from "@pulumi/command"
17
17
  import { glob } from "glob"
18
18
  import { HttpRoute, type HttpRouteArgs } from "./gateway"
19
- import { mapNamespaceLikeToNamespaceName, type NamespaceLike } from "./shared"
20
- import { Service } from "./service"
19
+ import { getProvider, mapNamespaceLikeToNamespaceName, type NamespaceLike } from "./shared"
20
+ import { getServiceType, Service, type ServiceArgs } from "./service"
21
21
 
22
22
  export type ChartArgs = Omit<
23
23
  helm.v4.ChartArgs,
@@ -35,6 +35,13 @@ export type ChartArgs = Omit<
35
35
  */
36
36
  serviceName?: string
37
37
 
38
+ /**
39
+ * The extra args to pass to the main service of the chart.
40
+ *
41
+ * Will be patched via transformations.
42
+ */
43
+ service?: Partial<ServiceArgs>
44
+
38
45
  /**
39
46
  * The manifest of the chart to resolve.
40
47
  */
@@ -69,18 +76,60 @@ export class Chart extends ComponentResource {
69
76
  ) {
70
77
  super("highstate:k8s:Chart", name, args, opts)
71
78
 
72
- this.chart = output(args).apply(args => {
79
+ const namespace = output(args.namespace).apply(namespace =>
80
+ output(namespace ? mapNamespaceLikeToNamespaceName(namespace) : "default"),
81
+ )
82
+
83
+ this.chart = output({ args, namespace }).apply(async ({ args, namespace }) => {
73
84
  return new helm.v4.Chart(
74
85
  name,
75
86
  omit(
76
87
  {
77
88
  ...args,
78
89
  chart: resolveHelmChart(args.chart),
79
- namespace: args.namespace ? mapNamespaceLikeToNamespaceName(args.namespace) : undefined,
90
+ namespace,
80
91
  },
81
92
  ["httpRoute"],
82
93
  ),
83
- { parent: this, ...opts },
94
+ {
95
+ ...opts,
96
+ parent: this,
97
+ provider: await getProvider(args.cluster),
98
+
99
+ transforms: [
100
+ ...(opts?.transforms ?? []),
101
+
102
+ resourceArgs => {
103
+ const serviceName = args.serviceName ?? name
104
+ const expectedName = `${name}:${namespace}/${serviceName}`
105
+
106
+ if (
107
+ resourceArgs.type === "kubernetes:core/v1:Service" &&
108
+ resourceArgs.name === expectedName
109
+ ) {
110
+ const spec = resourceArgs.props.spec as types.input.core.v1.ServiceSpec
111
+
112
+ return {
113
+ props: {
114
+ ...resourceArgs.props,
115
+ spec: {
116
+ ...spec,
117
+ ...(args.service ?? {}),
118
+
119
+ type: getServiceType(args.service, args.cluster),
120
+
121
+ externalIPs:
122
+ args.service?.externalIPs ?? args.cluster.externalIps ?? spec.externalIPs,
123
+ },
124
+ },
125
+ opts: resourceArgs.opts,
126
+ }
127
+ }
128
+
129
+ return undefined
130
+ },
131
+ ],
132
+ },
84
133
  )
85
134
  })
86
135
 
@@ -125,8 +174,8 @@ export class Chart extends ComponentResource {
125
174
  //
126
175
  resolvedName,
127
176
  service,
128
- args.cluster.info,
129
- { parent: this, ...this.opts },
177
+ args.cluster,
178
+ { ...this.opts, parent: this },
130
179
  )
131
180
 
132
181
  this.services.set(resolvedName, wrappedService)
package/src/index.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  export {
2
- getProvider as createProvider,
3
- createNamespace,
4
- getNamespace,
2
+ getProvider,
5
3
  mapMetadata,
6
4
  mapNamespaceLikeToNamespaceName,
7
5
  mapNamespaceNameToSelector,
@@ -14,11 +12,17 @@ export {
14
12
  } from "./shared"
15
13
  export { type DeploymentArgs, Deployment } from "./deployment"
16
14
  export {
17
- type ServiceArgs as ServiceArgs,
15
+ type ServiceArgs,
16
+ type ServiceEndpointMetadata,
18
17
  Service,
19
18
  mapContainerPortToServicePort,
20
19
  mapServiceToLabelSelector,
20
+ hasServiceMetadata,
21
+ getServiceMetadata,
22
+ withServiceMetadata,
23
+ isFromCluster,
21
24
  } from "./service"
25
+ export { type SecretArgs, type CreateOrPatchSecretArgs, Secret } from "./secret"
22
26
  export { type StatefulSetArgs, StatefulSet } from "./stateful-set"
23
27
  export {
24
28
  type NetworkPolicyArgs,
@@ -59,3 +63,6 @@ export {
59
63
  export { type HttpRouteArgs, HttpRoute } from "./gateway"
60
64
  export { type PersistentVolumeClaimArgs, PersistentVolumeClaim } from "./pvc"
61
65
  export { detectExternalIps, createK8sTerminal } from "./cluster"
66
+ export { getBestEndpoint, requireBestEndpoint } from "./network"
67
+ export { Workload, ExposableWorkload } from "./workload"
68
+ export { type NamespaceArgs, type CreateOrPatchNamespaceArgs, Namespace } from "./namespace"
package/src/job.ts CHANGED
@@ -1,21 +1,11 @@
1
1
  import { batch, type types } from "@pulumi/kubernetes"
2
- import {
3
- ComponentResource,
4
- normalize,
5
- Output,
6
- output,
7
- type ComponentResourceOptions,
8
- type Input,
9
- type InputArray,
10
- } from "@highstate/pulumi"
2
+ import { ComponentResource, Output, output, type ComponentResourceOptions } from "@highstate/pulumi"
11
3
  import { mergeDeep, omit } from "remeda"
12
- import { mapContainerToRaw, mapWorkloadVolume, type Container } from "./container"
13
- import { commonExtraArgs, mapMetadata, type CommonArgs } from "./shared"
4
+ import { commonExtraArgs, getProvider, mapMetadata } from "./shared"
5
+ import { getWorkloadComponents, type WorkloadArgs } from "./workload"
14
6
 
15
- export type JobArgs = CommonArgs & {
16
- container?: Input<Container>
17
- containers?: InputArray<Container>
18
- } & Omit<Partial<types.input.batch.v1.JobSpec>, "template"> & {
7
+ export type JobArgs = WorkloadArgs &
8
+ Omit<Partial<types.input.batch.v1.JobSpec>, "template"> & {
19
9
  template?: {
20
10
  metadata?: types.input.meta.v1.ObjectMeta
21
11
  spec?: Partial<types.input.core.v1.PodSpec>
@@ -30,37 +20,29 @@ export class Job extends ComponentResource {
30
20
  */
31
21
  public readonly job: Output<batch.v1.Job>
32
22
 
33
- constructor(name: string, args: JobArgs, opts?: ComponentResourceOptions) {
23
+ constructor(name: string, args: JobArgs, opts: ComponentResourceOptions) {
34
24
  super("highstate:k8s:Job", name, args, opts)
35
25
 
36
- this.job = output(args).apply(args => {
37
- const containers = normalize(args.container, args.containers)
26
+ const { podTemplate } = getWorkloadComponents(name, args, () => this, opts)
38
27
 
28
+ this.job = output({ args, podTemplate }).apply(async ({ args, podTemplate }) => {
39
29
  return new batch.v1.Job(
40
30
  name,
41
31
  {
42
32
  metadata: mapMetadata(args, name),
43
33
  spec: mergeDeep(
44
34
  {
45
- template: {
46
- spec: {
47
- containers: containers.map(container => mapContainerToRaw(container, name)),
48
-
49
- volumes: containers
50
- .flatMap(container => normalize(container.volume, container.volumes))
51
- .map(mapWorkloadVolume),
52
-
53
- restartPolicy: "Never",
54
- },
55
- },
35
+ template: podTemplate,
56
36
  } satisfies types.input.batch.v1.JobSpec,
57
37
  omit(args, jobExtraArgs) as types.input.batch.v1.JobSpec,
58
38
  ),
59
39
  },
60
- { parent: this, ...opts },
40
+ {
41
+ ...opts,
42
+ parent: this,
43
+ provider: await getProvider(args.cluster),
44
+ },
61
45
  )
62
46
  })
63
-
64
- this.registerOutputs({ job: this.job })
65
47
  }
66
48
  }