]> git.proxmox.com Git - qemu-server.git/blobdiff - qm
qm rescan: skip vm state files
[qemu-server.git] / qm
diff --git a/qm b/qm
index 546e08fa03a51b16bf6f99e0ea492270198182ad..25f84ea026d5ad6147c141dd73e175a96d43c09b 100755 (executable)
--- a/qm
+++ b/qm
@@ -35,13 +35,13 @@ $rpcenv->init_request();
 $rpcenv->set_language($ENV{LANG});
 $rpcenv->set_user('root@pam'); 
 
-my $nodename = PVE::INotify::nodename();
+my $upid_exit = sub {
+    my $upid = shift;
+    my $status = PVE::Tools::upid_read_status($upid);
+    exit($status eq 'OK' ? 0 : -1);
+};
 
-PVE::JSONSchema::register_standard_option('skiplock', {
-    description => "Ignore locks - only root is allowed to use this option.",
-    type => 'boolean', 
-    optional => 1,
-});
+my $nodename = PVE::INotify::nodename();
 
 sub run_vnc_proxy {
     my ($vmid) = @_;
@@ -185,7 +185,9 @@ __PACKAGE__->register_method ({
        my $vmid = $param->{vmid};
 
        PVE::QemuServer::lock_config ($vmid, sub {
-           PVE::QemuServer::change_config_nolock  ($vmid, {}, { lock => 1 }, 1);
+           my $conf = PVE::QemuServer::load_config($vmid);
+           delete $conf->{lock};
+           PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
        });
 
        return undef;
@@ -195,7 +197,7 @@ __PACKAGE__->register_method ({
     name => 'mtunnel', 
     path => 'mtunnel', 
     method => 'POST',
-    description => "Used by vzmigrate - do not use manually.",
+    description => "Used by qmigrate - do not use manually.",
     parameters => {
        additionalProperties => 0,
        properties => {},
@@ -204,6 +206,11 @@ __PACKAGE__->register_method ({
     code => sub {
        my ($param) = @_;
 
+       if (!PVE::Cluster::check_cfs_quorum(1)) {
+           print "no quorum\n";
+           return undef;
+       }
        print "tunnel online\n";
        *STDOUT->flush();
 
@@ -215,69 +222,6 @@ __PACKAGE__->register_method ({
        return undef;
     }});
 
-__PACKAGE__->register_method ({
-    name => 'startall', 
-    path => 'startall', 
-    method => 'POST',
-    description => "Start all virtual machines (when onboot=1).",
-    parameters => {
-       additionalProperties => 0,
-       properties => {},
-    },
-    returns => { type => 'null'},
-    code => sub {
-       my ($param) = @_;
-
-       my $vzlist = PVE::QemuServer::vzlist();
-       my $storecfg = PVE::Storage::config();
-
-       my $count = 0;
-       foreach my $vmid (keys %$vzlist) {
-           next if $vzlist->{$vmid}->{pid}; # already running
-
-           sleep(2) if $count != 0; # reduce load
-           $count++;
-
-           eval {
-               my $conf = PVE::QemuServer::load_config($vmid);
-               if ($conf->{onboot}) {
-                   print STDERR "Starting Qemu VM $vmid\n";
-                   PVE::QemuServer::vm_start($storecfg, $vmid);
-               }
-           };
-           print STDERR $@ if $@;
-       }
-
-       return undef;
-    }});
-
-__PACKAGE__->register_method ({
-    name => 'stopall', 
-    path => 'stopall', 
-    method => 'POST',
-    description => "Stop all virtual machines.",
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           timeout => {
-               description => "Timeout in seconds. Default is to wait 3 minutes.",
-               type => 'integer',
-               minimum => 1,
-               optional => 1,
-           }
-       },
-    },
-    returns => { type => 'null'},
-    code => sub {
-       my ($param) = @_;
-
-       my $timeout = $param->{timeout};
-
-       PVE::QemuServer::vm_stopall($timeout);
-
-       return undef;
-    }});
-
 __PACKAGE__->register_method ({
     name => 'wait', 
     path => 'wait', 
@@ -350,7 +294,7 @@ __PACKAGE__->register_method ({
            last if $input =~ m/^\s*q(uit)?\s*$/;
 
            eval {
-               print PVE::QemuServer::vm_monitor_command ($vmid, $input);
+               print PVE::QemuServer::vm_human_monitor_command ($vmid, $input);
            };
            print "ERROR: $@" if $@;
        }
@@ -359,6 +303,89 @@ __PACKAGE__->register_method ({
 
     }});
 
+__PACKAGE__->register_method ({
+    name => 'rescan', 
+    path => 'rescan', 
+    method => 'POST',
+    description => "Rescan all storages and update disk sizes and unused disk images.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           vmid => get_standard_option('pve-vmid', {optional => 1}),
+       },
+    },
+    returns => { type => 'null'},
+    code => sub {
+       my ($param) = @_;
+
+       my $cfg = PVE::Cluster::cfs_read_file("storage.cfg");
+
+       my $info = PVE::Storage::vdisk_list($cfg, undef, $param->{vmid});
+
+       my $volid_hash = {};
+       foreach my $storeid (keys %$info) {
+           foreach my $item (@{$info->{$storeid}}) {
+               next if !($item->{volid} && $item->{size});
+               $volid_hash->{$item->{volid}} = $item;
+           }
+       }
+
+       my $updatefn =  sub {
+           my ($vmid) = @_;
+
+           my $conf = PVE::QemuServer::load_config($vmid);
+           
+           PVE::QemuServer::check_lock($conf);
+
+           my $changes;
+
+           my $used = {};
+
+           # update size info
+           foreach my $opt (keys %$conf) {
+               if (PVE::QemuServer::valid_drivename($opt)) {
+                   my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
+                   my $volid = $drive->{file};
+                   next if !$volid;
+
+                   $used->{$volid} = 1;
+
+                   next if PVE::QemuServer::drive_is_cdrom($drive);
+                   next if !$volid_hash->{$volid};
+
+                   $drive->{size} = $volid_hash->{$volid}->{size};
+                   $changes = 1;
+                   $conf->{$opt} = PVE::QemuServer::print_drive($vmid, $drive);
+               }
+           }
+
+           # add unused volumes
+           foreach my $storeid (keys %$info) {
+               foreach my $item (@{$info->{$storeid}}) {
+                   next if !($item->{volid} && $item->{vmid});
+                   next if $item->{vmid} ne $vmid;
+                   next if $item->{volid} =~ m/vm-$vmid-state-/;
+                   next if $used->{$item->{volid}};
+                   $changes = 1;
+                   PVE::QemuServer::add_unused_volume($conf, $item->{volid});
+               }
+           }
+
+           PVE::QemuServer::update_config_nolock($vmid, $conf, 1) if $changes;
+       };
+
+       if (defined($param->{vmid})) {
+           PVE::QemuServer::lock_config($param->{vmid}, $updatefn, $param->{vmid});
+       } else {
+           my $vmlist = PVE::QemuServer::config_list();
+           foreach my $vmid (keys %$vmlist) {
+               PVE::QemuServer::lock_config($vmid, $updatefn, $vmid);      
+           }
+       }
+
+       return undef;
+    }});
+
 my $cmddef = {
     list => [ "PVE::API2::Qemu", 'vmlist', [],
             { node => $nodename }, sub {
@@ -380,18 +407,23 @@ my $cmddef = {
                 
              } ],
 
-    create => [ "PVE::API2::Qemu", 'create_vm', ['vmid'], { node => $nodename } ],
+    create => [ "PVE::API2::Qemu", 'create_vm', ['vmid'], { node => $nodename }, $upid_exit ],
+
+    destroy => [ "PVE::API2::Qemu", 'destroy_vm', ['vmid'], { node => $nodename }, $upid_exit ],
 
-    destroy => [ "PVE::API2::Qemu", 'destroy_vm', ['vmid'], { node => $nodename } ],
+    migrate => [ "PVE::API2::Qemu", 'migrate_vm', ['vmid', 'target'], { node => $nodename }, $upid_exit ],
 
     set => [ "PVE::API2::Qemu", 'update_vm', ['vmid'], { node => $nodename } ],
 
+    resize => [ "PVE::API2::Qemu", 'resize_vm', ['vmid', 'disk', 'size'], { node => $nodename } ],
+
     unlink => [ "PVE::API2::Qemu", 'unlink', ['vmid', 'idlist'], { node => $nodename } ],
 
     config => [ "PVE::API2::Qemu", 'vm_config', ['vmid'], 
                { node => $nodename }, sub {
                    my $config = shift;
                    foreach my $k (sort (keys %$config)) {
+                       next if $k eq 'digest';
                        my $v = $config->{$k};
                        if ($k eq 'description') {
                            $v = PVE::Tools::encode_text($v);
@@ -404,60 +436,44 @@ my $cmddef = {
 
     status => [ __PACKAGE__, 'status', ['vmid']],
 
-    vncproxy => [ __PACKAGE__, 'vncproxy', ['vmid']],
+    snapshot => [ "PVE::API2::Qemu", 'snapshot', ['vmid', 'snapname'], { node => $nodename } , $upid_exit ],
 
-    wait => [ __PACKAGE__, 'wait', ['vmid']],
+    delsnapshot => [ "PVE::API2::Qemu", 'delsnapshot', ['vmid', 'snapname'], { node => $nodename } , $upid_exit ],
 
-    unlock => [ __PACKAGE__, 'unlock', ['vmid']],
+    rollback => [ "PVE::API2::Qemu", 'rollback', ['vmid', 'snapname'], { node => $nodename } , $upid_exit ],
 
-    monitor  => [ __PACKAGE__, 'monitor', ['vmid']],
+    start => [ "PVE::API2::Qemu", 'vm_start', ['vmid'], { node => $nodename } , $upid_exit ],
 
-    startall => [ __PACKAGE__, 'startall', []],
+    stop => [ "PVE::API2::Qemu", 'vm_stop', ['vmid'], { node => $nodename }, $upid_exit ],
 
-    stopall => [ __PACKAGE__, 'stopall', []],
+    reset => [ "PVE::API2::Qemu", 'vm_reset', ['vmid'], { node => $nodename }, $upid_exit ],
 
-    mtunnel => [ __PACKAGE__, 'mtunnel', []],  
-};
+    shutdown => [ "PVE::API2::Qemu", 'vm_shutdown', ['vmid'], { node => $nodename }, $upid_exit ],
 
-sub register_vm_command {
-    my ($cmd, $descr) = @_;
-
-    # we create a wrapper, because we want one 'description' per command
-    __PACKAGE__->register_method ({
-       name => $cmd, 
-       path => $cmd, 
-       method => 'PUT',
-       description => $descr,
-       parameters => {
-           additionalProperties => 0,
-           properties => {
-               vmid => get_standard_option('pve-vmid'),
-               skiplock => get_standard_option('skiplock'),
-           },
-       },
-       returns => { type => 'null'},
-       code => sub {
-           my ($param) = @_;
+    suspend => [ "PVE::API2::Qemu", 'vm_suspend', ['vmid'], { node => $nodename }, $upid_exit ],
 
-           $param->{command} = $cmd;
-           $param->{node} = $nodename;
+    resume => [ "PVE::API2::Qemu", 'vm_resume', ['vmid'], { node => $nodename }, $upid_exit ],
 
-           return PVE::API2::Qemu->vm_command($param);
-       }});
+    sendkey => [ "PVE::API2::Qemu", 'vm_sendkey', ['vmid', 'key'], { node => $nodename } ],
 
-    $cmddef->{$cmd} = [ __PACKAGE__, $cmd, ['vmid']];
-}
+    vncproxy => [ __PACKAGE__, 'vncproxy', ['vmid']],
+
+    wait => [ __PACKAGE__, 'wait', ['vmid']],
+
+    unlock => [ __PACKAGE__, 'unlock', ['vmid']],
 
-register_vm_command('start', "Start virtual machine.");
-register_vm_command('stop', "Stop virtual machine.");
-register_vm_command('reset', "Reset virtual machine.");
-register_vm_command('shutdown', "Shutdown virtual machine (send ACPI showdown request)");
-register_vm_command('suspend', "Suspend virtual machine.");
-register_vm_command('resume', "Resume virtual machine.");
-register_vm_command('cad', "Send CTRL-ALT-DELETE keys.");
+    rescan  => [ __PACKAGE__, 'rescan', []],
+
+    monitor  => [ __PACKAGE__, 'monitor', ['vmid']],
+
+    mtunnel => [ __PACKAGE__, 'mtunnel', []],  
+};
 
 my $cmd = shift;
 
+# Note: disable '+' prefix for Getopt::Long (for resize command)
+use Getopt::Long qw(:config no_getopt_compat); 
+
 PVE::CLIHandler::handle_cmd($cmddef, "qm", $cmd, \@ARGV, undef, $0);
 
 exit 0;