Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 691744c4

History | View | Annotate | Download (23.6 kB)

1
#
2
#
3

    
4
# Copyright (C) 2006, 2007, 2008 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 os
27
import os.path
28
import time
29
import logging
30
from cStringIO import StringIO
31

    
32
from ganeti import constants
33
from ganeti import errors
34
from ganeti import utils
35
from ganeti.hypervisor import hv_base
36

    
37

    
38
class XenHypervisor(hv_base.BaseHypervisor):
39
  """Xen generic hypervisor interface
40

41
  This is the Xen base class used for both Xen PVM and HVM. It contains
42
  all the functionality that is identical for both.
43

44
  """
45
  REBOOT_RETRY_COUNT = 60
46
  REBOOT_RETRY_INTERVAL = 10
47

    
48
  @classmethod
49
  def _WriteConfigFile(cls, instance, block_devices):
50
    """Write the Xen config file for the instance.
51

52
    """
53
    raise NotImplementedError
54

    
55
  @staticmethod
56
  def _WriteConfigFileStatic(instance_name, data):
57
    """Write the Xen config file for the instance.
58

59
    This version of the function just writes the config file from static data.
60

61
    """
62
    utils.WriteFile("/etc/xen/%s" % instance_name, data=data)
63

    
64
  @staticmethod
65
  def _ReadConfigFile(instance_name):
66
    """Returns the contents of the instance config file.
67

68
    """
69
    try:
70
      file_content = utils.ReadFile("/etc/xen/%s" % instance_name)
71
    except EnvironmentError, err:
72
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
73
    return file_content
74

    
75
  @staticmethod
76
  def _RemoveConfigFile(instance_name):
77
    """Remove the xen configuration file.
78

79
    """
80
    utils.RemoveFile("/etc/xen/%s" % instance_name)
81

    
82
  @staticmethod
83
  def _GetXMList(include_node):
84
    """Return the list of running instances.
85

86
    If the include_node argument is True, then we return information
87
    for dom0 also, otherwise we filter that from the return value.
88

89
    @return: list of (name, id, memory, vcpus, state, time spent)
90

91
    """
92
    for _ in range(5):
93
      result = utils.RunCmd(["xm", "list"])
94
      if not result.failed:
95
        break
96
      logging.error("xm list failed (%s): %s", result.fail_reason,
97
                    result.output)
98
      time.sleep(1)
99

    
100
    if result.failed:
101
      raise errors.HypervisorError("xm list failed, retries"
102
                                   " exceeded (%s): %s" %
103
                                   (result.fail_reason, result.output))
104

    
105
    # skip over the heading
106
    lines = result.stdout.splitlines()[1:]
107
    result = []
108
    for line in lines:
109
      # The format of lines is:
110
      # Name      ID Mem(MiB) VCPUs State  Time(s)
111
      # Domain-0   0  3418     4 r-----    266.2
112
      data = line.split()
113
      if len(data) != 6:
114
        raise errors.HypervisorError("Can't parse output of xm list,"
115
                                     " line: %s" % line)
116
      try:
117
        data[1] = int(data[1])
118
        data[2] = int(data[2])
119
        data[3] = int(data[3])
120
        data[5] = float(data[5])
121
      except (TypeError, ValueError), err:
122
        raise errors.HypervisorError("Can't parse output of xm list,"
123
                                     " line: %s, error: %s" % (line, err))
124

    
125
      # skip the Domain-0 (optional)
126
      if include_node or data[0] != 'Domain-0':
127
        result.append(data)
128

    
129
    return result
130

    
131
  def ListInstances(self):
132
    """Get the list of running instances.
133

134
    """
135
    xm_list = self._GetXMList(False)
136
    names = [info[0] for info in xm_list]
137
    return names
138

    
139
  def GetInstanceInfo(self, instance_name):
140
    """Get instance properties.
141

142
    @param instance_name: the instance name
143

144
    @return: tuple (name, id, memory, vcpus, stat, times)
145

146
    """
147
    xm_list = self._GetXMList(instance_name=="Domain-0")
148
    result = None
149
    for data in xm_list:
