Revision a2d32034

/dev/null
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
"""Base class for all hypervisors
23

  
24
"""
25

  
26
class BaseHypervisor(object):
27
  """Abstract virtualisation technology interface
28

  
29
  The goal is that all aspects of the virtualisation technology must
30
  be abstracted away from the rest of code.
31

  
32
  """
33
  def __init__(self):
34
    pass
35

  
36
  def StartInstance(self, instance, block_devices, extra_args):
37
    """Start an instance."""
38
    raise NotImplementedError
39

  
40
  def StopInstance(self, instance, force=False):
41
    """Stop an instance."""
42
    raise NotImplementedError
43

  
44
  def RebootInstance(self, instance):
45
    """Reboot an instance."""
46
    raise NotImplementedError
47

  
48
  def ListInstances(self):
49
    """Get the list of running instances."""
50
    raise NotImplementedError
51

  
52
  def GetInstanceInfo(self, instance_name):
53
    """Get instance properties.
54

  
55
    Args:
56
      instance_name: the instance name
57

  
58
    Returns:
59
      (name, id, memory, vcpus, state, times)
60

  
61
    """
62
    raise NotImplementedError
63

  
64
  def GetAllInstancesInfo(self):
65
    """Get properties of all instances.
66

  
67
    Returns:
68
      [(name, id, memory, vcpus, stat, times),...]
69
    """
70
    raise NotImplementedError
71

  
72
  def GetNodeInfo(self):
73
    """Return information about the node.
74

  
75
    The return value is a dict, which has to have the following items:
76
      (all values in MiB)
77
      - memory_total: the total memory size on the node
78
      - memory_free: the available memory on the node for instances
79
      - memory_dom0: the memory used by the node itself, if available
80

  
81
    """
82
    raise NotImplementedError
83

  
84
  @staticmethod
85
  def GetShellCommandForConsole(instance):
86
    """Return a command for connecting to the console of an instance.
87

  
88
    """
89
    raise NotImplementedError
90

  
91
  def Verify(self):
92
    """Verify the hypervisor.
93

  
94
    """
95
    raise NotImplementedError
/dev/null
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
"""Fake hypervisor
23

  
24
"""
25

  
26
import os
27
import os.path
28
import re
29

  
30
from ganeti import utils
31
from ganeti import constants
32
from ganeti import errors
33
from ganeti.hypervisor import BaseHypervisor
34

  
35

  
36
class FakeHypervisor(BaseHypervisor.BaseHypervisor):
37
  """Fake hypervisor interface.
38

  
39
  This can be used for testing the ganeti code without having to have
40
  a real virtualisation software installed.
41

  
42
  """
43
  _ROOT_DIR = constants.RUN_DIR + "/ganeti-fake-hypervisor"
44

  
45
  def __init__(self):
46
    BaseHypervisor.__init__(self)
47
    if not os.path.exists(self._ROOT_DIR):
48
      os.mkdir(self._ROOT_DIR)
49

  
50
  def ListInstances(self):
51
    """Get the list of running instances.
52

  
53
    """
54
    return os.listdir(self._ROOT_DIR)
55

  
56
  def GetInstanceInfo(self, instance_name):
57
    """Get instance properties.
58

  
59
    Args:
60
      instance_name: the instance name
61

  
62
    Returns:
63
      (name, id, memory, vcpus, stat, times)
64
    """
65
    file_name = "%s/%s" % (self._ROOT_DIR, instance_name)
66
    if not os.path.exists(file_name):
67
      return None
68
    try:
69
      fh = file(file_name, "r")
70
      try:
71
        inst_id = fh.readline().strip()
72
        memory = fh.readline().strip()
73
        vcpus = fh.readline().strip()
74
        stat = "---b-"
75
        times = "0"
76
        return (instance_name, inst_id, memory, vcpus, stat, times)
77
      finally:
78
        fh.close()
79
    except IOError, err:
80
      raise errors.HypervisorError("Failed to list instance %s: %s" %
81
                                   (instance_name, err))
82

  
83
  def GetAllInstancesInfo(self):
84
    """Get properties of all instances.
85

  
86
    Returns:
87
      [(name, id, memory, vcpus, stat, times),...]
88
    """
89
    data = []
90
    for file_name in os.listdir(self._ROOT_DIR):
91
      try:
92
        fh = file(self._ROOT_DIR+"/"+file_name, "r")
93
        inst_id = "-1"
94
        memory = "0"
95
        stat = "-----"
96
        times = "-1"
97
        try:
98
          inst_id = fh.readline().strip()
99
          memory = fh.readline().strip()
100
          vcpus = fh.readline().strip()
101
          stat = "---b-"
102
          times = "0"
103
        finally:
104
          fh.close()
105
        data.append((file_name, inst_id, memory, vcpus, stat, times))
106
      except IOError, err:
107
        raise errors.HypervisorError("Failed to list instances: %s" % err)
108
    return data
109

  
110
  def StartInstance(self, instance, force, extra_args):
111
    """Start an instance.
112

  
113
    For the fake hypervisor, it just creates a file in the base dir,
114
    creating an exception if it already exists. We don't actually
115
    handle race conditions properly, since these are *FAKE* instances.
116

  
117
    """
118
    file_name = self._ROOT_DIR + "/%s" % instance.name
119
    if os.path.exists(file_name):
120
      raise errors.HypervisorError("Failed to start instance %s: %s" %
121
                                   (instance.name, "already running"))
122
    try:
123
      fh = file(file_name, "w")
124
      try:
