@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.
- package/dist/chunk-DQSCJM5S.js +183 -0
- package/dist/chunk-DQSCJM5S.js.map +1 -0
- package/dist/chunk-FKNHHKOL.js +260 -0
- package/dist/chunk-FKNHHKOL.js.map +1 -0
- package/dist/chunk-HW3NS3MC.js +347 -0
- package/dist/chunk-HW3NS3MC.js.map +1 -0
- package/dist/chunk-OQ7UXASD.js +193 -0
- package/dist/chunk-OQ7UXASD.js.map +1 -0
- package/dist/chunk-QGHMLKTW.js +1123 -0
- package/dist/chunk-QGHMLKTW.js.map +1 -0
- package/dist/chunk-UNVSWG6D.js +214 -0
- package/dist/chunk-UNVSWG6D.js.map +1 -0
- package/dist/deployment-ZP3ASKPT.js +10 -0
- package/dist/deployment-ZP3ASKPT.js.map +1 -0
- package/dist/highstate.manifest.json +8 -6
- package/dist/index.js +291 -954
- package/dist/index.js.map +1 -1
- package/dist/stateful-set-2AH7RAF7.js +10 -0
- package/dist/stateful-set-2AH7RAF7.js.map +1 -0
- package/dist/units/access-point/index.js +6 -1
- package/dist/units/access-point/index.js.map +1 -1
- package/dist/units/cert-manager/index.js +19 -24
- package/dist/units/cert-manager/index.js.map +1 -1
- package/dist/units/cluster-dns/index.js +36 -0
- package/dist/units/cluster-dns/index.js.map +1 -0
- package/dist/units/cluster-patch/index.js +34 -0
- package/dist/units/cluster-patch/index.js.map +1 -0
- package/dist/units/dns01-issuer/index.js +2 -2
- package/dist/units/dns01-issuer/index.js.map +1 -1
- package/dist/units/existing-cluster/index.js +22 -14
- package/dist/units/existing-cluster/index.js.map +1 -1
- package/dist/units/gateway-api/index.js +1 -1
- package/package.json +12 -10
- package/src/access-point.ts +44 -39
- package/src/container.ts +54 -5
- package/src/cron-job.ts +14 -30
- package/src/deployment.ts +170 -127
- package/src/gateway/http-route.ts +7 -5
- package/src/helm.ts +57 -8
- package/src/index.ts +11 -4
- package/src/job.ts +14 -32
- package/src/namespace.ts +241 -0
- package/src/network-policy.ts +371 -87
- package/src/network.ts +41 -0
- package/src/pvc.ts +43 -25
- package/src/scripting/bundle.ts +125 -22
- package/src/scripting/container.ts +16 -11
- package/src/scripting/environment.ts +56 -6
- package/src/secret.ts +195 -0
- package/src/service.ts +209 -89
- package/src/shared.ts +42 -51
- package/src/stateful-set.ts +193 -88
- package/src/units/access-point/index.ts +8 -1
- package/src/units/cert-manager/index.ts +15 -20
- package/src/units/cluster-dns/index.ts +37 -0
- package/src/units/cluster-patch/index.ts +35 -0
- package/src/units/dns01-issuer/index.ts +1 -1
- package/src/units/existing-cluster/index.ts +24 -14
- package/src/workload.ts +342 -44
- package/dist/chunk-K4WKJ4L5.js +0 -455
- package/dist/chunk-K4WKJ4L5.js.map +0 -1
- package/dist/chunk-T5Z2M4JE.js +0 -103
- package/dist/chunk-T5Z2M4JE.js.map +0 -1
package/src/secret.ts
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
import type { k8s } from "@highstate/library"
|
2
|
+
import { core, type types } from "@pulumi/kubernetes"
|
3
|
+
import {
|
4
|
+
ComponentResource,
|
5
|
+
output,
|
6
|
+
Output,
|
7
|
+
type ComponentResourceOptions,
|
8
|
+
type Input,
|
9
|
+
type Inputs,
|
10
|
+
} from "@pulumi/pulumi"
|
11
|
+
import { getProvider, mapMetadata, withPatchName, type CommonArgs } from "./shared"
|
12
|
+
|
13
|
+
export type SecretArgs = CommonArgs &
|
14
|
+
Omit<types.input.core.v1.Secret, "kind" | "metadata" | "apiVersion">
|
15
|
+
|
16
|
+
export type CreateOrPatchSecretArgs = SecretArgs & {
|
17
|
+
/**
|
18
|
+
* The resource to use to determine the name of the secret.
|
19
|
+
*
|
20
|
+
* If not provided, the secret will be created, otherwise it will be retrieved/patched.
|
21
|
+
*/
|
22
|
+
existing: Input<k8s.Resource> | undefined
|
23
|
+
}
|
24
|
+
|
25
|
+
export abstract class Secret extends ComponentResource {
|
26
|
+
protected constructor(
|
27
|
+
type: string,
|
28
|
+
name: string,
|
29
|
+
args: Inputs,
|
30
|
+
opts: ComponentResourceOptions | undefined,
|
31
|
+
|
32
|
+
/**
|
33
|
+
* The cluster where the secret is created.
|
34
|
+
*/
|
35
|
+
readonly cluster: Output<k8s.Cluster>,
|
36
|
+
|
37
|
+
/**
|
38
|
+
* The metadata of the underlying Kubernetes secret.
|
39
|
+
*/
|
40
|
+
readonly metadata: Output<types.output.meta.v1.ObjectMeta>,
|
41
|
+
|
42
|
+
/**
|
43
|
+
* The data of the underlying Kubernetes secret.
|
44
|
+
*/
|
45
|
+
readonly data: Output<Record<string, string>>,
|
46
|
+
|
47
|
+
/**
|
48
|
+
* The stringData of the underlying Kubernetes secret.
|
49
|
+
*/
|
50
|
+
readonly stringData: Output<Record<string, string>>,
|
51
|
+
) {
|
52
|
+
super(type, name, args, opts)
|
53
|
+
}
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Creates a new secret.
|
57
|
+
*/
|
58
|
+
static create(name: string, args: SecretArgs, opts?: ComponentResourceOptions): Secret {
|
59
|
+
return new CreatedSecret(name, args, opts)
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Creates a new secret or patches an existing one.
|
64
|
+
*
|
65
|
+
* Will throw an error if the secret does not exist when `args.resource` is provided.
|
66
|
+
*/
|
67
|
+
static createOrPatch(
|
68
|
+
name: string,
|
69
|
+
args: CreateOrPatchSecretArgs,
|
70
|
+
opts?: ComponentResourceOptions,
|
71
|
+
): Secret {
|
72
|
+
if (!args.existing) {
|
73
|
+
return new CreatedSecret(name, args, opts)
|
74
|
+
}
|
75
|
+
|
76
|
+
return new SecretPatch(
|
77
|
+
name,
|
78
|
+
{
|
79
|
+
...args,
|
80
|
+
name: withPatchName("secret", args.existing, args.cluster),
|
81
|
+
namespace: output(args.existing).metadata.namespace,
|
82
|
+
},
|
83
|
+
opts,
|
84
|
+
)
|
85
|
+
}
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Gets an existing secret.
|
89
|
+
*
|
90
|
+
* Will throw an error if the secret does not exist.
|
91
|
+
*/
|
92
|
+
static get(
|
93
|
+
name: string,
|
94
|
+
id: Input<string>,
|
95
|
+
cluster: Input<k8s.Cluster>,
|
96
|
+
opts?: ComponentResourceOptions,
|
97
|
+
): Secret {
|
98
|
+
return new ExternalSecret(name, id, cluster, opts)
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
class CreatedSecret extends Secret {
|
103
|
+
constructor(name: string, args: SecretArgs, opts?: ComponentResourceOptions) {
|
104
|
+
const secret = output(args).apply(async args => {
|
105
|
+
return new core.v1.Secret(
|
106
|
+
name,
|
107
|
+
{
|
108
|
+
metadata: mapMetadata(args, name),
|
109
|
+
data: args.data,
|
110
|
+
stringData: args.stringData,
|
111
|
+
},
|
112
|
+
{
|
113
|
+
...opts,
|
114
|
+
parent: this,
|
115
|
+
provider: await getProvider(args.cluster),
|
116
|
+
},
|
117
|
+
)
|
118
|
+
})
|
119
|
+
|
120
|
+
super(
|
121
|
+
"highstate:k8s:Secret",
|
122
|
+
name,
|
123
|
+
args,
|
124
|
+
opts,
|
125
|
+
output(args.cluster),
|
126
|
+
secret.metadata,
|
127
|
+
secret.data,
|
128
|
+
secret.stringData,
|
129
|
+
)
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
class SecretPatch extends Secret {
|
134
|
+
constructor(name: string, args: SecretArgs, opts?: ComponentResourceOptions) {
|
135
|
+
const secret = output(args).apply(async args => {
|
136
|
+
return new core.v1.SecretPatch(
|
137
|
+
name,
|
138
|
+
{
|
139
|
+
metadata: mapMetadata(args, name),
|
140
|
+
data: args.data,
|
141
|
+
stringData: args.stringData,
|
142
|
+
},
|
143
|
+
{
|
144
|
+
...opts,
|
145
|
+
parent: this,
|
146
|
+
provider: await getProvider(args.cluster),
|
147
|
+
},
|
148
|
+
)
|
149
|
+
})
|
150
|
+
|
151
|
+
super(
|
152
|
+
"highstate:k8s:SecretPatch",
|
153
|
+
name,
|
154
|
+
args,
|
155
|
+
opts,
|
156
|
+
output(args.cluster),
|
157
|
+
secret.metadata,
|
158
|
+
secret.data,
|
159
|
+
secret.stringData,
|
160
|
+
)
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
class ExternalSecret extends Secret {
|
165
|
+
constructor(
|
166
|
+
name: string,
|
167
|
+
id: Input<string>,
|
168
|
+
cluster: Input<k8s.Cluster>,
|
169
|
+
opts?: ComponentResourceOptions,
|
170
|
+
) {
|
171
|
+
const secret = output(id).apply(async realName => {
|
172
|
+
return core.v1.Secret.get(
|
173
|
+
//
|
174
|
+
name,
|
175
|
+
realName,
|
176
|
+
{
|
177
|
+
...opts,
|
178
|
+
parent: this,
|
179
|
+
provider: await getProvider(cluster),
|
180
|
+
},
|
181
|
+
)
|
182
|
+
})
|
183
|
+
|
184
|
+
super(
|
185
|
+
"highstate:k8s:ExternalSecret",
|
186
|
+
name,
|
187
|
+
{ id, cluster },
|
188
|
+
opts,
|
189
|
+
output(cluster),
|
190
|
+
secret.metadata,
|
191
|
+
secret.data,
|
192
|
+
secret.stringData,
|
193
|
+
)
|
194
|
+
}
|
195
|
+
}
|
package/src/service.ts
CHANGED
@@ -1,43 +1,109 @@
|
|
1
|
-
import type { k8s } from "@highstate/library"
|
1
|
+
import type { k8s, network } from "@highstate/library"
|
2
2
|
import { core, types } from "@pulumi/kubernetes"
|
3
3
|
import {
|
4
4
|
ComponentResource,
|
5
|
-
interpolate,
|
6
5
|
normalize,
|
7
6
|
output,
|
8
7
|
Output,
|
9
|
-
Resource,
|
10
8
|
type ComponentResourceOptions,
|
11
9
|
type Input,
|
12
|
-
type InputArray,
|
13
10
|
type Inputs,
|
14
11
|
} from "@highstate/pulumi"
|
15
|
-
import { omit } from "remeda"
|
12
|
+
import { omit, uniqueBy } from "remeda"
|
16
13
|
import { deepmerge } from "deepmerge-ts"
|
14
|
+
import { filterEndpoints, l4EndpointToString, parseL3Endpoint } from "@highstate/common"
|
17
15
|
import {
|
18
16
|
commonExtraArgs,
|
19
17
|
mapMetadata,
|
20
18
|
resourceIdToString,
|
21
|
-
verifyProvider,
|
22
19
|
type CommonArgs,
|
23
20
|
type ResourceId,
|
21
|
+
type SelectorLike,
|
24
22
|
} from "./shared"
|
25
23
|
|
26
24
|
export type ServiceArgs = CommonArgs & {
|
27
|
-
port?: Input<types.input.core.v1.ServicePort>
|
28
|
-
|
29
25
|
/**
|
30
|
-
* The
|
26
|
+
* The port to expose the service on.
|
31
27
|
*/
|
32
|
-
|
28
|
+
port?: Input<types.input.core.v1.ServicePort>
|
33
29
|
|
34
30
|
/**
|
35
|
-
*
|
31
|
+
* Whether the service should be exposed by `NodePort` or `LoadBalancer`.
|
32
|
+
*
|
33
|
+
* The type of the service will be determined automatically based on the cluster.
|
36
34
|
*/
|
37
|
-
|
35
|
+
external?: boolean
|
38
36
|
} & types.input.core.v1.ServiceSpec
|
39
37
|
|
40
|
-
const serviceExtraArgs = [...commonExtraArgs, "port", "ports", "
|
38
|
+
const serviceExtraArgs = [...commonExtraArgs, "port", "ports", "external"] as const
|
39
|
+
|
40
|
+
export type ServiceEndpointMetadata = {
|
41
|
+
clusterId: string
|
42
|
+
name: string
|
43
|
+
namespace: string
|
44
|
+
selector: SelectorLike
|
45
|
+
targetPort: string | number
|
46
|
+
}
|
47
|
+
|
48
|
+
/**
|
49
|
+
* Checks if the endpoint has service metadata.
|
50
|
+
*
|
51
|
+
* Alters the type of the endpoint to include the service metadata if it exists.
|
52
|
+
*
|
53
|
+
* @param endpoint The endpoint to check.
|
54
|
+
* @returns True if the endpoint has service metadata, false otherwise.
|
55
|
+
*/
|
56
|
+
export function hasServiceMetadata(
|
57
|
+
endpoint: network.L3Endpoint,
|
58
|
+
): endpoint is network.L3Endpoint & { metadata: { k8sService: ServiceEndpointMetadata } } {
|
59
|
+
return endpoint.metadata?.k8sService !== undefined
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Returns the service metadata of the endpoint.
|
64
|
+
*
|
65
|
+
* @param endpoint The endpoint to get the service metadata from.
|
66
|
+
* @returns The service metadata of the endpoint, or undefined if it doesn't exist.
|
67
|
+
*/
|
68
|
+
export function getServiceMetadata(
|
69
|
+
endpoint: network.L3Endpoint,
|
70
|
+
): ServiceEndpointMetadata | undefined {
|
71
|
+
return endpoint.metadata?.k8sService as ServiceEndpointMetadata
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Adds service metadata to the endpoint.
|
76
|
+
*
|
77
|
+
* @param endpoint The endpoint to add the metadata to.
|
78
|
+
* @param metadata The metadata to add.
|
79
|
+
* @returns The endpoint with the added metadata.
|
80
|
+
*/
|
81
|
+
export function withServiceMetadata<TEdnpoint extends network.L34Endpoint>(
|
82
|
+
endpoint: TEdnpoint,
|
83
|
+
metadata: ServiceEndpointMetadata,
|
84
|
+
): TEdnpoint & { metadata: { k8sService: ServiceEndpointMetadata } } {
|
85
|
+
return {
|
86
|
+
...endpoint,
|
87
|
+
metadata: {
|
88
|
+
...endpoint.metadata,
|
89
|
+
k8sService: metadata,
|
90
|
+
},
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
/**
|
95
|
+
* Checks if the endpoint is from the given cluster.
|
96
|
+
*
|
97
|
+
* @param endpoint The endpoint to check.
|
98
|
+
* @param cluster The cluster to check against.
|
99
|
+
* @returns True if the endpoint is from the cluster, false otherwise.
|
100
|
+
*/
|
101
|
+
export function isFromCluster(
|
102
|
+
endpoint: network.L3Endpoint,
|
103
|
+
cluster: k8s.Cluster,
|
104
|
+
): endpoint is network.L3Endpoint & { metadata: { k8sService: ServiceEndpointMetadata } } {
|
105
|
+
return getServiceMetadata(endpoint)?.clusterId === cluster.id
|
106
|
+
}
|
41
107
|
|
42
108
|
export abstract class Service extends ComponentResource {
|
43
109
|
protected constructor(
|
@@ -49,7 +115,7 @@ export abstract class Service extends ComponentResource {
|
|
49
115
|
/**
|
50
116
|
* The cluster info associated with the service.
|
51
117
|
*/
|
52
|
-
readonly
|
118
|
+
readonly cluster: Output<k8s.Cluster>,
|
53
119
|
|
54
120
|
/**
|
55
121
|
* The metadata of the underlying Kubernetes service.
|
@@ -65,11 +131,6 @@ export abstract class Service extends ComponentResource {
|
|
65
131
|
* The status of the underlying Kubernetes service.
|
66
132
|
*/
|
67
133
|
readonly status: Output<types.output.core.v1.ServiceStatus>,
|
68
|
-
|
69
|
-
/**
|
70
|
-
* The resources associated with the service.
|
71
|
-
*/
|
72
|
-
readonly resources: InputArray<Resource>,
|
73
134
|
) {
|
74
135
|
super(type, name, args, opts)
|
75
136
|
}
|
@@ -80,9 +141,9 @@ export abstract class Service extends ComponentResource {
|
|
80
141
|
get entity(): Output<k8s.Service> {
|
81
142
|
return output({
|
82
143
|
type: "k8s.service",
|
83
|
-
|
144
|
+
clusterId: this.cluster.id,
|
84
145
|
metadata: this.metadata,
|
85
|
-
|
146
|
+
endpoints: this.endpoints,
|
86
147
|
})
|
87
148
|
}
|
88
149
|
|
@@ -93,94 +154,143 @@ export abstract class Service extends ComponentResource {
|
|
93
154
|
static wrap(
|
94
155
|
name: string,
|
95
156
|
service: Input<core.v1.Service>,
|
96
|
-
|
157
|
+
cluster: Input<k8s.Cluster>,
|
97
158
|
opts: ComponentResourceOptions,
|
98
159
|
): Service {
|
99
|
-
return new WrappedService(name, service,
|
160
|
+
return new WrappedService(name, service, cluster, opts)
|
100
161
|
}
|
101
162
|
|
102
163
|
static external(
|
103
164
|
name: string,
|
104
165
|
id: ResourceId,
|
105
|
-
|
166
|
+
cluster: Input<k8s.Cluster>,
|
106
167
|
opts: ComponentResourceOptions,
|
107
168
|
): Service {
|
108
|
-
return new ExternalService(name, id,
|
169
|
+
return new ExternalService(name, id, cluster, opts)
|
109
170
|
}
|
110
171
|
|
111
|
-
static of(
|
112
|
-
|
113
|
-
|
172
|
+
static of(
|
173
|
+
name: string,
|
174
|
+
entity: Input<k8s.Service>,
|
175
|
+
cluster: Input<k8s.Cluster>,
|
176
|
+
opts: ComponentResourceOptions,
|
177
|
+
): Service {
|
178
|
+
return new ExternalService(
|
179
|
+
name,
|
180
|
+
output(entity).metadata,
|
181
|
+
output({ cluster, entity }).apply(({ cluster, entity }) => {
|
182
|
+
if (cluster.id !== entity.clusterId) {
|
183
|
+
throw new Error(
|
184
|
+
`Cluster mismatch when wrapping service "${name}": "${cluster.id}" != "${entity.clusterId}"`,
|
185
|
+
)
|
186
|
+
}
|
114
187
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
*/
|
120
|
-
get clusterHost(): Output<string> {
|
121
|
-
return interpolate`${this.metadata.name}.${this.metadata.namespace}.svc`
|
188
|
+
return cluster
|
189
|
+
}),
|
190
|
+
opts,
|
191
|
+
)
|
122
192
|
}
|
123
193
|
|
124
194
|
/**
|
125
|
-
* Returns the
|
195
|
+
* Returns the endpoints of the service applying the given filter.
|
126
196
|
*
|
127
|
-
* If
|
197
|
+
* If no filter is specified, the default behavior of `filterEndpoints` is used.
|
128
198
|
*
|
129
|
-
* If the
|
199
|
+
* @param filter If specified, the endpoints are filtered based on the given filter.
|
200
|
+
* @returns The endpoints of the service.
|
130
201
|
*/
|
131
|
-
|
132
|
-
return output({
|
133
|
-
|
134
|
-
if (loadBalancerIp) {
|
135
|
-
return loadBalancerIp
|
136
|
-
}
|
137
|
-
|
138
|
-
const nodeIp = spec.externalIPs?.[0]
|
139
|
-
if (nodeIp) {
|
140
|
-
return nodeIp
|
141
|
-
}
|
142
|
-
|
143
|
-
return undefined
|
202
|
+
filterEndpoints(filter?: network.EndpointFilter): Output<network.L4Endpoint[]> {
|
203
|
+
return output({ endpoints: this.endpoints }).apply(({ endpoints }) => {
|
204
|
+
return filterEndpoints(endpoints, filter)
|
144
205
|
})
|
145
206
|
}
|
146
207
|
|
147
208
|
/**
|
148
|
-
*
|
149
|
-
*
|
150
|
-
* Resolves to the external IP if available, otherwise the cluster IP.
|
151
|
-
*
|
152
|
-
* If the service is headless, an error is thrown.
|
209
|
+
* Returns the endpoints of the service including both internal and external endpoints.
|
153
210
|
*/
|
154
|
-
get
|
155
|
-
return output({
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
211
|
+
get endpoints(): Output<network.L4Endpoint[]> {
|
212
|
+
return output({
|
213
|
+
clusterId: this.cluster.id,
|
214
|
+
metadata: this.metadata,
|
215
|
+
spec: this.spec,
|
216
|
+
status: this.status,
|
217
|
+
}).apply(({ clusterId, metadata, spec, status }) => {
|
218
|
+
const endpointMetadata = {
|
219
|
+
k8sService: {
|
220
|
+
clusterId,
|
221
|
+
name: metadata.name,
|
222
|
+
namespace: metadata.namespace,
|
223
|
+
selector: spec.selector,
|
224
|
+
targetPort: spec.ports[0].targetPort ?? spec.ports[0].port,
|
225
|
+
},
|
226
|
+
}
|
160
227
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
228
|
+
const clusterIpEndpoints = spec.clusterIPs?.map(ip => ({
|
229
|
+
...parseL3Endpoint(ip),
|
230
|
+
port: spec.ports[0].port,
|
231
|
+
protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,
|
232
|
+
metadata: endpointMetadata,
|
233
|
+
}))
|
234
|
+
|
235
|
+
if (clusterIpEndpoints.length > 0) {
|
236
|
+
clusterIpEndpoints.unshift({
|
237
|
+
type: "hostname",
|
238
|
+
visibility: "internal",
|
239
|
+
hostname: `${metadata.name}.${metadata.namespace}.svc.cluster.local`,
|
240
|
+
port: spec.ports[0].port,
|
241
|
+
protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,
|
242
|
+
metadata: endpointMetadata,
|
243
|
+
})
|
244
|
+
}
|
165
245
|
|
166
|
-
|
167
|
-
|
168
|
-
|
246
|
+
const nodePortEndpoints =
|
247
|
+
spec.type === "NodePort"
|
248
|
+
? spec.externalIPs?.map(ip => ({
|
249
|
+
...parseL3Endpoint(ip),
|
250
|
+
port: spec.ports[0].nodePort,
|
251
|
+
protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,
|
252
|
+
metadata: endpointMetadata,
|
253
|
+
}))
|
254
|
+
: []
|
255
|
+
|
256
|
+
const loadBalancerEndpoints =
|
257
|
+
spec.type === "LoadBalancer"
|
258
|
+
? status.loadBalancer?.ingress?.map(endpoint => ({
|
259
|
+
...parseL3Endpoint(endpoint.ip ?? endpoint.hostname),
|
260
|
+
port: spec.ports[0].port,
|
261
|
+
protocol: spec.ports[0].protocol?.toLowerCase() as network.L4Protocol,
|
262
|
+
metadata: endpointMetadata,
|
263
|
+
}))
|
264
|
+
: []
|
265
|
+
|
266
|
+
return uniqueBy(
|
267
|
+
[
|
268
|
+
...(clusterIpEndpoints ?? []),
|
269
|
+
...(loadBalancerEndpoints ?? []),
|
270
|
+
...(nodePortEndpoints ?? []),
|
271
|
+
],
|
272
|
+
endpoint => l4EndpointToString(endpoint),
|
273
|
+
)
|
274
|
+
})
|
169
275
|
}
|
170
276
|
}
|
171
277
|
|
172
278
|
class CreatedService extends Service {
|
173
279
|
constructor(name: string, args: ServiceArgs, opts: ComponentResourceOptions) {
|
174
|
-
const service = output(args).apply(
|
175
|
-
|
176
|
-
|
177
|
-
return new (args.patch ? core.v1.ServicePatch : core.v1.Service)(
|
280
|
+
const service = output(args).apply(args => {
|
281
|
+
return new core.v1.Service(
|
178
282
|
name,
|
179
283
|
{
|
180
|
-
metadata: mapMetadata(args
|
284
|
+
metadata: mapMetadata(args, name),
|
181
285
|
spec: deepmerge(
|
182
286
|
{
|
183
287
|
ports: normalize(args.port, args.ports),
|
288
|
+
|
289
|
+
externalIPs: args.external
|
290
|
+
? (args.externalIPs ?? args.cluster.externalIps)
|
291
|
+
: args.cluster.externalIps,
|
292
|
+
|
293
|
+
type: getServiceType(args, args.cluster),
|
184
294
|
},
|
185
295
|
omit(args, serviceExtraArgs),
|
186
296
|
),
|
@@ -195,11 +305,10 @@ class CreatedService extends Service {
|
|
195
305
|
args,
|
196
306
|
opts,
|
197
307
|
|
198
|
-
output(args.cluster)
|
308
|
+
output(args.cluster),
|
199
309
|
service.metadata,
|
200
310
|
service.spec,
|
201
311
|
service.status,
|
202
|
-
[service],
|
203
312
|
)
|
204
313
|
}
|
205
314
|
}
|
@@ -208,20 +317,19 @@ class WrappedService extends Service {
|
|
208
317
|
constructor(
|
209
318
|
name: string,
|
210
319
|
service: Input<core.v1.Service>,
|
211
|
-
|
320
|
+
cluster: Input<k8s.Cluster>,
|
212
321
|
opts: ComponentResourceOptions,
|
213
322
|
) {
|
214
323
|
super(
|
215
324
|
"highstate:k8s:WrappedService",
|
216
325
|
name,
|
217
|
-
{ service, clusterInfo },
|
326
|
+
{ service, clusterInfo: cluster },
|
218
327
|
opts,
|
219
328
|
|
220
|
-
output(
|
329
|
+
output(cluster),
|
221
330
|
output(service).metadata,
|
222
331
|
output(service).spec,
|
223
332
|
output(service).status,
|
224
|
-
[service],
|
225
333
|
)
|
226
334
|
}
|
227
335
|
}
|
@@ -229,32 +337,29 @@ class WrappedService extends Service {
|
|
229
337
|
class ExternalService extends Service {
|
230
338
|
constructor(
|
231
339
|
name: string,
|
232
|
-
id: ResourceId
|
233
|
-
|
340
|
+
id: Input<ResourceId>,
|
341
|
+
cluster: Input<k8s.Cluster>,
|
234
342
|
opts: ComponentResourceOptions,
|
235
343
|
) {
|
236
|
-
const service = output(id).apply(
|
237
|
-
await verifyProvider(opts.provider, this.clusterInfo)
|
238
|
-
|
344
|
+
const service = output(id).apply(id => {
|
239
345
|
return core.v1.Service.get(
|
240
346
|
//
|
241
347
|
name,
|
242
348
|
resourceIdToString(id),
|
243
|
-
{ parent: this
|
349
|
+
{ ...opts, parent: this },
|
244
350
|
)
|
245
351
|
})
|
246
352
|
|
247
353
|
super(
|
248
354
|
"highstate:k8s:ExternalService",
|
249
355
|
name,
|
250
|
-
{ id,
|
356
|
+
{ id, cluster },
|
251
357
|
opts,
|
252
358
|
|
253
|
-
output(
|
359
|
+
output(cluster),
|
254
360
|
service.metadata,
|
255
361
|
service.spec,
|
256
362
|
service.status,
|
257
|
-
[service],
|
258
363
|
)
|
259
364
|
}
|
260
365
|
}
|
@@ -277,3 +382,18 @@ export function mapServiceToLabelSelector(
|
|
277
382
|
matchLabels: service.spec.selector,
|
278
383
|
}
|
279
384
|
}
|
385
|
+
|
386
|
+
export function getServiceType(
|
387
|
+
service: Pick<ServiceArgs, "type" | "external"> | undefined,
|
388
|
+
cluster: k8s.Cluster,
|
389
|
+
): Input<string> {
|
390
|
+
if (service?.type) {
|
391
|
+
return service.type
|
392
|
+
}
|
393
|
+
|
394
|
+
if (!service?.external) {
|
395
|
+
return "ClusterIP"
|
396
|
+
}
|
397
|
+
|
398
|
+
return cluster.quirks?.externalServiceType === "LoadBalancer" ? "LoadBalancer" : "NodePort"
|
399
|
+
}
|