use strict;
use warnings;
+use Cwd 'abs_path';
use PVE::Cluster;
use PVE::SafeSyslog;
name => 'create_vm',
path => '',
method => 'POST',
- description => "Create new virtual machine.",
+ description => "Create or restore a virtual machine.",
protected => 1,
proxyto => 'node',
parameters => {
{
node => get_standard_option('pve-node'),
vmid => get_standard_option('pve-vmid'),
+ archive => {
+ description => "The backup file.",
+ type => 'string',
+ optional => 1,
+ maxLength => 255,
+ },
+ storage => get_standard_option('pve-storage-id', {
+ description => "Default storage.",
+ optional => 1,
+ }),
+ force => {
+ optional => 1,
+ type => 'boolean',
+ description => "Allow to overwrite existing VM.",
+ requires => 'archive',
+ },
+ unique => {
+ optional => 1,
+ type => 'boolean',
+ description => "Assign a unique random ethernet address.",
+ requires => 'archive',
+ },
}),
},
returns => {
my $vmid = extract_param($param, 'vmid');
+ my $archive = extract_param($param, 'archive');
+
+ my $storage = extract_param($param, 'storage');
+
+ my $force = extract_param($param, 'force');
+
+ my $unique = extract_param($param, 'unique');
+
my $filename = PVE::QemuServer::config_file($vmid);
- # first test (befor locking)
- die "unable to create vm $vmid: config file already exists\n"
- if -f $filename;
my $storecfg = PVE::Storage::config();
- &$resolve_cdrom_alias($param);
+ PVE::Cluster::check_cfs_quorum();
- foreach my $opt (keys %$param) {
- if (PVE::QemuServer::valid_drivename($opt)) {
- my $drive = PVE::QemuServer::parse_drive($opt, $param->{$opt});
- raise_param_exc({ $opt => "unable to parse drive options" }) if !$drive;
+ if (!$archive) {
+ &$resolve_cdrom_alias($param);
- PVE::QemuServer::cleanup_drive_path($opt, $storecfg, $drive);
- $param->{$opt} = PVE::QemuServer::print_drive($vmid, $drive);
+ foreach my $opt (keys %$param) {
+ if (PVE::QemuServer::valid_drivename($opt)) {
+ my $drive = PVE::QemuServer::parse_drive($opt, $param->{$opt});
+ raise_param_exc({ $opt => "unable to parse drive options" }) if !$drive;
+
+ PVE::QemuServer::cleanup_drive_path($opt, $storecfg, $drive);
+ $param->{$opt} = PVE::QemuServer::print_drive($vmid, $drive);
+ }
+ }
+
+ PVE::QemuServer::add_random_macs($param);
+ } else {
+ my $keystr = join(' ', keys %$param);
+ raise_param_exc({ archive => "option conflicts with other options ($keystr)"}) if $keystr;
+
+ if ($archive eq '-') {
+ die "pipe requires cli environment\n"
+ && $rpcenv->{type} ne 'cli';
+ } else {
+ my $path;
+ if (PVE::Storage::parse_volume_id($archive, 1)) {
+ $path = PVE::Storage::path($storecfg, $archive);
+ } else {
+ raise_param_exc({ archive => "Only root can pass arbitrary paths." })
+ if $user ne 'root@pam';
+
+ $path = abs_path($archive);
+ }
+ die "can't find archive file '$archive'\n" if !($path && -f $path);
+ $archive = $path;
}
}
- PVE::QemuServer::add_random_macs($param);
+ my $restorefn = sub {
+
+ if (-f $filename) {
+ die "unable to restore vm $vmid: config file already exists\n"
+ if !$force;
+
+ 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 {
+ PVE::QemuServer::restore_archive($archive, $vmid, {
+ storage => $storage,
+ unique => $unique });
+ };
+
+ return $rpcenv->fork_worker('qmrestore', $vmid, $user, $realcmd);
+ };
my $createfn = sub {
my $vollist = [];
eval {
- $vollist = PVE::QemuServer::create_disks($storecfg, $vmid, $param);
+ $vollist = PVE::QemuServer::create_disks($storecfg, $vmid, $param, $storage);
# try to be smart about bootdisk
my @disks = PVE::QemuServer::disknames();
return $rpcenv->fork_worker('qmcreate', $vmid, $user, $realcmd);
};
- return PVE::QemuServer::lock_config($vmid, $createfn);
+ return PVE::QemuServer::lock_config($vmid, $archive ? $restorefn : $createfn);
}});
__PACKAGE__->register_method({
{ subdir => 'migrate' },
{ subdir => 'rrd' },
{ subdir => 'rrddata' },
+ { subdir => 'monitor' },
];
return $res;
}
next if !defined($conf->{$opt});
if (PVE::QemuServer::valid_drivename($opt)) {
- PVE::QemuServer::vm_devicedel($vmid, $conf, $opt);
+ PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
if (PVE::QemuServer::drive_is_cdrom($drive)) {
$cdchange->{$opt} = undef;
my $storecfg = PVE::Storage::config();
my $realcmd = sub {
+ my $upid = shift;
+
+ syslog('info', "destroy VM $vmid: $upid\n");
+
PVE::QemuServer::vm_destroy($storecfg, $vmid, $skiplock);
};
my $rpcenv = PVE::RPCEnvironment::get();
my $user = $rpcenv->get_user();
- my $ticket = PVE::AccessControl::assemble_ticket($user);
my $vmid = $param->{vmid};
my $node = $param->{node};
+ my $authpath = "/vms/$vmid";
+
+ my $ticket = PVE::AccessControl::assemble_vnc_ticket($user, $authpath);
+
$sslcert = PVE::Tools::file_get_contents("/etc/pve/pve-root-ca.pem", 8192)
if !$sslcert;
my $remip;
- if ($node ne PVE::INotify::nodename()) {
+ if ($node ne 'localhost' && $node ne PVE::INotify::nodename()) {
$remip = PVE::Cluster::remote_node_ip($node);
}
# test if VM exists
my $conf = PVE::QemuServer::load_config($param->{vmid});
- my $vmstatus = PVE::QemuServer::vmstatus($param->{vmid});
+ my $vmstatus = PVE::QemuServer::vmstatus($param->{vmid});
+ my $status = $vmstatus->{$param->{vmid}};
- return $vmstatus->{$param->{vmid}};
+ my $cc = PVE::Cluster::cfs_read_file('cluster.conf');
+ if (PVE::Cluster::cluster_conf_lookup_pvevm($cc, 0, $param->{vmid}, 1)) {
+ $status->{ha} = 1;
+ } else {
+ $status->{ha} = 0;
+ }
+
+ return $status;
}});
__PACKAGE__->register_method({
type => 'integer',
minimum => 0,
optional => 1,
+ },
+ keepActive => {
+ description => "Do not decativate storage volumes.",
+ type => 'boolean',
+ optional => 1,
+ default => 0,
}
},
},
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ my $keepActive = extract_param($param, 'keepActive');
+ raise_param_exc({ keepActive => "Only root may use this option." })
+ if $keepActive && $user ne 'root@pam';
+
+ my $storecfg = PVE::Storage::config();
+
my $realcmd = sub {
my $upid = shift;
syslog('info', "stop VM $vmid: $upid\n");
- PVE::QemuServer::vm_stop($vmid, $skiplock);
-
- my $pid = PVE::QemuServer::check_running ($vmid);
-
- if ($pid && $param->{timeout}) {
- print "waiting until VM $vmid stopps (PID $pid)\n";
-
- my $count = 0;
- while (($count < $param->{timeout}) &&
- PVE::QemuServer::check_running($vmid)) {
- $count++;
- sleep 1;
- }
-
- die "wait failed - got timeout\n" if PVE::QemuServer::check_running($vmid);
- }
+ PVE::QemuServer::vm_stop($storecfg, $vmid, $skiplock, 0,
+ $param->{timeout}, 0, 1, $keepActive);
return;
};
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid not running\n" if !PVE::QemuServer::check_running($vmid);
+
my $realcmd = sub {
my $upid = shift;
- syslog('info', "reset VM $vmid: $upid\n");
-
PVE::QemuServer::vm_reset($vmid, $skiplock);
return;
type => 'integer',
minimum => 0,
optional => 1,
+ },
+ forceStop => {
+ description => "Make sure the VM stops.",
+ type => 'boolean',
+ optional => 1,
+ default => 0,
+ },
+ keepActive => {
+ description => "Do not decativate storage volumes.",
+ type => 'boolean',
+ optional => 1,
+ default => 0,
}
},
},
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ my $keepActive = extract_param($param, 'keepActive');
+ raise_param_exc({ keepActive => "Only root may use this option." })
+ if $keepActive && $user ne 'root@pam';
+
+ my $storecfg = PVE::Storage::config();
+
my $realcmd = sub {
my $upid = shift;
syslog('info', "shutdown VM $vmid: $upid\n");
- PVE::QemuServer::vm_shutdown($vmid, $skiplock);
-
- my $pid = PVE::QemuServer::check_running ($vmid);
-
- if ($pid && $param->{timeout}) {
- print "waiting until VM $vmid stopps (PID $pid)\n";
-
- my $count = 0;
- while (($count < $param->{timeout}) &&
- PVE::QemuServer::check_running($vmid)) {
- $count++;
- sleep 1;
- }
-
- die "wait failed - got timeout\n" if PVE::QemuServer::check_running($vmid);
- }
+ PVE::QemuServer::vm_stop($storecfg, $vmid, $skiplock, 0, $param->{timeout},
+ 1, $param->{forceStop}, $keepActive);
return;
};
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid not running\n" if !PVE::QemuServer::check_running($vmid);
+
my $realcmd = sub {
my $upid = shift;
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid not running\n" if !PVE::QemuServer::check_running($vmid);
+
my $realcmd = sub {
my $upid = shift;
my $vmid = extract_param($param, 'vmid');
- raise_param_exc({ force => "Only root may use this option." }) if $user ne 'root@pam';
+ raise_param_exc({ force => "Only root may use this option." })
+ if $param->{force} && $user ne 'root@pam';
# test if VM exists
- PVE::QemuServer::load_config($vmid);
+ my $conf = PVE::QemuServer::load_config($vmid);
# try to detect errors early
+
+ PVE::QemuServer::check_lock($conf);
+
if (PVE::QemuServer::check_running($vmid)) {
die "cant migrate running VM without --online\n"
if !$param->{online};
my $realcmd = sub {
my $upid = shift;
- PVE::QemuMigrate::migrate($target, $targetip, $vmid, $param->{online}, $param->{force});
+ PVE::QemuMigrate->migrate($target, $targetip, $vmid, $param);
};
my $upid = $rpcenv->fork_worker('qmigrate', $vmid, $user, $realcmd);
return $upid;
}});
+__PACKAGE__->register_method({
+ name => 'monitor',
+ path => '{vmid}/monitor',
+ method => 'POST',
+ protected => 1,
+ proxyto => 'node',
+ description => "Execute Qemu monitor commands.",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ vmid => get_standard_option('pve-vmid'),
+ command => {
+ type => 'string',
+ description => "The monitor command.",
+ }
+ },
+ },
+ returns => { type => 'string'},
+ code => sub {
+ my ($param) = @_;
+
+ my $vmid = $param->{vmid};
+
+ my $conf = PVE::QemuServer::load_config ($vmid); # check if VM exists
+
+ my $res = '';
+ eval {
+ $res = PVE::QemuServer::vm_monitor_command($vmid, $param->{command});
+ };
+ $res = "ERROR: $@" if $@;
+
+ return $res;
+ }});
+
1;