@ydkn/pulumi-components 0.8.8 → 0.9.1

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.
Files changed (182) hide show
  1. package/index.d.ts +5 -1
  2. package/index.js +5 -1
  3. package/index.js.map +1 -1
  4. package/lib/alpine/config.d.ts +19 -0
  5. package/lib/alpine/config.js +195 -0
  6. package/lib/alpine/config.js.map +1 -0
  7. package/lib/alpine/deployment.js +2 -2
  8. package/lib/alpine/deployment.js.map +1 -1
  9. package/lib/alpine/host.d.ts +25 -0
  10. package/lib/alpine/host.js +98 -0
  11. package/lib/alpine/host.js.map +1 -0
  12. package/lib/alpine/index.d.ts +3 -1
  13. package/lib/alpine/index.js +3 -1
  14. package/lib/alpine/index.js.map +1 -1
  15. package/lib/avahi/deployment.d.ts +2 -0
  16. package/lib/avahi/deployment.js +44 -20
  17. package/lib/avahi/deployment.js.map +1 -1
  18. package/lib/avahi/service.d.ts +2 -2
  19. package/lib/avahi/service.js +9 -7
  20. package/lib/avahi/service.js.map +1 -1
  21. package/lib/certManager/certificate.js +1 -1
  22. package/lib/certManager/certificate.js.map +1 -1
  23. package/lib/certManager/issuer.d.ts +1 -1
  24. package/lib/certManager/operator.js +8 -8
  25. package/lib/certManager/operator.js.map +1 -1
  26. package/lib/cups/avahiService.d.ts +1 -1
  27. package/lib/cups/avahiService.js +1 -1
  28. package/lib/cups/avahiService.js.map +1 -1
  29. package/lib/cups/deployment.d.ts +1 -1
  30. package/lib/cups/deployment.js +3 -3
  31. package/lib/cups/deployment.js.map +1 -1
  32. package/lib/dashy/deployment.d.ts +35 -0
  33. package/lib/dashy/deployment.js +78 -0
  34. package/lib/dashy/deployment.js.map +1 -0
  35. package/lib/dashy/index.d.ts +2 -0
  36. package/lib/dashy/index.js +3 -0
  37. package/lib/dashy/index.js.map +1 -0
  38. package/lib/dhcpd/deployment.d.ts +6 -6
  39. package/lib/dhcpd/deployment.js +40 -30
  40. package/lib/dhcpd/deployment.js.map +1 -1
  41. package/lib/externalDns/operator.d.ts +2 -2
  42. package/lib/externalDns/operator.js +5 -16
  43. package/lib/externalDns/operator.js.map +1 -1
  44. package/lib/fcos/assets/install-ready.service +12 -0
  45. package/lib/fcos/assets/install-run.service +14 -0
  46. package/lib/fcos/config.d.ts +2 -5
  47. package/lib/fcos/config.js +44 -34
  48. package/lib/fcos/config.js.map +1 -1
  49. package/lib/fcos/host.d.ts +8 -12
  50. package/lib/fcos/host.js +45 -39
  51. package/lib/fcos/host.js.map +1 -1
  52. package/lib/fcos/index.d.ts +3 -3
  53. package/lib/fcos/index.js.map +1 -1
  54. package/lib/flatcar/assets/install-ready.service +12 -0
  55. package/lib/flatcar/assets/install-run.service +14 -0
  56. package/lib/flatcar/config.d.ts +3 -5
  57. package/lib/flatcar/config.js +44 -42
  58. package/lib/flatcar/config.js.map +1 -1
  59. package/lib/flatcar/host.d.ts +8 -12
  60. package/lib/flatcar/host.js +39 -29
  61. package/lib/flatcar/host.js.map +1 -1
  62. package/lib/flatcar/index.d.ts +3 -3
  63. package/lib/flatcar/index.js.map +1 -1
  64. package/lib/freeradius/deployment.js +1 -1
  65. package/lib/gitlab/project.js +4 -4
  66. package/lib/gitlab/project.js.map +1 -1
  67. package/lib/grafana/alloy.d.ts +1 -1
  68. package/lib/grafana/alloy.js +11 -12
  69. package/lib/grafana/alloy.js.map +1 -1
  70. package/lib/grafana/deployment.js +2 -2
  71. package/lib/grafana/deployment.js.map +1 -1
  72. package/lib/hcloud/assets/alpine-install.sh +45 -0
  73. package/lib/hcloud/assets/fcos-install.sh +13 -6
  74. package/lib/hcloud/assets/flatcar-install.sh +2 -2
  75. package/lib/hcloud/cluster.d.ts +9 -2
  76. package/lib/hcloud/cluster.js +273 -117
  77. package/lib/hcloud/cluster.js.map +1 -1
  78. package/lib/homeAssistant/deployment.d.ts +38 -0
  79. package/lib/homeAssistant/deployment.js +183 -0
  80. package/lib/homeAssistant/deployment.js.map +1 -0
  81. package/lib/homeAssistant/index.d.ts +2 -0
  82. package/lib/homeAssistant/index.js +3 -0
  83. package/lib/homeAssistant/index.js.map +1 -0
  84. package/lib/jellyfin/deployment.d.ts +1 -1
  85. package/lib/jellyfin/deployment.js +2 -5
  86. package/lib/jellyfin/deployment.js.map +1 -1
  87. package/lib/k0s/cluster.js +9 -4
  88. package/lib/k0s/cluster.js.map +1 -1
  89. package/lib/kubernetes/crashedCleanup.js +19 -2
  90. package/lib/kubernetes/crashedCleanup.js.map +1 -1
  91. package/lib/kubernetes/transformations/removeCrdDescriptions.js.map +1 -1
  92. package/lib/kubernetes/v1/secureIngress.js.map +1 -1
  93. package/lib/kured/deployment.d.ts +16 -0
  94. package/lib/kured/deployment.js +42 -0
  95. package/lib/kured/deployment.js.map +1 -0
  96. package/lib/kured/index.d.ts +2 -0
  97. package/lib/kured/index.js +3 -0
  98. package/lib/kured/index.js.map +1 -0
  99. package/lib/loki/deployment.js +8 -1
  100. package/lib/loki/deployment.js.map +1 -1
  101. package/lib/metallb/controller.d.ts +3 -0
  102. package/lib/metallb/controller.js +2 -0
  103. package/lib/metallb/controller.js.map +1 -1
  104. package/lib/mongodb/cluster.js +1 -1
  105. package/lib/mongodb/cluster.js.map +1 -1
  106. package/lib/musicAssistant/deployment.d.ts +26 -0
  107. package/lib/musicAssistant/deployment.js +77 -0
  108. package/lib/musicAssistant/deployment.js.map +1 -0
  109. package/lib/musicAssistant/index.d.ts +2 -0
  110. package/lib/musicAssistant/index.js +3 -0
  111. package/lib/musicAssistant/index.js.map +1 -0
  112. package/lib/nats/cluster.js +14 -10
  113. package/lib/nats/cluster.js.map +1 -1
  114. package/lib/netbird/agent.d.ts +0 -4
  115. package/lib/netbird/agent.js +5 -38
  116. package/lib/netbird/agent.js.map +1 -1
  117. package/lib/netbird/management.d.ts +1 -0
  118. package/lib/netbird/management.js +18 -3
  119. package/lib/netbird/management.js.map +1 -1
  120. package/lib/node/config.d.ts +37 -0
  121. package/lib/node/config.js +2 -0
  122. package/lib/node/config.js.map +1 -0
  123. package/lib/node/index.d.ts +2 -2
  124. package/lib/node/index.js.map +1 -1
  125. package/lib/node/node.d.ts +1 -1
  126. package/lib/plex/mediaServer.d.ts +1 -1
  127. package/lib/plex/mediaServer.js +4 -4
  128. package/lib/plex/mediaServer.js.map +1 -1
  129. package/lib/postgresql/cluster.js +1 -1
  130. package/lib/postgresql/cluster.js.map +1 -1
  131. package/lib/raspberrypi/cluster.d.ts +5 -2
  132. package/lib/raspberrypi/cluster.js +128 -76
  133. package/lib/raspberrypi/cluster.js.map +1 -1
  134. package/lib/redis/standalone.js +2 -2
  135. package/lib/rook/blockPool.js +1 -0
  136. package/lib/rook/blockPool.js.map +1 -1
  137. package/lib/rook/cluster.d.ts +0 -2
  138. package/lib/rook/cluster.js +10 -35
  139. package/lib/rook/cluster.js.map +1 -1
  140. package/lib/rook/filesystem.js +2 -1
  141. package/lib/rook/filesystem.js.map +1 -1
  142. package/lib/rook/operator.d.ts +8 -0
  143. package/lib/rook/operator.js +128 -122
  144. package/lib/rook/operator.js.map +1 -1
  145. package/lib/rook/sharedFilesystem.js +1 -0
  146. package/lib/rook/sharedFilesystem.js.map +1 -1
  147. package/lib/samba/avahiService.d.ts +1 -1
  148. package/lib/samba/avahiService.js +1 -1
  149. package/lib/samba/avahiService.js.map +1 -1
  150. package/lib/samba/dc.js +27 -1
  151. package/lib/samba/dc.js.map +1 -1
  152. package/lib/samba/deployment.d.ts +2 -1
  153. package/lib/samba/deployment.js +5 -6
  154. package/lib/samba/deployment.js.map +1 -1
  155. package/lib/torproxy/deployment.js +2 -3
  156. package/lib/torproxy/deployment.js.map +1 -1
  157. package/lib/traefik/controller.d.ts +12 -0
  158. package/lib/traefik/controller.js +37 -4
  159. package/lib/traefik/controller.js.map +1 -1
  160. package/lib/transmission/deployment.d.ts +5 -3
  161. package/lib/transmission/deployment.js +27 -11
  162. package/lib/transmission/deployment.js.map +1 -1
  163. package/lib/ubuntu/deployment.js +2 -2
  164. package/lib/ubuntu/deployment.js.map +1 -1
  165. package/lib/unifi/index.d.ts +2 -2
  166. package/lib/unifi/index.js +2 -2
  167. package/lib/unifi/index.js.map +1 -1
  168. package/lib/unifi/{networkServer.d.ts → osServer.d.ts} +7 -16
  169. package/lib/unifi/{networkServer.js → osServer.js} +86 -139
  170. package/lib/unifi/osServer.js.map +1 -0
  171. package/lib/utils/args.js +1 -1
  172. package/lib/utils/args.js.map +1 -1
  173. package/lib/velero/operator.d.ts +2 -2
  174. package/lib/velero/operator.js +6 -6
  175. package/lib/velero/operator.js.map +1 -1
  176. package/lib/wireguard/deployment.js +1 -1
  177. package/lib/zitadel/deployment.js +1 -1
  178. package/lib/zitadel/deployment.js.map +1 -1
  179. package/package.json +28 -24
  180. package/lib/netbird/assets/nftables.sh +0 -44
  181. package/lib/unifi/assets/init-mongo.sh +0 -19
  182. package/lib/unifi/networkServer.js.map +0 -1