125
        fh.write("0\n%d\n%d\n" % (instance.memory, instance.vcpus))
126
      finally:
127
        fh.close()
128
    except IOError, err:
129
      raise errors.HypervisorError("Failed to start instance %s: %s" %
130
                                   (instance.name, err))
131

  
132
  def StopInstance(self, instance, force=False):
133
    """Stop an instance.
134

  
135
    For the fake hypervisor, this just removes the file in the base
136
    dir, if it exist, otherwise we raise an exception.
137

  
138
    """
139
    file_name = self._ROOT_DIR + "/%s" % instance.name
140
    if not os.path.exists(file_name):
141
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
142
                                   (instance.name, "not running"))
143
    utils.RemoveFile(file_name)
144

  
145
  def RebootInstance(self, instance):
146
    """Reboot an instance.
147

  
148
    For the fake hypervisor, this does nothing.
149

  
150
    """
151
    return
152

  
153
  def GetNodeInfo(self):
154
    """Return information about the node.
155

  
156
    The return value is a dict, which has to have the following items:
157
      (all values in MiB)
158
      - memory_total: the total memory size on the node
159
      - memory_free: the available memory on the node for instances
160
      - memory_dom0: the memory used by the node itself, if available
161

  
162
    """
163
    # global ram usage from the xm info command
164
    # memory                 : 3583
165
    # free_memory            : 747
166
    # note: in xen 3, memory has changed to total_memory
167
    try:
168
      fh = file("/proc/meminfo")
169
      try:
170
        data = fh.readlines()
171
      finally:
172
        fh.close()
173
    except IOError, err:
174
      raise errors.HypervisorError("Failed to list node info: %s" % err)
175

  
176
    result = {}
177
    sum_free = 0
178
    for line in data:
179
      splitfields = line.split(":", 1)
180

  
181
      if len(splitfields) > 1:
182
        key = splitfields[0].strip()
183
        val = splitfields[1].strip()
184
        if key == 'MemTotal':
185
          result['memory_total'] = int(val.split()[0])/1024
186
        elif key in ('MemFree', 'Buffers', 'Cached'):
187
          sum_free += int(val.split()[0])/1024
188
        elif key == 'Active':
189
          result['memory_dom0'] = int(val.split()[0])/1024
190
    result['memory_free'] = sum_free
191

  
192
    cpu_total = 0
193
    try:
194
      fh = open("/proc/cpuinfo")
195
      try:
196
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
197
                                   fh.read()))
198
      finally:
199
        fh.close()
200
    except EnvironmentError, err:
201
      raise HypervisorError("Failed to list node info: %s" % err)
202
    result['cpu_total'] = cpu_total
203

  
204
    return result
205

  
206
  @staticmethod
207
  def GetShellCommandForConsole(instance):
208
    """Return a command for connecting to the console of an instance.
209

  
210
    """
211
    return "echo Console not available for fake hypervisor"
212

  
213
  def Verify(self):
214
    """Verify the hypervisor.
215

  
216
    For the fake hypervisor, it just checks the existence of the base
217
    dir.
218

  
219
    """
220
    if not os.path.exists(self._ROOT_DIR):
221
      return "The required directory '%s' does not exist." % self._ROOT_DIR
b/lib/hypervisor/Makefile.am
1 1
CLEANFILES = *.py[oc]
2 2

  
3 3
hypervisordir = $(pkgpythondir)/hypervisor
4
hypervisor_PYTHON = __init__.py XenHypervisor.py FakeHypervisor.py \
5
	BaseHypervisor.py
4
hypervisor_PYTHON = __init__.py hv_base.py hv_fake.py hv_xen.py
6 5
python_files = $(hypervisor_PYTHON)
7 6

  
8 7
include $(srcdir)/../Makefile.libcommon
/dev/null
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
from cStringIO import StringIO
30

  
31
from ganeti import constants
32
from ganeti import errors
33
from ganeti import logger
34
from ganeti import utils
35
from ganeti.hypervisor import BaseHypervisor
36

  
37

  
38
class XenHypervisor(BaseHypervisor.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

  
46
  @staticmethod
47
  def _WriteConfigFile(instance, block_devices, extra_args):
48
    """Write the Xen config file for the instance.
49

  
50
    """
51
    raise NotImplementedError
52

  
53
  @staticmethod
54
  def _RemoveConfigFile(instance):
55
    """Remove the xen configuration file.
56

  
57
    """
58
    utils.RemoveFile("/etc/xen/%s" % instance.name)
59

  
60
  @staticmethod
61
  def _GetXMList(include_node):
62
    """Return the list of running instances.
63

  
64
    If the `include_node` argument is True, then we return information
65
    for dom0 also, otherwise we filter that from the return value.
66

  
67
    The return value is a list of (name, id, memory, vcpus, state, time spent)
68

  
69
    """
70
    for dummy in range(5):
71
      result = utils.RunCmd(["xm", "list"])
72
      if not result.failed:
73
        break
74
      logger.Error("xm list failed (%s): %s" % (result.fail_reason,
75
                                                result.output))
76
      time.sleep(1)
77

  
78
    if result.failed:
79
      raise errors.HypervisorError("xm list failed, retries"
80
                                   " exceeded (%s): %s" %
81
                                   (result.fail_reason, result.stderr))
82

  
83
    # skip over the heading
84
    lines = result.stdout.splitlines()[1:]
85
    result = []
86
    for line in lines:
87
      # The format of lines is:
88
      # Name      ID Mem(MiB) VCPUs State  Time(s)
89
      # Domain-0   0  3418     4 r-----    266.2
90
      data = line.split()
91
      if len(data) != 6:
92
        raise errors.HypervisorError("Can't parse output of xm list,"
93
                                     " line: %s" % line)
94
      try:
95
        data[1] = int(data[1])
96
        data[2] = int(data[2])
97
        data[3] = int(data[3])
98
        data[5] = float(data[5])
99
      except ValueError, err:
100
        raise errors.HypervisorError("Can't parse output of xm list,"
101
                                     " line: %s, error: %s" % (line, err))
102

  
103
      # skip the Domain-0 (optional)
104
      if include_node or data[0] != 'Domain-0':
105
        result.append(data)
106

  
107
    return result
108

  
109
  def ListInstances(self):
110
    """Get the list of running instances.
111

  
112
    """
113
    xm_list = self._GetXMList(False)
114
    names = [info[0] for info in xm_list]
115
    return names
116

  
117
  def GetInstanceInfo(self, instance_name):
118
    """Get instance properties.
119

  
120
    Args:
121
      instance_name: the instance name
122

  
123
    Returns:
124
      (name, id, memory, vcpus, stat, times)
125
    """
126
    xm_list = self._GetXMList(instance_name=="Domain-0")
127
    result = None
128
    for data in xm_list:
129
      if data[0] == instance_name:
130
        result = data
131
        break
132
    return result
133

  
134
  def GetAllInstancesInfo(self):
135
    """Get properties of all instances.
136

  
137
    Returns:
138
      [(name, id, memory, vcpus, stat, times),...]
139
    """
140
    xm_list = self._GetXMList(False)
141
    return xm_list
142

  
143
  def StartInstance(self, instance, block_devices, extra_args):
144
    """Start an instance."""
145
    self._WriteConfigFile(instance, block_devices, extra_args)
146
    result = utils.RunCmd(["xm", "create", instance.name])
147

  
148
    if result.failed:
149
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
150
                                   (instance.name, result.fail_reason,
151
                                    result.output))