150
      if data[0] == instance_name:
151
        result = data
152
        break
153
    return result
154

    
155
  def GetAllInstancesInfo(self):
156
    """Get properties of all instances.
157

158
    @return: list of tuples (name, id, memory, vcpus, stat, times)
159

160
    """
161
    xm_list = self._GetXMList(False)
162
    return xm_list
163

    
164
  def StartInstance(self, instance, block_devices):
165
    """Start an instance.
166

167
    """
168
    self._WriteConfigFile(instance, block_devices)
169
    result = utils.RunCmd(["xm", "create", instance.name])
170

    
171
    if result.failed:
172
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
173
                                   (instance.name, result.fail_reason,
174
                                    result.output))
175

    
176
  def StopInstance(self, instance, force=False):
177
    """Stop an instance.
178

179
    """
180
    self._RemoveConfigFile(instance.name)
181
    if force:
182
      command = ["xm", "destroy", instance.name]
183
    else:
184
      command = ["xm", "shutdown", instance.name]
185
    result = utils.RunCmd(command)
186

    
187
    if result.failed:
188
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
189
                                   (instance.name, result.fail_reason,
190
                                    result.output))
191

    
192
  def RebootInstance(self, instance):
193
    """Reboot an instance.
194

195
    """
196
    ini_info = self.GetInstanceInfo(instance.name)
197
    result = utils.RunCmd(["xm", "reboot", instance.name])
198

    
199
    if result.failed:
200
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
201
                                   (instance.name, result.fail_reason,
202
                                    result.output))
203
    done = False
204
    retries = self.REBOOT_RETRY_COUNT
205
    while retries > 0:
206
      new_info = self.GetInstanceInfo(instance.name)
207
      # check if the domain ID has changed or the run time has
208
      # decreased
209
      if new_info[1] != ini_info[1] or new_info[5] < ini_info[5]:
210
        done = True
211
        break
212
      time.sleep(self.REBOOT_RETRY_INTERVAL)
213
      retries -= 1
214

    
215
    if not done:
216
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
217
                                   " did not reboot in the expected interval" %
218
                                   (instance.name, ))
219

    
220
  def GetNodeInfo(self):
221
    """Return information about the node.
222

223
    @return: a dict with the following keys (memory values in MiB):
224
          - memory_total: the total memory size on the node
225
          - memory_free: the available memory on the node for instances
226
          - memory_dom0: the memory used by the node itself, if available
227
          - nr_cpus: total number of CPUs
228
          - nr_nodes: in a NUMA system, the number of domains
229
          - nr_sockets: the number of physical CPU sockets in the node
230

231
    """
232
    # note: in xen 3, memory has changed to total_memory
233
    result = utils.RunCmd(["xm", "info"])
234
    if result.failed:
235
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
236
                    result.output)
237
      return None
238

    
239
    xmoutput = result.stdout.splitlines()
240
    result = {}
241
    cores_per_socket = threads_per_core = nr_cpus = None
242
    for line in xmoutput:
243
      splitfields = line.split(":", 1)
244

    
245
      if len(splitfields) > 1:
246
        key = splitfields[0].strip()
247
        val = splitfields[1].strip()
248
        if key == 'memory' or key == 'total_memory':
249
          result['memory_total'] = int(val)
250
        elif key == 'free_memory':
251
          result['memory_free'] = int(val)
252
        elif key == 'nr_cpus':
253
          nr_cpus = result['cpu_total'] = int(val)
254
        elif key == 'nr_nodes':
255
          result['cpu_nodes'] = int(val)
256
        elif key == 'cores_per_socket':
257
          cores_per_socket = int(val)
258
        elif key == 'threads_per_core':
259
          threads_per_core = int(val)
260

    
261
    if (cores_per_socket is not None and
262
        threads_per_core is not None and nr_cpus is not None):
263
      result['cpu_sockets'] = nr_cpus / (cores_per_socket * threads_per_core)
264

    
265
    dom0_info = self.GetInstanceInfo("Domain-0")
266
    if dom0_info is not None:
267
      result['memory_dom0'] = dom0_info[2]
268

    
269
    return result
