Cloudinit define custom commands with runcmd

nook24

Member
Sep 3, 2020
5
0
6
33
Hi folks,
I'm pretty new to cloud-init and was playing around with it today. I struggle a bit with executing a custom command.
I have found this post https://forum.proxmox.com/threads/cloudinit-userdata-runcmd.53099/ and this blog post https://blog.dustinrue.com/2020/05/going-deeper-with-proxmox-cloud-init/ explaining pretty much the steps required to add runcmd commands.

The question I have is, do I really have to put all the Proxmox defaults into a snippets/user-data.yml file, or can I only add my runcmd part and Proxmox will merge both files together?
If I have to pass the complete file, is it still possible to edit cloud-init options via the Proxmox GUI?
At the moment I'm not feeling comfortable to create snippets at all.

What I try to achieve is, to add a generic cloud image from Ubuntu and Debian as a VM template. I'm doing this like so and it is working perfectly fine so far.

Code:
wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img

qm create 7000 --name "ubuntu-2004-cloudinit-template" --cores 2 --sockets 1 --memory 2048 --net0 virtio,bridge=vmbr0 --agent 1 --ostype l26
qm importdisk 7000 focal-server-cloudimg-amd64.img local-zfs
qm set 7000 --scsihw virtio-scsi-pci --scsi0 local-zfs:vm-7000-disk-0,cache=writeback,discard=on
qm set 7000 --serial0 socket --vga serial0
qm set 7000 --ide2 local-zfs:cloudinit
qm set 7000 --boot c --bootdisk scsi0
qm set 7000 --ipconfig0 ip=dhcp
qm set 7000 --nameserver 192.168.0.1
qm set 7000 --searchdomain "home.lab"
qm set 7000 --ciuser root
qm set 7000 --sshkeys "/var/lib/homelab/ansible_id_rsa.pub"

Is it possible to add a runcmd via qm set somehow? I would need this to trigger an HTTP API to start Ansible which will install some packages and configurations onto the system.
 
The cloudinit consists of two parts: Instance Data and User Data. Instance Data is further split into subsections of Network/Meta/Vendor:
https://cloudinit.readthedocs.io/en/latest/topics/instancedata.html

The UI/CLI support in Proxmox provides basic minimum to get folks going. For anything more advanced you will need to provide a custom file via snippet.
There is no merging between default PVE userdata and custom one.

There are two approaches :
- You can do it all via CloudInit and use absolute basic OS template
- You can pre-install your packages and configuration changes and then convert the VM to template. There are a few guides on the net on how to prep a VM to be a template.

Its up to you which way to go.

Good luck

Blockbridge: Ultra low latency all-NVME shared storage for Proxmox - https://www.blockbridge.com/proxmox
 
I found a solution that looks promising. In the past I did build my own templates. But this was always a hassle to update the templates and to create new once. So basically this is the reason why I want to go with the generic cloud images.

I also don't want to lose the functionality to edit the basic cloud-init config via the Proxmox UI. So for this reason I don't want to modify the files in the backend.

If a Proxmox dev reads this, would be cool if you add the runcmd option to cloud-init :)

For now, I download the cloud image, than manipulate the qcow2 file with guestfish and inject a new systemd service.
The systemd service just executes curl to trigger an HTTP API endpoint which will tell my Ansilbe Server to execute Ansible onto this IP address.

Bash:
#!/bin/bash

/usr/bin/guestfish <<_EOF_
add /tmp/focal-server-cloudimg-amd64.img
run
mount /dev/sda1 /
upload -<<END /lib/systemd/system/after-cloudinit.service
[Unit]
Description=Runs as soon as cloud-init has finisehd
After=network-online.target cloud-final.service
After=multi-user.target
Before=apt-daily.service
Wants=network-online.target

[Service]
Type=oneshot
# Tell Ansible Semaphore to run Playbook on me
ExecStart=/usr/bin/curl http://192.168.0.2/provisioning
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
END

command "/bin/systemctl enable after-cloudinit.service"
unmount /
_EOF_

This is a bit hacky, but it looks like it works fine.