152

  
153
  def StopInstance(self, instance, force=False):
154
    """Stop an instance."""
155
    self._RemoveConfigFile(instance)
156
    if force:
157
      command = ["xm", "destroy", instance.name]
158
    else:
159
      command = ["xm", "shutdown", instance.name]
160
    result = utils.RunCmd(command)
161

  
162
    if result.failed:
163
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
164
                                   (instance.name, result.fail_reason))
165

  
166
  def RebootInstance(self, instance):
167
    """Reboot an instance."""
168
    result = utils.RunCmd(["xm", "reboot", instance.name])
169

  
170
    if result.failed:
171
      raise errors.HypervisorError("Failed to reboot instance %s: %s" %
172
                                   (instance.name, result.fail_reason))
173

  
174
  def GetNodeInfo(self):
175
    """Return information about the node.
176

  
177
    The return value is a dict, which has to have the following items:
178
      (all values in MiB)
179
      - memory_total: the total memory size on the node
180
      - memory_free: the available memory on the node for instances
181
      - memory_dom0: the memory used by the node itself, if available
182

  
183
    """
184
    # note: in xen 3, memory has changed to total_memory
185
    result = utils.RunCmd(["xm", "info"])
186
    if result.failed:
187
      logger.Error("Can't run 'xm info': %s" % result.fail_reason)
188
      return None
189

  
190
    xmoutput = result.stdout.splitlines()
191
    result = {}
192
    for line in xmoutput:
193
      splitfields = line.split(":", 1)
194

  
195
      if len(splitfields) > 1:
196
        key = splitfields[0].strip()
197
        val = splitfields[1].strip()
198
        if key == 'memory' or key == 'total_memory':
199
          result['memory_total'] = int(val)
200
        elif key == 'free_memory':
201
          result['memory_free'] = int(val)
202
        elif key == 'nr_cpus':
203
          result['cpu_total'] = int(val)
204
    dom0_info = self.GetInstanceInfo("Domain-0")
205
    if dom0_info is not None:
206
      result['memory_dom0'] = dom0_info[2]
207

  
208
    return result
209

  
210
  @staticmethod
211
  def GetShellCommandForConsole(instance):
212
    """Return a command for connecting to the console of an instance.
213

  
214
    """
215
    raise NotImplementedError
216

  
217

  
218
  def Verify(self):
219
    """Verify the hypervisor.
220

  
221
    For Xen, this verifies that the xend process is running.
222

  
223
    """
224
    if not utils.CheckDaemonAlive('/var/run/xend.pid', 'xend'):
225
      return "xend daemon is not running"
226

  
227
  @staticmethod
228
  def _GetConfigFileDiskData(disk_template, block_devices):
229
    """Get disk directive for xen config file.
230

  
231
    This method builds the xen config disk directive according to the
232
    given disk_template and block_devices.
233

  
234
    Args:
235
      disk_template: String containing instance disk template
236
      block_devices: List[tuple1,tuple2,...]
237
        tuple: (cfdev, rldev)
238
          cfdev: dict containing ganeti config disk part
239
          rldev: ganeti.bdev.BlockDev object
240

  
241
    Returns:
242
      String containing disk directive for xen instance config file
243

  
244
    """
245
    FILE_DRIVER_MAP = {
246
      constants.FD_LOOP: "file",
247
      constants.FD_BLKTAP: "tap:aio",
248
      }
249
    disk_data = []
250
    for cfdev, rldev in block_devices:
251
      if cfdev.dev_type == constants.LD_FILE:
252
        line = "'%s:%s,%s,w'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