@@ -3,8 +3,8 @@
3
3
  DRIVE="${1}"
4
4
  CONFIG="${2}"
5
5
 
6
- apt-get update -y
7
- apt-get install -y gawk
6
+ apt-get update -qq -y
7
+ apt-get install -qq -y gawk
8
8
 
9
9
  curl -sf -o /tmp/flatcar-install https://raw.githubusercontent.com/flatcar/init/flatcar-master/bin/flatcar-install
10
10
  chmod +x /tmp/flatcar-install
@@ -4,12 +4,12 @@ import * as k8s from "@pulumi/kubernetes";
4
4
  import { ComponentResource } from "../common/index.js";
5
5
  import * as node from "../node/index.js";
6
6
  import * as k0s from "../k0s/index.js";
7
- export interface Node extends node.Node, node.IgnitionArgs {
7
+ export interface Node extends node.Node, node.ConfigArgs {
8
8
  serverType: pulumi.Input<string>;
9
9
  count?: pulumi.Input<number>;
10
10
  location?: pulumi.Input<string>;
11
11
  }
12
- export interface ClusterArgs extends k0s.ClusterArgs, node.IgnitionArgs {
12
+ export interface ClusterArgs extends k0s.ClusterArgs, node.ConfigArgs {
13
13
  name?: pulumi.Input<string>;
14
14
  token: pulumi.Input<string>;
15
15
  location: pulumi.Input<string>;
@@ -30,6 +30,8 @@ export declare class Cluster extends ComponentResource {
30
30
  private static readonly dnsServers;
31
31
  private static readonly gatewayIPv6;
32
32
  private static readonly ignitionConfigPathRemote;
33
+ private static readonly cloudInitMetaDataPathRemote;
34
+ private static readonly cloudInitUserDataPathRemote;
33
35
  private static readonly installScriptPathRemote;
34
36
  private readonly sshKey;
35
37
  private readonly network;
@@ -58,8 +60,13 @@ export declare class Cluster extends ComponentResource {
58
60
  */
59
61
  constructor(name: string, args: ClusterArgs, opts?: pulumi.ComponentResourceOptions);
60
62
  private createServers;
63
+ private mergeNodeArgs;
64
+ private networkManagerConfigFiles;
65
+ private networkdConfigFiles;
66
+ private interfacesConfigFiles;
61
67
  private configureFcosNode;
62
68
  private configureFlatcarNode;
69
+ private configureAlpineNode;
63
70
  private fileAssetFromString;
64
71
  private static ethernetInterfaceName;
65
72
  }
@@ -11,6 +11,7 @@ import * as crypto from "crypto";
11
11
  import { ComponentResource } from "../common/index.js";
12
12
  import * as fcos from "../fcos/index.js";
13
13
  import * as flatcar from "../flatcar/index.js";
14
+ import * as alpine from "../alpine/index.js";
14
15
  import * as k0s from "../k0s/index.js";
15
16
  import { Kubernetes } from "./kubernetes.js";
16
17
  export class Cluster extends ComponentResource {
@@ -27,10 +28,15 @@ export class Cluster extends ComponentResource {
27
28
  flatcar: {
28
29
  DEFAULT: { primary: "eth0", private: [1, 2].map((i) => `eth${i}`) },
29
30
  },
31
+ alpine: {
32
+ DEFAULT: { primary: "eth0", private: [1, 2].map((i) => `eth${i}`) },
33
+ },
30
34
  };
31
- static dnsServers = ["2a01:4ff:ff00::add:1", "2a01:4ff:ff00::add:2"];
35
+ static dnsServers = ["185.12.64.1", "185.12.64.2"]; // ["2a01:4ff:ff00::add:1", "2a01:4ff:ff00::add:2"];
32
36
  static gatewayIPv6 = "fe80::1";
33
37
  static ignitionConfigPathRemote = "/tmp/config.ign";
38
+ static cloudInitMetaDataPathRemote = "/tmp/meta-data";
39
+ static cloudInitUserDataPathRemote = "/tmp/user-data";
34
40
  static installScriptPathRemote = "/tmp/install.sh";
35
41
  sshKey;
36
42
  network;
@@ -83,7 +89,7 @@ export class Cluster extends ComponentResource {
83
89
  .apply(([result]) => {
84
90
  return result.images.filter((image) => image.osFlavor === "ubuntu").sort((a, b) => (a > b ? -1 : 1))[0].name;
85
91
  });
86
- const servers = this.createServers(args.nodes, serverImage, this.sshKey, this.sshPrivateKey.privateKeyOpenssh, this.nodeSubnet, this.placementGroup, args.files, args.links, args.systemdUnits, args.sshAuthorizedKeys, args.protect);
92
+ const servers = this.createServers(args.nodes, serverImage, this.sshKey, this.sshPrivateKey.privateKeyOpenssh, this.nodeSubnet, this.placementGroup, args.packages, args.filesystems, args.users, args.files, args.run, args.sshAuthorizedKeys, args.protect);
87
93
  this.nodes = servers.apply((servers) => servers.map((s) => s.node));
88
94
  const nodeIPs = pulumi.all([this.nodes]).apply(([nodes]) => pulumi.all(nodes).apply((nodes) => {
89
95
  const nodeIPs = [];
@@ -186,7 +192,7 @@ export class Cluster extends ComponentResource {
186
192
  }, { ...emptyOpts, providers: [this.provider] });
187
193
  this.registerOutputs();
188
194
  }
189
- createServers(nodes, image, sshKey, sshPrivateKey, subnet, placementGroup, files, links, systemdUnits, sshAuthorizedKeys, protect) {
195
+ createServers(nodes, image, sshKey, sshPrivateKey, subnet, placementGroup, packages, filesystems, users, files, run, sshAuthorizedKeys, protect) {
190
196
  const emptyOpts = this.opts();
191
197
  const hcloudOpts = this.opts(hcloud.Provider);
192
198
  return pulumi.all([nodes]).apply(([nodes]) => {
@@ -232,113 +238,21 @@ export class Cluster extends ComponentResource {
232
238
  }, { ...hcloudOpts, protect }));
233
239
  }
234
240
  const serverNetwork = pulumi.all([server.id, server.name]).apply(([serverId, serverName]) => {
235
- return new hcloud.ServerNetwork(serverName, { serverId: parseInt(serverId), subnetId: subnet.id }, hcloudOpts);
241
+ return new hcloud.ServerNetwork(serverName, { serverId: parseInt(serverId), subnetId: subnet.id }, { ...hcloudOpts, dependsOn: [server] });
236
242
  });
237
243
  const node = pulumi
238
- .all([hostname, files, links, systemdUnits, sshAuthorizedKeys, server.ipv6Address, server.serverType])
239
- .apply(([hostname, files, links, systemdUnits, sshAuthorizedKeys, ipv6Address, serverType]) => {
240
- const ethernetInterfaces = Cluster.ethernetInterfaceName(nodeGroup.operatingSystem, serverType);
244
+ .all([hostname, filesystems, files, server])
245
+ .apply(([hostname, filesystems, files, server]) => {
241
246
  let host;
242
247
  switch (nodeGroup.operatingSystem) {
243
248
  case "fcos":
244
- host = new fcos.Host(hostname, {
245
- hostname,
246
- filesystems: dataVolume !== undefined
247
- ? [
248
- {
249
- device: pulumi.interpolate `/dev/disk/by-id/scsi-0HC_Volume_${dataVolume.id}`,
250
- path: "/var/lib/k0s",
251
- format: dataVolume.format.apply((format) => format ?? "ext4"),
252
- },
253
- ]
254
- : [],
255
- files: pulumi.all(files ?? []).apply((files) => {
256
- files.push({
257
- path: `/etc/NetworkManager/system-connections/${ethernetInterfaces.primary}.nmconnection`,
258
- contents: [
259
- "[connection]",
260
- "type=ethernet",
261
- `id=${ethernetInterfaces.primary}`,
262
- `interface-name=${ethernetInterfaces.primary}`,
263
- "[ipv4]",
264
- "method=auto",
265
- "ignore-auto-dns=true",
266
- "[ipv6]",
267
- "method=manual",
268
- `address1=${ipv6Address}`,
269
- `gateway=${Cluster.gatewayIPv6}`,
270
- `dns=${Cluster.dnsServers.join(";")}`,
271
- ].join("\n"),
272
- mode: 0o600,
273
- });
274
- for (const iface of ethernetInterfaces.private) {
275
- files.push({
276
- path: `/etc/NetworkManager/system-connections/${iface}.nmconnection`,
277
- contents: [
278
- "[connection]",
279
- "type=ethernet",
280
- `id=${iface}`,
281
- `interface-name=${iface}`,
282
- "[ipv4]",
283
- "method=auto",
284
- "never-default=true",
285
- "[ipv6]",
286
- "method=auto",
287
- "never-default=true",
288
- ].join("\n"),
289
- mode: 0o600,
290
- });
291
- }
292
- return files;
293
- }),
294
- links,
295
- systemdUnits,
296
- users: [{ name: "core", sshAuthorizedKeys }],
297
- sshUsers: [{ name: Cluster.sshUsername, groups: ["sudo"] }],
298
- }, emptyOpts);
249
+ host = new fcos.Host(hostname, this.mergeNodeArgs(nodeGroup, hostname, dataVolume, packages, filesystems, users, files, run, sshAuthorizedKeys, this.networkManagerConfigFiles(nodeGroup, server)), emptyOpts);
299
250
  break;
300
251
  case "flatcar":
301
- host = new flatcar.Host(hostname, {
302
- hostname,
303
- filesystems: dataVolume !== undefined
304
- ? [
305
- {
306
- device: pulumi.interpolate `/dev/disk/by-id/scsi-0HC_Volume_${dataVolume.id}`,
307
- path: "/var/lib/k0s",
308
- format: dataVolume.format.apply((format) => format ?? "ext4"),
309
- },
310
- ]
311
- : [],
312
- files: pulumi.all(files ?? []).apply((files) => {
313
- files.push({
314
- path: `/etc/systemd/network/10-${ethernetInterfaces.primary}.network`,
315
- contents: [
316
- "[Match]",
317
- `Name=${ethernetInterfaces.primary}`,
318
- "[Link]",
319
- "RequiredForOnline=routable",
320
- "[Network]",
321
- "DHCP=yes",
322
- `Address=${ipv6Address}/64`,
323
- `Gateway=${Cluster.gatewayIPv6}`,
324
- ...Cluster.dnsServers.map((dns) => `DNS=${dns}`),
325
- ].join("\n"),
326
- mode: 0o644,
327
- });
328
- for (const iface of ethernetInterfaces.private) {
329
- files.push({
330
- path: `/etc/systemd/network/10-${iface}.network`,
331
- contents: ["[Match]", `Name=${iface}`, "[Network]", "DHCP=yes", "IPv6AcceptRA=true"].join("\n"),
332
- mode: 0o644,
333
- });
334
- }
335
- return files;
336
- }),
337
- links,
338
- systemdUnits,
339
- users: [{ name: "core", sshAuthorizedKeys }],
340
- sshUsers: [{ name: Cluster.sshUsername, groups: ["sudo"] }],
341
- }, emptyOpts);
252
+ host = new flatcar.Host(hostname, this.mergeNodeArgs(nodeGroup, hostname, dataVolume, packages, filesystems, users, files, run, sshAuthorizedKeys, this.networkdConfigFiles(nodeGroup, server)), emptyOpts);
253
+ break;
254
+ case "alpine":
255
+ host = new alpine.Host(hostname, this.mergeNodeArgs(nodeGroup, hostname, dataVolume, packages, filesystems, users, files, run, sshAuthorizedKeys, this.interfacesConfigFiles(nodeGroup, server)), emptyOpts);
342
256
  break;
343
257
  default:
344
258
  throw new Error(`Unsupported operating system ${nodeGroup.operatingSystem}`);
@@ -353,17 +267,9 @@ export class Cluster extends ComponentResource {
353
267
  labels: nodeGroup.labels ?? {},
354
268
  taints: nodeGroup.taints ?? [],
355
269
  username: Cluster.sshUsername,
356
- privateKey: host.sshPrivateKeys.apply((sshPrivateKeys) => {
357
- for (const username in sshPrivateKeys) {
358
- if (username === Cluster.sshUsername) {
359
- // eslint-disable-next-line security/detect-object-injection
360
- return sshPrivateKeys[username].privateKeyOpenssh;
361
- }
362
- }
363
- throw new Error(`No private key found for user ${Cluster.sshUsername}`);
364
- }),
270
+ privateKey: host.deployPrivateKey.privateKeyOpenssh,
365
271
  operatingSystem: nodeGroup.operatingSystem,
366
- ignitionConfig: host.ignitionConfig,
272
+ initConfig: host.initConfig,
367
273
  disabled: nodeGroup.disabled ?? false,
368
274
  };
369
275
  });
@@ -375,7 +281,10 @@ export class Cluster extends ComponentResource {
375
281
  return this.configureFcosNode(sshPrivateKey, server, node);
376
282
  case "flatcar":
377
283
  return this.configureFlatcarNode(sshPrivateKey, server, node);
284
+ case "alpine":
285
+ return this.configureAlpineNode(sshPrivateKey, server, node);
378
286
  default:
287
+ //eslint-disable-next-line @typescript-eslint/restrict-template-expressions
379
288
  throw new Error(`Unsupported operating system ${os}`);
380
289
  }
381
290
  }),
@@ -385,6 +294,180 @@ export class Cluster extends ComponentResource {
385
294
  return results;
386
295
  });
387
296
  }
297
+ mergeNodeArgs(serverNode, hostname, dataVolume, packages, filesystems, users, files, run, sshAuthorizedKeys, additionalFiles) {
298
+ return {
299
+ hostname: pulumi.output(hostname),
300
+ packages: pulumi
301
+ .all([serverNode])
302
+ .apply(([serverNode]) => pulumi
303
+ .all([packages])
304
+ .apply(([packages]) => pulumi
305
+ .all(packages ?? [])
306
+ .apply((packages) => pulumi.all(serverNode.packages ?? []).apply((nodePackages) => packages.concat(nodePackages))))),
307
+ filesystems: pulumi.all([serverNode]).apply(([serverNode]) => pulumi.all([filesystems]).apply(([filesystems]) => pulumi.all(filesystems ?? []).apply((filesystems) => pulumi.all(serverNode.filesystems ?? []).apply((nodeFilesystems) => pulumi.all([dataVolume]).apply(([dataVolume]) => pulumi
308
+ .all([dataVolume ? dataVolume.id : undefined, dataVolume ? dataVolume.format : undefined])
309
+ .apply(([dataVolumeId, dataVolumeFormat]) => (dataVolumeId !== undefined && dataVolumeFormat !== undefined
310
+ ? [
311
+ {
312
+ device: `/dev/disk/by-id/scsi-0HC_Volume_${dataVolumeId}`,
313
+ path: "/var/lib/k0s",
314
+ format: dataVolumeFormat ?? "ext4",
315
+ },
316
+ ]
317
+ : [])
318
+ .concat(filesystems)
319
+ .concat(nodeFilesystems))))))),
320
+ users: pulumi.all([serverNode]).apply(([serverNode]) => pulumi.all([users]).apply(([users]) => pulumi.all(users ?? []).apply((users) => pulumi.all(serverNode.users ?? []).apply((nodeUsers) => {
321
+ const allUsers = [];
322
+ for (const user of users ?? []) {
323
+ for (const [i, u] of (allUsers ?? []).entries()) {
324
+ if (user.name === u.name) {
325
+ allUsers[i] = { ...u, ...user }; // eslint-disable-line security/detect-object-injection
326
+ break;
327
+ }
328
+ }
329
+ }
330
+ for (const user of nodeUsers ?? []) {
331
+ for (const [i, u] of (allUsers ?? []).entries()) {
332
+ if (user.name === u.name) {
333
+ allUsers[i] = { ...u, ...user }; // eslint-disable-line security/detect-object-injection
334
+ break;
335
+ }
336
+ }
337
+ }
338
+ return allUsers;
339
+ })))),
340
+ files: pulumi.all([serverNode, hostname]).apply(([serverNode, hostname]) => pulumi.all([files]).apply(([files]) => pulumi.all(files ?? []).apply((files) => pulumi.all([additionalFiles]).apply(([additionalFiles]) => pulumi.all(additionalFiles ?? []).apply((additionalFiles) => pulumi.all(serverNode.files ?? []).apply((nodeFiles) => files
341
+ .concat(additionalFiles)
342
+ .concat(nodeFiles)
343
+ .concat([
344
+ {
345
+ path: "/var/lib/calico/nodename",
346
+ user: "root",
347
+ group: "root",
348
+ mode: 0o644,
349
+ contents: hostname,
350
+ },
351
+ ]))))))),
352
+ run: pulumi
353
+ .all([serverNode])
354
+ .apply(([serverNode]) => pulumi
355
+ .all([run])
356
+ .apply(([run]) => pulumi
357
+ .all(run ?? [])
358
+ .apply((run) => pulumi.all(serverNode.run ?? []).apply((nodeRun) => run.concat(nodeRun))))),
359
+ sshAuthorizedKeys,
360
+ };
361
+ }
362
+ networkManagerConfigFiles(nodeGroup, server) {
363
+ return pulumi
364
+ .all([nodeGroup.operatingSystem, server.serverType, server.ipv6Address])
365
+ .apply(([os, serverType, ipv6Address]) => {
366
+ const configs = [];
367
+ const ethernetInterfaces = Cluster.ethernetInterfaceName(os, serverType);
368
+ configs.push({
369
+ path: `/etc/NetworkManager/system-connections/${ethernetInterfaces.primary}.nmconnection`,
370
+ contents: [
371
+ "[connection]",
372
+ "type=ethernet",
373
+ `id=${ethernetInterfaces.primary}`,
374
+ `interface-name=${ethernetInterfaces.primary}`,
375
+ "[ipv4]",
376
+ "method=auto",
377
+ "ignore-auto-dns=true",
378
+ "[ipv6]",
379
+ "method=manual",
380
+ `address1=${ipv6Address}`,
381
+ `gateway=${Cluster.gatewayIPv6}`,
382
+ `dns=${Cluster.dnsServers.join(";")}`,
383
+ ].join("\n"),
384
+ mode: 0o600,
385
+ });
386
+ for (const iface of ethernetInterfaces.private) {
387
+ configs.push({
388
+ path: `/etc/NetworkManager/system-connections/${iface}.nmconnection`,
389
+ contents: [
390
+ "[connection]",
391
+ "type=ethernet",
392
+ `id=${iface}`,
393
+ `interface-name=${iface}`,
394
+ "[ipv4]",
395
+ "method=auto",
396
+ "never-default=true",
397
+ "[ipv6]",
398
+ "method=auto",
399
+ "never-default=true",
400
+ ].join("\n"),
401
+ mode: 0o600,
402
+ });
403
+ }
404
+ return configs;
405
+ });
406
+ }
407
+ networkdConfigFiles(nodeGroup, server) {
408
+ return pulumi
409
+ .all([nodeGroup.operatingSystem, server.serverType, server.ipv6Address])
410
+ .apply(([os, serverType, ipv6Address]) => {
411
+ const configs = [];
412
+ const ethernetInterfaces = Cluster.ethernetInterfaceName(os, serverType);
413
+ configs.push({
414
+ path: `/etc/systemd/network/10-${ethernetInterfaces.primary}.network`,
415
+ contents: [
416
+ "[Match]",
417
+ `Name=${ethernetInterfaces.primary}`,
418
+ "[Link]",
419
+ "RequiredForOnline=routable",
420
+ "[Network]",
421
+ "DHCP=yes",
422
+ `Address=${ipv6Address}/64`,
423
+ `Gateway=${Cluster.gatewayIPv6}`,
424
+ ...Cluster.dnsServers.map((dns) => `DNS=${dns}`),
425
+ ].join("\n"),
426
+ mode: 0o644,
427
+ });
428
+ for (const iface of ethernetInterfaces.private) {
429
+ configs.push({
430
+ path: `/etc/systemd/network/10-${iface}.network`,
431
+ contents: ["[Match]", `Name=${iface}`, "[Network]", "DHCP=yes", "IPv6AcceptRA=true"].join("\n"),
432
+ mode: 0o644,
433
+ });
434
+ }
435
+ return configs;
436
+ });
437
+ }
438
+ interfacesConfigFiles(nodeGroup, server) {
439
+ return pulumi
440
+ .all([nodeGroup.operatingSystem, server.name, server.serverType, server.ipv6Address])
441
+ .apply(([os, name, serverType, ipv6Address]) => {
442
+ const ethernetInterfaces = Cluster.ethernetInterfaceName(os, serverType);
443
+ return [
444
+ {
445
+ path: "/etc/network/interfaces",
446
+ contents: [
447
+ "auto lo",
448
+ "iface lo inet loopback",
449
+ "",
450
+ `auto ${ethernetInterfaces.primary}`,
451
+ `iface ${ethernetInterfaces.primary} inet dhcp`,
452
+ "",
453
+ `iface ${ethernetInterfaces.primary} inet6 static`,
454
+ `address ${ipv6Address}`,
455
+ "netmask 64",
456
+ `gateway ${Cluster.gatewayIPv6}`,
457
+ `post-up sh -c "echo -n '' > /etc/resolv.conf"`,
458
+ ...Cluster.dnsServers.map((dns) => `post-up sh -c "echo 'nameserver ${dns}' >> /etc/resolv.conf"`),
459
+ ...(ethernetInterfaces.private ?? []).map((iface) => [
460
+ "",
461
+ `auto ${iface}`,
462
+ `iface ${iface} inet manual`,
463
+ `post-up /sbin/udhcpc -b -R -p /var/run/udhcpc.${iface}.pid -o -O 1 -i ${iface} -x hostname:${name}`,
464
+ ].join("\n")),
465
+ ].join("\n"),
466
+ mode: 0o644,
467
+ },
468
+ ];
469
+ });
470
+ }
388
471
  configureFcosNode(sshPrivateKey, server, node) {
389
472
  const emptyOpts = this.opts();
390
473
  return pulumi.all([server.name, server.ipv4Address, node]).apply(([nodeName, ipv4Address, node]) => {
@@ -402,7 +485,8 @@ export class Cluster extends ComponentResource {
402
485
  }, { ...emptyOpts, dependsOn: server, ignoreChanges: ["connection", "source", "remotePath"] });
403
486
  const fcosConfigFile = new command.remote.CopyToRemote(`${nodeName}-fcos-config`, {
404
487
  connection,
405
- source: this.fileAssetFromString(node.ignitionConfig),
488
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
489
+ source: this.fileAssetFromString(node.initConfig),
406
490
  remotePath: Cluster.ignitionConfigPathRemote,
407
491
  }, { ...emptyOpts, dependsOn: server, ignoreChanges: ["connection", "source", "remotePath"] });
408
492
  const fcosInstall = new command.remote.Command(`${nodeName}-fcos-install`, {
@@ -411,6 +495,7 @@ export class Cluster extends ComponentResource {
411
495
  `chmod +x ${Cluster.installScriptPathRemote}`,
412
496
  `${Cluster.installScriptPathRemote} /dev/sda ${Cluster.ignitionConfigPathRemote}`,
413
497
  ].join(" && "),
498
+ addPreviousOutputInEnv: false,
414
499
  }, { ...emptyOpts, dependsOn: [fcosInstallScript, fcosConfigFile], ignoreChanges: ["connection", "create"] });
415
500
  return new command.remote.Command(`${nodeName}-fcos-up`, {
416
501
  connection: {
@@ -420,7 +505,8 @@ export class Cluster extends ComponentResource {
420
505
  perDialTimeout: 10,
421
506
  dialErrorLimit: 30,
422
507
  },
423
- create: "echo up",
508
+ create: "until test -f /tmp/install-ready; do echo 'Waiting for install to finish...'; sleep 2; done",
509
+ addPreviousOutputInEnv: false,
424
510
  }, { ...emptyOpts, dependsOn: fcosInstall, ignoreChanges: ["connection", "create"] });
425
511
  });
426
512
  }
@@ -441,7 +527,8 @@ export class Cluster extends ComponentResource {
441
527
  }, { ...emptyOpts, dependsOn: server, ignoreChanges: ["connection", "source", "remotePath"] });
442
528
  const flatcarConfigFile = new command.remote.CopyToRemote(`${nodeName}-flatcar-config`, {
443
529
  connection,
444
- source: this.fileAssetFromString(node.ignitionConfig),
530
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
531
+ source: this.fileAssetFromString(node.initConfig),
445
532
  remotePath: Cluster.ignitionConfigPathRemote,
446
533
  }, { ...emptyOpts, dependsOn: server, ignoreChanges: ["connection", "source", "remotePath"] });
447
534
  const flatcarInstall = new command.remote.Command(`${nodeName}-flatcar-install`, {
@@ -450,6 +537,7 @@ export class Cluster extends ComponentResource {
450
537
  `chmod +x ${Cluster.installScriptPathRemote}`,
451
538
  `${Cluster.installScriptPathRemote} /dev/sda ${Cluster.ignitionConfigPathRemote}`,
452
539
  ].join(" && "),
540
+ addPreviousOutputInEnv: false,
453
541
  }, { ...emptyOpts, dependsOn: [flatcarInstallScript, flatcarConfigFile], ignoreChanges: ["connection", "create"] });
454
542
  return new command.remote.Command(`${nodeName}-flatcar-up`, {
455
543
  connection: {
@@ -459,10 +547,68 @@ export class Cluster extends ComponentResource {
459
547
  perDialTimeout: 10,
460
548
  dialErrorLimit: 30,
461
549
  },
462
- create: "echo up",
550
+ create: "until test -f /tmp/install-ready; do echo 'Waiting for install to finish...'; sleep 2; done",
551
+ addPreviousOutputInEnv: false,
463
552
  }, { ...emptyOpts, dependsOn: flatcarInstall, ignoreChanges: ["connection", "create"] });
464
553
  });
465
554
  }
555
+ configureAlpineNode(sshPrivateKey, server, node) {
556
+ const emptyOpts = this.opts();
557
+ return pulumi.all([server.name, server.ipv4Address, node]).apply(([nodeName, ipv4Address, node]) => {
558
+ const connection = {
559
+ host: ipv4Address,
560
+ privateKey: sshPrivateKey,
561
+ user: Cluster.rescueSshUsername,
562
+ perDialTimeout: 10,
563
+ dialErrorLimit: 30,
564
+ };
565
+ const installScript = new command.remote.CopyToRemote(`${nodeName}-alpine-install-script`, {
566
+ connection,
567
+ source: new pulumi.asset.FileAsset(path.join(path.dirname(url.fileURLToPath(import.meta.url)), "assets", "alpine-install.sh")),
568
+ remotePath: Cluster.installScriptPathRemote,
569
+ }, { ...emptyOpts, dependsOn: server, ignoreChanges: ["connection", "source", "remotePath"] });
570
+ const metaDataFile = new command.remote.CopyToRemote(`${nodeName}-alpine-meta-data`, {
571
+ connection,
572
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access
573
+ source: this.fileAssetFromString(node.initConfig.metaData),
574
+ remotePath: Cluster.cloudInitMetaDataPathRemote,
575
+ }, { ...emptyOpts, dependsOn: server, ignoreChanges: ["connection", "source", "remotePath"] });
576
+ const userDataFile = new command.remote.CopyToRemote(`${nodeName}-alpine-user-data`, {
577
+ connection,
578
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-member-access
579
+ source: this.fileAssetFromString(node.initConfig.userData),
580
+ remotePath: Cluster.cloudInitUserDataPathRemote,
581
+ }, { ...emptyOpts, dependsOn: server, ignoreChanges: ["connection", "source", "remotePath"] });
582
+ const installCommand = new command.remote.Command(`${nodeName}-alpine-install`, {
583
+ connection,
584
+ create: [
585
+ `chmod +x ${Cluster.installScriptPathRemote}`,
586
+ [
587
+ Cluster.installScriptPathRemote,
588
+ "/dev/sda",
589
+ Cluster.cloudInitMetaDataPathRemote,
590
+ Cluster.cloudInitUserDataPathRemote,
591
+ ].join(" "),
592
+ ].join(" && "),
593
+ addPreviousOutputInEnv: false,
594
+ }, {
595
+ ...emptyOpts,
596
+ dependsOn: [installScript, metaDataFile, userDataFile],
597
+ ignoreChanges: ["connection", "create"],
598
+ });
599
+ return new command.remote.Command(`${nodeName}-alpine-up`, {
600
+ connection: {
601
+ host: ipv4Address,
602
+ privateKey: node.privateKey,
603
+ user: Cluster.sshUsername,
604
+ perDialTimeout: 10,
605
+ dialErrorLimit: 30,
606
+ },
607
+ create: "until test -f /tmp/install-ready; do echo 'Waiting for install to finish...'; sleep 2; done",
608
+ addPreviousOutputInEnv: false,
609
+ }, { ...emptyOpts, dependsOn: installCommand, ignoreChanges: ["connection", "create"] });
610
+ });
611
+ }
466
612
  fileAssetFromString(content) {
467
613
  return pulumi.all([content]).apply(([content]) => {
468
614
  const filename = `/tmp/${crypto.createHash("sha1").update(content).digest("hex")}`;
@@ -495,6 +641,16 @@ export class Cluster extends ComponentResource {
495
641
  }
496
642
  }
497
643
  return { primary: primaryInterface, private: privateInterfaces };
644
+ case "alpine":
645
+ primaryInterface = Cluster.interfacesMap.alpine.DEFAULT.primary;
646
+ privateInterfaces = Cluster.interfacesMap.alpine.DEFAULT.private;
647
+ for (const [pattern, iface] of Object.entries(Cluster.interfacesMap.alpine)) {
648
+ if (RegExp(pattern).exec(serverType)) {
649
+ primaryInterface = iface.primary;
650
+ privateInterfaces = iface.private;
651
+ }
652
+ }
653
+ return { primary: primaryInterface, private: privateInterfaces };
498
654
  default:
499
655
  throw new Error(`Unsupported operating system ${os}`);
500
656
  }