1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Xen hypervisors
23
24 """
25
26 import logging
27 from cStringIO import StringIO
28
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 ssconf
37
38
39 XEND_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xend-config.sxp")
40 XL_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xen/xl.conf")
41 VIF_BRIDGE_SCRIPT = utils.PathJoin(pathutils.XEN_CONFIG_DIR,
42 "scripts/vif-bridge")
43 _DOM0_NAME = "Domain-0"
47 """Create a CPU config string for Xen's config file.
48
49 """
50
51 cpu_list = utils.ParseMultiCpuMask(cpu_mask)
52
53 if len(cpu_list) == 1:
54 all_cpu_mapping = cpu_list[0]
55 if all_cpu_mapping == constants.CPU_PINNING_OFF:
56
57
58 return None
59 else:
60
61
62 return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
63 else:
64
65 def _GetCPUMap(vcpu):
66 if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
67 cpu_map = constants.CPU_PINNING_ALL_XEN
68 else:
69 cpu_map = ",".join(map(str, vcpu))
70 return "\"%s\"" % cpu_map
71
72
73
74
75 return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
76
79 """Xen generic hypervisor interface
80
81 This is the Xen base class used for both Xen PVM and HVM. It contains
82 all the functionality that is identical for both.
83
84 """
85 CAN_MIGRATE = True
86 REBOOT_RETRY_COUNT = 60
87 REBOOT_RETRY_INTERVAL = 10
88
89 ANCILLARY_FILES = [
90 XEND_CONFIG_FILE,
91 XL_CONFIG_FILE,
92 VIF_BRIDGE_SCRIPT,
93 ]
94 ANCILLARY_FILES_OPT = [
95 XL_CONFIG_FILE,
96 ]
97
98 @staticmethod
100 """Get the config file name for an instance.
101
102 @param instance_name: instance name
103 @type instance_name: str
104 @return: fully qualified path to instance config file
105 @rtype: str
106
107 """
108 return utils.PathJoin(pathutils.XEN_CONFIG_DIR, instance_name)
109
110 @classmethod
112 """Write the Xen config file for the instance.
113
114 """
115 raise NotImplementedError
116
117 @staticmethod
119 """Write the Xen config file for the instance.
120
121 This version of the function just writes the config file from static data.
122
123 """
124
125 utils.RemoveFile(utils.PathJoin(pathutils.XEN_CONFIG_DIR, "auto",
126 instance_name))
127
128 cfg_file = XenHypervisor._ConfigFileName(instance_name)
129 try:
130 utils.WriteFile(cfg_file, data=data)
131 except EnvironmentError, err:
132 raise errors.HypervisorError("Cannot write Xen instance configuration"
133 " file %s: %s" % (cfg_file, err))
134
135 @staticmethod
137 """Returns the contents of the instance config file.
138
139 """
140 filename = XenHypervisor._ConfigFileName(instance_name)
141
142 try:
143 file_content = utils.ReadFile(filename)
144 except EnvironmentError, err:
145 raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
146
147 return file_content
148
149 @staticmethod
155
156 @staticmethod
158 """Helper function for L{_GetXMList} to run "xm list".
159
160 """
161 result = utils.RunCmd([constants.XEN_CMD, "list"])
162 if result.failed:
163 logging.error("xm list failed (%s): %s", result.fail_reason,
164 result.output)
165 xmlist_errors.append(result)
166 raise utils.RetryAgain()
167
168
169 return result.stdout.splitlines()[1:]
170
171 @classmethod
173 """Return the list of running instances.
174
175 If the include_node argument is True, then we return information
176 for dom0 also, otherwise we filter that from the return value.
177
178 @return: list of (name, id, memory, vcpus, state, time spent)
179
180 """
181 xmlist_errors = []
182 try:
183 lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, ))
184 except utils.RetryTimeout:
185 if xmlist_errors:
186 xmlist_result = xmlist_errors.pop()
187
188 errmsg = ("xm list failed, timeout exceeded (%s): %s" %
189 (xmlist_result.fail_reason, xmlist_result.output))
190 else:
191 errmsg = "xm list failed"
192
193 raise errors.HypervisorError(errmsg)
194
195 result = []
196 for line in lines:
197
198
199
200 data = line.split()
201 if len(data) != 6:
202 raise errors.HypervisorError("Can't parse output of xm list,"
203 " line: %s" % line)
204 try:
205 data[1] = int(data[1])
206 data[2] = int(data[2])
207 data[3] = int(data[3])
208 data[5] = float(data[5])
209 except (TypeError, ValueError), err:
210 raise errors.HypervisorError("Can't parse output of xm list,"
211 " line: %s, error: %s" % (line, err))
212
213
214 if include_node or data[0] != _DOM0_NAME:
215 result.append(data)
216
217 return result
218
220 """Get the list of running instances.
221
222 """
223 xm_list = self._GetXMList(False)
224 names = [info[0] for info in xm_list]
225 return names
226
228 """Get instance properties.
229
230 @param instance_name: the instance name
231
232 @return: tuple (name, id, memory, vcpus, stat, times)
233
234 """
235 xm_list = self._GetXMList(instance_name == _DOM0_NAME)
236 result = None
237 for data in xm_list:
238 if data[0] == instance_name:
239 result = data
240 break
241 return result
242
244 """Get properties of all instances.
245
246 @return: list of tuples (name, id, memory, vcpus, stat, times)
247
248 """
249 xm_list = self._GetXMList(False)
250 return xm_list
251
252 - def StartInstance(self, instance, block_devices, startup_paused):
268
269 - def StopInstance(self, instance, force=False, retry=False, name=None):
288
314
315 try:
316 utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
317 self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
318 except utils.RetryTimeout:
319 raise errors.HypervisorError("Failed to reboot instance %s: instance"
320 " did not reboot in the expected interval" %
321 (instance.name, ))
322
345
347 """Return information about the node.
348
349 @return: a dict with the following keys (memory values in MiB):
350 - memory_total: the total memory size on the node
351 - memory_free: the available memory on the node for instances
352 - memory_dom0: the memory used by the node itself, if available
353 - nr_cpus: total number of CPUs
354 - nr_nodes: in a NUMA system, the number of domains
355 - nr_sockets: the number of physical CPU sockets in the node
356 - hv_version: the hypervisor version in the form (major, minor)
357
358 """
359 result = utils.RunCmd([constants.XEN_CMD, "info"])
360 if result.failed:
361 logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
362 result.output)
363 return None
364
365 xmoutput = result.stdout.splitlines()
366 result = {}
367 cores_per_socket = threads_per_core = nr_cpus = None
368 xen_major, xen_minor = None, None
369 memory_total = None
370 memory_free = None
371
372 for line in xmoutput:
373 splitfields = line.split(":", 1)
374
375 if len(splitfields) > 1:
376 key = splitfields[0].strip()
377 val = splitfields[1].strip()
378
379
380 if key == "memory" or key == "total_memory":
381 memory_total = int(val)
382 elif key == "free_memory":
383 memory_free = int(val)
384 elif key == "nr_cpus":
385 nr_cpus = result["cpu_total"] = int(val)
386 elif key == "nr_nodes":
387 result["cpu_nodes"] = int(val)
388 elif key == "cores_per_socket":
389 cores_per_socket = int(val)
390 elif key == "threads_per_core":
391 threads_per_core = int(val)
392 elif key == "xen_major":
393 xen_major = int(val)
394 elif key == "xen_minor":
395 xen_minor = int(val)
396
397 if None not in [cores_per_socket, threads_per_core, nr_cpus]:
398 result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
399
400 total_instmem = 0
401 for (name, _, mem, vcpus, _, _) in self._GetXMList(True):
402 if name == _DOM0_NAME:
403 result["memory_dom0"] = mem
404 result["dom0_cpus"] = vcpus
405
406
407 total_instmem += mem
408
409 if memory_free is not None:
410 result["memory_free"] = memory_free
411
412 if memory_total is not None:
413 result["memory_total"] = memory_total
414
415
416 if None not in [memory_total, memory_free, total_instmem]:
417 result["memory_hv"] = memory_total - memory_free - total_instmem
418
419 if not (xen_major is None or xen_minor is None):
420 result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
421
422 return result
423
424 @classmethod
435
437 """Verify the hypervisor.
438
439 For Xen, this verifies that the xend process is running.
440
441 @return: Problem description if something is wrong, C{None} otherwise
442
443 """
444 result = utils.RunCmd([constants.XEN_CMD, "info"])
445 if result.failed:
446 return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
447
448 return None
449
450 @staticmethod
452 """Get disk directive for xen config file.
453
454 This method builds the xen config disk directive according to the
455 given disk_template and block_devices.
456
457 @param block_devices: list of tuples (cfdev, rldev):
458 - cfdev: dict containing ganeti config disk part
459 - rldev: ganeti.bdev.BlockDev object
460 @param blockdev_prefix: a string containing blockdevice prefix,
461 e.g. "sd" for /dev/sda
462
463 @return: string containing disk directive for xen instance config file
464
465 """
466 FILE_DRIVER_MAP = {
467 constants.FD_LOOP: "file",
468 constants.FD_BLKTAP: "tap:aio",
469 }
470 disk_data = []
471 if len(block_devices) > 24:
472
473 raise errors.HypervisorError("Too many disks")
474 namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
475 for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
476 if cfdev.mode == constants.DISK_RDWR:
477 mode = "w"
478 else:
479 mode = "r"
480 if cfdev.dev_type == constants.LD_FILE:
481 line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
482 dev_path, sd_name, mode)
483 else:
484 line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
485 disk_data.append(line)
486
487 return disk_data
488
490 """Get instance information to perform a migration.
491
492 @type instance: L{objects.Instance}
493 @param instance: instance to be migrated
494 @rtype: string
495 @return: content of the xen config file
496
497 """
498 return self._ReadConfigFile(instance.name)
499
501 """Prepare to accept an instance.
502
503 @type instance: L{objects.Instance}
504 @param instance: instance to be accepted
505 @type info: string
506 @param info: content of the xen config file on the source node
507 @type target: string
508 @param target: target host (usually ip), on this node
509
510 """
511 pass
512
514 """Finalize an instance migration.
515
516 After a successful migration we write the xen config file.
517 We do nothing on a failure, as we did not change anything at accept time.
518
519 @type instance: L{objects.Instance}
520 @param instance: instance whose migration is being finalized
521 @type info: string
522 @param info: content of the xen config file on the source node
523 @type success: boolean
524 @param success: whether the migration was a success or a failure
525
526 """
527 if success:
528 self._WriteConfigFileStatic(instance.name, info)
529
531 """Migrate an instance to a target node.
532
533 The migration will not be attempted if the instance is not
534 currently running.
535
536 @type instance: L{objects.Instance}
537 @param instance: the instance to be migrated
538 @type target: string
539 @param target: ip address of the target node
540 @type live: boolean
541 @param live: perform a live migration
542
543 """
544 if self.GetInstanceInfo(instance.name) is None:
545 raise errors.HypervisorError("Instance not running, cannot migrate")
546
547 port = instance.hvparams[constants.HV_MIGRATION_PORT]
548
549 if (constants.XEN_CMD == constants.XEN_CMD_XM and
550 not netutils.TcpPing(target, port, live_port_needed=True)):
551 raise errors.HypervisorError("Remote host %s not listening on port"
552 " %s, cannot migrate" % (target, port))
553
554 args = [constants.XEN_CMD, "migrate"]
555 if constants.XEN_CMD == constants.XEN_CMD_XM:
556 args.extend(["-p", "%d" % port])
557 if live:
558 args.append("-l")
559 elif constants.XEN_CMD == constants.XEN_CMD_XL:
560 cluster_name = ssconf.SimpleStore().GetClusterName()
561 args.extend(["-s", constants.XL_SSH_CMD % cluster_name])
562 args.extend(["-C", self._ConfigFileName(instance.name)])
563 else:
564 raise errors.HypervisorError("Unsupported xen command: %s" %
565 constants.XEN_CMD)
566
567 args.extend([instance.name, target])
568 result = utils.RunCmd(args)
569 if result.failed:
570 raise errors.HypervisorError("Failed to migrate instance %s: %s" %
571 (instance.name, result.output))
572
574 """Finalize the instance migration on the source node.
575
576 @type instance: L{objects.Instance}
577 @param instance: the instance that was migrated
578 @type success: bool
579 @param success: whether the migration succeeded or not
580 @type live: bool
581 @param live: whether the user requested a live migration or not
582
583 """
584
585 if success:
586
587 try:
588 self._RemoveConfigFile(instance.name)
589 except EnvironmentError:
590 logging.exception("Failure while removing instance config file")
591
593 """Get the migration status
594
595 As MigrateInstance for Xen is still blocking, if this method is called it
596 means that MigrateInstance has completed successfully. So we can safely
597 assume that the migration was successful and notify this fact to the client.
598
599 @type instance: L{objects.Instance}
600 @param instance: the instance that is being migrated
601 @rtype: L{objects.MigrationStatus}
602 @return: the status of the current migration (one of
603 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
604 progress info that can be retrieved from the hypervisor
605
606 """
607 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
608
609 @classmethod
611 """Xen-specific powercycle.
612
613 This first does a Linux reboot (which triggers automatically a Xen
614 reboot), and if that fails it tries to do a Xen reboot. The reason
615 we don't try a Xen reboot first is that the xen reboot launches an
616 external command which connects to the Xen hypervisor, and that
617 won't work in case the root filesystem is broken and/or the xend
618 daemon is not working.
619
620 """
621 try:
622 cls.LinuxPowercycle()
623 finally:
624 utils.RunCmd([constants.XEN_CMD, "debug", "R"])
625
628 """Xen PVM hypervisor interface"""
629
630 PARAMETERS = {
631 constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
632 constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
633 constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
634 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
635 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
636 constants.HV_ROOT_PATH: hv_base.NO_CHECK,
637 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
638 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
639 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
640
641 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
642 constants.HV_REBOOT_BEHAVIOR:
643 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
644 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
645 constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
646 constants.HV_CPU_WEIGHT:
647 (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
648 }
649
650 @classmethod
652 """Write the Xen config file for the instance.
653
654 """
655 hvp = instance.hvparams
656 config = StringIO()
657 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
658
659
660
661 if hvp[constants.HV_USE_BOOTLOADER]:
662
663 bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
664 if bootloader_path:
665 config.write("bootloader = '%s'\n" % bootloader_path)
666 else:
667 raise errors.HypervisorError("Bootloader enabled, but missing"
668 " bootloader path")
669
670 bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
671 if bootloader_args:
672 config.write("bootargs = '%s'\n" % bootloader_args)
673 else:
674
675 kpath = hvp[constants.HV_KERNEL_PATH]
676 config.write("kernel = '%s'\n" % kpath)
677
678
679 initrd_path = hvp[constants.HV_INITRD_PATH]
680 if initrd_path:
681 config.write("ramdisk = '%s'\n" % initrd_path)
682
683
684 config.write("memory = %d\n" % startup_memory)
685 config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
686 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
687 cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
688 if cpu_pinning:
689 config.write("%s\n" % cpu_pinning)
690 cpu_cap = hvp[constants.HV_CPU_CAP]
691 if cpu_cap:
692 config.write("cpu_cap=%d\n" % cpu_cap)
693 cpu_weight = hvp[constants.HV_CPU_WEIGHT]
694 if cpu_weight:
695 config.write("cpu_weight=%d\n" % cpu_weight)
696
697 config.write("name = '%s'\n" % instance.name)
698
699 vif_data = []
700 for nic in instance.nics:
701 nic_str = "mac=%s" % (nic.mac)
702 ip = getattr(nic, "ip", None)
703 if ip is not None:
704 nic_str += ", ip=%s" % ip
705 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
706 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
707 vif_data.append("'%s'" % nic_str)
708
709 disk_data = cls._GetConfigFileDiskData(block_devices,
710 hvp[constants.HV_BLOCKDEV_PREFIX])
711
712 config.write("vif = [%s]\n" % ",".join(vif_data))
713 config.write("disk = [%s]\n" % ",".join(disk_data))
714
715 if hvp[constants.HV_ROOT_PATH]:
716 config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
717 config.write("on_poweroff = 'destroy'\n")
718 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
719 config.write("on_reboot = 'restart'\n")
720 else:
721 config.write("on_reboot = 'destroy'\n")
722 config.write("on_crash = 'restart'\n")
723 config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
724 cls._WriteConfigFileStatic(instance.name, config.getvalue())
725
726 return True
727
730 """Xen HVM hypervisor interface"""
731
732 ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
733 pathutils.VNC_PASSWORD_FILE,
734 ]
735 ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
736 pathutils.VNC_PASSWORD_FILE,
737 ]
738
739 PARAMETERS = {
740 constants.HV_ACPI: hv_base.NO_CHECK,
741 constants.HV_BOOT_ORDER: (True, ) +
742 (lambda x: x and len(x.strip("acdn")) == 0,
743 "Invalid boot order specified, must be one or more of [acdn]",
744 None, None),
745 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
746 constants.HV_DISK_TYPE:
747 hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
748 constants.HV_NIC_TYPE:
749 hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
750 constants.HV_PAE: hv_base.NO_CHECK,
751 constants.HV_VNC_BIND_ADDRESS:
752 (False, netutils.IP4Address.IsValid,
753 "VNC bind address is not a valid IP address", None, None),
754 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
755 constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
756 constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
757 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
758 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
759 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
760
761 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
762
763 constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
764 constants.HV_REBOOT_BEHAVIOR:
765 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
766 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
767 constants.HV_CPU_CAP: hv_base.NO_CHECK,
768 constants.HV_CPU_WEIGHT:
769 (False, lambda x: 0 < x < 65535, "invalid weight", None, None),
770 constants.HV_VIF_TYPE:
771 hv_base.ParamInSet(False, constants.HT_HVM_VALID_VIF_TYPES),
772 }
773
774 @classmethod
776 """Create a Xen 3.1 HVM config file.
777
778 """
779 hvp = instance.hvparams
780
781 config = StringIO()
782 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
783
784
785 kpath = hvp[constants.HV_KERNEL_PATH]
786 config.write("kernel = '%s'\n" % kpath)
787
788 config.write("builder = 'hvm'\n")
789 config.write("memory = %d\n" % startup_memory)
790 config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
791 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
792 cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
793 if cpu_pinning:
794 config.write("%s\n" % cpu_pinning)
795 cpu_cap = hvp[constants.HV_CPU_CAP]
796 if cpu_cap:
797 config.write("cpu_cap=%d\n" % cpu_cap)
798 cpu_weight = hvp[constants.HV_CPU_WEIGHT]
799 if cpu_weight:
800 config.write("cpu_weight=%d\n" % cpu_weight)
801
802 config.write("name = '%s'\n" % instance.name)
803 if hvp[constants.HV_PAE]:
804 config.write("pae = 1\n")
805 else:
806 config.write("pae = 0\n")
807 if hvp[constants.HV_ACPI]:
808 config.write("acpi = 1\n")
809 else:
810 config.write("acpi = 0\n")
811 config.write("apic = 1\n")
812 config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
813 config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
814 config.write("sdl = 0\n")
815 config.write("usb = 1\n")
816 config.write("usbdevice = 'tablet'\n")
817 config.write("vnc = 1\n")
818 if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
819 config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
820 else:
821 config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
822
823 if instance.network_port > constants.VNC_BASE_PORT:
824 display = instance.network_port - constants.VNC_BASE_PORT
825 config.write("vncdisplay = %s\n" % display)
826 config.write("vncunused = 0\n")
827 else:
828 config.write("# vncdisplay = 1\n")
829 config.write("vncunused = 1\n")
830
831 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
832 try:
833 password = utils.ReadFile(vnc_pwd_file)
834 except EnvironmentError, err:
835 raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
836 (vnc_pwd_file, err))
837
838 config.write("vncpasswd = '%s'\n" % password.rstrip())
839
840 config.write("serial = 'pty'\n")
841 if hvp[constants.HV_USE_LOCALTIME]:
842 config.write("localtime = 1\n")
843
844 vif_data = []
845
846
847
848 nic_type = hvp[constants.HV_NIC_TYPE]
849
850 if nic_type is None:
851 vif_type_str = ""
852 if hvp[constants.HV_VIF_TYPE]:
853 vif_type_str = ", type=%s" % hvp[constants.HV_VIF_TYPE]
854
855 nic_type_str = vif_type_str
856 elif nic_type == constants.HT_NIC_PARAVIRTUAL:
857 nic_type_str = ", type=paravirtualized"
858 else:
859
860 nic_type_str = ", model=%s, type=%s" % \
861 (nic_type, constants.HT_HVM_VIF_IOEMU)
862 for nic in instance.nics:
863 nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
864 ip = getattr(nic, "ip", None)
865 if ip is not None:
866 nic_str += ", ip=%s" % ip
867 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
868 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
869 vif_data.append("'%s'" % nic_str)
870
871 config.write("vif = [%s]\n" % ",".join(vif_data))
872
873 disk_data = cls._GetConfigFileDiskData(block_devices,
874 hvp[constants.HV_BLOCKDEV_PREFIX])
875
876 iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
877 if iso_path:
878 iso = "'file:%s,hdc:cdrom,r'" % iso_path
879 disk_data.append(iso)
880
881 config.write("disk = [%s]\n" % (",".join(disk_data)))
882
883 pci_pass_arr = []
884 pci_pass = hvp[constants.HV_PASSTHROUGH]
885 if pci_pass:
886 pci_pass_arr = pci_pass.split(";")
887 config.write("pci = %s\n" % pci_pass_arr)
888 config.write("on_poweroff = 'destroy'\n")
889 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
890 config.write("on_reboot = 'restart'\n")
891 else:
892 config.write("on_reboot = 'destroy'\n")
893 config.write("on_crash = 'restart'\n")
894 cls._WriteConfigFileStatic(instance.name, config.getvalue())
895
896 return True
897