253
                                 rldev.dev_path, cfdev.iv_name)
254
      else:
255
        line = "'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
256
      disk_data.append(line)
257

  
258
    return disk_data
259

  
260

  
261
class XenPvmHypervisor(XenHypervisor):
262
  """Xen PVM hypervisor interface"""
263

  
264
  @classmethod
265
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
266
    """Write the Xen config file for the instance.
267

  
268
    """
269
    config = StringIO()
270
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
271

  
272
    # kernel handling
273
    if instance.kernel_path in (None, constants.VALUE_DEFAULT):
274
      kpath = constants.XEN_KERNEL
275
    else:
276
      if not os.path.exists(instance.kernel_path):
277
        raise errors.HypervisorError("The kernel %s for instance %s is"
278
                                     " missing" % (instance.kernel_path,
279
                                                   instance.name))
280
      kpath = instance.kernel_path
281
    config.write("kernel = '%s'\n" % kpath)
282

  
283
    # initrd handling
284
    if instance.initrd_path in (None, constants.VALUE_DEFAULT):
285
      if os.path.exists(constants.XEN_INITRD):
286
        initrd_path = constants.XEN_INITRD
287
      else:
288
        initrd_path = None
289
    elif instance.initrd_path == constants.VALUE_NONE:
290
      initrd_path = None
291
    else:
292
      if not os.path.exists(instance.initrd_path):
293
        raise errors.HypervisorError("The initrd %s for instance %s is"
294
                                     " missing" % (instance.initrd_path,
295
                                                   instance.name))
296
      initrd_path = instance.initrd_path
297

  
298
    if initrd_path:
299
      config.write("ramdisk = '%s'\n" % initrd_path)
300

  
301
    # rest of the settings
302
    config.write("memory = %d\n" % instance.memory)
303
    config.write("vcpus = %d\n" % instance.vcpus)
304
    config.write("name = '%s'\n" % instance.name)
305

  
306
    vif_data = []
307
    for nic in instance.nics:
308
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
309
      ip = getattr(nic, "ip", None)
310
      if ip is not None:
311
        nic_str += ", ip=%s" % ip
312
      vif_data.append("'%s'" % nic_str)
313

  
314
    config.write("vif = [%s]\n" % ",".join(vif_data))
315
    config.write("disk = [%s]\n" % ",".join(
316
                 cls._GetConfigFileDiskData(instance.disk_template,
317
                                            block_devices)))
318
    config.write("root = '/dev/sda ro'\n")
319
    config.write("on_poweroff = 'destroy'\n")
320
    config.write("on_reboot = 'restart'\n")
321
    config.write("on_crash = 'restart'\n")
322
    if extra_args:
323
      config.write("extra = '%s'\n" % extra_args)
324
    # just in case it exists
325
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
326
    try:
327
      f = open("/etc/xen/%s" % instance.name, "w")
328
      try:
329
        f.write(config.getvalue())
330
      finally:
331
        f.close()
332
    except IOError, err:
333
      raise errors.OpExecError("Cannot write Xen instance confile"
334
                               " file /etc/xen/%s: %s" % (instance.name, err))
335
    return True
336

  
337
  @staticmethod
338
  def GetShellCommandForConsole(instance):
339
    """Return a command for connecting to the console of an instance.
340

  
341
    """
342
    return "xm console %s" % instance.name
343

  
344

  
345
class XenHvmHypervisor(XenHypervisor):
346
  """Xen HVM hypervisor interface"""
347

  
348
  @classmethod
349
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
350
    """Create a Xen 3.1 HVM config file.
351

  
352
    """
353
    config = StringIO()
354
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
355
    config.write("kernel = '/usr/lib/xen/boot/hvmloader'\n")
356
    config.write("builder = 'hvm'\n")
357
    config.write("memory = %d\n" % instance.memory)
358
    config.write("vcpus = %d\n" % instance.vcpus)
359
    config.write("name = '%s'\n" % instance.name)
360
    config.write("pae = 1\n")
361
    config.write("acpi = 1\n")
362
    config.write("apic = 1\n")
363
    arch = os.uname()[4]
364
    if '64' in arch:
365
      config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
366
    else:
367
      config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
368
    if instance.hvm_boot_order is None:
369
      config.write("boot = '%s'\n" % constants.HT_HVM_DEFAULT_BOOT_ORDER)
370
    else:
371
      config.write("boot = '%s'\n" % instance.hvm_boot_order)
372
    config.write("sdl = 0\n")
373
    config.write("usb = 1\n");
374
    config.write("usbdevice = 'tablet'\n");
375
    config.write("vnc = 1\n")
376
    config.write("vnclisten = '0.0.0.0'\n")
377

  
378
    if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
379
      display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
380
      config.write("vncdisplay = %s\n" % display)
381
      config.write("vncunused = 0\n")
382
    else:
383
      config.write("# vncdisplay = 1\n")
384
      config.write("vncunused = 1\n")
385

  
386
    try:
387
      password_file = open(constants.VNC_PASSWORD_FILE, "r")
388
      try:
389
        password = password_file.readline()
390
      finally:
391
        password_file.close()
392
    except IOError:
393
      raise errors.OpExecError("failed to open VNC password file %s " %
394
                               constants.VNC_PASSWORD_FILE)
395

  
396
    config.write("vncpasswd = '%s'\n" % password.rstrip())
397

  
398
    config.write("serial = 'pty'\n")
399
    config.write("localtime = 1\n")
400

  
401
    vif_data = []
402
    for nic in instance.nics:
