Package ganeti :: Package hypervisor :: Module hv_xen
[hide private]
[frames] | no frames]

Source Code for Module ganeti.hypervisor.hv_xen

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc. 
  5  # 
  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. 
 10  # 
 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. 
 15  # 
 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 
 19  # 02110-1301, USA. 
 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 36 37 -class XenHypervisor(hv_base.BaseHypervisor):
38 """Xen generic hypervisor interface 39 40 This is the Xen base class used for both Xen PVM and HVM. It contains 41 all the functionality that is identical for both. 42 43 """ 44 CAN_MIGRATE = True 45 REBOOT_RETRY_COUNT = 60 46 REBOOT_RETRY_INTERVAL = 10 47 48 ANCILLARY_FILES = [ 49 "/etc/xen/xend-config.sxp", 50 "/etc/xen/scripts/vif-bridge", 51 ] 52 53 @classmethod
54 - def _WriteConfigFile(cls, instance, block_devices):
55 """Write the Xen config file for the instance. 56 57 """ 58 raise NotImplementedError
59 60 @staticmethod
61 - def _WriteConfigFileStatic(instance_name, data):
62 """Write the Xen config file for the instance. 63 64 This version of the function just writes the config file from static data. 65 66 """ 67 utils.WriteFile("/etc/xen/%s" % instance_name, data=data)
68 69 @staticmethod
70 - def _ReadConfigFile(instance_name):
71 """Returns the contents of the instance config file. 72 73 """ 74 try: 75 file_content = utils.ReadFile("/etc/xen/%s" % instance_name) 76 except EnvironmentError, err: 77 raise errors.HypervisorError("Failed to load Xen config file: %s" % err) 78 return file_content
79 80 @staticmethod
81 - def _RemoveConfigFile(instance_name):
82 """Remove the xen configuration file. 83 84 """ 85 utils.RemoveFile("/etc/xen/%s" % instance_name)
86 87 @staticmethod
88 - def _RunXmList(xmlist_errors):
89 """Helper function for L{_GetXMList} to run "xm list". 90 91 """ 92 result = utils.RunCmd(["xm", "list"]) 93 if result.failed: 94 logging.error("xm list failed (%s): %s", result.fail_reason, 95 result.output) 96 xmlist_errors.append(result) 97 raise utils.RetryAgain() 98 99 # skip over the heading 100 return result.stdout.splitlines()[1:]
101 102 @classmethod
103 - def _GetXMList(cls, include_node):
104 """Return the list of running instances. 105 106 If the include_node argument is True, then we return information 107 for dom0 also, otherwise we filter that from the return value. 108 109 @return: list of (name, id, memory, vcpus, state, time spent) 110 111 """ 112 xmlist_errors = [] 113 try: 114 lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, )) 115 except utils.RetryTimeout: 116 if xmlist_errors: 117 xmlist_result = xmlist_errors.pop() 118 119 errmsg = ("xm list failed, timeout exceeded (%s): %s" % 120 (xmlist_result.fail_reason, xmlist_result.output)) 121 else: 122 errmsg = "xm list failed" 123 124 raise errors.HypervisorError(errmsg) 125 126 result = [] 127 for line in lines: 128 # The format of lines is: 129 # Name ID Mem(MiB) VCPUs State Time(s) 130 # Domain-0 0 3418 4 r----- 266.2 131 data = line.split() 132 if len(data) != 6: 133 raise errors.HypervisorError("Can't parse output of xm list," 134 " line: %s" % line) 135 try: 136 data[1] = int(data[1]) 137 data[2] = int(data[2]) 138 data[3] = int(data[3]) 139 data[5] = float(data[5]) 140 except (TypeError, ValueError), err: 141 raise errors.HypervisorError("Can't parse output of xm list," 142 " line: %s, error: %s" % (line, err)) 143 144 # skip the Domain-0 (optional) 145 if include_node or data[0] != "Domain-0": 146 result.append(data) 147 148 return result
149
150 - def ListInstances(self):
151 """Get the list of running instances. 152 153 """ 154 xm_list = self._GetXMList(False) 155 names = [info[0] for info in xm_list] 156 return names
157
158 - def GetInstanceInfo(self, instance_name):
159 """Get instance properties. 160 161 @param instance_name: the instance name 162 163 @return: tuple (name, id, memory, vcpus, stat, times) 164 165 """ 166 xm_list = self._GetXMList(instance_name == "Domain-0") 167 result = None 168 for data in xm_list: 169 if data[0] == instance_name: 170 result = data 171 break 172 return result
173
174 - def GetAllInstancesInfo(self):
175 """Get properties of all instances. 176 177 @return: list of tuples (name, id, memory, vcpus, stat, times) 178 179 """ 180 xm_list = self._GetXMList(False) 181 return xm_list
182
183 - def StartInstance(self, instance, block_devices, startup_paused):
184 """Start an instance. 185 186 """ 187 self._WriteConfigFile(instance, block_devices) 188 cmd = ["xm", "create"] 189 if startup_paused: 190 cmd.extend(["--paused"]) 191 cmd.extend([instance.name]) 192 result = utils.RunCmd(cmd) 193 194 if result.failed: 195 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" % 196 (instance.name, result.fail_reason, 197 result.output))
198
199 - def StopInstance(self, instance, force=False, retry=False, name=None):
200 """Stop an instance. 201 202 """ 203 if name is None: 204 name = instance.name 205 self._RemoveConfigFile(name) 206 if force: 207 command = ["xm", "destroy", name] 208 else: 209 command = ["xm", "shutdown", name] 210 result = utils.RunCmd(command) 211 212 if result.failed: 213 raise errors.HypervisorError("Failed to stop instance %s: %s, %s" % 214 (name, result.fail_reason, result.output))
215
216 - def RebootInstance(self, instance):
217 """Reboot an instance. 218 219 """ 220 ini_info = self.GetInstanceInfo(instance.name) 221 222 if ini_info is None: 223 raise errors.HypervisorError("Failed to reboot instance %s," 224 " not running" % instance.name) 225 226 result = utils.RunCmd(["xm", "reboot", instance.name]) 227 if result.failed: 228 raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" % 229 (instance.name, result.fail_reason, 230 result.output)) 231 232 def _CheckInstance(): 233 new_info = self.GetInstanceInfo(instance.name) 234 235 # check if the domain ID has changed or the run time has decreased 236 if (new_info is not None and 237 (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])): 238 return 239 240 raise utils.RetryAgain()
241 242 try: 243 utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL, 244 self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT) 245 except utils.RetryTimeout: 246 raise errors.HypervisorError("Failed to reboot instance %s: instance" 247 " did not reboot in the expected interval" % 248 (instance.name, ))
249
250 - def GetNodeInfo(self):
251 """Return information about the node. 252 253 @return: a dict with the following keys (memory values in MiB): 254 - memory_total: the total memory size on the node 255 - memory_free: the available memory on the node for instances 256 - memory_dom0: the memory used by the node itself, if available 257 - nr_cpus: total number of CPUs 258 - nr_nodes: in a NUMA system, the number of domains 259 - nr_sockets: the number of physical CPU sockets in the node 260 261 """ 262 # note: in xen 3, memory has changed to total_memory 263 result = utils.RunCmd(["xm", "info"]) 264 if result.failed: 265 logging.error("Can't run 'xm info' (%s): %s", result.fail_reason, 266 result.output) 267 return None 268 269 xmoutput = result.stdout.splitlines() 270 result = {} 271 cores_per_socket = threads_per_core = nr_cpus = None 272 for line in xmoutput: 273 splitfields = line.split(":", 1) 274 275 if len(splitfields) > 1: 276 key = splitfields[0].strip() 277 val = splitfields[1].strip() 278 if key == "memory" or key == "total_memory": 279 result["memory_total"] = int(val) 280 elif key == "free_memory": 281 result["memory_free"] = int(val) 282 elif key == "nr_cpus": 283 nr_cpus = result["cpu_total"] = int(val) 284 elif key == "nr_nodes": 285 result["cpu_nodes"] = int(val) 286 elif key == "cores_per_socket": 287 cores_per_socket = int(val) 288 elif key == "threads_per_core": 289 threads_per_core = int(val) 290 291 if (cores_per_socket is not None and 292 threads_per_core is not None and nr_cpus is not None): 293 result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core) 294 295 dom0_info = self.GetInstanceInfo("Domain-0") 296 if dom0_info is not None: 297 result["memory_dom0"] = dom0_info[2] 298 299 return result
300 301 @classmethod
302 - def GetInstanceConsole(cls, instance, hvparams, beparams):
303 """Return a command for connecting to the console of an instance. 304 305 """ 306 return objects.InstanceConsole(instance=instance.name, 307 kind=constants.CONS_SSH, 308 host=instance.primary_node, 309 user=constants.GANETI_RUNAS, 310 command=[constants.XM_CONSOLE_WRAPPER, 311 instance.name])
312
313 - def Verify(self):
314 """Verify the hypervisor. 315 316 For Xen, this verifies that the xend process is running. 317 318 """ 319 result = utils.RunCmd(["xm", "info"]) 320 if result.failed: 321 return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
322 323 @staticmethod
324 - def _GetConfigFileDiskData(block_devices, blockdev_prefix):
325 """Get disk directive for xen config file. 326 327 This method builds the xen config disk directive according to the 328 given disk_template and block_devices. 329 330 @param block_devices: list of tuples (cfdev, rldev): 331 - cfdev: dict containing ganeti config disk part 332 - rldev: ganeti.bdev.BlockDev object 333 @param blockdev_prefix: a string containing blockdevice prefix, 334 e.g. "sd" for /dev/sda 335 336 @return: string containing disk directive for xen instance config file 337 338 """ 339 FILE_DRIVER_MAP = { 340 constants.FD_LOOP: "file", 341 constants.FD_BLKTAP: "tap:aio", 342 } 343 disk_data = [] 344 if len(block_devices) > 24: 345 # 'z' - 'a' = 24 346 raise errors.HypervisorError("Too many disks") 347 namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)] 348 for sd_name, (cfdev, dev_path) in zip(namespace, block_devices): 349 if cfdev.mode == constants.DISK_RDWR: 350 mode = "w" 351 else: 352 mode = "r" 353 if cfdev.dev_type == constants.LD_FILE: 354 line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]], 355 dev_path, sd_name, mode) 356 else: 357 line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode) 358 disk_data.append(line) 359 360 return disk_data
361
362 - def MigrationInfo(self, instance):
363 """Get instance information to perform a migration. 364 365 @type instance: L{objects.Instance} 366 @param instance: instance to be migrated 367 @rtype: string 368 @return: content of the xen config file 369 370 """ 371 return self._ReadConfigFile(instance.name)
372
373 - def AcceptInstance(self, instance, info, target):
374 """Prepare to accept an instance. 375 376 @type instance: L{objects.Instance} 377 @param instance: instance to be accepted 378 @type info: string 379 @param info: content of the xen config file on the source node 380 @type target: string 381 @param target: target host (usually ip), on this node 382 383 """ 384 pass
385
386 - def FinalizeMigration(self, instance, info, success):
387 """Finalize an instance migration. 388 389 After a successful migration we write the xen config file. 390 We do nothing on a failure, as we did not change anything at accept time. 391 392 @type instance: L{objects.Instance} 393 @param instance: instance whose migration is being finalized 394 @type info: string 395 @param info: content of the xen config file on the source node 396 @type success: boolean 397 @param success: whether the migration was a success or a failure 398 399 """ 400 if success: 401 self._WriteConfigFileStatic(instance.name, info)
402
403 - def MigrateInstance(self, instance, target, live):
404 """Migrate an instance to a target node. 405 406 The migration will not be attempted if the instance is not 407 currently running. 408 409 @type instance: L{objects.Instance} 410 @param instance: the instance to be migrated 411 @type target: string 412 @param target: ip address of the target node 413 @type live: boolean 414 @param live: perform a live migration 415 416 """ 417 if self.GetInstanceInfo(instance.name) is None: 418 raise errors.HypervisorError("Instance not running, cannot migrate") 419 420 port = instance.hvparams[constants.HV_MIGRATION_PORT] 421 422 if not netutils.TcpPing(target, port, live_port_needed=True): 423 raise errors.HypervisorError("Remote host %s not listening on port" 424 " %s, cannot migrate" % (target, port)) 425 426 args = ["xm", "migrate", "-p", "%d" % port] 427 if live: 428 args.append("-l") 429 args.extend([instance.name, target]) 430 result = utils.RunCmd(args) 431 if result.failed: 432 raise errors.HypervisorError("Failed to migrate instance %s: %s" % 433 (instance.name, result.output)) 434 # remove old xen file after migration succeeded 435 try: 436 self._RemoveConfigFile(instance.name) 437 except EnvironmentError: 438 logging.exception("Failure while removing instance config file")
439 440 @classmethod
441 - def PowercycleNode(cls):
442 """Xen-specific powercycle. 443 444 This first does a Linux reboot (which triggers automatically a Xen 445 reboot), and if that fails it tries to do a Xen reboot. The reason 446 we don't try a Xen reboot first is that the xen reboot launches an 447 external command which connects to the Xen hypervisor, and that 448 won't work in case the root filesystem is broken and/or the xend 449 daemon is not working. 450 451 """ 452 try: 453 cls.LinuxPowercycle() 454 finally: 455 utils.RunCmd(["xm", "debug", "R"])
456
457 458 -class XenPvmHypervisor(XenHypervisor):
459 """Xen PVM hypervisor interface""" 460 461 PARAMETERS = { 462 constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK, 463 constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK, 464 constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK, 465 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK, 466 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK, 467 constants.HV_ROOT_PATH: hv_base.NO_CHECK, 468 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK, 469 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK, 470 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK, 471 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar). 472 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK, 473 constants.HV_REBOOT_BEHAVIOR: 474 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS) 475 } 476 477 @classmethod
478 - def _WriteConfigFile(cls, instance, block_devices):
479 """Write the Xen config file for the instance. 480 481 """ 482 hvp = instance.hvparams 483 config = StringIO() 484 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n") 485 486 # if bootloader is True, use bootloader instead of kernel and ramdisk 487 # parameters. 488 if hvp[constants.HV_USE_BOOTLOADER]: 489 # bootloader handling 490 bootloader_path = hvp[constants.HV_BOOTLOADER_PATH] 491 if bootloader_path: 492 config.write("bootloader = '%s'\n" % bootloader_path) 493 else: 494 raise errors.HypervisorError("Bootloader enabled, but missing" 495 " bootloader path") 496 497 bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS] 498 if bootloader_args: 499 config.write("bootargs = '%s'\n" % bootloader_args) 500 else: 501 # kernel handling 502 kpath = hvp[constants.HV_KERNEL_PATH] 503 config.write("kernel = '%s'\n" % kpath) 504 505 # initrd handling 506 initrd_path = hvp[constants.HV_INITRD_PATH] 507 if initrd_path: 508 config.write("ramdisk = '%s'\n" % initrd_path) 509 510 # rest of the settings 511 config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY]) 512 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS]) 513 config.write("name = '%s'\n" % instance.name) 514 515 vif_data = [] 516 for nic in instance.nics: 517 nic_str = "mac=%s" % (nic.mac) 518 ip = getattr(nic, "ip", None) 519 if ip is not None: 520 nic_str += ", ip=%s" % ip 521 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED: 522 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK] 523 vif_data.append("'%s'" % nic_str) 524 525 disk_data = cls._GetConfigFileDiskData(block_devices, 526 hvp[constants.HV_BLOCKDEV_PREFIX]) 527 528 config.write("vif = [%s]\n" % ",".join(vif_data)) 529 config.write("disk = [%s]\n" % ",".join(disk_data)) 530 531 if hvp[constants.HV_ROOT_PATH]: 532 config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH]) 533 config.write("on_poweroff = 'destroy'\n") 534 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED: 535 config.write("on_reboot = 'restart'\n") 536 else: 537 config.write("on_reboot = 'destroy'\n") 538 config.write("on_crash = 'restart'\n") 539 config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS]) 540 # just in case it exists 541 utils.RemoveFile("/etc/xen/auto/%s" % instance.name) 542 try: 543 utils.WriteFile("/etc/xen/%s" % instance.name, data=config.getvalue()) 544 except EnvironmentError, err: 545 raise errors.HypervisorError("Cannot write Xen instance confile" 546 " file /etc/xen/%s: %s" % 547 (instance.name, err)) 548 549 return True
550
551 552 -class XenHvmHypervisor(XenHypervisor):
553 """Xen HVM hypervisor interface""" 554 555 ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [ 556 constants.VNC_PASSWORD_FILE, 557 ] 558 559 PARAMETERS = { 560 constants.HV_ACPI: hv_base.NO_CHECK, 561 constants.HV_BOOT_ORDER: (True, ) + 562 (lambda x: x and len(x.strip("acdn")) == 0, 563 "Invalid boot order specified, must be one or more of [acdn]", 564 None, None), 565 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK, 566 constants.HV_DISK_TYPE: 567 hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES), 568 constants.HV_NIC_TYPE: 569 hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES), 570 constants.HV_PAE: hv_base.NO_CHECK, 571 constants.HV_VNC_BIND_ADDRESS: 572 (False, netutils.IP4Address.IsValid, 573 "VNC bind address is not a valid IP address", None, None), 574 constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK, 575 constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK, 576 constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK, 577 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK, 578 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK, 579 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK, 580 # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar). 581 constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK, 582 constants.HV_REBOOT_BEHAVIOR: 583 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS) 584 } 585 586 @classmethod
587 - def _WriteConfigFile(cls, instance, block_devices):
588 """Create a Xen 3.1 HVM config file. 589 590 """ 591 hvp = instance.hvparams 592 593 config = StringIO() 594 config.write("# this is autogenerated by Ganeti, please do not edit\n#\n") 595 596 # kernel handling 597 kpath = hvp[constants.HV_KERNEL_PATH] 598 config.write("kernel = '%s'\n" % kpath) 599 600 config.write("builder = 'hvm'\n") 601 config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY]) 602 config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS]) 603 config.write("name = '%s'\n" % instance.name) 604 if hvp[constants.HV_PAE]: 605 config.write("pae = 1\n") 606 else: 607 config.write("pae = 0\n") 608 if hvp[constants.HV_ACPI]: 609 config.write("acpi = 1\n") 610 else: 611 config.write("acpi = 0\n") 612 config.write("apic = 1\n") 613 config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL]) 614 config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER]) 615 config.write("sdl = 0\n") 616 config.write("usb = 1\n") 617 config.write("usbdevice = 'tablet'\n") 618 config.write("vnc = 1\n") 619 if hvp[constants.HV_VNC_BIND_ADDRESS] is None: 620 config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS) 621 else: 622 config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS]) 623 624 if instance.network_port > constants.VNC_BASE_PORT: 625 display = instance.network_port - constants.VNC_BASE_PORT 626 config.write("vncdisplay = %s\n" % display) 627 config.write("vncunused = 0\n") 628 else: 629 config.write("# vncdisplay = 1\n") 630 config.write("vncunused = 1\n") 631 632 vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE] 633 try: 634 password = utils.ReadFile(vnc_pwd_file) 635 except EnvironmentError, err: 636 raise errors.HypervisorError("Failed to open VNC password file %s: %s" % 637 (vnc_pwd_file, err)) 638 639 config.write("vncpasswd = '%s'\n" % password.rstrip()) 640 641 config.write("serial = 'pty'\n") 642 if hvp[constants.HV_USE_LOCALTIME]: 643 config.write("localtime = 1\n") 644 645 vif_data = [] 646 nic_type = hvp[constants.HV_NIC_TYPE] 647 if nic_type is None: 648 # ensure old instances don't change 649 nic_type_str = ", type=ioemu" 650 elif nic_type == constants.HT_NIC_PARAVIRTUAL: 651 nic_type_str = ", type=paravirtualized" 652 else: 653 nic_type_str = ", model=%s, type=ioemu" % nic_type 654 for nic in instance.nics: 655 nic_str = "mac=%s%s" % (nic.mac, nic_type_str) 656 ip = getattr(nic, "ip", None) 657 if ip is not None: 658 nic_str += ", ip=%s" % ip 659 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED: 660 nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK] 661 vif_data.append("'%s'" % nic_str) 662 663 config.write("vif = [%s]\n" % ",".join(vif_data)) 664 665 disk_data = cls._GetConfigFileDiskData(block_devices, 666 hvp[constants.HV_BLOCKDEV_PREFIX]) 667 668 iso_path = hvp[constants.HV_CDROM_IMAGE_PATH] 669 if iso_path: 670 iso = "'file:%s,hdc:cdrom,r'" % iso_path 671 disk_data.append(iso) 672 673 config.write("disk = [%s]\n" % (",".join(disk_data))) 674 675 config.write("on_poweroff = 'destroy'\n") 676 if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED: 677 config.write("on_reboot = 'restart'\n") 678 else: 679 config.write("on_reboot = 'destroy'\n") 680 config.write("on_crash = 'restart'\n") 681 # just in case it exists 682 utils.RemoveFile("/etc/xen/auto/%s" % instance.name) 683 try: 684 utils.WriteFile("/etc/xen/%s" % instance.name, 685 data=config.getvalue()) 686 except EnvironmentError, err: 687 raise errors.HypervisorError("Cannot write Xen instance confile" 688 " file /etc/xen/%s: %s" % 689 (instance.name, err)) 690 691 return True
692