Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: accept cloudinit data inline #12

Open
mark-rushakoff opened this issue Aug 3, 2022 · 3 comments
Open

Feature request: accept cloudinit data inline #12

mark-rushakoff opened this issue Aug 3, 2022 · 3 comments
Labels
enhancement New feature or request

Comments

@mark-rushakoff
Copy link

I am trying to use cloudinit_config with many part blocks to compose a MIME document to use for cloudinit against a multipass resource.

The cloudinit_config resource only exposes a rendered value. I am new to terraform, so maybe I'm missing something, but I don't see a way to write that rendered value to a file, and then provide the path of the file to the multipass resource.

I would like to be able to write:

data "cloudinit_config" "cloudinit_ubuntu" {
  part {
    content = file("./cloudinit/groups.yml")
  }
  part {
    content = file("./cloudinit/users.yml")
  }
  # etc.
}

resource "multipass_instance" "ubuntu" {
  name = "ubuntu"
  disk = "3072MiB"
  memory = "512MiB"

  # cloudinit_data would be mutually exclusive with cloudinit_file
  cloudinit_data = data.cloudinit_ubuntu.rendered
}

AFAICS, it should be okay to hold cloudinit_data in memory, and then pass it as stdin to multipass launch --cloud-init=-, but it could just as well go into a temporary file managed by the multipass provider if necessary.

@larstobi
Copy link
Owner

larstobi commented Aug 3, 2022

Hi, many thanks for your feature request!

Your feature request is a valid one, and is technically possible with multipass. One way to solve it is to have the provider write temporary files with the cloudinit content, and another is to use stdin to pass the content in directly, by using this feature: canonical/multipass#628. Adding this feature is on my horizon. :-)

multipass doesn't provide a way to see the cloudinit file after it has been launched, nor does it give any checksum value for the contents, so it will be impossible to check if any content has changed from its side. So, we can spot any content diffs by using the Terraform state file only.

One way you can work around this provider's lack of a cloudinit_data parameter with Terraform is by using the hashicorp/local provider[1]. It provides you with a local_file resource that you can use to write files.

data "cloudinit_config" "cloudinit_ubuntu" {
  part {
    content = file("./cloudinit/groups.yml")
  }
  part {
    content = file("./cloudinit/users.yml")
  }
  # etc.
}

resource "local_file" "cloudinit_ubuntu" {
  filename = "ubuntu-cloudinit.yml"
  content  = data.cloudinit_config.cloudinit_ubuntu.rendered
}

resource "multipass_instance" "ubuntu" {
  name           = "ubuntu"
  disk           = "3072MiB"
  memory         = "512MiB"
  cloudinit_file = local_file.cloudinit_ubuntu.filename
}

[1] https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file

@larstobi larstobi added the enhancement New feature or request label Aug 3, 2022
@mark-rushakoff
Copy link
Author

Thanks for teaching me how to use the local_file resource properly. That approach correctly passes the rendered file to multipass, but unfortunately, multipass does not (yet) support multipart/mime cloudinit files: canonical/multipass#1892

I can find another way to combine the YAML segments, which will be sufficient if I end up only needing to combine plain cloud config data.

@Schachte
Copy link

Schachte commented Feb 19, 2024

This is how I solved this (adjacent cloud-init template yaml inside of ./template/cloud-init.yaml.tpl)
edit: Just realized it's fairly similar to @larstobi, but this features variable interpolation using template files, so slightly different.

I think passing this in via stdin would be awesome and happy to work on that PR if you haven't already!

resource "local_file" "cloudinit" {
  for_each = { for i, name in var.instance_names : name => {
    ip_address = var.ip_addresses[i]
  } }

  filename = "${path.module}/cloud-init-${each.key}.yaml"
  content = templatefile("${path.module}/templates/cloud-init.yaml.tpl", {
    ip_address = each.value.ip_address
  })
}

resource "multipass_instance" "dev_vm" {
  for_each = { for i, name in var.instance_names : name => {
    ip_address = var.ip_addresses[i]
  } }

  name   = each.key
  cpus   = var.cpus
  memory = var.memory
  disk   = var.disk
  image  = var.image

  cloudinit_file = local_file.cloudinit[each.key].filename
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants