1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """KVM hypervisor
23
24 """
25
26 import errno
27 import os
28 import os.path
29 import re
30 import tempfile
31 import time
32 import logging
33 import pwd
34 import struct
35 import fcntl
36 import shutil
37 import socket
38 import stat
39 import StringIO
40 try:
41 import affinity
42 except ImportError:
43 affinity = None
44
45 from ganeti import utils
46 from ganeti import constants
47 from ganeti import errors
48 from ganeti import serializer
49 from ganeti import objects
50 from ganeti import uidpool
51 from ganeti import ssconf
52 from ganeti import netutils
53 from ganeti import pathutils
54 from ganeti.hypervisor import hv_base
55 from ganeti.utils import wrapper as utils_wrapper
56
57
58 _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge"
59 _KVM_START_PAUSED_FLAG = "-S"
60
61
62
63
64 TUNSETIFF = 0x400454ca
65 TUNGETIFF = 0x800454d2
66 TUNGETFEATURES = 0x800454cf
67 IFF_TAP = 0x0002
68 IFF_NO_PI = 0x1000
69 IFF_VNET_HDR = 0x4000
70
71
72 _SPICE_ADDITIONAL_PARAMS = frozenset([
73 constants.HV_KVM_SPICE_IP_VERSION,
74 constants.HV_KVM_SPICE_PASSWORD_FILE,
75 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR,
76 constants.HV_KVM_SPICE_JPEG_IMG_COMPR,
77 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR,
78 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION,
79 constants.HV_KVM_SPICE_USE_TLS,
80 ])
84 """Retrieves supported TUN features from file descriptor.
85
86 @see: L{_ProbeTapVnetHdr}
87
88 """
89 req = struct.pack("I", 0)
90 try:
91 buf = _ioctl(fd, TUNGETFEATURES, req)
92 except EnvironmentError, err:
93 logging.warning("ioctl(TUNGETFEATURES) failed: %s", err)
94 return None
95 else:
96 (flags, ) = struct.unpack("I", buf)
97 return flags
98
101 """Check whether to enable the IFF_VNET_HDR flag.
102
103 To do this, _all_ of the following conditions must be met:
104 1. TUNGETFEATURES ioctl() *must* be implemented
105 2. TUNGETFEATURES ioctl() result *must* contain the IFF_VNET_HDR flag
106 3. TUNGETIFF ioctl() *must* be implemented; reading the kernel code in
107 drivers/net/tun.c there is no way to test this until after the tap device
108 has been created using TUNSETIFF, and there is no way to change the
109 IFF_VNET_HDR flag after creating the interface, catch-22! However both
110 TUNGETIFF and TUNGETFEATURES were introduced in kernel version 2.6.27,
111 thus we can expect TUNGETIFF to be present if TUNGETFEATURES is.
112
113 @type fd: int
114 @param fd: the file descriptor of /dev/net/tun
115
116 """
117 flags = _features_fn(fd)
118
119 if flags is None:
120
121 return False
122
123 result = bool(flags & IFF_VNET_HDR)
124
125 if not result:
126 logging.warning("Kernel does not support IFF_VNET_HDR, not enabling")
127
128 return result
129
132 """Open a new tap device and return its file descriptor.
133
134 This is intended to be used by a qemu-type hypervisor together with the -net
135 tap,fd=<fd> command line parameter.
136
137 @type vnet_hdr: boolean
138 @param vnet_hdr: Enable the VNET Header
139 @return: (ifname, tapfd)
140 @rtype: tuple
141
142 """
143 try:
144 tapfd = os.open("/dev/net/tun", os.O_RDWR)
145 except EnvironmentError:
146 raise errors.HypervisorError("Failed to open /dev/net/tun")
147
148 flags = IFF_TAP | IFF_NO_PI
149
150 if vnet_hdr and _ProbeTapVnetHdr(tapfd):
151 flags |= IFF_VNET_HDR
152
153
154 ifr = struct.pack("16sh", "", flags)
155
156 try:
157 res = fcntl.ioctl(tapfd, TUNSETIFF, ifr)
158 except EnvironmentError, err:
159 raise errors.HypervisorError("Failed to allocate a new TAP device: %s" %
160 err)
161
162
163 ifname = struct.unpack("16sh", res)[0].strip("\x00")
164 return (ifname, tapfd)
165
168 """QEMU Messaging Protocol (QMP) message.
169
170 """
172 """Creates a new QMP message based on the passed data.
173
174 """
175 if not isinstance(data, dict):
176 raise TypeError("QmpMessage must be initialized with a dict")
177
178 self.data = data
179
181 """Get the value of the required field if present, or None.
182
183 Overrides the [] operator to provide access to the message data,
184 returning None if the required item is not in the message
185 @return: the value of the field_name field, or None if field_name
186 is not contained in the message
187
188 """
189 return self.data.get(field_name, None)
190
192 """Set the value of the required field_name to field_value.
193
194 """
195 self.data[field_name] = field_value
196
197 @staticmethod
199 """Build a QmpMessage from a JSON encoded string.
200
201 @type json_string: str
202 @param json_string: JSON string representing the message
203 @rtype: L{QmpMessage}
204 @return: a L{QmpMessage} built from json_string
205
206 """
207
208 data = serializer.LoadJson(json_string)
209 return QmpMessage(data)
210
214
216
217
218 return self.data == other.data
219
222 """Connection to the QEMU Monitor using the QEMU Monitor Protocol (QMP).
223
224 """
225 _FIRST_MESSAGE_KEY = "QMP"
226 _EVENT_KEY = "event"
227 _ERROR_KEY = "error"
228 _RETURN_KEY = RETURN_KEY = "return"
229 _ACTUAL_KEY = ACTUAL_KEY = "actual"
230 _ERROR_CLASS_KEY = "class"
231 _ERROR_DATA_KEY = "data"
232 _ERROR_DESC_KEY = "desc"
233 _EXECUTE_KEY = "execute"
234 _ARGUMENTS_KEY = "arguments"
235 _CAPABILITIES_COMMAND = "qmp_capabilities"
236 _MESSAGE_END_TOKEN = "\r\n"
237 _SOCKET_TIMEOUT = 5
238
240 """Instantiates the QmpConnection object.
241
242 @type monitor_filename: string
243 @param monitor_filename: the filename of the UNIX raw socket on which the
244 QMP monitor is listening
245
246 """
247 self.monitor_filename = monitor_filename
248 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
249
250
251 self.sock.settimeout(self._SOCKET_TIMEOUT)
252 self._connected = False
253 self._buf = ""
254
256 sock_stat = None
257 try:
258 sock_stat = os.stat(self.monitor_filename)
259 except EnvironmentError, err:
260 if err.errno == errno.ENOENT:
261 raise errors.HypervisorError("No qmp socket found")
262 else:
263 raise errors.HypervisorError("Error checking qmp socket: %s",
264 utils.ErrnoOrStr(err))
265 if not stat.S_ISSOCK(sock_stat.st_mode):
266 raise errors.HypervisorError("Qmp socket is not a socket")
267
269 """Make sure that the connection is established.
270
271 """
272 if not self._connected:
273 raise errors.ProgrammerError("To use a QmpConnection you need to first"
274 " invoke connect() on it")
275
277 """Connects to the QMP monitor.
278
279 Connects to the UNIX socket and makes sure that we can actually send and
280 receive data to the kvm instance via QMP.
281
282 @raise errors.HypervisorError: when there are communication errors
283 @raise errors.ProgrammerError: when there are data serialization errors
284
285 """
286 if self._connected:
287 raise errors.ProgrammerError("Cannot connect twice")
288
289 self._check_socket()
290
291
292 try:
293 self.sock.connect(self.monitor_filename)
294 except EnvironmentError:
295 raise errors.HypervisorError("Can't connect to qmp socket")
296 self._connected = True
297
298
299
300 greeting = self._Recv()
301 if not greeting[self._FIRST_MESSAGE_KEY]:
302 self._connected = False
303 raise errors.HypervisorError("kvm: QMP communication error (wrong"
304 " server greeting")
305
306
307
308
309 self.Execute(self._CAPABILITIES_COMMAND)
310
312 """Extract and parse a QMP message from the given buffer.
313
314 Seeks for a QMP message in the given buf. If found, it parses it and
315 returns it together with the rest of the characters in the buf.
316 If no message is found, returns None and the whole buffer.
317
318 @raise errors.ProgrammerError: when there are data serialization errors
319
320 """
321 message = None
322
323
324 pos = buf.find(self._MESSAGE_END_TOKEN)
325 if pos >= 0:
326 try:
327 message = QmpMessage.BuildFromJsonString(buf[:pos + 1])
328 except Exception, err:
329 raise errors.ProgrammerError("QMP data serialization error: %s" % err)
330 buf = buf[pos + 1:]
331
332 return (message, buf)
333
335 """Receives a message from QMP and decodes the received JSON object.
336
337 @rtype: QmpMessage
338 @return: the received message
339 @raise errors.HypervisorError: when there are communication errors
340 @raise errors.ProgrammerError: when there are data serialization errors
341
342 """
343 self._check_connection()
344
345
346 (message, self._buf) = self._ParseMessage(self._buf)
347 if message:
348 return message
349
350 recv_buffer = StringIO.StringIO(self._buf)
351 recv_buffer.seek(len(self._buf))
352 try:
353 while True:
354 data = self.sock.recv(4096)
355 if not data:
356 break
357 recv_buffer.write(data)
358
359 (message, self._buf) = self._ParseMessage(recv_buffer.getvalue())
360 if message:
361 return message
362
363 except socket.timeout, err:
364 raise errors.HypervisorError("Timeout while receiving a QMP message: "
365 "%s" % (err))
366 except socket.error, err:
367 raise errors.HypervisorError("Unable to receive data from KVM using the"
368 " QMP protocol: %s" % err)
369
370 - def _Send(self, message):
371 """Encodes and sends a message to KVM using QMP.
372
373 @type message: QmpMessage
374 @param message: message to send to KVM
375 @raise errors.HypervisorError: when there are communication errors
376 @raise errors.ProgrammerError: when there are data serialization errors
377
378 """
379 self._check_connection()
380 try:
381 message_str = str(message)
382 except Exception, err:
383 raise errors.ProgrammerError("QMP data deserialization error: %s" % err)
384
385 try:
386 self.sock.sendall(message_str)
387 except socket.timeout, err:
388 raise errors.HypervisorError("Timeout while sending a QMP message: "
389 "%s (%s)" % (err.string, err.errno))
390 except socket.error, err:
391 raise errors.HypervisorError("Unable to send data from KVM using the"
392 " QMP protocol: %s" % err)
393
394 - def Execute(self, command, arguments=None):
395 """Executes a QMP command and returns the response of the server.
396
397 @type command: str
398 @param command: the command to execute
399 @type arguments: dict
400 @param arguments: dictionary of arguments to be passed to the command
401 @rtype: dict
402 @return: dictionary representing the received JSON object
403 @raise errors.HypervisorError: when there are communication errors
404 @raise errors.ProgrammerError: when there are data serialization errors
405
406 """
407 self._check_connection()
408 message = QmpMessage({self._EXECUTE_KEY: command})
409 if arguments:
410 message[self._ARGUMENTS_KEY] = arguments
411 self._Send(message)
412
413
414
415 while True:
416 response = self._Recv()
417 err = response[self._ERROR_KEY]
418 if err:
419 raise errors.HypervisorError("kvm: error executing the %s"
420 " command: %s (%s, %s):" %
421 (command,
422 err[self._ERROR_DESC_KEY],
423 err[self._ERROR_CLASS_KEY],
424 err[self._ERROR_DATA_KEY]))
425
426 elif not response[self._EVENT_KEY]:
427 return response
428
431 """KVM hypervisor interface
432
433 """
434 CAN_MIGRATE = True
435
436 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor"
437 _PIDS_DIR = _ROOT_DIR + "/pid"
438 _UIDS_DIR = _ROOT_DIR + "/uid"
439 _CTRL_DIR = _ROOT_DIR + "/ctrl"
440 _CONF_DIR = _ROOT_DIR + "/conf"
441 _NICS_DIR = _ROOT_DIR + "/nic"
442 _KEYMAP_DIR = _ROOT_DIR + "/keymap"
443
444 _CHROOT_DIR = _ROOT_DIR + "/chroot"
445
446
447
448
449
450 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine"
451 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR,
452 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR]
453
454 PARAMETERS = {
455 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK,
456 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK,
457 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
458 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
459 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
460 constants.HV_ACPI: hv_base.NO_CHECK,
461 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK,
462 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK,
463 constants.HV_VNC_BIND_ADDRESS:
464 (False, lambda x: (netutils.IP4Address.IsValid(x) or
465 utils.IsNormAbsPath(x)),
466 "The VNC bind address must be either a valid IP address or an absolute"
467 " pathname", None, None),
468 constants.HV_VNC_TLS: hv_base.NO_CHECK,
469 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK,
470 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK,
471 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
472 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK,
473 constants.HV_KVM_SPICE_IP_VERSION:
474 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or
475 x in constants.VALID_IP_VERSIONS),
476 "The SPICE IP version should be 4 or 6",
477 None, None),
478 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK,
479 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR:
480 hv_base.ParamInSet(
481 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS),
482 constants.HV_KVM_SPICE_JPEG_IMG_COMPR:
483 hv_base.ParamInSet(
484 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
485 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR:
486 hv_base.ParamInSet(
487 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS),
488 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION:
489 hv_base.ParamInSet(
490 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS),
491 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK,
492 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK,
493 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK,
494 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK,
495 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
496 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
497 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
498 constants.HV_BOOT_ORDER:
499 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES),
500 constants.HV_NIC_TYPE:
501 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES),
502 constants.HV_DISK_TYPE:
503 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES),
504 constants.HV_KVM_CDROM_DISK_TYPE:
505 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES),
506 constants.HV_USB_MOUSE:
507 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES),
508 constants.HV_KEYMAP: hv_base.NO_CHECK,
509 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
510 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK,
511 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK,
512 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
513 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
514 constants.HV_DISK_CACHE:
515 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES),
516 constants.HV_SECURITY_MODEL:
517 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES),
518 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK,
519 constants.HV_KVM_FLAG:
520 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES),
521 constants.HV_VHOST_NET: hv_base.NO_CHECK,
522 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
523 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
524 constants.HV_REBOOT_BEHAVIOR:
525 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
526 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
527 constants.HV_CPU_TYPE: hv_base.NO_CHECK,
528 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK,
529 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
530 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK,
531 constants.HV_SOUNDHW: hv_base.NO_CHECK,
532 constants.HV_USB_DEVICES: hv_base.NO_CHECK,
533 constants.HV_VGA: hv_base.NO_CHECK,
534 constants.HV_KVM_EXTRA: hv_base.NO_CHECK,
535 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK,
536 constants.HV_VNET_HDR: hv_base.NO_CHECK,
537 }
538
539 _VIRTIO = "virtio"
540 _VIRTIO_NET_PCI = "virtio-net-pci"
541
542 _MIGRATION_STATUS_RE = re.compile("Migration\s+status:\s+(\w+)",
543 re.M | re.I)
544 _MIGRATION_PROGRESS_RE = \
545 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n"
546 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n"
547 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I)
548
549 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5
550 _MIGRATION_INFO_RETRY_DELAY = 2
551
552 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b")
553
554 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I)
555 _CPU_INFO_CMD = "info cpus"
556 _CONT_CMD = "cont"
557
558 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M)
559 _CHECK_MACHINE_VERSION_RE = \
560 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M))
561
562 _QMP_RE = re.compile(r"^-qmp\s", re.M)
563 _SPICE_RE = re.compile(r"^-spice\s", re.M)
564 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
565 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
566 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
567 _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
568 _DISPLAY_RE = re.compile(r"^-display\s", re.M)
569 _MACHINE_RE = re.compile(r"^-machine\s", re.M)
570 _NEW_VIRTIO_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M)
571
572
573
574 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
575
576 ANCILLARY_FILES = [
577 _KVM_NETWORK_SCRIPT,
578 ]
579 ANCILLARY_FILES_OPT = [
580 _KVM_NETWORK_SCRIPT,
581 ]
582
583
584 _KVMOPT_HELP = "help"
585 _KVMOPT_MLIST = "mlist"
586 _KVMOPT_DEVICELIST = "devicelist"
587
588
589
590 _KVMOPTS_CMDS = {
591 _KVMOPT_HELP: (["--help"], False),
592 _KVMOPT_MLIST: (["-M", "?"], False),
593 _KVMOPT_DEVICELIST: (["-device", "?"], True),
594 }
595
602
603 @classmethod
605 """Returns the instance pidfile.
606
607 """
608 return utils.PathJoin(cls._PIDS_DIR, instance_name)
609
610 @classmethod
612 """Returns the instance uidfile.
613
614 """
615 return utils.PathJoin(cls._UIDS_DIR, instance_name)
616
617 @classmethod
619 """Check pid file for instance information.
620
621 Check that a pid file is associated with an instance, and retrieve
622 information from its command line.
623
624 @type pid: string or int
625 @param pid: process id of the instance to check
626 @rtype: tuple
627 @return: (instance_name, memory, vcpus)
628 @raise errors.HypervisorError: when an instance cannot be found
629
630 """
631 alive = utils.IsProcessAlive(pid)
632 if not alive:
633 raise errors.HypervisorError("Cannot get info for pid %s" % pid)
634
635 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline")
636 try:
637 cmdline = utils.ReadFile(cmdline_file)
638 except EnvironmentError, err:
639 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" %
640 (pid, err))
641
642 instance = None
643 memory = 0
644 vcpus = 0
645
646 arg_list = cmdline.split("\x00")
647 while arg_list:
648 arg = arg_list.pop(0)
649 if arg == "-name":
650 instance = arg_list.pop(0)
651 elif arg == "-m":
652 memory = int(arg_list.pop(0))
653 elif arg == "-smp":
654 vcpus = int(arg_list.pop(0).split(",")[0])
655
656 if instance is None:
657 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm"
658 " instance" % pid)
659
660 return (instance, memory, vcpus)
661
663 """Returns the instance pidfile, pid, and liveness.
664
665 @type instance_name: string
666 @param instance_name: instance name
667 @rtype: tuple
668 @return: (pid file name, pid, liveness)
669
670 """
671 pidfile = self._InstancePidFile(instance_name)
672 pid = utils.ReadPidFile(pidfile)
673
674 alive = False
675 try:
676 cmd_instance = self._InstancePidInfo(pid)[0]
677 alive = (cmd_instance == instance_name)
678 except errors.HypervisorError:
679 pass
680
681 return (pidfile, pid, alive)
682
684 """Raises an error unless the given instance is down.
685
686 """
687 alive = self._InstancePidAlive(instance_name)[2]
688 if alive:
689 raise errors.HypervisorError("Failed to start instance %s: %s" %
690 (instance_name, "already running"))
691
692 @classmethod
694 """Returns the instance monitor socket name
695
696 """
697 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
698
699 @classmethod
701 """Returns the instance serial socket name
702
703 """
704 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
705
706 @classmethod
708 """Returns the instance serial QMP socket name
709
710 """
711 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
712
713 @staticmethod
715 """Returns the correct parameters for socat
716
717 If we have a new-enough socat we can use raw mode with an escape character.
718
719 """
720 if constants.SOCAT_USE_ESCAPE:
721 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE
722 else:
723 return "echo=0,icanon=0"
724
725 @classmethod
727 """Returns the instance KVM runtime filename
728
729 """
730 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
731
732 @classmethod
734 """Returns the name of the KVM chroot dir of the instance
735
736 """
737 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
738
739 @classmethod
741 """Returns the name of the directory holding the tap device files for a
742 given instance.
743
744 """
745 return utils.PathJoin(cls._NICS_DIR, instance_name)
746
747 @classmethod
749 """Returns the name of the file containing the tap device for a given NIC
750
751 """
752 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
753
754 @classmethod
756 """Returns the name of the file containing the keymap for a given instance
757
758 """
759 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
760
761 @classmethod
763 """Try to read a uid file
764
765 """
766 if os.path.exists(uid_file):
767 try:
768 uid = int(utils.ReadOneLineFile(uid_file))
769 return uid
770 except EnvironmentError:
771 logging.warning("Can't read uid file", exc_info=True)
772 except (TypeError, ValueError):
773 logging.warning("Can't parse uid file contents", exc_info=True)
774 return None
775
776 @classmethod
778 """Removes an instance's rutime sockets/files/dirs.
779
780 """
781 utils.RemoveFile(pidfile)
782 utils.RemoveFile(cls._InstanceMonitor(instance_name))
783 utils.RemoveFile(cls._InstanceSerial(instance_name))
784 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name))
785 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name))
786 utils.RemoveFile(cls._InstanceKeymapFile(instance_name))
787 uid_file = cls._InstanceUidFile(instance_name)
788 uid = cls._TryReadUidFile(uid_file)
789 utils.RemoveFile(uid_file)
790 if uid is not None:
791 uidpool.ReleaseUid(uid)
792 try:
793 shutil.rmtree(cls._InstanceNICDir(instance_name))
794 except OSError, err:
795 if err.errno != errno.ENOENT:
796 raise
797 try:
798 chroot_dir = cls._InstanceChrootDir(instance_name)
799 utils.RemoveDir(chroot_dir)
800 except OSError, err:
801 if err.errno == errno.ENOTEMPTY:
802
803 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR,
804 prefix="%s-%s-" %
805 (instance_name,
806 utils.TimestampForFilename()))
807 logging.warning("The chroot directory of instance %s can not be"
808 " removed as it is not empty. Moving it to the"
809 " quarantine instead. Please investigate the"
810 " contents (%s) and clean up manually",
811 instance_name, new_chroot_dir)
812 utils.RenameFile(chroot_dir, new_chroot_dir)
813 else:
814 raise
815
816 @staticmethod
863
864 @staticmethod
869
870 @staticmethod
872 """Create a CPU mask suitable for sched_setaffinity from a list of
873 CPUs.
874
875 See man taskset for more info on sched_setaffinity masks.
876 For example: [ 0, 2, 5, 6 ] will return 101 (0x65, 0..01100101).
877
878 @type cpu_list: list of int
879 @param cpu_list: list of physical CPU numbers to map to vCPUs in order
880 @rtype: int
881 @return: a bit mask of CPU affinities
882
883 """
884 if cpu_list == constants.CPU_PINNING_OFF:
885 return constants.CPU_PINNING_ALL_KVM
886 else:
887 return sum(2 ** cpu for cpu in cpu_list)
888
889 @classmethod
891 """Change CPU affinity for running VM according to given CPU mask.
892
893 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3"
894 @type cpu_mask: string
895 @param process_id: process ID of KVM process. Used to pin entire VM
896 to physical CPUs.
897 @type process_id: int
898 @param thread_dict: map of virtual CPUs to KVM thread IDs
899 @type thread_dict: dict int:int
900
901 """
902
903 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
904
905 if len(cpu_list) == 1:
906 all_cpu_mapping = cpu_list[0]
907 if all_cpu_mapping == constants.CPU_PINNING_OFF:
908
909 pass
910 else:
911
912
913 cls._VerifyAffinityPackage()
914 affinity.set_process_affinity_mask(
915 process_id, cls._BuildAffinityCpuMask(all_cpu_mapping))
916 else:
917
918
919
920 assert len(thread_dict) == len(cpu_list)
921 cls._VerifyAffinityPackage()
922
923
924 for vcpu, i in zip(cpu_list, range(len(cpu_list))):
925 affinity.set_process_affinity_mask(thread_dict[i],
926 cls._BuildAffinityCpuMask(vcpu))
927
929 """Get a mapping of vCPU no. to thread IDs for the instance
930
931 @type instance_name: string
932 @param instance_name: instance in question
933 @rtype: dictionary of int:int
934 @return: a dictionary mapping vCPU numbers to thread IDs
935
936 """
937 result = {}
938 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD)
939 for line in output.stdout.splitlines():
940 match = self._CPU_INFO_RE.search(line)
941 if not match:
942 continue
943 grp = map(int, match.groups())
944 result[grp[0]] = grp[1]
945
946 return result
947
949 """Complete CPU pinning.
950
951 @type instance_name: string
952 @param instance_name: name of instance
953 @type cpu_mask: string
954 @param cpu_mask: CPU pinning mask as entered by user
955
956 """
957
958 _, pid, _ = self._InstancePidAlive(instance_name)
959
960 thread_dict = self._GetVcpuThreadIds(instance_name)
961
962 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
963
965 """Get the list of running instances.
966
967 We can do this by listing our live instances directory and
968 checking whether the associated kvm process is still alive.
969
970 """
971 result = []
972 for name in os.listdir(self._PIDS_DIR):
973 if self._InstancePidAlive(name)[2]:
974 result.append(name)
975 return result
976
978 """Get instance properties.
979
980 @type instance_name: string
981 @param instance_name: the instance name
982 @rtype: tuple of strings
983 @return: (name, id, memory, vcpus, stat, times)
984
985 """
986 _, pid, alive = self._InstancePidAlive(instance_name)
987 if not alive:
988 return None
989
990 _, memory, vcpus = self._InstancePidInfo(pid)
991 istat = "---b-"
992 times = "0"
993
994 try:
995 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name))
996 qmp.connect()
997 vcpus = len(qmp.Execute("query-cpus")[qmp.RETURN_KEY])
998
999
1000 mem_bytes = qmp.Execute("query-balloon")[qmp.RETURN_KEY][qmp.ACTUAL_KEY]
1001 memory = mem_bytes / 1048576
1002 except errors.HypervisorError:
1003 pass
1004
1005 return (instance_name, pid, memory, vcpus, istat, times)
1006
1008 """Get properties of all instances.
1009
1010 @return: list of tuples (name, id, memory, vcpus, stat, times)
1011
1012 """
1013 data = []
1014 for name in os.listdir(self._PIDS_DIR):
1015 try:
1016 info = self.GetInstanceInfo(name)
1017 except errors.HypervisorError:
1018
1019 continue
1020 if info:
1021 data.append(info)
1022 return data
1023
1026 """Generate KVM information to start an instance.
1027
1028 @type kvmhelp: string
1029 @param kvmhelp: output of kvm --help
1030 @attention: this function must not have any side-effects; for
1031 example, it must not write to the filesystem, or read values
1032 from the current system the are expected to differ between
1033 nodes, since it is only run once at instance startup;
1034 actions/kvm arguments that can vary between systems should be
1035 done in L{_ExecuteKVMRuntime}
1036
1037 """
1038
1039 hvp = instance.hvparams
1040 self.ValidateParameters(hvp)
1041
1042 pidfile = self._InstancePidFile(instance.name)
1043 kvm = hvp[constants.HV_KVM_PATH]
1044 kvm_cmd = [kvm]
1045
1046 kvm_cmd.extend(["-name", instance.name])
1047 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]])
1048
1049 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]]
1050 if hvp[constants.HV_CPU_CORES]:
1051 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES])
1052 if hvp[constants.HV_CPU_THREADS]:
1053 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS])
1054 if hvp[constants.HV_CPU_SOCKETS]:
1055 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS])
1056
1057 kvm_cmd.extend(["-smp", ",".join(smp_list)])
1058
1059 kvm_cmd.extend(["-pidfile", pidfile])
1060 kvm_cmd.extend(["-balloon", "virtio"])
1061 kvm_cmd.extend(["-daemonize"])
1062 if not instance.hvparams[constants.HV_ACPI]:
1063 kvm_cmd.extend(["-no-acpi"])
1064 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \
1065 constants.INSTANCE_REBOOT_EXIT:
1066 kvm_cmd.extend(["-no-reboot"])
1067
1068 mversion = hvp[constants.HV_KVM_MACHINE_VERSION]
1069 if not mversion:
1070 mversion = self._GetDefaultMachineVersion(kvm)
1071 if self._MACHINE_RE.search(kvmhelp):
1072
1073
1074
1075 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED):
1076 specprop = ",accel=kvm"
1077 else:
1078 specprop = ""
1079 machinespec = "%s%s" % (mversion, specprop)
1080 kvm_cmd.extend(["-machine", machinespec])
1081 else:
1082 kvm_cmd.extend(["-M", mversion])
1083 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1084 self._ENABLE_KVM_RE.search(kvmhelp)):
1085 kvm_cmd.extend(["-enable-kvm"])
1086 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1087 self._DISABLE_KVM_RE.search(kvmhelp)):
1088 kvm_cmd.extend(["-disable-kvm"])
1089
1090 kernel_path = hvp[constants.HV_KERNEL_PATH]
1091 if kernel_path:
1092 boot_disk = boot_cdrom = boot_floppy = boot_network = False
1093 else:
1094 boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
1095 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM
1096 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY
1097 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK
1098
1099 if startup_paused:
1100 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1101
1102 if boot_network:
1103 kvm_cmd.extend(["-boot", "n"])
1104
1105
1106
1107 needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1108
1109 disk_type = hvp[constants.HV_DISK_TYPE]
1110 if disk_type == constants.HT_DISK_PARAVIRTUAL:
1111 if_val = ",if=virtio"
1112 else:
1113 if_val = ",if=%s" % disk_type
1114
1115 disk_cache = hvp[constants.HV_DISK_CACHE]
1116 if instance.disk_template in constants.DTS_EXT_MIRROR:
1117 if disk_cache != "none":
1118
1119 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'"
1120 " to prevent shared storage corruption on migration",
1121 disk_cache)
1122 cache_val = ",cache=none"
1123 elif disk_cache != constants.HT_CACHE_DEFAULT:
1124 cache_val = ",cache=%s" % disk_cache
1125 else:
1126 cache_val = ""
1127 for cfdev, dev_path in block_devices:
1128 if cfdev.mode != constants.DISK_RDWR:
1129 raise errors.HypervisorError("Instance has read-only disks which"
1130 " are not supported by KVM")
1131
1132 boot_val = ""
1133 if boot_disk:
1134 kvm_cmd.extend(["-boot", "c"])
1135 boot_disk = False
1136 if needs_boot_flag and disk_type != constants.HT_DISK_IDE:
1137 boot_val = ",boot=on"
1138
1139 drive_val = "file=%s,format=raw%s%s%s" % (dev_path, if_val, boot_val,
1140 cache_val)
1141 kvm_cmd.extend(["-drive", drive_val])
1142
1143
1144 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE]
1145 if not cdrom_disk_type:
1146 cdrom_disk_type = disk_type
1147
1148 iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
1149 if iso_image:
1150 options = ",format=raw,media=cdrom"
1151
1152 if boot_cdrom:
1153 actual_cdrom_type = constants.HT_DISK_IDE
1154 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1155 actual_cdrom_type = "virtio"
1156 else:
1157 actual_cdrom_type = cdrom_disk_type
1158 if_val = ",if=%s" % actual_cdrom_type
1159
1160 boot_val = ""
1161 if boot_cdrom:
1162 kvm_cmd.extend(["-boot", "d"])
1163 if needs_boot_flag:
1164 boot_val = ",boot=on"
1165
1166 drive_val = "file=%s%s%s%s" % (iso_image, options, if_val, boot_val)
1167 kvm_cmd.extend(["-drive", drive_val])
1168
1169 iso_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH]
1170 if iso_image2:
1171 options = ",format=raw,media=cdrom"
1172 if cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL:
1173 if_val = ",if=virtio"
1174 else:
1175 if_val = ",if=%s" % cdrom_disk_type
1176 drive_val = "file=%s%s%s" % (iso_image2, options, if_val)
1177 kvm_cmd.extend(["-drive", drive_val])
1178
1179 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH]
1180 if floppy_image:
1181 options = ",format=raw,media=disk"
1182 if boot_floppy:
1183 kvm_cmd.extend(["-boot", "a"])
1184 options = "%s,boot=on" % options
1185 if_val = ",if=floppy"
1186 options = "%s%s" % (options, if_val)
1187 drive_val = "file=%s%s" % (floppy_image, options)
1188 kvm_cmd.extend(["-drive", drive_val])
1189
1190 if kernel_path:
1191 kvm_cmd.extend(["-kernel", kernel_path])
1192 initrd_path = hvp[constants.HV_INITRD_PATH]
1193 if initrd_path:
1194 kvm_cmd.extend(["-initrd", initrd_path])
1195 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH],
1196 hvp[constants.HV_KERNEL_ARGS]]
1197 if hvp[constants.HV_SERIAL_CONSOLE]:
1198 serial_speed = hvp[constants.HV_SERIAL_SPEED]
1199 root_append.append("console=ttyS0,%s" % serial_speed)
1200 kvm_cmd.extend(["-append", " ".join(root_append)])
1201
1202 mem_path = hvp[constants.HV_MEM_PATH]
1203 if mem_path:
1204 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"])
1205
1206 monitor_dev = ("unix:%s,server,nowait" %
1207 self._InstanceMonitor(instance.name))
1208 kvm_cmd.extend(["-monitor", monitor_dev])
1209 if hvp[constants.HV_SERIAL_CONSOLE]:
1210 serial_dev = ("unix:%s,server,nowait" %
1211 self._InstanceSerial(instance.name))
1212 kvm_cmd.extend(["-serial", serial_dev])
1213 else:
1214 kvm_cmd.extend(["-serial", "none"])
1215
1216 mouse_type = hvp[constants.HV_USB_MOUSE]
1217 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
1218 spice_bind = hvp[constants.HV_KVM_SPICE_BIND]
1219 spice_ip_version = None
1220
1221 kvm_cmd.extend(["-usb"])
1222
1223 if mouse_type:
1224 kvm_cmd.extend(["-usbdevice", mouse_type])
1225 elif vnc_bind_address:
1226 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET])
1227
1228 if vnc_bind_address:
1229 if netutils.IP4Address.IsValid(vnc_bind_address):
1230 if instance.network_port > constants.VNC_BASE_PORT:
1231 display = instance.network_port - constants.VNC_BASE_PORT
1232 if vnc_bind_address == constants.IP4_ADDRESS_ANY:
1233 vnc_arg = ":%d" % (display)
1234 else:
1235 vnc_arg = "%s:%d" % (vnc_bind_address, display)
1236 else:
1237 logging.error("Network port is not a valid VNC display (%d < %d),"
1238 " not starting VNC",
1239 instance.network_port, constants.VNC_BASE_PORT)
1240 vnc_arg = "none"
1241
1242
1243
1244 vnc_append = ""
1245 if hvp[constants.HV_VNC_TLS]:
1246 vnc_append = "%s,tls" % vnc_append
1247 if hvp[constants.HV_VNC_X509_VERIFY]:
1248 vnc_append = "%s,x509verify=%s" % (vnc_append,
1249 hvp[constants.HV_VNC_X509])
1250 elif hvp[constants.HV_VNC_X509]:
1251 vnc_append = "%s,x509=%s" % (vnc_append,
1252 hvp[constants.HV_VNC_X509])
1253 if hvp[constants.HV_VNC_PASSWORD_FILE]:
1254 vnc_append = "%s,password" % vnc_append
1255
1256 vnc_arg = "%s%s" % (vnc_arg, vnc_append)
1257
1258 else:
1259 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name)
1260
1261 kvm_cmd.extend(["-vnc", vnc_arg])
1262 elif spice_bind:
1263
1264
1265 if netutils.IsValidInterface(spice_bind):
1266
1267
1268 addresses = netutils.GetInterfaceIpAddresses(spice_bind)
1269 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION]
1270
1271
1272
1273 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
1274 if not addresses[spice_ip_version]:
1275 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address"
1276 " for %s" % (spice_ip_version,
1277 spice_bind))
1278
1279
1280 elif (addresses[constants.IP4_VERSION] and
1281 addresses[constants.IP6_VERSION]):
1282
1283
1284 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily()
1285 spice_ip_version = \
1286 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family)
1287 elif addresses[constants.IP4_VERSION]:
1288 spice_ip_version = constants.IP4_VERSION
1289 elif addresses[constants.IP6_VERSION]:
1290 spice_ip_version = constants.IP6_VERSION
1291 else:
1292 raise errors.HypervisorError("SPICE: Unable to get an IP address"
1293 " for %s" % (spice_bind))
1294
1295 spice_address = addresses[spice_ip_version][0]
1296
1297 else:
1298
1299
1300 spice_address = spice_bind
1301
1302 spice_arg = "addr=%s" % spice_address
1303 if hvp[constants.HV_KVM_SPICE_USE_TLS]:
1304 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" %
1305 (spice_arg, instance.network_port,
1306 pathutils.SPICE_CACERT_FILE))
1307 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" %
1308 (spice_arg, pathutils.SPICE_CERT_FILE,
1309 pathutils.SPICE_CERT_FILE))
1310 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS]
1311 if tls_ciphers:
1312 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers)
1313 else:
1314 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port)
1315
1316 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]:
1317 spice_arg = "%s,disable-ticketing" % spice_arg
1318
1319 if spice_ip_version:
1320 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version)
1321
1322
1323 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR]
1324 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR]
1325 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR]
1326 if img_lossless:
1327 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless)
1328 if img_jpeg:
1329 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg)
1330 if img_zlib_glz:
1331 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz)
1332
1333
1334 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION]
1335 if video_streaming:
1336 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming)
1337
1338
1339 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]:
1340 spice_arg = "%s,playback-compression=off" % spice_arg
1341 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]:
1342 spice_arg = "%s,agent-mouse=off" % spice_arg
1343 else:
1344
1345
1346 kvm_cmd.extend(["-device", "virtio-serial-pci"])
1347 kvm_cmd.extend([
1348 "-device",
1349 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0",
1350 ])
1351 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"])
1352
1353 logging.info("KVM: SPICE will listen on port %s", instance.network_port)
1354 kvm_cmd.extend(["-spice", spice_arg])
1355
1356 else:
1357
1358
1359 if self._DISPLAY_RE.search(kvmhelp):
1360 kvm_cmd.extend(["-display", "none"])
1361 else:
1362 kvm_cmd.extend(["-nographic"])
1363
1364 if hvp[constants.HV_USE_LOCALTIME]:
1365 kvm_cmd.extend(["-localtime"])
1366
1367 if hvp[constants.HV_KVM_USE_CHROOT]:
1368 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)])
1369
1370
1371 if hvp[constants.HV_CPU_TYPE]:
1372 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]])
1373
1374
1375 if hvp[constants.HV_SOUNDHW]:
1376 kvm_cmd.extend(["-soundhw", hvp[constants.HV_SOUNDHW]])
1377
1378
1379
1380 if hvp[constants.HV_VGA]:
1381 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]])
1382 elif spice_bind:
1383 kvm_cmd.extend(["-vga", "qxl"])
1384
1385
1386 if hvp[constants.HV_USB_DEVICES]:
1387 for dev in hvp[constants.HV_USB_DEVICES].split(","):
1388 kvm_cmd.extend(["-usbdevice", dev])
1389
1390 if hvp[constants.HV_KVM_EXTRA]:
1391 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" "))
1392
1393
1394
1395 kvm_nics = instance.nics
1396 hvparams = hvp
1397
1398 return (kvm_cmd, kvm_nics, hvparams)
1399
1409
1411 """Read an instance's KVM runtime
1412
1413 """
1414 try:
1415 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
1416 except EnvironmentError, err:
1417 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
1418 return file_content
1419
1421 """Save an instance's KVM runtime
1422
1423 """
1424 kvm_cmd, kvm_nics, hvparams = kvm_runtime
1425 serialized_nics = [nic.ToDict() for nic in kvm_nics]
1426 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
1427 self._WriteKVMRuntime(instance.name, serialized_form)
1428
1430 """Load an instance's KVM runtime
1431
1432 """
1433 if not serialized_runtime:
1434 serialized_runtime = self._ReadKVMRuntime(instance.name)
1435 loaded_runtime = serializer.Load(serialized_runtime)
1436 kvm_cmd, serialized_nics, hvparams = loaded_runtime
1437 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
1438 return (kvm_cmd, kvm_nics, hvparams)
1439
1440 - def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1441 """Run the KVM cmd and check for errors
1442
1443 @type name: string
1444 @param name: instance name
1445 @type kvm_cmd: list of strings
1446 @param kvm_cmd: runcmd input for kvm
1447 @type tap_fds: list of int
1448 @param tap_fds: fds of tap devices opened by Ganeti
1449
1450 """
1451 try:
1452 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds)
1453 finally:
1454 for fd in tap_fds:
1455 utils_wrapper.CloseFdNoError(fd)
1456
1457 if result.failed:
1458 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
1459 (name, result.fail_reason, result.output))
1460 if not self._InstancePidAlive(name)[2]:
1461 raise errors.HypervisorError("Failed to start instance %s" % name)
1462
1464 """Execute a KVM cmd, after completing it with some last minute data.
1465
1466 @type incoming: tuple of strings
1467 @param incoming: (target_host_ip, port)
1468 @type kvmhelp: string
1469 @param kvmhelp: output of kvm --help
1470
1471 """
1472
1473
1474
1475
1476
1477
1478
1479
1480 conf_hvp = instance.hvparams
1481 name = instance.name
1482 self._CheckDown(name)
1483
1484 temp_files = []
1485
1486 kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1487
1488 kvm_path = kvm_cmd[0]
1489 up_hvp = objects.FillDict(conf_hvp, up_hvp)
1490
1491
1492
1493 security_model = conf_hvp[constants.HV_SECURITY_MODEL]
1494 if security_model == constants.HT_SM_USER:
1495 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]])
1496
1497 keymap = conf_hvp[constants.HV_KEYMAP]
1498 if keymap:
1499 keymap_path = self._InstanceKeymapFile(name)
1500
1501
1502
1503
1504 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap)
1505 kvm_cmd.extend(["-k", keymap_path])
1506
1507
1508
1509
1510 tapfds = []
1511 taps = []
1512 if not kvm_nics:
1513 kvm_cmd.extend(["-net", "none"])
1514 else:
1515 vnet_hdr = False
1516 tap_extra = ""
1517 nic_type = up_hvp[constants.HV_NIC_TYPE]
1518 if nic_type == constants.HT_NIC_PARAVIRTUAL:
1519 nic_model = self._VIRTIO
1520 try:
1521 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST)
1522 if self._NEW_VIRTIO_RE.search(devlist):
1523 nic_model = self._VIRTIO_NET_PCI
1524 vnet_hdr = up_hvp[constants.HV_VNET_HDR]
1525 except errors.HypervisorError, _:
1526
1527
1528 pass
1529
1530 if up_hvp[constants.HV_VHOST_NET]:
1531
1532 if self._VHOST_RE.search(kvmhelp):
1533 tap_extra = ",vhost=on"
1534 else:
1535 raise errors.HypervisorError("vhost_net is configured"
1536 " but it is not available")
1537 else:
1538 nic_model = nic_type
1539
1540 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp)
1541
1542 for nic_seq, nic in enumerate(kvm_nics):
1543 tapname, tapfd = _OpenTap(vnet_hdr=vnet_hdr)
1544 tapfds.append(tapfd)
1545 taps.append(tapname)
1546 if kvm_supports_netdev:
1547 nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1548 tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1549 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
1550 else:
1551 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq,
1552 nic.mac, nic_model)
1553 tap_val = "tap,vlan=%s,fd=%d" % (nic_seq, tapfd)
1554 kvm_cmd.extend(["-net", tap_val, "-net", nic_val])
1555
1556 if incoming:
1557 target, port = incoming
1558 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)])
1559
1560
1561
1562
1563 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE]
1564 vnc_pwd = None
1565 if vnc_pwd_file:
1566 try:
1567 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True)
1568 except EnvironmentError, err:
1569 raise errors.HypervisorError("Failed to open VNC password file %s: %s"
1570 % (vnc_pwd_file, err))
1571
1572 if conf_hvp[constants.HV_KVM_USE_CHROOT]:
1573 utils.EnsureDirs([(self._InstanceChrootDir(name),
1574 constants.SECURE_DIR_MODE)])
1575
1576
1577 if self._QMP_RE.search(kvmhelp):
1578 logging.debug("Enabling QMP")
1579 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1580 self._InstanceQmpMonitor(instance.name)])
1581
1582
1583
1584 for nic_seq, nic in enumerate(kvm_nics):
1585 if (incoming and
1586 nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_BRIDGED):
1587 continue
1588 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
1589
1590
1591
1592
1593 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming
1594 if start_kvm_paused:
1595 kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1596
1597
1598
1599
1600 cpu_pinning = False
1601 if up_hvp.get(constants.HV_CPU_MASK, None):
1602 cpu_pinning = True
1603
1604 if security_model == constants.HT_SM_POOL:
1605 ss = ssconf.SimpleStore()
1606 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n")
1607 all_uids = set(uidpool.ExpandUidPool(uid_pool))
1608 uid = uidpool.RequestUnusedUid(all_uids)
1609 try:
1610 username = pwd.getpwuid(uid.GetUid()).pw_name
1611 kvm_cmd.extend(["-runas", username])
1612 self._RunKVMCmd(name, kvm_cmd, tapfds)
1613 except:
1614 uidpool.ReleaseUid(uid)
1615 raise
1616 else:
1617 uid.Unlock()
1618 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr())
1619 else:
1620 self._RunKVMCmd(name, kvm_cmd, tapfds)
1621
1622 utils.EnsureDirs([(self._InstanceNICDir(instance.name),
1623 constants.RUN_DIRS_MODE)])
1624 for nic_seq, tap in enumerate(taps):
1625 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq),
1626 data=tap)
1627
1628 if vnc_pwd:
1629 change_cmd = "change vnc password %s" % vnc_pwd
1630 self._CallMonitorCommand(instance.name, change_cmd)
1631
1632
1633
1634
1635
1636
1637 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]
1638 if spice_password_file:
1639 spice_pwd = ""
1640 try:
1641 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True)
1642 except EnvironmentError, err:
1643 raise errors.HypervisorError("Failed to open SPICE password file %s: %s"
1644 % (spice_password_file, err))
1645
1646 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name))
1647 qmp.connect()
1648 arguments = {
1649 "protocol": "spice",
1650 "password": spice_pwd,
1651 }
1652 qmp.Execute("set_password", arguments)
1653
1654 for filename in temp_files:
1655 utils.RemoveFile(filename)
1656
1657
1658 if cpu_pinning:
1659 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK])
1660
1661 start_memory = self._InstanceStartupMemory(instance)
1662 if start_memory < instance.beparams[constants.BE_MAXMEM]:
1663 self.BalloonInstanceMemory(instance, start_memory)
1664
1665 if start_kvm_paused:
1666
1667
1668
1669 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1670
1671 - def StartInstance(self, instance, block_devices, startup_paused):
1682
1684 """Invoke a command on the instance monitor.
1685
1686 """
1687 if timeout is not None:
1688 timeout_cmd = "timeout %s" % (timeout, )
1689 else:
1690 timeout_cmd = ""
1691
1692
1693
1694
1695
1696
1697
1698
1699 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" %
1700 (utils.ShellQuote(command),
1701 timeout_cmd,
1702 constants.SOCAT_PATH,
1703 utils.ShellQuote(self._InstanceMonitor(instance_name))))
1704
1705 result = utils.RunCmd(socat)
1706 if result.failed:
1707 msg = ("Failed to send command '%s' to instance '%s', reason '%s',"
1708 " output: %s" %
1709 (command, instance_name, result.fail_reason, result.output))
1710 raise errors.HypervisorError(msg)
1711
1712 return result
1713
1714 @classmethod
1716 """Parse the KVM version from the --help output.
1717
1718 @type text: string
1719 @param text: output of kvm --help
1720 @return: (version, v_maj, v_min, v_rev)
1721 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1722
1723 """
1724 match = cls._VERSION_RE.search(text.splitlines()[0])
1725 if not match:
1726 raise errors.HypervisorError("Unable to get KVM version")
1727
1728 v_all = match.group(0)
1729 v_maj = int(match.group(1))
1730 v_min = int(match.group(2))
1731 if match.group(4):
1732 v_rev = int(match.group(4))
1733 else:
1734 v_rev = 0
1735 return (v_all, v_maj, v_min, v_rev)
1736
1737 @classmethod
1739 """Return the output of a kvm invocation
1740
1741 @type kvm_path: string
1742 @param kvm_path: path to the kvm executable
1743 @type option: a key of _KVMOPTS_CMDS
1744 @param option: kvm option to fetch the output from
1745 @return: output a supported kvm invocation
1746 @raise errors.HypervisorError: when the KVM help output cannot be retrieved
1747
1748 """
1749 assert option in cls._KVMOPTS_CMDS, "Invalid output option"
1750
1751 optlist, can_fail = cls._KVMOPTS_CMDS[option]
1752
1753 result = utils.RunCmd([kvm_path] + optlist)
1754 if result.failed and not can_fail:
1755 raise errors.HypervisorError("Unable to get KVM %s output" %
1756 " ".join(optlist))
1757 return result.output
1758
1759 @classmethod
1761 """Return the installed KVM version.
1762
1763 @return: (version, v_maj, v_min, v_rev)
1764 @raise errors.HypervisorError: when the KVM version cannot be retrieved
1765
1766 """
1767 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
1768
1769 @classmethod
1780
1781 - def StopInstance(self, instance, force=False, retry=False, name=None,
1782 timeout=None):
1801
1810
1833
1835 """Get instance information to perform a migration.
1836
1837 @type instance: L{objects.Instance}
1838 @param instance: instance to be migrated
1839 @rtype: string
1840 @return: content of the KVM runtime file
1841
1842 """
1843 return self._ReadKVMRuntime(instance.name)
1844
1846 """Prepare to accept an instance.
1847
1848 @type instance: L{objects.Instance}
1849 @param instance: instance to be accepted
1850 @type info: string
1851 @param info: content of the KVM runtime file on the source node
1852 @type target: string
1853 @param target: target host (usually ip), on this node
1854
1855 """
1856 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1857 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT])
1858 kvmpath = instance.hvparams[constants.HV_KVM_PATH]
1859 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP)
1860 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp,
1861 incoming=incoming_address)
1862
1864 """Finalize the instance migration on the target node.
1865
1866 Stop the incoming mode KVM.
1867
1868 @type instance: L{objects.Instance}
1869 @param instance: instance whose migration is being finalized
1870
1871 """
1872 if success:
1873 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
1874 kvm_nics = kvm_runtime[1]
1875
1876 for nic_seq, nic in enumerate(kvm_nics):
1877 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1878
1879 continue
1880 try:
1881 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq))
1882 except EnvironmentError, err:
1883 logging.warning("Failed to find host interface for %s NIC #%d: %s",
1884 instance.name, nic_seq, str(err))
1885 continue
1886 try:
1887 self._ConfigureNIC(instance, nic_seq, nic, tap)
1888 except errors.HypervisorError, err:
1889 logging.warning(str(err))
1890
1891 self._WriteKVMRuntime(instance.name, info)
1892 else:
1893 self.StopInstance(instance, force=True)
1894
1896 """Migrate an instance to a target node.
1897
1898 The migration will not be attempted if the instance is not
1899 currently running.
1900
1901 @type instance: L{objects.Instance}
1902 @param instance: the instance to be migrated
1903 @type target: string
1904 @param target: ip address of the target node
1905 @type live: boolean
1906 @param live: perform a live migration
1907
1908 """
1909 instance_name = instance.name
1910 port = instance.hvparams[constants.HV_MIGRATION_PORT]
1911 _, _, alive = self._InstancePidAlive(instance_name)
1912 if not alive:
1913 raise errors.HypervisorError("Instance not running, cannot migrate")
1914
1915 if not live:
1916 self._CallMonitorCommand(instance_name, "stop")
1917
1918 migrate_command = ("migrate_set_speed %dm" %
1919 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH])
1920 self._CallMonitorCommand(instance_name, migrate_command)
1921
1922 migrate_command = ("migrate_set_downtime %dms" %
1923 instance.hvparams[constants.HV_MIGRATION_DOWNTIME])
1924 self._CallMonitorCommand(instance_name, migrate_command)
1925
1926 migrate_command = "migrate -d tcp:%s:%s" % (target, port)
1927 self._CallMonitorCommand(instance_name, migrate_command)
1928
1946
1948 """Get the migration status
1949
1950 @type instance: L{objects.Instance}
1951 @param instance: the instance that is being migrated
1952 @rtype: L{objects.MigrationStatus}
1953 @return: the status of the current migration (one of
1954 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
1955 progress info that can be retrieved from the hypervisor
1956
1957 """
1958 info_command = "info migrate"
1959 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS):
1960 result = self._CallMonitorCommand(instance.name, info_command)
1961 match = self._MIGRATION_STATUS_RE.search(result.stdout)
1962 if not match:
1963 if not result.stdout:
1964 logging.info("KVM: empty 'info migrate' result")
1965 else:
1966 logging.warning("KVM: unknown 'info migrate' result: %s",
1967 result.stdout)
1968 else:
1969 status = match.group(1)
1970 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES:
1971 migration_status = objects.MigrationStatus(status=status)
1972 match = self._MIGRATION_PROGRESS_RE.search(result.stdout)
1973 if match:
1974 migration_status.transferred_ram = match.group("transferred")
1975 migration_status.total_ram = match.group("total")
1976
1977 return migration_status
1978
1979 logging.warning("KVM: unknown migration status '%s'", status)
1980
1981 time.sleep(self._MIGRATION_INFO_RETRY_DELAY)
1982
1983 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
1984
1986 """Balloon an instance memory to a certain value.
1987
1988 @type instance: L{objects.Instance}
1989 @param instance: instance to be accepted
1990 @type mem: int
1991 @param mem: actual memory size to use for instance runtime
1992
1993 """
1994 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
1995
1997 """Return information about the node.
1998
1999 @return: a dict with the following keys (values in MiB):
2000 - memory_total: the total memory size on the node
2001 - memory_free: the available memory on the node for instances
2002 - memory_dom0: the memory used by the node itself, if available
2003 - hv_version: the hypervisor version in the form (major, minor,
2004 revision)
2005
2006 """
2007 result = self.GetLinuxNodeInfo()
2008
2009
2010
2011 _, v_major, v_min, v_rev = self._GetKVMVersion(constants.KVM_PATH)
2012 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev)
2013 return result
2014
2015 @classmethod
2017 """Return a command for connecting to the console of an instance.
2018
2019 """
2020 if hvparams[constants.HV_SERIAL_CONSOLE]:
2021 cmd = [pathutils.KVM_CONSOLE_WRAPPER,
2022 constants.SOCAT_PATH, utils.ShellQuote(instance.name),
2023 utils.ShellQuote(cls._InstanceMonitor(instance.name)),
2024 "STDIO,%s" % cls._SocatUnixConsoleParams(),
2025 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)]
2026 return objects.InstanceConsole(instance=instance.name,
2027 kind=constants.CONS_SSH,
2028 host=instance.primary_node,
2029 user=constants.SSH_CONSOLE_USER,
2030 command=cmd)
2031
2032 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
2033 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT:
2034 display = instance.network_port - constants.VNC_BASE_PORT
2035 return objects.InstanceConsole(instance=instance.name,
2036 kind=constants.CONS_VNC,
2037 host=vnc_bind_address,
2038 port=instance.network_port,
2039 display=display)
2040
2041 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2042 if spice_bind:
2043 return objects.InstanceConsole(instance=instance.name,
2044 kind=constants.CONS_SPICE,
2045 host=spice_bind,
2046 port=instance.network_port)
2047
2048 return objects.InstanceConsole(instance=instance.name,
2049 kind=constants.CONS_MESSAGE,
2050 message=("No serial shell for instance %s" %
2051 instance.name))
2052
2054 """Verify the hypervisor.
2055
2056 Check that the required binaries exist.
2057
2058 @return: Problem description if something is wrong, C{None} otherwise
2059
2060 """
2061 msgs = []
2062
2063
2064
2065 if not os.path.exists(constants.KVM_PATH):
2066 msgs.append("The KVM binary ('%s') does not exist" % constants.KVM_PATH)
2067 if not os.path.exists(constants.SOCAT_PATH):
2068 msgs.append("The socat binary ('%s') does not exist" %
2069 constants.SOCAT_PATH)
2070
2071 return self._FormatVerifyResults(msgs)
2072
2073 @classmethod
2075 """Check the given parameters for validity.
2076
2077 @type hvparams: dict
2078 @param hvparams: dictionary with parameter names/value
2079 @raise errors.HypervisorError: when a parameter is not valid
2080
2081 """
2082 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
2083
2084 kernel_path = hvparams[constants.HV_KERNEL_PATH]
2085 if kernel_path:
2086 if not hvparams[constants.HV_ROOT_PATH]:
2087 raise errors.HypervisorError("Need a root partition for the instance,"
2088 " if a kernel is defined")
2089
2090 if (hvparams[constants.HV_VNC_X509_VERIFY] and
2091 not hvparams[constants.HV_VNC_X509]):
2092 raise errors.HypervisorError("%s must be defined, if %s is" %
2093 (constants.HV_VNC_X509,
2094 constants.HV_VNC_X509_VERIFY))
2095
2096 if hvparams[constants.HV_SERIAL_CONSOLE]:
2097 serial_speed = hvparams[constants.HV_SERIAL_SPEED]
2098 valid_speeds = constants.VALID_SERIAL_SPEEDS
2099 if not serial_speed or serial_speed not in valid_speeds:
2100 raise errors.HypervisorError("Invalid serial console speed, must be"
2101 " one of: %s" %
2102 utils.CommaJoin(valid_speeds))
2103
2104 boot_order = hvparams[constants.HV_BOOT_ORDER]
2105 if (boot_order == constants.HT_BO_CDROM and
2106 not hvparams[constants.HV_CDROM_IMAGE_PATH]):
2107 raise errors.HypervisorError("Cannot boot from cdrom without an"
2108 " ISO path")
2109
2110 security_model = hvparams[constants.HV_SECURITY_MODEL]
2111 if security_model == constants.HT_SM_USER:
2112 if not hvparams[constants.HV_SECURITY_DOMAIN]:
2113 raise errors.HypervisorError("A security domain (user to run kvm as)"
2114 " must be specified")
2115 elif (security_model == constants.HT_SM_NONE or
2116 security_model == constants.HT_SM_POOL):
2117 if hvparams[constants.HV_SECURITY_DOMAIN]:
2118 raise errors.HypervisorError("Cannot have a security domain when the"
2119 " security model is 'none' or 'pool'")
2120
2121 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND]
2122 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION]
2123 if spice_bind:
2124 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED:
2125
2126
2127 if (netutils.IP4Address.IsValid(spice_bind) and
2128 spice_ip_version != constants.IP4_VERSION):
2129 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but"
2130 " the specified IP version is %s" %
2131 (spice_bind, spice_ip_version))
2132
2133 if (netutils.IP6Address.IsValid(spice_bind) and
2134 spice_ip_version != constants.IP6_VERSION):
2135 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but"
2136 " the specified IP version is %s" %
2137 (spice_bind, spice_ip_version))
2138 else:
2139
2140
2141 for param in _SPICE_ADDITIONAL_PARAMS:
2142 if hvparams[param]:
2143 raise errors.HypervisorError("SPICE: %s requires %s to be set" %
2144 (param, constants.HV_KVM_SPICE_BIND))
2145
2146 @classmethod
2196
2197 @classmethod
2199 """KVM powercycle, just a wrapper over Linux powercycle.
2200
2201 """
2202 cls.LinuxPowercycle()
2203