Hi guys, I have gotten cloud init to work with windows with some modification to proxmox and a windows template. since all of the other threads regarding this don't work anymore, at least i couldn't get them to, i thought i would share what i did.
the part is making proxmox save windows passwords as plaintext, or else the template cannot read them. i did this by editing
old code, line 1022:
new code, replace above:
then i changed some code to edit the metadata passed to the VM
line 210 in
this passes in hostname and ssh keys, i will get ssh keys working inside soon. it also adds the password here.
below this function, in
to
this is because it needs some extra arguments now.
one last step here, on line 200 and 204 in this file, in the function
without this dns will not set inside.
now we can start creating a windows template. download windows server iso and install, install qemu guest agent and virtio tools etc, normal stuff. you may want to snapshot now also in case you mess up some next steps or you want this clean image available as well.
next install cloudbase-init. make sure you have a serial port on your VM and you choose com1 during install for logging. pick Administrator as username during install. do not run sysprep or reboot afterwards. snapshot again if you like.
we will need to edit some cloudbase code to make things work better now. first edit is making the cloud init drive eject after cloudbase is done, so users cant see it for added security, especially since password is plaintext now. follow this guide to that https://ask.cloudbase.it/question/2939/how-to-umount-cd-drive-after-cloudbase-init-completed/
now we can edit cloud base config at C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf. you should read docs on what you can do here. you will want the configdrive meta data service, and inject password = no if you want to be able to rdp without changing pw over vnc. enable what plugins you would like here. below is example of mine
after, make sure the unattend conf matches the normal conf. then, run sysprep with commands below:
then, convert to template, and try it out. open a serial console to see logging if things fail. post your errors here if its not working and I will try to help.
the part is making proxmox save windows passwords as plaintext, or else the template cannot read them. i did this by editing
/usr/share/perl5/PVE/API2/Qemu.pm
old code, line 1022:
Perl:
if (defined(my $cipassword = $param->{cipassword})) {
# Same logic as in cloud-init (but with the regex fixed...)
$param->{cipassword} = PVE::Tools::encrypt_pw($cipassword)
if $cipassword !~ /^\$(?:[156]|2[ay])(\$.+){2}/;
}
Perl:
my $conf = PVE::QemuConfig->load_config($vmid);
my $ostype = $conf->{ostype};
if (defined(my $cipassword = $param->{cipassword})) {
# Same logic as in cloud-init (but with the regex fixed...)
if (!(PVE::QemuServer::windows_version($ostype))) {
$param->{cipassword} = PVE::Tools::encrypt_pw($cipassword)
if $cipassword !~ /^\$(?:[156]|2[ay])(\$.+){2}/;
}
}
then i changed some code to edit the metadata passed to the VM
line 210 in
/usr/share/perl5/PVE/QemuServer/Cloudinit.pm
replace the old configdrive2_metadata function with this:
Perl:
sub configdrive2_metadata {
my ($conf, $vmid, $user, $network) = @_;
my $uuid = Digest::SHA::sha1_hex($user.$network);
my $password = $conf->{cipassword};
my ($hostname, $fqdn) = get_hostname_fqdn($conf, $vmid);
my $startConfig = <<"EOF";
{
"hostname": "$hostname",
"uuid": "$uuid",
"admin_pass": "$password",
EOF
if (defined(my $keys = $conf->{sshkeys})) {
$startConfig .= " \"network_config\": { \"content_path\": \"/content/0000\" },\n";
$keys = URI::Escape::uri_unescape($keys);
$keys = [map { my $key = $_; chomp $key; $key } split(/\n/, $keys)];
$keys = [grep { /\S/ } @$keys];
$startConfig .= " \"keys\": [\n";
$startConfig .= " {\n";
my $keyCount = @$keys;
for (my $i=0; $i < $keyCount; $i++) {
# $startConfig .= " $keyCount "
if ($i == $keyCount-1){
$startConfig .= " \"key-$i\": \"".$keys->[$i]."\"\n";
} else {
$startConfig .= " \"key-$i\": \"".$keys->[$i]."\",\n";
}
}
$startConfig .= " }\n";
$startConfig .= " ]\n";
} else{
$startConfig .= " \"network_config\": { \"content_path\": \"/content/0000\" }\n";
}
$startConfig.= "}";
return $startConfig;
}
this passes in hostname and ssh keys, i will get ssh keys working inside soon. it also adds the password here.
below this function, in
generate_configdrive2
function, change:
Perl:
if (!defined($meta_data)) {
$meta_data = configdrive2_gen_metadata($user_data, $network_data);
}
Perl:
if (!defined($meta_data)) {
$meta_data = configdrive2_metadata($conf, $vmid, $user_data, $network_data);
}
one last step here, on line 200 and 204 in this file, in the function
configdrive2_network
proxmox has a small typo for dns servers and search domain (search domain not working yet, i will be back soon). change the _ to - so it looks like this:
Perl:
if ($nameservers && @$nameservers) {
$nameservers = join(' ', @$nameservers);
$content .= " dns-nameservers $nameservers\n";
}
if ($searchdomains && @$searchdomains) {
$searchdomains = join(' ', @$searchdomains);
$content .= " dns-search $searchdomains\n";
}
now we can start creating a windows template. download windows server iso and install, install qemu guest agent and virtio tools etc, normal stuff. you may want to snapshot now also in case you mess up some next steps or you want this clean image available as well.
next install cloudbase-init. make sure you have a serial port on your VM and you choose com1 during install for logging. pick Administrator as username during install. do not run sysprep or reboot afterwards. snapshot again if you like.
we will need to edit some cloudbase code to make things work better now. first edit is making the cloud init drive eject after cloudbase is done, so users cant see it for added security, especially since password is plaintext now. follow this guide to that https://ask.cloudbase.it/question/2939/how-to-umount-cd-drive-after-cloudbase-init-completed/
now we can edit cloud base config at C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf. you should read docs on what you can do here. you will want the configdrive meta data service, and inject password = no if you want to be able to rdp without changing pw over vnc. enable what plugins you would like here. below is example of mine
Code:
[DEFAULT]
username=Administrator
groups=Administrators
inject_user_password=no
config_drive_raw_hhd=true
config_drive_cdrom=true
config_drive_vfat=true
bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe
mtools_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\
verbose=true
debug=true
logdir=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\log\
logfile=cloudbase-init.log
default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN,requests=WARN
logging_serial_port_settings=COM1,115200,N,8
mtu_use_dhcp_config=false
ntp_use_dhcp_config=false
metadata_services=cloudbaseinit.metadata.services.configdrive.ConfigDriveService
local_scripts_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\
check_latest_version=true
plugins=cloudbaseinit.plugins.common.networkconfig.NetworkConfigPlugin,cloudbaseinit.plugins.common.mtu.MTUPlugin,cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin,cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin,cloudbaseinit.plugins.common.sshpublickeys.SetUserSSHPublicKeysPlugin,cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin
after, make sure the unattend conf matches the normal conf. then, run sysprep with commands below:
Code:
cd C:\Program Files\Cloudbase Solutions\Cloudbase-Init\conf
C:\Windows\System32\sysprep\sysprep.exe /generalize /oobe /unattend:Unattend.xml
Last edited: