use PVE::QemuServer::Memory;
use PVE::QemuServer::USB qw(parse_usb_device);
use PVE::QemuServer::Cloudinit;
+use PVE::Systemd;
use Time::HiRes qw(gettimeofday);
use File::Copy qw(copy);
use URI::Escape;
};
PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
+my $agent_fmt = {
+ enabled => {
+ description => "Enable/disable Qemu GuestAgent.",
+ type => 'boolean',
+ default => 0,
+ default_key => 1,
+ },
+ fstrim_cloned_disks => {
+ description => "Run fstrim after cloning/moving a disk.",
+ type => 'boolean',
+ optional => 1,
+ default => 0
+ },
+};
+
my $confdesc = {
onboot => {
optional => 1,
keyboard => {
optional => 1,
type => 'string',
- description => "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.".
+ description => "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
"It should not be necessary to set it.",
enum => PVE::Tools::kvmkeymaplist(),
default => undef,
},
agent => {
optional => 1,
- type => 'boolean',
- description => "Enable/disable Qemu GuestAgent.",
- default => 0,
+ description => "Enable/disable Qemu GuestAgent and its properties.",
+ type => 'string',
+ format => $agent_fmt,
},
kvm => {
optional => 1,
return $res;
}
+sub parse_guest_agent {
+ my ($value) = @_;
+
+ return {} if !defined($value->{agent});
+
+ my $res = eval { PVE::JSONSchema::parse_property_string($agent_fmt, $value->{agent}) };
+ warn $@ if $@;
+
+ # if the agent is disabled ignore the other potentially set properties
+ return {} if !$res->{enabled};
+ return $res;
+}
+
PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
sub verify_usb_device {
my ($value, $noerr) = @_;
return $drive->{size};
}
+our $vmstatus_return_properties = {
+ vmid => get_standard_option('pve-vmid'),
+ status => {
+ description => "Qemu process status.",
+ type => 'string',
+ enum => ['stopped', 'running'],
+ },
+ maxmem => {
+ description => "Maximum memory in bytes.",
+ type => 'integer',
+ optional => 1,
+ renderer => 'bytes',
+ },
+ maxdisk => {
+ description => "Root disk size in bytes.",
+ type => 'integer',
+ optional => 1,
+ renderer => 'bytes',
+ },
+ name => {
+ description => "VM name.",
+ type => 'string',
+ optional => 1,
+ },
+ qmpstatus => {
+ description => "Qemu QMP agent status.",
+ type => 'string',
+ optional => 1,
+ },
+ pid => {
+ description => "PID of running qemu process.",
+ type => 'integer',
+ optional => 1,
+ },
+ uptime => {
+ description => "Uptime.",
+ type => 'integer',
+ optional => 1,
+ renderer => 'duration',
+ },
+ cpus => {
+ description => "Maximum usable CPUs.",
+ type => 'number',
+ optional => 1,
+ },
+};
+
my $last_proc_pid_stat;
# get VM status information
my $cfspath = PVE::QemuConfig->cfs_config_path($vmid);
my $conf = PVE::Cluster::cfs_read_file($cfspath) || {};
- my $d = {};
+ my $d = { vmid => $vmid };
$d->{pid} = $list->{$vmid}->{pid};
# fixme: better status?
#push @$cmd, '-soundhw', 'es1370';
#push @$cmd, '-soundhw', $soundhw if $soundhw;
- if($conf->{agent}) {
+ if (parse_guest_agent($conf)->{enabled}) {
my $qgasocket = qmp_socket($vmid, 1);
my $pciaddr = print_pci_addr("qga0", $bridges);
push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
if ($winversion){
for(my $i = 1; $i < $qxlnum; $i++){
my $pciaddr = print_pci_addr("vga$i", $bridges);
- push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
+ push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
}
} else {
# assume other OS works like Linux
my $running = check_running($vmid);
+ if($running) {
+
+ $running = undef;
+ my $conf = PVE::QemuConfig->load_config($vmid);
+ foreach_drive($conf, sub {
+ my ($ds, $drive) = @_;
+ $running = 1 if $drive->{file} eq $volid;
+ });
+ }
+
if ($running && do_snapshots_with_qemu($storecfg, $volid)){
vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
} else {
my $run_qemu = sub {
PVE::Tools::run_fork sub {
- PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
+ PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
run_command($cmd, %run_params);
};
};
eval {
if ($shutdown) {
- if (defined($conf) && $conf->{agent}) {
+ if (defined($conf) && parse_guest_agent($conf)->{enabled}) {
vm_qmp_command($vmid, { execute => "guest-shutdown" }, $nocheck);
} else {
vm_qmp_command($vmid, { execute => "system_powerdown" }, $nocheck);
PVE::QemuConfig->lock_config($vmid, sub {
+ my $res = vm_mon_cmd($vmid, 'query-status');
+ my $resume_cmd = 'cont';
+
+ if ($res->{status} && $res->{status} eq 'suspended') {
+ $resume_cmd = 'system_wakeup';
+ }
+
if (!$nocheck) {
my $conf = PVE::QemuConfig->load_config($vmid);
PVE::QemuConfig->check_lock($conf)
if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
- vm_mon_cmd($vmid, "cont");
+ vm_mon_cmd($vmid, $resume_cmd);
} else {
- vm_mon_cmd_nocheck($vmid, "cont");
+ vm_mon_cmd_nocheck($vmid, $resume_cmd);
}
});
}
my ($vmid, $conf, $volid_hash) = @_;
my $changes;
+ my $prefix = "VM $vmid:";
# used and unused disks
my $referenced = {};
if ($new ne $conf->{$opt}) {
$changes = 1;
$conf->{$opt} = $new;
+ print "$prefix update disk '$opt' information.\n";
}
}
}
my $volid = $conf->{$opt};
my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
+ print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
$changes = 1;
delete $conf->{$opt};
}
next if !$path; # just to be sure
next if $referencedpath->{$path};
$changes = 1;
- PVE::QemuConfig->add_unused_volume($conf, $volid);
+ my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
+ print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
$referencedpath->{$path} = 1; # avoid to add more than once (aliases)
}
}
sub rescan {
- my ($vmid, $nolock) = @_;
+ my ($vmid, $nolock, $dryrun) = @_;
my $cfg = PVE::Storage::config();
+ # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
+ # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
+ foreach my $stor (keys %{$cfg->{ids}}) {
+ delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
+ }
+
+ print "rescan volumes...\n";
my $volid_hash = scan_volids($cfg, $vmid);
my $updatefn = sub {
my $changes = update_disksize($vmid, $conf, $vm_volids);
- PVE::QemuConfig->write_config($vmid, $conf) if $changes;
+ PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
};
if (defined($vmid)) {
}
sub qga_check_running {
- my ($vmid) = @_;
+ my ($vmid, $nowarn) = @_;
eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
if ($@) {
- warn "Qemu Guest Agent is not running - $@";
+ warn "Qemu Guest Agent is not running - $@" if !$nowarn;
return 0;
}
return 1;