Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ e2ee1cea

History | View | Annotate | Download (23.4 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 dummy 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 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
    ]
523

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

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

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

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

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

    
569
  def ValidateParameters(self, hvparams):
570
    """Check the given parameters for validity.
571

572
    For the PVM hypervisor, this only check the existence of the
573
    kernel.
574

575
    @type hvparams:  dict
576
    @param hvparams: dictionary with parameter names/value
577
    @raise errors.HypervisorError: when a parameter is not valid
578

579
    """
580
    super(XenHvmHypervisor, self).ValidateParameters(hvparams)
581

    
582
    # hvm_cdrom_image_path verification
583
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
584
    if iso_path and not os.path.isfile(iso_path):
585
      raise errors.HypervisorError("The HVM CDROM image must either be a"
586
                                   " regular file or a symlink pointing to"
587
                                   " an existing regular file, not %s" %
588
                                   iso_path)
589

    
590
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
591
    if not os.path.isfile(kernel_path):
592
      raise errors.HypervisorError("Instance kernel '%s' not found or"
593
                                   " not a file" % kernel_path)
594

    
595
  @classmethod
596
  def _WriteConfigFile(cls, instance, block_devices):
597
    """Create a Xen 3.1 HVM config file.
598

599
    """
600
    hvp = instance.hvparams
601

    
602
    config = StringIO()
603
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
604

    
605
    # kernel handling
606
    kpath = hvp[constants.HV_KERNEL_PATH]
607
    config.write("kernel = '%s'\n" % kpath)
608

    
609
    config.write("builder = 'hvm'\n")
610
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
611
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
612
    config.write("name = '%s'\n" % instance.name)
613
    if instance.hvparams[constants.HV_PAE]:
614
      config.write("pae = 1\n")
615
    else:
616
      config.write("pae = 0\n")
617
    if instance.hvparams[constants.HV_ACPI]:
618
      config.write("acpi = 1\n")
619
    else:
620
      config.write("acpi = 0\n")
621
    config.write("apic = 1\n")
622
    arch = os.uname()[4]
623
    if '64' in arch:
624
      config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
625
    else:
626
      config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
627
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
628
    config.write("sdl = 0\n")
629
    config.write("usb = 1\n")
630
    config.write("usbdevice = 'tablet'\n")
631
    config.write("vnc = 1\n")
632
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
633
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
634
    else:
635
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
636

    
637
    if instance.network_port > constants.VNC_BASE_PORT:
638
      display = instance.network_port - constants.VNC_BASE_PORT
639
      config.write("vncdisplay = %s\n" % display)
640
      config.write("vncunused = 0\n")
641
    else:
642
      config.write("# vncdisplay = 1\n")
643
      config.write("vncunused = 1\n")
644

    
645
    try:
646
      password = utils.ReadFile(constants.VNC_PASSWORD_FILE)
647
    except EnvironmentError, err:
648
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
649
                                   (constants.VNC_PASSWORD_FILE, err))
650

    
651
    config.write("vncpasswd = '%s'\n" % password.rstrip())
652

    
653
    config.write("serial = 'pty'\n")
654
    config.write("localtime = 1\n")
655

    
656
    vif_data = []
657
    nic_type = hvp[constants.HV_NIC_TYPE]
658
    if nic_type is None:
659
      # ensure old instances don't change
660
      nic_type_str = ", type=ioemu"
661
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
662
      nic_type_str = ", type=paravirtualized"
663
    else:
664
      nic_type_str = ", model=%s, type=ioemu" % nic_type
665
    for nic in instance.nics:
666
      nic_str = "mac=%s, bridge=%s%s" % (nic.mac, nic.bridge, nic_type_str)
667
      ip = getattr(nic, "ip", None)
668
      if ip is not None:
669
        nic_str += ", ip=%s" % ip
670
      vif_data.append("'%s'" % nic_str)
671

    
672
    config.write("vif = [%s]\n" % ",".join(vif_data))
673
    disk_data = cls._GetConfigFileDiskData(instance.disk_template,
674
                                            block_devices)
675
    disk_type = hvp[constants.HV_DISK_TYPE]
676
    if disk_type in (None, constants.HT_DISK_IOEMU):
677
      replacement = ",ioemu:hd"
678
    else:
679
      replacement = ",hd"
680
    disk_data = [line.replace(",sd", replacement) for line in disk_data]
681
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
682
    if iso_path:
683
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
684
      disk_data.append(iso)
685

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

    
688
    config.write("on_poweroff = 'destroy'\n")
689
    config.write("on_reboot = 'restart'\n")
690
    config.write("on_crash = 'restart'\n")
691
    # just in case it exists
692
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
693
    try:
694
      utils.WriteFile("/etc/xen/%s" % instance.name,
695
                      data=config.getvalue())
696
    except EnvironmentError, err:
697
      raise errors.HypervisorError("Cannot write Xen instance confile"
698
                                   " file /etc/xen/%s: %s" %
699
                                   (instance.name, err))
700

    
701
    return True