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?
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({
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';
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);
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});
skiplock => get_standard_option('skiplock'),
},
},
- returns => { type => 'null' },
+ returns => {
+ type => 'string',
+ },
code => sub {
my ($param) = @_;
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({
};
}});
+__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
}});
__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 => {
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) = @_;
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({
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']],
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);