403
      nic_str = "mac=%s, bridge=%s, type=ioemu" % (nic.mac, nic.bridge)
404
      ip = getattr(nic, "ip", None)
405
      if ip is not None:
406
        nic_str += ", ip=%s" % ip
407
      vif_data.append("'%s'" % nic_str)
408

  
409
    config.write("vif = [%s]\n" % ",".join(vif_data))
410
    iso = "'file:/srv/ganeti/iso/hvm-install.iso,hdc:cdrom,r'"
411
    config.write("disk = [%s, %s]\n" % (",".join(
412
                 cls._GetConfigFileDiskData(instance.disk_template,
413
                                            block_devices)), iso))
414
    config.write("on_poweroff = 'destroy'\n")
415
    config.write("on_reboot = 'restart'\n")
416
    config.write("on_crash = 'restart'\n")
417
    if extra_args:
418
      config.write("extra = '%s'\n" % extra_args)
419
    # just in case it exists
420
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
421
    try:
422
      f = open("/etc/xen/%s" % instance.name, "w")
423
      try:
424
        f.write(config.getvalue())
425
      finally:
426
        f.close()
427
    except IOError, err:
428
      raise errors.OpExecError("Cannot write Xen instance confile"
429
                               " file /etc/xen/%s: %s" % (instance.name, err))
430
    return True
431

  
432
  @staticmethod
433
  def GetShellCommandForConsole(instance):
434
    """Return a command for connecting to the console of an instance.
435

  
436
    """
437
    if instance.network_port is None:
438
      raise errors.OpExecError("no console port defined for %s"
439
                               % instance.name)
440
    else:
441
      raise errors.OpExecError("no PTY console, connect to %s:%s via VNC"
442
                               % (instance.primary_node,
443
                                  instance.network_port))
b/lib/hypervisor/__init__.py
27 27
from ganeti import constants
28 28
from ganeti import errors
29 29

  
30
from ganeti.hypervisor import FakeHypervisor
31
from ganeti.hypervisor import XenHypervisor
30
from ganeti.hypervisor import hv_fake
31
from ganeti.hypervisor import hv_xen
32 32

  
33 33

  
34 34
def GetHypervisor():
......
40 40
  """
41 41
  ht_kind = ssconf.SimpleStore().GetHypervisorType()
42 42
  if ht_kind == constants.HT_XEN_PVM30:
43
    cls = XenHypervisor.XenPvmHypervisor
43
    cls = hv_xen.XenPvmHypervisor
44 44
  elif ht_kind == constants.HT_XEN_HVM31:
45
    cls = XenHypervisor.XenHvmHypervisor
45
    cls = hv_xen.XenHvmHypervisor
46 46
  elif ht_kind == constants.HT_FAKE:
47
    cls = FakeHypervisor.FakeHypervisor
47
    cls = hv_fake.FakeHypervisor
48 48
  else:
49 49
    raise errors.HypervisorError("Unknown hypervisor type '%s'" % ht_kind)
50 50
  return cls()
b/lib/hypervisor/hv_base.py
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
"""Base class for all hypervisors
23

  
24
"""
25

  
26
class BaseHypervisor(object):
27
  """Abstract virtualisation technology interface
28

  
29
  The goal is that all aspects of the virtualisation technology must
30
  be abstracted away from the rest of code.
31

  
32
  """
33
  def __init__(self):
34
    pass
35

  
36
  def StartInstance(self, instance, block_devices, extra_args):
37
    """Start an instance."""
38
    raise NotImplementedError
39

  
40
  def StopInstance(self, instance, force=False):
41
    """Stop an instance."""
42
    raise NotImplementedError
43

  
44
  def RebootInstance(self, instance):
45
    """Reboot an instance."""
46
    raise NotImplementedError
47

  
48
  def ListInstances(self):
49
    """Get the list of running instances."""
50
    raise NotImplementedError
51

  
52
  def GetInstanceInfo(self, instance_name):
53
    """Get instance properties.
54

  
55
    Args:
56
      instance_name: the instance name
57

  
58
    Returns:
59
      (name, id, memory, vcpus, state, times)
60

  
61
    """
62
    raise NotImplementedError
63

  
64
  def GetAllInstancesInfo(self):
65
    """Get properties of all instances.
66

  
67
    Returns:
68
      [(name, id, memory, vcpus, stat, times),...]
69
    """
70
    raise NotImplementedError
71

  
72
  def GetNodeInfo(self):
73
    """Return information about the node.
74

  
75
    The return value is a dict, which has to have the following items:
76
      (all values in MiB)
77
      - memory_total: the total memory size on the node
78
      - memory_free: the available memory on the node for instances
79
      - memory_dom0: the memory used by the node itself, if available
80

  
81
    """
82
    raise NotImplementedError
83

  
84
  @staticmethod
85
  def GetShellCommandForConsole(instance):
86
    """Return a command for connecting to the console of an instance.
87

  
88
    """
89
    raise NotImplementedError
90

  
91
  def Verify(self):
92
    """Verify the hypervisor.
93

  
94
    """
95
    raise NotImplementedError
b/lib/hypervisor/hv_fake.py
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
"""Fake hypervisor
23

  
24
"""
25

  
26
import os
27
import os.path
28
import re
29

  
30
from ganeti import utils
31
from ganeti import constants
32
from ganeti import errors
33
from ganeti.hypervisor import hv_base
34

  
35

  
36
class FakeHypervisor(hv_base.BaseHypervisor):
37
  """Fake hypervisor interface.
38

  
39
  This can be used for testing the ganeti code without having to have
