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
37 XEND_CONFIG_FILE = "/etc/xen/xend-config.sxp"
38 XL_CONFIG_FILE = "/etc/xen/xl.conf"
39 VIF_BRIDGE_SCRIPT = "/etc/xen/scripts/vif-bridge"
40 _DOM0_NAME = "Domain-0"
43 class XenHypervisor(hv_base.BaseHypervisor):
44 """Xen generic hypervisor interface
46 This is the Xen base class used for both Xen PVM and HVM. It contains
47 all the functionality that is identical for both.
51 REBOOT_RETRY_COUNT = 60
52 REBOOT_RETRY_INTERVAL = 10
59 ANCILLARY_FILES_OPT = [
64 def _ConfigFileName(instance_name):
65 """Get the config file name for an instance.
67 @param instance_name: instance name
68 @type instance_name: str
69 @return: fully qualified path to instance config file
73 return "/etc/xen/%s" % instance_name
76 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
77 """Write the Xen config file for the instance.
80 raise NotImplementedError
83 def _WriteConfigFileStatic(instance_name, data):
84 """Write the Xen config file for the instance.
86 This version of the function just writes the config file from static data.
89 # just in case it exists
90 utils.RemoveFile("/etc/xen/auto/%s" % instance_name)
91 cfg_file = XenHypervisor._ConfigFileName(instance_name)
93 utils.WriteFile(cfg_file, data=data)
94 except EnvironmentError, err:
95 raise errors.HypervisorError("Cannot write Xen instance configuration"
96 " file %s: %s" % (cfg_file, err))
99 def _ReadConfigFile(instance_name):
100 """Returns the contents of the instance config file.
104 file_content = utils.ReadFile(
105 XenHypervisor._ConfigFileName(instance_name))
106 except EnvironmentError, err:
107 raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
111 def _RemoveConfigFile(instance_name):
112 """Remove the xen configuration file.
115 utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
118 def _CreateConfigCpus(cls, cpu_mask):
119 """Create a CPU config string that's compatible with Xen's
123 # Convert the string CPU mask to a list of list of int's
124 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
126 if len(cpu_list) == 1:
127 all_cpu_mapping = cpu_list[0]
128 if all_cpu_mapping == constants.CPU_PINNING_OFF:
129 # If CPU pinning has 1 entry that's "all", then remove the
130 # parameter from the config file
133 # If CPU pinning has one non-all entry, mapping all vCPUS (the entire
134 # VM) to one physical CPU, using format 'cpu = "C"'
135 return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
137 def _GetCPUMap(vcpu):
138 if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
139 cpu_map = constants.CPU_PINNING_ALL_XEN
141 cpu_map = ",".join(map(str, vcpu))
142 return "\"%s\"" % cpu_map
144 # build the result string in format 'cpus = [ "c", "c", "c" ]',
145 # where each c is a physical CPU number, a range, a list, or any
147 return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
150 def _RunXmList(xmlist_errors):
151 """Helper function for L{_GetXMList} to run "xm list".
154 result = utils.RunCmd([constants.XEN_CMD, "list"])
156 logging.error("xm list failed (%s): %s", result.fail_reason,
158 xmlist_errors.append(result)
159 raise utils.RetryAgain()
161 # skip over the heading
162 return result.stdout.splitlines()[1:]
165 def _GetXMList(cls, include_node):
166 """Return the list of running instances.
168 If the include_node argument is True, then we return information
169 for dom0 also, otherwise we filter that from the return value.
171 @return: list of (name, id, memory, vcpus, state, time spent)
176 lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, ))
177 except utils.RetryTimeout:
179 xmlist_result = xmlist_errors.pop()
181 errmsg = ("xm list failed, timeout exceeded (%s): %s" %
182 (xmlist_result.fail_reason, xmlist_result.output))
184 errmsg = "xm list failed"
186 raise errors.HypervisorError(errmsg)
190 # The format of lines is:
191 # Name ID Mem(MiB) VCPUs State Time(s)
192 # Domain-0 0 3418 4 r----- 266.2
195 raise errors.HypervisorError("Can't parse output of xm list,"
198 data[1] = int(data[1])
199 data[2] = int(data[2])
200 data[3] = int(data[3])
201 data[5] = float(data[5])
202 except (TypeError, ValueError), err:
203 raise errors.HypervisorError("Can't parse output of xm list,"
204 " line: %s, error: %s" % (line, err))
206 # skip the Domain-0 (optional)
207 if include_node or data[0] != _DOM0_NAME:
212 def ListInstances(self):
213 """Get the list of running instances.
216 xm_list = self._GetXMList(False)
217 names = [info[0] for info in xm_list]
220 def GetInstanceInfo(self, instance_name):
221 """Get instance properties.
223 @param instance_name: the instance name
225 @return: tuple (name, id, memory, vcpus, stat, times)
228 xm_list = self._GetXMList(instance_name == _DOM0_NAME)
231 if data[0] == instance_name:
236 def GetAllInstancesInfo(self):
237 """Get properties of all instances.
239 @return: list of tuples (name, id, memory, vcpus, stat, times)
242 xm_list = self._GetXMList(False)
245 def StartInstance(self, instance, block_devices, startup_paused):
246 """Start an instance.
249 startup_memory = self._InstanceStartupMemory(instance)
250 self._WriteConfigFile(instance, startup_memory, block_devices)
251 cmd = [constants.XEN_CMD, "create"]
254 cmd.extend([self._ConfigFileName(instance.name)])
255 result = utils.RunCmd(cmd)
258 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
259 (instance.name, result.fail_reason,
262 def StopInstance(self, instance, force=False, retry=False, name=None):
268 self._RemoveConfigFile(name)
270 command = [constants.XEN_CMD, "destroy", name]
272 command = [constants.XEN_CMD, "shutdown", name]
273 result = utils.RunCmd(command)
276 raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
277 (name, result.fail_reason, result.output))
279 def RebootInstance(self, instance):
280 """Reboot an instance.
283 ini_info = self.GetInstanceInfo(instance.name)
286 raise errors.HypervisorError("Failed to reboot instance %s,"
287 " not running" % instance.name)
289 result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
291 raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
292 (instance.name, result.fail_reason,
295 def _CheckInstance():
296 new_info = self.GetInstanceInfo(instance.name)
298 # check if the domain ID has changed or the run time has decreased
299 if (new_info is not None and
300 (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
303 raise utils.RetryAgain()
306 utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
307 self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
308 except utils.RetryTimeout:
309 raise errors.HypervisorError("Failed to reboot instance %s: instance"
310 " did not reboot in the expected interval" %
313 def BalloonInstanceMemory(self, instance, mem):
314 """Balloon an instance memory to a certain value.
316 @type instance: L{objects.Instance}
317 @param instance: instance to be accepted
319 @param mem: actual memory size to use for instance runtime
322 cmd = [constants.XEN_CMD, "mem-set", instance.name, mem]
323 result = utils.RunCmd(cmd)
325 raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
326 (instance.name, result.fail_reason,
328 cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
329 cmd.append(XenHypervisor._ConfigFileName(instance.name))
330 result = utils.RunCmd(cmd)
332 raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
333 (instance.name, result.fail_reason,
336 def GetNodeInfo(self):
337 """Return information about the node.
339 @return: a dict with the following keys (memory values in MiB):
340 - memory_total: the total memory size on the node
341 - memory_free: the available memory on the node for instances
342 - memory_dom0: the memory used by the node itself, if available
343 - nr_cpus: total number of CPUs
344 - nr_nodes: in a NUMA system, the number of domains
345 - nr_sockets: the number of physical CPU sockets in the node
346 - hv_version: the hypervisor version in the form (major, minor)
349 result = utils.RunCmd([constants.XEN_CMD, "info"])
351 logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
355 xmoutput = result.stdout.splitlines()
357 cores_per_socket = threads_per_core = nr_cpus = None
358 xen_major, xen_minor = None, None
362 for line in xmoutput:
363 splitfields = line.split(":", 1)
365 if len(splitfields) > 1:
366 key = splitfields[0].strip()
367 val = splitfields[1].strip()
369 # note: in xen 3, memory has changed to total_memory
370 if key == "memory" or key == "total_memory":
371 memory_total = int(val)
372 elif key == "free_memory":
373 memory_free = int(val)
374 elif key == "nr_cpus":
375 nr_cpus = result["cpu_total"] = int(val)
376 elif key == "nr_nodes":
377 result["cpu_nodes"] = int(val)
378 elif key == "cores_per_socket":
379 cores_per_socket = int(val)
380 elif key == "threads_per_core":
381 threads_per_core = int(val)
382 elif key == "xen_major":
384 elif key == "xen_minor":
387 if None not in [cores_per_socket, threads_per_core, nr_cpus]:
388 result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
391 for (name, _, mem, vcpus, _, _) in self._GetXMList(True):
392 if name == _DOM0_NAME:
393 result["memory_dom0"] = mem
394 result["dom0_cpus"] = vcpus
396 # Include Dom0 in total memory usage
399 if memory_free is not None:
400 result["memory_free"] = memory_free
402 if memory_total is not None:
403 result["memory_total"] = memory_total
405 # Calculate memory used by hypervisor
406 if None not in [memory_total, memory_free, total_instmem]:
407 result["memory_hv"] = memory_total - memory_free - total_instmem
409 if not (xen_major is None or xen_minor is None):
410 result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
415 def GetInstanceConsole(cls, instance, hvparams, beparams):
416 """Return a command for connecting to the console of an instance.
419 return objects.InstanceConsole(instance=instance.name,
420 kind=constants.CONS_SSH,
421 host=instance.primary_node,
422 user=constants.GANETI_RUNAS,
423 command=[constants.XM_CONSOLE_WRAPPER,
427 """Verify the hypervisor.
429 For Xen, this verifies that the xend process is running.
432 result = utils.RunCmd([constants.XEN_CMD, "info"])
434 return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
437 def _GetConfigFileDiskData(block_devices, blockdev_prefix):
438 """Get disk directive for xen config file.
440 This method builds the xen config disk directive according to the
441 given disk_template and block_devices.
443 @param block_devices: list of tuples (cfdev, rldev):
444 - cfdev: dict containing ganeti config disk part
445 - rldev: ganeti.bdev.BlockDev object
446 @param blockdev_prefix: a string containing blockdevice prefix,
447 e.g. "sd" for /dev/sda
449 @return: string containing disk directive for xen instance config file
453 constants.FD_LOOP: "file",
454 constants.FD_BLKTAP: "tap:aio",
457 if len(block_devices) > 24:
459 raise errors.HypervisorError("Too many disks")
460 namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
461 for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
462 if cfdev.mode == constants.DISK_RDWR:
466 if cfdev.dev_type == constants.LD_FILE:
467 line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
468 dev_path, sd_name, mode)
470 line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
471 disk_data.append(line)
475 def MigrationInfo(self, instance):
476 """Get instance information to perform a migration.
478 @type instance: L{objects.Instance}
479 @param instance: instance to be migrated
481 @return: content of the xen config file
484 return self._ReadConfigFile(instance.name)
486 def AcceptInstance(self, instance, info, target):
487 """Prepare to accept an instance.
489 @type instance: L{objects.Instance}
490 @param instance: instance to be accepted
492 @param info: content of the xen config file on the source node
494 @param target: target host (usually ip), on this node
499 def FinalizeMigrationDst(self, instance, info, success):
500 """Finalize an instance migration.
502 After a successful migration we write the xen config file.
503 We do nothing on a failure, as we did not change anything at accept time.
505 @type instance: L{objects.Instance}
506 @param instance: instance whose migration is being finalized
508 @param info: content of the xen config file on the source node
509 @type success: boolean
510 @param success: whether the migration was a success or a failure
514 self._WriteConfigFileStatic(instance.name, info)
516 def MigrateInstance(self, instance, target, live):
517 """Migrate an instance to a target node.
519 The migration will not be attempted if the instance is not
522 @type instance: L{objects.Instance}
523 @param instance: the instance to be migrated
525 @param target: ip address of the target node
527 @param live: perform a live migration
530 if self.GetInstanceInfo(instance.name) is None:
531 raise errors.HypervisorError("Instance not running, cannot migrate")
533 port = instance.hvparams[constants.HV_MIGRATION_PORT]
535 if not netutils.TcpPing(target, port, live_port_needed=True):
536 raise errors.HypervisorError("Remote host %s not listening on port"
537 " %s, cannot migrate" % (target, port))
539 # FIXME: migrate must be upgraded for transitioning to "xl" (xen 4.1).
540 # This should be reworked in Ganeti 2.7
541 # ssh must recognize the key of the target host for the migration
542 args = [constants.XEN_CMD, "migrate"]
543 if constants.XEN_CMD == constants.XEN_CMD_XM:
544 args.extend(["-p", "%d" % port])
547 elif constants.XEN_CMD == constants.XEN_CMD_XL:
548 args.extend(["-C", self._ConfigFileName(instance.name)])
550 raise errors.HypervisorError("Unsupported xen command: %s" %
553 args.extend([instance.name, target])
554 result = utils.RunCmd(args)
556 raise errors.HypervisorError("Failed to migrate instance %s: %s" %
557 (instance.name, result.output))
559 def FinalizeMigrationSource(self, instance, success, live):
560 """Finalize the instance migration on the source node.
562 @type instance: L{objects.Instance}
563 @param instance: the instance that was migrated
565 @param success: whether the migration succeeded or not
567 @param live: whether the user requested a live migration or not
570 # pylint: disable=W0613
572 # remove old xen file after migration succeeded
574 self._RemoveConfigFile(instance.name)
575 except EnvironmentError:
576 logging.exception("Failure while removing instance config file")
578 def GetMigrationStatus(self, instance):
579 """Get the migration status
581 As MigrateInstance for Xen is still blocking, if this method is called it
582 means that MigrateInstance has completed successfully. So we can safely
583 assume that the migration was successful and notify this fact to the client.
585 @type instance: L{objects.Instance}
586 @param instance: the instance that is being migrated
587 @rtype: L{objects.MigrationStatus}
588 @return: the status of the current migration (one of
589 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
590 progress info that can be retrieved from the hypervisor
593 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
596 def PowercycleNode(cls):
597 """Xen-specific powercycle.
599 This first does a Linux reboot (which triggers automatically a Xen
600 reboot), and if that fails it tries to do a Xen reboot. The reason
601 we don't try a Xen reboot first is that the xen reboot launches an
602 external command which connects to the Xen hypervisor, and that
603 won't work in case the root filesystem is broken and/or the xend
604 daemon is not working.
608 cls.LinuxPowercycle()
610 utils.RunCmd([constants.XEN_CMD, "debug", "R"])
613 class XenPvmHypervisor(XenHypervisor):
614 """Xen PVM hypervisor interface"""
617 constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
618 constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
619 constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
620 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
621 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
622 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
623 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
624 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
625 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
626 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
627 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
628 constants.HV_REBOOT_BEHAVIOR:
629 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
630 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
634 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
635 """Write the Xen config file for the instance.
638 hvp = instance.hvparams
640 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
642 # if bootloader is True, use bootloader instead of kernel and ramdisk
644 if hvp[constants.HV_USE_BOOTLOADER]:
645 # bootloader handling
646 bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
648 config.write("bootloader = '%s'\n" % bootloader_path)
650 raise errors.HypervisorError("Bootloader enabled, but missing"
653 bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
655 config.write("bootargs = '%s'\n" % bootloader_args)
658 kpath = hvp[constants.HV_KERNEL_PATH]
659 config.write("kernel = '%s'\n" % kpath)
662 initrd_path = hvp[constants.HV_INITRD_PATH]
664 config.write("ramdisk = '%s'\n" % initrd_path)
666 # rest of the settings
667 config.write("memory = %d\n" % startup_memory)
668 config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
669 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
670 cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
672 config.write("%s\n" % cpu_pinning)
674 config.write("name = '%s'\n" % instance.name)
677 for nic in instance.nics:
678 nic_str = "mac=%s" % (nic.mac)
679 ip = getattr(nic, "ip", None)
681 nic_str += ", ip=%s" % ip
682 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
683 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
684 vif_data.append("'%s'" % nic_str)
686 disk_data = cls._GetConfigFileDiskData(block_devices,
687 hvp[constants.HV_BLOCKDEV_PREFIX])
689 config.write("vif = [%s]\n" % ",".join(vif_data))
690 config.write("disk = [%s]\n" % ",".join(disk_data))
692 if hvp[constants.HV_ROOT_PATH]:
693 config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
694 config.write("on_poweroff = 'destroy'\n")
695 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
696 config.write("on_reboot = 'restart'\n")
698 config.write("on_reboot = 'destroy'\n")
699 config.write("on_crash = 'restart'\n")
700 config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
701 cls._WriteConfigFileStatic(instance.name, config.getvalue())
706 class XenHvmHypervisor(XenHypervisor):
707 """Xen HVM hypervisor interface"""
709 ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
710 constants.VNC_PASSWORD_FILE,
712 ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
713 constants.VNC_PASSWORD_FILE,
717 constants.HV_ACPI: hv_base.NO_CHECK,
718 constants.HV_BOOT_ORDER: (True, ) +
719 (lambda x: x and len(x.strip("acdn")) == 0,
720 "Invalid boot order specified, must be one or more of [acdn]",
722 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
723 constants.HV_DISK_TYPE:
724 hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
725 constants.HV_NIC_TYPE:
726 hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
727 constants.HV_PAE: hv_base.NO_CHECK,
728 constants.HV_VNC_BIND_ADDRESS:
729 (False, netutils.IP4Address.IsValid,
730 "VNC bind address is not a valid IP address", None, None),
731 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
732 constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
733 constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
734 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
735 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
736 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
737 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
738 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
739 # Add PCI passthrough
740 constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
741 constants.HV_REBOOT_BEHAVIOR:
742 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
743 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
747 def _WriteConfigFile(cls, instance, startup_memory, block_devices):
748 """Create a Xen 3.1 HVM config file.
751 hvp = instance.hvparams
754 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
757 kpath = hvp[constants.HV_KERNEL_PATH]
758 config.write("kernel = '%s'\n" % kpath)
760 config.write("builder = 'hvm'\n")
761 config.write("memory = %d\n" % startup_memory)
762 config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
763 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
764 cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
766 config.write("%s\n" % cpu_pinning)
768 config.write("name = '%s'\n" % instance.name)
769 if hvp[constants.HV_PAE]:
770 config.write("pae = 1\n")
772 config.write("pae = 0\n")
773 if hvp[constants.HV_ACPI]:
774 config.write("acpi = 1\n")
776 config.write("acpi = 0\n")
777 config.write("apic = 1\n")
778 config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
779 config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
780 config.write("sdl = 0\n")
781 config.write("usb = 1\n")
782 config.write("usbdevice = 'tablet'\n")
783 config.write("vnc = 1\n")
784 if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
785 config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
787 config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
789 if instance.network_port > constants.VNC_BASE_PORT:
790 display = instance.network_port - constants.VNC_BASE_PORT
791 config.write("vncdisplay = %s\n" % display)
792 config.write("vncunused = 0\n")
794 config.write("# vncdisplay = 1\n")
795 config.write("vncunused = 1\n")
797 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
799 password = utils.ReadFile(vnc_pwd_file)
800 except EnvironmentError, err:
801 raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
804 config.write("vncpasswd = '%s'\n" % password.rstrip())
806 config.write("serial = 'pty'\n")
807 if hvp[constants.HV_USE_LOCALTIME]:
808 config.write("localtime = 1\n")
811 nic_type = hvp[constants.HV_NIC_TYPE]
813 # ensure old instances don't change
814 nic_type_str = ", type=ioemu"
815 elif nic_type == constants.HT_NIC_PARAVIRTUAL:
816 nic_type_str = ", type=paravirtualized"
818 nic_type_str = ", model=%s, type=ioemu" % nic_type
819 for nic in instance.nics:
820 nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
821 ip = getattr(nic, "ip", None)
823 nic_str += ", ip=%s" % ip
824 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
825 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
826 vif_data.append("'%s'" % nic_str)
828 config.write("vif = [%s]\n" % ",".join(vif_data))
830 disk_data = cls._GetConfigFileDiskData(block_devices,
831 hvp[constants.HV_BLOCKDEV_PREFIX])
833 iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
835 iso = "'file:%s,hdc:cdrom,r'" % iso_path
836 disk_data.append(iso)
838 config.write("disk = [%s]\n" % (",".join(disk_data)))
839 # Add PCI passthrough
841 pci_pass = hvp[constants.HV_PASSTHROUGH]
843 pci_pass_arr = pci_pass.split(";")
844 config.write("pci = %s\n" % pci_pass_arr)
845 config.write("on_poweroff = 'destroy'\n")
846 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
847 config.write("on_reboot = 'restart'\n")
849 config.write("on_reboot = 'destroy'\n")
850 config.write("on_crash = 'restart'\n")
851 cls._WriteConfigFileStatic(instance.name, config.getvalue())