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 ssconf
38 XEND_CONFIG_FILE = "/etc/xen/xend-config.sxp"
39 XL_CONFIG_FILE = "/etc/xen/xl.conf"
40 VIF_BRIDGE_SCRIPT = "/etc/xen/scripts/vif-bridge"
41 _DOM0_NAME = "Domain-0"
44 class XenHypervisor(hv_base.BaseHypervisor):
45 """Xen generic hypervisor interface
47 This is the Xen base class used for both Xen PVM and HVM. It contains
48 all the functionality that is identical for both.
52 REBOOT_RETRY_COUNT = 60
53 REBOOT_RETRY_INTERVAL = 10
60 ANCILLARY_FILES_OPT = [
65 def _ConfigFileName(instance_name):
66 """Get the config file name for an instance.
68 @param instance_name: instance name
69 @type instance_name: str
70 @return: fully qualified path to instance config file
74 return "/etc/xen/%s" % instance_name
77 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
78 """Write the Xen config file for the instance.
81 raise NotImplementedError
84 def _WriteConfigFileStatic(instance_name, data):
85 """Write the Xen config file for the instance.
87 This version of the function just writes the config file from static data.
90 # just in case it exists
91 utils.RemoveFile("/etc/xen/auto/%s" % instance_name)
92 cfg_file = XenHypervisor._ConfigFileName(instance_name)
94 utils.WriteFile(cfg_file, data=data)
95 except EnvironmentError, err:
96 raise errors.HypervisorError("Cannot write Xen instance configuration"
97 " file %s: %s" % (cfg_file, err))
100 def _ReadConfigFile(instance_name):
101 """Returns the contents of the instance config file.
105 file_content = utils.ReadFile(
106 XenHypervisor._ConfigFileName(instance_name))
107 except EnvironmentError, err:
108 raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
112 def _RemoveConfigFile(instance_name):
113 """Remove the xen configuration file.
116 utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
119 def _CreateConfigCpus(cls, cpu_mask):
120 """Create a CPU config string that's compatible with Xen's
124 # Convert the string CPU mask to a list of list of int's
125 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
127 if len(cpu_list) == 1:
128 all_cpu_mapping = cpu_list[0]
129 if all_cpu_mapping == constants.CPU_PINNING_OFF:
130 # If CPU pinning has 1 entry that's "all", then remove the
131 # parameter from the config file
134 # If CPU pinning has one non-all entry, mapping all vCPUS (the entire
135 # VM) to one physical CPU, using format 'cpu = "C"'
136 return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
138 def _GetCPUMap(vcpu):
139 if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
140 cpu_map = constants.CPU_PINNING_ALL_XEN
142 cpu_map = ",".join(map(str, vcpu))
143 return "\"%s\"" % cpu_map
145 # build the result string in format 'cpus = [ "c", "c", "c" ]',
146 # where each c is a physical CPU number, a range, a list, or any
148 return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
151 def _RunXmList(xmlist_errors):
152 """Helper function for L{_GetXMList} to run "xm list".
155 result = utils.RunCmd([constants.XEN_CMD, "list"])
157 logging.error("xm list failed (%s): %s", result.fail_reason,
159 xmlist_errors.append(result)
160 raise utils.RetryAgain()
162 # skip over the heading
163 return result.stdout.splitlines()[1:]
166 def _GetXMList(cls, include_node):
167 """Return the list of running instances.
169 If the include_node argument is True, then we return information
170 for dom0 also, otherwise we filter that from the return value.
172 @return: list of (name, id, memory, vcpus, state, time spent)
177 lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, ))
178 except utils.RetryTimeout:
180 xmlist_result = xmlist_errors.pop()
182 errmsg = ("xm list failed, timeout exceeded (%s): %s" %
183 (xmlist_result.fail_reason, xmlist_result.output))
185 errmsg = "xm list failed"
187 raise errors.HypervisorError(errmsg)
191 # The format of lines is:
192 # Name ID Mem(MiB) VCPUs State Time(s)
193 # Domain-0 0 3418 4 r----- 266.2
196 raise errors.HypervisorError("Can't parse output of xm list,"
199 data[1] = int(data[1])
200 data[2] = int(data[2])
201 data[3] = int(data[3])
202 data[5] = float(data[5])
203 except (TypeError, ValueError), err:
204 raise errors.HypervisorError("Can't parse output of xm list,"
205 " line: %s, error: %s" % (line, err))
207 # skip the Domain-0 (optional)
208 if include_node or data[0] != _DOM0_NAME:
213 def ListInstances(self):
214 """Get the list of running instances.
217 xm_list = self._GetXMList(False)
218 names = [info[0] for info in xm_list]
221 def GetInstanceInfo(self, instance_name):
222 """Get instance properties.
224 @param instance_name: the instance name
226 @return: tuple (name, id, memory, vcpus, stat, times)
229 xm_list = self._GetXMList(instance_name == _DOM0_NAME)
232 if data[0] == instance_name:
237 def GetAllInstancesInfo(self):
238 """Get properties of all instances.
240 @return: list of tuples (name, id, memory, vcpus, stat, times)
243 xm_list = self._GetXMList(False)
246 def StartInstance(self, instance, block_devices, startup_paused):
247 """Start an instance.
250 startup_memory = self._InstanceStartupMemory(instance)
251 self._WriteConfigFile(instance, startup_memory, block_devices)
252 cmd = [constants.XEN_CMD, "create"]
255 cmd.extend([self._ConfigFileName(instance.name)])
256 result = utils.RunCmd(cmd)
259 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
260 (instance.name, result.fail_reason,
263 def StopInstance(self, instance, force=False, retry=False, name=None):
269 self._RemoveConfigFile(name)
271 command = [constants.XEN_CMD, "destroy", name]
273 command = [constants.XEN_CMD, "shutdown", name]
274 result = utils.RunCmd(command)
277 raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
278 (name, result.fail_reason, result.output))
280 def RebootInstance(self, instance):
281 """Reboot an instance.
284 ini_info = self.GetInstanceInfo(instance.name)
287 raise errors.HypervisorError("Failed to reboot instance %s,"
288 " not running" % instance.name)
290 result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
292 raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
293 (instance.name, result.fail_reason,
296 def _CheckInstance():
297 new_info = self.GetInstanceInfo(instance.name)
299 # check if the domain ID has changed or the run time has decreased
300 if (new_info is not None and
301 (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
304 raise utils.RetryAgain()
307 utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
308 self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
309 except utils.RetryTimeout:
310 raise errors.HypervisorError("Failed to reboot instance %s: instance"
311 " did not reboot in the expected interval" %
314 def BalloonInstanceMemory(self, instance, mem):
315 """Balloon an instance memory to a certain value.
317 @type instance: L{objects.Instance}
318 @param instance: instance to be accepted
320 @param mem: actual memory size to use for instance runtime
323 cmd = [constants.XEN_CMD, "mem-set", instance.name, mem]
324 result = utils.RunCmd(cmd)
326 raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
327 (instance.name, result.fail_reason,
329 cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
330 cmd.append(XenHypervisor._ConfigFileName(instance.name))
331 result = utils.RunCmd(cmd)
333 raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
334 (instance.name, result.fail_reason,
337 def GetNodeInfo(self):
338 """Return information about the node.
340 @return: a dict with the following keys (memory values in MiB):
341 - memory_total: the total memory size on the node
342 - memory_free: the available memory on the node for instances
343 - memory_dom0: the memory used by the node itself, if available
344 - nr_cpus: total number of CPUs
345 - nr_nodes: in a NUMA system, the number of domains
346 - nr_sockets: the number of physical CPU sockets in the node
347 - hv_version: the hypervisor version in the form (major, minor)
350 result = utils.RunCmd([constants.XEN_CMD, "info"])
352 logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
356 xmoutput = result.stdout.splitlines()
358 cores_per_socket = threads_per_core = nr_cpus = None
359 xen_major, xen_minor = None, None
363 for line in xmoutput:
364 splitfields = line.split(":", 1)
366 if len(splitfields) > 1:
367 key = splitfields[0].strip()
368 val = splitfields[1].strip()
370 # note: in xen 3, memory has changed to total_memory
371 if key == "memory" or key == "total_memory":
372 memory_total = int(val)
373 elif key == "free_memory":
374 memory_free = int(val)
375 elif key == "nr_cpus":
376 nr_cpus = result["cpu_total"] = int(val)
377 elif key == "nr_nodes":
378 result["cpu_nodes"] = int(val)
379 elif key == "cores_per_socket":
380 cores_per_socket = int(val)
381 elif key == "threads_per_core":
382 threads_per_core = int(val)
383 elif key == "xen_major":
385 elif key == "xen_minor":
388 if None not in [cores_per_socket, threads_per_core, nr_cpus]:
389 result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
392 for (name, _, mem, vcpus, _, _) in self._GetXMList(True):
393 if name == _DOM0_NAME:
394 result["memory_dom0"] = mem
395 result["dom0_cpus"] = vcpus
397 # Include Dom0 in total memory usage
400 if memory_free is not None:
401 result["memory_free"] = memory_free
403 if memory_total is not None:
404 result["memory_total"] = memory_total
406 # Calculate memory used by hypervisor
407 if None not in [memory_total, memory_free, total_instmem]:
408 result["memory_hv"] = memory_total - memory_free - total_instmem
410 if not (xen_major is None or xen_minor is None):
411 result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
416 def GetInstanceConsole(cls, instance, hvparams, beparams):
417 """Return a command for connecting to the console of an instance.
420 return objects.InstanceConsole(instance=instance.name,
421 kind=constants.CONS_SSH,
422 host=instance.primary_node,
423 user=constants.GANETI_RUNAS,
424 command=[constants.XEN_CONSOLE_WRAPPER,
425 constants.XEN_CMD, instance.name])
428 """Verify the hypervisor.
430 For Xen, this verifies that the xend process is running.
433 result = utils.RunCmd([constants.XEN_CMD, "info"])
435 return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
438 def _GetConfigFileDiskData(block_devices, blockdev_prefix):
439 """Get disk directive for xen config file.
441 This method builds the xen config disk directive according to the
442 given disk_template and block_devices.
444 @param block_devices: list of tuples (cfdev, rldev):
445 - cfdev: dict containing ganeti config disk part
446 - rldev: ganeti.bdev.BlockDev object
447 @param blockdev_prefix: a string containing blockdevice prefix,
448 e.g. "sd" for /dev/sda
450 @return: string containing disk directive for xen instance config file
454 constants.FD_LOOP: "file",
455 constants.FD_BLKTAP: "tap:aio",
458 if len(block_devices) > 24:
460 raise errors.HypervisorError("Too many disks")
461 namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
462 for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
463 if cfdev.mode == constants.DISK_RDWR:
467 if cfdev.dev_type == constants.LD_FILE:
468 line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
469 dev_path, sd_name, mode)
471 line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
472 disk_data.append(line)
476 def MigrationInfo(self, instance):
477 """Get instance information to perform a migration.
479 @type instance: L{objects.Instance}
480 @param instance: instance to be migrated
482 @return: content of the xen config file
485 return self._ReadConfigFile(instance.name)
487 def AcceptInstance(self, instance, info, target):
488 """Prepare to accept an instance.
490 @type instance: L{objects.Instance}
491 @param instance: instance to be accepted
493 @param info: content of the xen config file on the source node
495 @param target: target host (usually ip), on this node
500 def FinalizeMigrationDst(self, instance, info, success):
501 """Finalize an instance migration.
503 After a successful migration we write the xen config file.
504 We do nothing on a failure, as we did not change anything at accept time.
506 @type instance: L{objects.Instance}
507 @param instance: instance whose migration is being finalized
509 @param info: content of the xen config file on the source node
510 @type success: boolean
511 @param success: whether the migration was a success or a failure
515 self._WriteConfigFileStatic(instance.name, info)
517 def MigrateInstance(self, instance, target, live):
518 """Migrate an instance to a target node.
520 The migration will not be attempted if the instance is not
523 @type instance: L{objects.Instance}
524 @param instance: the instance to be migrated
526 @param target: ip address of the target node
528 @param live: perform a live migration
531 if self.GetInstanceInfo(instance.name) is None:
532 raise errors.HypervisorError("Instance not running, cannot migrate")
534 port = instance.hvparams[constants.HV_MIGRATION_PORT]
536 if (constants.XEN_CMD == constants.XEN_CMD_XM and
537 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 cluster_name = ssconf.SimpleStore().GetClusterName()
551 args.extend(["-s", constants.XL_SSH_CMD % cluster_name])
552 args.extend(["-C", self._ConfigFileName(instance.name)])
554 raise errors.HypervisorError("Unsupported xen command: %s" %
557 args.extend([instance.name, target])
558 result = utils.RunCmd(args)
560 raise errors.HypervisorError("Failed to migrate instance %s: %s" %
561 (instance.name, result.output))
563 def FinalizeMigrationSource(self, instance, success, live):
564 """Finalize the instance migration on the source node.
566 @type instance: L{objects.Instance}
567 @param instance: the instance that was migrated
569 @param success: whether the migration succeeded or not
571 @param live: whether the user requested a live migration or not
574 # pylint: disable=W0613
576 # remove old xen file after migration succeeded
578 self._RemoveConfigFile(instance.name)
579 except EnvironmentError:
580 logging.exception("Failure while removing instance config file")
582 def GetMigrationStatus(self, instance):
583 """Get the migration status
585 As MigrateInstance for Xen is still blocking, if this method is called it
586 means that MigrateInstance has completed successfully. So we can safely
587 assume that the migration was successful and notify this fact to the client.
589 @type instance: L{objects.Instance}
590 @param instance: the instance that is being migrated
591 @rtype: L{objects.MigrationStatus}
592 @return: the status of the current migration (one of
593 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
594 progress info that can be retrieved from the hypervisor
597 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
600 def PowercycleNode(cls):
601 """Xen-specific powercycle.
603 This first does a Linux reboot (which triggers automatically a Xen
604 reboot), and if that fails it tries to do a Xen reboot. The reason
605 we don't try a Xen reboot first is that the xen reboot launches an
606 external command which connects to the Xen hypervisor, and that
607 won't work in case the root filesystem is broken and/or the xend
608 daemon is not working.
612 cls.LinuxPowercycle()
614 utils.RunCmd([constants.XEN_CMD, "debug", "R"])
617 class XenPvmHypervisor(XenHypervisor):
618 """Xen PVM hypervisor interface"""
621 constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
622 constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
623 constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
624 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
625 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
626 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
627 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
628 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
629 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
630 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
631 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
632 constants.HV_REBOOT_BEHAVIOR:
633 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
634 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
638 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
639 """Write the Xen config file for the instance.
642 hvp = instance.hvparams
644 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
646 # if bootloader is True, use bootloader instead of kernel and ramdisk
648 if hvp[constants.HV_USE_BOOTLOADER]:
649 # bootloader handling
650 bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
652 config.write("bootloader = '%s'\n" % bootloader_path)
654 raise errors.HypervisorError("Bootloader enabled, but missing"
657 bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
659 config.write("bootargs = '%s'\n" % bootloader_args)
662 kpath = hvp[constants.HV_KERNEL_PATH]
663 config.write("kernel = '%s'\n" % kpath)
666 initrd_path = hvp[constants.HV_INITRD_PATH]
668 config.write("ramdisk = '%s'\n" % initrd_path)
670 # rest of the settings
671 config.write("memory = %d\n" % startup_memory)
672 config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
673 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
674 cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
676 config.write("%s\n" % cpu_pinning)
678 config.write("name = '%s'\n" % instance.name)
681 for nic in instance.nics:
682 nic_str = "mac=%s" % (nic.mac)
683 ip = getattr(nic, "ip", None)
685 nic_str += ", ip=%s" % ip
686 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
687 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
688 vif_data.append("'%s'" % nic_str)
690 disk_data = cls._GetConfigFileDiskData(block_devices,
691 hvp[constants.HV_BLOCKDEV_PREFIX])
693 config.write("vif = [%s]\n" % ",".join(vif_data))
694 config.write("disk = [%s]\n" % ",".join(disk_data))
696 if hvp[constants.HV_ROOT_PATH]:
697 config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
698 config.write("on_poweroff = 'destroy'\n")
699 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
700 config.write("on_reboot = 'restart'\n")
702 config.write("on_reboot = 'destroy'\n")
703 config.write("on_crash = 'restart'\n")
704 config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
705 cls._WriteConfigFileStatic(instance.name, config.getvalue())
710 class XenHvmHypervisor(XenHypervisor):
711 """Xen HVM hypervisor interface"""
713 ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
714 constants.VNC_PASSWORD_FILE,
716 ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
717 constants.VNC_PASSWORD_FILE,
721 constants.HV_ACPI: hv_base.NO_CHECK,
722 constants.HV_BOOT_ORDER: (True, ) +
723 (lambda x: x and len(x.strip("acdn")) == 0,
724 "Invalid boot order specified, must be one or more of [acdn]",
726 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
727 constants.HV_DISK_TYPE:
728 hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
729 constants.HV_NIC_TYPE:
730 hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
731 constants.HV_PAE: hv_base.NO_CHECK,
732 constants.HV_VNC_BIND_ADDRESS:
733 (False, netutils.IP4Address.IsValid,
734 "VNC bind address is not a valid IP address", None, None),
735 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
736 constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
737 constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
738 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
739 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
740 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
741 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
742 constants.HV_BLOCKDEV_PREFIX: 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)))
842 config.write("on_poweroff = 'destroy'\n")
843 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
844 config.write("on_reboot = 'restart'\n")
846 config.write("on_reboot = 'destroy'\n")
847 config.write("on_crash = 'restart'\n")
848 cls._WriteConfigFileStatic(instance.name, config.getvalue())