40
  a real virtualisation software installed.
41

  
42
  """
43
  _ROOT_DIR = constants.RUN_DIR + "/ganeti-fake-hypervisor"
44

  
45
  def __init__(self):
46
    hv_base.BaseHypervisor.__init__(self)
47
    if not os.path.exists(self._ROOT_DIR):
48
      os.mkdir(self._ROOT_DIR)
49

  
50
  def ListInstances(self):
51
    """Get the list of running instances.
52

  
53
    """
54
    return os.listdir(self._ROOT_DIR)
55

  
56
  def GetInstanceInfo(self, instance_name):
57
    """Get instance properties.
58

  
59
    Args:
60
      instance_name: the instance name
61

  
62
    Returns:
63
      (name, id, memory, vcpus, stat, times)
64
    """
65
    file_name = "%s/%s" % (self._ROOT_DIR, instance_name)
66
    if not os.path.exists(file_name):
67
      return None
68
    try:
69
      fh = file(file_name, "r")
70
      try:
71
        inst_id = fh.readline().strip()
72
        memory = fh.readline().strip()
73
        vcpus = fh.readline().strip()
74
        stat = "---b-"
75
        times = "0"
76
        return (instance_name, inst_id, memory, vcpus, stat, times)
77
      finally:
78
        fh.close()
79
    except IOError, err:
80
      raise errors.HypervisorError("Failed to list instance %s: %s" %
81
                                   (instance_name, err))
82

  
83
  def GetAllInstancesInfo(self):
84
    """Get properties of all instances.
85

  
86
    Returns:
87
      [(name, id, memory, vcpus, stat, times),...]
88
    """
89
    data = []
90
    for file_name in os.listdir(self._ROOT_DIR):
91
      try:
92
        fh = file(self._ROOT_DIR+"/"+file_name, "r")
93
        inst_id = "-1"
94
        memory = "0"
95
        stat = "-----"
96
        times = "-1"
97
        try:
98
          inst_id = fh.readline().strip()
99
          memory = fh.readline().strip()
100
          vcpus = fh.readline().strip()
101
          stat = "---b-"
102
          times = "0"
103
        finally:
104
          fh.close()
105
        data.append((file_name, inst_id, memory, vcpus, stat, times))
106
      except IOError, err:
107
        raise errors.HypervisorError("Failed to list instances: %s" % err)
108
    return data
109

  
110
  def StartInstance(self, instance, force, extra_args):
111
    """Start an instance.
112

  
113
    For the fake hypervisor, it just creates a file in the base dir,
114
    creating an exception if it already exists. We don't actually
115
    handle race conditions properly, since these are *FAKE* instances.
116

  
117
    """
118
    file_name = self._ROOT_DIR + "/%s" % instance.name
119
    if os.path.exists(file_name):
120
      raise errors.HypervisorError("Failed to start instance %s: %s" %
121
                                   (instance.name, "already running"))
122
    try:
123
      fh = file(file_name, "w")
124
      try:
125
        fh.write("0\n%d\n%d\n" % (instance.memory, instance.vcpus))
126
      finally:
127
        fh.close()
128
    except IOError, err:
129
      raise errors.HypervisorError("Failed to start instance %s: %s" %
130
                                   (instance.name, err))
131

  
132
  def StopInstance(self, instance, force=False):
133
    """Stop an instance.
134

  
135
    For the fake hypervisor, this just removes the file in the base
136
    dir, if it exist, otherwise we raise an exception.
137

  
138
    """
139
    file_name = self._ROOT_DIR + "/%s" % instance.name
140
    if not os.path.exists(file_name):
141
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
142
                                   (instance.name, "not running"))
143
    utils.RemoveFile(file_name)
144

  
145
  def RebootInstance(self, instance):
146
    """Reboot an instance.
147

  
148
    For the fake hypervisor, this does nothing.
149

  
150
    """
151
    return
152

  
153
  def GetNodeInfo(self):
154
    """Return information about the node.
155

  
156
    The return value is a dict, which has to have the following items:
157
      (all values in MiB)
158
      - memory_total: the total memory size on the node
159
      - memory_free: the available memory on the node for instances
160
      - memory_dom0: the memory used by the node itself, if available
161

  
162
    """
163
    # global ram usage from the xm info command
164
    # memory                 : 3583
165
    # free_memory            : 747
166
    # note: in xen 3, memory has changed to total_memory
167
    try:
168
      fh = file("/proc/meminfo")
169
      try:
170
        data = fh.readlines()
171
      finally:
172
        fh.close()
173
    except IOError, err:
174
      raise errors.HypervisorError("Failed to list node info: %s" % err)
175

  
176
    result = {}
177
    sum_free = 0
178
    for line in data:
179
      splitfields = line.split(":", 1)
180

  
181
      if len(splitfields) > 1:
182
        key = splitfields[0].strip()
183
        val = splitfields[1].strip()
184
        if key == 'MemTotal':
185
          result['memory_total'] = int(val.split()[0])/1024
186
        elif key in ('MemFree', 'Buffers', 'Cached'):
187
          sum_free += int(val.split()[0])/1024
188
        elif key == 'Active':
189
          result['memory_dom0'] = int(val.split()[0])/1024
190
    result['memory_free'] = sum_free
191

  
192
    cpu_total = 0
193
    try:
194
      fh = open("/proc/cpuinfo")
195
      try:
196
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
197
                                   fh.read()))
198
      finally:
199
        fh.close()
200
    except EnvironmentError, err:
201
      raise HypervisorError("Failed to list node info: %s" % err)
202
    result['cpu_total'] = cpu_total
203

  
204
    return result
205

  
206
  @staticmethod
207
  def GetShellCommandForConsole(instance):
208
    """Return a command for connecting to the console of an instance.
