]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/API2/Qemu.pm
vncproxy: wait max 10s for the socket if it does not exist
[qemu-server.git] / PVE / API2 / Qemu.pm
index a4b84e9fca641f73e3e43f74abc82926ec50267e..f91716f3e91c670c24961cfeeea6d145f3862f6d 100644 (file)
@@ -72,7 +72,8 @@ my $create_disks = sub {
        my $volid = $disk->{file};
 
        if (!$volid || $volid eq 'none' || $volid eq 'cdrom') {
-           $res->{$ds} = $settings->{$ds};
+           delete $disk->{size};
+           $res->{$ds} = PVE::QemuServer::print_drive($vmid, $disk);
        } elsif ($volid =~ m/^(([^:\s]+):)?(\d+(\.\d+)?)$/) {
            my ($storeid, $size) = ($2 || $default_storage, $3);
            die "no storage ID specified (and no default storage)\n" if !$storeid;
@@ -147,7 +148,7 @@ my $check_vm_modify_config_perm = sub {
            $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.CPU']);
        } elsif ($opt eq 'boot' || $opt eq 'bootdisk') {
            $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Disk']);
-       } elsif ($opt eq 'memory' || $opt eq 'balloon') {
+       } elsif ($opt eq 'memory' || $opt eq 'balloon' || $opt eq 'shares') {
            $rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Memory']);
        } elsif ($opt eq 'args' || $opt eq 'lock') {
            die "only root can set '$opt' config\n";
@@ -348,9 +349,6 @@ __PACKAGE__->register_method({
 
                die "unable to restore vm $vmid: vm is running\n"
                    if PVE::QemuServer::check_running($vmid);
-
-               # destroy existing data - keep empty config
-               PVE::QemuServer::destroy_vm($storecfg, $vmid, 1);
            }
 
            my $realcmd = sub {
@@ -648,8 +646,21 @@ my $vmconfig_delete_option = sub {
            $rpcenv->check($authuser, "/storage/$sid", ['Datastore.Allocate']);
        }
     }
-               
-    die "error hot-unplug $opt" if !PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+
+    my $unplugwarning = "";
+    if($conf->{ostype} && $conf->{ostype} eq 'l26'){
+       $unplugwarning = "<br>verify that you have acpiphp && pci_hotplug modules loaded in your guest VM";
+    }elsif($conf->{ostype} && $conf->{ostype} eq 'l24'){
+       $unplugwarning = "<br>kernel 2.4 don't support hotplug, please disable hotplug in options";
+    }elsif(!$conf->{ostype} || ($conf->{ostype} && $conf->{ostype} eq 'other')){
+       $unplugwarning = "<br>verify that your guest support acpi hotplug";
+    }
+
+    if($opt eq 'tablet'){
+       PVE::QemuServer::vm_deviceplug(undef, $conf, $vmid, $opt);
+    }else{
+        die "error hot-unplug $opt $unplugwarning" if !PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+    }
 
     if ($isDisk) {
        my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
@@ -829,6 +840,8 @@ __PACKAGE__->register_method({
 
        my $storecfg = PVE::Storage::config();
 
+       my $defaults = PVE::QemuServer::load_defaults();
+
        &$resolve_cdrom_alias($param);
 
        # now try to verify all parameters
@@ -875,6 +888,14 @@ __PACKAGE__->register_method({
 
            PVE::QemuServer::check_lock($conf) if !$skiplock;
 
+           if ($param->{memory} || defined($param->{balloon})) {
+               my $maxmem = $param->{memory} || $conf->{memory} || $defaults->{memory};
+               my $balloon = defined($param->{balloon}) ?  $param->{balloon} : $conf->{balloon};
+
+               die "balloon value too large (must be smaller than assigned memory)\n"
+                   if $balloon > $maxmem;
+           }
+
            PVE::Cluster::log_msg('info', $authuser, "update VM $vmid: " . join (' ', @paramarr));
 
            foreach my $opt (@delete) { # delete
@@ -882,6 +903,8 @@ __PACKAGE__->register_method({
                &$vmconfig_delete_option($rpcenv, $authuser, $conf, $storecfg, $vmid, $opt, $force);
            }
 
+           my $running = PVE::QemuServer::check_running($vmid);
+
            foreach my $opt (keys %$param) { # add/change
 
                $conf = PVE::QemuServer::load_config($vmid); # update/reload
@@ -900,10 +923,24 @@ __PACKAGE__->register_method({
 
                } else {
 
+                   if($opt eq 'tablet' && $param->{$opt} == 1){
+                       PVE::QemuServer::vm_deviceplug(undef, $conf, $vmid, $opt);
+                   }elsif($opt eq 'tablet' && $param->{$opt} == 0){
+                       PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
+                   }
+
                    $conf->{$opt} = $param->{$opt};
                    PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
                }
            }
+
+           # allow manual ballooning if shares is set to zero
+           if ($running && defined($param->{balloon}) && 
+               defined($conf->{shares}) && ($conf->{shares} == 0)) {
+               my $balloon = $param->{'balloon'} || $conf->{memory} || $defaults->{memory};
+               PVE::QemuServer::vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
+           }
+
        };
 
        PVE::QemuServer::lock_config($vmid, $updatefn);
@@ -1065,16 +1102,17 @@ __PACKAGE__->register_method({
            $remip = PVE::Cluster::remote_node_ip($node);
        }
 
-       # NOTE: kvm VNC traffic is already TLS encrypted,
-       # so we select the fastest chipher here (or 'none'?)
-       my $remcmd = $remip ? ['/usr/bin/ssh', '-T', '-o', 'BatchMode=yes',
-                              '-c', 'blowfish-cbc', $remip] : [];
+       # NOTE: kvm VNC traffic is already TLS encrypted
+       my $remcmd = $remip ? ['/usr/bin/ssh', '-T', '-o', 'BatchMode=yes', $remip] : [];
 
        my $timeout = 10;
 
        my $realcmd = sub {
            my $upid = shift;
 
+           my $c = 0;
+           while ( ++$c < 10 && !-e "/var/run/qemu-server/$vmid.vnc" ) { sleep(1); }
+
            syslog('info', "starting vnc proxy $upid\n");
 
            my $qmcmd = [@$remcmd, "/usr/sbin/qm", 'vncproxy', $vmid];
@@ -1091,6 +1129,8 @@ __PACKAGE__->register_method({
 
        my $upid = $rpcenv->fork_worker('vncproxy', $vmid, $authuser, $realcmd);
 
+       PVE::Tools::wait_for_vnc_port($port);
+
        return {
            user => $authuser,
            ticket => $ticket,
@@ -1629,6 +1669,62 @@ __PACKAGE__->register_method({
        return;
     }});
 
+__PACKAGE__->register_method({
+    name => 'vm_feature',
+    path => '{vmid}/feature',
+    method => 'GET',
+    proxyto => 'node',
+    protected => 1, 
+    description => "Check if feature for virtual machine is available.",
+    permissions => {
+       check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
+    },
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+            feature => {
+                description => "Feature to check.",
+                type => 'string',
+                enum => [ 'snapshot', 'clone' ],
+            },
+            snapname => get_standard_option('pve-snapshot-name', {
+                optional => 1,
+            }),
+       },
+
+    },
+    returns => {
+        type => 'boolean'
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $snapname = extract_param($param, 'snapname');
+
+       my $feature = extract_param($param, 'feature');
+
+       my $running = PVE::QemuServer::check_running($vmid);
+
+       my $conf = PVE::QemuServer::load_config($vmid);
+
+       if($snapname){
+           my $snap = $conf->{snapshots}->{$snapname};
+            die "snapshot '$snapname' does not exist\n" if !defined($snap);
+           $conf = $snap;
+       }
+       my $storecfg = PVE::Storage::config();
+
+       my $hasfeature = PVE::QemuServer::has_feature($feature, $conf, $storecfg, $snapname, $running);
+       my $res = $hasfeature ? 1 : 0 ;
+       return $res;
+    }});
+
 __PACKAGE__->register_method({
     name => 'migrate_vm',
     path => '{vmid}/migrate',
@@ -1844,6 +1940,9 @@ __PACKAGE__->register_method({
 
            die "you can't resize a cdrom\n" if PVE::QemuServer::drive_is_cdrom($drive);
 
+           die "you can't online resize a virtio windows bootdisk\n" 
+               if PVE::QemuServer::check_running($vmid) && $conf->{bootdisk} eq $disk && $conf->{ostype} =~ m/^w/ && $disk =~ m/^virtio/;
+
            my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
 
            $rpcenv->check($authuser, "/storage/$storeid", ['Datastore.AllocateSpace']);
@@ -2224,4 +2323,61 @@ __PACKAGE__->register_method({
        return $rpcenv->fork_worker('qmdelsnapshot', $vmid, $authuser, $realcmd);
     }});
 
+__PACKAGE__->register_method({
+    name => 'template',
+    path => '{vmid}/template',
+    method => 'POST',
+    protected => 1,
+    proxyto => 'node',
+    description => "Create a Template.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+           disk => {
+               optional => 1,
+               type => 'string',
+               description => "If you want to convert only 1 disk to base image.",
+               enum => [PVE::QemuServer::disknames()],
+           },
+
+       },
+    },
+    returns => { type => 'null'},
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $authuser = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $disk = extract_param($param, 'disk');
+
+       my $updatefn =  sub {
+
+           my $conf = PVE::QemuServer::load_config($vmid);
+
+           PVE::QemuServer::check_lock($conf);
+
+           die "you can't convert a template to a template" 
+               if PVE::QemuServer::is_template($conf) && !$disk;
+           my $realcmd = sub {
+               PVE::QemuServer::template_create($vmid, $conf, $disk);
+           };
+           return $rpcenv->fork_worker('qmtemplate', $vmid, $authuser, $realcmd);
+
+           PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
+       };
+
+       PVE::QemuServer::lock_config($vmid, $updatefn);
+       return undef;
+    }});
+
+
+
 1;