270

    
271
  @classmethod
272
  def GetShellCommandForConsole(cls, instance, hvparams, beparams):
273
    """Return a command for connecting to the console of an instance.
274

275
    """
276
    return "xm console %s" % instance.name
277

    
278

    
279
  def Verify(self):
280
    """Verify the hypervisor.
281

282
    For Xen, this verifies that the xend process is running.
283

284
    """
285
    result = utils.RunCmd(["xm", "info"])
286
    if result.failed:
287
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
288

    
289
  @staticmethod
290
  def _GetConfigFileDiskData(disk_template, block_devices):
291
    """Get disk directive for xen config file.
292

293
    This method builds the xen config disk directive according to the
294
    given disk_template and block_devices.
295

296
    @param disk_template: string containing instance disk template
297
    @param block_devices: list of tuples (cfdev, rldev):
298
        - cfdev: dict containing ganeti config disk part
299
        - rldev: ganeti.bdev.BlockDev object
300

301
    @return: string containing disk directive for xen instance config file
302

303
    """
304
    FILE_DRIVER_MAP = {
305
      constants.FD_LOOP: "file",
306
      constants.FD_BLKTAP: "tap:aio",
307
      }
308
    disk_data = []
309
    if len(block_devices) > 24:
310
      # 'z' - 'a' = 24
311
      raise errors.HypervisorError("Too many disks")
312
    # FIXME: instead of this hardcoding here, each of PVM/HVM should
313
    # directly export their info (currently HVM will just sed this info)
314
    namespace = ["sd" + chr(i + ord('a')) for i in range(24)]
315
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
316
      if cfdev.mode == constants.DISK_RDWR:
317
        mode = "w"
318
      else:
319
        mode = "r"
320
      if cfdev.dev_type == constants.LD_FILE:
321
        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
322
                                  dev_path, sd_name, mode)
323
      else:
324
        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
325
      disk_data.append(line)
326

    
327
    return disk_data
328

    
329
  def MigrationInfo(self, instance):
330
    """Get instance information to perform a migration.
331

332
    @type instance: L{objects.Instance}
333
    @param instance: instance to be migrated
334
    @rtype: string
335
    @return: content of the xen config file
336

337
    """
338
    return self._ReadConfigFile(instance.name)
339

    
340
  def AcceptInstance(self, instance, info, target):
341
    """Prepare to accept an instance.
342

343
    @type instance: L{objects.Instance}
344
    @param instance: instance to be accepted
345
    @type info: string
346
    @param info: content of the xen config file on the source node
347
    @type target: string
348
    @param target: target host (usually ip), on this node
349

350
    """
351
    pass
352

    
353
  def FinalizeMigration(self, instance, info, success):
354
    """Finalize an instance migration.
355

356
    After a successful migration we write the xen config file.
357
    We do nothing on a failure, as we did not change anything at accept time.
358

359
    @type instance: L{objects.Instance}
360
    @param instance: instance whose migration is being aborted
361
    @type info: string
362
    @param info: content of the xen config file on the source node
363
    @type success: boolean
364
    @param success: whether the migration was a success or a failure
365

366
    """
367
    if success:
368
      self._WriteConfigFileStatic(instance.name, info)
369

    
370
  def MigrateInstance(self, instance, target, live):
371
    """Migrate an instance to a target node.
372

373
    The migration will not be attempted if the instance is not
374
    currently running.
375

376
    @type instance: string
377
    @param instance: instance name
378
    @type target: string
379
    @param target: ip address of the target node
380
    @type live: boolean
381
    @param live: perform a live migration
382

383
    """
384
    if self.GetInstanceInfo(instance) is None:
385
      raise errors.HypervisorError("Instance not running, cannot migrate")
386
    args = ["xm", "migrate"]
387
    if live:
388
      args.append("-l")
389
    args.extend([instance, target])
390
    result = utils.RunCmd(args)
391
    if result.failed:
392
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
393
                                   (instance, result.output))
394
    # remove old xen file after migration succeeded
395
    try:
396
      self._RemoveConfigFile(instance)
397
    except EnvironmentError:
