@highstate/k8s 0.9.31 → 0.9.33
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-4YC2SLCU.js → chunk-2F2IID7N.js} +8 -3
- package/dist/chunk-2F2IID7N.js.map +1 -0
- package/dist/{chunk-64LNVTHJ.js → chunk-2ZAEILVT.js} +5 -5
- package/dist/{chunk-64LNVTHJ.js.map → chunk-2ZAEILVT.js.map} +1 -1
- package/dist/{chunk-2FKGGWPJ.js → chunk-3DFFUGSJ.js} +6 -3
- package/dist/chunk-3DFFUGSJ.js.map +1 -0
- package/dist/{chunk-HOARC4LU.js → chunk-IDKGFFZ7.js} +43 -25
- package/dist/chunk-IDKGFFZ7.js.map +1 -0
- package/dist/{chunk-XYJNM2EN.js → chunk-OEOMZP2C.js} +114 -12
- package/dist/chunk-OEOMZP2C.js.map +1 -0
- package/dist/{chunk-ARG3I734.js → chunk-XU6ZPTWO.js} +6 -3
- package/dist/chunk-XU6ZPTWO.js.map +1 -0
- package/dist/deployment-D3ZXIZRN.js +8 -0
- package/dist/{deployment-PKZ4IQMG.js.map → deployment-D3ZXIZRN.js.map} +1 -1
- package/dist/highstate.manifest.json +2 -2
- package/dist/impl/gateway-route.js +295 -73
- package/dist/impl/gateway-route.js.map +1 -1
- package/dist/impl/tls-certificate.js +2 -2
- package/dist/impl/tls-certificate.js.map +1 -1
- package/dist/index.js +13 -6
- package/dist/index.js.map +1 -1
- package/dist/stateful-set-AXF4QRFI.js +8 -0
- package/dist/{stateful-set-OMPM2F7W.js.map → stateful-set-AXF4QRFI.js.map} +1 -1
- package/dist/units/cert-manager/index.js +4 -4
- package/dist/units/gateway-api/index.js +1 -1
- package/dist/units/gateway-api/index.js.map +1 -1
- package/dist/units/reduced-access-cluster/index.js +3 -3
- package/package.json +10 -10
- package/src/container.ts +8 -0
- package/src/cron-job.ts +4 -0
- package/src/deployment.ts +4 -0
- package/src/gateway/gateway.ts +22 -5
- package/src/gateway/http-route.ts +6 -1
- package/src/gateway/index.ts +2 -0
- package/src/gateway/tcp-route.ts +87 -0
- package/src/gateway/udp-route.ts +87 -0
- package/src/impl/gateway-route.ts +418 -85
- package/src/impl/tls-certificate.ts +1 -1
- package/src/index.ts +1 -0
- package/src/job.ts +4 -0
- package/src/stateful-set.ts +4 -0
- package/src/tls.ts +9 -1
- package/src/units/gateway-api/index.ts +1 -1
- package/src/workload.ts +61 -23
- package/dist/chunk-2FKGGWPJ.js.map +0 -1
- package/dist/chunk-4YC2SLCU.js.map +0 -1
- package/dist/chunk-ARG3I734.js.map +0 -1
- package/dist/chunk-HOARC4LU.js.map +0 -1
- package/dist/chunk-XYJNM2EN.js.map +0 -1
- package/dist/deployment-PKZ4IQMG.js +0 -8
- package/dist/stateful-set-OMPM2F7W.js +0 -8
@@ -0,0 +1,87 @@
|
|
1
|
+
import type { Gateway } from "./gateway"
|
2
|
+
import { gateway, type types } from "@highstate/gateway-api"
|
3
|
+
import {
|
4
|
+
ComponentResource,
|
5
|
+
type ComponentResourceOptions,
|
6
|
+
type Input,
|
7
|
+
type InputArray,
|
8
|
+
normalizeInputsAndMap,
|
9
|
+
type Output,
|
10
|
+
output,
|
11
|
+
} from "@highstate/pulumi"
|
12
|
+
import { getProvider, mapMetadata, type ScopedResourceArgs } from "../shared"
|
13
|
+
import { type BackendRef, resolveBackendRef } from "./backend"
|
14
|
+
|
15
|
+
export type UdpRouteArgs = Omit<ScopedResourceArgs, "namespace"> & {
|
16
|
+
/**
|
17
|
+
* The gateway to associate with the route.
|
18
|
+
*/
|
19
|
+
gateway: Input<Gateway>
|
20
|
+
|
21
|
+
/**
|
22
|
+
* The name of the listener to attach the route to.
|
23
|
+
*/
|
24
|
+
listenerName: Input<string>
|
25
|
+
|
26
|
+
/**
|
27
|
+
* The backend reference handled by the route.
|
28
|
+
*/
|
29
|
+
backend?: Input<BackendRef>
|
30
|
+
|
31
|
+
/**
|
32
|
+
* The backend references handled by the route.
|
33
|
+
*/
|
34
|
+
backends?: InputArray<BackendRef>
|
35
|
+
}
|
36
|
+
|
37
|
+
export class UdpRoute extends ComponentResource {
|
38
|
+
/**
|
39
|
+
* The underlying Kubernetes resource.
|
40
|
+
*/
|
41
|
+
public readonly route: Output<gateway.v1alpha2.UDPRoute>
|
42
|
+
|
43
|
+
constructor(name: string, args: UdpRouteArgs, opts?: ComponentResourceOptions) {
|
44
|
+
super("highstate:k8s:UdpRoute", name, args, opts)
|
45
|
+
|
46
|
+
const gatewayOutput = output(args.gateway)
|
47
|
+
|
48
|
+
const parentRefs = output({
|
49
|
+
gateway: gatewayOutput,
|
50
|
+
listenerName: args.listenerName,
|
51
|
+
}).apply(
|
52
|
+
({ gateway, listenerName }) =>
|
53
|
+
[
|
54
|
+
{
|
55
|
+
group: "gateway.networking.k8s.io",
|
56
|
+
kind: "Gateway",
|
57
|
+
name: gateway.metadata.name,
|
58
|
+
namespace: gateway.namespace.metadata.name,
|
59
|
+
sectionName: listenerName,
|
60
|
+
},
|
61
|
+
] satisfies types.input.gateway.v1alpha2.UDPRouteSpecParentRefs[],
|
62
|
+
)
|
63
|
+
|
64
|
+
const backendRefs = normalizeInputsAndMap(args.backend, args.backends, resolveBackendRef)
|
65
|
+
|
66
|
+
this.route = gatewayOutput.cluster.apply(cluster => {
|
67
|
+
return new gateway.v1alpha2.UDPRoute(
|
68
|
+
name,
|
69
|
+
{
|
70
|
+
metadata: mapMetadata(args, name).apply(metadata => ({
|
71
|
+
...metadata,
|
72
|
+
namespace: gatewayOutput.namespace.metadata.name,
|
73
|
+
})),
|
74
|
+
spec: {
|
75
|
+
parentRefs,
|
76
|
+
rules: [
|
77
|
+
{
|
78
|
+
backendRefs,
|
79
|
+
},
|
80
|
+
],
|
81
|
+
} satisfies types.input.gateway.v1alpha2.UDPRouteSpec,
|
82
|
+
},
|
83
|
+
{ ...opts, parent: this, provider: getProvider(cluster) },
|
84
|
+
)
|
85
|
+
})
|
86
|
+
}
|
87
|
+
}
|
@@ -1,9 +1,14 @@
|
|
1
1
|
import type { Secret } from "../secret"
|
2
|
-
import {
|
3
|
-
|
4
|
-
|
2
|
+
import {
|
3
|
+
filterEndpoints,
|
4
|
+
type GatewayRouteSpec,
|
5
|
+
gatewayRouteMediator,
|
6
|
+
type TlsCertificate,
|
7
|
+
} from "@highstate/common"
|
8
|
+
import { k8s, type network } from "@highstate/library"
|
9
|
+
import { type ComponentResourceOptions, type Input, toPromise } from "@highstate/pulumi"
|
5
10
|
import { core } from "@pulumi/kubernetes"
|
6
|
-
import { Gateway, HttpRoute } from "../gateway"
|
11
|
+
import { Gateway, HttpRoute, TcpRoute, UdpRoute } from "../gateway"
|
7
12
|
import { Namespace } from "../namespace"
|
8
13
|
import { l4EndpointToServicePort, Service } from "../service"
|
9
14
|
import { getProvider, mapMetadata } from "../shared"
|
@@ -21,107 +26,209 @@ export const createGatewayRoute = gatewayRouteMediator.implement(
|
|
21
26
|
|
22
27
|
const certificateRef = certSecret
|
23
28
|
? {
|
24
|
-
kind: "Secret",
|
25
|
-
group: "",
|
29
|
+
kind: "Secret" as const,
|
30
|
+
group: "" as const,
|
26
31
|
name: certSecret.metadata.name,
|
27
32
|
}
|
28
33
|
: undefined
|
29
34
|
|
30
|
-
|
31
|
-
{
|
35
|
+
if (spec.type === "http") {
|
36
|
+
return await createHttpGatewayRoute({
|
32
37
|
name,
|
38
|
+
spec,
|
39
|
+
opts,
|
40
|
+
data,
|
33
41
|
namespace,
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
},
|
44
|
-
},
|
45
|
-
],
|
46
|
-
},
|
42
|
+
certificateRef,
|
43
|
+
})
|
44
|
+
}
|
45
|
+
|
46
|
+
const protocol = spec.type === "tcp" ? "TCP" : "UDP"
|
47
|
+
|
48
|
+
return await createL4GatewayRoute({
|
49
|
+
name,
|
50
|
+
spec,
|
47
51
|
opts,
|
48
|
-
|
52
|
+
data,
|
53
|
+
namespace,
|
54
|
+
protocol,
|
55
|
+
})
|
56
|
+
},
|
57
|
+
)
|
49
58
|
|
50
|
-
|
51
|
-
|
52
|
-
const httpRoute = new HttpRoute(
|
53
|
-
name,
|
54
|
-
{
|
55
|
-
gateway,
|
56
|
-
rule: { backend: spec.nativeData },
|
57
|
-
},
|
58
|
-
opts,
|
59
|
-
)
|
59
|
+
type HttpGatewayRouteSpec = Extract<GatewayRouteSpec, { type: "http" }>
|
60
|
+
type L4GatewayRouteSpec = Extract<GatewayRouteSpec, { type: "tcp" | "udp" }>
|
60
61
|
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
type CreateHttpGatewayRouteArgs = {
|
63
|
+
name: string
|
64
|
+
spec: HttpGatewayRouteSpec
|
65
|
+
opts: ComponentResourceOptions | undefined
|
66
|
+
data: k8s.GatewayData
|
67
|
+
namespace: Namespace
|
68
|
+
certificateRef:
|
69
|
+
| {
|
70
|
+
kind: "Secret"
|
71
|
+
group: ""
|
72
|
+
name: Input<string>
|
64
73
|
}
|
65
|
-
|
74
|
+
| undefined
|
75
|
+
}
|
66
76
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
77
|
+
async function createHttpGatewayRoute({
|
78
|
+
name,
|
79
|
+
spec,
|
80
|
+
opts,
|
81
|
+
data,
|
82
|
+
namespace,
|
83
|
+
certificateRef,
|
84
|
+
}: CreateHttpGatewayRouteArgs) {
|
85
|
+
const backendService =
|
86
|
+
spec.nativeData instanceof Service
|
87
|
+
? spec.nativeData
|
88
|
+
: (await createServiceFromEndpoints(name, namespace, spec.endpoints, data.cluster, opts))
|
89
|
+
.service
|
71
90
|
|
72
|
-
|
91
|
+
const listeners = [
|
92
|
+
{
|
93
|
+
name: "https",
|
94
|
+
port: data.httpsPort,
|
95
|
+
protocol: "HTTPS",
|
96
|
+
tls: {
|
97
|
+
mode: "Terminate",
|
98
|
+
certificateRefs: certificateRef ? [certificateRef] : undefined,
|
99
|
+
},
|
100
|
+
},
|
101
|
+
]
|
73
102
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
103
|
+
const gateway = await Gateway.createOnce(
|
104
|
+
{
|
105
|
+
name: data.className,
|
106
|
+
namespace,
|
107
|
+
gatewayClassName: data.className,
|
108
|
+
listeners,
|
109
|
+
},
|
110
|
+
opts,
|
111
|
+
)
|
112
|
+
|
113
|
+
const httpRoute = new HttpRoute(
|
114
|
+
name,
|
115
|
+
{
|
116
|
+
gateway,
|
117
|
+
rule: {
|
118
|
+
backend: backendService,
|
119
|
+
},
|
120
|
+
},
|
121
|
+
opts,
|
122
|
+
)
|
123
|
+
|
124
|
+
return {
|
125
|
+
resource: httpRoute,
|
126
|
+
endpoints: await toPromise(gateway.endpoints),
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
type CreateL4GatewayRouteArgs = {
|
131
|
+
name: string
|
132
|
+
spec: L4GatewayRouteSpec
|
133
|
+
opts: ComponentResourceOptions | undefined
|
134
|
+
data: k8s.GatewayData
|
135
|
+
namespace: Namespace
|
136
|
+
protocol: "TCP" | "UDP"
|
137
|
+
}
|
138
|
+
|
139
|
+
async function createL4GatewayRoute({
|
140
|
+
name,
|
141
|
+
spec,
|
142
|
+
opts,
|
143
|
+
data,
|
144
|
+
namespace,
|
145
|
+
protocol,
|
146
|
+
}: CreateL4GatewayRouteArgs) {
|
147
|
+
const serviceData =
|
148
|
+
spec.nativeData instanceof Service
|
149
|
+
? {
|
150
|
+
service: spec.nativeData,
|
151
|
+
ports: await getServicePorts(spec.nativeData),
|
152
|
+
}
|
153
|
+
: await createServiceFromEndpoints(name, namespace, spec.endpoints, data.cluster, opts)
|
154
|
+
|
155
|
+
const serviceName = await toPromise(serviceData.service.metadata.name)
|
156
|
+
|
157
|
+
const backendPort = await selectBackendPort({
|
158
|
+
ports: serviceData.ports,
|
159
|
+
protocol,
|
160
|
+
targetPort: spec.targetPort,
|
161
|
+
serviceName,
|
162
|
+
routeName: name,
|
163
|
+
})
|
92
164
|
|
93
|
-
|
165
|
+
const listenerPort = await resolveListenerPort({
|
166
|
+
requestedPort: spec.port,
|
167
|
+
backendPort,
|
168
|
+
protocol,
|
169
|
+
routeName: name,
|
170
|
+
})
|
94
171
|
|
95
|
-
|
96
|
-
|
172
|
+
const listenerName = `${protocol.toLowerCase()}-${listenerPort}`
|
173
|
+
|
174
|
+
const gateway = await Gateway.createOnce(
|
175
|
+
{
|
176
|
+
name: data.className,
|
177
|
+
namespace,
|
178
|
+
gatewayClassName: data.className,
|
179
|
+
listeners: [
|
97
180
|
{
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
ports: [l4EndpointToServicePort(endpoint)],
|
102
|
-
})),
|
181
|
+
name: listenerName,
|
182
|
+
port: listenerPort,
|
183
|
+
protocol,
|
103
184
|
},
|
104
|
-
|
185
|
+
],
|
186
|
+
},
|
187
|
+
opts,
|
188
|
+
)
|
189
|
+
|
190
|
+
const backendRef = serviceData.service.metadata.apply(metadata => {
|
191
|
+
if (!metadata?.name) {
|
192
|
+
throw new Error(
|
193
|
+
`Service "${serviceName}" referenced by gateway route "${name}" does not have a name.`,
|
105
194
|
)
|
106
195
|
}
|
107
196
|
|
108
|
-
const httpRoute = new HttpRoute(
|
109
|
-
name,
|
110
|
-
{
|
111
|
-
gateway,
|
112
|
-
rule: {
|
113
|
-
backend: service,
|
114
|
-
},
|
115
|
-
},
|
116
|
-
opts,
|
117
|
-
)
|
118
|
-
|
119
197
|
return {
|
120
|
-
|
121
|
-
|
198
|
+
name: metadata.name,
|
199
|
+
namespace: metadata.namespace,
|
200
|
+
port: backendPort.port,
|
122
201
|
}
|
123
|
-
}
|
124
|
-
|
202
|
+
})
|
203
|
+
|
204
|
+
const routeOpts = { ...opts, parent: gateway }
|
205
|
+
|
206
|
+
const route =
|
207
|
+
protocol === "TCP"
|
208
|
+
? new TcpRoute(
|
209
|
+
name,
|
210
|
+
{
|
211
|
+
gateway,
|
212
|
+
listenerName,
|
213
|
+
backend: backendRef,
|
214
|
+
},
|
215
|
+
routeOpts,
|
216
|
+
)
|
217
|
+
: new UdpRoute(
|
218
|
+
name,
|
219
|
+
{
|
220
|
+
gateway,
|
221
|
+
listenerName,
|
222
|
+
backend: backendRef,
|
223
|
+
},
|
224
|
+
routeOpts,
|
225
|
+
)
|
226
|
+
|
227
|
+
return {
|
228
|
+
resource: route,
|
229
|
+
endpoints: await toPromise(gateway.endpoints),
|
230
|
+
}
|
231
|
+
}
|
125
232
|
|
126
233
|
async function getCertificateSecret(
|
127
234
|
_name: string,
|
@@ -143,13 +250,239 @@ async function getCertificateSecret(
|
|
143
250
|
const targetClusterId = await toPromise(namespace.cluster.id)
|
144
251
|
|
145
252
|
if (certNamespace === targetNamespace && certClusterId === targetClusterId) {
|
146
|
-
// 1. short path - same namespace and cluster, just return the secret
|
147
253
|
return await toPromise(resource.secret)
|
148
254
|
}
|
149
255
|
}
|
150
256
|
|
151
|
-
// 2. long path - create a new secret in the target namespace with the certificate data
|
152
257
|
throw new Error(
|
153
258
|
"Not implemented: copying certificate secret across namespaces/clusters/different systems",
|
154
259
|
)
|
155
260
|
}
|
261
|
+
|
262
|
+
type ServicePortInfo = {
|
263
|
+
name: string | undefined
|
264
|
+
port: number
|
265
|
+
protocol: "TCP" | "UDP"
|
266
|
+
targetPort?: number | string
|
267
|
+
}
|
268
|
+
|
269
|
+
async function createServiceFromEndpoints(
|
270
|
+
name: string,
|
271
|
+
namespace: Namespace,
|
272
|
+
endpointsInput: Input<network.L4Endpoint[]>,
|
273
|
+
cluster: k8s.Cluster,
|
274
|
+
opts: ComponentResourceOptions | undefined,
|
275
|
+
): Promise<{ service: Service; ports: ServicePortInfo[] }> {
|
276
|
+
const endpoints = await toPromise(endpointsInput)
|
277
|
+
|
278
|
+
if (!endpoints.length) {
|
279
|
+
throw new Error(`Gateway route "${name}" has no endpoints to expose.`)
|
280
|
+
}
|
281
|
+
|
282
|
+
const hostnameEndpoints = filterEndpoints(endpoints, undefined, ["hostname"])
|
283
|
+
const ipEndpoints = filterEndpoints(endpoints, undefined, ["ipv4", "ipv6"])
|
284
|
+
|
285
|
+
if (
|
286
|
+
hostnameEndpoints.length > 0 &&
|
287
|
+
hostnameEndpoints[0].visibility > ipEndpoints[0]?.visibility
|
288
|
+
) {
|
289
|
+
const hostnamePortInfos: ServicePortInfo[] = []
|
290
|
+
for (const endpoint of hostnameEndpoints) {
|
291
|
+
hostnamePortInfos.push(toServicePortInfoFromEndpoint(endpoint))
|
292
|
+
}
|
293
|
+
|
294
|
+
const service = Service.create(`hs-backend-${name}`, {
|
295
|
+
namespace,
|
296
|
+
type: "ExternalName",
|
297
|
+
externalName: hostnameEndpoints[0].hostname,
|
298
|
+
ports: hostnameEndpoints.map(l4EndpointToServicePort),
|
299
|
+
})
|
300
|
+
|
301
|
+
return {
|
302
|
+
service,
|
303
|
+
ports: hostnamePortInfos,
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
if (ipEndpoints.length === 0) {
|
308
|
+
throw new Error(`Gateway route "${name}" requires at least one IP endpoint.`)
|
309
|
+
}
|
310
|
+
|
311
|
+
const ipPortInfos: ServicePortInfo[] = []
|
312
|
+
for (const endpoint of ipEndpoints) {
|
313
|
+
ipPortInfos.push(toServicePortInfoFromEndpoint(endpoint))
|
314
|
+
}
|
315
|
+
|
316
|
+
const service = Service.create(`hs-backend-${name}`, {
|
317
|
+
namespace,
|
318
|
+
type: "ClusterIP",
|
319
|
+
ports: ipEndpoints.map(l4EndpointToServicePort),
|
320
|
+
})
|
321
|
+
|
322
|
+
const endpointsName = `hs-backend-${name}`
|
323
|
+
|
324
|
+
new core.v1.Endpoints(
|
325
|
+
endpointsName,
|
326
|
+
{
|
327
|
+
metadata: mapMetadata({ namespace }, endpointsName),
|
328
|
+
subsets: ipEndpoints.map(endpoint => ({
|
329
|
+
addresses: [{ ip: endpoint.address }],
|
330
|
+
ports: [l4EndpointToServicePort(endpoint)],
|
331
|
+
})),
|
332
|
+
},
|
333
|
+
{ ...opts, provider: getProvider(cluster), parent: service },
|
334
|
+
)
|
335
|
+
|
336
|
+
return {
|
337
|
+
service,
|
338
|
+
ports: ipPortInfos,
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
async function getServicePorts(service: Service): Promise<ServicePortInfo[]> {
|
343
|
+
const spec = await toPromise(service.spec)
|
344
|
+
const ports = spec.ports ?? []
|
345
|
+
|
346
|
+
const result: ServicePortInfo[] = []
|
347
|
+
|
348
|
+
for (const port of ports) {
|
349
|
+
const value = port.port
|
350
|
+
const protocol = (port.protocol ?? "TCP").toUpperCase()
|
351
|
+
|
352
|
+
if (value === undefined || (protocol !== "TCP" && protocol !== "UDP")) {
|
353
|
+
continue
|
354
|
+
}
|
355
|
+
|
356
|
+
result.push({
|
357
|
+
name: port.name ?? undefined,
|
358
|
+
port: value,
|
359
|
+
protocol: protocol as "TCP" | "UDP",
|
360
|
+
targetPort: port.targetPort as number | string | undefined,
|
361
|
+
})
|
362
|
+
}
|
363
|
+
|
364
|
+
return result
|
365
|
+
}
|
366
|
+
|
367
|
+
function toServicePortInfoFromEndpoint(endpoint: network.L4Endpoint): ServicePortInfo {
|
368
|
+
return {
|
369
|
+
name: undefined,
|
370
|
+
port: endpoint.port,
|
371
|
+
protocol: endpoint.protocol.toUpperCase() as "TCP" | "UDP",
|
372
|
+
targetPort: endpoint.port,
|
373
|
+
}
|
374
|
+
}
|
375
|
+
|
376
|
+
async function selectBackendPort({
|
377
|
+
ports,
|
378
|
+
protocol,
|
379
|
+
targetPort,
|
380
|
+
serviceName,
|
381
|
+
routeName,
|
382
|
+
}: {
|
383
|
+
ports: ServicePortInfo[]
|
384
|
+
protocol: "TCP" | "UDP"
|
385
|
+
targetPort: Input<string | number | undefined> | undefined
|
386
|
+
serviceName: string
|
387
|
+
routeName: string
|
388
|
+
}): Promise<ServicePortInfo> {
|
389
|
+
const candidates = ports.filter(port => port.protocol === protocol)
|
390
|
+
|
391
|
+
if (candidates.length === 0) {
|
392
|
+
throw new Error(
|
393
|
+
`Service "${serviceName}" does not expose any ${protocol} ports required by gateway route "${routeName}".`,
|
394
|
+
)
|
395
|
+
}
|
396
|
+
|
397
|
+
if (!targetPort) {
|
398
|
+
return candidates[0]
|
399
|
+
}
|
400
|
+
|
401
|
+
const resolvedTarget = await toPromise(targetPort)
|
402
|
+
|
403
|
+
if (resolvedTarget === undefined || resolvedTarget === null) {
|
404
|
+
return candidates[0]
|
405
|
+
}
|
406
|
+
|
407
|
+
if (typeof resolvedTarget === "number") {
|
408
|
+
const match = candidates.find(candidate => {
|
409
|
+
if (candidate.port === resolvedTarget) {
|
410
|
+
return true
|
411
|
+
}
|
412
|
+
|
413
|
+
if (typeof candidate.targetPort === "number") {
|
414
|
+
return candidate.targetPort === resolvedTarget
|
415
|
+
}
|
416
|
+
|
417
|
+
return false
|
418
|
+
})
|
419
|
+
|
420
|
+
if (match) {
|
421
|
+
return match
|
422
|
+
}
|
423
|
+
|
424
|
+
throw new Error(
|
425
|
+
`Gateway route "${routeName}" requested target port ${resolvedTarget}, but service "${serviceName}" does not expose it for ${protocol} backends.`,
|
426
|
+
)
|
427
|
+
}
|
428
|
+
|
429
|
+
const targetString = String(resolvedTarget)
|
430
|
+
|
431
|
+
const match = candidates.find(candidate => {
|
432
|
+
if (candidate.name === targetString) {
|
433
|
+
return true
|
434
|
+
}
|
435
|
+
|
436
|
+
if (typeof candidate.targetPort === "string") {
|
437
|
+
return candidate.targetPort === targetString
|
438
|
+
}
|
439
|
+
|
440
|
+
return false
|
441
|
+
})
|
442
|
+
|
443
|
+
if (match) {
|
444
|
+
return match
|
445
|
+
}
|
446
|
+
|
447
|
+
throw new Error(
|
448
|
+
`Gateway route "${routeName}" requested target port "${targetString}", but service "${serviceName}" does not expose it for ${protocol} backends.`,
|
449
|
+
)
|
450
|
+
}
|
451
|
+
|
452
|
+
async function resolveListenerPort({
|
453
|
+
requestedPort,
|
454
|
+
backendPort,
|
455
|
+
protocol,
|
456
|
+
routeName,
|
457
|
+
}: {
|
458
|
+
requestedPort: Input<number | undefined> | undefined
|
459
|
+
backendPort: ServicePortInfo
|
460
|
+
protocol: "TCP" | "UDP"
|
461
|
+
routeName: string
|
462
|
+
}): Promise<number> {
|
463
|
+
if (!requestedPort) {
|
464
|
+
return backendPort.port
|
465
|
+
}
|
466
|
+
|
467
|
+
const resolved = await toPromise(requestedPort)
|
468
|
+
|
469
|
+
if (resolved === undefined || resolved === null) {
|
470
|
+
return backendPort.port
|
471
|
+
}
|
472
|
+
|
473
|
+
if (!Number.isInteger(resolved)) {
|
474
|
+
throw new Error(
|
475
|
+
`Gateway route "${routeName}" must use integer listener ports for ${protocol.toLowerCase()} traffic.`,
|
476
|
+
)
|
477
|
+
}
|
478
|
+
|
479
|
+
const port = Number(resolved)
|
480
|
+
|
481
|
+
if (port < 1 || port > 65535) {
|
482
|
+
throw new Error(
|
483
|
+
`Gateway route "${routeName}" specified listener port ${port}, which is outside the valid range 1-65535.`,
|
484
|
+
)
|
485
|
+
}
|
486
|
+
|
487
|
+
return port
|
488
|
+
}
|
package/src/index.ts
CHANGED
package/src/job.ts
CHANGED
package/src/stateful-set.ts
CHANGED
@@ -87,6 +87,10 @@ export abstract class StatefulSet extends ExposableWorkload {
|
|
87
87
|
)
|
88
88
|
}
|
89
89
|
|
90
|
+
protected override get templateMetadata(): Output<types.output.meta.v1.ObjectMeta> {
|
91
|
+
return this.spec.template.metadata
|
92
|
+
}
|
93
|
+
|
90
94
|
/**
|
91
95
|
* The Highstate stateful set entity.
|
92
96
|
*/
|
package/src/tls.ts
CHANGED
@@ -30,6 +30,8 @@ export type CreateOrGetCertificateArgs = CertificateArgs & {
|
|
30
30
|
* Represents a cert-manager Certificate resource with metadata and secret.
|
31
31
|
*/
|
32
32
|
export abstract class Certificate extends ComponentResource {
|
33
|
+
private _secret?: Output<Secret>
|
34
|
+
|
33
35
|
protected constructor(
|
34
36
|
type: string,
|
35
37
|
private readonly name: string,
|
@@ -82,7 +84,11 @@ export abstract class Certificate extends ComponentResource {
|
|
82
84
|
* The secret containing the certificate data.
|
83
85
|
*/
|
84
86
|
get secret(): Output<Secret> {
|
85
|
-
|
87
|
+
if (this._secret) {
|
88
|
+
return this._secret
|
89
|
+
}
|
90
|
+
|
91
|
+
this._secret = output({
|
86
92
|
secretName: this.spec.apply(spec => spec.secretName),
|
87
93
|
namespace: this.namespace,
|
88
94
|
}).apply(({ secretName, namespace }) => {
|
@@ -91,6 +97,8 @@ export abstract class Certificate extends ComponentResource {
|
|
91
97
|
namespace,
|
92
98
|
})
|
93
99
|
})
|
100
|
+
|
101
|
+
return this._secret
|
94
102
|
}
|
95
103
|
|
96
104
|
/**
|