]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
add print_drivedevice_full sub for disk -device syntax
[qemu-server.git] / PVE / QemuServer.pm
CommitLineData
1e3baf05
DM
1package PVE::QemuServer;
2
3use strict;
4use POSIX;
5use IO::Handle;
6use IO::Select;
7use IO::File;
8use IO::Dir;
9use IO::Socket::UNIX;
10use File::Basename;
11use File::Path;
12use File::stat;
13use Getopt::Long;
14use Digest::SHA1;
15use Fcntl ':flock';
16use Cwd 'abs_path';
17use IPC::Open3;
18use Fcntl;
19use PVE::SafeSyslog;
20use Storable qw(dclone);
21use PVE::Exception qw(raise raise_param_exc);
22use PVE::Storage;
23use PVE::Tools qw(run_command lock_file file_read_firstline);
24use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
25use PVE::INotify;
26use PVE::ProcFSTools;
27use Time::HiRes qw (gettimeofday);
28
29my $clock_ticks = POSIX::sysconf(&POSIX::_SC_CLK_TCK);
30
31# Note about locking: we use flock on the config file protect
32# against concurent actions.
33# Aditionaly, we have a 'lock' setting in the config file. This
34# can be set to 'migrate' or 'backup'. Most actions are not
35# allowed when such lock is set. But you can ignore this kind of
36# lock with the --skiplock flag.
37
38cfs_register_file('/qemu-server/', \&parse_vm_config);
39
40#no warnings 'redefine';
41
42unless(defined(&_VZSYSCALLS_H_)) {
43 eval 'sub _VZSYSCALLS_H_ () {1;}' unless defined(&_VZSYSCALLS_H_);
44 require 'sys/syscall.ph';
45 if(defined(&__x86_64__)) {
46 eval 'sub __NR_fairsched_vcpus () {499;}' unless defined(&__NR_fairsched_vcpus);
47 eval 'sub __NR_fairsched_mknod () {504;}' unless defined(&__NR_fairsched_mknod);
48 eval 'sub __NR_fairsched_rmnod () {505;}' unless defined(&__NR_fairsched_rmnod);
49 eval 'sub __NR_fairsched_chwt () {506;}' unless defined(&__NR_fairsched_chwt);
50 eval 'sub __NR_fairsched_mvpr () {507;}' unless defined(&__NR_fairsched_mvpr);
51 eval 'sub __NR_fairsched_rate () {508;}' unless defined(&__NR_fairsched_rate);
52 eval 'sub __NR_setluid () {501;}' unless defined(&__NR_setluid);
53 eval 'sub __NR_setublimit () {502;}' unless defined(&__NR_setublimit);
54 }
55 elsif(defined( &__i386__) ) {
56 eval 'sub __NR_fairsched_mknod () {500;}' unless defined(&__NR_fairsched_mknod);
57 eval 'sub __NR_fairsched_rmnod () {501;}' unless defined(&__NR_fairsched_rmnod);
58 eval 'sub __NR_fairsched_chwt () {502;}' unless defined(&__NR_fairsched_chwt);
59 eval 'sub __NR_fairsched_mvpr () {503;}' unless defined(&__NR_fairsched_mvpr);
60 eval 'sub __NR_fairsched_rate () {504;}' unless defined(&__NR_fairsched_rate);
61 eval 'sub __NR_fairsched_vcpus () {505;}' unless defined(&__NR_fairsched_vcpus);
62 eval 'sub __NR_setluid () {511;}' unless defined(&__NR_setluid);
63 eval 'sub __NR_setublimit () {512;}' unless defined(&__NR_setublimit);
64 } else {
65 die("no fairsched syscall for this arch");
66 }
67 require 'asm/ioctl.ph';
68 eval 'sub KVM_GET_API_VERSION () { &_IO(0xAE, 0x);}' unless defined(&KVM_GET_API_VERSION);
69}
70
71sub fairsched_mknod {
72 my ($parent, $weight, $desired) = @_;
73
74 return syscall(&__NR_fairsched_mknod, int ($parent), int ($weight), int ($desired));
75}
76
77sub fairsched_rmnod {
78 my ($id) = @_;
79
80 return syscall(&__NR_fairsched_rmnod, int ($id));
81}
82
83sub fairsched_mvpr {
84 my ($pid, $newid) = @_;
85
86 return syscall(&__NR_fairsched_mvpr, int ($pid), int ($newid));
87}
88
89sub fairsched_vcpus {
90 my ($id, $vcpus) = @_;
91
92 return syscall(&__NR_fairsched_vcpus, int ($id), int ($vcpus));
93}
94
95sub fairsched_rate {
96 my ($id, $op, $rate) = @_;
97
98 return syscall(&__NR_fairsched_rate, int ($id), int ($op), int ($rate));
99}
100
101use constant FAIRSCHED_SET_RATE => 0;
102use constant FAIRSCHED_DROP_RATE => 1;
103use constant FAIRSCHED_GET_RATE => 2;
104
105sub fairsched_cpulimit {
106 my ($id, $limit) = @_;
107
108 my $cpulim1024 = int ($limit * 1024 / 100);
109 my $op = $cpulim1024 ? FAIRSCHED_SET_RATE : FAIRSCHED_DROP_RATE;
110
111 return fairsched_rate ($id, $op, $cpulim1024);
112}
113
114my $nodename = PVE::INotify::nodename();
115
116mkdir "/etc/pve/nodes/$nodename";
117my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
118mkdir $confdir;
119
120my $var_run_tmpdir = "/var/run/qemu-server";
121mkdir $var_run_tmpdir;
122
123my $lock_dir = "/var/lock/qemu-server";
124mkdir $lock_dir;
125
126my $pcisysfs = "/sys/bus/pci";
127
128my $keymaphash = PVE::Tools::kvmkeymaps();
129
130my $confdesc = {
131 onboot => {
132 optional => 1,
133 type => 'boolean',
134 description => "Specifies whether a VM will be started during system bootup.",
135 default => 0,
136 },
137 autostart => {
138 optional => 1,
139 type => 'boolean',
140 description => "Automatic restart after crash (currently ignored).",
141 default => 0,
142 },
143 reboot => {
144 optional => 1,
145 type => 'boolean',
146 description => "Allow reboot. If set to '0' the VM exit on reboot.",
147 default => 1,
148 },
149 lock => {
150 optional => 1,
151 type => 'string',
152 description => "Lock/unlock the VM.",
153 enum => [qw(migrate backup)],
154 },
155 cpulimit => {
156 optional => 1,
157 type => 'integer',
158 description => "Limit of CPU usage in per cent. Note if the computer has 2 CPUs, it has total of 200% CPU time. Value '0' indicates no CPU limit.\n\nNOTE: This option is currently ignored.",
159 minimum => 0,
160 default => 0,
161 },
162 cpuunits => {
163 optional => 1,
164 type => 'integer',
165 description => "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.\n\nNOTE: You can disable fair-scheduler configuration by setting this to 0.",
166 minimum => 0,
167 maximum => 500000,
168 default => 1000,
169 },
170 memory => {
171 optional => 1,
172 type => 'integer',
173 description => "Amount of RAM for the VM in MB.",
174 minimum => 16,
175 default => 512,
176 },
177 keyboard => {
178 optional => 1,
179 type => 'string',
180 description => "Keybord layout for vnc server. Default is read from the datacenter configuration file.",
181 enum => [ keys %$keymaphash ],
182 default => 'en-us',
183 },
184 name => {
185 optional => 1,
186 type => 'string',
187 description => "Set a name for the VM. Only used on the configuration web interface.",
188 },
189 description => {
190 optional => 1,
191 type => 'string',
192 description => "Description for the VM. Only used on the configuration web interface.",
193 },
194 ostype => {
195 optional => 1,
196 type => 'string',
197 enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 l24 l26)],
198 description => <<EODESC,
199Used to enable special optimization/features for specific
200operating systems:
201
202other => unspecified OS
203wxp => Microsoft Windows XP
204w2k => Microsoft Windows 2000
205w2k3 => Microsoft Windows 2003
206w2k8 => Microsoft Windows 2008
207wvista => Microsoft Windows Vista
208win7 => Microsoft Windows 7
209l24 => Linux 2.4 Kernel
210l26 => Linux 2.6/3.X Kernel
211
212other|l24|l26 ... no special behaviour
213wxp|w2k|w2k3|w2k8|wvista|win7 ... use --localtime switch
214EODESC
215 },
216 boot => {
217 optional => 1,
218 type => 'string',
219 description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
220 pattern => '[acdn]{1,4}',
221 default => 'cad',
222 },
223 bootdisk => {
224 optional => 1,
225 type => 'string', format => 'pve-qm-bootdisk',
226 description => "Enable booting from specified disk.",
227 pattern => '(ide|scsi|virtio)\d+',
228 },
229 smp => {
230 optional => 1,
231 type => 'integer',
232 description => "The number of CPUs. Please use option -sockets instead.",
233 minimum => 1,
234 default => 1,
235 },
236 sockets => {
237 optional => 1,
238 type => 'integer',
239 description => "The number of CPU sockets.",
240 minimum => 1,
241 default => 1,
242 },
243 cores => {
244 optional => 1,
245 type => 'integer',
246 description => "The number of cores per socket.",
247 minimum => 1,
248 default => 1,
249 },
250 acpi => {
251 optional => 1,
252 type => 'boolean',
253 description => "Enable/disable ACPI.",
254 default => 1,
255 },
256 kvm => {
257 optional => 1,
258 type => 'boolean',
259 description => "Enable/disable KVM hardware virtualization.",
260 default => 1,
261 },
262 tdf => {
263 optional => 1,
264 type => 'boolean',
265 description => "Enable/disable time drift fix.",
266 default => 1,
267 },
268 localtime => {
269 optional => 1,
270 type => 'boolean',
271 description => "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
272 },
273 freeze => {
274 optional => 1,
275 type => 'boolean',
276 description => "Freeze CPU at startup (use 'c' monitor command to start execution).",
277 },
278 vga => {
279 optional => 1,
280 type => 'string',
281 description => "Select VGA type. If you want to use high resolution modes (>= 1280x1024x16) then you should use option 'std' or 'vmware'. Default is 'std' for win7/w2k8, and 'cirrur' for other OS types",
282 enum => [qw(std cirrus vmware)],
283 },
284 hostpci => {
285 optional => 1,
286 type => 'string', format => 'pve-qm-hostpci',
287 typetext => "HOSTPCIDEVICE { , HOSTPCIDEVICE }",
288 description => <<EODESCR,
289Map host pci devices. HOSTPCIDEVICE syntax is:
290
291'bus:dev.func' (hexadecimal numbers)
292
293You can us the 'lspci' command to list existing pci devices.
294
295Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
296
297Experimental: user reported problems with this option.
298EODESCR
299 },
300 serial => {
301 optional => 1,
302 type => 'string', format => 'pve-qm-serial',
303 typetext => "SERIALDEVICE { , SERIALDEVICE }",
304 description => <<EODESCR,
305Map host serial devices. SERIALDEVICE syntax is /dev/ttyS*
306
307Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
308
309Experimental: user reported problems with this option.
310EODESCR
311 },
312 parallel => {
313 optional => 1,
314 type => 'string', format => 'pve-qm-parallel',
315 typetext => "PARALLELDEVICE { , PARALLELDEVICE }",
316 description => <<EODESCR,
317Map host parallel devices. PARALLELDEVICE syntax is /dev/parport*
318
319Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
320
321Experimental: user reported problems with this option.
322EODESCR
323 },
324 startdate => {
325 optional => 1,
326 type => 'string',
327 typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
328 description => "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
329 pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
330 default => 'now',
331 },
332 args => {
333 optional => 1,
334 type => 'string',
335 description => <<EODESCR,
336Note: this option is for experts only. It allows you to pass arbitrary arguments to kvm, for example:
337
338args: -no-reboot -no-hpet
339EODESCR
340 },
341 tablet => {
342 optional => 1,
343 type => 'boolean',
344 default => 1,
345 description => "Enable/disable the usb tablet device. This device is usually needed to allow absolute mouse positioning. Else the mouse runs out of sync with normal vnc clients. If you're running lots of console-only guests on one host, you may consider disabling this to save some context switches.",
346 },
347 migrate_speed => {
348 optional => 1,
349 type => 'integer',
350 description => "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
351 minimum => 0,
352 default => 0,
353 },
354 migrate_downtime => {
355 optional => 1,
356 type => 'integer',
357 description => "Set maximum tolerated downtime (in seconds) for migrations.",
358 minimum => 0,
359 default => 1,
360 },
361 cdrom => {
362 optional => 1,
363 type => 'string', format => 'pve-qm-drive',
364 typetext => 'volume',
365 description => "This is an alias for option -ide2",
366 },
367 cpu => {
368 optional => 1,
369 description => "Emulated CPU type.",
370 type => 'string',
371 enum => [ qw(486 athlon pentium pentium2 pentium3 coreduo core2duo kvm32 kvm64 qemu32 qemu64 phenom host) ],
372 default => 'qemu64',
373 },
374};
375
376# what about other qemu settings ?
377#cpu => 'string',
378#machine => 'string',
379#fda => 'file',
380#fdb => 'file',
381#mtdblock => 'file',
382#sd => 'file',
383#pflash => 'file',
384#snapshot => 'bool',
385#bootp => 'file',
386##tftp => 'dir',
387##smb => 'dir',
388#kernel => 'file',
389#append => 'string',
390#initrd => 'file',
391##soundhw => 'string',
392
393while (my ($k, $v) = each %$confdesc) {
394 PVE::JSONSchema::register_standard_option("pve-qm-$k", $v);
395}
396
397my $MAX_IDE_DISKS = 4;
f62db2a4
DA
398my $MAX_SCSI_DISKS = 14;
399my $MAX_VIRTIO_DISKS = 6;
1e3baf05 400my $MAX_USB_DEVICES = 5;
f62db2a4 401my $MAX_NETS = 6;
1e3baf05
DM
402my $MAX_UNUSED_DISKS = 8;
403
404my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
405 'ne2k_isa', 'i82551', 'i82557b', 'i82559er'];
406my $nic_model_list_txt = join (' ', sort @$nic_model_list);
407
408# fixme:
409my $netdesc = {
410 optional => 1,
411 type => 'string', format => 'pve-qm-net',
412 typetext => "MODEL=XX:XX:XX:XX:XX:XX [,bridge=<dev>][,rate=<mbps>]",
413 description => <<EODESCR,
414Specify network devices.
415
416MODEL is one of: $nic_model_list_txt
417
418XX:XX:XX:XX:XX:XX should be an unique MAC address. This is
419automatically generated if not specified.
420
421The bridge parameter can be used to automatically add the interface to a bridge device. The Proxmox VE standard bridge is called 'vmbr0'.
422
423Option 'rate' is used to limit traffic bandwidth from and to this interface. It is specified as floating point number, unit is 'Megabytes per second'.
424
425If you specify no bridge, we create a kvm 'user' (NATed) network device, which provides DHCP and DNS services. The following addresses are used:
426
42710.0.2.2 Gateway
42810.0.2.3 DNS Server
42910.0.2.4 SMB Server
430
431The DHCP server assign addresses to the guest starting from 10.0.2.15.
432
433EODESCR
434};
435PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
436
437for (my $i = 0; $i < $MAX_NETS; $i++) {
438 $confdesc->{"net$i"} = $netdesc;
439}
440
441my $drivename_hash;
442
443my $idedesc = {
444 optional => 1,
445 type => 'string', format => 'pve-qm-drive',
446 typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback] [,format=f] [,backup=yes|no] [,aio=native|threads]',
447 description => "Use volume as IDE hard disk or CD-ROM (n is 0 to 3).",
448};
449PVE::JSONSchema::register_standard_option("pve-qm-ide", $idedesc);
450
451my $scsidesc = {
452 optional => 1,
453 type => 'string', format => 'pve-qm-drive',
454 typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback] [,format=f] [,backup=yes|no] [,aio=native|threads]',
455 description => "Use volume as SCSI hard disk or CD-ROM (n is 0 to 15).",
456};
457PVE::JSONSchema::register_standard_option("pve-qm-scsi", $scsidesc);
458
459my $virtiodesc = {
460 optional => 1,
461 type => 'string', format => 'pve-qm-drive',
462 typetext => '[volume=]volume,] [,media=cdrom|disk] [,cyls=c,heads=h,secs=s[,trans=t]] [,snapshot=on|off] [,cache=none|writethrough|writeback] [,format=f] [,backup=yes|no] [,aio=native|threads]',
463 description => "Use volume as VIRTIO hard disk (n is 0 to 15).",
464};
465PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc);
466
467my $usbdesc = {
468 optional => 1,
469 type => 'string', format => 'pve-qm-usb-device',
470 typetext => 'host=HOSTUSBDEVICE',
471 description => <<EODESCR,
472Configure an USB device (n is 0 to 5). This can be used to
473pass-through usb devices to the guest. HOSTUSBDEVICE syntax is:
474
475'bus-port(.port)*' (decimal numbers) or
476'vendor_id:product_id' (hexadeciaml numbers)
477
478You can use the 'lsusb -t' command to list existing usb devices.
479
480Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
481
482EODESCR
483};
484PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
485
486
487for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
488 $drivename_hash->{"ide$i"} = 1;
489 $confdesc->{"ide$i"} = $idedesc;
490}
491
492for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
493 $drivename_hash->{"scsi$i"} = 1;
494 $confdesc->{"scsi$i"} = $scsidesc ;
495}
496
497for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
498 $drivename_hash->{"virtio$i"} = 1;
499 $confdesc->{"virtio$i"} = $virtiodesc;
500}
501
502for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
503 $confdesc->{"usb$i"} = $usbdesc;
504}
505
506my $unuseddesc = {
507 optional => 1,
508 type => 'string', format => 'pve-volume-id',
509 description => "Reference to unused volumes.",
510};
511
512for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
513 $confdesc->{"unused$i"} = $unuseddesc;
514}
515
516my $kvm_api_version = 0;
517
518sub kvm_version {
519
520 return $kvm_api_version if $kvm_api_version;
521
522 my $fh = IO::File->new ("</dev/kvm") ||
523 return 0;
524
525 if (my $v = $fh->ioctl (KVM_GET_API_VERSION(), 0)) {
526 $kvm_api_version = $v;
527 }
528
529 $fh->close();
530
531 return $kvm_api_version;
532}
533
534my $kvm_user_version;
535
536sub kvm_user_version {
537
538 return $kvm_user_version if $kvm_user_version;
539
540 $kvm_user_version = 'unknown';
541
542 my $tmp = `kvm -help 2>/dev/null`;
543
544 if ($tmp =~ m/^QEMU( PC)? emulator version (\d+\.\d+\.\d+) /) {
545 $kvm_user_version = $2;
546 }
547
548 return $kvm_user_version;
549
550}
551
552my $kernel_has_vhost_net = -c '/dev/vhost-net';
553
554sub disknames {
555 # order is important - used to autoselect boot disk
556 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
557 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
558 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))));
559}
560
561sub valid_drivename {
562 my $dev = shift;
563
564 return defined ($drivename_hash->{$dev});
565}
566
567sub option_exists {
568 my $key = shift;
569 return defined($confdesc->{$key});
570}
571
572sub nic_models {
573 return $nic_model_list;
574}
575
576sub os_list_description {
577
578 return {
579 other => 'Other',
580 wxp => 'Windows XP',
581 w2k => 'Windows 2000',
582 w2k3 =>, 'Windows 2003',
583 w2k8 => 'Windows 2008',
584 wvista => 'Windows Vista',
585 win7 => 'Windows 7',
586 l24 => 'Linux 2.4',
587 l26 => 'Linux 2.6',
588 };
589}
590
591# a clumsy way to split an argument string into an array,
592# we simply pass it to the cli (exec call)
593# fixme: use Text::ParseWords::shellwords() ?
594sub split_args {
595 my ($str) = @_;
596
597 my $args = [];
598
599 return $args if !$str;
600
601 my $cmd = 'perl -e \'foreach my $a (@ARGV) { print "$a\n"; } \' -- ' . $str;
602
603 eval {
604 run_command ($cmd, outfunc => sub {
605 my $data = shift;
606 push @$args, $data;
607 });
608 };
609
610 my $err = $@;
611
612 die "unable to parse args: $str\n" if $err;
613
614 return $args;
615}
616
617sub disk_devive_info {
618 my $dev = shift;
619
620 die "unknown disk device format '$dev'" if $dev !~ m/^(ide|scsi|virtio)(\d+)$/;
621
622 my $bus = $1;
623 my $index = $2;
624 my $maxdev = 1024;
625
626 if ($bus eq 'ide') {
627 $maxdev = 2;
628 } elsif ($bus eq 'scsi') {
f62db2a4 629 $maxdev = 7;
1e3baf05
DM
630 }
631
632 my $controller = int ($index / $maxdev);
633 my $unit = $index % $maxdev;
634
635
636 return { bus => $bus, desc => uc($bus) . " $controller:$unit",
637 controller => $controller, unit => $unit, index => $index };
638
639}
640
641sub qemu_drive_name {
642 my ($dev, $media) = @_;
643
644 my $info = disk_devive_info ($dev);
645 my $mediastr = '';
646
647 if (($info->{bus} eq 'ide') || ($info->{bus} eq 'scsi')) {
648 $mediastr = ($media eq 'cdrom') ? "-cd" : "-hd";
649 return sprintf("%s%i%s%i", $info->{bus}, $info->{controller},
650 $mediastr, $info->{unit});
651 } else {
652 return sprintf("%s%i", $info->{bus}, $info->{index});
653 }
654}
655
656my $cdrom_path;
657
658sub get_cdrom_path {
659
660 return $cdrom_path if $cdrom_path;
661
662 return $cdrom_path = "/dev/cdrom" if -l "/dev/cdrom";
663 return $cdrom_path = "/dev/cdrom1" if -l "/dev/cdrom1";
664 return $cdrom_path = "/dev/cdrom2" if -l "/dev/cdrom2";
665}
666
667sub get_iso_path {
668 my ($storecfg, $vmid, $cdrom) = @_;
669
670 if ($cdrom eq 'cdrom') {
671 return get_cdrom_path();
672 } elsif ($cdrom eq 'none') {
673 return '';
674 } elsif ($cdrom =~ m|^/|) {
675 return $cdrom;
676 } else {
677 return PVE::Storage::path ($storecfg, $cdrom);
678 }
679}
680
681# try to convert old style file names to volume IDs
682sub filename_to_volume_id {
683 my ($vmid, $file, $media) = @_;
684
685 if (!($file eq 'none' || $file eq 'cdrom' ||
686 $file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
687
688 return undef if $file =~ m|/|;
689
690 if ($media && $media eq 'cdrom') {
691 $file = "local:iso/$file";
692 } else {
693 $file = "local:$vmid/$file";
694 }
695 }
696
697 return $file;
698}
699
700sub verify_media_type {
701 my ($opt, $vtype, $media) = @_;
702
703 return if !$media;
704
705 my $etype;
706 if ($media eq 'disk') {
707 $etype = 'image';
708 } elsif ($media eq 'cdrom') {
709 $etype = 'iso';
710 } else {
711 die "internal error";
712 }
713
714 return if ($vtype eq $etype);
715
716 raise_param_exc({ $opt => "unexpected media type ($vtype != $etype)" });
717}
718
719sub cleanup_drive_path {
720 my ($opt, $storecfg, $drive) = @_;
721
722 # try to convert filesystem paths to volume IDs
723
724 if (($drive->{file} !~ m/^(cdrom|none)$/) &&
725 ($drive->{file} !~ m|^/dev/.+|) &&
726 ($drive->{file} !~ m/^([^:]+):(.+)$/) &&
727 ($drive->{file} !~ m/^\d+$/)) {
728 my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
729 raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
730 $drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
731 verify_media_type($opt, $vtype, $drive->{media});
732 $drive->{file} = $volid;
733 }
734
735 $drive->{media} = 'cdrom' if !$drive->{media} && $drive->{file} =~ m/^(cdrom|none)$/;
736}
737
738sub create_conf_nolock {
739 my ($vmid, $settings) = @_;
740
741 my $filename = config_file ($vmid);
742
743 die "configuration file '$filename' already exists\n" if -f $filename;
744
745 my $defaults = load_defaults();
746
747 $settings->{name} = "vm$vmid" if !$settings->{name};
748 $settings->{memory} = $defaults->{memory} if !$settings->{memory};
749
750 my $data = '';
751 foreach my $opt (keys %$settings) {
752 next if !$confdesc->{$opt};
753
754 my $value = $settings->{$opt};
755 next if !$value;
756
757 $data .= "$opt: $value\n";
758 }
759
760 PVE::Tools::file_set_contents($filename, $data);
761}
762
763# ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
764# [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
765# [,aio=native|threads]
766
767sub parse_drive {
768 my ($key, $data) = @_;
769
770 my $res = {};
771
772 # $key may be undefined - used to verify JSON parameters
773 if (!defined($key)) {
774 $res->{interface} = 'unknown'; # should not harm when used to verify parameters
775 $res->{index} = 0;
776 } elsif ($key =~ m/^([^\d]+)(\d+)$/) {
777 $res->{interface} = $1;
778 $res->{index} = $2;
779 } else {
780 return undef;
781 }
782
783 foreach my $p (split (/,/, $data)) {
784 next if $p =~ m/^\s*$/;
785
786 if ($p =~ m/^(file|volume|cyls|heads|secs|trans|media|snapshot|cache|format|rerror|werror|backup|aio)=(.+)$/) {
787 my ($k, $v) = ($1, $2);
788
789 $k = 'file' if $k eq 'volume';
790
791 return undef if defined $res->{$k};
792
793 $res->{$k} = $v;
794 } else {
795 if (!$res->{file} && $p !~ m/=/) {
796 $res->{file} = $p;
797 } else {
798 return undef;
799 }
800 }
801 }
802
803 return undef if !$res->{file};
804
805 return undef if $res->{cache} &&
806 $res->{cache} !~ m/^(off|none|writethrough|writeback)$/;
807 return undef if $res->{snapshot} && $res->{snapshot} !~ m/^(on|off)$/;
808 return undef if $res->{cyls} && $res->{cyls} !~ m/^\d+$/;
809 return undef if $res->{heads} && $res->{heads} !~ m/^\d+$/;
810 return undef if $res->{secs} && $res->{secs} !~ m/^\d+$/;
811 return undef if $res->{media} && $res->{media} !~ m/^(disk|cdrom)$/;
812 return undef if $res->{trans} && $res->{trans} !~ m/^(none|lba|auto)$/;
813 return undef if $res->{format} && $res->{format} !~ m/^(raw|cow|qcow|qcow2|vmdk|cloop)$/;
814 return undef if $res->{rerror} && $res->{rerror} !~ m/^(ignore|report|stop)$/;
815 return undef if $res->{werror} && $res->{werror} !~ m/^(enospc|ignore|report|stop)$/;
816 return undef if $res->{backup} && $res->{backup} !~ m/^(yes|no)$/;
817 return undef if $res->{aio} && $res->{aio} !~ m/^(native|threads)$/;
818
819 if ($res->{media} && ($res->{media} eq 'cdrom')) {
820 return undef if $res->{snapshot} || $res->{trans} || $res->{format};
821 return undef if $res->{heads} || $res->{secs} || $res->{cyls};
822 return undef if $res->{interface} eq 'virtio';
823 }
824
825 # rerror does not work with scsi drives
826 if ($res->{rerror}) {
827 return undef if $res->{interface} eq 'scsi';
828 }
829
830 return $res;
831}
832
833my @qemu_drive_options = qw(heads secs cyls trans media format cache snapshot rerror werror aio);
834
835sub print_drive {
836 my ($vmid, $drive) = @_;
837
838 my $opts = '';
839 foreach my $o (@qemu_drive_options, 'backup') {
840 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
841 }
842
843 return "$drive->{file}$opts";
844}
845
ca916ecc
DA
846sub print_drivedevice_full {
847 my ($storecfg, $vmid, $drive) = @_;
848
849 my $device = '';
850 my $maxdev = 0;
851
852 if ($drive->{interface} eq 'virtio') {
853
854 $device="virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=device-$drive->{interface}$drive->{index}";
855 }
856
857 elsif ($drive->{interface} eq 'scsi') {
858
859 $maxdev = 7;
860 my $controller = int ($drive->{index} / $maxdev);
861 my $unit = $drive->{index} % $maxdev;
862
863 $device="scsi-disk,bus=scsi$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=device-$drive->{interface}$drive->{index}";
864 }
865
866 elsif ($drive->{interface} eq 'ide'){
867
868 $maxdev = 2;
869 my $controller = int ($drive->{index} / $maxdev);
870 my $unit = $drive->{index} % $maxdev;
871
872 $device="ide-drive,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=device-$drive->{interface}$drive->{index}";
873 }
874
875 if ($drive->{interface} eq 'usb'){
876 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
877 }
878
879 return $device;
880}
881
1e3baf05
DM
882sub print_drive_full {
883 my ($storecfg, $vmid, $drive) = @_;
884
885 my $opts = '';
886 foreach my $o (@qemu_drive_options) {
887 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
888 }
889
890 # use linux-aio by default (qemu default is threads)
891 $opts .= ",aio=native" if !$drive->{aio};
892
893 my $path;
894 my $volid = $drive->{file};
895 if (drive_is_cdrom ($drive)) {
896 $path = get_iso_path ($storecfg, $vmid, $volid);
897 } else {
898 if ($volid =~ m|^/|) {
899 $path = $volid;
900 } else {
901 $path = PVE::Storage::path ($storecfg, $volid);
902 }
903 }
904
905 my $pathinfo = $path ? "file=$path," : '';
906
3ebfcc86 907 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1e3baf05
DM
908}
909
910
911sub drive_is_cdrom {
912 my ($drive) = @_;
913
914 return $drive && $drive->{media} && ($drive->{media} eq 'cdrom');
915
916}
917
918# netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
919sub parse_net {
920 my ($data) = @_;
921
922 my $res = {};
923
924 foreach my $kvp (split (/,/, $data)) {
925
926 if ($kvp =~ m/^(ne2k_pci|e1000|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i) {
927 my $model = lc ($1);
928 my $mac = uc($3) || random_ether_addr ();
929 $res->{model} = $model;
930 $res->{macaddr} = $mac;
931 } elsif ($kvp =~ m/^bridge=(\S+)$/) {
932 $res->{bridge} = $1;
933 } elsif ($kvp =~ m/^rate=(\d+(\.\d+)?)$/) {
934 $res->{rate} = $1;
935 } else {
936 return undef;
937 }
938
939 }
940
941 return undef if !$res->{model};
942
943 return $res;
944}
945
946sub print_net {
947 my $net = shift;
948
949 my $res = "$net->{model}";
950 $res .= "=$net->{macaddr}" if $net->{macaddr};
951 $res .= ",bridge=$net->{bridge}" if $net->{bridge};
952 $res .= ",rate=$net->{rate}" if $net->{rate};
953
954 return $res;
955}
956
957sub add_random_macs {
958 my ($settings) = @_;
959
960 foreach my $opt (keys %$settings) {
961 next if $opt !~ m/^net(\d+)$/;
962 my $net = parse_net($settings->{$opt});
963 next if !$net;
964 $settings->{$opt} = print_net($net);
965 }
966}
967
968sub add_unused_volume {
969 my ($config, $res, $volid) = @_;
970
971 my $key;
972 for (my $ind = $MAX_UNUSED_DISKS - 1; $ind >= 0; $ind--) {
973 my $test = "unused$ind";
974 if (my $vid = $config->{$test}) {
975 return if $vid eq $volid; # do not add duplicates
976 } else {
977 $key = $test;
978 }
979 }
980
981 die "To many unused volume - please delete them first.\n" if !$key;
982
983 $res->{$key} = $volid;
984}
985
986# fixme: remove all thos $noerr parameters?
987
988PVE::JSONSchema::register_format('pve-qm-bootdisk', \&verify_bootdisk);
989sub verify_bootdisk {
990 my ($value, $noerr) = @_;
991
992 return $value if valid_drivename($value);
993
994 return undef if $noerr;
995
996 die "invalid boot disk '$value'\n";
997}
998
999PVE::JSONSchema::register_format('pve-qm-net', \&verify_net);
1000sub verify_net {
1001 my ($value, $noerr) = @_;
1002
1003 return $value if parse_net($value);
1004
1005 return undef if $noerr;
1006
1007 die "unable to parse network options\n";
1008}
1009
1010PVE::JSONSchema::register_format('pve-qm-drive', \&verify_drive);
1011sub verify_drive {
1012 my ($value, $noerr) = @_;
1013
1014 return $value if parse_drive (undef, $value);
1015
1016 return undef if $noerr;
1017
1018 die "unable to parse drive options\n";
1019}
1020
1021PVE::JSONSchema::register_format('pve-qm-hostpci', \&verify_hostpci);
1022sub verify_hostpci {
1023 my ($value, $noerr) = @_;
1024
1025 my @dl = split (/,/, $value);
1026 foreach my $v (@dl) {
1027 if ($v !~ m/^[a-f0-9]{2}:[a-f0-9]{2}\.[a-f0-9]$/i) {
1028 return undef if $noerr;
1029 die "unable to parse pci id\n";
1030 }
1031 }
1032 return $value;
1033}
1034
1035sub parse_usb_device {
1036 my ($value) = @_;
1037
1038 return undef if !$value;
1039
1040 my @dl = split (/,/, $value);
1041 my $found;
1042
1043 my $res = {};
1044 foreach my $v (@dl) {
1045 if ($v =~ m/^host=([0-9A-Fa-f]{4}):([0-9A-Fa-f]{4})$/) {
1046 $found = 1;
1047 $res->{vendorid} = $1;
1048 $res->{productid} = $2;
1049 } elsif ($v =~ m/^host=(\d+)\-(\d+(\.\d+)*)$/) {
1050 $found = 1;
1051 $res->{hostbus} = $1;
1052 $res->{hostport} = $2;
1053 } else {
1054 return undef;
1055 }
1056 }
1057 return undef if !$found;
1058
1059 return $res;
1060}
1061
1062PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
1063sub verify_usb_device {
1064 my ($value, $noerr) = @_;
1065
1066 return $value if parse_usb_device($value);
1067
1068 return undef if $noerr;
1069
1070 die "unable to parse usb device\n";
1071}
1072
1073PVE::JSONSchema::register_format('pve-qm-parallel', \&verify_parallel);
1074sub verify_parallel {
1075 my ($value, $noerr) = @_;
1076
1077 my @dl = split (/,/, $value);
1078 foreach my $v (@dl) {
1079 if ($v !~ m|^/dev/parport\d+$|) {
1080 return undef if $noerr;
1081 die "invalid device name\n";
1082 }
1083 }
1084 return $value;
1085}
1086
1087PVE::JSONSchema::register_format('pve-qm-serial', \&verify_serial);
1088sub verify_serial {
1089 my ($value, $noerr) = @_;
1090
1091 my @dl = split (/,/, $value);
1092 foreach my $v (@dl) {
1093 if ($v !~ m|^/dev/ttyS\d+$|) {
1094 return undef if $noerr;
1095 die "invalid device name\n";
1096 }
1097 }
1098 return $value;
1099}
1100
1101# add JSON properties for create and set function
1102sub json_config_properties {
1103 my $prop = shift;
1104
1105 foreach my $opt (keys %$confdesc) {
1106 $prop->{$opt} = $confdesc->{$opt};
1107 }
1108
1109 return $prop;
1110}
1111
1112sub check_type {
1113 my ($key, $value) = @_;
1114
1115 die "unknown setting '$key'\n" if !$confdesc->{$key};
1116
1117 my $type = $confdesc->{$key}->{type};
1118
1119 if (!defined ($value)) {
1120 die "got undefined value\n";
1121 }
1122
1123 if ($value =~ m/[\n\r]/) {
1124 die "property contains a line feed\n";
1125 }
1126
1127 if ($type eq 'boolean') {
1128 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
1129 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
1130 die "type check ('boolean') failed - got '$value'\n";
1131 } elsif ($type eq 'integer') {
1132 return int($1) if $value =~ m/^(\d+)$/;
1133 die "type check ('integer') failed - got '$value'\n";
1134 } elsif ($type eq 'string') {
1135 if (my $fmt = $confdesc->{$key}->{format}) {
1136 if ($fmt eq 'pve-qm-drive') {
1137 # special case - we need to pass $key to parse_drive()
1138 my $drive = parse_drive ($key, $value);
1139 return $value if $drive;
1140 die "unable to parse drive options\n";
1141 }
1142 PVE::JSONSchema::check_format($fmt, $value);
1143 return $value;
1144 }
1145 $value =~ s/^\"(.*)\"$/$1/;
1146 return $value;
1147 } else {
1148 die "internal error"
1149 }
1150}
1151
1152sub lock_config {
1153 my ($vmid, $code, @param) = @_;
1154
1155 my $filename = config_file_lock ($vmid);
1156
1157 lock_file($filename, 10, $code, @param);
1158
1159 die $@ if $@;
1160}
1161
1162sub cfs_config_path {
1163 my ($vmid) = @_;
1164
1165 return "nodes/$nodename/qemu-server/$vmid.conf";
1166}
1167
1168sub config_file {
1169 my ($vmid) = @_;
1170
1171 my $cfspath = cfs_config_path($vmid);
1172 return "/etc/pve/$cfspath";
1173}
1174
1175sub config_file_lock {
1176 my ($vmid) = @_;
1177
1178 return "$lock_dir/lock-$vmid.conf";
1179}
1180
1181sub touch_config {
1182 my ($vmid) = @_;
1183
1184 my $conf = config_file ($vmid);
1185 utime undef, undef, $conf;
1186}
1187
1188sub create_disks {
1189 my ($storecfg, $vmid, $settings) = @_;
1190
1191 my $vollist = [];
1192
1193 eval {
1194 foreach_drive($settings, sub {
1195 my ($ds, $disk) = @_;
1196
1197 return if drive_is_cdrom ($disk);
1198
1199 my $file = $disk->{file};
1200
1201 if ($file =~ m/^(([^:\s]+):)?(\d+(\.\d+)?)$/) {
1202 my $storeid = $2 || 'local';
1203 my $size = $3;
1204 my $defformat = PVE::Storage::storage_default_format ($storecfg, $storeid);
1205 my $fmt = $disk->{format} || $defformat;
1206 syslog ('info', "VM $vmid creating new disk - size is $size GB");
1207
1208 my $volid = PVE::Storage::vdisk_alloc ($storecfg, $storeid, $vmid,
1209 $fmt, undef, $size*1024*1024);
1210
1211 $disk->{file} = $volid;
1212 delete ($disk->{format}); # no longer needed
1213 push @$vollist, $volid;
1214 $settings->{$ds} = PVE::QemuServer::print_drive ($vmid, $disk);
1215 } else {
1216 my $path;
1217 if ($disk->{file} =~ m|^/dev/.+|) {
1218 $path = $disk->{file};
1219 } else {
1220 $path = PVE::Storage::path ($storecfg, $disk->{file});
1221 }
1222 if (!(-f $path || -b $path)) {
1223 die "image '$path' does not exists\n";
1224 }
1225 }
1226 });
1227 };
1228
1229 my $err = $@;
1230
1231 if ($err) {
1232 syslog ('err', "VM $vmid creating disks failed");
1233 foreach my $volid (@$vollist) {
1234 eval { PVE::Storage::vdisk_free ($storecfg, $volid); };
1235 warn $@ if $@;
1236 }
1237 die $err;
1238 }
1239
1240 return $vollist;
1241}
1242
1243sub unlink_image {
1244 my ($storecfg, $vmid, $volid) = @_;
1245
1246 die "reject to unlink absolute path '$volid'"
1247 if $volid =~ m|^/|;
1248
1249 my ($path, $owner) = PVE::Storage::path ($storecfg, $volid);
1250
1251 die "reject to unlink '$volid' - not owned by this VM"
1252 if !$owner || ($owner != $vmid);
1253
1254 syslog ('info', "VM $vmid deleting volume '$volid'");
1255
1256 PVE::Storage::vdisk_free ($storecfg, $volid);
1257
1258 touch_config ($vmid);
1259}
1260
1261sub destroy_vm {
1262 my ($storecfg, $vmid) = @_;
1263
1264 my $conffile = config_file ($vmid);
1265
1266 my $conf = load_config ($vmid);
1267
1268 check_lock ($conf);
1269
1270 # only remove disks owned by this VM
1271 foreach_drive($conf, sub {
1272 my ($ds, $drive) = @_;
1273
1274 return if drive_is_cdrom ($drive);
1275
1276 my $volid = $drive->{file};
1277 next if !$volid || $volid =~ m|^/|;
1278
1279 my ($path, $owner) = PVE::Storage::path ($storecfg, $volid);
1280 next if !$path || !$owner || ($owner != $vmid);
1281
1282 PVE::Storage::vdisk_free ($storecfg, $volid);
1283 });
1284
1285 unlink $conffile;
1286
1287 # also remove unused disk
1288 eval {
1289 my $dl = PVE::Storage::vdisk_list ($storecfg, undef, $vmid);
1290
1291 eval {
1292 PVE::Storage::foreach_volid ($dl, sub {
1293 my ($volid, $sid, $volname, $d) = @_;
1294 PVE::Storage::vdisk_free ($storecfg, $volid);
1295 });
1296 };
1297 warn $@ if $@;
1298
1299 };
1300 warn $@ if $@;
1301}
1302
1303# fixme: remove?
1304sub load_diskinfo_old {
1305 my ($storecfg, $vmid, $conf) = @_;
1306
1307 my $info = {};
1308 my $res = {};
1309 my $vollist;
1310
1311 foreach_drive($conf, sub {
1312 my ($ds, $di) = @_;
1313
1314 $res->{$ds} = $di;
1315
1316 return if drive_is_cdrom ($di);
1317
1318 if ($di->{file} =~ m|^/dev/.+|) {
1319 $info->{$di->{file}}->{size} = PVE::Storage::file_size_info ($di->{file});
1320 } else {
1321 push @$vollist, $di->{file};
1322 }
1323 });
1324
1325 eval {
1326 my $dl = PVE::Storage::vdisk_list ($storecfg, undef, $vmid, $vollist);
1327
1328 PVE::Storage::foreach_volid ($dl, sub {
1329 my ($volid, $sid, $volname, $d) = @_;
1330 $info->{$volid} = $d;
1331 });
1332 };
1333 warn $@ if $@;
1334
1335 foreach my $ds (keys %$res) {
1336 my $di = $res->{$ds};
1337
1338 $res->{$ds}->{disksize} = $info->{$di->{file}} ?
1339 $info->{$di->{file}}->{size} / (1024*1024) : 0;
1340 }
1341
1342 return $res;
1343}
1344
1345sub load_config {
1346 my ($vmid) = @_;
1347
1348 my $cfspath = cfs_config_path($vmid);
1349
1350 my $conf = PVE::Cluster::cfs_read_file($cfspath);
1351
1352 die "no such VM ('$vmid')\n" if !defined($conf);
1353
1354 return $conf;
1355}
1356
1357sub parse_vm_config {
1358 my ($filename, $raw) = @_;
1359
1360 return undef if !defined($raw);
1361
554ac7e7
DM
1362 my $res = {
1363 digest => Digest::SHA1::sha1_hex($raw),
1364 };
1e3baf05
DM
1365
1366 $filename =~ m|/qemu-server/(\d+)\.conf$|
1367 || die "got strange filename '$filename'";
1368
1369 my $vmid = $1;
1370
1371 while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
1372 my $line = $1;
1373
1374 next if $line =~ m/^\#/;
1375
1376 next if $line =~ m/^\s*$/;
1377
1378 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
1379 my $key = $1;
1380 my $value = PVE::Tools::decode_text($2);
1381 $res->{$key} = $value;
1382 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
1383 my $key = $1;
1384 my $value = $2;
1385 $res->{$key} = $value;
1386 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
1387 my $key = $1;
1388 my $value = $2;
1389 eval { $value = check_type($key, $value); };
1390 if ($@) {
1391 warn "vm $vmid - unable to parse value of '$key' - $@";
1392 } else {
1393 my $fmt = $confdesc->{$key}->{format};
1394 if ($fmt && $fmt eq 'pve-qm-drive') {
1395 my $v = parse_drive($key, $value);
1396 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
1397 $v->{file} = $volid;
1398 $value = print_drive ($vmid, $v);
1399 } else {
1400 warn "vm $vmid - unable to parse value of '$key'\n";
1401 next;
1402 }
1403 }
1404
1405 if ($key eq 'cdrom') {
1406 $res->{ide2} = $value;
1407 } else {
1408 $res->{$key} = $value;
1409 }
1410 }
1411 }
1412 }
1413
1414 # convert old smp to sockets
1415 if ($res->{smp} && !$res->{sockets}) {
1416 $res->{sockets} = $res->{smp};
1417 }
1418 delete $res->{smp};
1419
1420 return $res;
1421}
1422
1423sub change_config {
1424 my ($vmid, $settings, $unset, $skiplock) = @_;
1425
1426 lock_config ($vmid, &change_config_nolock, $settings, $unset, $skiplock);
1427}
1428
1429sub change_config_nolock {
1430 my ($vmid, $settings, $unset, $skiplock) = @_;
1431
1432 my $res = {};
1433
1434 $unset->{ide2} = $unset->{cdrom} if $unset->{cdrom};
1435
1436 check_lock($settings) if !$skiplock;
1437
1438 # we do not use 'smp' any longer
1439 if ($settings->{sockets}) {
1440 $unset->{smp} = 1;
1441 } elsif ($settings->{smp}) {
1442 $settings->{sockets} = $settings->{smp};
1443 $unset->{smp} = 1;
1444 }
1445
1446 my $new_volids = {};
1447
1448 foreach my $key (keys %$settings) {
554ac7e7 1449 next if $key eq 'digest';
1e3baf05
DM
1450 my $value = $settings->{$key};
1451 if ($key eq 'description') {
1452 $value = PVE::Tools::encode_text($value);
1453 }
1454 eval { $value = check_type($key, $value); };
1455 die "unable to parse value of '$key' - $@" if $@;
1456 if ($key eq 'cdrom') {
1457 $res->{ide2} = $value;
1458 } else {
1459 $res->{$key} = $value;
1460 }
1461 if (valid_drivename($key)) {
1462 my $drive = PVE::QemuServer::parse_drive($key, $value);
1463 $new_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
1464 }
1465 }
1466
1467 my $filename = config_file($vmid);
1468 my $tmpfn = "$filename.$$.tmp";
1469
1470 my $fh = new IO::File ($filename, "r") ||
1471 die "unable to read config for VM $vmid\n";
1472
1473 my $werror = "unable to write config for VM $vmid\n";
1474
1475 my $out = new IO::File ($tmpfn, "w") || die $werror;
1476
1477 eval {
1478
1479 my $done;
1480
1481 while (my $line = <$fh>) {
1482
1483 if (($line =~ m/^\#/) || ($line =~ m/^\s*$/)) {
1484 die $werror unless print $out $line;
1485 next;
1486 }
1487
1488 if ($line =~ m/^([a-z][a-z_]*\d*):\s*(.*\S)\s*$/) {
1489 my $key = $1;
1490 my $value = $2;
1491
1492 # remove 'unusedX' settings if we re-add a volume
1493 next if $key =~ m/^unused/ && $new_volids->{$value};
1494
1495 # convert 'smp' to 'sockets'
1496 $key = 'sockets' if $key eq 'smp';
1497
1498 next if $done->{$key};
1499 $done->{$key} = 1;
1500
1501 if (defined ($res->{$key})) {
1502 $value = $res->{$key};
1503 delete $res->{$key};
1504 }
1505 if (!defined ($unset->{$key})) {
1506 die $werror unless print $out "$key: $value\n";
1507 }
1508
1509 next;
1510 }
1511
1512 die "unable to parse config file: $line\n";
1513 }
1514
1515 foreach my $key (keys %$res) {
1516
1517 if (!defined ($unset->{$key})) {
1518 die $werror unless print $out "$key: $res->{$key}\n";
1519 }
1520 }
1521 };
1522
1523 my $err = $@;
1524
1525 $fh->close();
1526
1527 if ($err) {
1528 $out->close();
1529 unlink $tmpfn;
1530 die $err;
1531 }
1532
1533 if (!$out->close()) {
1534 $err = "close failed - $!\n";
1535 unlink $tmpfn;
1536 die $err;
1537 }
1538
1539 if (!rename($tmpfn, $filename)) {
1540 $err = "rename failed - $!\n";
1541 unlink $tmpfn;
1542 die $err;
1543 }
1544}
1545
1546sub load_defaults {
1547
1548 my $res = {};
1549
1550 # we use static defaults from our JSON schema configuration
1551 foreach my $key (keys %$confdesc) {
1552 if (defined(my $default = $confdesc->{$key}->{default})) {
1553 $res->{$key} = $default;
1554 }
1555 }
1556
1557 my $conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
1558 $res->{keyboard} = $conf->{keyboard} if $conf->{keyboard};
1559
1560 return $res;
1561}
1562
1563sub config_list {
1564 my $vmlist = PVE::Cluster::get_vmlist();
1565 my $res = {};
1566 return $res if !$vmlist || !$vmlist->{ids};
1567 my $ids = $vmlist->{ids};
1568
1569 my $nodename = PVE::INotify::nodename();
1570 foreach my $vmid (keys %$ids) {
1571 my $d = $ids->{$vmid};
1572 next if !$d->{node} || $d->{node} ne $nodename;
1573 $res->{$vmid}->{exists} = 1;
1574 }
1575 return $res;
1576}
1577
1578sub check_lock {
1579 my ($conf) = @_;
1580
1581 die "VM is locked ($conf->{lock})\n" if $conf->{lock};
1582}
1583
1584sub check_cmdline {
1585 my ($pidfile, $pid) = @_;
1586
1587 my $fh = IO::File->new ("/proc/$pid/cmdline", "r");
1588 if (defined ($fh)) {
1589 my $line = <$fh>;
1590 $fh->close;
1591 return undef if !$line;
1592 my @param = split (/\0/, $line);
1593
1594 my $cmd = $param[0];
1595 return if !$cmd || ($cmd !~ m|kvm$|);
1596
1597 for (my $i = 0; $i < scalar (@param); $i++) {
1598 my $p = $param[$i];
1599 next if !$p;
1600 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
1601 my $p = $param[$i+1];
1602 return 1 if $p && ($p eq $pidfile);
1603 return undef;
1604 }
1605 }
1606 }
1607 return undef;
1608}
1609
1610sub check_running {
1611 my ($vmid) = @_;
1612
1613 my $filename = config_file ($vmid);
1614
1615 die "unable to find configuration file for VM $vmid - no such machine\n"
1616 if ! -f $filename;
1617
1618 my $pidfile = pidfile_name ($vmid);
1619
1620 if (my $fd = IO::File->new ("<$pidfile")) {
1621 my $st = stat ($fd);
1622 my $line = <$fd>;
1623 close ($fd);
1624
1625 my $mtime = $st->mtime;
1626 if ($mtime > time()) {
1627 warn "file '$filename' modified in future\n";
1628 }
1629
1630 if ($line =~ m/^(\d+)$/) {
1631 my $pid = $1;
1632
1633 return $pid if ((-d "/proc/$pid") && check_cmdline ($pidfile, $pid));
1634 }
1635 }
1636
1637 return undef;
1638}
1639
1640sub vzlist {
1641
1642 my $vzlist = config_list();
1643
1644 my $fd = IO::Dir->new ($var_run_tmpdir) || return $vzlist;
1645
1646 while (defined(my $de = $fd->read)) {
1647 next if $de !~ m/^(\d+)\.pid$/;
1648 my $vmid = $1;
1649 next if !defined ($vzlist->{$vmid});
1650 if (my $pid = check_running ($vmid)) {
1651 $vzlist->{$vmid}->{pid} = $pid;
1652 }
1653 }
1654
1655 return $vzlist;
1656}
1657
1658my $storage_timeout_hash = {};
1659
1660sub disksize {
1661 my ($storecfg, $conf) = @_;
1662
1663 my $bootdisk = $conf->{bootdisk};
1664 return undef if !$bootdisk;
1665 return undef if !valid_drivename($bootdisk);
1666
1667 return undef if !$conf->{$bootdisk};
1668
1669 my $drive = parse_drive($bootdisk, $conf->{$bootdisk});
1670 return undef if !defined($drive);
1671
1672 return undef if drive_is_cdrom($drive);
1673
1674 my $volid = $drive->{file};
1675 return undef if !$volid;
1676
1677 my $path;
1678 my $storeid;
1679 my $timeoutid;
1680
1681 if ($volid =~ m|^/|) {
1682 $path = $timeoutid = $volid;
1683 } else {
1684 $storeid = $timeoutid = PVE::Storage::parse_volume_id ($volid);
1685 $path = PVE::Storage::path($storecfg, $volid);
1686 }
1687
1688 my $last_timeout = $storage_timeout_hash->{$timeoutid};
1689 if ($last_timeout) {
1690 if ((time() - $last_timeout) < 30) {
1691 # skip storage with errors
1692 return undef ;
1693 }
1694 delete $storage_timeout_hash->{$timeoutid};
1695 }
1696
1697 my ($size, $format, $used);
1698
1699 ($size, $format, $used) = PVE::Storage::file_size_info($path, 1);
1700
1701 if (!defined($format)) {
1702 # got timeout
1703 $storage_timeout_hash->{$timeoutid} = time();
1704 return undef;
1705 }
1706
1707 return wantarray ? ($size, $used) : $size;
1708}
1709
1710my $last_proc_pid_stat;
1711
1712sub vmstatus {
1713 my ($opt_vmid) = @_;
1714
1715 my $res = {};
1716
1717 my $storecfg = PVE::Storage::config();
1718
1719 my $list = vzlist();
1720 my ($uptime) = PVE::ProcFSTools::read_proc_uptime();
1721
1722 foreach my $vmid (keys %$list) {
1723 next if $opt_vmid && ($vmid ne $opt_vmid);
1724
1725 my $cfspath = cfs_config_path($vmid);
1726 my $conf = PVE::Cluster::cfs_read_file($cfspath) || {};
1727
1728 my $d = {};
1729 $d->{pid} = $list->{$vmid}->{pid};
1730
1731 # fixme: better status?
1732 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
1733
1734 my ($size, $used) = disksize($storecfg, $conf);
1735 if (defined($size) && defined($used)) {
1736 $d->{disk} = $used;
1737 $d->{maxdisk} = $size;
1738 } else {
1739 $d->{disk} = 0;
1740 $d->{maxdisk} = 0;
1741 }
1742
1743 $d->{cpus} = ($conf->{sockets} || 1) * ($conf->{cores} || 1);
1744 $d->{name} = $conf->{name} || "VM $vmid";
1745 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024) : 0;
1746
1747
1748 $d->{uptime} = 0;
1749 $d->{cpu} = 0;
1750 $d->{relcpu} = 0;
1751 $d->{mem} = 0;
1752
1753 $d->{netout} = 0;
1754 $d->{netin} = 0;
1755
1756 $d->{diskread} = 0;
1757 $d->{diskwrite} = 0;
1758
1759 $res->{$vmid} = $d;
1760 }
1761
1762 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
1763 foreach my $dev (keys %$netdev) {
1764 next if $dev !~ m/^tap([1-9]\d*)i/;
1765 my $vmid = $1;
1766 my $d = $res->{$vmid};
1767 next if !$d;
1768
1769 $d->{netout} += $netdev->{$dev}->{receive};
1770 $d->{netin} += $netdev->{$dev}->{transmit};
1771 }
1772
1773 my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
1774 my $cpucount = $cpuinfo->{cpus} || 1;
1775 my $ctime = gettimeofday;
1776
1777 foreach my $vmid (keys %$list) {
1778
1779 my $d = $res->{$vmid};
1780 my $pid = $d->{pid};
1781 next if !$pid;
1782
1783 if (my $fh = IO::File->new("/proc/$pid/io", "r")) {
1784 my $data = {};
1785 while (defined (my $line = <$fh>)) {
1786 if ($line =~ m/^([rw]char):\s+(\d+)$/) {
1787 $data->{$1} = $2;
1788 }
1789 }
1790 close($fh);
1791 $d->{diskread} = $data->{rchar} || 0;
1792 $d->{diskwrite} = $data->{wchar} || 0;
1793 }
1794
1795 my $statstr = file_read_firstline("/proc/$pid/stat");
1796 next if !$statstr;
1797
1798 my ($utime, $stime, $vsize, $rss, $starttime);
1799 if ($statstr =~ m/^$pid \(.*\) \S (-?\d+) -?\d+ -?\d+ -?\d+ -?\d+ \d+ \d+ \d+ \d+ \d+ (\d+) (\d+) (-?\d+) (-?\d+) -?\d+ -?\d+ -?\d+ 0 (\d+) (\d+) (-?\d+) \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ \d+ -?\d+ -?\d+ \d+ \d+ \d+/) {
1800 ($utime, $stime, $vsize, $rss, $starttime) = ($2, $3, $7, $8 * 4096, $6);
1801 } else {
1802 next;
1803 }
1804
1805 my $used = $utime + $stime;
1806
1807 my $vcpus = $d->{cpus} > $cpucount ? $cpucount : $d->{cpus};
1808
1809 $d->{uptime} = int ($uptime - ($starttime/100));
1810
1811 if ($vsize) {
1812 $d->{mem} = int (($rss/$vsize)*$d->{maxmem});
1813 }
1814
1815 my $old = $last_proc_pid_stat->{$pid};
1816 if (!$old) {
1817 $last_proc_pid_stat->{$pid} = {
1818 time => $ctime,
1819 used => $used,
1820 cpu => 0,
1821 relcpu => 0,
1822 };
1823 next;
1824 }
1825
1826 my $dtime = ($ctime - $old->{time}) * $cpucount * $clock_ticks;
1827
1828 if ($dtime > 1000) {
1829 my $dutime = $used - $old->{used};
1830
1831 $d->{cpu} = $dutime/$dtime;
1832 $d->{relcpu} = ($d->{cpu} * $cpucount) / $vcpus;
1833 $last_proc_pid_stat->{$pid} = {
1834 time => $ctime,
1835 used => $used,
1836 cpu => $d->{cpu},
1837 relcpu => $d->{relcpu},
1838 };
1839 } else {
1840 $d->{cpu} = $old->{cpu};
1841 $d->{relcpu} = $old->{relcpu};
1842 }
1843 }
1844
1845 return $res;
1846}
1847
1848sub foreach_drive {
1849 my ($conf, $func) = @_;
1850
1851 foreach my $ds (keys %$conf) {
1852 next if !valid_drivename($ds);
1853
1854 my $drive = parse_drive ($ds, $conf->{$ds});
1855 next if !$drive;
1856
1857 &$func($ds, $drive);
1858 }
1859}
1860
1861sub config_to_command {
1862 my ($storecfg, $vmid, $conf, $defaults, $migrate_uri) = @_;
1863
1864 my $cmd = [];
1865
1866 my $kvmver = kvm_user_version();
1867 my $vernum = 0; # unknown
1868 if ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
1869 $vernum = $1*1000000+$2*1000+$3;
1870 }
1871
1872 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 14000;
1873
1874 my $have_ovz = -f '/proc/vz/vestat';
1875
1876 push @$cmd, '/usr/bin/kvm';
1877
1878 push @$cmd, '-id', $vmid;
1879
1880 my $use_virtio = 0;
1881
1882 my $socket = monitor_socket ($vmid);
1883 push @$cmd, '-monitor', "unix:$socket,server,nowait";
1884
1885 $socket = vnc_socket ($vmid);
1886 push @$cmd, '-vnc', "unix:$socket,x509,password";
1887
1888 push @$cmd, '-pidfile' , pidfile_name ($vmid);
1889
1890 push @$cmd, '-daemonize';
1891
1892 push @$cmd, '-incoming', $migrate_uri if $migrate_uri;
1893
1894 # include usb device config
1895 push @$cmd, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg';
1896
1897 # enable absolute mouse coordinates (needed by vnc)
1898 my $tablet = defined ($conf->{tablet}) ? $conf->{tablet} : $defaults->{tablet};
1899 push @$cmd, '-device', 'usb-tablet,bus=ehci.0,port=6' if $tablet;
1900
1901 # host pci devices
1902 if (my $pcidl = $conf->{hostpci}) {
1903 my @dl = split (/,/, $pcidl);
1904 foreach my $dev (@dl) {
1905 push @$cmd, '-device', "pci-assign,host=$dev" if $dev;
1906 }
1907 }
1908
1909 # usb devices
1910 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1911 my $d = parse_usb_device($conf->{"usb$i"});
1912 next if !$d;
1913 if ($d->{vendorid} && $d->{productid}) {
1914 push @$cmd, '-device', "usb-host,vendorid=$d->{vendorid},productid=$d->{productid}";
1915 } elsif (defined($d->{hostbus}) && defined($d->{hostport})) {
1916 push @$cmd, '-device', "usb-host,hostbus=$d->{hostbus},hostport=$d->{hostport}";
1917 }
1918 }
1919
1920 if (my $usbdl = $conf->{hostusb}) {
1921 my @dl = split (/,/, $usbdl);
1922 foreach my $dev (@dl) {
1923 push @$cmd, '-usbdevice', "host:$dev" if $dev;
1924 }
1925 }
1926
1927 # serial devices
1928 if (my $serdl = $conf->{serial}) {
1929 my @dl = split (/,/, $serdl);
1930 foreach my $dev (@dl) {
1931 next if !$dev;
1932 if (-c $dev) {
1933 push @$cmd, '-serial', "$dev";
1934 }
1935 }
1936 }
1937
1938 # parallel devices
1939 if (my $pardl = $conf->{parallel}) {
1940 my @dl = split (/,/, $pardl);
1941 foreach my $dev (@dl) {
1942 next if !$dev;
1943 if (-c $dev) {
1944 push @$cmd, '-parallel', "$dev";
1945 }
1946 }
1947 }
1948
1949 my $vmname = $conf->{name} || "vm$vmid";
1950
1951 push @$cmd, '-name', $vmname;
1952
1953 my $sockets = 1;
1954 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
1955 $sockets = $conf->{sockets} if $conf->{sockets};
1956
1957 my $cores = $conf->{cores} || 1;
1958
1959 my $boot_opt;
1960
1961 push @$cmd, '-smp', "sockets=$sockets,cores=$cores";
1962
1963 push @$cmd, '-cpu', $conf->{cpu} if $conf->{cpu};
1964
1965 $boot_opt = "menu=on";
1966 if ($conf->{boot}) {
1967 $boot_opt .= ",order=$conf->{boot}";
1968 }
1969
1970 push @$cmd, '-nodefaults';
1971
1972 push @$cmd, '-boot', $boot_opt if $boot_opt;
1973
1974 push @$cmd, '-no-acpi' if defined ($conf->{acpi}) && $conf->{acpi} == 0;
1975
1976 push @$cmd, '-no-reboot' if defined ($conf->{reboot}) && $conf->{reboot} == 0;
1977
1978 my $vga = $conf->{vga};
1979 if (!$vga) {
1980 if ($conf->{ostype} && ($conf->{ostype} eq 'win7' || $conf->{ostype} eq 'w2k8')) {
1981 $vga = 'std';
1982 } else {
1983 $vga = 'cirrus';
1984 }
1985 }
1986
1987 push @$cmd, '-vga', $vga if $vga; # for kvm 77 and later
1988
1989 # time drift fix
1990 my $tdf = defined ($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
1991 push @$cmd, '-tdf' if $tdf;
1992
1993 my $nokvm = defined ($conf->{kvm}) && $conf->{kvm} == 0 ? 1 : 0;
1994
1995 if (my $ost = $conf->{ostype}) {
1996 # other, wxp, w2k, w2k3, w2k8, wvista, win7, l24, l26
1997
1998 if ($ost =~ m/^w/) { # windows
1999 push @$cmd, '-localtime' if !defined ($conf->{localtime});
2000
2001 # use rtc-td-hack when acpi is enabled
2002 if (!(defined ($conf->{acpi}) && $conf->{acpi} == 0)) {
2003 push @$cmd, '-rtc-td-hack';
2004 }
2005 }
2006
2007 # -tdf ?
2008 # -no-acpi
2009 # -no-kvm
2010 # -win2k-hack ?
2011 }
2012
2013 push @$cmd, '-no-kvm' if $nokvm;
2014
2015 push @$cmd, '-localtime' if $conf->{localtime};
2016
2017 push @$cmd, '-startdate', $conf->{startdate} if $conf->{startdate};
2018
2019 push @$cmd, '-S' if $conf->{freeze};
2020
2021 # set keyboard layout
2022 my $kb = $conf->{keyboard} || $defaults->{keyboard};
2023 push @$cmd, '-k', $kb if $kb;
2024
2025 # enable sound
2026 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
2027 #push @$cmd, '-soundhw', 'es1370';
2028 #push @$cmd, '-soundhw', $soundhw if $soundhw;
2029
2030 my $vollist = [];
2031
2032 foreach_drive($conf, sub {
2033 my ($ds, $drive) = @_;
2034
2035 eval {
2036 PVE::Storage::parse_volume_id ($drive->{file});
2037 push @$vollist, $drive->{file};
2038 }; # ignore errors
2039
2040 $use_virtio = 1 if $ds =~ m/^virtio/;
2041 my $tmp = print_drive_full ($storecfg, $vmid, $drive);
2042 $tmp .= ",boot=on" if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
2043 push @$cmd, '-drive', $tmp;
ca916ecc 2044 push @$cmd, '-device',print_drivedevice_full ($storecfg,$vmid, $drive);
1e3baf05
DM
2045 });
2046
2047 push @$cmd, '-m', $conf->{memory} || $defaults->{memory};
2048
2049 my $foundnet = 0;
2050
2051 foreach my $k (sort keys %$conf) {
2052 next if $k !~ m/^net(\d+)$/;
2053 my $i = int ($1);
2054
2055 die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
2056
2057 if ($conf->{"net$i"} && (my $net = parse_net($conf->{"net$i"}))) {
2058
2059 $foundnet = 1;
2060
2061 my $ifname = "tap${vmid}i$i";
2062
2063 # kvm uses TUNSETIFF ioctl, and that limits ifname length
2064 die "interface name '$ifname' is too long (max 15 character)\n"
2065 if length($ifname) >= 16;
2066
2067 my $device = $net->{model};
2068 my $vhostparam = '';
2069 if ($net->{model} eq 'virtio') {
2070 $use_virtio = 1;
2071 $device = 'virtio-net-pci';
2072 $vhostparam = ',vhost=on' if $kernel_has_vhost_net;
2073 };
2074
2075 if ($net->{bridge}) {
2076 push @$cmd, '-netdev', "type=tap,id=${k},ifname=${ifname},script=/var/lib/qemu-server/pve-bridge$vhostparam";
2077 } else {
2078 push @$cmd, '-netdev', "type=user,id=${k},hostname=$vmname";
2079 }
2080
2081 # qemu > 0.15 always try to boot from network - we disable that by
2082 # not loading the pxe rom file
2083 my $extra = (!$conf->{boot} || ($conf->{boot} !~ m/n/)) ?
2084 "romfile=," : '';
2085 push @$cmd, '-device', "$device,${extra}mac=$net->{macaddr},netdev=${k}";
2086 }
2087 }
2088
2089 push @$cmd, '-net', 'none' if !$foundnet;
2090
2091 # hack: virtio with fairsched is unreliable, so we do not use fairsched
2092 # when the VM uses virtio devices.
2093 if (!$use_virtio && $have_ovz) {
2094
2095 my $cpuunits = defined ($conf->{cpuunits}) ?
2096 $conf->{cpuunits} : $defaults->{cpuunits};
2097
2098 push @$cmd, '-cpuunits', $cpuunits if $cpuunits;
2099
2100 # fixme: cpulimit is currently ignored
2101 #push @$cmd, '-cpulimit', $conf->{cpulimit} if $conf->{cpulimit};
2102 }
2103
2104 # add custom args
2105 if ($conf->{args}) {
2106 my $aa = split_args ($conf->{args});
2107 push @$cmd, @$aa;
2108 }
2109
2110 return wantarray ? ($cmd, $vollist) : $cmd;
2111}
2112
2113sub vnc_socket {
2114 my ($vmid) = @_;
2115 return "${var_run_tmpdir}/$vmid.vnc";
2116}
2117
2118sub monitor_socket {
2119 my ($vmid) = @_;
2120 return "${var_run_tmpdir}/$vmid.mon";
2121}
2122
2123sub pidfile_name {
2124 my ($vmid) = @_;
2125 return "${var_run_tmpdir}/$vmid.pid";
2126}
2127
2128sub random_ether_addr {
2129
2130 my $rand = Digest::SHA1::sha1_hex (rand(), time());
2131
2132 my $mac = '';
2133 for (my $i = 0; $i < 6; $i++) {
2134 my $ss = hex (substr ($rand, $i*2, 2));
2135 if (!$i) {
2136 $ss &= 0xfe; # clear multicast
2137 $ss |= 2; # set local id
2138 }
2139 $ss = sprintf ("%02X", $ss);
2140
2141 if (!$i) {
2142 $mac .= "$ss";
2143 } else {
2144 $mac .= ":$ss";
2145 }
2146 }
2147
2148 return $mac;
2149}
2150
2151sub next_migrate_port {
2152
2153 for (my $p = 60000; $p < 60010; $p++) {
2154
2155 my $sock = IO::Socket::INET->new (Listen => 5,
2156 LocalAddr => 'localhost',
2157 LocalPort => $p,
2158 ReuseAddr => 1,
2159 Proto => 0);
2160
2161 if ($sock) {
2162 close ($sock);
2163 return $p;
2164 }
2165 }
2166
2167 die "unable to find free migration port";
2168}
2169
2170sub vm_start {
2171 my ($storecfg, $vmid, $statefile, $skiplock) = @_;
2172
2173 lock_config ($vmid, sub {
2174 my $conf = load_config ($vmid);
2175
2176 check_lock ($conf) if !$skiplock;
2177
2178 if (check_running ($vmid)) {
2179 my $msg = "VM $vmid already running - start failed\n" ;
2180 syslog ('err', $msg);
2181 die $msg;
2182 } else {
2183 syslog ('info', "VM $vmid start");
2184 }
2185
2186 my $migrate_uri;
2187 my $migrate_port = 0;
2188
2189 if ($statefile) {
2190 if ($statefile eq 'tcp') {
2191 $migrate_port = next_migrate_port();
2192 $migrate_uri = "tcp:localhost:${migrate_port}";
2193 } else {
2194 if (-f $statefile) {
2195 $migrate_uri = "exec:cat $statefile";
2196 } else {
2197 warn "state file '$statefile' does not exist - doing normal startup\n";
2198 }
2199 }
2200 }
2201
2202 my $defaults = load_defaults();
2203
2204 my ($cmd, $vollist) = config_to_command ($storecfg, $vmid, $conf, $defaults, $migrate_uri);
2205 # host pci devices
2206 if (my $pcidl = $conf->{hostpci}) {
2207 my @dl = split (/,/, $pcidl);
2208 foreach my $dev (@dl) {
2209 $dev = lc($dev);
2210 my $info = pci_device_info("0000:$dev");
2211 die "no pci device info for device '$dev'\n" if !$info;
2212 die "can't unbind pci device '$dev'\n" if !pci_dev_bind_to_stub($info);
2213 die "can't reset pci device '$dev'\n" if !pci_dev_reset($info);
2214 }
2215 }
2216
2217 PVE::Storage::activate_volumes($storecfg, $vollist);
2218
2219 eval { run_command ($cmd, timeout => $migrate_uri ? undef : 30); };
2220
2221 my $err = $@;
2222
2223 if ($err) {
2224 my $msg = "start failed: $err";
2225 syslog ('err', "VM $vmid $msg");
2226 die $msg;
2227 }
2228
2229 if ($statefile) {
2230
2231 if ($statefile eq 'tcp') {
2232 print "migration listens on port $migrate_port\n";
2233 } else {
2234 unlink $statefile;
2235 # fixme: send resume - is that necessary ?
2236 eval { vm_monitor_command ($vmid, "cont", 1) };
2237 }
2238 }
2239
2240 if (my $migrate_speed =
2241 $conf->{migrate_speed} || $defaults->{migrate_speed}) {
2242 my $cmd = "migrate_set_speed ${migrate_speed}m";
2243 eval { vm_monitor_command ($vmid, $cmd, 1); };
2244 }
2245
2246 if (my $migrate_downtime =
2247 $conf->{migrate_downtime} || $defaults->{migrate_downtime}) {
2248 my $cmd = "migrate_set_downtime ${migrate_downtime}";
2249 eval { vm_monitor_command ($vmid, $cmd, 1); };
2250 }
2251 });
2252}
2253
2254sub __read_avail {
2255 my ($fh, $timeout) = @_;
2256
2257 my $sel = new IO::Select;
2258 $sel->add ($fh);
2259
2260 my $res = '';
2261 my $buf;
2262
2263 my @ready;
2264 while (scalar (@ready = $sel->can_read ($timeout))) {
2265 my $count;
2266 if ($count = $fh->sysread ($buf, 8192)) {
2267 if ($buf =~ /^(.*)\(qemu\) $/s) {
2268 $res .= $1;
2269 last;
2270 } else {
2271 $res .= $buf;
2272 }
2273 } else {
2274 if (!defined ($count)) {
2275 die "$!\n";
2276 }
2277 last;
2278 }
2279 }
2280
2281 die "monitor read timeout\n" if !scalar (@ready);
2282
2283 return $res;
2284}
2285
2286sub vm_monitor_command {
2287 my ($vmid, $cmdstr, $nolog) = @_;
2288
2289 my $res;
2290
2291 syslog ("info", "VM $vmid monitor command '$cmdstr'") if !$nolog;
2292
2293 eval {
2294 die "VM not running\n" if !check_running ($vmid);
2295
2296 my $sname = monitor_socket ($vmid);
2297
2298 my $sock = IO::Socket::UNIX->new ( Peer => $sname ) ||
2299 die "unable to connect to VM $vmid socket - $!\n";
2300
2301 my $timeout = 3;
2302
2303 # hack: migrate sometime blocks the monitor (when migrate_downtime
2304 # is set)
2305 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
2306 $timeout = 60*60; # 1 hour
2307 }
2308
2309 # read banner;
2310 my $data = __read_avail ($sock, $timeout);
2311
2312 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
2313 die "got unexpected qemu monitor banner\n";
2314 }
2315
2316 my $sel = new IO::Select;
2317 $sel->add ($sock);
2318
2319 if (!scalar (my @ready = $sel->can_write ($timeout))) {
2320 die "monitor write error - timeout";
2321 }
2322
2323 my $fullcmd = "$cmdstr\r";
2324
2325 my $b;
2326 if (!($b = $sock->syswrite ($fullcmd)) || ($b != length ($fullcmd))) {
2327 die "monitor write error - $!";
2328 }
2329
2330 return if ($cmdstr eq 'q') || ($cmdstr eq 'quit');
2331
2332 $timeout = 20;
2333
2334 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
2335 $timeout = 60*60; # 1 hour
2336 } elsif ($cmdstr =~ m/^(eject|change)/) {
2337 $timeout = 60; # note: cdrom mount command is slow
2338 }
2339 if ($res = __read_avail ($sock, $timeout)) {
2340
2341 my @lines = split ("\r?\n", $res);
2342
2343 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
2344
2345 $res = join ("\n", @lines);
2346 $res .= "\n";
2347 }
2348 };
2349
2350 my $err = $@;
2351
2352 if ($err) {
2353 syslog ("err", "VM $vmid monitor command failed - $err");
2354 die $err;
2355 }
2356
2357 return $res;
2358}
2359
2360sub vm_commandline {
2361 my ($storecfg, $vmid) = @_;
2362
2363 my $conf = load_config ($vmid);
2364
2365 my $defaults = load_defaults();
2366
2367 my $cmd = config_to_command ($storecfg, $vmid, $conf, $defaults);
2368
2369 return join (' ', @$cmd);
2370}
2371
2372sub vm_reset {
2373 my ($vmid, $skiplock) = @_;
2374
2375 lock_config ($vmid, sub {
2376
2377 my $conf = load_config ($vmid);
2378
2379 check_lock ($conf) if !$skiplock;
2380
2381 syslog ("info", "VM $vmid sending 'reset'");
2382
2383 vm_monitor_command ($vmid, "system_reset", 1);
2384 });
2385}
2386
2387sub vm_shutdown {
2388 my ($vmid, $skiplock) = @_;
2389
2390 lock_config ($vmid, sub {
2391
2392 my $conf = load_config ($vmid);
2393
2394 check_lock ($conf) if !$skiplock;
2395
2396 syslog ("info", "VM $vmid sending 'shutdown'");
2397
2398 vm_monitor_command ($vmid, "system_powerdown", 1);
2399 });
2400}
2401
2402sub vm_stop {
2403 my ($vmid, $skiplock) = @_;
2404
2405 lock_config ($vmid, sub {
2406
2407 my $pid = check_running ($vmid);
2408
2409 if (!$pid) {
2410 syslog ('info', "VM $vmid already stopped");
2411 return;
2412 }
2413
2414 my $conf = load_config ($vmid);
2415
2416 check_lock ($conf) if !$skiplock;
2417
2418 syslog ("info", "VM $vmid stopping");
2419
2420 eval { vm_monitor_command ($vmid, "quit", 1); };
2421
2422 my $err = $@;
2423
2424 if (!$err) {
2425 # wait some time
2426 my $timeout = 50; # fixme: how long?
2427
2428 my $count = 0;
2429 while (($count < $timeout) && check_running ($vmid)) {
2430 $count++;
2431 sleep 1;
2432 }
2433
2434 if ($count >= $timeout) {
2435 syslog ('info', "VM $vmid still running - terminating now with SIGTERM");
2436 kill 15, $pid;
2437 }
2438 } else {
2439 syslog ('info', "VM $vmid quit failed - terminating now with SIGTERM");
2440 kill 15, $pid;
2441 }
2442
2443 # wait again
2444 my $timeout = 10;
2445
2446 my $count = 0;
2447 while (($count < $timeout) && check_running ($vmid)) {
2448 $count++;
2449 sleep 1;
2450 }
2451
2452 if ($count >= $timeout) {
2453 syslog ('info', "VM $vmid still running - terminating now with SIGKILL\n");
2454 kill 9, $pid;
2455 }
2456
2457 fairsched_rmnod ($vmid); # try to destroy group
2458 });
2459}
2460
2461sub vm_suspend {
2462 my ($vmid, $skiplock) = @_;
2463
2464 lock_config ($vmid, sub {
2465
2466 my $conf = load_config ($vmid);
2467
2468 check_lock ($conf) if !$skiplock;
2469
2470 syslog ("info", "VM $vmid suspend");
2471
2472 vm_monitor_command ($vmid, "stop", 1);
2473 });
2474}
2475
2476sub vm_resume {
2477 my ($vmid, $skiplock) = @_;
2478
2479 lock_config ($vmid, sub {
2480
2481 my $conf = load_config ($vmid);
2482
2483 check_lock ($conf) if !$skiplock;
2484
2485 syslog ("info", "VM $vmid resume");
2486
2487 vm_monitor_command ($vmid, "cont", 1);
2488 });
2489}
2490
2491sub vm_cad {
2492 my ($vmid, $skiplock) = @_;
2493
2494 lock_config ($vmid, sub {
2495
2496 my $conf = load_config ($vmid);
2497
2498 check_lock ($conf) if !$skiplock;
2499
2500 syslog ("info", "VM $vmid sending cntl-alt-delete");
2501
2502 vm_monitor_command ($vmid, "sendkey ctrl-alt-delete", 1);
2503 });
2504}
2505
2506sub vm_destroy {
2507 my ($storecfg, $vmid, $skiplock) = @_;
2508
2509 lock_config ($vmid, sub {
2510
2511 my $conf = load_config ($vmid);
2512
2513 check_lock ($conf) if !$skiplock;
2514
2515 syslog ("info", "VM $vmid destroy called (removing all data)");
2516
2517 eval {
2518 if (!check_running($vmid)) {
2519 fairsched_rmnod($vmid); # try to destroy group
2520 destroy_vm($storecfg, $vmid);
2521 } else {
2522 die "VM is running\n";
2523 }
2524 };
2525
2526 my $err = $@;
2527
2528 if ($err) {
2529 syslog ("err", "VM $vmid destroy failed - $err");
2530 die $err;
2531 }
2532 });
2533}
2534
2535sub vm_stopall {
2536 my ($timeout) = @_;
2537
2538 $timeout = 3*60 if !$timeout;
2539
2540 my $vzlist = vzlist();
2541 my $count = 0;
2542 foreach my $vmid (keys %$vzlist) {
2543 next if !$vzlist->{$vmid}->{pid};
2544 $count++;
2545 }
2546
2547 if ($count) {
2548
2549 my $msg = "Stopping Qemu Server - sending shutdown requests to all VMs\n";
2550 syslog ('info', $msg);
2551 print STDERR $msg;
2552
2553 foreach my $vmid (keys %$vzlist) {
2554 next if !$vzlist->{$vmid}->{pid};
2555 eval { vm_shutdown ($vmid, 1); };
2556 print STDERR $@ if $@;
2557 }
2558
2559 my $wt = 5;
2560 my $maxtries = int (($timeout + $wt -1)/$wt);
2561 my $try = 0;
2562 while (($try < $maxtries) && $count) {
2563 $try++;
2564 sleep $wt;
2565
2566 $vzlist = vzlist();
2567 $count = 0;
2568 foreach my $vmid (keys %$vzlist) {
2569 next if !$vzlist->{$vmid}->{pid};
2570 $count++;
2571 }
2572 last if !$count;
2573 }
2574
2575 return if !$count;
2576
2577 foreach my $vmid (keys %$vzlist) {
2578 next if !$vzlist->{$vmid}->{pid};
2579
2580 $msg = "VM $vmid still running - sending stop now\n";
2581 syslog ('info', $msg);
2582 print $msg;
2583
2584 eval { vm_monitor_command ($vmid, "quit", 1); };
2585 print STDERR $@ if $@;
2586
2587 }
2588
2589 $timeout = 30;
2590 $maxtries = int (($timeout + $wt -1)/$wt);
2591 $try = 0;
2592 while (($try < $maxtries) && $count) {
2593 $try++;
2594 sleep $wt;
2595
2596 $vzlist = vzlist();
2597 $count = 0;
2598 foreach my $vmid (keys %$vzlist) {
2599 next if !$vzlist->{$vmid}->{pid};
2600 $count++;
2601 }
2602 last if !$count;
2603 }
2604
2605 return if !$count;
2606
2607 foreach my $vmid (keys %$vzlist) {
2608 next if !$vzlist->{$vmid}->{pid};
2609
2610 $msg = "VM $vmid still running - terminating now with SIGTERM\n";
2611 syslog ('info', $msg);
2612 print $msg;
2613 kill 15, $vzlist->{$vmid}->{pid};
2614 }
2615
2616 # this is called by system shotdown scripts, so remaining
2617 # processes gets killed anyways (no need to send kill -9 here)
2618
2619 $msg = "Qemu Server stopped\n";
2620 syslog ('info', $msg);
2621 print STDERR $msg;
2622 }
2623}
2624
2625# pci helpers
2626
2627sub file_write {
2628 my ($filename, $buf) = @_;
2629
2630 my $fh = IO::File->new ($filename, "w");
2631 return undef if !$fh;
2632
2633 my $res = print $fh $buf;
2634
2635 $fh->close();
2636
2637 return $res;
2638}
2639
2640sub pci_device_info {
2641 my ($name) = @_;
2642
2643 my $res;
2644
2645 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
2646 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
2647
2648 my $irq = file_read_firstline("$pcisysfs/devices/$name/irq");
2649 return undef if !defined($irq) || $irq !~ m/^\d+$/;
2650
2651 my $vendor = file_read_firstline("$pcisysfs/devices/$name/vendor");
2652 return undef if !defined($vendor) || $vendor !~ s/^0x//;
2653
2654 my $product = file_read_firstline("$pcisysfs/devices/$name/device");
2655 return undef if !defined($product) || $product !~ s/^0x//;
2656
2657 $res = {
2658 name => $name,
2659 vendor => $vendor,
2660 product => $product,
2661 domain => $domain,
2662 bus => $bus,
2663 slot => $slot,
2664 func => $func,
2665 irq => $irq,
2666 has_fl_reset => -f "$pcisysfs/devices/$name/reset" || 0,
2667 };
2668
2669 return $res;
2670}
2671
2672sub pci_dev_reset {
2673 my ($dev) = @_;
2674
2675 my $name = $dev->{name};
2676
2677 my $fn = "$pcisysfs/devices/$name/reset";
2678
2679 return file_write ($fn, "1");
2680}
2681
2682sub pci_dev_bind_to_stub {
2683 my ($dev) = @_;
2684
2685 my $name = $dev->{name};
2686
2687 my $testdir = "$pcisysfs/drivers/pci-stub/$name";
2688 return 1 if -d $testdir;
2689
2690 my $data = "$dev->{vendor} $dev->{product}";
2691 return undef if !file_write ("$pcisysfs/drivers/pci-stub/new_id", $data);
2692
2693 my $fn = "$pcisysfs/devices/$name/driver/unbind";
2694 if (!file_write ($fn, $name)) {
2695 return undef if -f $fn;
2696 }
2697
2698 $fn = "$pcisysfs/drivers/pci-stub/bind";
2699 if (! -d $testdir) {
2700 return undef if !file_write ($fn, $name);
2701 }
2702
2703 return -d $testdir;
2704}
2705
27061;