398
      logging.exception("Failure while removing instance config file")
399

    
400

    
401
class XenPvmHypervisor(XenHypervisor):
402
  """Xen PVM hypervisor interface"""
403

    
404
  PARAMETERS = [
405
    constants.HV_KERNEL_PATH,
406
    constants.HV_INITRD_PATH,
407
    constants.HV_ROOT_PATH,
408
    constants.HV_KERNEL_ARGS,
409
    ]
410

    
411
  @classmethod
412
  def CheckParameterSyntax(cls, hvparams):
413
    """Check the given parameters for validity.
414

415
    For the PVM hypervisor, this only check the existence of the
416
    kernel.
417

418
    @type hvparams:  dict
419
    @param hvparams: dictionary with parameter names/value
420
    @raise errors.HypervisorError: when a parameter is not valid
421

422
    """
423
    super(XenPvmHypervisor, cls).CheckParameterSyntax(hvparams)
424

    
425
    if not hvparams[constants.HV_KERNEL_PATH]:
426
      raise errors.HypervisorError("Need a kernel for the instance")
427

    
428
    if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
429
      raise errors.HypervisorError("The kernel path must be an absolute path")
430

    
431
    if not hvparams[constants.HV_ROOT_PATH]:
432
      raise errors.HypervisorError("Need a root partition for the instance")
433

    
434
    if hvparams[constants.HV_INITRD_PATH]:
435
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
436
        raise errors.HypervisorError("The initrd path must be an absolute path"
437
                                     ", if defined")
438

    
439
  def ValidateParameters(self, hvparams):
440
    """Check the given parameters for validity.
441

442
    For the PVM hypervisor, this only check the existence of the
443
    kernel.
444

445
    """
446
    super(XenPvmHypervisor, self).ValidateParameters(hvparams)
447

    
448
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
449
    if not os.path.isfile(kernel_path):
450
      raise errors.HypervisorError("Instance kernel '%s' not found or"
451
                                   " not a file" % kernel_path)
452
    initrd_path = hvparams[constants.HV_INITRD_PATH]
453
    if initrd_path and not os.path.isfile(initrd_path):
454
      raise errors.HypervisorError("Instance initrd '%s' not found or"
455
                                   " not a file" % initrd_path)
456

    
457
  @classmethod
458
  def _WriteConfigFile(cls, instance, block_devices):
459
    """Write the Xen config file for the instance.
460

461
    """
462
    hvp = instance.hvparams
463
    config = StringIO()
464
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
465

    
466
    # kernel handling
467
    kpath = hvp[constants.HV_KERNEL_PATH]
468
    config.write("kernel = '%s'\n" % kpath)
469

    
470
    # initrd handling
471
    initrd_path = hvp[constants.HV_INITRD_PATH]
472
    if initrd_path:
473
      config.write("ramdisk = '%s'\n" % initrd_path)
474

    
475
    # rest of the settings
476
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
477
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
478
    config.write("name = '%s'\n" % instance.name)
479

    
480
    vif_data = []
481
    for nic in instance.nics:
482
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
483
      ip = getattr(nic, "ip", None)
484
      if ip is not None:
485
        nic_str += ", ip=%s" % ip
486
      vif_data.append("'%s'" % nic_str)
487

    
488
    config.write("vif = [%s]\n" % ",".join(vif_data))
489
    config.write("disk = [%s]\n" % ",".join(
490
                 cls._GetConfigFileDiskData(instance.disk_template,
491
                                            block_devices)))
492

    
493
    config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
494
    config.write("on_poweroff = 'destroy'\n")
495
    config.write("on_reboot = 'restart'\n")
496
    config.write("on_crash = 'restart'\n")
497
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
498
    # just in case it exists
499
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
500
    try:
501
      utils.WriteFile("/etc/xen/%s" % instance.name, data=config.getvalue())
502
    except EnvironmentError, err:
503
      raise errors.HypervisorError("Cannot write Xen instance confile"
504
                                   " file /etc/xen/%s: %s" %
505
                                   (instance.name, err))
506

    
507
    return True
