diff --git a/examples/cloud-init/aws.ssm.yaml b/examples/cloud-init/aws.ssm.yaml
new file mode 100644
index 0000000..66c7163
--- /dev/null
+++ b/examples/cloud-init/aws.ssm.yaml
@@ -0,0 +1,14 @@
+#cloud-config
+
+# Install and enable the SSM agent on supported instances.
+
+# Tested on:
+# - Amazon Linux 2023.4.20240416
+
+package_upgrade: false
+packages:
+ - amazon-ssm-agent
+
+runcmd:
+ - systemctl daemon-reload
+ - systemctl enable --now 'amazon-ssm-agent.service'
diff --git a/examples/pulumi/multi-part cloud-init/.env b/examples/pulumi/multi-part cloud-init/.env
new file mode 100644
index 0000000..41d3df1
--- /dev/null
+++ b/examples/pulumi/multi-part cloud-init/.env
@@ -0,0 +1 @@
+PULUMI_CONFIG_PASSPHRASE=test123
diff --git a/examples/pulumi/multi-part cloud-init/.gitignore b/examples/pulumi/multi-part cloud-init/.gitignore
new file mode 100644
index 0000000..37a8612
--- /dev/null
+++ b/examples/pulumi/multi-part cloud-init/.gitignore
@@ -0,0 +1,3 @@
+/bin/
+/node_modules/
+/package-lock.json
diff --git a/examples/pulumi/multi-part cloud-init/Pulumi.all.yaml b/examples/pulumi/multi-part cloud-init/Pulumi.all.yaml
new file mode 100644
index 0000000..ba72914
--- /dev/null
+++ b/examples/pulumi/multi-part cloud-init/Pulumi.all.yaml
@@ -0,0 +1,7 @@
+encryptionsalt: v1:Tl2L4ymfbTk=:v1:PNPJ5bUKKgCFe8G/:hrgipeFmFMPSAYcf5lgS6dUCe33WtA==
+config:
+ aws:defaultTags:
+ tags:
+ ManagedBy: pulumi
+ PulumiProject: cloud-init.multi-part
+ aws:region: eu-west-1
diff --git a/examples/pulumi/multi-part cloud-init/Pulumi.yaml b/examples/pulumi/multi-part cloud-init/Pulumi.yaml
new file mode 100644
index 0000000..ba3a68f
--- /dev/null
+++ b/examples/pulumi/multi-part cloud-init/Pulumi.yaml
@@ -0,0 +1,9 @@
+name: cloud-init.multi-part
+runtime: nodejs
+description: Simple example of multi-part cloud-init usage
+config:
+ pulumi:tags:
+ value:
+ pulumi:template: typescript
+backend:
+ url: file://.
diff --git a/examples/pulumi/multi-part cloud-init/index.ts b/examples/pulumi/multi-part cloud-init/index.ts
new file mode 100644
index 0000000..67099c4
--- /dev/null
+++ b/examples/pulumi/multi-part cloud-init/index.ts
@@ -0,0 +1,23 @@
+import * as cloudinit from "@pulumi/cloudinit";
+import * as fs from 'fs';
+
+export const userData = new cloudinit.Config(
+ "userData",
+ {
+ gzip: false,
+ base64Encode: false,
+ parts: [
+ {
+ contentType: "text/cloud-config",
+ content: fs.readFileSync("../../cloud-init/aws.ssm.yaml", "utf8"),
+ filename: "cloud-config.ssm.yml",
+ },
+ {
+ contentType: "text/cloud-config",
+ content: fs.readFileSync("../../cloud-init/docker.yum.yaml", "utf8"),
+ filename: "cloud-config.docker.yml",
+ mergeType: "dict(recurse_array,no_replace)+list(append)",
+ },
+ ],
+ },
+);
diff --git a/examples/pulumi/multi-part cloud-init/package.json b/examples/pulumi/multi-part cloud-init/package.json
new file mode 100644
index 0000000..ff86adb
--- /dev/null
+++ b/examples/pulumi/multi-part cloud-init/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "cloud-init.multi-part",
+ "main": "index.ts",
+ "devDependencies": {
+ "@types/node": "^18"
+ },
+ "dependencies": {
+ "@pulumi/cloudinit": "^1.4.1",
+ "typescript": "^5.0.0"
+ }
+}
\ No newline at end of file
diff --git a/examples/pulumi/multi-part cloud-init/tsconfig.json b/examples/pulumi/multi-part cloud-init/tsconfig.json
new file mode 100644
index 0000000..f960d51
--- /dev/null
+++ b/examples/pulumi/multi-part cloud-init/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "outDir": "bin",
+ "target": "es2020",
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "experimentalDecorators": true,
+ "pretty": true,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitReturns": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "files": [
+ "index.ts"
+ ]
+}
diff --git a/knowledge base/cloud-init.md b/knowledge base/cloud-init.md
index 570644f..377d62e 100644
--- a/knowledge base/cloud-init.md
+++ b/knowledge base/cloud-init.md
@@ -4,9 +4,8 @@
1. [TL;DR](#tldr)
1. [Merge 2 or more files or parts](#merge-2-or-more-files-or-parts)
- 1. [In Terraform](#in-terraform)
1. [Further readings](#further-readings)
-1. [Sources](#sources)
+ 1. [Sources](#sources)
## TL;DR
@@ -76,8 +75,6 @@ runcmd:
## Merge 2 or more files or parts
-FIXME
-
See [Merging User-Data sections] for details.
```yaml
@@ -103,9 +100,50 @@ packages:
merge_type: 'list(append)+dict(recurse_array)+str()'
```
-### In Terraform
+
+ In Pulumi
-1. create a data resource containing the files in order, one per part:
+1. Create a data resource containing the files in order, one per part:
+
+ ```ts
+ new cloudinit.Config("example", {
+ gzip: false,
+ base64Encode: false,
+ parts: [
+ {
+ contentType: "text/cloud-config",
+ content: fs.readFileSync("cloud-init/aws.ssm.yaml", "utf8"),
+ filename: "cloud-config.ssm.yml",
+ },
+ {
+ contentType: "text/cloud-config",
+ content: YAML.stringify({
+ number: 3,
+ plain: 'string',
+ block: 'two\nlines\n'
+ }),
+ filename: "cloud-config.inline.yml",
+ mergeType: "dict(recurse_array,no_replace)+list(append)",
+ },
+ ],
+ });
+ ```
+
+1. Give its rendered form as input to a virtual machine's `userdata` attribute, or export it:
+
+ ```ts
+ let userData = new cloudinit.Config("userData", { … });
+ new aws.ec2.Instance("instance", {
+ userData: userData.rendered,
+ …
+ })
+ ```
+
+
+
+ In Terraform
+
+1. Create a data resource containing the files in order, one per part:
```hcl
# https://registry.terraform.io/providers/hashicorp/cloudinit/latest/docs
@@ -134,7 +172,7 @@ merge_type: 'list(append)+dict(recurse_array)+str()'
}
```
-1. give its rendered form as input to a vm's userdata attribute or an output resource:
+1. Give its rendered form as input to a virtual machine's `userdata` attribute or an output resource:
```hcl
resource "azurerm_linux_virtual_machine" "vm" {
@@ -147,6 +185,8 @@ merge_type: 'list(append)+dict(recurse_array)+str()'
}
```
+
+
## Further readings
- [Website]
@@ -158,9 +198,7 @@ merge_type: 'list(append)+dict(recurse_array)+str()'
- [Mime Multi Part Archive] format
- [Docker cloud init example]
-## Sources
-
-All the references in the [further readings] section, plus the following:
+### Sources
- [Debugging cloud-init]
- [Tutorial]
@@ -172,21 +210,19 @@ All the references in the [further readings] section, plus the following:
References
-->
-
-[debugging cloud-init]: https://canonical-cloud-init.readthedocs-hosted.com/en/latest/howto/debugging.html
-[examples]: https://cloudinit.readthedocs.io/en/latest/topics/examples.html
-[merging user-data sections]: https://canonical-cloud-init.readthedocs-hosted.com/en/latest/reference/merging.html
-[modules]: https://cloudinit.readthedocs.io/en/latest/topics/modules.html
-[mime multi part archive]: https://cloudinit.readthedocs.io/en/latest/topics/format.html#mime-multi-part-archive
-[tutorial]: https://canonical-cloud-init.readthedocs-hosted.com/en/latest/tutorial/
-[website]: https://cloud-init.io/
-
-[further readings]: #further-readings
-
[docker cloud init example]: ../examples/cloud-init/docker.yum.yaml
+
+[debugging cloud-init]: https://docs.cloud-init.io/en/latest/howto/debugging.html
+[examples]: https://docs.cloud-init.io/en/latest/reference/examples.html
+[merging user-data sections]: https://docs.cloud-init.io/en/latest/reference/merging.html
+[modules]: https://cloudinit.readthedocs.io/en/latest/topics/modules.html
+[mime multi part archive]: https://cloudinit.readthedocs.io/en/latest/topics/format.html#mime-multi-part-archive
+[tutorial]: https://docs.cloud-init.io/en/latest/tutorial/
+[website]: https://cloud-init.io/
+
[cloud-init configuration merging]: https://jen20.dev/post/cloudinit-configuration-merging/
[cloud-init multipart encoding issues]: https://github.com/hashicorp/terraform/issues/4794