]> git.proxmox.com Git - qemu-server.git/commitdiff
create background tasks
authorDietmar Maurer <dietmar@proxmox.com>
Mon, 10 Oct 2011 11:17:40 +0000 (13:17 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Mon, 10 Oct 2011 11:17:40 +0000 (13:17 +0200)
PVE/API2/Qemu.pm
PVE/QemuServer.pm
qm

index 324900bf0278b12dd9e63ebedd02857bc4e39b68..eba65b516f13883c57c1d0fcfe57a51b3531d6ba 100644 (file)
@@ -77,10 +77,16 @@ __PACKAGE__->register_method({
                vmid => get_standard_option('pve-vmid'),
            }),
     },
-    returns => { type => 'null'},
+    returns => { 
+       type => 'string',
+    },
     code => sub {
        my ($param) = @_;
 
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $user = $rpcenv->get_user();
+
        my $node = extract_param($param, 'node');
 
        # fixme: fork worker?
@@ -108,47 +114,50 @@ __PACKAGE__->register_method({
 
        PVE::QemuServer::add_random_macs($param);
 
-       #fixme: ? syslog ('info', "VM $vmid creating new virtual machine");
-       
-       my $vollist = [];
-
        my $createfn = sub {
 
            # second test (after locking test is accurate)
            die "unable to create vm $vmid: config file already exists\n" 
                if -f $filename;
 
-           $vollist = PVE::QemuServer::create_disks($storecfg, $vmid, $param);
+           my $realcmd = sub {
 
-           # try to be smart about bootdisk
-           my @disks = PVE::QemuServer::disknames();
-           my $firstdisk;
-           foreach my $ds (reverse @disks) {
-               next if !$param->{$ds};
-               my $disk = PVE::QemuServer::parse_drive($ds, $param->{$ds});
-               next if PVE::QemuServer::drive_is_cdrom($disk);
-               $firstdisk = $ds;
-           }
+               my $vollist = [];
 
-           if (!$param->{bootdisk} && $firstdisk) {
-               $param->{bootdisk} = $firstdisk; 
-           }
+               eval {
+                   $vollist = PVE::QemuServer::create_disks($storecfg, $vmid, $param);
 
-           PVE::QemuServer::create_conf_nolock($vmid, $param);
-       };
+                   # try to be smart about bootdisk
+                   my @disks = PVE::QemuServer::disknames();
+                   my $firstdisk;
+                   foreach my $ds (reverse @disks) {
+                       next if !$param->{$ds};
+                       my $disk = PVE::QemuServer::parse_drive($ds, $param->{$ds});
+                       next if PVE::QemuServer::drive_is_cdrom($disk);
+                       $firstdisk = $ds;
+                   }
 
-       eval { PVE::QemuServer::lock_config($vmid, $createfn); };
-       my $err = $@;
+                   if (!$param->{bootdisk} && $firstdisk) {
+                       $param->{bootdisk} = $firstdisk; 
+                   }
 
-       if ($err) {
-           foreach my $volid (@$vollist) {
-               eval { PVE::Storage::vdisk_free($storecfg, $volid); };
-               warn $@ if $@;
-           }
-           die "create failed - $err";
-       }
+                   PVE::QemuServer::create_conf_nolock($vmid, $param);
+               };
+               my $err = $@;
 
-       return undef;
+               if ($err) {
+                   foreach my $volid (@$vollist) {
+                       eval { PVE::Storage::vdisk_free($storecfg, $volid); };
+                       warn $@ if $@;
+                   }
+                   die "create failed - $err";
+               }
+           };
+
+           return $rpcenv->fork_worker('qmcreate', $vmid, $user, $realcmd);
+       };
+
+       return PVE::QemuServer::lock_config($vmid, $createfn);
     }});
 
 __PACKAGE__->register_method({
@@ -355,6 +364,13 @@ __PACKAGE__->register_method({
 
        my $vmid = extract_param($param, 'vmid');
 
+       my $digest = extract_param($param, 'digest');
+
+       my @paramarr = (); # used for log message
+       foreach my $key (keys %$param) {
+           push @paramarr, "-$key", $param->{$key};
+       }
+
        my $skiplock = extract_param($param, 'skiplock');
        raise_param_exc({ skiplock => "Only root may use this option." }) 
            if $skiplock && $user ne 'root@pam';
@@ -364,8 +380,6 @@ __PACKAGE__->register_method({
 
        die "no options specified\n" if !$delete && !scalar(keys %$param);
 
-       my $digest = extract_param($param, 'digest');
-
        my $storecfg = PVE::Storage::config(); 
 
        &$resolve_cdrom_alias($param);
@@ -411,6 +425,8 @@ __PACKAGE__->register_method({
 
            PVE::QemuServer::check_lock($conf) if !$skiplock;
 
+           PVE::Cluster::log_msg('info', $user, "update VM $vmid: " . join (' ', @paramarr));
+
            foreach my $opt (keys %$eject) {
                if ($conf->{$opt}) {
                    my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
@@ -510,7 +526,9 @@ __PACKAGE__->register_method({
            skiplock => get_standard_option('skiplock'),
        },
     },
-    returns => { type => 'null' },
+    returns => { 
+       type => 'string',
+    },
     code => sub {
        my ($param) = @_;
 
@@ -524,11 +542,16 @@ __PACKAGE__->register_method({
        raise_param_exc({ skiplock => "Only root may use this option." }) 
            if $skiplock && $user ne 'root@pam';
 
+       # test if VM exists
+       my $conf = PVE::QemuServer::load_config($vmid);
+
        my $storecfg = PVE::Storage::config(); 
 
-       PVE::QemuServer::vm_destroy($storecfg, $vmid, $skiplock);
+       my $realcmd = sub {
+           PVE::QemuServer::vm_destroy($storecfg, $vmid, $skiplock);
+       };
 
-       return undef;
+       return $rpcenv->fork_worker('qmdestroy', $vmid, $user, $realcmd);
     }});
 
 __PACKAGE__->register_method({
@@ -651,9 +674,47 @@ __PACKAGE__->register_method({
        };
     }});
 
+__PACKAGE__->register_method({
+    name => 'vmcmdidx',
+    path => '{vmid}/status', 
+    method => 'GET',
+    proxyto => 'node',
+    description => "Directory index",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+       },
+    },
+    returns => {
+       type => 'array',
+       items => {
+           type => "object",
+           properties => {
+               subdir => { type => 'string' },
+           },
+       },
+       links => [ { rel => 'child', href => "{subdir}" } ],
+    },
+    code => sub {
+       my ($param) = @_;
+
+       # test if VM exists
+       my $conf = PVE::QemuServer::load_config($param->{vmid});
+
+       my $res = [
+           { subdir => 'current' },
+           { subdir => 'start' },
+           { subdir => 'stop' },
+           ];
+       
+       return $res;
+    }});
+
 __PACKAGE__->register_method({
     name => 'vm_status', 
-    path => '{vmid}/status',
+    path => '{vmid}/status/current',
     method => 'GET',
     proxyto => 'node',
     protected => 1, # qemu pid files are only readable by root
@@ -678,12 +739,12 @@ __PACKAGE__->register_method({
     }});
 
 __PACKAGE__->register_method({
-    name => 'vm_command', 
-    path => '{vmid}/status',
-    method => 'PUT',
+    name => 'vm_start', 
+    path => '{vmid}/status/start',
+    method => 'POST',
     protected => 1,
     proxyto => 'node',
-    description => "Set virtual machine status (execute vm commands).",
+    description => "Start virtual machine.",
     parameters => {
        additionalProperties => 0,
        properties => {
@@ -691,14 +752,11 @@ __PACKAGE__->register_method({
            vmid => get_standard_option('pve-vmid'),
            skiplock => get_standard_option('skiplock'),
            stateuri => get_standard_option('pve-qm-stateuri'),
-           command => { 
-               description => "The command to execute.",
-               type => 'string',
-               enum => [qw(start stop reset shutdown cad suspend resume) ],
-           },
        },
     },
-    returns => { type => 'null'},
+    returns => { 
+       type => 'string',
+    },
     code => sub {
        my ($param) = @_;
 
@@ -718,29 +776,289 @@ __PACKAGE__->register_method({
        raise_param_exc({ skiplock => "Only root may use this option." }) 
            if $skiplock && $user ne 'root@pam';
 
-       my $command = $param->{command};
-
        my $storecfg = PVE::Storage::config(); 
-       
-       if ($command eq 'start') {
+
+       my $realcmd = sub {
+           my $upid = shift;
+
+           syslog('info', "start VM $vmid: $upid\n");
+
            PVE::QemuServer::vm_start($storecfg, $vmid, $stateuri, $skiplock);
-       } elsif ($command eq 'stop') {
+
+           return;
+       };
+
+       return $rpcenv->fork_worker('qmstart', $vmid, $user, $realcmd);
+    }});
+
+__PACKAGE__->register_method({
+    name => 'vm_stop', 
+    path => '{vmid}/status/stop',
+    method => 'POST',
+    protected => 1,
+    proxyto => 'node',
+    description => "Stop virtual machine.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+           skiplock => get_standard_option('skiplock'),
+       },
+    },
+    returns => { 
+       type => 'string',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $user = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $skiplock = extract_param($param, 'skiplock');
+       raise_param_exc({ skiplock => "Only root may use this option." }) 
+           if $skiplock && $user ne 'root@pam';
+
+       my $realcmd = sub {
+           my $upid = shift;
+
+           syslog('info', "stop VM $vmid: $upid\n");
+
            PVE::QemuServer::vm_stop($vmid, $skiplock);
-       } elsif ($command eq 'reset') {
+
+           return;
+       };
+
+       return $rpcenv->fork_worker('qmstop', $vmid, $user, $realcmd);
+    }});
+
+__PACKAGE__->register_method({
+    name => 'vm_reset', 
+    path => '{vmid}/status/reset',
+    method => 'POST',
+    protected => 1,
+    proxyto => 'node',
+    description => "Reset virtual machine.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+           skiplock => get_standard_option('skiplock'),
+       },
+    },
+    returns => { 
+       type => 'string',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $user = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $skiplock = extract_param($param, 'skiplock');
+       raise_param_exc({ skiplock => "Only root may use this option." }) 
+           if $skiplock && $user ne 'root@pam';
+
+       my $realcmd = sub {
+           my $upid = shift;
+
+           syslog('info', "reset VM $vmid: $upid\n");
+
            PVE::QemuServer::vm_reset($vmid, $skiplock);
-       } elsif ($command eq 'shutdown') {
+
+           return;
+       };
+
+       return $rpcenv->fork_worker('qmreset', $vmid, $user, $realcmd);
+    }});
+
+__PACKAGE__->register_method({
+    name => 'vm_shutdown', 
+    path => '{vmid}/status/shutdown',
+    method => 'POST',
+    protected => 1,
+    proxyto => 'node',
+    description => "Shutdown virtual machine.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+           skiplock => get_standard_option('skiplock'),
+       },
+    },
+    returns => { 
+       type => 'string',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $user = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $skiplock = extract_param($param, 'skiplock');
+       raise_param_exc({ skiplock => "Only root may use this option." }) 
+           if $skiplock && $user ne 'root@pam';
+
+       my $realcmd = sub {
+           my $upid = shift;
+
+           syslog('info', "shutdown VM $vmid: $upid\n");
+
            PVE::QemuServer::vm_shutdown($vmid, $skiplock);
-       } elsif ($command eq 'suspend') {
+
+           return;
+       };
+
+       return $rpcenv->fork_worker('qmshutdown', $vmid, $user, $realcmd);
+    }});
+
+__PACKAGE__->register_method({
+    name => 'vm_suspend', 
+    path => '{vmid}/status/suspend',
+    method => 'POST',
+    protected => 1,
+    proxyto => 'node',
+    description => "Suspend virtual machine.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+           skiplock => get_standard_option('skiplock'),
+       },
+    },
+    returns => { 
+       type => 'string',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $user = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $skiplock = extract_param($param, 'skiplock');
+       raise_param_exc({ skiplock => "Only root may use this option." }) 
+           if $skiplock && $user ne 'root@pam';
+
+       my $realcmd = sub {
+           my $upid = shift;
+
+           syslog('info', "suspend VM $vmid: $upid\n");
+
            PVE::QemuServer::vm_suspend($vmid, $skiplock);
-       } elsif ($command eq 'resume') {
+
+           return;
+       };
+
+       return $rpcenv->fork_worker('qmsuspend', $vmid, $user, $realcmd);
+    }});
+
+__PACKAGE__->register_method({
+    name => 'vm_resume', 
+    path => '{vmid}/status/resume',
+    method => 'POST',
+    protected => 1,
+    proxyto => 'node',
+    description => "Resume virtual machine.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+           skiplock => get_standard_option('skiplock'),
+       },
+    },
+    returns => { 
+       type => 'string',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $user = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $skiplock = extract_param($param, 'skiplock');
+       raise_param_exc({ skiplock => "Only root may use this option." }) 
+           if $skiplock && $user ne 'root@pam';
+
+       my $realcmd = sub {
+           my $upid = shift;
+
+           syslog('info', "resume VM $vmid: $upid\n");
+
            PVE::QemuServer::vm_resume($vmid, $skiplock);
-       } elsif ($command eq 'cad') {
-           PVE::QemuServer::vm_cad($vmid, $skiplock);
-       } else {
-           raise_param_exc({ command => "unknown command '$command'" }) 
-       }
 
-       return undef;
+           return;
+       };
+
+       return $rpcenv->fork_worker('qmresume', $vmid, $user, $realcmd);
+    }});
+
+__PACKAGE__->register_method({
+    name => 'vm_sendkey', 
+    path => '{vmid}/sendkey',
+    method => 'PUT',
+    protected => 1,
+    proxyto => 'node',
+    description => "Send key event to virtual machine.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+           skiplock => get_standard_option('skiplock'),
+           key => {
+               description => "The key (qemu monitor encoding).",
+               type => 'string'
+           }
+       },
+    },
+    returns => { type => 'null'},
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $user = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $skiplock = extract_param($param, 'skiplock');
+       raise_param_exc({ skiplock => "Only root may use this option." }) 
+           if $skiplock && $user ne 'root@pam';
+
+       PVE::QemuServer::vm_sendkey($vmid, $skiplock, $param->{key});
+
+       return;
     }});
 
 __PACKAGE__->register_method({
index 2e70d80687a58c32e860cf9a17dc9810c3af55a9..82cadf599a3cf0b2c579d8b7a8707d30b0e6d00f 100644 (file)
@@ -1215,9 +1215,11 @@ sub lock_config {
 
     my $filename = config_file_lock($vmid);
 
-    lock_file($filename, 10, $code, @param);
+    my $res = lock_file($filename, 10, $code, @param);
 
     die $@ if $@;
+
+    return $res;
 }
 
 sub cfs_config_path {
@@ -2561,8 +2563,8 @@ sub vm_resume {
     });
 }
 
-sub vm_cad {
-    my ($vmid, $skiplock) = @_;
+sub vm_sendkey {
+    my ($vmid, $skiplock, $key) = @_;
 
     lock_config($vmid, sub {
 
@@ -2570,9 +2572,9 @@ sub vm_cad {
 
        check_lock($conf) if !$skiplock;
 
-       syslog("info", "VM $vmid sending cntl-alt-delete");
+       syslog("info", "VM $vmid sending key $key");
 
-       vm_monitor_command($vmid, "sendkey ctrl-alt-delete", 1);
+       vm_monitor_command($vmid, "sendkey $key", 1);
     });
 }
 
diff --git a/qm b/qm
index 6cb0dd2d719f8ae689d20e837b5afb7568e4172f..a03c0df7a0dbfcc6b28b905cfea6f692ab0cc349 100755 (executable)
--- a/qm
+++ b/qm
@@ -415,6 +415,20 @@ my $cmddef = {
 
     status => [ __PACKAGE__, 'status', ['vmid']],
 
+    start => [ "PVE::API2::Qemu", 'vm_start', ['vmid'], { node => $nodename } ],
+
+    stop => [ "PVE::API2::Qemu", 'vm_stop', ['vmid'], { node => $nodename } ],
+
+    reset => [ "PVE::API2::Qemu", 'vm_reset', ['vmid'], { node => $nodename } ],
+
+    shutdown => [ "PVE::API2::Qemu", 'vm_shutdown', ['vmid'], { node => $nodename } ],
+
+    suspend => [ "PVE::API2::Qemu", 'vm_suspend', ['vmid'], { node => $nodename } ],
+
+    resume => [ "PVE::API2::Qemu", 'vm_resume', ['vmid'], { node => $nodename } ],
+
+    sendkey => [ "PVE::API2::Qemu", 'vm_sendkey', ['vmid', 'key'], { node => $nodename } ],
+
     vncproxy => [ __PACKAGE__, 'vncproxy', ['vmid']],
 
     wait => [ __PACKAGE__, 'wait', ['vmid']],
@@ -430,44 +444,6 @@ my $cmddef = {
     mtunnel => [ __PACKAGE__, 'mtunnel', []],  
 };
 
-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'),
-               stateuri => get_standard_option('pve-qm-stateuri'),
-           },
-       },
-       returns => { type => 'null'},
-       code => sub {
-           my ($param) = @_;
-
-           $param->{command} = $cmd;
-           $param->{node} = $nodename;
-
-           return PVE::API2::Qemu->vm_command($param);
-       }});
-
-    $cmddef->{$cmd} = [ __PACKAGE__, $cmd, ['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.");
-
 my $cmd = shift;
 
 PVE::CLIHandler::handle_cmd($cmddef, "qm", $cmd, \@ARGV, undef, $0);