508

    
509

    
510
class XenHvmHypervisor(XenHypervisor):
511
  """Xen HVM hypervisor interface"""
512

    
513
  PARAMETERS = [
514
    constants.HV_ACPI,
515
    constants.HV_BOOT_ORDER,
516
    constants.HV_CDROM_IMAGE_PATH,
517
    constants.HV_DISK_TYPE,
518
    constants.HV_NIC_TYPE,
519
    constants.HV_PAE,
520
    constants.HV_VNC_BIND_ADDRESS,
521
    constants.HV_KERNEL_PATH,
522
    constants.HV_DEVICE_MODEL,
523
    ]
524

    
525
  @classmethod
526
  def CheckParameterSyntax(cls, hvparams):
527
    """Check the given parameter syntax.
528

529
    """
530
    super(XenHvmHypervisor, cls).CheckParameterSyntax(hvparams)
531
    # boot order verification
532
    boot_order = hvparams[constants.HV_BOOT_ORDER]
533
    if not boot_order or len(boot_order.strip("acdn")) != 0:
534
      raise errors.HypervisorError("Invalid boot order '%s' specified,"
535
                                   " must be one or more of [acdn]" %
536
                                   boot_order)
537
    # device type checks
538
    nic_type = hvparams[constants.HV_NIC_TYPE]
539
    if nic_type not in constants.HT_HVM_VALID_NIC_TYPES:
540
      raise errors.HypervisorError(\
541
        "Invalid NIC type %s specified for the Xen"
542
        " HVM hypervisor. Please choose one of: %s"
543
        % (nic_type, utils.CommaJoin(constants.HT_HVM_VALID_NIC_TYPES)))
544
    disk_type = hvparams[constants.HV_DISK_TYPE]
545
    if disk_type not in constants.HT_HVM_VALID_DISK_TYPES:
546
      raise errors.HypervisorError(\
547
        "Invalid disk type %s specified for the Xen"
548
        " HVM hypervisor. Please choose one of: %s"
549
        % (disk_type, utils.CommaJoin(constants.HT_HVM_VALID_DISK_TYPES)))
550
    # vnc_bind_address verification
551
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
552
    if vnc_bind_address:
553
      if not utils.IsValidIP(vnc_bind_address):
554
        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
555
                                   " like a valid IP address" %
556
                                   vnc_bind_address)
557

    
558
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
559
    if iso_path and not os.path.isabs(iso_path):
560
      raise errors.HypervisorError("The path to the HVM CDROM image must"
561
                                   " be an absolute path or None, not %s" %
562
                                   iso_path)
563

    
564
    if not hvparams[constants.HV_KERNEL_PATH]:
565
      raise errors.HypervisorError("Need a kernel for the instance")
566

    
567
    if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
568
      raise errors.HypervisorError("The kernel path must be an absolute path")
569

    
570
    if not hvparams[constants.HV_DEVICE_MODEL]:
571
      raise errors.HypervisorError("Need a device model for the instance")
572

    
573
    if not os.path.isabs(hvparams[constants.HV_DEVICE_MODEL]):
574
      raise errors.HypervisorError("The device model must be an absolute path")
575

    
576

    
577
  def ValidateParameters(self, hvparams):
578
    """Check the given parameters for validity.
579

580
    For the PVM hypervisor, this only check the existence of the
581
    kernel.
582

583
    @type hvparams:  dict
584
    @param hvparams: dictionary with parameter names/value
585
    @raise errors.HypervisorError: when a parameter is not valid
586

587
    """
588
    super(XenHvmHypervisor, self).ValidateParameters(hvparams)
589

    
590
    # hvm_cdrom_image_path verification
591
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
592
    if iso_path and not os.path.isfile(iso_path):
593
      raise errors.HypervisorError("The HVM CDROM image must either be a"
594
                                   " regular file or a symlink pointing to"
595
                                   " an existing regular file, not %s" %
596
                                   iso_path)
597

    
598
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
599
    if not os.path.isfile(kernel_path):
600
      raise errors.HypervisorError("Instance kernel '%s' not found or"
601
                                   " not a file" % kernel_path)
