cloud init plugin not being applied (a working example would be handy)
version 14.12
command:
sudo sdm --customize
--plugin user:"deluser=pi"
--plugin cloudinit:"userdata=$2"
--extend --xmb 4096
--regen-ssh-host-keys
--reboot 5
--nowait-timesync
--redact
$1
I've used it for initializing ubuntu systems and have had success with the following project and used it and the documentation you link to ubuntu-autoinstall
this is the user data file i'm trying to apply. user-data.yml
i noticed this in the imaging log Plugin cloudinit: Append userdata '/etc/sdm/assets/cloudinit/userdata/user-data.yml.yaml' to /boot/firmware/user-data my file was named user-data.yml, I changed to remove the extension, but still it's not being applied it's in the location above but boot/firmware/user-data is an empty directory
this is the output from the image creation
-
Mount IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' mount: /dev/loop0p2 mounted on /mnt/sdm. mount: /dev/loop0p1 mounted on /mnt/sdm/boot/firmware.
-
Unmount IMG for --extend umount: /mnt/sdm/boot/firmware unmounted umount: /mnt/sdm unmounted
-
Extend IMG by 4096MB (4.3GB, 4.0GiB)...
-
Resize partition 2 of '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' to 6728MB
-
Remount IMG to resize the file system
-
Mount IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' mount: /dev/loop0p2 mounted on /mnt/sdm. mount: /dev/loop0p1 mounted on /mnt/sdm/boot/firmware.
-
Resize the file system % (Ignore 'on-line resizing required' message) resize2fs 1.47.0 (5-Feb-2023) Filesystem at /dev/loop0p2 is mounted on /mnt/sdm; on-line resizing required old_desc_blocks = 1, new_desc_blocks = 1 The filesystem on /dev/loop0p2 is now 1642496 (4k) blocks long.
-
Start Configuration
Command Line: /usr/local/bin/sdm --customize --plugin user:deluser=pi --plugin cloudinit:userdata=/home/tcronin/src/piImage/build/user-data --extend --xmb 4096 --regen-ssh-host-keys --reboot 5 --nowait-timesync --redact /home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img
- Host Information Hostname: tec-pi-mgr Pagesize: 16384 Memory: 8256656 kB uname: Linux tec-pi-mgr 6.12.47+rpt-rpi-2712 #1 SMP PREEMPT Debian 1:6.12.47-1+rpt1~bookworm (2025-09-16) aarch64 GNU/Linux Raspberry Pi Model: Raspberry Pi 5 Model B Rev 1.0 os-release Name: Debian GNU/Linux 12 (bookworm) Version: 12 (bookworm) sdm Version: V14.12
- IMG Information Name: /home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img Date: 2025-11-24 RasPiOS Version: 13 RasPiOS Architecture: 64-bit aarch64 os-release Version: 13 (trixie)
- Plugins selected:
(Plugin arguments redacted per --redact)
- user
- cloudinit
IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4156732 1K-blocks (4.3GB, 4.0GiB) free Copy sdm to /usr/local/sdm in the IMG
- Start Phase 0 image customization
Run Plugins Phase '0' Run Plugin 'user' (/mnt/sdm/usr/local/sdm/plugins/user) Phase 0
- Plugin user: Start Phase 0
Plugin user: Keys/values found: deluser: pi
- Plugin user: Complete Phase 0
Run Plugin 'cloudinit' (/mnt/sdm/usr/local/sdm/plugins/cloudinit) Phase 0
- Plugin cloudinit: Start Phase 0
Plugin cloudinit: Keys/values found: userdata: /home/tcronin/src/piImage/build/user-data Plugin cloudinit: Copy userdata file '/home/tcronin/src/piImage/build/user-data' to /mnt/sdm/etc/sdm/assets/cloudinit/userdata
- Plugin cloudinit: Complete Phase 0
- Phase 0 Completed
- Enter image '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' for Phase 1
- Start Phase 1 image customization
IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4156696 1K-blocks (4.3GB, 4.0GiB) free at start of Phase 1 image customization Start 'apt update' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4156696 1K-blocks (4.3GB, 4.0GiB) free at start of 'apt update' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4156524 1K-blocks (4.3GB, 4.0GiB) free at end of 'apt update' Run Plugins Phase '1' Run Plugin 'user' (/usr/local/sdm/plugins/user) Phase 1
- Plugin user: Start Phase 1
Plugin user: Delete user 'pi' userdel: pi mail spool (/var/mail/pi) not found
- Plugin user: Complete Phase 1
Run Plugin 'cloudinit' (/usr/local/sdm/plugins/cloudinit) Phase 1
- Plugin cloudinit: Start Phase 1
- Plugin cloudinit: Complete Phase 1
- Phase 1 post-app installation/configuration
Start 'apt upgrade' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4156524 1K-blocks (4.3GB, 4.0GiB) free at start of 'apt upgrade' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145448 1K-blocks (4.2GB, 4.0GiB) free at end of 'apt upgrade' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145444 1K-blocks (4.2GB, 4.0GiB) free at end of Phase 1 image customization
- Phase 1 Completed
Run Plugins Phase 'post-install' Run Plugin 'user' (/usr/local/sdm/plugins/user) Phase post-install
- Plugin user: Start Phase post-install % Plugin user: No saved passwords found to redact
Plugin user: Redact any userlists in /etc/sdm/assets/user
- Plugin user: Complete Phase post-install
Run Plugin 'cloudinit' (/usr/local/sdm/plugins/cloudinit) Phase post-install
- Plugin cloudinit: Start Phase post-install
Plugin cloudinit: Append userdata '/etc/sdm/assets/cloudinit/userdata/user-data.yaml' to /boot/firmware/user-data
- Plugin cloudinit: Complete Phase post-install
Start 'apt autoremove' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145444 1K-blocks (4.2GB, 4.0GiB) free at start of 'apt autoremove' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145444 1K-blocks (4.2GB, 4.0GiB) free at end of 'apt autoremove' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145444 1K-blocks (4.2GB, 4.0GiB) free at end of image customization Configure and enable sdm FirstBoot service (sdm-firstboot) Run graphics post-install configuration Plugin sdm.phaseops: No sdm-configurable Display Manager found Plugin sdm.phaseops: Set RasPiOS to B1:'console no login' for sdm FirstBoot Configure SSH Plugin sdm.phaseops: Enable SSH service Write sdm FirstBoot L10n configuration script Customize elapsed time: 00:00:10
% Customization warning messages: 2025-12-04 19:22:31 % Plugin user: No saved passwords found to redact
- Run bash on non-terminal standard input umount: /mnt/sdm/boot/firmware unmounted umount: /mnt/sdm unmounted
- Start shrink on IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img'
Check the file system rootfs: 72834/399024 files (0.2% non-contiguous), 531552/1642496 blocks resize2fs 1.47.0 (5-Feb-2023) Shrink the root file system from 1642496 (6.7GB, 6.3GiB) to 685472 4096-byte blocks (2.8GB, 2.6GiB) resize2fs 1.47.0 (5-Feb-2023) Resizing the filesystem on /dev/loop0 to 685472 (4k) blocks. Begin pass 2 (max = 10533) Relocating blocks XXXXXXX--------------------------------- XXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 0% EXECUTING [11s] Begin pass 3 (max = 51) XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXECUTING [11s] The filesystem on /dev/loop0 is now 685472 (4k) blocks long.
% Ignore Warning about shrinking a partition may cause data loss
Warning: Shrinking a partition can cause data loss, are you sure you want to continue? Yes/No? Yes
Shrink the image by truncating to 3352952832 (3.4GB, 3.1GiB)
- Shrink complete IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' was (7.3GB, 6.8GiB) now (3.4GB, 3.1GiB)
Can you provide me the yml you're using (appropriately redacted)?
Thx!
https://raw.githubusercontent.com/tim-oe/piImage/refs/heads/main/src/cloud-init/pi/user-data.yml
Thx! On it in the morning.
OK, I reread your post a couple of times, and I'm pretty convinced that one or both of us are confused 🤪. In the log you provided, I see
Plugin cloudinit: Start Phase post-install Plugin cloudinit: Append userdata '/etc/sdm/assets/cloudinit/userdata/user-data.yaml' to /boot/firmware/user-data
So, it's putting the file in the correct place. Can you verify that the file you provided is in /boot/firmware?
Next, you've said that the cloudinit plugin is not being applied. From my perspective, IF the file is in /boot/firmware per the above, then the cloudinit plugin is working correctly.
On the other hand, if your expectation is that the cloud-init user-data configuration runs as part of sdm's customization, that's an interesting idea, but not the way it works today (it's "V1" 😉)
In looking into the feasibility of running it as part of customization, it appears to be possible, with limitations. For instance, some networking stuff may not work, and hardware things like disk partitioning definitely won't work. It also may require running systemd-nspawn with the --boot switch, which sdm doesn't use today for anything.
The yml file you pointed me at has functions in it that are very close to what sdm's customization provides. I envisioned that an sdm user might want to use the cloudinit plugin for certain features that are not in sdm.
Looking forward to hearing your thoughts on this...both with what's there today (besides being minimal!), and what you'd like to see longer term, hopefully with a bit of context so I can understand what you're trying to do.
Thx!
running the command getting the following output:
Run Plugin 'cloudinit' (/usr/local/sdm/plugins/cloudinit) Phase post-install
- Plugin cloudinit: Start Phase post-install
Plugin cloudinit: Append userdata '/etc/sdm/assets/cloudinit/userdata/user-data.yaml' to /boot/firmware/user-data
- Plugin cloudinit: Complete Phase post-install
Start 'apt autoremove' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145444 1K-blocks (4.2GB, 4.0GiB) free at start of 'apt autoremove' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145444 1K-blocks (4.2GB, 4.0GiB) free at end of 'apt autoremove' IMG '/home/tcronin/src/piImage/build/2025-11-24-raspios-trixie-arm64-lite.img' has 4145444 1K-blocks (4.2GB, 4.0GiB) free at end of image customization Configure and enable sdm FirstBoot service (sdm-firstboot) Run graphics post-install configuration Plugin sdm.phaseops: No sdm-configurable Display Manager found Plugin sdm.phaseops: Set RasPiOS to B1:'console no login' for sdm FirstBoot Configure SSH Plugin sdm.phaseops: Enable SSH service Write sdm FirstBoot L10n configuration script Customize elapsed time: 00:00:10
then mounting the image the file is in this folder root@tec-thinkpad:/media/tcronin/rootfs/etc/sdm/assets/cloudinit/userdata# ls -l total 4 -rw-r--r-- 1 root root 2911 Dec 6 00:30 user-data.yaml
but the there's no /boot/firmware/userdata
root@tec-thinkpad:/media/tcronin/rootfs/boot/firmware# ls -l total 0
here's the image file that was generated https://drive.google.com/file/d/1oVCCUu-WV814I_ERgK627dViJi4ol1Ho/view?usp=sharing
Is it possible that you're not looking at the /boot/firmware of the customized IMG?
I just downloaded the IMG you provided (thanks...a great simplification in chasing this down), and here's what I found:
pw/l/tmp# ls -l pi-image.img
-rwxr--r-- 1 bls users 3352948736 Dec 6 16:17 pi-image.img
pw/l/tmp# sdm --explore pi-image.img
* Mount IMG 'pi-image.img'
mount: /dev/loop1p2 mounted on /mnt/sdm.
mount: /dev/loop1p1 mounted on /mnt/sdm/boot/firmware.
* Enter IMG 'pi-image.img'
root@sdm:/# cd /etc/sdm/assets/cloudinit/userdata/
root@sdm:/etc/sdm/assets/cloudinit/userdata# ls -al
total 12
drwxr-xr-x 2 root root 4096 Dec 5 22:30 .
drwxr-xr-x 5 root root 4096 Dec 5 22:30 ..
-rw-r--r-- 1 root root 2911 Dec 5 22:30 user-data.yaml
root@sdm:/etc/sdm/assets/cloudinit/userdata# tail user-data.yaml
ethernets:
eth:
match:
name: eth*
dhcp4: true
# format drive using defaults
storage:
layout:
name: direct
root@sdm:/etc/sdm/assets/cloudinit/userdata# cd /boot/firmware
root@sdm:/boot/firmware# ls -l user-data
-rwxr-xr-x 1 root root 6300 Dec 5 22:30 user-data
root@sdm:/boot/firmware# tail user-data
eth:
match:
name: eth*
dhcp4: true
# format drive using defaults
storage:
layout:
name: direct
# End sdm userdata file 'user-data.yaml'
it's totally possible that i'm not looking in the right place for it. I'm mounting the iso and browsing the rootfs mount. that being said it still not running it as the default install process screens launch. i can complete the manual install and can send you addition data/logs, just let me know what you need.
as to your other points, yes there's tons of overlap with what you've implemented and what cloud init does, with yours being specialized for the PI. it's really been beneficial and has saved me tons of time and grief, thanks for that!
i've used cloud-init for provisioning ubuntu base systems, including vms, and saw you had it and wondered if i could standardize.
My goal with both cloud-init and sdm is to seed the image with enough configuration so that i can the complete the setup with ansible. Setup, disk, networking, ssh, user creds, base packages.
it's totally possible that i'm not looking in the right place for it. I'm mounting the iso and browsing the rootfs mount. that being said it still not running it as the default install process screens launch. i can complete the manual install and can send you addition data/logs, just let me know what you need.
I'm afraid you missed my point. You ARE looking in the wrong place, as I demonstrated. I used sdm --explore to mount and enter the IMG container, and the file /boot/firmware/user-data definitely exists. Since you didn't provide console output for the way you mounted the IMG, I can only assume that you only mounted the rootfs and not the bootfs.
So, this aspect is a user error on your point.
That said, I'm currently unable to get the user-data file to correctly process. cloud-init has some sort of gut-spilling python errors logged which provide no helpful information for a cloud-init newbie to sort out.
I'm still looking into this aspect, and will update this when I've got something to report.
as to your other points, yes there's tons of overlap with what you've implemented and what cloud init does, with yours being specialized for the PI. it's really been beneficial and has saved me tons of time and grief, thanks for that! i've used cloud-init for provisioning ubuntu base systems, including vms, and saw you had it and wondered if i could standardize. My goal with both cloud-init and sdm is to seed the image with enough configuration so that i can the complete the setup with ansible. Setup, disk, networking, ssh, user creds, base packages.
I think there are differentiated uses for sdm and cloud-init on RasPiOS, driven by preference (in some cases). It's worth noting that, in general, sdm customizations are done either when the IMG is customized (using sdm) or when it's burned (also using sdm...can run additional plugins, etc).
Cloud-init, on the other hand, runs during system boot. In some cases, it appears to cause an additional system reboot, which I don't understand yet. Worth noting that cloud-init can be used on other Linux platforms, so more important and useful in multi-OS environments.
sdm pulls customization to be done as early as is feasible, while cloud-init does all customizations after the system has booted. Both generally equivalent, and indeed, cloud-init is the only way to do things in certain environments (cloud instantiations, etc).
But, in the Pi case, if you're bringing up a handful of Pis and want to install some "stuff" into them, sdm enables you to customize a single IMG with all the apps installed and then install only those apps that are unique to a particular host.
With cloud-init, the whole lot of apps will be installed at boot time on each and every Pi. With a large collection of apps this could end up taking a fair amount of time and bandwidth.
thanks for the update i will use the explore flag going forward. i will stick with the sdm features for pi as they work. feel free to prioritize this as you see fit, as i was just seeing the feasibility to use it to standardize some processes. thanks for you efforts
thanks for the update i will use the explore flag going forward. i will stick with the sdm features for pi as they work. feel free to prioritize this as you see fit, as i was just seeing the feasibility to use it to standardize some processes. thanks for you efforts
You're welcome! And thanks for trying the cloudinit plugin. I definitely want to get it working correctly, so I'll (hopefully) have good news on having cloud-init process it correctly.
OK...it works now. I did not get the fix to the cloudinit plugin into V14.13, but it is checked into github so you can download it from the main branch.
I did not try your yaml, but this one works with no errors:
#cloud-config
hostname: pit
manage_etc_hosts: true
packages:
- avahi-daemon
apt:
conf: |
Acquire {
Check-Date "false";
};
timezone: America/Los_Angeles
keyboard:
model: pc105
layout: "us"
enable_ssh: true
users:
- name: nouser
groups: users
shell: /usr/sbin/nologin
no_create_home: true
no_user_group: true
no_log_init: true
sudo: null
- name: blsxyz
groups: users,adm,dialout,audio,netdev,video,plugdev,cdrom,games,input,gpio,spi,i2c,render,sudo
shell: /bin/bash
lock_passwd: false
passwd: <redacted>
sudo: ALL=(ALL) NOPASSWD:ALL
runcmd:
- [ rfkill, unblock, wifi ]
- [ sh, -c, "for f in /var/lib/systemd/rfkill/*:wlan; do echo 0 > \"$f\"; done" ]
LMK how it goes for you. Thx!
thanks for the example shed some light on some of the ubuntu specific configs i have in mine. i updated my local cloudinit script from the repo
i took your file and made minor changes, see attached user-data.yml
in running i see some of he cloud init services fail but the interactive installer doesn't launch and i get the the login prompt after a reboot
hostname is set but users/groups are not created, i was able to hand edit the sdcard to login but not seeing what the errors might be. attached is the logs.
cloud-init.log cloud-init-output.log
here's the image created: https://drive.google.com/file/d/1qFaQZm9zVCs18QNcgjj_nXWsFy3RuMUJ/view?usp=sharing
let me know what other information you need.
thanks for the example shed some light on some of the ubuntu specific configs i have in mine. i updated my local cloudinit script from the repo
i took your file and made minor changes, see attached user-data.yml
in running i see some of he cloud init services fail but the interactive installer doesn't launch and i get the the login prompt after a reboot
hostname is set but users/groups are not created, i was able to hand edit the sdcard to login but not seeing what the errors might be. attached is the logs.
cloud-init.log cloud-init-output.log
here's the image created: https://drive.google.com/file/d/1qFaQZm9zVCs18QNcgjj_nXWsFy3RuMUJ/view?usp=sharing
let me know what other information you need.
I'm afraid you've mistaken me for someone who is cloud-init knowledgeable 😲
In spite of my lack of knowledge 🤣I took a look at your IMG and fiddled with it a bit. If you remove sdm's user:deluser=pi the users specified in user-data will be created (and the user pi ends up evaporated). I can't explain this yet.
I'm not sure what interactive installer you're referring to.
I did notice there was an error at the end of /var/log/cloud-init-output.log:
sh: 1: cannot create : Directory nonexistent
No clue where that came from, or what process/script is mal-formed to cause this.
That's pretty much the extent of my cloud-init knowledge at this point. Here are some hints for you as you work through this:
- ALWAYS use the sdm plugin
--plugin system:journal=persistent. The default on Trixie is "volatile", which evaporates all prior logs. The first boot log, viewed with journalctl, can be quite helpful. - Always review /var/log/cloud-init.log and /var/log/cloud-init-output.log.
- If there are any python stack traces in there, something is wrong. cloud-init has a strange philosophy for reporting errors
- Errors I've noticed that seem to be innocuous:
- No module named cc_netplan_nm_patch. Everyone gets this
- Sub-process /usr/bin/sqv gets a signature error. Probably bc the system time hasn't synced yet. Ignore it
- sdm and cloud-init can step on each other's toes if you aren't careful. Really careful. The reason I added the cloudinit plugin wasn't to use it for basic system customization. Rather it was to be able to leverage more complex cloud-init configuration stuff that might appear in the future (e.g., installing and configuring some complex app, etc).
- Remember that sdm tries to do customizations as early as possible, while cloud-init can only do customizations once the system has booted (literally as late as possible). There are advantages to both, depending on the scenario, but force-fitting them together on the same customization surfaces can be a less-than-joyous experience.
ok, i'll remove the user plugin def conflicting not sure if the directory issue is related to the nouser user?
i'm no expert either lots of CCP and googling and fingers crossed
here's a vid of the startup, initially cloud-init.local and clound-init.network fail but after the reboot they are runnning https://drive.google.com/file/d/1Cu2nM5CVODkTYopjTjD2lCZ5FD_May1C/view?usp=sharing
wonder if the cloud init network failure is that i'm also using your network plugin and it assumes pristine system.
ran again without the user plugin, also noticed noticed error thrown during run command, removing that section it ran without errors. the rfkill isn't needed as wifi worked after reboot
this is what i got working hostname: HOSTNAME manage_etc_hosts: true packages:
- htop
apt:
conf: |
Acquire {
Check-Date "false";
};
timezone: Etc/UTC
keyboard:
model: pc105
layout: "us"
enable_ssh: true
users:
-
name: tcronin groups: users,adm,dialout,audio,netdev,video,plugdev,cdrom,games,input,gpio,spi,i2c,render,sudo shell: /bin/bash lock_passwd: false passwd: ${TEC_PWD_HASH} sudo: ALL=(ALL) NOPASSWD:ALL ssh_authorized_keys:
- ${TEC_AUTH_KEY}
-
name: ansible groups: users,adm,sudo shell: /bin/bash lock_passwd: true passwd: ${ANS_PWD_HASH} sudo: ALL=(ALL) NOPASSWD:ALL ssh_authorized_keys:
- ${ANS_AUTH_KEY}
-
the sdm image command:
sudo sdm --customize
--plugin cloudinit:"userdata=$2"
--plugin network:"netman=nm|ifname=wlan0|wifissid=<REDACT>|wifipassword=$WIFI_PWD|wificountry=US"
--extend --xmb 4096
--regen-ssh-host-keys
--reboot 5
--nowait-timesync
--redact
$1
going to mark this resolved,