@highstate/k8s 0.18.0 → 0.20.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.
- package/dist/{chunk-FE4SHRAJ.js → chunk-23X5SXQG.js} +22 -7
- package/dist/chunk-23X5SXQG.js.map +1 -0
- package/dist/{chunk-LGHFSXNT.js → chunk-ADHZK6V2.js} +14 -10
- package/dist/chunk-ADHZK6V2.js.map +1 -0
- package/dist/{chunk-VCXWCZ43.js → chunk-BTAEFJ5N.js} +27 -15
- package/dist/chunk-BTAEFJ5N.js.map +1 -0
- package/dist/{chunk-BR2CLUUD.js → chunk-IXE3OKB4.js} +27 -8
- package/dist/chunk-IXE3OKB4.js.map +1 -0
- package/dist/{chunk-TWBMG6TD.js → chunk-OG2OPX7B.js} +30 -12
- package/dist/chunk-OG2OPX7B.js.map +1 -0
- package/dist/{chunk-DCUMJSO6.js → chunk-P26SQ2ZB.js} +17 -51
- package/dist/chunk-P26SQ2ZB.js.map +1 -0
- package/dist/{chunk-MIC2BHGS.js → chunk-PG27ZY2H.js} +25 -7
- package/dist/chunk-PG27ZY2H.js.map +1 -0
- package/dist/chunk-PZYGZSN5.js +54 -0
- package/dist/{chunk-PZ5AY32C.js.map → chunk-PZYGZSN5.js.map} +1 -1
- package/dist/{chunk-YIJUVPU2.js → chunk-S77TE7UC.js} +27 -15
- package/dist/chunk-S77TE7UC.js.map +1 -0
- package/dist/{chunk-P2VOUU7E.js → chunk-SZKOAHNX.js} +383 -205
- package/dist/chunk-SZKOAHNX.js.map +1 -0
- package/dist/chunk-TOLFVF4S.js +889 -0
- package/dist/chunk-TOLFVF4S.js.map +1 -0
- package/dist/{chunk-RVB4WWZZ.js → chunk-TVKT3ZYX.js} +174 -18
- package/dist/chunk-TVKT3ZYX.js.map +1 -0
- package/dist/cron-job-RKB2HYTO.js +7 -0
- package/dist/{cron-job-NX4HD4FI.js.map → cron-job-RKB2HYTO.js.map} +1 -1
- package/dist/deployment-T35TUOL2.js +7 -0
- package/dist/{deployment-O2LJ5WR5.js.map → deployment-T35TUOL2.js.map} +1 -1
- package/dist/highstate.manifest.json +3 -2
- package/dist/impl/dynamic-endpoint-resolver.js +90 -0
- package/dist/impl/dynamic-endpoint-resolver.js.map +1 -0
- package/dist/impl/gateway-route.js +159 -62
- package/dist/impl/gateway-route.js.map +1 -1
- package/dist/impl/tls-certificate.js +6 -5
- package/dist/impl/tls-certificate.js.map +1 -1
- package/dist/index.js +106 -23
- package/dist/index.js.map +1 -1
- package/dist/job-PE4AKOHB.js +7 -0
- package/dist/job-PE4AKOHB.js.map +1 -0
- package/dist/stateful-set-LUIRHQJY.js +7 -0
- package/dist/{stateful-set-VJYKTQ72.js.map → stateful-set-LUIRHQJY.js.map} +1 -1
- package/dist/units/cert-manager/index.js +7 -8
- package/dist/units/cert-manager/index.js.map +1 -1
- package/dist/units/cluster-patch/index.js +6 -6
- package/dist/units/cluster-patch/index.js.map +1 -1
- package/dist/units/dns01-issuer/index.js +52 -15
- package/dist/units/dns01-issuer/index.js.map +1 -1
- package/dist/units/existing-cluster/index.js +39 -18
- package/dist/units/existing-cluster/index.js.map +1 -1
- package/dist/units/gateway-api/index.js +2 -2
- package/dist/units/reduced-access-cluster/index.js +8 -8
- package/dist/units/reduced-access-cluster/index.js.map +1 -1
- package/package.json +9 -7
- package/src/cluster.ts +12 -8
- package/src/config-map.ts +15 -5
- package/src/container.ts +4 -2
- package/src/cron-job.ts +25 -4
- package/src/deployment.ts +32 -17
- package/src/gateway/backend.ts +3 -3
- package/src/gateway/gateway.ts +12 -56
- package/src/helm.ts +354 -22
- package/src/impl/dynamic-endpoint-resolver.ts +109 -0
- package/src/impl/gateway-route.ts +231 -57
- package/src/impl/tls-certificate.ts +8 -3
- package/src/index.ts +1 -0
- package/src/job.ts +23 -5
- package/src/kubectl.ts +166 -0
- package/src/namespace.ts +47 -3
- package/src/network-policy.ts +1 -1
- package/src/pvc.ts +12 -2
- package/src/rbac.ts +28 -5
- package/src/scripting/environment.ts +3 -2
- package/src/secret.ts +15 -5
- package/src/service.ts +28 -6
- package/src/shared.ts +30 -2
- package/src/stateful-set.ts +32 -17
- package/src/tls.ts +31 -5
- package/src/units/cluster-patch/index.ts +5 -5
- package/src/units/dns01-issuer/index.ts +56 -12
- package/src/units/existing-cluster/index.ts +36 -15
- package/src/units/reduced-access-cluster/index.ts +6 -3
- package/src/worker.ts +4 -2
- package/src/workload.ts +453 -213
- package/dist/chunk-4G6LLC2X.js +0 -240
- package/dist/chunk-4G6LLC2X.js.map +0 -1
- package/dist/chunk-BR2CLUUD.js.map +0 -1
- package/dist/chunk-DCUMJSO6.js.map +0 -1
- package/dist/chunk-FE4SHRAJ.js.map +0 -1
- package/dist/chunk-KMLRI5UZ.js +0 -155
- package/dist/chunk-KMLRI5UZ.js.map +0 -1
- package/dist/chunk-LGHFSXNT.js.map +0 -1
- package/dist/chunk-MIC2BHGS.js.map +0 -1
- package/dist/chunk-OBDQONMV.js +0 -401
- package/dist/chunk-OBDQONMV.js.map +0 -1
- package/dist/chunk-P2VOUU7E.js.map +0 -1
- package/dist/chunk-PZ5AY32C.js +0 -9
- package/dist/chunk-RVB4WWZZ.js.map +0 -1
- package/dist/chunk-TWBMG6TD.js.map +0 -1
- package/dist/chunk-VCXWCZ43.js.map +0 -1
- package/dist/chunk-YIJUVPU2.js.map +0 -1
- package/dist/cron-job-NX4HD4FI.js +0 -8
- package/dist/deployment-O2LJ5WR5.js +0 -8
- package/dist/job-SYME6Y43.js +0 -8
- package/dist/job-SYME6Y43.js.map +0 -1
- package/dist/stateful-set-VJYKTQ72.js +0 -8
package/src/workload.ts
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import type { k8s, network } from "@highstate/library"
|
|
2
2
|
import type { types } from "@pulumi/kubernetes"
|
|
3
|
-
import type { Except } from "type-fest"
|
|
3
|
+
import type { DistributedOmit, Except } from "type-fest"
|
|
4
4
|
import type { DeploymentArgs } from "./deployment"
|
|
5
5
|
import type { JobArgs } from "./job"
|
|
6
6
|
import type { StatefulSetArgs } from "./stateful-set"
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
AccessPointRoute,
|
|
9
|
+
type AccessPointRouteArgs,
|
|
10
|
+
type GatewayHttpRuleArgs,
|
|
11
|
+
type GatewayRuleArgs,
|
|
12
|
+
mergeEndpoints,
|
|
13
|
+
} from "@highstate/common"
|
|
8
14
|
import { type TerminalSpec, trimIndentation, type UnitTerminal } from "@highstate/contract"
|
|
9
15
|
import {
|
|
10
16
|
type ComponentResourceOptions,
|
|
11
17
|
type DeepInput,
|
|
12
|
-
fileFromString,
|
|
13
18
|
type InputArray,
|
|
19
|
+
type InputRecord,
|
|
20
|
+
makeFileOutput,
|
|
14
21
|
normalize,
|
|
15
22
|
normalizeInputs,
|
|
23
|
+
toPromise,
|
|
16
24
|
} from "@highstate/pulumi"
|
|
17
25
|
import {
|
|
18
26
|
type ComponentResource,
|
|
@@ -26,7 +34,7 @@ import {
|
|
|
26
34
|
} from "@pulumi/pulumi"
|
|
27
35
|
import { sha256 } from "crypto-hash"
|
|
28
36
|
import { deepmerge } from "deepmerge-ts"
|
|
29
|
-
import { filter, flat, isNonNullish, unique, uniqueBy } from "remeda"
|
|
37
|
+
import { filter, flat, isNonNullish, omit, unique, uniqueBy } from "remeda"
|
|
30
38
|
import {
|
|
31
39
|
type Container,
|
|
32
40
|
getFallbackContainerName,
|
|
@@ -39,7 +47,14 @@ import { Namespace } from "./namespace"
|
|
|
39
47
|
import { NetworkPolicy, type NetworkPolicyArgs } from "./network-policy"
|
|
40
48
|
import { podSpecDefaults } from "./pod"
|
|
41
49
|
import { mapContainerPortToServicePort, Service, type ServiceArgs } from "./service"
|
|
42
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
commonExtraArgs,
|
|
52
|
+
getClusterKubeconfigContent,
|
|
53
|
+
images,
|
|
54
|
+
NamespacedResource,
|
|
55
|
+
type ScopedResourceArgs,
|
|
56
|
+
type SelectorLike,
|
|
57
|
+
} from "./shared"
|
|
43
58
|
|
|
44
59
|
export type WorkloadTerminalArgs = {
|
|
45
60
|
/**
|
|
@@ -84,31 +99,150 @@ export type WorkloadArgs = ScopedResourceArgs & {
|
|
|
84
99
|
|
|
85
100
|
export const workloadExtraArgs = [...commonExtraArgs, "container", "containers"] as const
|
|
86
101
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Filters pod template containers for patch operations to include only containers owned by the patch args.
|
|
104
|
+
*
|
|
105
|
+
* This prevents patching containers from existing workload spec that are not declared via workload container args.
|
|
106
|
+
*
|
|
107
|
+
* @param template The merged pod template that will be sent to Kubernetes.
|
|
108
|
+
* @param ownedTemplate The pod template generated from workload container args.
|
|
109
|
+
* @returns The pod template with filtered container lists.
|
|
110
|
+
*/
|
|
111
|
+
export function filterPatchOwnedContainersInTemplate(
|
|
112
|
+
template: Unwrap<types.input.core.v1.PodTemplateSpec>,
|
|
113
|
+
ownedTemplate: Unwrap<types.input.core.v1.PodTemplateSpec>,
|
|
114
|
+
): Unwrap<types.input.core.v1.PodTemplateSpec> {
|
|
115
|
+
const ownedContainerNames = unique(
|
|
116
|
+
(ownedTemplate.spec?.containers ?? []).map(container => container.name).filter(isNonNullish),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
const ownedInitContainerNames = unique(
|
|
120
|
+
(ownedTemplate.spec?.initContainers ?? [])
|
|
121
|
+
.map(container => container.name)
|
|
122
|
+
.filter(isNonNullish),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
const filterByOwnedNames = <TContainer extends { name?: string }>(
|
|
126
|
+
source: TContainer[] | undefined,
|
|
127
|
+
ownedNames: string[],
|
|
128
|
+
): TContainer[] | undefined => {
|
|
129
|
+
if (!source || source.length === 0 || ownedNames.length === 0) {
|
|
130
|
+
return undefined
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const filtered = source.filter(container =>
|
|
134
|
+
container.name ? ownedNames.includes(container.name) : false,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return filtered.length > 0 ? filtered : undefined
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const containers = filterByOwnedNames(template.spec?.containers, ownedContainerNames)
|
|
141
|
+
const initContainers = filterByOwnedNames(template.spec?.initContainers, ownedInitContainerNames)
|
|
142
|
+
|
|
143
|
+
const {
|
|
144
|
+
containers: _containers,
|
|
145
|
+
initContainers: _initContainers,
|
|
146
|
+
...restSpec
|
|
147
|
+
} = template.spec ?? {}
|
|
148
|
+
|
|
149
|
+
const spec = {
|
|
150
|
+
...restSpec,
|
|
151
|
+
...(containers ? { containers } : {}),
|
|
152
|
+
...(initContainers ? { initContainers } : {}),
|
|
153
|
+
} as Partial<Unwrap<types.input.core.v1.PodSpec>>
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
...template,
|
|
157
|
+
spec: spec as Unwrap<types.input.core.v1.PodSpec>,
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
type WorkloadHttpGatewayRuleArgs = DistributedOmit<GatewayHttpRuleArgs, "backend" | "backends"> & {
|
|
162
|
+
/**
|
|
163
|
+
* The service port to route to.
|
|
164
|
+
*
|
|
165
|
+
* Can be either a numeric port or a named port from the workload service.
|
|
166
|
+
*
|
|
167
|
+
* If not specified, it first falls back to the servicePort of the route,
|
|
168
|
+
* then to the first port of the workload service.
|
|
169
|
+
*/
|
|
170
|
+
servicePort?: Input<number | string>
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
type WorkloadTcpUdpGatewayRuleArgs = DistributedOmit<GatewayRuleArgs, "backend" | "backends"> & {
|
|
174
|
+
/**
|
|
175
|
+
* The service port to route to.
|
|
176
|
+
*
|
|
177
|
+
* Can be either a numeric port or a named port from the workload service.
|
|
178
|
+
*
|
|
179
|
+
* If not specified, it first falls back to the servicePort of the route,
|
|
180
|
+
* then to the first port of the workload service.
|
|
181
|
+
*/
|
|
182
|
+
servicePort?: Input<number | string>
|
|
183
|
+
}
|
|
91
184
|
|
|
92
|
-
|
|
185
|
+
type WorkloadGatewayRuleArgs = WorkloadHttpGatewayRuleArgs | WorkloadTcpUdpGatewayRuleArgs
|
|
186
|
+
|
|
187
|
+
export type WorkloadRouteArgs = Except<AccessPointRouteArgs, "backend" | "backends" | "rules"> & {
|
|
188
|
+
/**
|
|
189
|
+
* The service port to route to by default.
|
|
190
|
+
*
|
|
191
|
+
* Can be either a numeric port or a named port from the workload service.
|
|
192
|
+
*
|
|
193
|
+
* Can be overridden by `rules.*.servicePort`.
|
|
194
|
+
* If omitted, the first port of the workload service is used.
|
|
195
|
+
*/
|
|
196
|
+
servicePort?: Input<number | string>
|
|
197
|
+
} & (
|
|
198
|
+
| {
|
|
199
|
+
type: "http"
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The path to match for the `default` rule of the listener.
|
|
203
|
+
*/
|
|
204
|
+
path?: Input<string>
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* The paths to match for the `default` rule of the listener.
|
|
208
|
+
*/
|
|
209
|
+
paths?: Input<string[]>
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The rules of the route.
|
|
213
|
+
*/
|
|
214
|
+
rules?: InputRecord<WorkloadHttpGatewayRuleArgs>
|
|
215
|
+
}
|
|
216
|
+
| {
|
|
217
|
+
type: "tcp" | "udp"
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The rules of the route.
|
|
221
|
+
*/
|
|
222
|
+
rules?: InputRecord<WorkloadTcpUdpGatewayRuleArgs>
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
export type WorkloadServiceArgs = WorkloadArgs & {
|
|
93
227
|
service?: Input<Omit<ServiceArgs, "cluster" | "namespace">>
|
|
94
228
|
|
|
95
229
|
/**
|
|
96
230
|
* The configuration for the access point route to create.
|
|
97
231
|
*/
|
|
98
|
-
route?: Input<
|
|
232
|
+
route?: Input<WorkloadRouteArgs>
|
|
99
233
|
|
|
100
234
|
/**
|
|
101
235
|
* The configuration for the access point routes to create.
|
|
102
236
|
*/
|
|
103
|
-
routes?: InputArray<
|
|
237
|
+
routes?: InputArray<WorkloadRouteArgs>
|
|
104
238
|
|
|
105
239
|
/**
|
|
106
240
|
* The existing workload to patch.
|
|
107
241
|
*/
|
|
108
|
-
existing?: Input<k8s.
|
|
242
|
+
existing?: Input<k8s.Workload>
|
|
109
243
|
}
|
|
110
244
|
|
|
111
|
-
export const
|
|
245
|
+
export const workloadServiceExtraArgs = [
|
|
112
246
|
...workloadExtraArgs,
|
|
113
247
|
"service",
|
|
114
248
|
"route",
|
|
@@ -116,9 +250,8 @@ export const exposableWorkloadExtraArgs = [
|
|
|
116
250
|
] as const
|
|
117
251
|
|
|
118
252
|
export type WorkloadType = "Deployment" | "StatefulSet" | "Job" | "CronJob"
|
|
119
|
-
export type ExposableWorkloadType = "Deployment" | "StatefulSet"
|
|
120
253
|
|
|
121
|
-
export type GenericWorkloadArgs = Omit<
|
|
254
|
+
export type GenericWorkloadArgs = Omit<WorkloadServiceArgs, "existing"> & {
|
|
122
255
|
/**
|
|
123
256
|
* The type of workload to create.
|
|
124
257
|
*
|
|
@@ -136,14 +269,14 @@ export type GenericWorkloadArgs = Omit<ExposableWorkloadArgs, "existing"> & {
|
|
|
136
269
|
*
|
|
137
270
|
* Will be ignored for other workload types.
|
|
138
271
|
*/
|
|
139
|
-
deployment?: Input<DeploymentArgs
|
|
272
|
+
deployment?: Input<Omit<DeploymentArgs, "name" | "namespace">>
|
|
140
273
|
|
|
141
274
|
/**
|
|
142
275
|
* The args specific to the "StatefulSet" workload type.
|
|
143
276
|
*
|
|
144
277
|
* Will be ignored for other workload types.
|
|
145
278
|
*/
|
|
146
|
-
statefulSet?: Input<StatefulSetArgs
|
|
279
|
+
statefulSet?: Input<Omit<StatefulSetArgs, "name" | "namespace">>
|
|
147
280
|
|
|
148
281
|
/**
|
|
149
282
|
* The args specific to the "Job" workload type.
|
|
@@ -160,34 +293,6 @@ export type GenericWorkloadArgs = Omit<ExposableWorkloadArgs, "existing"> & {
|
|
|
160
293
|
cronJob?: Input<JobArgs>
|
|
161
294
|
}
|
|
162
295
|
|
|
163
|
-
export type GenericExposableWorkloadArgs = Omit<ExposableWorkloadArgs, "existing"> & {
|
|
164
|
-
/**
|
|
165
|
-
* The type of workload to create.
|
|
166
|
-
*
|
|
167
|
-
* Will be ignored if the `existing` argument is provided.
|
|
168
|
-
*/
|
|
169
|
-
defaultType: ExposableWorkloadType
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* The existing workload to patch.
|
|
173
|
-
*/
|
|
174
|
-
existing: Input<k8s.ExposableWorkload | undefined>
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* The args specific to the "Deployment" workload type.
|
|
178
|
-
*
|
|
179
|
-
* Will be ignored for other workload types.
|
|
180
|
-
*/
|
|
181
|
-
deployment?: Input<DeploymentArgs>
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* The args specific to the "StatefulSet" workload type.
|
|
185
|
-
*
|
|
186
|
-
* Will be ignored for other workload types.
|
|
187
|
-
*/
|
|
188
|
-
statefulSet?: Input<StatefulSetArgs>
|
|
189
|
-
}
|
|
190
|
-
|
|
191
296
|
export function getWorkloadComponents(
|
|
192
297
|
name: string,
|
|
193
298
|
args: WorkloadArgs,
|
|
@@ -315,9 +420,9 @@ export function getWorkloadComponents(
|
|
|
315
420
|
return { labels, containers, volumes, podSpec, podTemplate, networkPolicy }
|
|
316
421
|
}
|
|
317
422
|
|
|
318
|
-
export function
|
|
423
|
+
export function getWorkloadServiceComponents(
|
|
319
424
|
name: string,
|
|
320
|
-
args:
|
|
425
|
+
args: WorkloadServiceArgs,
|
|
321
426
|
parent: () => ComponentResource,
|
|
322
427
|
opts: ComponentResourceOptions | undefined,
|
|
323
428
|
isForPatch?: boolean,
|
|
@@ -361,7 +466,7 @@ export function getExposableWorkloadComponents(
|
|
|
361
466
|
routesArgs: normalizeInputs(args.route, args.routes),
|
|
362
467
|
service,
|
|
363
468
|
namespace: output(args.namespace),
|
|
364
|
-
}).apply(({ routesArgs, service, namespace }) => {
|
|
469
|
+
}).apply(async ({ routesArgs, service, namespace }) => {
|
|
365
470
|
if (!routesArgs.length || !service) {
|
|
366
471
|
return []
|
|
367
472
|
}
|
|
@@ -370,16 +475,114 @@ export function getExposableWorkloadComponents(
|
|
|
370
475
|
return []
|
|
371
476
|
}
|
|
372
477
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
...routeArgs,
|
|
376
|
-
endpoints: service.endpoints,
|
|
478
|
+
const serviceEndpoints = await toPromise(service.endpoints)
|
|
479
|
+
const servicePorts = await toPromise(service.spec.ports)
|
|
377
480
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
481
|
+
const resolveServiceEndpoints = async (
|
|
482
|
+
servicePort: Input<number | string> | undefined,
|
|
483
|
+
routeName: string,
|
|
484
|
+
): Promise<network.L4Endpoint[]> => {
|
|
485
|
+
if (serviceEndpoints.length === 0) {
|
|
486
|
+
throw new Error(`No endpoints found for workload service in route "${routeName}"`)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
let resolvedServicePort: number | undefined
|
|
490
|
+
|
|
491
|
+
if (servicePort != null) {
|
|
492
|
+
const requestedServicePort = await toPromise(servicePort)
|
|
493
|
+
|
|
494
|
+
if (typeof requestedServicePort === "string") {
|
|
495
|
+
const namedPort = servicePorts?.find(port => port.name === requestedServicePort)
|
|
496
|
+
|
|
497
|
+
if (!namedPort) {
|
|
498
|
+
throw new Error(
|
|
499
|
+
`Named port "${requestedServicePort}" not found for workload service in route "${routeName}"`,
|
|
500
|
+
)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
resolvedServicePort = namedPort.port
|
|
504
|
+
} else {
|
|
505
|
+
resolvedServicePort = requestedServicePort
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
resolvedServicePort = serviceEndpoints[0]?.port
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (resolvedServicePort == null) {
|
|
512
|
+
throw new Error(
|
|
513
|
+
`Unable to resolve service port for workload service in route "${routeName}"`,
|
|
514
|
+
)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const filteredEndpoints = serviceEndpoints.filter(
|
|
518
|
+
endpoint => endpoint.port === resolvedServicePort,
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
if (filteredEndpoints.length === 0) {
|
|
522
|
+
throw new Error(
|
|
523
|
+
`No endpoints with port ${resolvedServicePort} found for workload service in route "${routeName}"`,
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return filteredEndpoints
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return await Promise.all(
|
|
531
|
+
routesArgs.map(async (routeArgs, index) => {
|
|
532
|
+
const routeName = `${name}.${index}`
|
|
533
|
+
const routeRules = (await toPromise(routeArgs.rules)) as
|
|
534
|
+
| Record<string, WorkloadGatewayRuleArgs>
|
|
535
|
+
| undefined
|
|
536
|
+
const routeRuleValues = Object.values(routeRules ?? {})
|
|
537
|
+
const needsDefaultBackend =
|
|
538
|
+
routeRuleValues.length === 0 || routeRuleValues.some(rule => rule.servicePort == null)
|
|
539
|
+
|
|
540
|
+
const defaultServiceEndpoints = needsDefaultBackend
|
|
541
|
+
? await resolveServiceEndpoints(routeArgs.servicePort, routeName)
|
|
542
|
+
: undefined
|
|
543
|
+
|
|
544
|
+
const resolvedRules = routeRules
|
|
545
|
+
? await Promise.all(
|
|
546
|
+
Object.entries(routeRules).map(async ([ruleName, rule]) => {
|
|
547
|
+
const ruleServiceEndpoints = await resolveServiceEndpoints(
|
|
548
|
+
rule.servicePort ?? routeArgs.servicePort,
|
|
549
|
+
`${routeName}:${ruleName}`,
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
return [
|
|
553
|
+
ruleName,
|
|
554
|
+
{
|
|
555
|
+
...omit(rule, ["servicePort"]),
|
|
556
|
+
backend: {
|
|
557
|
+
endpoints: ruleServiceEndpoints,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
] as const
|
|
561
|
+
}),
|
|
562
|
+
)
|
|
563
|
+
: undefined
|
|
564
|
+
|
|
565
|
+
const resolvedRulesInput = resolvedRules
|
|
566
|
+
? (Object.fromEntries(resolvedRules) as unknown as InputRecord<GatewayRuleArgs>)
|
|
567
|
+
: undefined
|
|
568
|
+
|
|
569
|
+
return new AccessPointRoute(routeName, {
|
|
570
|
+
...omit(routeArgs, ["servicePort", "rules"]),
|
|
571
|
+
...(defaultServiceEndpoints
|
|
572
|
+
? {
|
|
573
|
+
backend: {
|
|
574
|
+
endpoints: defaultServiceEndpoints,
|
|
575
|
+
},
|
|
576
|
+
}
|
|
577
|
+
: {}),
|
|
578
|
+
rules: resolvedRulesInput,
|
|
579
|
+
metadata: {
|
|
580
|
+
...(routeArgs.metadata ?? {}),
|
|
581
|
+
"k8s.namespace": namespace,
|
|
582
|
+
},
|
|
583
|
+
})
|
|
584
|
+
}),
|
|
585
|
+
)
|
|
383
586
|
})
|
|
384
587
|
|
|
385
588
|
return { labels, containers, volumes, podSpec, podTemplate, networkPolicy, service, routes }
|
|
@@ -409,17 +612,81 @@ export abstract class Workload extends NamespacedResource {
|
|
|
409
612
|
* Will be created if one or more containers have `allowedEndpoints` defined.
|
|
410
613
|
*/
|
|
411
614
|
readonly networkPolicy: Output<NetworkPolicy | undefined>,
|
|
615
|
+
|
|
616
|
+
protected readonly _service: Output<Service | undefined> = output(undefined),
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* The access point routes associated with the workload.
|
|
620
|
+
*/
|
|
621
|
+
readonly routes: Output<AccessPointRoute[]> = output([]),
|
|
412
622
|
) {
|
|
413
623
|
super(type, name, args, opts, metadata, namespace)
|
|
414
624
|
}
|
|
415
625
|
|
|
626
|
+
abstract get entity(): Output<k8s.Workload>
|
|
627
|
+
|
|
416
628
|
protected abstract get templateMetadata(): Output<types.output.meta.v1.ObjectMeta>
|
|
417
629
|
|
|
418
630
|
protected abstract getTerminalMeta(): Output<UnitTerminal["meta"]>
|
|
419
631
|
|
|
420
|
-
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: for pulumi which for some reason tries to copy all properties
|
|
421
632
|
private set terminal(_value: never) {}
|
|
422
633
|
|
|
634
|
+
private set logsTerminal(_value: never) {}
|
|
635
|
+
|
|
636
|
+
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: for pulumi which for some reason tries to copy all properties
|
|
637
|
+
private set terminals(_value: never) {}
|
|
638
|
+
|
|
639
|
+
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: for pulumi which for some reason tries to copy all properties
|
|
640
|
+
private set optionalService(_value: never) {}
|
|
641
|
+
|
|
642
|
+
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: for pulumi which for some reason tries to copy all properties
|
|
643
|
+
private set service(_value: never) {}
|
|
644
|
+
|
|
645
|
+
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: for pulumi which for some reason tries to copy all properties
|
|
646
|
+
private set selector(_value: never) {}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* The service associated with the workload.
|
|
650
|
+
*/
|
|
651
|
+
get optionalService(): Output<Service | undefined> {
|
|
652
|
+
return this._service
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* The service associated with the workload.
|
|
657
|
+
*
|
|
658
|
+
* Will throw an error if the service is not available.
|
|
659
|
+
*/
|
|
660
|
+
get service(): Output<Service> {
|
|
661
|
+
return this._service.apply(service => {
|
|
662
|
+
if (!service) {
|
|
663
|
+
throw new Error(`The service of the workload "${this.name}" is not available.`)
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return service
|
|
667
|
+
})
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* The merged and deduplicated L3 endpoints of all routes.
|
|
672
|
+
*/
|
|
673
|
+
get endpoints(): Output<network.L3Endpoint[]> {
|
|
674
|
+
return this.routes.apply(routes =>
|
|
675
|
+
output(routes.map(route => route.route.endpoints))
|
|
676
|
+
.apply(endpoints => flat(endpoints))
|
|
677
|
+
.apply(mergeEndpoints),
|
|
678
|
+
)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* The selector matching pods created from this workload's template labels.
|
|
683
|
+
*/
|
|
684
|
+
get selector(): Output<SelectorLike> {
|
|
685
|
+
return this.podTemplate.apply(template => ({
|
|
686
|
+
matchLabels: template.metadata?.labels,
|
|
687
|
+
}))
|
|
688
|
+
}
|
|
689
|
+
|
|
423
690
|
/**
|
|
424
691
|
* The instance terminal to interact with the workload's pods.
|
|
425
692
|
*/
|
|
@@ -445,11 +712,15 @@ export abstract class Workload extends NamespacedResource {
|
|
|
445
712
|
command: ["bash", "/welcome.sh"],
|
|
446
713
|
|
|
447
714
|
files: {
|
|
448
|
-
"/kubeconfig":
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
715
|
+
"/kubeconfig": makeFileOutput({
|
|
716
|
+
name: "kubeconfig",
|
|
717
|
+
content: getClusterKubeconfigContent(this.cluster),
|
|
718
|
+
isSecret: true,
|
|
719
|
+
}),
|
|
720
|
+
|
|
721
|
+
"/welcome.sh": makeFileOutput({
|
|
722
|
+
name: "welcome.sh",
|
|
723
|
+
content: interpolate`
|
|
453
724
|
#!/bin/bash
|
|
454
725
|
set -euo pipefail
|
|
455
726
|
|
|
@@ -494,7 +765,7 @@ export abstract class Workload extends NamespacedResource {
|
|
|
494
765
|
# execute into the selected pod
|
|
495
766
|
exec kubectl exec -it -n "$NAMESPACE" "$SELECTED_POD" -c "$CONTAINER_NAME" -- "$SHELL"
|
|
496
767
|
`.apply(trimIndentation),
|
|
497
|
-
),
|
|
768
|
+
}),
|
|
498
769
|
},
|
|
499
770
|
|
|
500
771
|
env: {
|
|
@@ -504,6 +775,104 @@ export abstract class Workload extends NamespacedResource {
|
|
|
504
775
|
})
|
|
505
776
|
}
|
|
506
777
|
|
|
778
|
+
/**
|
|
779
|
+
* The instance terminal to view the workload's logs.
|
|
780
|
+
*/
|
|
781
|
+
get logsTerminal(): Output<UnitTerminal> {
|
|
782
|
+
const containerName = this.podTemplate.spec.containers.apply(containers => containers[0].name)
|
|
783
|
+
|
|
784
|
+
const podLabelSelector = this.templateMetadata
|
|
785
|
+
.apply(meta => meta.labels ?? {})
|
|
786
|
+
.apply(labels =>
|
|
787
|
+
Object.entries(labels)
|
|
788
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
789
|
+
.join(","),
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
return output({
|
|
793
|
+
name: interpolate`${this.metadata.name}.logs`,
|
|
794
|
+
|
|
795
|
+
meta: output(this.getTerminalMeta()).apply(meta => ({
|
|
796
|
+
...meta,
|
|
797
|
+
title: `${meta.title} Logs`,
|
|
798
|
+
globalTitle: `${meta.globalTitle} | Logs`,
|
|
799
|
+
description: `The logs of ${meta.title.toLowerCase()}.`,
|
|
800
|
+
})),
|
|
801
|
+
|
|
802
|
+
spec: {
|
|
803
|
+
image: images["terminal-kubectl"].image,
|
|
804
|
+
command: ["bash", "/welcome.sh"],
|
|
805
|
+
|
|
806
|
+
files: {
|
|
807
|
+
"/kubeconfig": makeFileOutput({
|
|
808
|
+
name: "kubeconfig",
|
|
809
|
+
content: getClusterKubeconfigContent(this.cluster),
|
|
810
|
+
isSecret: true,
|
|
811
|
+
}),
|
|
812
|
+
|
|
813
|
+
"/welcome.sh": makeFileOutput({
|
|
814
|
+
name: "welcome.sh",
|
|
815
|
+
content: interpolate`
|
|
816
|
+
#!/bin/bash
|
|
817
|
+
set -euo pipefail
|
|
818
|
+
|
|
819
|
+
NAMESPACE="${this.metadata.namespace}"
|
|
820
|
+
RESOURCE_TYPE="${this.kind.toLowerCase()}"
|
|
821
|
+
RESOURCE_NAME="${this.metadata.name}"
|
|
822
|
+
CONTAINER_NAME="${containerName}"
|
|
823
|
+
LABEL_SELECTOR="${podLabelSelector}"
|
|
824
|
+
|
|
825
|
+
echo "Connecting to logs of $RESOURCE_TYPE \"$RESOURCE_NAME\" in namespace \"$NAMESPACE\""
|
|
826
|
+
|
|
827
|
+
# get all pods for this workload
|
|
828
|
+
PODS=$(kubectl get pods -n "$NAMESPACE" -l "$LABEL_SELECTOR" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || echo "")
|
|
829
|
+
|
|
830
|
+
if [ -z "$PODS" ]; then
|
|
831
|
+
echo "No pods found"
|
|
832
|
+
exit 1
|
|
833
|
+
fi
|
|
834
|
+
|
|
835
|
+
# convert space-separated string to array
|
|
836
|
+
read -ra POD_ARRAY <<< "$PODS"
|
|
837
|
+
|
|
838
|
+
if [ \${#POD_ARRAY[@]} -eq 1 ]; then
|
|
839
|
+
# single pod found, connect directly
|
|
840
|
+
SELECTED_POD="\${POD_ARRAY[0]}"
|
|
841
|
+
echo "Found single pod: $SELECTED_POD"
|
|
842
|
+
else
|
|
843
|
+
# multiple pods found, use fzf for selection
|
|
844
|
+
echo "Found \${#POD_ARRAY[@]} pods. Please select one."
|
|
845
|
+
|
|
846
|
+
SELECTED_POD=$(printf '%s\n' "\${POD_ARRAY[@]}" | fzf --prompt="Select pod: " --height 10 --border --info=inline)
|
|
847
|
+
|
|
848
|
+
if [ -z "$SELECTED_POD" ]; then
|
|
849
|
+
echo "No pod selected"
|
|
850
|
+
exit 1
|
|
851
|
+
fi
|
|
852
|
+
|
|
853
|
+
echo "Selected pod: $SELECTED_POD"
|
|
854
|
+
fi
|
|
855
|
+
|
|
856
|
+
# stream logs for the selected pod
|
|
857
|
+
exec kubectl logs -f -n "$NAMESPACE" "$SELECTED_POD" -c "$CONTAINER_NAME"
|
|
858
|
+
`.apply(trimIndentation),
|
|
859
|
+
}),
|
|
860
|
+
},
|
|
861
|
+
|
|
862
|
+
env: {
|
|
863
|
+
KUBECONFIG: "/kubeconfig",
|
|
864
|
+
},
|
|
865
|
+
},
|
|
866
|
+
})
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* The instance terminals to interact with the workload's pods and view its logs.
|
|
871
|
+
*/
|
|
872
|
+
get terminals(): Output<UnitTerminal>[] {
|
|
873
|
+
return [this.logsTerminal, this.terminal]
|
|
874
|
+
}
|
|
875
|
+
|
|
507
876
|
/**
|
|
508
877
|
* Creates a terminal with a custom command.
|
|
509
878
|
*
|
|
@@ -517,9 +886,7 @@ export abstract class Workload extends NamespacedResource {
|
|
|
517
886
|
command: InputArray<string>,
|
|
518
887
|
spec?: { env?: DeepInput<TerminalSpec["env"]>; files?: DeepInput<TerminalSpec["files"]> },
|
|
519
888
|
): Output<UnitTerminal> {
|
|
520
|
-
const containerName =
|
|
521
|
-
return containers[0]?.name ?? this.name
|
|
522
|
-
})
|
|
889
|
+
const containerName = this.podTemplate.spec.containers.apply(containers => containers[0].name)
|
|
523
890
|
|
|
524
891
|
return output({
|
|
525
892
|
name,
|
|
@@ -539,7 +906,7 @@ export abstract class Workload extends NamespacedResource {
|
|
|
539
906
|
"-it",
|
|
540
907
|
"-n",
|
|
541
908
|
this.metadata.namespace,
|
|
542
|
-
`${this.kind.toLowerCase()}/${this.metadata.name}`,
|
|
909
|
+
interpolate`${this.kind.toLowerCase()}/${this.metadata.name}`,
|
|
543
910
|
"-c",
|
|
544
911
|
containerName,
|
|
545
912
|
"--",
|
|
@@ -547,7 +914,11 @@ export abstract class Workload extends NamespacedResource {
|
|
|
547
914
|
]),
|
|
548
915
|
|
|
549
916
|
files: {
|
|
550
|
-
"/kubeconfig":
|
|
917
|
+
"/kubeconfig": makeFileOutput({
|
|
918
|
+
name: "kubeconfig",
|
|
919
|
+
content: getClusterKubeconfigContent(this.cluster),
|
|
920
|
+
isSecret: true,
|
|
921
|
+
}),
|
|
551
922
|
...spec?.files,
|
|
552
923
|
},
|
|
553
924
|
|
|
@@ -627,13 +998,23 @@ export abstract class Workload extends NamespacedResource {
|
|
|
627
998
|
if (args.defaultType === "Deployment") {
|
|
628
999
|
const { Deployment } = await import("./deployment")
|
|
629
1000
|
|
|
630
|
-
|
|
1001
|
+
const deploymentArgs = deepmerge(
|
|
1002
|
+
omit(args, ["defaultType", "existing", "deployment", "statefulSet", "job", "cronJob"]),
|
|
1003
|
+
args.deployment ?? {},
|
|
1004
|
+
) as DeploymentArgs
|
|
1005
|
+
|
|
1006
|
+
return Deployment.create(name, deploymentArgs, opts)
|
|
631
1007
|
}
|
|
632
1008
|
|
|
633
1009
|
if (args.defaultType === "StatefulSet") {
|
|
634
1010
|
const { StatefulSet } = await import("./stateful-set")
|
|
635
1011
|
|
|
636
|
-
|
|
1012
|
+
const statefulSetArgs = deepmerge(
|
|
1013
|
+
omit(args, ["defaultType", "existing", "deployment", "statefulSet", "job", "cronJob"]),
|
|
1014
|
+
args.statefulSet ?? {},
|
|
1015
|
+
) as StatefulSetArgs
|
|
1016
|
+
|
|
1017
|
+
return StatefulSet.create(name, statefulSetArgs, opts)
|
|
637
1018
|
}
|
|
638
1019
|
|
|
639
1020
|
if (args.defaultType === "Job") {
|
|
@@ -652,144 +1033,3 @@ export abstract class Workload extends NamespacedResource {
|
|
|
652
1033
|
})
|
|
653
1034
|
}
|
|
654
1035
|
}
|
|
655
|
-
|
|
656
|
-
export abstract class ExposableWorkload extends Workload {
|
|
657
|
-
protected constructor(
|
|
658
|
-
type: string,
|
|
659
|
-
name: string,
|
|
660
|
-
args: Inputs,
|
|
661
|
-
opts: ComponentResourceOptions | undefined,
|
|
662
|
-
|
|
663
|
-
metadata: Output<types.output.meta.v1.ObjectMeta>,
|
|
664
|
-
namespace: Output<Namespace>,
|
|
665
|
-
|
|
666
|
-
terminalArgs: Output<Unwrap<WorkloadTerminalArgs>>,
|
|
667
|
-
containers: Output<Container[]>,
|
|
668
|
-
podTemplate: Output<types.output.core.v1.PodTemplateSpec>,
|
|
669
|
-
networkPolicy: Output<NetworkPolicy | undefined>,
|
|
670
|
-
|
|
671
|
-
protected readonly _service: Output<Service | undefined>,
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* The access point routes associated with the workload.
|
|
675
|
-
*/
|
|
676
|
-
readonly routes: Output<AccessPointRoute[]>,
|
|
677
|
-
) {
|
|
678
|
-
super(
|
|
679
|
-
type,
|
|
680
|
-
name,
|
|
681
|
-
args,
|
|
682
|
-
opts,
|
|
683
|
-
metadata,
|
|
684
|
-
namespace,
|
|
685
|
-
terminalArgs,
|
|
686
|
-
containers,
|
|
687
|
-
podTemplate,
|
|
688
|
-
networkPolicy,
|
|
689
|
-
)
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: for pulumi which for some reason tries to copy all properties
|
|
693
|
-
private set optionalService(_value: never) {}
|
|
694
|
-
|
|
695
|
-
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: for pulumi which for some reason tries to copy all properties
|
|
696
|
-
private set service(_value: never) {}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
* The service associated with the workload.
|
|
700
|
-
*/
|
|
701
|
-
get optionalService(): Output<Service | undefined> {
|
|
702
|
-
return this._service
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* The service associated with the workload.
|
|
707
|
-
*
|
|
708
|
-
* Will throw an error if the service is not available.
|
|
709
|
-
*/
|
|
710
|
-
get service(): Output<Service> {
|
|
711
|
-
return this._service.apply(service => {
|
|
712
|
-
if (!service) {
|
|
713
|
-
throw new Error(`The service of the workload "${this.name}" is not available.`)
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
return service
|
|
717
|
-
})
|
|
718
|
-
}
|
|
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
|
-
|
|
731
|
-
/**
|
|
732
|
-
* The entity of the workload.
|
|
733
|
-
*/
|
|
734
|
-
abstract get entity(): Output<k8s.ExposableWorkload>
|
|
735
|
-
|
|
736
|
-
/**
|
|
737
|
-
* The sped of the underlying Kubernetes workload.
|
|
738
|
-
*/
|
|
739
|
-
abstract get spec(): Output<
|
|
740
|
-
types.output.apps.v1.DeploymentSpec | types.output.apps.v1.StatefulSetSpec
|
|
741
|
-
>
|
|
742
|
-
|
|
743
|
-
/**
|
|
744
|
-
* Creates a generic exposable workload or patches the existing one.
|
|
745
|
-
*/
|
|
746
|
-
static createOrPatchGeneric(
|
|
747
|
-
name: string,
|
|
748
|
-
args: GenericExposableWorkloadArgs,
|
|
749
|
-
opts?: CustomResourceOptions,
|
|
750
|
-
): Output<ExposableWorkload> {
|
|
751
|
-
return output(args).apply(async args => {
|
|
752
|
-
if (args.existing?.kind === "Deployment") {
|
|
753
|
-
const { Deployment } = await import("./deployment")
|
|
754
|
-
|
|
755
|
-
return Deployment.patch(
|
|
756
|
-
name,
|
|
757
|
-
{
|
|
758
|
-
...deepmerge(args, args.deployment),
|
|
759
|
-
name: args.existing.metadata.name,
|
|
760
|
-
namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
|
|
761
|
-
},
|
|
762
|
-
opts,
|
|
763
|
-
)
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
if (args.existing?.kind === "StatefulSet") {
|
|
767
|
-
const { StatefulSet } = await import("./stateful-set")
|
|
768
|
-
|
|
769
|
-
return StatefulSet.patch(
|
|
770
|
-
name,
|
|
771
|
-
{
|
|
772
|
-
...deepmerge(args, args.statefulSet),
|
|
773
|
-
name: args.existing.metadata.name,
|
|
774
|
-
namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
|
|
775
|
-
},
|
|
776
|
-
opts,
|
|
777
|
-
)
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
if (args.defaultType === "Deployment") {
|
|
781
|
-
const { Deployment } = await import("./deployment")
|
|
782
|
-
|
|
783
|
-
return Deployment.create(name, deepmerge(args, args.deployment), opts)
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
if (args.defaultType === "StatefulSet") {
|
|
787
|
-
const { StatefulSet } = await import("./stateful-set")
|
|
788
|
-
|
|
789
|
-
return StatefulSet.create(name, deepmerge(args, args.statefulSet), opts)
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
throw new Error(`Unknown workload type: ${args.defaultType as string}`)
|
|
793
|
-
})
|
|
794
|
-
}
|
|
795
|
-
}
|