602

    
603
    device_model = hvparams[constants.HV_DEVICE_MODEL]
604
    if not os.path.isfile(device_model):
605
      raise errors.HypervisorError("Device model '%s' not found or"
606
                                   " not a file" % device_model)
607

    
608
  @classmethod
609
  def _WriteConfigFile(cls, instance, block_devices):
610
    """Create a Xen 3.1 HVM config file.
611

612
    """
613
    hvp = instance.hvparams
614

    
615
    config = StringIO()
616
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
617

    
618
    # kernel handling
619
    kpath = hvp[constants.HV_KERNEL_PATH]
620
    config.write("kernel = '%s'\n" % kpath)
621

    
622
    config.write("builder = 'hvm'\n")
623
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
624
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
625
    config.write("name = '%s'\n" % instance.name)
626
    if hvp[constants.HV_PAE]:
627
      config.write("pae = 1\n")
628
    else:
629
      config.write("pae = 0\n")
630
    if hvp[constants.HV_ACPI]:
631
      config.write("acpi = 1\n")
632
    else:
633
      config.write("acpi = 0\n")
634
    config.write("apic = 1\n")
635
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
636
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
637
    config.write("sdl = 0\n")
638
    config.write("usb = 1\n")
639
    config.write("usbdevice = 'tablet'\n")
640
    config.write("vnc = 1\n")
641
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
642
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
643
    else:
644
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
645

    
646
    if instance.network_port > constants.VNC_BASE_PORT:
647
      display = instance.network_port - constants.VNC_BASE_PORT
648
      config.write("vncdisplay = %s\n" % display)
649
      config.write("vncunused = 0\n")
650
    else:
651
      config.write("# vncdisplay = 1\n")
652
      config.write("vncunused = 1\n")
653

    
654
    try:
655
      password = utils.ReadFile(constants.VNC_PASSWORD_FILE)
656
    except EnvironmentError, err:
657
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
658
                                   (constants.VNC_PASSWORD_FILE, err))
659

    
660
    config.write("vncpasswd = '%s'\n" % password.rstrip())
661

    
662
    config.write("serial = 'pty'\n")
663
    config.write("localtime = 1\n")
664

    
665
    vif_data = []
666
    nic_type = hvp[constants.HV_NIC_TYPE]
667
    if nic_type is None:
668
      # ensure old instances don't change
669
      nic_type_str = ", type=ioemu"
670
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
671
      nic_type_str = ", type=paravirtualized"
672
    else:
673
      nic_type_str = ", model=%s, type=ioemu" % nic_type
674
    for nic in instance.nics:
675
      nic_str = "mac=%s, bridge=%s%s" % (nic.mac, nic.bridge, nic_type_str)
676
      ip = getattr(nic, "ip", None)
677
      if ip is not None:
678
        nic_str += ", ip=%s" % ip
679
      vif_data.append("'%s'" % nic_str)
680

    
681
    config.write("vif = [%s]\n" % ",".join(vif_data))
682
    disk_data = cls._GetConfigFileDiskData(instance.disk_template,
683
                                            block_devices)
684
    disk_type = hvp[constants.HV_DISK_TYPE]
685
    if disk_type in (None, constants.HT_DISK_IOEMU):
686
      replacement = ",ioemu:hd"
687
    else:
688
      replacement = ",hd"
689
    disk_data = [line.replace(",sd", replacement) for line in disk_data]
690
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
691
    if iso_path:
692
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
693
      disk_data.append(iso)
694

    
695
    config.write("disk = [%s]\n" % (",".join(disk_data)))
696

    
697
    config.write("on_poweroff = 'destroy'\n")
698
    config.write("on_reboot = 'restart'\n")
699
    config.write("on_crash = 'restart'\n")
700
    # just in case it exists
701
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
702
    try:
703
      utils.WriteFile("/etc/xen/%s" % instance.name,
704
                      data=config.getvalue())
705
    except EnvironmentError, err:
706
      raise errors.HypervisorError("Cannot write Xen instance confile"
707
                                   " file /etc/xen/%s: %s" %
708
                                   (instance.name, err))
709

    
710
    return True