@highstate/common 0.9.16 → 0.9.19
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-HZBJ6LLS.js → chunk-WDYIUWYZ.js} +659 -267
- package/dist/chunk-WDYIUWYZ.js.map +1 -0
- package/dist/highstate.manifest.json +12 -8
- package/dist/index.js +1 -1
- package/dist/units/access-point/index.js +16 -0
- package/dist/units/access-point/index.js.map +1 -0
- package/dist/units/databases/existing-mariadb/index.js +17 -0
- package/dist/units/databases/existing-mariadb/index.js.map +1 -0
- package/dist/units/databases/existing-mongodb/index.js +17 -0
- package/dist/units/databases/existing-mongodb/index.js.map +1 -0
- package/dist/units/databases/existing-postgresql/index.js +17 -0
- package/dist/units/databases/existing-postgresql/index.js.map +1 -0
- package/dist/units/dns/record-set/index.js +22 -11
- package/dist/units/dns/record-set/index.js.map +1 -1
- package/dist/units/existing-server/index.js +12 -12
- package/dist/units/existing-server/index.js.map +1 -1
- package/dist/units/network/l3-endpoint/index.js +1 -1
- package/dist/units/network/l3-endpoint/index.js.map +1 -1
- package/dist/units/network/l4-endpoint/index.js +1 -1
- package/dist/units/network/l4-endpoint/index.js.map +1 -1
- package/dist/units/script/index.js +1 -1
- package/dist/units/script/index.js.map +1 -1
- package/dist/units/server-dns/index.js +1 -1
- package/dist/units/server-dns/index.js.map +1 -1
- package/dist/units/server-patch/index.js +1 -1
- package/dist/units/server-patch/index.js.map +1 -1
- package/dist/units/ssh/key-pair/index.js +6 -6
- package/dist/units/ssh/key-pair/index.js.map +1 -1
- package/package.json +61 -8
- package/src/shared/access-point.ts +110 -0
- package/src/shared/command.ts +310 -69
- package/src/shared/dns.ts +150 -90
- package/src/shared/files.ts +34 -34
- package/src/shared/gateway.ts +117 -0
- package/src/shared/impl-ref.ts +123 -0
- package/src/shared/index.ts +4 -0
- package/src/shared/network.ts +41 -27
- package/src/shared/passwords.ts +38 -2
- package/src/shared/ssh.ts +261 -126
- package/src/shared/tls.ts +123 -0
- package/src/units/access-point/index.ts +12 -0
- package/src/units/databases/existing-mariadb/index.ts +14 -0
- package/src/units/databases/existing-mongodb/index.ts +14 -0
- package/src/units/databases/existing-postgresql/index.ts +14 -0
- package/src/units/dns/record-set/index.ts +21 -11
- package/src/units/existing-server/index.ts +12 -17
- package/src/units/ssh/key-pair/index.ts +6 -6
- package/dist/chunk-HZBJ6LLS.js.map +0 -1
package/src/shared/ssh.ts
CHANGED
@@ -1,93 +1,96 @@
|
|
1
|
-
import
|
1
|
+
import { stripNullish, type UnitTerminal } from "@highstate/contract"
|
2
|
+
import type { ssh, common, network } from "@highstate/library"
|
2
3
|
import {
|
3
|
-
|
4
|
+
fileFromString,
|
4
5
|
output,
|
5
|
-
Output,
|
6
|
+
type Output,
|
6
7
|
secret,
|
8
|
+
toPromise,
|
7
9
|
type Input,
|
8
|
-
type InstanceTerminal,
|
9
10
|
} from "@highstate/pulumi"
|
10
11
|
import getKeys, { PrivateExport } from "micro-key-producer/ssh.js"
|
11
12
|
import { randomBytes } from "micro-key-producer/utils.js"
|
12
|
-
import {
|
13
|
+
import { remote } from "@pulumi/command"
|
13
14
|
import * as images from "../../assets/images.json"
|
14
|
-
import { l3EndpointToString,
|
15
|
+
import { l3EndpointToString, l3EndpointToL4 } from "./network"
|
16
|
+
import { Command } from "./command"
|
15
17
|
|
16
|
-
export function createSshTerminal(
|
17
|
-
credentials: Input<ssh.
|
18
|
-
): Output<
|
19
|
-
|
20
|
-
if (!credentials) {
|
21
|
-
return undefined
|
22
|
-
}
|
18
|
+
export async function createSshTerminal(
|
19
|
+
credentials: Input<ssh.Connection>,
|
20
|
+
): Promise<Output<UnitTerminal>> {
|
21
|
+
const resolvedCredentials = await toPromise(credentials)
|
23
22
|
|
24
|
-
|
23
|
+
const command = ["ssh", "-tt", "-o", "UserKnownHostsFile=/known_hosts"]
|
25
24
|
|
26
|
-
|
27
|
-
|
25
|
+
// TODO: select best endpoint based on the environment
|
26
|
+
const endpoint = resolvedCredentials.endpoints[0]
|
28
27
|
|
29
|
-
|
28
|
+
command.push("-p", endpoint.port.toString())
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
if (resolvedCredentials.keyPair) {
|
31
|
+
command.push("-i", "/private_key")
|
32
|
+
}
|
34
33
|
|
35
|
-
|
34
|
+
command.push(`${resolvedCredentials.user}@${l3EndpointToString(endpoint)}`)
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
if (resolvedCredentials.password) {
|
37
|
+
command.unshift("sshpass", "-f", "/password")
|
38
|
+
}
|
40
39
|
|
41
|
-
|
42
|
-
|
40
|
+
return output({
|
41
|
+
name: "ssh",
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
meta: {
|
44
|
+
title: "Shell",
|
45
|
+
description: "Connect to the server via SSH.",
|
46
|
+
icon: "gg:remote",
|
47
|
+
},
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
spec: {
|
50
|
+
image: images["terminal-ssh"].image,
|
51
|
+
command,
|
53
52
|
|
54
|
-
|
55
|
-
|
53
|
+
files: stripNullish({
|
54
|
+
"/password": resolvedCredentials.password
|
55
|
+
? fileFromString("password", resolvedCredentials.password, { isSecret: true })
|
56
|
+
: undefined,
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
value: credentials.keyPair?.privateKey,
|
61
|
-
},
|
62
|
-
meta: {
|
63
|
-
name: "private_key",
|
58
|
+
"/private_key": resolvedCredentials.keyPair?.privateKey
|
59
|
+
? fileFromString("private_key", resolvedCredentials.keyPair.privateKey, {
|
60
|
+
isSecret: true,
|
64
61
|
mode: 0o600,
|
65
|
-
}
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
mode: 0o644,
|
76
|
-
},
|
77
|
-
},
|
78
|
-
},
|
79
|
-
},
|
80
|
-
} satisfies InstanceTerminal
|
62
|
+
})
|
63
|
+
: undefined,
|
64
|
+
|
65
|
+
"/known_hosts": fileFromString(
|
66
|
+
"known_hosts",
|
67
|
+
`${l3EndpointToString(endpoint)} ${resolvedCredentials.hostKey}`,
|
68
|
+
{ mode: 0o644 },
|
69
|
+
),
|
70
|
+
}),
|
71
|
+
},
|
81
72
|
})
|
82
73
|
}
|
83
74
|
|
84
|
-
|
75
|
+
/**
|
76
|
+
* Generates a secure random SSH private key.
|
77
|
+
* The key is generated using the Ed25519 algorithm.
|
78
|
+
*
|
79
|
+
* @returns The generated SSH private key in PEM format.
|
80
|
+
*/
|
81
|
+
export function generateSshPrivateKey(): Output<string> {
|
85
82
|
const seed = randomBytes(32)
|
86
83
|
|
87
|
-
return getKeys(seed).privateKey
|
84
|
+
return secret(getKeys(seed).privateKey)
|
88
85
|
}
|
89
86
|
|
90
|
-
|
87
|
+
/**
|
88
|
+
* Converts a private SSH key string to a KeyPair object.
|
89
|
+
*
|
90
|
+
* @param privateKeyString The private key string to convert.
|
91
|
+
* @returns An Output of the KeyPair object.
|
92
|
+
*/
|
93
|
+
export function sshPrivateKeyToKeyPair(privateKeyString: Input<string>): Output<ssh.KeyPair> {
|
91
94
|
return output(privateKeyString).apply(privateKeyString => {
|
92
95
|
const privateKeyStruct = PrivateExport.decode(privateKeyString)
|
93
96
|
|
@@ -105,87 +108,219 @@ export function privateKeyToKeyPair(privateKeyString: Input<string>): Output<ssh
|
|
105
108
|
})
|
106
109
|
}
|
107
110
|
|
108
|
-
export type
|
111
|
+
export type ServerOptions = {
|
112
|
+
/**
|
113
|
+
* The local name of the server to namespace resources.
|
114
|
+
*/
|
115
|
+
name: string
|
116
|
+
|
117
|
+
/**
|
118
|
+
* The fallback hostname to use if the server cannot be determined.
|
119
|
+
*
|
120
|
+
* If not provided, the `name` will be used as the fallback hostname.
|
121
|
+
*/
|
122
|
+
fallbackHostname?: string
|
123
|
+
|
124
|
+
/**
|
125
|
+
* The L3 endpoints of the server.
|
126
|
+
*/
|
127
|
+
endpoints: network.L3Endpoint[]
|
128
|
+
|
129
|
+
/**
|
130
|
+
* The arguments for the SSH connection.
|
131
|
+
*/
|
132
|
+
sshArgs?: Partial<ssh.Args>
|
133
|
+
|
134
|
+
/**
|
135
|
+
* The password for the SSH connection.
|
136
|
+
*/
|
137
|
+
sshPassword?: Input<string>
|
138
|
+
|
139
|
+
/**
|
140
|
+
* The private key for the SSH connection.
|
141
|
+
*/
|
142
|
+
sshPrivateKey?: Input<string>
|
143
|
+
|
144
|
+
/**
|
145
|
+
* The SSH key pair for the server.
|
146
|
+
* If provided, it will take precedence over the `sshPrivateKey` argument.
|
147
|
+
*/
|
109
148
|
sshKeyPair?: Input<ssh.KeyPair>
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Whether to wait for the server to respond to a ping command before returning.
|
152
|
+
*
|
153
|
+
* If true, the command will wait for a successful ping response before proceeding.
|
154
|
+
*
|
155
|
+
* By default, this is equal to `!waitForSsh`, so when `waitForSsh` is true, no extra ping is performed.
|
156
|
+
*/
|
157
|
+
waitForPing?: boolean
|
158
|
+
|
159
|
+
/**
|
160
|
+
* The interval in seconds to wait between ping attempts.
|
161
|
+
*
|
162
|
+
* Only used if `waitForPing` is true.
|
163
|
+
* By default, it will wait 5 seconds between attempts.
|
164
|
+
*/
|
165
|
+
pingInterval?: number
|
166
|
+
|
167
|
+
/**
|
168
|
+
* The timeout in seconds to wait for the server to respond to a ping command.
|
169
|
+
*
|
170
|
+
* Only used if `waitForPing` is true.
|
171
|
+
* By default, it will wait 5 minutes (300 seconds) before timing out.
|
172
|
+
*/
|
173
|
+
pingTimeout?: number
|
174
|
+
|
175
|
+
/**
|
176
|
+
* Whether to wait for the SSH service to be available before returning.
|
177
|
+
*
|
178
|
+
* If true, the command will wait for the SSH service to respond before proceeding.
|
179
|
+
*
|
180
|
+
* By default, this is true if `sshArgs.enabled` is true, otherwise false.
|
181
|
+
*/
|
182
|
+
waitForSsh?: boolean
|
183
|
+
|
184
|
+
/**
|
185
|
+
* The interval in seconds to wait between SSH connection attempts.
|
186
|
+
*
|
187
|
+
* Only used if `waitForSsh` is true.
|
188
|
+
* By default, it will wait 5 seconds between attempts.
|
189
|
+
*/
|
190
|
+
sshCheckInterval?: number
|
191
|
+
|
192
|
+
/**
|
193
|
+
* The timeout in seconds to wait for the SSH service to respond.
|
194
|
+
*
|
195
|
+
* Only used if `waitForSsh` is true.
|
196
|
+
* By default, it will wait 5 minutes (300 seconds) before timing out.
|
197
|
+
*/
|
198
|
+
sshCheckTimeout?: number
|
110
199
|
}
|
111
200
|
|
112
|
-
export type
|
113
|
-
|
201
|
+
export type ServerBundle = {
|
202
|
+
/**
|
203
|
+
* The server entity created with the provided options.
|
204
|
+
*/
|
205
|
+
server: Output<common.Server>
|
206
|
+
|
207
|
+
/**
|
208
|
+
* The SSH terminal created for the server.
|
209
|
+
*/
|
210
|
+
terminal?: Output<UnitTerminal>
|
114
211
|
}
|
115
212
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
213
|
+
/**
|
214
|
+
* Creates a server entity with the provided options and returns a bundle containing the server entity and terminal.
|
215
|
+
*
|
216
|
+
* Basically, it just a convenience function that calls `createServerEntity` and `createSshTerminal`.
|
217
|
+
*
|
218
|
+
* @param options The options for creating the server entity.
|
219
|
+
* @returns A promise that resolves to a ServerBundle containing the server entity and terminal.
|
220
|
+
*/
|
221
|
+
export async function createServerBundle(options: ServerOptions): Promise<ServerBundle> {
|
222
|
+
const server = await createServerEntity(options)
|
223
|
+
const ssh = await toPromise(server.ssh)
|
224
|
+
|
225
|
+
return {
|
226
|
+
server,
|
227
|
+
terminal: ssh ? await createSshTerminal(ssh) : undefined,
|
122
228
|
}
|
229
|
+
}
|
123
230
|
|
124
|
-
|
231
|
+
/**
|
232
|
+
* Creates a server entity with the provided options.
|
233
|
+
* It will create a command to check the SSH service and return the server entity.
|
234
|
+
*
|
235
|
+
* @param options The options for creating the server entity.
|
236
|
+
* @returns A promise that resolves to the created server entity.
|
237
|
+
*/
|
238
|
+
export async function createServerEntity({
|
239
|
+
name,
|
240
|
+
fallbackHostname,
|
241
|
+
endpoints,
|
242
|
+
sshArgs = { enabled: true, port: 22, user: "root" },
|
243
|
+
sshPassword,
|
244
|
+
sshPrivateKey,
|
245
|
+
sshKeyPair,
|
246
|
+
pingInterval,
|
247
|
+
pingTimeout,
|
248
|
+
waitForPing,
|
249
|
+
waitForSsh,
|
250
|
+
sshCheckInterval,
|
251
|
+
sshCheckTimeout,
|
252
|
+
}: ServerOptions): Promise<Output<common.Server>> {
|
253
|
+
if (endpoints.length === 0) {
|
254
|
+
throw new Error("At least one L3 endpoint is required to create a server entity")
|
255
|
+
}
|
125
256
|
|
126
|
-
|
127
|
-
|
257
|
+
fallbackHostname ??= name
|
258
|
+
waitForSsh ??= sshArgs.enabled
|
259
|
+
waitForPing ??= !waitForSsh
|
128
260
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
const connection = output({
|
139
|
-
host: l3EndpointToString(endpoint),
|
140
|
-
port: sshPort,
|
141
|
-
user: sshUser,
|
142
|
-
password: sshPassword,
|
143
|
-
privateKey: sshPrivateKey,
|
144
|
-
dialErrorLimit: 3,
|
145
|
-
})
|
261
|
+
if (waitForPing) {
|
262
|
+
await Command.waitFor(`${name}.ping`, {
|
263
|
+
host: "local",
|
264
|
+
create: `ping -c 1 ${l3EndpointToString(endpoints[0])}`,
|
265
|
+
timeout: pingTimeout ?? 300,
|
266
|
+
interval: pingInterval ?? 5,
|
267
|
+
triggers: [Date.now()],
|
268
|
+
}).wait()
|
269
|
+
}
|
146
270
|
|
147
|
-
if (!
|
271
|
+
if (!sshArgs.enabled) {
|
148
272
|
return output({
|
149
|
-
hostname:
|
150
|
-
endpoints
|
273
|
+
hostname: name,
|
274
|
+
endpoints,
|
151
275
|
})
|
152
276
|
}
|
153
277
|
|
154
|
-
const
|
155
|
-
create: `nc -zv ${l3EndpointToString(endpoint)} ${sshPort} && echo "up" || echo "down"`,
|
156
|
-
triggers: [Date.now()],
|
157
|
-
})
|
278
|
+
const sshHost = sshArgs?.host ?? l3EndpointToString(endpoints[0])
|
158
279
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
}
|
166
|
-
|
167
|
-
const hostnameResult = new remote.Command("hostname", {
|
168
|
-
connection,
|
169
|
-
create: "hostname",
|
280
|
+
if (waitForSsh) {
|
281
|
+
await Command.waitFor(`${name}.ssh`, {
|
282
|
+
host: "local",
|
283
|
+
create: `nc -zv ${sshHost} ${sshArgs.port}`,
|
284
|
+
timeout: sshCheckTimeout ?? 300,
|
285
|
+
interval: sshCheckInterval ?? 5,
|
170
286
|
triggers: [Date.now()],
|
171
|
-
})
|
287
|
+
}).wait()
|
288
|
+
}
|
172
289
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
290
|
+
const connection = output({
|
291
|
+
host: sshHost,
|
292
|
+
port: sshArgs.port,
|
293
|
+
user: sshArgs.user,
|
294
|
+
password: sshPassword,
|
295
|
+
privateKey: sshKeyPair ? output(sshKeyPair).privateKey : sshPrivateKey,
|
296
|
+
dialErrorLimit: 3,
|
297
|
+
})
|
178
298
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
299
|
+
const hostnameResult = new remote.Command("hostname", {
|
300
|
+
connection,
|
301
|
+
create: "hostname",
|
302
|
+
triggers: [Date.now()],
|
303
|
+
})
|
304
|
+
|
305
|
+
const hostKeyResult = new remote.Command("host-key", {
|
306
|
+
connection,
|
307
|
+
create: "cat /etc/ssh/ssh_host_ed25519_key.pub",
|
308
|
+
triggers: [Date.now()],
|
309
|
+
})
|
310
|
+
|
311
|
+
return output({
|
312
|
+
endpoints,
|
313
|
+
hostname: hostnameResult.stdout.apply(x => x.trim()),
|
314
|
+
ssh: {
|
315
|
+
endpoints: [l3EndpointToL4(sshHost, sshArgs.port ?? 22)],
|
316
|
+
user: sshArgs.user ?? "root",
|
317
|
+
hostKey: hostKeyResult.stdout.apply(x => x.trim()),
|
318
|
+
password: connection.password,
|
319
|
+
keyPair: sshKeyPair
|
320
|
+
? sshKeyPair
|
321
|
+
: sshPrivateKey
|
322
|
+
? sshPrivateKeyToKeyPair(sshPrivateKey)
|
323
|
+
: undefined,
|
324
|
+
},
|
190
325
|
})
|
191
326
|
}
|
@@ -0,0 +1,123 @@
|
|
1
|
+
import type { common } from "@highstate/library"
|
2
|
+
import { getOrCreate, z } from "@highstate/contract"
|
3
|
+
import {
|
4
|
+
ComponentResource,
|
5
|
+
type ComponentResourceOptions,
|
6
|
+
type Input,
|
7
|
+
type InputArray,
|
8
|
+
normalizeInputs,
|
9
|
+
type Output,
|
10
|
+
output,
|
11
|
+
Resource,
|
12
|
+
} from "@highstate/pulumi"
|
13
|
+
import { ImplementationMediator } from "./impl-ref"
|
14
|
+
|
15
|
+
export const tlsCertificateMediator = new ImplementationMediator(
|
16
|
+
"tls-certificate",
|
17
|
+
z.object({
|
18
|
+
name: z.string(),
|
19
|
+
spec: z.custom<TlsCertificateSpec>(),
|
20
|
+
opts: z.custom<ComponentResourceOptions>().optional(),
|
21
|
+
}),
|
22
|
+
z.instanceof(Resource),
|
23
|
+
)
|
24
|
+
|
25
|
+
export type TlsCertificateSpec = {
|
26
|
+
/**
|
27
|
+
* The common name for the certificate.
|
28
|
+
*/
|
29
|
+
commonName?: Input<string>
|
30
|
+
|
31
|
+
/**
|
32
|
+
* The alternative DNS names for the certificate.
|
33
|
+
*/
|
34
|
+
dnsNames?: InputArray<string>
|
35
|
+
|
36
|
+
/**
|
37
|
+
* The native data to pass to the implementation.
|
38
|
+
*
|
39
|
+
* This is used for data which implementation may natively understand
|
40
|
+
* and may use this data to create certificates using native resources.
|
41
|
+
*/
|
42
|
+
nativeData?: unknown
|
43
|
+
}
|
44
|
+
|
45
|
+
export type TlsCertificateArgs = TlsCertificateSpec & {
|
46
|
+
/**
|
47
|
+
* The issuer to use for the certificate.
|
48
|
+
*/
|
49
|
+
issuer?: Input<common.TlsIssuer>
|
50
|
+
|
51
|
+
/**
|
52
|
+
* The issuers to use for the certificate.
|
53
|
+
*
|
54
|
+
* If multiple issuers are provided, the certificate will be created using the first issuer that supports the requested common name.
|
55
|
+
*/
|
56
|
+
issuers?: InputArray<common.TlsIssuer>
|
57
|
+
}
|
58
|
+
|
59
|
+
export class TlsCertificate extends ComponentResource {
|
60
|
+
/**
|
61
|
+
* The underlying resource created by the implementation.
|
62
|
+
*/
|
63
|
+
readonly resource: Output<Resource>
|
64
|
+
|
65
|
+
constructor(name: string, args: TlsCertificateArgs, opts?: ComponentResourceOptions) {
|
66
|
+
super("highstate:common:TlsCertificate", name, args, opts)
|
67
|
+
|
68
|
+
const issuers = normalizeInputs(args.issuer, args.issuers)
|
69
|
+
|
70
|
+
this.resource = output({
|
71
|
+
issuers,
|
72
|
+
commonName: args.commonName,
|
73
|
+
dnsNames: args.dnsNames,
|
74
|
+
}).apply(async ({ issuers, commonName, dnsNames }) => {
|
75
|
+
// for now, we require single issuer to match all requested names
|
76
|
+
const matchedIssuer = issuers.find(issuer => {
|
77
|
+
if (commonName && !commonName.endsWith(issuer.domain)) {
|
78
|
+
return false
|
79
|
+
}
|
80
|
+
|
81
|
+
if (dnsNames && !dnsNames.every(name => name.endsWith(issuer.domain))) {
|
82
|
+
return false
|
83
|
+
}
|
84
|
+
|
85
|
+
return true
|
86
|
+
})
|
87
|
+
|
88
|
+
if (!matchedIssuer) {
|
89
|
+
throw new Error(
|
90
|
+
`No TLS issuer matched the common name "${commonName}" and DNS names "${dnsNames?.join(", ") ?? ""}"`,
|
91
|
+
)
|
92
|
+
}
|
93
|
+
|
94
|
+
return await tlsCertificateMediator.call(matchedIssuer.implRef, {
|
95
|
+
name,
|
96
|
+
spec: args,
|
97
|
+
})
|
98
|
+
})
|
99
|
+
}
|
100
|
+
|
101
|
+
private static readonly tlsCertificateCache = new Map<string, TlsCertificate>()
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Creates a TLS certificate for the specified common name and DNS names.
|
105
|
+
*
|
106
|
+
* If a TLS certificate with the same name already exists, it will be reused.
|
107
|
+
*
|
108
|
+
* @param name The name of the TLS certificate.
|
109
|
+
* @param args The arguments for the TLS certificate.
|
110
|
+
* @param opts The options for the resource.
|
111
|
+
*/
|
112
|
+
static createOnce(
|
113
|
+
name: string,
|
114
|
+
args: TlsCertificateArgs,
|
115
|
+
opts?: ComponentResourceOptions,
|
116
|
+
): TlsCertificate {
|
117
|
+
return getOrCreate(
|
118
|
+
TlsCertificate.tlsCertificateCache,
|
119
|
+
name,
|
120
|
+
() => new TlsCertificate(name, args, opts),
|
121
|
+
)
|
122
|
+
}
|
123
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { common } from "@highstate/library"
|
2
|
+
import { forUnit } from "@highstate/pulumi"
|
3
|
+
|
4
|
+
const { inputs, outputs } = forUnit(common.accessPoint)
|
5
|
+
|
6
|
+
export default outputs({
|
7
|
+
accessPoint: {
|
8
|
+
gateway: inputs.gateway,
|
9
|
+
tlsIssuers: inputs.tlsIssuers ?? [],
|
10
|
+
dnsProviders: inputs.dnsProviders ?? [],
|
11
|
+
},
|
12
|
+
})
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { databases } from "@highstate/library"
|
2
|
+
import { forUnit } from "@highstate/pulumi"
|
3
|
+
import { parseEndpoints } from "../../../shared"
|
4
|
+
|
5
|
+
const { args, secrets, inputs, outputs } = forUnit(databases.existingMariadb)
|
6
|
+
|
7
|
+
export default outputs({
|
8
|
+
mariadb: {
|
9
|
+
endpoints: parseEndpoints(args.endpoints, inputs.endpoints),
|
10
|
+
username: args.username,
|
11
|
+
password: secrets.password,
|
12
|
+
database: args.database,
|
13
|
+
},
|
14
|
+
})
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { databases } from "@highstate/library"
|
2
|
+
import { forUnit } from "@highstate/pulumi"
|
3
|
+
import { parseEndpoints } from "../../../shared"
|
4
|
+
|
5
|
+
const { args, secrets, inputs, outputs } = forUnit(databases.existingMongodb)
|
6
|
+
|
7
|
+
export default outputs({
|
8
|
+
mongodb: {
|
9
|
+
endpoints: parseEndpoints(args.endpoints, inputs.endpoints),
|
10
|
+
username: args.username,
|
11
|
+
password: secrets.password,
|
12
|
+
database: args.database,
|
13
|
+
},
|
14
|
+
})
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { databases } from "@highstate/library"
|
2
|
+
import { forUnit } from "@highstate/pulumi"
|
3
|
+
import { parseEndpoints } from "../../../shared"
|
4
|
+
|
5
|
+
const { args, secrets, inputs, outputs } = forUnit(databases.existingPostgresql)
|
6
|
+
|
7
|
+
export default outputs({
|
8
|
+
postgresql: {
|
9
|
+
endpoints: parseEndpoints(args.endpoints, inputs.endpoints),
|
10
|
+
username: args.username,
|
11
|
+
password: secrets.password,
|
12
|
+
database: args.database,
|
13
|
+
},
|
14
|
+
})
|
@@ -1,16 +1,26 @@
|
|
1
1
|
import { dns } from "@highstate/library"
|
2
|
-
import { forUnit
|
3
|
-
import {
|
2
|
+
import { forUnit } from "@highstate/pulumi"
|
3
|
+
import { updateEndpointsWithFqdn } from "../../../shared"
|
4
4
|
|
5
|
-
const {
|
5
|
+
const { args, inputs, outputs } = forUnit(dns.recordSet)
|
6
6
|
|
7
|
-
const endpoints = await
|
7
|
+
const { endpoints: l3Endpoints } = await updateEndpointsWithFqdn(
|
8
|
+
inputs.l3Endpoints ?? [],
|
9
|
+
args.fqdn,
|
10
|
+
args.endpointFilter,
|
11
|
+
args.patchMode,
|
12
|
+
inputs.dnsProviders,
|
13
|
+
)
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
const { endpoints: l4Endpoints } = await updateEndpointsWithFqdn(
|
16
|
+
inputs.l4Endpoints ?? [],
|
17
|
+
args.fqdn,
|
18
|
+
args.endpointFilter,
|
19
|
+
args.patchMode,
|
20
|
+
inputs.dnsProviders,
|
21
|
+
)
|
22
|
+
|
23
|
+
export default outputs({
|
24
|
+
l3Endpoints,
|
25
|
+
l4Endpoints,
|
16
26
|
})
|