209

  
210
    """
211
    return "echo Console not available for fake hypervisor"
212

  
213
  def Verify(self):
214
    """Verify the hypervisor.
215

  
216
    For the fake hypervisor, it just checks the existence of the base
217
    dir.
218

  
219
    """
220
    if not os.path.exists(self._ROOT_DIR):
221
      return "The required directory '%s' does not exist." % self._ROOT_DIR
b/lib/hypervisor/hv_xen.py
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
from cStringIO import StringIO
30

  
31
from ganeti import constants
32
from ganeti import errors
33
from ganeti import logger
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

  
46
  @staticmethod
47
  def _WriteConfigFile(instance, block_devices, extra_args):
48
    """Write the Xen config file for the instance.
49

  
50
    """
51
    raise NotImplementedError
52

  
53
  @staticmethod
54
  def _RemoveConfigFile(instance):
55
    """Remove the xen configuration file.
56

  
57
    """
58
    utils.RemoveFile("/etc/xen/%s" % instance.name)
59

  
60
  @staticmethod
61
  def _GetXMList(include_node):
62
    """Return the list of running instances.
63

  
64
    If the `include_node` argument is True, then we return information
65
    for dom0 also, otherwise we filter that from the return value.
66

  
67
    The return value is a list of (name, id, memory, vcpus, state, time spent)
68

  
69
    """
70
    for dummy in range(5):
71
      result = utils.RunCmd(["xm", "list"])
72
      if not result.failed:
73
        break
74
      logger.Error("xm list failed (%s): %s" % (result.fail_reason,
75
                                                result.output))
76
      time.sleep(1)
77

  
78
    if result.failed:
79
      raise errors.HypervisorError("xm list failed, retries"
80
                                   " exceeded (%s): %s" %
81
                                   (result.fail_reason, result.stderr))
82

  
83
    # skip over the heading
84
    lines = result.stdout.splitlines()[1:]
85
    result = []
86
    for line in lines:
87
      # The format of lines is:
88
      # Name      ID Mem(MiB) VCPUs State  Time(s)
89
      # Domain-0   0  3418     4 r-----    266.2
90
      data = line.split()
91
      if len(data) != 6:
92
        raise errors.HypervisorError("Can't parse output of xm list,"
93
                                     " line: %s" % line)
94
      try:
95
        data[1] = int(data[1])
96
        data[2] = int(data[2])
97
        data[3] = int(data[3])
98
        data[5] = float(data[5])
99
      except ValueError, err:
100
        raise errors.HypervisorError("Can't parse output of xm list,"
101
                                     " line: %s, error: %s" % (line, err))
102

  
103
      # skip the Domain-0 (optional)
104
      if include_node or data[0] != 'Domain-0':
105
        result.append(data)
106

  
107
    return result
108

  
109
  def ListInstances(self):
110
    """Get the list of running instances.
111

  
112
    """
113
    xm_list = self._GetXMList(False)
114
    names = [info[0] for info in xm_list]
115
    return names
116

  
117
  def GetInstanceInfo(self, instance_name):
118
    """Get instance properties.
119

  
120
    Args:
121
      instance_name: the instance name
122

  
123
    Returns:
124
      (name, id, memory, vcpus, stat, times)
125
    """
126
    xm_list = self._GetXMList(instance_name=="Domain-0")
127
    result = None
128
    for data in xm_list:
129
      if data[0] == instance_name:
130
        result = data
131
        break
132
    return result
133

  
134
  def GetAllInstancesInfo(self):
135
    """Get properties of all instances.
136

  
137
    Returns:
138
      [(name, id, memory, vcpus, stat, times),...]
139
    """
140
    xm_list = self._GetXMList(False)
141
    return xm_list
142

  
143
  def StartInstance(self, instance, block_devices, extra_args):
144
    """Start an instance."""
145
    self._WriteConfigFile(instance, block_devices, extra_args)
146
    result = utils.RunCmd(["xm", "create", instance.name])
147

  
148
    if result.failed:
149
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
150
                                   (instance.name, result.fail_reason,
151
                                    result.output))
152

  
153
  def StopInstance(self, instance, force=False):
154
    """Stop an instance."""
155
    self._RemoveConfigFile(instance)
156
    if force:
157
      command = ["xm", "destroy", instance.name]
158
    else:
159
      command = ["xm", "shutdown", instance.name]
160
    result = utils.RunCmd(command)
161

  
162
    if result.failed:
163
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
164
                                   (instance.name, result.fail_reason))
165

  
166
  def RebootInstance(self, instance):
167
    """Reboot an instance."""
168
    result = utils.RunCmd(["xm", "reboot", instance.name])
169

  
170
    if result.failed:
171
      raise errors.HypervisorError("Failed to reboot instance %s: %s" %
172
                                   (instance.name, result.fail_reason))
173

  
174
  def GetNodeInfo(self):
175
    """Return information about the node.
176

  
177
    The return value is a dict, which has to have the following items:
178
      (all values in MiB)
179
      - memory_total: the total memory size on the node
180
      - memory_free: the available memory on the node for instances
181
      - memory_dom0: the memory used by the node itself, if available
