]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
cleanup cloud-init option descriptions
[qemu-server.git] / PVE / QemuServer.pm
index 8fab6b85e68caf651170426250b7f723c565944f..628ca3359cf11140ebb1d1242dabfb1e8e1c9aba 100644 (file)
@@ -45,6 +45,8 @@ my $qemu_snap_storage = {rbd => 1, sheepdog => 1};
 
 my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
 
+my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
+
 # Note about locking: we use flock on the config file protect
 # against concurent actions.
 # Aditionaly, we have a 'lock' setting in the config file. This
@@ -535,6 +537,25 @@ EODESCR
        description => "Select BIOS implementation.",
        default => 'seabios',
     },
+};
+
+my $confdesc_cloudinit = {
+    citype => {
+       optional => 1,
+       type => 'string',
+       description => 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
+       enum => ['configdrive2', 'nocloud'],
+    },
+    ciuser => {
+       optional => 1,
+       type => 'string',
+       description => "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
+    },
+    cipassword => {
+       optional => 1,
+       type => 'string',
+       description => 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
+    },
     searchdomain => {
        optional => 1,
        type => 'string',
@@ -549,14 +570,7 @@ EODESCR
        optional => 1,
        type => 'string',
        format => 'urlencoded',
-       description => "cloud-init : Setup public SSH keys (one key per line, " .
-                       "OpenSSH format).",
-    },
-    hostname => {
-       optional => 1,
-       description => "cloud-init: Hostname to use instead of the vm-name + search-domain.",
-       type => 'string', format => 'dns-name',
-       maxLength => 255,
+       description => "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
     },
 };
 
@@ -770,7 +784,11 @@ PVE::JSONSchema::register_standard_option("pve-qm-ipconfig", $netdesc);
 
 for (my $i = 0; $i < $MAX_NETS; $i++)  {
     $confdesc->{"net$i"} = $netdesc;
-    $confdesc->{"ipconfig$i"} = $ipconfigdesc;
+    $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
+}
+
+foreach my $key (keys %$confdesc_cloudinit) {
+    $confdesc->{$key} = $confdesc_cloudinit->{$key};
 }
 
 PVE::JSONSchema::register_format('pve-volume-id-or-qm-path', \&verify_volume_id_or_qm_path);
@@ -1878,8 +1896,15 @@ sub print_cpu_device {
     return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
 }
 
-sub drive_is_cdrom {
+sub drive_is_cloudinit {
     my ($drive) = @_;
+    return $drive->{file} =~ m@[:/]vm-\d+-cloudinit(?:\.$QEMU_FORMAT_RE)?$@;
+}
+
+sub drive_is_cdrom {
+    my ($drive, $exclude_cloudinit) = @_;
+
+    return 0 if $exclude_cloudinit && drive_is_cloudinit($drive);
 
     return $drive && $drive->{media} && ($drive->{media} eq 'cdrom');
 
@@ -2053,7 +2078,10 @@ sub vmconfig_undelete_pending_option {
 sub vmconfig_register_unused_drive {
     my ($storecfg, $vmid, $conf, $drive) = @_;
 
-    if (!drive_is_cdrom($drive)) {
+    if (drive_is_cloudinit($drive)) {
+       eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
+       warn $@ if $@;
+    } elsif (!drive_is_cdrom($drive)) {
        my $volid = $drive->{file};
        if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
            PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
@@ -2204,6 +2232,12 @@ sub json_config_properties {
     return $prop;
 }
 
+# return copy of $confdesc_cloudinit to generate documentation
+sub cloudinit_config_properties {
+
+    return dclone($confdesc_cloudinit);
+}
+
 sub check_type {
     my ($key, $value) = @_;
 
@@ -2287,7 +2321,7 @@ sub destroy_vm {
     foreach_drive($conf, sub {
        my ($ds, $drive) = @_;
 
-       return if drive_is_cdrom($drive);
+       return if drive_is_cdrom($drive, 1);
 
        my $volid = $drive->{file};
 
@@ -4372,6 +4406,22 @@ sub vmconfig_hotplug_pending {
        }
     }
 
+    my $apply_pending_cloudinit;
+    $apply_pending_cloudinit = sub {
+       my ($key, $value) = @_;
+       $apply_pending_cloudinit = sub {}; # once is enough
+
+       my @cloudinit_opts = keys %$confdesc_cloudinit;
+       foreach my $opt (keys %{$conf->{pending}}) {
+           next if !grep { $_ eq $opt } @cloudinit_opts;
+           $conf->{$opt} = delete $conf->{pending}->{$opt};
+       }
+
+       my $new_conf = { %$conf };
+       $new_conf->{$key} = $value;
+       PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
+    };
+
     foreach my $opt (keys %{$conf->{pending}}) {
        next if $selection && !$selection->{$opt};
        my $value = $conf->{pending}->{$opt};
@@ -4413,6 +4463,10 @@ sub vmconfig_hotplug_pending {
                                    $vmid, $opt, $value);
            } elsif (is_valid_drivename($opt)) {
                # some changes can be done without hotplug
+               my $drive = parse_drive($opt, $value);
+               if (drive_is_cloudinit($drive)) {
+                   &$apply_pending_cloudinit($opt, $value);
+               }
                vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
                                     $vmid, $opt, $value, 1);
            } elsif ($opt =~ m/^memory$/) { #dimms
@@ -4675,6 +4729,9 @@ sub vmconfig_update_disk {
 
                if ($drive->{file} eq 'none') {
                    vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
+                   if (drive_is_cloudinit($old_drive)) {
+                       vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
+                   }
                } else {
                    my $path = get_iso_path($storecfg, $vmid, $drive->{file});
                    vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
@@ -6157,7 +6214,7 @@ sub qemu_img_convert {
 sub qemu_img_format {
     my ($scfg, $volname) = @_;
 
-    if ($scfg->{path} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
+    if ($scfg->{path} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
        return $1;
     } else {
        return "raw";
@@ -6353,7 +6410,17 @@ sub clone_disk {
        my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
 
        print "create full clone of drive $drivename ($drive->{file})\n";
-       $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, undef, ($size/1024));
+       my $name = undef;
+       if (drive_is_cloudinit($drive)) {
+           $name = "vm-$newvmid-cloudinit";
+           # cloudinit only supports raw and qcow2 atm:
+           if ($dst_format eq 'qcow2') {
+               $name .= '.qcow2';
+           } elsif ($dst_format ne 'raw') {
+               die "clone: unhandled format for cloudinit image\n";
+           }
+       }
+       $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
        push @$newvollist, $newvolid;
 
        PVE::Storage::activate_volumes($storecfg, [$newvolid]);