Command-line menu app that builds cloud-init customization configuration for new VM provisioning on VMware vSphere, KVM, and Physical/Other — for both Linux (cloud-init) and Windows (Cloudbase-Init + Sysprep).
Config-only: CloudSeed emits user-data/meta-data, Cloudbase-Init conf files and a Windows Sysprep answer file. It does not build an ISO — you apply the config directly (guestinfo/vApp on vSphere, --cloud-init on KVM, or drop-in on the golden image). See GUIDE.md.
Zero dependencies (Python 3 standard library only). A portable single-file binary is available via python build_dist.py (PyInstaller). Runs on Windows and Linux.
| cloud-init version | Status | Notes |
|---|---|---|
| 23.x - 24.x | ✅ Fully supported | Current stable, all modules |
| 22.x | ✅ Supported | Minor differences in network v2 syntax |
| 21.x | Missing some modules (ntp, growpart) | |
| < 21 | ❌ Not supported | Too old for modern config schema |
CloudSeed generates configs compatible with cloud-init ≥ 22.1. The interactive menu and batch mode will warn if your target image runs an older version. Run cloud-init --version on your golden image to check.
git clone <repo-url> cloudseed
cd cloudseed
pip install -e .Or just run it (no install needed):
python -m cloudseedMain Menu (new in v1.1.0):
cloudseed # or: python -m cloudseedShows: Generate Configuration | Toolbox (External Tools) | Config Validator | Cloud-Init Doctor | Template Maker | Guide Help | Exit
Generate Configuration (interactive menu):
- Pick target platform: vSphere (VMware), KVM (libvirt), or Physical / Other
- Pick OS: Linux or Windows
- Multi-select modules — toggle modules by number +
Enterto confirm (green ✓ = selected), presscto configure selected,a=all,n=none,0=back - For each selected module, configure sub-items one-by-one (press Enter for defaults)
- Choose output directory
- Files generated + apply instructions printed (see GUIDE.md)
Non-interactive (batch) — feed config as JSON:
cloudseed --json config.json --out ./outThis writes (config-only, no ISO):
- Linux:
user-data,meta-data,cloudseed.json,README.txt - Windows:
cloudbase-init.conf,cloudbase-init-unattend.conf,sysprep-unattend.xml,run-sysprep.bat,cloudseed.json,README.txt - vSphere extras:
vsphere-customization-spec.xml,vsphere-pre-script.sh/.bat,vsphere-post-script.sh/.bat
- Run SID Changer (Windows — executes Sysprep-based SID change, must be Administrator)
Config Validator — validate exported configs:
- Check configs won't re-run after first boot
- Verify cloudseed.json consistency
- Validate Windows Sysprep/Cloudbase-Init files
Cloud-Init Doctor — diagnose cloud-init on running systems:
- Full diagnosis (all checks)
- Cloud-init status & version
- Cloud-init configuration
- Boot & service status
- Network configuration
- Disk space
- Save diagnosis report (JSON)
| Module | Linux | Windows | cloud-init min | Description |
|---|---|---|---|---|
hostname |
✅ | ✅ | 22.1 | Set hostname |
users |
✅ | ✅ | 22.1 | Create admin user + password + sudo/Administrators |
ssh |
✅ | ✅ | 22.1 | SSH authorized keys + password auth toggle |
root |
✅ | ❌ | 22.1 | Harden root (disable root SSH login) |
network |
✅ | ✅ | 22.1 | Network (DHCP / static IP, DNS, search domains) |
packages |
✅ | ❌ | 22.1 | Install OS packages / upgrade on first boot |
locale |
✅ | ❌ | 22.1 | Locale + keyboard + timezone |
disk |
✅ | ❌ | 22.1 | Grow root filesystem / LVM (growpart) |
ntp |
✅ | ✅ | 22.1 | NTP time servers + pools |
files |
✅ | ✅ | 22.1 | Write arbitrary files to target |
bootcmd |
✅ | ❌ | 22.1 | Early boot commands (bootcmd) |
firstboot |
✅ | ✅ | 22.1 | First-boot commands (runcmd / LocalScripts) |
final |
✅ | ❌ | 22.1 | Final status message on console |
template_best_practices |
✅ | ✅ | N/A | Template cleanup & preparation (logs, tmp, SSH, machine-id, package cache, journal, udev, Windows updates, event logs, driver store, VM tools, guest agent) |
| Module | Linux | Windows | Description |
|---|---|---|---|
platform_hostname |
✅ | ✅ | Let platform (vSphere/KVM/Physical) set VM hostname (default: on) |
platform_network |
✅ | ✅ | Let platform handle network config (avoid cloud-init conflicts) |
platform_ntp |
✅ | ✅ | Let platform handle NTP (avoid cloud-init conflicts) |
Note: Platform modules now appear for all platforms (vSphere, KVM, Physical/Other). When a platform module is selected, its cloud-init equivalent is auto-disabled (and vice versa).
| Module | Linux | Windows | Description |
|---|---|---|---|
vsphere_spec |
✅ | ✅ | Export vSphere Customization Spec (XML) + import guide |
vsphere_scripts |
✅ | ✅ | vSphere Pre/Post Customization Scripts (with vendor samples) |
- vSphere: apply Linux via VM guestinfo (
guestinfo.userdata/guestinfo.metadata) or dropuser-datainto the golden image's/etc/cloud/cloud.cfg.d/. Windows: placecloudbase-init*.confin the Cloudbase-Init conf dir and runrun-sysprep.batbefore sealing. Use exported Customization Spec XML for vSphere Guest Customization (import guide in generated README.txt). - KVM:
virt-install --cloud-init user-data=./user-data,meta-data=./meta-data, or drop-in on the image. Windows same as vSphere for conf files. - Physical / Other: CloudSeed generates standard cloud-init / Cloudbase-Init configs for any provisioning method (PXE, ISO, config drive, etc.)
- Passwords are hashed by default with a
$6$SHA-512 crypt hash (cloud-init rejects plaintext). Resolution: hostcrypt()→openssl passwd -6→ pure-stdlib fallback. Use--plaintext-passwordto emit plaintext (discouraged). - No ISO is produced — CloudSeed is config-only. Full apply steps in GUIDE.md.
- Conflict avoidance: Enable "Let Platform Handle..." modules to let vSphere/KVM manage hostname/network/NTP instead of cloud-init, avoiding duplicate configuration.
- Overwrite protection: If output file exists, CloudSeed asks: Overwrite / Add suffix / Skip / Overwrite ALL.
- Selector lists for known-value fields — timezone (hierarchical region→zone for Linux, flat list for Windows), locale, keyboard layout, disk device/partition show numbered lists; user picks by number or types custom value. Line-input filtering works in all terminals (SSH, Docker, non-TTY).
- Post-export validation — After generating configs, CloudSeed automatically runs Config Validator on the output directory and shows summary.
| Flag | Effect |
|---|---|
| (none) | Interactive menu (Main Menu → Generate Configuration → platform → OS → modules → per-module overrides). |
--json FILE |
Batch mode: read a saved config and generate files. No prompts. |
--out DIR |
Output directory (default ./cloudseed-out in current path). |
--plaintext-password |
Emit the password verbatim instead of a $6$ SHA-512 hash. Discouraged — cloud-init rejects plaintext on most images. |
--print |
(batch) also print generated contents to stdout. |
--version |
Print CloudSeed <version> and exit. |
--detect-cloud-init |
Detect installed cloud-init version on current system and show compatibility. |
--write-to-cloud-init-path |
Write generated user-data directly to /etc/cloud/cloud.cfg.d/99-cloudseed.cfg (Linux only, requires root). |
cloudseed.json is written alongside every run and is the full config — you can edit it and re-run with --json (no menu). Key fields:
Minimal Linux example:
{"os_type":"linux","modules":["hostname","users","ssh"],
"hostname":"web01","username":"admin","ssh_keys":["ssh-rsa AAAA..."]}Re-run without the menu:
cloudseed --json out/cloudseed.json --out out2CloudSeed validates your configuration and emits warnings:
⚠️ Plaintext password — cloud-init ≥ 22 rejects plaintext passwords. Use default hashing.⚠️ Static network without gateway — may leave VM unreachable.⚠️ Missing SSH keys with password locked — will lock you out iflock_password=trueand no keys.⚠️ Windows without Sysprep — cloning without generalize creates duplicate SIDs.⚠️ cloud-init version < 22 — some modules (ntp, growpart) may not work.⚠️ Disk grow on wrong device — verify/dev/sda1exists on target image.⚠️ Package list empty with upgrade — upgrade runs but installs nothing extra.
Warnings are printed during interactive/batch mode and also written to the output README.txt.
Validate exported configurations after generation or on existing config directories:
cloudseed # Main Menu → Config Validator → Validate a config directoryChecks:
- No persistent runs:
runcmd(per-instance),bootcmd(every boot),phone_home, package update/upgrade - cloudseed.json consistency: required fields, module/file matching
- Windows: sysprep-unattend.xml (generalize/specialize/oobe passes), Cloudbase-Init configs
Diagnose cloud-init issues on a running system (requires cloud-init installed locally):
cloudseed # Main Menu → Cloud-Init Doctor → Full DiagnosisChecks:
- Cloud-init status: version, enabled, running, stage completion (generator, local, network, config, final)
- Configuration: merged config query, config file locations
- Boot & services: systemd status for all cloud-init services, failed units
- Network: netplan, networkd, current interfaces
- Disk space: df output with low-space warnings
- Save report: JSON output for CI/CD integration
By default CloudSeed creates ./cloudseed-out/ in the current working directory. Generated files are organized into platform/OS specific subdirectories (e.g., vsphere-linux/, kvm-windows/, physical-linux/) for easier management of multi-platform configurations. The directory contains all generated files plus a README.txt with apply instructions specific to your configuration.
For creating a golden image / template:
- Run CloudSeed with your desired modules
- Apply the config to a VM (see GUIDE.md)
- Linux:
sudo cloud-init clean --machine-idthen shutdown - Windows: run
run-sysprep.bat(as Administrator) — VM shuts down with generalized state - Convert VM to template / clone — each clone gets fresh identity
MIT
{ "platform": "vsphere", // "vsphere" | "kvm" | "physical" "os_type": "linux", // "linux" | "windows" "modules": ["hostname","users","ssh","network","packages","firstboot"], "hostname": "", // empty = auto-generate from prefix "hostname_prefix": "vm", // prefix for auto-generated hostname "use_platform_hostname": true, // let platform (vSphere/KVM) set hostname "username": "admin", "password": "ChangeMe!123", // hashed to $6$ by default "plaintext_password": false, // true => emit plaintext (see flag) "password_rounds": 5000, "sudo": true, "lock_password": false, "ssh_pwauth": false, "disable_root": true, "ssh_keys": ["ssh-rsa AAAA..."], "net_mode": "dhcp", // "dhcp" | "static" "net_interface": "eth0", "net_address": "", "net_netmask": "255.255.255.0", "net_gateway": "", "net_dns": ["8.8.8.8","1.1.1.1"], "net_search": [], "let_platform_handle_network": false, // let platform handle network (avoid conflicts) "package_upgrade": true, "packages": ["nginx"], "timezone": "UTC", "locale": "en_US.UTF-8", "keyboard_layout": "us", "grow_device": "/dev/sda", "grow_partition": "1", "ntp_servers": ["pool.ntp.org"], "let_platform_handle_ntp": false, // let platform handle NTP "write_files": [{"path":"/etc/foo","content":"bar","permissions":"0644"}], "bootcmd": [], "firstboot": ["systemctl enable nginx"], "final_message": "CloudSeed: system ready.", // Windows only: "sysprep": true, "sysprep_organization": "MyOrg", "sysprep_owner": "Administrator", "sysprep_computer_prefix": "WIN", "sysprep_timezone": "W. Europe Standard Time", "sysprep_locale": "en-US", "sysprep_product_key": "", // vSphere Customization Spec export: "export_vsphere_spec": false, "vsphere_spec_name": "CloudSeed-Spec", // vSphere Pre/Post Customization Scripts: "vsphere_pre_script": "", "vsphere_post_script": "", "use_sample_scripts": false }