182

  
183
    """
184
    # note: in xen 3, memory has changed to total_memory
185
    result = utils.RunCmd(["xm", "info"])
186
    if result.failed:
187
      logger.Error("Can't run 'xm info': %s" % result.fail_reason)
188
      return None
189

  
190
    xmoutput = result.stdout.splitlines()
191
    result = {}
192
    for line in xmoutput:
193
      splitfields = line.split(":", 1)
194

  
195
      if len(splitfields) > 1:
196
        key = splitfields[0].strip()
197
        val = splitfields[1].strip()
198
        if key == 'memory' or key == 'total_memory':
199
          result['memory_total'] = int(val)
200
        elif key == 'free_memory':
201
          result['memory_free'] = int(val)
202
        elif key == 'nr_cpus':
203
          result['cpu_total'] = int(val)
204
    dom0_info = self.GetInstanceInfo("Domain-0")
205
    if dom0_info is not None:
206
      result['memory_dom0'] = dom0_info[2]
207

  
208
    return result
209

  
210
  @staticmethod
211
  def GetShellCommandForConsole(instance):
212
    """Return a command for connecting to the console of an instance.
213

  
214
    """
215
    raise NotImplementedError
216

  
217

  
218
  def Verify(self):
219
    """Verify the hypervisor.
220

  
221
    For Xen, this verifies that the xend process is running.
222

  
223
    """
224
    if not utils.CheckDaemonAlive('/var/run/xend.pid', 'xend'):
225
      return "xend daemon is not running"
226

  
227
  @staticmethod
228
  def _GetConfigFileDiskData(disk_template, block_devices):
229
    """Get disk directive for xen config file.
230

  
231
    This method builds the xen config disk directive according to the
232
    given disk_template and block_devices.
233

  
234
    Args:
235
      disk_template: String containing instance disk template
236
      block_devices: List[tuple1,tuple2,...]
237
        tuple: (cfdev, rldev)
238
          cfdev: dict containing ganeti config disk part
239
          rldev: ganeti.bdev.BlockDev object
240

  
241
    Returns:
242
      String containing disk directive for xen instance config file
243

  
244
    """
245
    FILE_DRIVER_MAP = {
246
      constants.FD_LOOP: "file",
247
      constants.FD_BLKTAP: "tap:aio",
248
      }
249
    disk_data = []
250
    for cfdev, rldev in block_devices:
251
      if cfdev.dev_type == constants.LD_FILE:
252
        line = "'%s:%s,%s,w'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
253
                                 rldev.dev_path, cfdev.iv_name)
254
      else:
255
        line = "'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
256
      disk_data.append(line)
257

  
258
    return disk_data
259

  
260

  
261
class XenPvmHypervisor(XenHypervisor):
262
  """Xen PVM hypervisor interface"""
263

  
264
  @classmethod
265
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
266
    """Write the Xen config file for the instance.
267

  
268
    """
269
    config = StringIO()
270
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
271

  
272
    # kernel handling
273
    if instance.kernel_path in (None, constants.VALUE_DEFAULT):
274
      kpath = constants.XEN_KERNEL
275
    else:
276
      if not os.path.exists(instance.kernel_path):
277
        raise errors.HypervisorError("The kernel %s for instance %s is"
278
                                     " missing" % (instance.kernel_path,
279
                                                   instance.name))
280
      kpath = instance.kernel_path
281
    config.write("kernel = '%s'\n" % kpath)
282

  
283
    # initrd handling
284
    if instance.initrd_path in (None, constants.VALUE_DEFAULT):
285
      if os.path.exists(constants.XEN_INITRD):
286
        initrd_path = constants.XEN_INITRD
287
      else:
288
        initrd_path = None
289
    elif instance.initrd_path == constants.VALUE_NONE:
290
      initrd_path = None
291
    else:
292
      if not os.path.exists(instance.initrd_path):
293
        raise errors.HypervisorError("The initrd %s for instance %s is"
294
                                     " missing" % (instance.initrd_path,
295
                                                   instance.name))
296
      initrd_path = instance.initrd_path
297

  
298
    if initrd_path:
299
      config.write("ramdisk = '%s'\n" % initrd_path)
300

  
301
    # rest of the settings
302
    config.write("memory = %d\n" % instance.memory)
303
    config.write("vcpus = %d\n" % instance.vcpus)
304
    config.write("name = '%s'\n" % instance.name)
305

  
306
    vif_data = []
307
    for nic in instance.nics:
308
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
309
      ip = getattr(nic, "ip", None)
310
      if ip is not None:
311
        nic_str += ", ip=%s" % ip
312
      vif_data.append("'%s'" % nic_str)
313

  
314
    config.write("vif = [%s]\n" % ",".join(vif_data))
315
    config.write("disk = [%s]\n" % ",".join(
316
                 cls._GetConfigFileDiskData(instance.disk_template,
317
                                            block_devices)))
318
    config.write("root = '/dev/sda ro'\n")
319
    config.write("on_poweroff = 'destroy'\n")
320
    config.write("on_reboot = 'restart'\n")
321
    config.write("on_crash = 'restart'\n")
322
    if extra_args:
323
      config.write("extra = '%s'\n" % extra_args)
324
    # just in case it exists
325
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
326
    try:
327
      f = open("/etc/xen/%s" % instance.name, "w")
328
      try:
329
        f.write(config.getvalue())
330
      finally:
331
        f.close()
332
    except IOError, err:
333
      raise errors.OpExecError("Cannot write Xen instance confile"
334
                               " file /etc/xen/%s: %s" % (instance.name, err))
335
    return True
336

  
337
  @staticmethod
338
  def GetShellCommandForConsole(instance):
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff