4 # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 from cStringIO import StringIO
29 from ganeti import constants
30 from ganeti import errors
31 from ganeti import utils
32 from ganeti.hypervisor import hv_base
33 from ganeti import netutils
34 from ganeti import objects
35 from ganeti import pathutils
36 from ganeti import vcluster
39 XEND_CONFIG_FILE = vcluster.AddNodePrefix("/etc/xen/xend-config.sxp")
40 XL_CONFIG_FILE = vcluster.AddNodePrefix("/etc/xen/xl.conf")
41 VIF_BRIDGE_SCRIPT = vcluster.AddNodePrefix("/etc/xen/scripts/vif-bridge")
42 _DOM0_NAME = "Domain-0"
45 class XenHypervisor(hv_base.BaseHypervisor):
46 """Xen generic hypervisor interface
48 This is the Xen base class used for both Xen PVM and HVM. It contains
49 all the functionality that is identical for both.
53 REBOOT_RETRY_COUNT = 60
54 REBOOT_RETRY_INTERVAL = 10
61 ANCILLARY_FILES_OPT = [
66 def _ConfigFileName(instance_name):
67 """Get the config file name for an instance.
69 @param instance_name: instance name
70 @type instance_name: str
71 @return: fully qualified path to instance config file
75 return "/etc/xen/%s" % instance_name
78 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
79 """Write the Xen config file for the instance.
82 raise NotImplementedError
85 def _WriteConfigFileStatic(instance_name, data):
86 """Write the Xen config file for the instance.
88 This version of the function just writes the config file from static data.
91 # just in case it exists
92 utils.RemoveFile("/etc/xen/auto/%s" % instance_name)
93 cfg_file = XenHypervisor._ConfigFileName(instance_name)
95 utils.WriteFile(cfg_file, data=data)
96 except EnvironmentError, err:
97 raise errors.HypervisorError("Cannot write Xen instance configuration"
98 " file %s: %s" % (cfg_file, err))
101 def _ReadConfigFile(instance_name):
102 """Returns the contents of the instance config file.
106 file_content = utils.ReadFile(
107 XenHypervisor._ConfigFileName(instance_name))
108 except EnvironmentError, err:
109 raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
113 def _RemoveConfigFile(instance_name):
114 """Remove the xen configuration file.
117 utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
120 def _CreateConfigCpus(cls, cpu_mask):
121 """Create a CPU config string that's compatible with Xen's
125 # Convert the string CPU mask to a list of list of int's
126 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
128 if len(cpu_list) == 1:
129 all_cpu_mapping = cpu_list[0]
130 if all_cpu_mapping == constants.CPU_PINNING_OFF:
131 # If CPU pinning has 1 entry that's "all", then remove the
132 # parameter from the config file
135 # If CPU pinning has one non-all entry, mapping all vCPUS (the entire
136 # VM) to one physical CPU, using format 'cpu = "C"'
137 return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
139 def _GetCPUMap(vcpu):
140 if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
141 cpu_map = constants.CPU_PINNING_ALL_XEN
143 cpu_map = ",".join(map(str, vcpu))
144 return "\"%s\"" % cpu_map
146 # build the result string in format 'cpus = [ "c", "c", "c" ]',
147 # where each c is a physical CPU number, a range, a list, or any
149 return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
152 def _RunXmList(xmlist_errors):
153 """Helper function for L{_GetXMList} to run "xm list".
156 result = utils.RunCmd([constants.XEN_CMD, "list"])
158 logging.error("xm list failed (%s): %s", result.fail_reason,
160 xmlist_errors.append(result)
161 raise utils.RetryAgain()
163 # skip over the heading
164 return result.stdout.splitlines()[1:]
167 def _GetXMList(cls, include_node):
168 """Return the list of running instances.
170 If the include_node argument is True, then we return information
171 for dom0 also, otherwise we filter that from the return value.
173 @return: list of (name, id, memory, vcpus, state, time spent)
178 lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, ))
179 except utils.RetryTimeout:
181 xmlist_result = xmlist_errors.pop()
183 errmsg = ("xm list failed, timeout exceeded (%s): %s" %
184 (xmlist_result.fail_reason, xmlist_result.output))
186 errmsg = "xm list failed"
188 raise errors.HypervisorError(errmsg)
192 # The format of lines is:
193 # Name ID Mem(MiB) VCPUs State Time(s)
194 # Domain-0 0 3418 4 r----- 266.2
197 raise errors.HypervisorError("Can't parse output of xm list,"
200 data[1] = int(data[1])
201 data[2] = int(data[2])
202 data[3] = int(data[3])
203 data[5] = float(data[5])
204 except (TypeError, ValueError), err:
205 raise errors.HypervisorError("Can't parse output of xm list,"
206 " line: %s, error: %s" % (line, err))
208 # skip the Domain-0 (optional)
209 if include_node or data[0] != _DOM0_NAME:
214 def ListInstances(self):
215 """Get the list of running instances.
218 xm_list = self._GetXMList(False)
219 names = [info[0] for info in xm_list]
222 def GetInstanceInfo(self, instance_name):
223 """Get instance properties.
225 @param instance_name: the instance name
227 @return: tuple (name, id, memory, vcpus, stat, times)
230 xm_list = self._GetXMList(instance_name == _DOM0_NAME)
233 if data[0] == instance_name:
238 def GetAllInstancesInfo(self):
239 """Get properties of all instances.
241 @return: list of tuples (name, id, memory, vcpus, stat, times)
244 xm_list = self._GetXMList(False)
247 def StartInstance(self, instance, block_devices, startup_paused):
248 """Start an instance.
251 startup_memory = self._InstanceStartupMemory(instance)
252 self._WriteConfigFile(instance, startup_memory, block_devices)
253 cmd = [constants.XEN_CMD, "create"]
256 cmd.extend([self._ConfigFileName(instance.name)])
257 result = utils.RunCmd(cmd)
260 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
261 (instance.name, result.fail_reason,
264 def StopInstance(self, instance, force=False, retry=False, name=None):
270 self._RemoveConfigFile(name)
272 command = [constants.XEN_CMD, "destroy", name]
274 command = [constants.XEN_CMD, "shutdown", name]
275 result = utils.RunCmd(command)
278 raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
279 (name, result.fail_reason, result.output))
281 def RebootInstance(self, instance):
282 """Reboot an instance.
285 ini_info = self.GetInstanceInfo(instance.name)
288 raise errors.HypervisorError("Failed to reboot instance %s,"
289 " not running" % instance.name)
291 result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
293 raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
294 (instance.name, result.fail_reason,
297 def _CheckInstance():
298 new_info = self.GetInstanceInfo(instance.name)
300 # check if the domain ID has changed or the run time has decreased
301 if (new_info is not None and
302 (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
305 raise utils.RetryAgain()
308 utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
309 self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
310 except utils.RetryTimeout:
311 raise errors.HypervisorError("Failed to reboot instance %s: instance"
312 " did not reboot in the expected interval" %
315 def BalloonInstanceMemory(self, instance, mem):
316 """Balloon an instance memory to a certain value.
318 @type instance: L{objects.Instance}
319 @param instance: instance to be accepted
321 @param mem: actual memory size to use for instance runtime
324 cmd = [constants.XEN_CMD, "mem-set", instance.name, mem]
325 result = utils.RunCmd(cmd)
327 raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
328 (instance.name, result.fail_reason,
330 cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
331 cmd.append(XenHypervisor._ConfigFileName(instance.name))
332 result = utils.RunCmd(cmd)
334 raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
335 (instance.name, result.fail_reason,
338 def GetNodeInfo(self):
339 """Return information about the node.
341 @return: a dict with the following keys (memory values in MiB):
342 - memory_total: the total memory size on the node
343 - memory_free: the available memory on the node for instances
344 - memory_dom0: the memory used by the node itself, if available
345 - nr_cpus: total number of CPUs
346 - nr_nodes: in a NUMA system, the number of domains
347 - nr_sockets: the number of physical CPU sockets in the node
348 - hv_version: the hypervisor version in the form (major, minor)
351 result = utils.RunCmd([constants.XEN_CMD, "info"])
353 logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
357 xmoutput = result.stdout.splitlines()
359 cores_per_socket = threads_per_core = nr_cpus = None
360 xen_major, xen_minor = None, None
364 for line in xmoutput:
365 splitfields = line.split(":", 1)
367 if len(splitfields) > 1:
368 key = splitfields[0].strip()
369 val = splitfields[1].strip()
371 # note: in xen 3, memory has changed to total_memory
372 if key == "memory" or key == "total_memory":
373 memory_total = int(val)
374 elif key == "free_memory":
375 memory_free = int(val)
376 elif key == "nr_cpus":
377 nr_cpus = result["cpu_total"] = int(val)
378 elif key == "nr_nodes":
379 result["cpu_nodes"] = int(val)
380 elif key == "cores_per_socket":
381 cores_per_socket = int(val)
382 elif key == "threads_per_core":
383 threads_per_core = int(val)
384 elif key == "xen_major":
386 elif key == "xen_minor":
389 if None not in [cores_per_socket, threads_per_core, nr_cpus]:
390 result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
393 for (name, _, mem, vcpus, _, _) in self._GetXMList(True):
394 if name == _DOM0_NAME:
395 result["memory_dom0"] = mem
396 result["dom0_cpus"] = vcpus
398 # Include Dom0 in total memory usage
401 if memory_free is not None:
402 result["memory_free"] = memory_free
404 if memory_total is not None:
405 result["memory_total"] = memory_total
407 # Calculate memory used by hypervisor
408 if None not in [memory_total, memory_free, total_instmem]:
409 result["memory_hv"] = memory_total - memory_free - total_instmem
411 if not (xen_major is None or xen_minor is None):
412 result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
417 def GetInstanceConsole(cls, instance, hvparams, beparams):
418 """Return a command for connecting to the console of an instance.
421 return objects.InstanceConsole(instance=instance.name,
422 kind=constants.CONS_SSH,
423 host=instance.primary_node,
424 user=constants.SSH_CONSOLE_USER,
425 command=[pathutils.XM_CONSOLE_WRAPPER,
429 """Verify the hypervisor.
431 For Xen, this verifies that the xend process is running.
434 result = utils.RunCmd([constants.XEN_CMD, "info"])
436 return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
439 def _GetConfigFileDiskData(block_devices, blockdev_prefix):
440 """Get disk directive for xen config file.
442 This method builds the xen config disk directive according to the
443 given disk_template and block_devices.
445 @param block_devices: list of tuples (cfdev, rldev):
446 - cfdev: dict containing ganeti config disk part
447 - rldev: ganeti.bdev.BlockDev object
448 @param blockdev_prefix: a string containing blockdevice prefix,
449 e.g. "sd" for /dev/sda
451 @return: string containing disk directive for xen instance config file
455 constants.FD_LOOP: "file",
456 constants.FD_BLKTAP: "tap:aio",
459 if len(block_devices) > 24:
461 raise errors.HypervisorError("Too many disks")
462 namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
463 for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
464 if cfdev.mode == constants.DISK_RDWR:
468 if cfdev.dev_type == constants.LD_FILE:
469 line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
470 dev_path, sd_name, mode)
472 line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
473 disk_data.append(line)
477 def MigrationInfo(self, instance):
478 """Get instance information to perform a migration.
480 @type instance: L{objects.Instance}
481 @param instance: instance to be migrated
483 @return: content of the xen config file
486 return self._ReadConfigFile(instance.name)
488 def AcceptInstance(self, instance, info, target):
489 """Prepare to accept an instance.
491 @type instance: L{objects.Instance}
492 @param instance: instance to be accepted
494 @param info: content of the xen config file on the source node
496 @param target: target host (usually ip), on this node
501 def FinalizeMigrationDst(self, instance, info, success):
502 """Finalize an instance migration.
504 After a successful migration we write the xen config file.
505 We do nothing on a failure, as we did not change anything at accept time.
507 @type instance: L{objects.Instance}
508 @param instance: instance whose migration is being finalized
510 @param info: content of the xen config file on the source node
511 @type success: boolean
512 @param success: whether the migration was a success or a failure
516 self._WriteConfigFileStatic(instance.name, info)
518 def MigrateInstance(self, instance, target, live):
519 """Migrate an instance to a target node.
521 The migration will not be attempted if the instance is not
524 @type instance: L{objects.Instance}
525 @param instance: the instance to be migrated
527 @param target: ip address of the target node
529 @param live: perform a live migration
532 if self.GetInstanceInfo(instance.name) is None:
533 raise errors.HypervisorError("Instance not running, cannot migrate")
535 port = instance.hvparams[constants.HV_MIGRATION_PORT]
537 if not netutils.TcpPing(target, port, live_port_needed=True):
538 raise errors.HypervisorError("Remote host %s not listening on port"
539 " %s, cannot migrate" % (target, port))
541 # FIXME: migrate must be upgraded for transitioning to "xl" (xen 4.1).
542 # This should be reworked in Ganeti 2.7
543 # ssh must recognize the key of the target host for the migration
544 args = [constants.XEN_CMD, "migrate"]
545 if constants.XEN_CMD == constants.XEN_CMD_XM:
546 args.extend(["-p", "%d" % port])
549 elif constants.XEN_CMD == constants.XEN_CMD_XL:
550 args.extend(["-C", self._ConfigFileName(instance.name)])
552 raise errors.HypervisorError("Unsupported xen command: %s" %
555 args.extend([instance.name, target])
556 result = utils.RunCmd(args)
558 raise errors.HypervisorError("Failed to migrate instance %s: %s" %
559 (instance.name, result.output))
561 def FinalizeMigrationSource(self, instance, success, live):
562 """Finalize the instance migration on the source node.
564 @type instance: L{objects.Instance}
565 @param instance: the instance that was migrated
567 @param success: whether the migration succeeded or not
569 @param live: whether the user requested a live migration or not
572 # pylint: disable=W0613
574 # remove old xen file after migration succeeded
576 self._RemoveConfigFile(instance.name)
577 except EnvironmentError:
578 logging.exception("Failure while removing instance config file")
580 def GetMigrationStatus(self, instance):
581 """Get the migration status
583 As MigrateInstance for Xen is still blocking, if this method is called it
584 means that MigrateInstance has completed successfully. So we can safely
585 assume that the migration was successful and notify this fact to the client.
587 @type instance: L{objects.Instance}
588 @param instance: the instance that is being migrated
589 @rtype: L{objects.MigrationStatus}
590 @return: the status of the current migration (one of
591 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
592 progress info that can be retrieved from the hypervisor
595 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
598 def PowercycleNode(cls):
599 """Xen-specific powercycle.
601 This first does a Linux reboot (which triggers automatically a Xen
602 reboot), and if that fails it tries to do a Xen reboot. The reason
603 we don't try a Xen reboot first is that the xen reboot launches an
604 external command which connects to the Xen hypervisor, and that
605 won't work in case the root filesystem is broken and/or the xend
606 daemon is not working.
610 cls.LinuxPowercycle()
612 utils.RunCmd([constants.XEN_CMD, "debug", "R"])
615 class XenPvmHypervisor(XenHypervisor):
616 """Xen PVM hypervisor interface"""
619 constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
620 constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
621 constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
622 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
623 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
624 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
625 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
626 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
627 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
628 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
629 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
630 constants.HV_REBOOT_BEHAVIOR:
631 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
632 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
636 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
637 """Write the Xen config file for the instance.
640 hvp = instance.hvparams
642 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
644 # if bootloader is True, use bootloader instead of kernel and ramdisk
646 if hvp[constants.HV_USE_BOOTLOADER]:
647 # bootloader handling
648 bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
650 config.write("bootloader = '%s'\n" % bootloader_path)
652 raise errors.HypervisorError("Bootloader enabled, but missing"
655 bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
657 config.write("bootargs = '%s'\n" % bootloader_args)
660 kpath = hvp[constants.HV_KERNEL_PATH]
661 config.write("kernel = '%s'\n" % kpath)
664 initrd_path = hvp[constants.HV_INITRD_PATH]
666 config.write("ramdisk = '%s'\n" % initrd_path)
668 # rest of the settings
669 config.write("memory = %d\n" % startup_memory)
670 config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
671 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
672 cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
674 config.write("%s\n" % cpu_pinning)
676 config.write("name = '%s'\n" % instance.name)
679 for nic in instance.nics:
680 nic_str = "mac=%s" % (nic.mac)
681 ip = getattr(nic, "ip", None)
683 nic_str += ", ip=%s" % ip
684 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
685 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
686 vif_data.append("'%s'" % nic_str)
688 disk_data = cls._GetConfigFileDiskData(block_devices,
689 hvp[constants.HV_BLOCKDEV_PREFIX])
691 config.write("vif = [%s]\n" % ",".join(vif_data))
692 config.write("disk = [%s]\n" % ",".join(disk_data))
694 if hvp[constants.HV_ROOT_PATH]:
695 config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
696 config.write("on_poweroff = 'destroy'\n")
697 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
698 config.write("on_reboot = 'restart'\n")
700 config.write("on_reboot = 'destroy'\n")
701 config.write("on_crash = 'restart'\n")
702 config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
703 cls._WriteConfigFileStatic(instance.name, config.getvalue())
708 class XenHvmHypervisor(XenHypervisor):
709 """Xen HVM hypervisor interface"""
711 ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
712 pathutils.VNC_PASSWORD_FILE,
714 ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
715 pathutils.VNC_PASSWORD_FILE,
719 constants.HV_ACPI: hv_base.NO_CHECK,
720 constants.HV_BOOT_ORDER: (True, ) +
721 (lambda x: x and len(x.strip("acdn")) == 0,
722 "Invalid boot order specified, must be one or more of [acdn]",
724 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
725 constants.HV_DISK_TYPE:
726 hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
727 constants.HV_NIC_TYPE:
728 hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
729 constants.HV_PAE: hv_base.NO_CHECK,
730 constants.HV_VNC_BIND_ADDRESS:
731 (False, netutils.IP4Address.IsValid,
732 "VNC bind address is not a valid IP address", None, None),
733 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
734 constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
735 constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
736 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
737 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
738 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
739 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
740 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
741 # Add PCI passthrough
742 constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
743 constants.HV_REBOOT_BEHAVIOR:
744 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
745 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
749 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
750 """Create a Xen 3.1 HVM config file.
753 hvp = instance.hvparams
756 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
759 kpath = hvp[constants.HV_KERNEL_PATH]
760 config.write("kernel = '%s'\n" % kpath)
762 config.write("builder = 'hvm'\n")
763 config.write("memory = %d\n" % startup_memory)
764 config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
765 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
766 cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
768 config.write("%s\n" % cpu_pinning)
770 config.write("name = '%s'\n" % instance.name)
771 if hvp[constants.HV_PAE]:
772 config.write("pae = 1\n")
774 config.write("pae = 0\n")
775 if hvp[constants.HV_ACPI]:
776 config.write("acpi = 1\n")
778 config.write("acpi = 0\n")
779 config.write("apic = 1\n")
780 config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
781 config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
782 config.write("sdl = 0\n")
783 config.write("usb = 1\n")
784 config.write("usbdevice = 'tablet'\n")
785 config.write("vnc = 1\n")
786 if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
787 config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
789 config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
791 if instance.network_port > constants.VNC_BASE_PORT:
792 display = instance.network_port - constants.VNC_BASE_PORT
793 config.write("vncdisplay = %s\n" % display)
794 config.write("vncunused = 0\n")
796 config.write("# vncdisplay = 1\n")
797 config.write("vncunused = 1\n")
799 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
801 password = utils.ReadFile(vnc_pwd_file)
802 except EnvironmentError, err:
803 raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
806 config.write("vncpasswd = '%s'\n" % password.rstrip())
808 config.write("serial = 'pty'\n")
809 if hvp[constants.HV_USE_LOCALTIME]:
810 config.write("localtime = 1\n")
813 nic_type = hvp[constants.HV_NIC_TYPE]
815 # ensure old instances don't change
816 nic_type_str = ", type=ioemu"
817 elif nic_type == constants.HT_NIC_PARAVIRTUAL:
818 nic_type_str = ", type=paravirtualized"
820 nic_type_str = ", model=%s, type=ioemu" % nic_type
821 for nic in instance.nics:
822 nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
823 ip = getattr(nic, "ip", None)
825 nic_str += ", ip=%s" % ip
826 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
827 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
828 vif_data.append("'%s'" % nic_str)
830 config.write("vif = [%s]\n" % ",".join(vif_data))
832 disk_data = cls._GetConfigFileDiskData(block_devices,
833 hvp[constants.HV_BLOCKDEV_PREFIX])
835 iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
837 iso = "'file:%s,hdc:cdrom,r'" % iso_path
838 disk_data.append(iso)
840 config.write("disk = [%s]\n" % (",".join(disk_data)))
841 # Add PCI passthrough
843 pci_pass = hvp[constants.HV_PASSTHROUGH]
845 pci_pass_arr = pci_pass.split(";")
846 config.write("pci = %s\n" % pci_pass_arr)
847 config.write("on_poweroff = 'destroy'\n")
848 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
849 config.write("on_reboot = 'restart'\n")
851 config.write("on_reboot = 'destroy'\n")
852 config.write("on_crash = 'restart'\n")
853 cls._WriteConfigFileStatic(instance.name, config.getvalue())