@highstate/k8s 0.9.18 → 0.9.20
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-2EEHJZPD.js +13 -0
- package/dist/chunk-2EEHJZPD.js.map +1 -0
- package/dist/{chunk-OFFSHGC6.js → chunk-4JGXGN2L.js} +66 -48
- package/dist/chunk-4JGXGN2L.js.map +1 -0
- package/dist/chunk-A3XGSDIW.js +306 -0
- package/dist/chunk-A3XGSDIW.js.map +1 -0
- package/dist/chunk-IMTXUK2U.js +244 -0
- package/dist/chunk-IMTXUK2U.js.map +1 -0
- package/dist/chunk-JYNXQ3I3.js +287 -0
- package/dist/chunk-JYNXQ3I3.js.map +1 -0
- package/dist/{chunk-5C2BJGES.js → chunk-KDD6XUWM.js} +30 -23
- package/dist/chunk-KDD6XUWM.js.map +1 -0
- package/dist/chunk-NOFJC3EM.js +236 -0
- package/dist/chunk-NOFJC3EM.js.map +1 -0
- package/dist/chunk-NXSYCA3V.js +337 -0
- package/dist/chunk-NXSYCA3V.js.map +1 -0
- package/dist/chunk-SBC3TUIN.js +1513 -0
- package/dist/chunk-SBC3TUIN.js.map +1 -0
- package/dist/chunk-SI7X6N46.js +338 -0
- package/dist/chunk-SI7X6N46.js.map +1 -0
- package/dist/chunk-WGMJCZSK.js +360 -0
- package/dist/chunk-WGMJCZSK.js.map +1 -0
- package/dist/deployment-752P6JIT.js +8 -0
- package/dist/{deployment-XK3CDJOE.js.map → deployment-752P6JIT.js.map} +1 -1
- package/dist/highstate.manifest.json +8 -7
- package/dist/impl/gateway-route.js +123 -0
- package/dist/impl/gateway-route.js.map +1 -0
- package/dist/impl/tls-certificate.js +32 -0
- package/dist/impl/tls-certificate.js.map +1 -0
- package/dist/index.js +736 -208
- package/dist/index.js.map +1 -1
- package/dist/stateful-set-N64YVKR7.js +8 -0
- package/dist/{stateful-set-7CAQWTV2.js.map → stateful-set-N64YVKR7.js.map} +1 -1
- package/dist/units/cert-manager/index.js +11 -10
- package/dist/units/cert-manager/index.js.map +1 -1
- package/dist/units/dns01-issuer/index.js +27 -23
- package/dist/units/dns01-issuer/index.js.map +1 -1
- package/dist/units/existing-cluster/index.js +11 -8
- package/dist/units/existing-cluster/index.js.map +1 -1
- package/dist/units/gateway-api/index.js +2 -2
- package/dist/units/gateway-api/index.js.map +1 -1
- package/package.json +39 -13
- package/src/cluster.ts +30 -22
- package/src/config-map.ts +195 -57
- package/src/container.ts +5 -5
- package/src/cron-job.ts +403 -31
- package/src/deployment.ts +260 -120
- package/src/dns01-solver.ts +10 -0
- package/src/gateway/backend.ts +2 -2
- package/src/gateway/gateway.ts +383 -0
- package/src/gateway/http-route.ts +17 -24
- package/src/gateway/index.ts +1 -0
- package/src/helm.ts +83 -53
- package/src/impl/gateway-route.ts +155 -0
- package/src/impl/tls-certificate.ts +33 -0
- package/src/index.ts +22 -67
- package/src/job.ts +393 -28
- package/src/namespace.ts +236 -99
- package/src/network-policy.ts +216 -165
- package/src/network.ts +2 -2
- package/src/pvc.ts +266 -65
- package/src/rbac.ts +218 -0
- package/src/scripting/bundle.ts +9 -20
- package/src/scripting/container.ts +1 -1
- package/src/scripting/environment.ts +5 -5
- package/src/secret.ts +200 -62
- package/src/service.ts +288 -158
- package/src/shared.ts +94 -67
- package/src/stateful-set.ts +270 -117
- package/src/tls.ts +344 -0
- package/src/units/cert-manager/index.ts +2 -3
- package/src/units/dns01-issuer/index.ts +30 -14
- package/src/units/existing-cluster/index.ts +10 -7
- package/src/units/gateway-api/index.ts +2 -2
- package/src/worker.ts +26 -0
- package/src/workload.ts +275 -171
- package/dist/chunk-5C2BJGES.js.map +0 -1
- package/dist/chunk-5TLC5BXR.js +0 -256
- package/dist/chunk-5TLC5BXR.js.map +0 -1
- package/dist/chunk-BBIY3KUN.js +0 -1557
- package/dist/chunk-BBIY3KUN.js.map +0 -1
- package/dist/chunk-OFFSHGC6.js.map +0 -1
- package/dist/chunk-TZHOUJRC.js +0 -202
- package/dist/chunk-TZHOUJRC.js.map +0 -1
- package/dist/chunk-YWRJ4EZM.js +0 -192
- package/dist/chunk-YWRJ4EZM.js.map +0 -1
- package/dist/deployment-XK3CDJOE.js +0 -6
- package/dist/stateful-set-7CAQWTV2.js +0 -6
- package/dist/units/access-point/index.js +0 -21
- package/dist/units/access-point/index.js.map +0 -1
- package/src/access-point.ts +0 -191
- package/src/units/access-point/index.ts +0 -19
- package/src/units/dns01-issuer/solver.ts +0 -23
package/src/workload.ts
CHANGED
@@ -1,59 +1,81 @@
|
|
1
1
|
import type { k8s } from "@highstate/library"
|
2
|
+
import type { types } from "@pulumi/kubernetes"
|
2
3
|
import type { DeploymentArgs } from "./deployment"
|
3
4
|
import type { StatefulSetArgs } from "./stateful-set"
|
4
|
-
import type
|
5
|
+
import { AccessPointRoute, type AccessPointRouteArgs } from "@highstate/common"
|
6
|
+
import { type TerminalSpec, trimIndentation, type UnitTerminal } from "@highstate/contract"
|
5
7
|
import {
|
6
|
-
normalize,
|
7
8
|
type ComponentResourceOptions,
|
9
|
+
type DeepInput,
|
10
|
+
fileFromString,
|
8
11
|
type InputArray,
|
9
|
-
|
12
|
+
normalize,
|
13
|
+
normalizeInputs,
|
10
14
|
} from "@highstate/pulumi"
|
11
15
|
import {
|
12
|
-
ComponentResource,
|
13
|
-
interpolate,
|
14
|
-
Output,
|
15
|
-
output,
|
16
|
+
type ComponentResource,
|
16
17
|
type CustomResourceOptions,
|
17
18
|
type Input,
|
19
|
+
type Inputs,
|
20
|
+
interpolate,
|
21
|
+
type Output,
|
22
|
+
output,
|
23
|
+
type Unwrap,
|
18
24
|
} from "@pulumi/pulumi"
|
19
|
-
import { filter, isNonNullish, unique, uniqueBy } from "remeda"
|
20
|
-
import { deepmerge } from "deepmerge-ts"
|
21
25
|
import { sha256 } from "crypto-hash"
|
22
|
-
import {
|
23
|
-
import {
|
24
|
-
import { HttpRoute, type HttpRouteArgs } from "./gateway"
|
26
|
+
import { deepmerge } from "deepmerge-ts"
|
27
|
+
import { filter, isNonNullish, unique, uniqueBy } from "remeda"
|
25
28
|
import {
|
29
|
+
type Container,
|
26
30
|
getWorkloadVolumeResourceUuid,
|
27
31
|
mapContainerToRaw,
|
28
32
|
mapWorkloadVolume,
|
29
|
-
type Container,
|
30
33
|
type WorkloadVolume,
|
31
34
|
} from "./container"
|
35
|
+
import { Namespace } from "./namespace"
|
32
36
|
import { NetworkPolicy, type NetworkPolicyArgs } from "./network-policy"
|
33
37
|
import { podSpecDefaults } from "./pod"
|
38
|
+
import { mapContainerPortToServicePort, Service, type ServiceArgs } from "./service"
|
39
|
+
import { commonExtraArgs, images, ScopedResource, type ScopedResourceArgs } from "./shared"
|
34
40
|
|
35
|
-
export type
|
36
|
-
container?: Input<Container>
|
37
|
-
containers?: InputArray<Container>
|
38
|
-
|
41
|
+
export type WorkloadTerminalArgs = {
|
39
42
|
/**
|
40
43
|
* The shell to use in the terminal.
|
41
44
|
*
|
42
45
|
* By default, `bash` is used.
|
43
46
|
*/
|
44
|
-
|
47
|
+
shell?: string
|
48
|
+
}
|
49
|
+
|
50
|
+
export type WorkloadArgs = ScopedResourceArgs & {
|
51
|
+
container?: Input<Container>
|
52
|
+
containers?: InputArray<Container>
|
53
|
+
|
54
|
+
/**
|
55
|
+
* The args for the terminal to use.
|
56
|
+
*/
|
57
|
+
terminal?: Input<WorkloadTerminalArgs>
|
45
58
|
|
46
59
|
/**
|
47
60
|
* The network policy to apply to the deployment.
|
48
61
|
*/
|
49
|
-
networkPolicy?:
|
62
|
+
networkPolicy?: Omit<NetworkPolicyArgs, "selector" | "cluster" | "namespace">
|
50
63
|
}
|
51
64
|
|
52
65
|
export const workloadExtraArgs = [...commonExtraArgs, "container", "containers"] as const
|
53
66
|
|
54
67
|
export type ExposableWorkloadArgs = WorkloadArgs & {
|
55
68
|
service?: Input<Omit<ServiceArgs, "cluster" | "namespace">>
|
56
|
-
|
69
|
+
|
70
|
+
/**
|
71
|
+
* The configuration for the access point route to create.
|
72
|
+
*/
|
73
|
+
route?: Input<Omit<AccessPointRouteArgs, "endpoints" | "customData">>
|
74
|
+
|
75
|
+
/**
|
76
|
+
* The configuration for the access point routes to create.
|
77
|
+
*/
|
78
|
+
routes?: InputArray<Omit<AccessPointRouteArgs, "endpoints" | "customData">>
|
57
79
|
|
58
80
|
/**
|
59
81
|
* The existing workload to patch.
|
@@ -61,7 +83,12 @@ export type ExposableWorkloadArgs = WorkloadArgs & {
|
|
61
83
|
existing?: Input<k8s.ExposableWorkload>
|
62
84
|
}
|
63
85
|
|
64
|
-
export const exposableWorkloadExtraArgs = [
|
86
|
+
export const exposableWorkloadExtraArgs = [
|
87
|
+
...workloadExtraArgs,
|
88
|
+
"service",
|
89
|
+
"route",
|
90
|
+
"routes",
|
91
|
+
] as const
|
65
92
|
|
66
93
|
export type ExposableWorkloadType = "Deployment" | "StatefulSet"
|
67
94
|
|
@@ -125,16 +152,20 @@ export function getWorkloadComponents(
|
|
125
152
|
return output(rawVolumes.map(mapWorkloadVolume)).apply(uniqueBy(volume => volume.name))
|
126
153
|
})
|
127
154
|
|
128
|
-
const podSpec = output({
|
155
|
+
const podSpec = output({
|
156
|
+
cluster: output(args.namespace).cluster,
|
157
|
+
containers,
|
158
|
+
volumes,
|
159
|
+
}).apply(({ cluster, containers, volumes }) => {
|
129
160
|
const spec = {
|
130
161
|
volumes,
|
131
|
-
containers: containers.map(container => mapContainerToRaw(container,
|
162
|
+
containers: containers.map(container => mapContainerToRaw(container, cluster, name)),
|
132
163
|
...podSpecDefaults,
|
133
164
|
} satisfies types.input.core.v1.PodSpec
|
134
165
|
|
135
166
|
if (
|
136
167
|
containers.some(container => container.enableTun) &&
|
137
|
-
|
168
|
+
cluster.quirks?.tunDevicePolicy?.type !== "plugin"
|
138
169
|
) {
|
139
170
|
spec.volumes = output(spec.volumes).apply(volumes => [
|
140
171
|
...(volumes ?? []),
|
@@ -162,6 +193,7 @@ export function getWorkloadComponents(
|
|
162
193
|
metadata: {
|
163
194
|
labels,
|
164
195
|
annotations: {
|
196
|
+
// to trigger a redeployment when the volumes change
|
165
197
|
"highstate.io/dependency-hash": dependencyHash,
|
166
198
|
},
|
167
199
|
},
|
@@ -169,28 +201,30 @@ export function getWorkloadComponents(
|
|
169
201
|
} satisfies types.input.core.v1.PodTemplateSpec
|
170
202
|
})
|
171
203
|
|
172
|
-
const networkPolicy = output({
|
204
|
+
const networkPolicy = output({ containers }).apply(({ containers }) => {
|
173
205
|
const allowedEndpoints = containers.flatMap(container => container.allowedEndpoints ?? [])
|
174
206
|
|
175
207
|
if (allowedEndpoints.length === 0 && !args.networkPolicy) {
|
176
208
|
return output(undefined)
|
177
209
|
}
|
178
210
|
|
179
|
-
return
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
211
|
+
return output(
|
212
|
+
new NetworkPolicy(
|
213
|
+
name,
|
214
|
+
{
|
215
|
+
namespace: args.namespace,
|
216
|
+
selector: labels,
|
217
|
+
description: `Network policy for "${name}"`,
|
185
218
|
|
186
|
-
|
219
|
+
...args.networkPolicy,
|
187
220
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
221
|
+
egressRules: output(args.networkPolicy?.egressRules).apply(egressRules => [
|
222
|
+
...(egressRules ?? []),
|
223
|
+
...(allowedEndpoints.length > 0 ? [{ toEndpoints: allowedEndpoints }] : []),
|
224
|
+
]),
|
225
|
+
},
|
226
|
+
{ ...opts, parent: parent() },
|
227
|
+
),
|
194
228
|
)
|
195
229
|
})
|
196
230
|
|
@@ -206,93 +240,79 @@ export function getExposableWorkloadComponents(
|
|
206
240
|
const { labels, containers, volumes, podSpec, podTemplate, networkPolicy } =
|
207
241
|
getWorkloadComponents(name, args, parent, opts)
|
208
242
|
|
209
|
-
const service = output({
|
210
|
-
|
243
|
+
const service = output({
|
244
|
+
existing: args.existing,
|
245
|
+
serviceArgs: args.service,
|
246
|
+
containers,
|
247
|
+
}).apply(({ existing, serviceArgs, containers }) => {
|
248
|
+
if (!args.service && !args.route) {
|
211
249
|
return undefined
|
212
250
|
}
|
213
251
|
|
214
|
-
if (
|
215
|
-
return Service.
|
252
|
+
if (existing?.service) {
|
253
|
+
return Service.for(existing.service, output(args.namespace).cluster)
|
216
254
|
}
|
217
255
|
|
218
|
-
if (
|
256
|
+
if (existing) {
|
219
257
|
return undefined
|
220
258
|
}
|
221
259
|
|
222
260
|
const ports = containers.flatMap(container => normalize(container.port, container.ports))
|
223
261
|
|
224
|
-
return Service.create(
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
? ports.map(mapContainerPortToServicePort)
|
236
|
-
: args.service?.ports,
|
237
|
-
},
|
238
|
-
{
|
239
|
-
...opts,
|
240
|
-
parent: parent(),
|
241
|
-
provider: await getProvider(args.cluster),
|
242
|
-
},
|
243
|
-
)
|
262
|
+
return Service.create(name, {
|
263
|
+
...serviceArgs,
|
264
|
+
selector: labels,
|
265
|
+
namespace: args.namespace,
|
266
|
+
|
267
|
+
ports:
|
268
|
+
// allow to completely override the ports
|
269
|
+
!serviceArgs?.port && !serviceArgs?.ports
|
270
|
+
? ports.map(mapContainerPortToServicePort)
|
271
|
+
: serviceArgs?.ports,
|
272
|
+
})
|
244
273
|
})
|
245
274
|
|
246
|
-
const
|
247
|
-
args,
|
275
|
+
const routes = output({
|
276
|
+
routesArgs: normalizeInputs(args.route, args.routes),
|
248
277
|
service,
|
249
|
-
|
250
|
-
|
251
|
-
|
278
|
+
namespace: output(args.namespace),
|
279
|
+
}).apply(({ routesArgs, service, namespace }) => {
|
280
|
+
if (!routesArgs.length || !service) {
|
281
|
+
return []
|
252
282
|
}
|
253
283
|
|
254
284
|
if (args.existing) {
|
255
|
-
return
|
285
|
+
return []
|
256
286
|
}
|
257
287
|
|
258
|
-
return
|
259
|
-
name,
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
}
|
267
|
-
|
268
|
-
...opts,
|
269
|
-
parent: parent(),
|
270
|
-
provider: await getProvider(args.cluster),
|
271
|
-
},
|
272
|
-
)
|
288
|
+
return routesArgs.map(routeArgs => {
|
289
|
+
return new AccessPointRoute(name, {
|
290
|
+
...routeArgs,
|
291
|
+
endpoints: service.endpoints,
|
292
|
+
|
293
|
+
// pass the native data to the route to allow implementation to use it
|
294
|
+
gatewayNativeData: service,
|
295
|
+
tlsCertificateNativeData: namespace,
|
296
|
+
})
|
297
|
+
})
|
273
298
|
})
|
274
299
|
|
275
|
-
return { labels, containers, volumes, podSpec, podTemplate, networkPolicy, service,
|
300
|
+
return { labels, containers, volumes, podSpec, podTemplate, networkPolicy, service, routes }
|
276
301
|
}
|
277
302
|
|
278
|
-
export abstract class Workload extends
|
303
|
+
export abstract class Workload extends ScopedResource {
|
279
304
|
protected constructor(
|
280
305
|
type: string,
|
281
306
|
protected readonly name: string,
|
282
|
-
|
307
|
+
args: Inputs,
|
283
308
|
opts: ComponentResourceOptions | undefined,
|
284
309
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
/**
|
293
|
-
* The metadata of the underlying Kubernetes workload.
|
294
|
-
*/
|
295
|
-
readonly metadata: Output<types.output.meta.v1.ObjectMeta>,
|
310
|
+
apiVersion: Output<string>,
|
311
|
+
kind: Output<string>,
|
312
|
+
protected readonly terminalArgs: Output<Unwrap<WorkloadTerminalArgs>>,
|
313
|
+
protected readonly containers: Output<Container[]>,
|
314
|
+
namespace: Output<Namespace>,
|
315
|
+
metadata: Output<types.output.meta.v1.ObjectMeta>,
|
296
316
|
|
297
317
|
/**
|
298
318
|
* The network policy associated with the workload.
|
@@ -301,81 +321,187 @@ export abstract class Workload extends ComponentResource {
|
|
301
321
|
*/
|
302
322
|
readonly networkPolicy: Output<NetworkPolicy | undefined>,
|
303
323
|
) {
|
304
|
-
super(type, name, args, opts)
|
324
|
+
super(type, name, args, opts, apiVersion, kind, namespace, metadata)
|
305
325
|
}
|
306
326
|
|
327
|
+
protected abstract getTerminalMeta(): Output<UnitTerminal["meta"]>
|
328
|
+
|
307
329
|
/**
|
308
330
|
* The instance terminal to interact with the deployment.
|
309
331
|
*/
|
310
|
-
get terminal(): Output<
|
311
|
-
const containerName = output(this.
|
312
|
-
const containers = normalize(args.container, args.containers)
|
313
|
-
|
332
|
+
get terminal(): Output<UnitTerminal> {
|
333
|
+
const containerName = output(this.containers).apply(containers => {
|
314
334
|
return containers[0]?.name ?? this.name
|
315
335
|
})
|
316
336
|
|
337
|
+
const shell = this.terminalArgs.apply(args => args.shell ?? "bash")
|
338
|
+
|
339
|
+
const workloadLabelQuery = output(this.metadata)
|
340
|
+
.apply(meta => meta.labels ?? {})
|
341
|
+
.apply(labels =>
|
342
|
+
Object.entries(labels)
|
343
|
+
.map(([key, value]) => `${key}=${value}`)
|
344
|
+
.join(","),
|
345
|
+
)
|
346
|
+
|
317
347
|
return output({
|
318
348
|
name: this.metadata.name,
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
349
|
+
meta: this.getTerminalMeta(),
|
350
|
+
|
351
|
+
spec: {
|
352
|
+
image: images["terminal-kubectl"].image,
|
353
|
+
command: ["bash", "/welcome.sh"],
|
354
|
+
|
355
|
+
files: {
|
356
|
+
"/kubeconfig": fileFromString("kubeconfig", this.cluster.kubeconfig, { isSecret: true }),
|
357
|
+
|
358
|
+
"/welcome.sh": fileFromString(
|
359
|
+
"welcome.sh",
|
360
|
+
interpolate`
|
361
|
+
#!/bin/bash
|
362
|
+
set -euo pipefail
|
363
|
+
|
364
|
+
NAMESPACE="${this.metadata.namespace}"
|
365
|
+
RESOURCE_TYPE="${this.kind.apply(k => k.toLowerCase())}"
|
366
|
+
RESOURCE_NAME="${this.metadata.name}"
|
367
|
+
CONTAINER_NAME="${containerName}"
|
368
|
+
SHELL="${shell}"
|
369
|
+
|
370
|
+
echo "Connecting to $RESOURCE_TYPE \\"$RESOURCE_NAME\\" in namespace \\"$NAMESPACE\\""
|
371
|
+
|
372
|
+
# get all pods for this workload
|
373
|
+
PODS=$(kubectl get pods -n "$NAMESPACE" -l "${workloadLabelQuery}" -o jsonpath='{.items[*].metadata.name}' 2>/dev/null || echo "")
|
374
|
+
|
375
|
+
if [ -z "$PODS" ]; then
|
376
|
+
echo "No pods found"
|
377
|
+
exit 1
|
378
|
+
fi
|
379
|
+
|
380
|
+
# convert space-separated string to array
|
381
|
+
read -ra POD_ARRAY <<< "$PODS"
|
382
|
+
|
383
|
+
if [ \${#POD_ARRAY[@]} -eq 1 ]; then
|
384
|
+
# single pod found, connect directly
|
385
|
+
SELECTED_POD="\${POD_ARRAY[0]}"
|
386
|
+
echo "Found single pod: $SELECTED_POD"
|
387
|
+
else
|
388
|
+
# multiple pods found, use fzf for selection
|
389
|
+
echo "Found \${#POD_ARRAY[@]} pods. Please select one."
|
390
|
+
|
391
|
+
SELECTED_POD=$(printf '%s\n' "\${POD_ARRAY[@]}" | fzf --prompt="Select pod: " --height 10 --border --info=inline)
|
392
|
+
|
393
|
+
if [ -z "$SELECTED_POD" ]; then
|
394
|
+
echo "No pod selected"
|
395
|
+
exit 1
|
396
|
+
fi
|
397
|
+
|
398
|
+
echo "Selected pod: $SELECTED_POD"
|
399
|
+
fi
|
400
|
+
|
401
|
+
# execute into the selected pod
|
402
|
+
exec kubectl exec -it -n "$NAMESPACE" "$SELECTED_POD" -c "$CONTAINER_NAME" -- "$SHELL"
|
403
|
+
`.apply(trimIndentation),
|
404
|
+
),
|
405
|
+
},
|
342
406
|
|
343
|
-
|
344
|
-
|
407
|
+
env: {
|
408
|
+
KUBECONFIG: "/kubeconfig",
|
409
|
+
},
|
345
410
|
},
|
346
411
|
})
|
347
412
|
}
|
348
413
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
414
|
+
/**
|
415
|
+
* Creates a terminal with a custom command.
|
416
|
+
*
|
417
|
+
* @param meta The metadata for the terminal.
|
418
|
+
* @param command The command to run in the terminal.
|
419
|
+
* @param spec Additional spec options for the terminal.
|
420
|
+
*/
|
421
|
+
createTerminal(
|
422
|
+
name: string,
|
423
|
+
meta: UnitTerminal["meta"],
|
424
|
+
command: InputArray<string>,
|
425
|
+
spec?: { env?: DeepInput<TerminalSpec["env"]>; files?: DeepInput<TerminalSpec["files"]> },
|
426
|
+
): Output<UnitTerminal> {
|
427
|
+
const containerName = output(this.containers).apply(containers => {
|
428
|
+
return containers[0]?.name ?? this.name
|
429
|
+
})
|
430
|
+
|
431
|
+
return output({
|
432
|
+
name,
|
433
|
+
|
434
|
+
meta: output(this.getTerminalMeta()).apply(currentMeta => ({
|
435
|
+
...currentMeta,
|
436
|
+
...meta,
|
437
|
+
})),
|
438
|
+
|
439
|
+
spec: {
|
440
|
+
image: images["terminal-kubectl"].image,
|
441
|
+
|
442
|
+
command: output(command).apply(command => [
|
443
|
+
"exec",
|
444
|
+
"kubectl",
|
445
|
+
"exec",
|
446
|
+
"-it",
|
447
|
+
"-n",
|
448
|
+
this.metadata.namespace,
|
449
|
+
interpolate`${this.kind.apply(k => k.toLowerCase())}/${this.metadata.name}`,
|
450
|
+
"-c",
|
451
|
+
containerName,
|
452
|
+
"--",
|
453
|
+
...command,
|
454
|
+
]),
|
455
|
+
|
456
|
+
files: {
|
457
|
+
"/kubeconfig": fileFromString("kubeconfig", this.cluster.kubeconfig, { isSecret: true }),
|
458
|
+
...spec?.files,
|
459
|
+
},
|
460
|
+
|
461
|
+
env: {
|
462
|
+
KUBECONFIG: "/kubeconfig",
|
463
|
+
...spec?.env,
|
464
|
+
},
|
465
|
+
},
|
466
|
+
})
|
360
467
|
}
|
361
468
|
}
|
362
469
|
|
363
470
|
export abstract class ExposableWorkload extends Workload {
|
364
471
|
protected constructor(
|
365
472
|
type: string,
|
366
|
-
|
367
|
-
args:
|
473
|
+
name: string,
|
474
|
+
args: Inputs,
|
368
475
|
opts: ComponentResourceOptions | undefined,
|
369
476
|
|
370
|
-
|
371
|
-
|
477
|
+
apiVersion: Output<string>,
|
478
|
+
kind: Output<string>,
|
479
|
+
terminalArgs: Output<Unwrap<WorkloadTerminalArgs>>,
|
480
|
+
containers: Output<Container[]>,
|
481
|
+
namespace: Output<Namespace>,
|
372
482
|
metadata: Output<types.output.meta.v1.ObjectMeta>,
|
373
483
|
networkPolicy: Output<NetworkPolicy | undefined>,
|
374
484
|
|
375
485
|
protected readonly _service: Output<Service | undefined>,
|
376
|
-
|
486
|
+
|
487
|
+
/**
|
488
|
+
* The access point routes associated with the workload.
|
489
|
+
*/
|
490
|
+
readonly routes: Output<AccessPointRoute[]>,
|
377
491
|
) {
|
378
|
-
super(
|
492
|
+
super(
|
493
|
+
type,
|
494
|
+
name,
|
495
|
+
args,
|
496
|
+
opts,
|
497
|
+
apiVersion,
|
498
|
+
kind,
|
499
|
+
terminalArgs,
|
500
|
+
containers,
|
501
|
+
namespace,
|
502
|
+
metadata,
|
503
|
+
networkPolicy,
|
504
|
+
)
|
379
505
|
}
|
380
506
|
|
381
507
|
/**
|
@@ -385,13 +511,6 @@ export abstract class ExposableWorkload extends Workload {
|
|
385
511
|
return this._service
|
386
512
|
}
|
387
513
|
|
388
|
-
/**
|
389
|
-
* The HTTP route associated with the workload.
|
390
|
-
*/
|
391
|
-
get optionalHttpRoute(): Output<HttpRoute | undefined> {
|
392
|
-
return this._httpRoute
|
393
|
-
}
|
394
|
-
|
395
514
|
/**
|
396
515
|
* The service associated with the workload.
|
397
516
|
*
|
@@ -407,21 +526,6 @@ export abstract class ExposableWorkload extends Workload {
|
|
407
526
|
})
|
408
527
|
}
|
409
528
|
|
410
|
-
/**
|
411
|
-
* The HTTP route associated with the workload.
|
412
|
-
*
|
413
|
-
* Will throw an error if the HTTP route is not available.
|
414
|
-
*/
|
415
|
-
get httpRoute(): Output<HttpRoute> {
|
416
|
-
return this._httpRoute.apply(httpRoute => {
|
417
|
-
if (!httpRoute) {
|
418
|
-
throw new Error(`The HTTP route of the workload "${this.name}" is not available.`)
|
419
|
-
}
|
420
|
-
|
421
|
-
return httpRoute
|
422
|
-
})
|
423
|
-
}
|
424
|
-
|
425
529
|
/**
|
426
530
|
* The entity of the workload.
|
427
531
|
*/
|
@@ -443,7 +547,7 @@ export abstract class ExposableWorkload extends Workload {
|
|
443
547
|
opts?: CustomResourceOptions,
|
444
548
|
): Output<ExposableWorkload> {
|
445
549
|
return output(args).apply(async args => {
|
446
|
-
if (args.existing?.type === "
|
550
|
+
if (args.existing?.type === "deployment") {
|
447
551
|
const { Deployment } = await import("./deployment")
|
448
552
|
|
449
553
|
return Deployment.patch(
|
@@ -451,13 +555,13 @@ export abstract class ExposableWorkload extends Workload {
|
|
451
555
|
{
|
452
556
|
...deepmerge(args, args.deployment),
|
453
557
|
name: args.existing.metadata.name,
|
454
|
-
namespace: args.existing.
|
558
|
+
namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
|
455
559
|
},
|
456
560
|
opts,
|
457
561
|
)
|
458
562
|
}
|
459
563
|
|
460
|
-
if (args.existing?.type === "
|
564
|
+
if (args.existing?.type === "stateful-set") {
|
461
565
|
const { StatefulSet } = await import("./stateful-set")
|
462
566
|
|
463
567
|
return StatefulSet.patch(
|
@@ -465,7 +569,7 @@ export abstract class ExposableWorkload extends Workload {
|
|
465
569
|
{
|
466
570
|
...deepmerge(args, args.statefulSet),
|
467
571
|
name: args.existing.metadata.name,
|
468
|
-
namespace: args.existing.
|
572
|
+
namespace: Namespace.forResourceAsync(args.existing, output(args.namespace).cluster),
|
469
573
|
},
|
470
574
|
opts,
|
471
575
|
)
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"sources":["../src/cluster.ts"],"names":[],"mappings":";;;;;AAMA,SAAS,YAAY,EAAA,EAAY;AAC/B,EAAA,MAAM,cAAA,GAAiB,0BAAA;AACvB,EAAA,OAAO,cAAA,CAAe,KAAK,EAAE,CAAA;AAC/B;AAEA,eAAsB,iBAAA,CACpB,YACA,iBAAA,EACmB;AACnB,EAAA,MAAM,OAAA,GAAU,UAAA,CAAW,aAAA,CAAc,SAAS,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,QAAA,EAAS;AAErC,EAAA,OAAO,KAAA,CAAM,KAAA,CAAM,OAAA,CAAQ,CAAA,IAAA,KAAQ;AACjC,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,MAAA,EAAQ,SAAA,IAAa,EAAC;AAC7C,IAAA,MAAM,aAAa,SAAA,CAAU,IAAA,CAAK,CAAA,OAAA,KAAW,OAAA,CAAQ,SAAS,YAAY,CAAA;AAC1E,IAAA,MAAM,aAAa,SAAA,CAAU,IAAA,CAAK,CAAA,OAAA,KAAW,OAAA,CAAQ,SAAS,YAAY,CAAA;AAE1E,IAAA,MAAM,SAAmB,EAAC;AAE1B,IAAA,IAAI,YAAY,OAAA,EAAS;AACvB,MAAA,MAAA,CAAO,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA,IAChC;AAEA,IAAA,IAAI,UAAA,EAAY,OAAA,IAAW,iBAAA,KAAsB,QAAA,EAAU;AACzD,MAAA,MAAA,CAAO,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA,IAChC;AAEA,IAAA,IAAI,UAAA,EAAY,WAAW,iBAAA,KAAsB,QAAA,IAAY,CAAC,WAAA,CAAY,UAAA,CAAW,OAAO,CAAA,EAAG;AAC7F,MAAA,MAAA,CAAO,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA,IAChC;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,CAAC,CAAA;AACH;AAEO,SAAS,kBAAkB,UAAA,EAA6C;AAC7E,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,YAAA;AAAA,IACN,KAAA,EAAO,oBAAA;AAAA,IACP,WAAA,EAAa,2CAAA;AAAA,IACb,IAAA,EAAM,oBAAA;AAAA,IAEN,KAAA,EAAO,cAAA,CAAO,kBAAkB,CAAA,CAAE,KAAA;AAAA,IAClC,OAAA,EAAS,CAAC,MAAA,EAAQ,aAAa,CAAA;AAAA,IAE/B,KAAA,EAAO;AAAA,MACL,aAAA,EAAe,OAAO,UAAU,CAAA;AAAA,MAEhC,aAAA,EAAe,IAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA,MAAA;AAAA,KASjB;AAAA,IAEA,GAAA,EAAK;AAAA,MACH,UAAA,EAAY;AAAA;AACd,GACF;AACF","file":"chunk-5C2BJGES.js","sourcesContent":["import type { k8s } from \"@highstate/library\"\nimport { text } from \"@highstate/contract\"\nimport { secret, type Input, type InstanceTerminal } from \"@highstate/pulumi\"\nimport { CoreV1Api, type KubeConfig } from \"@kubernetes/client-node\"\nimport { images } from \"./shared\"\n\nfunction isPrivateIp(ip: string) {\n const privateIpRegex = /^(10|172\\.16|192\\.168)\\./\n return privateIpRegex.test(ip)\n}\n\nexport async function detectExternalIps(\n kubeConfig: KubeConfig,\n internalIpsPolicy: k8s.InternalIpsPolicy,\n): Promise<string[]> {\n const nodeApi = kubeConfig.makeApiClient(CoreV1Api)\n const nodes = await nodeApi.listNode()\n\n return nodes.items.flatMap(node => {\n const addresses = node.status?.addresses ?? []\n const externalIp = addresses.find(address => address.type === \"ExternalIP\")\n const internalIp = addresses.find(address => address.type === \"InternalIP\")\n\n const result: string[] = []\n\n if (externalIp?.address) {\n result.push(externalIp.address)\n }\n\n if (internalIp?.address && internalIpsPolicy === \"always\") {\n result.push(internalIp.address)\n }\n\n if (internalIp?.address && internalIpsPolicy === \"public\" && !isPrivateIp(internalIp.address)) {\n result.push(internalIp.address)\n }\n\n return result\n })\n}\n\nexport function createK8sTerminal(kubeconfig: Input<string>): InstanceTerminal {\n return {\n name: \"management\",\n title: \"Cluster Management\",\n description: \"Manage the cluster using kubectl and helm\",\n icon: \"devicon:kubernetes\",\n\n image: images[\"terminal-kubectl\"].image,\n command: [\"bash\", \"/welcome.sh\"],\n\n files: {\n \"/kubeconfig\": secret(kubeconfig),\n\n \"/welcome.sh\": text`\n echo \"Connecting to the cluster...\"\n kubectl cluster-info\n\n echo \"Use 'kubectl' and 'helm' to manage the cluster.\"\n echo\n\n exec bash\n `,\n },\n\n env: {\n KUBECONFIG: \"/kubeconfig\",\n },\n }\n}\n"]}
|