Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 30e4e741

History | View | Annotate | Download (21.4 kB)

1 65a6f9b7 Michael Hanselmann
#
2 65a6f9b7 Michael Hanselmann
#
3 65a6f9b7 Michael Hanselmann
4 65a6f9b7 Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 Google Inc.
5 65a6f9b7 Michael Hanselmann
#
6 65a6f9b7 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 65a6f9b7 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 65a6f9b7 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 65a6f9b7 Michael Hanselmann
# (at your option) any later version.
10 65a6f9b7 Michael Hanselmann
#
11 65a6f9b7 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 65a6f9b7 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 65a6f9b7 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 65a6f9b7 Michael Hanselmann
# General Public License for more details.
15 65a6f9b7 Michael Hanselmann
#
16 65a6f9b7 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 65a6f9b7 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 65a6f9b7 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 65a6f9b7 Michael Hanselmann
# 02110-1301, USA.
20 65a6f9b7 Michael Hanselmann
21 65a6f9b7 Michael Hanselmann
22 65a6f9b7 Michael Hanselmann
"""Xen hypervisors
23 65a6f9b7 Michael Hanselmann

24 65a6f9b7 Michael Hanselmann
"""
25 65a6f9b7 Michael Hanselmann
26 b48909c8 Iustin Pop
import logging
27 65a6f9b7 Michael Hanselmann
from cStringIO import StringIO
28 65a6f9b7 Michael Hanselmann
29 65a6f9b7 Michael Hanselmann
from ganeti import constants
30 65a6f9b7 Michael Hanselmann
from ganeti import errors
31 65a6f9b7 Michael Hanselmann
from ganeti import utils
32 a2d32034 Michael Hanselmann
from ganeti.hypervisor import hv_base
33 65a6f9b7 Michael Hanselmann
34 65a6f9b7 Michael Hanselmann
35 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
36 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
37 65a6f9b7 Michael Hanselmann

38 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
39 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
40 65a6f9b7 Michael Hanselmann

41 65a6f9b7 Michael Hanselmann
  """
42 7dd106d3 Iustin Pop
  REBOOT_RETRY_COUNT = 60
43 7dd106d3 Iustin Pop
  REBOOT_RETRY_INTERVAL = 10
44 65a6f9b7 Michael Hanselmann
45 3680f662 Guido Trotter
  ANCILLARY_FILES = [
46 3680f662 Guido Trotter
    '/etc/xen/xend-config.sxp',
47 3680f662 Guido Trotter
    '/etc/xen/scripts/vif-bridge',
48 3680f662 Guido Trotter
    ]
49 3680f662 Guido Trotter
50 5661b908 Iustin Pop
  @classmethod
51 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
52 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
53 65a6f9b7 Michael Hanselmann

54 65a6f9b7 Michael Hanselmann
    """
55 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
56 65a6f9b7 Michael Hanselmann
57 65a6f9b7 Michael Hanselmann
  @staticmethod
58 4390ccff Guido Trotter
  def _WriteConfigFileStatic(instance_name, data):
59 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
60 4390ccff Guido Trotter

61 4390ccff Guido Trotter
    This version of the function just writes the config file from static data.
62 4390ccff Guido Trotter

63 4390ccff Guido Trotter
    """
64 4390ccff Guido Trotter
    utils.WriteFile("/etc/xen/%s" % instance_name, data=data)
65 4390ccff Guido Trotter
66 4390ccff Guido Trotter
  @staticmethod
67 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
68 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
69 4390ccff Guido Trotter

70 4390ccff Guido Trotter
    """
71 4390ccff Guido Trotter
    try:
72 4390ccff Guido Trotter
      file_content = utils.ReadFile("/etc/xen/%s" % instance_name)
73 4390ccff Guido Trotter
    except EnvironmentError, err:
74 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
75 4390ccff Guido Trotter
    return file_content
76 4390ccff Guido Trotter
77 4390ccff Guido Trotter
  @staticmethod
78 53c776b5 Iustin Pop
  def _RemoveConfigFile(instance_name):
79 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
80 65a6f9b7 Michael Hanselmann

81 65a6f9b7 Michael Hanselmann
    """
82 53c776b5 Iustin Pop
    utils.RemoveFile("/etc/xen/%s" % instance_name)
83 65a6f9b7 Michael Hanselmann
84 65a6f9b7 Michael Hanselmann
  @staticmethod
85 06b78e8b Michael Hanselmann
  def _RunXmList(xmlist_errors):
86 06b78e8b Michael Hanselmann
    """Helper function for L{_GetXMList} to run "xm list".
87 06b78e8b Michael Hanselmann

88 06b78e8b Michael Hanselmann
    """
89 06b78e8b Michael Hanselmann
    result = utils.RunCmd(["xm", "list"])
90 06b78e8b Michael Hanselmann
    if result.failed:
91 06b78e8b Michael Hanselmann
      logging.error("xm list failed (%s): %s", result.fail_reason,
92 06b78e8b Michael Hanselmann
                    result.output)
93 06b78e8b Michael Hanselmann
      xmlist_errors.append(result)
94 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
95 06b78e8b Michael Hanselmann
96 06b78e8b Michael Hanselmann
    # skip over the heading
97 06b78e8b Michael Hanselmann
    return result.stdout.splitlines()[1:]
98 06b78e8b Michael Hanselmann
99 06b78e8b Michael Hanselmann
  @classmethod
100 06b78e8b Michael Hanselmann
  def _GetXMList(cls, include_node):
101 65a6f9b7 Michael Hanselmann
    """Return the list of running instances.
102 65a6f9b7 Michael Hanselmann

103 c41eea6e Iustin Pop
    If the include_node argument is True, then we return information
104 65a6f9b7 Michael Hanselmann
    for dom0 also, otherwise we filter that from the return value.
105 65a6f9b7 Michael Hanselmann

106 c41eea6e Iustin Pop
    @return: list of (name, id, memory, vcpus, state, time spent)
107 65a6f9b7 Michael Hanselmann

108 65a6f9b7 Michael Hanselmann
    """
109 06b78e8b Michael Hanselmann
    xmlist_errors = []
110 06b78e8b Michael Hanselmann
    try:
111 06b78e8b Michael Hanselmann
      lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, ))
112 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
113 06b78e8b Michael Hanselmann
      if xmlist_errors:
114 06b78e8b Michael Hanselmann
        xmlist_result = xmlist_errors.pop()
115 65a6f9b7 Michael Hanselmann
116 06b78e8b Michael Hanselmann
        errmsg = ("xm list failed, timeout exceeded (%s): %s" %
117 06b78e8b Michael Hanselmann
                  (xmlist_result.fail_reason, xmlist_result.output))
118 06b78e8b Michael Hanselmann
      else:
119 06b78e8b Michael Hanselmann
        errmsg = "xm list failed"
120 06b78e8b Michael Hanselmann
121 06b78e8b Michael Hanselmann
      raise errors.HypervisorError(errmsg)
122 65a6f9b7 Michael Hanselmann
123 65a6f9b7 Michael Hanselmann
    result = []
124 65a6f9b7 Michael Hanselmann
    for line in lines:
125 65a6f9b7 Michael Hanselmann
      # The format of lines is:
126 65a6f9b7 Michael Hanselmann
      # Name      ID Mem(MiB) VCPUs State  Time(s)
127 65a6f9b7 Michael Hanselmann
      # Domain-0   0  3418     4 r-----    266.2
128 65a6f9b7 Michael Hanselmann
      data = line.split()
129 65a6f9b7 Michael Hanselmann
      if len(data) != 6:
130 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
131 65a6f9b7 Michael Hanselmann
                                     " line: %s" % line)
132 65a6f9b7 Michael Hanselmann
      try:
133 65a6f9b7 Michael Hanselmann
        data[1] = int(data[1])
134 65a6f9b7 Michael Hanselmann
        data[2] = int(data[2])
135 65a6f9b7 Michael Hanselmann
        data[3] = int(data[3])
136 65a6f9b7 Michael Hanselmann
        data[5] = float(data[5])
137 65a6f9b7 Michael Hanselmann
      except ValueError, err:
138 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
139 65a6f9b7 Michael Hanselmann
                                     " line: %s, error: %s" % (line, err))
140 65a6f9b7 Michael Hanselmann
141 65a6f9b7 Michael Hanselmann
      # skip the Domain-0 (optional)
142 65a6f9b7 Michael Hanselmann
      if include_node or data[0] != 'Domain-0':
143 65a6f9b7 Michael Hanselmann
        result.append(data)
144 65a6f9b7 Michael Hanselmann
145 65a6f9b7 Michael Hanselmann
    return result
146 65a6f9b7 Michael Hanselmann
147 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
148 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
149 65a6f9b7 Michael Hanselmann

150 65a6f9b7 Michael Hanselmann
    """
151 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
152 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
153 65a6f9b7 Michael Hanselmann
    return names
154 65a6f9b7 Michael Hanselmann
155 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
156 65a6f9b7 Michael Hanselmann
    """Get instance properties.
157 65a6f9b7 Michael Hanselmann

158 c41eea6e Iustin Pop
    @param instance_name: the instance name
159 c41eea6e Iustin Pop

160 c41eea6e Iustin Pop
    @return: tuple (name, id, memory, vcpus, stat, times)
161 65a6f9b7 Michael Hanselmann

162 65a6f9b7 Michael Hanselmann
    """
163 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(instance_name=="Domain-0")
164 65a6f9b7 Michael Hanselmann
    result = None
165 65a6f9b7 Michael Hanselmann
    for data in xm_list:
166 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
167 65a6f9b7 Michael Hanselmann
        result = data
168 65a6f9b7 Michael Hanselmann
        break
169 65a6f9b7 Michael Hanselmann
    return result
170 65a6f9b7 Michael Hanselmann
171 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
172 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
173 65a6f9b7 Michael Hanselmann

174 c41eea6e Iustin Pop
    @return: list of tuples (name, id, memory, vcpus, stat, times)
175 c41eea6e Iustin Pop

176 65a6f9b7 Michael Hanselmann
    """
177 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
178 65a6f9b7 Michael Hanselmann
    return xm_list
179 65a6f9b7 Michael Hanselmann
180 07813a9e Iustin Pop
  def StartInstance(self, instance, block_devices):
181 c41eea6e Iustin Pop
    """Start an instance.
182 c41eea6e Iustin Pop

183 c41eea6e Iustin Pop
    """
184 07813a9e Iustin Pop
    self._WriteConfigFile(instance, block_devices)
185 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "create", instance.name])
186 65a6f9b7 Michael Hanselmann
187 65a6f9b7 Michael Hanselmann
    if result.failed:
188 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
189 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
190 65a6f9b7 Michael Hanselmann
                                    result.output))
191 65a6f9b7 Michael Hanselmann
192 07b49e41 Guido Trotter
  def StopInstance(self, instance, force=False, retry=False):
193 c41eea6e Iustin Pop
    """Stop an instance.
194 c41eea6e Iustin Pop

195 c41eea6e Iustin Pop
    """
196 53c776b5 Iustin Pop
    self._RemoveConfigFile(instance.name)
197 65a6f9b7 Michael Hanselmann
    if force:
198 65a6f9b7 Michael Hanselmann
      command = ["xm", "destroy", instance.name]
199 65a6f9b7 Michael Hanselmann
    else:
200 65a6f9b7 Michael Hanselmann
      command = ["xm", "shutdown", instance.name]
201 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
202 65a6f9b7 Michael Hanselmann
203 65a6f9b7 Michael Hanselmann
    if result.failed:
204 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
205 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
206 3213d3c8 Iustin Pop
                                    result.output))
207 65a6f9b7 Michael Hanselmann
208 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
209 c41eea6e Iustin Pop
    """Reboot an instance.
210 c41eea6e Iustin Pop

211 c41eea6e Iustin Pop
    """
212 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
213 65a6f9b7 Michael Hanselmann
214 06b78e8b Michael Hanselmann
    result = utils.RunCmd(["xm", "reboot", instance.name])
215 65a6f9b7 Michael Hanselmann
    if result.failed:
216 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
217 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
218 3213d3c8 Iustin Pop
                                    result.output))
219 06b78e8b Michael Hanselmann
220 06b78e8b Michael Hanselmann
    def _CheckInstance():
221 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
222 06b78e8b Michael Hanselmann
223 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
224 7dd106d3 Iustin Pop
      if new_info[1] != ini_info[1] or new_info[5] < ini_info[5]:
225 06b78e8b Michael Hanselmann
        return
226 7dd106d3 Iustin Pop
227 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
228 06b78e8b Michael Hanselmann
229 06b78e8b Michael Hanselmann
    try:
230 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
231 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
232 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
233 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
234 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
235 7dd106d3 Iustin Pop
                                   (instance.name, ))
236 65a6f9b7 Michael Hanselmann
237 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
238 65a6f9b7 Michael Hanselmann
    """Return information about the node.
239 65a6f9b7 Michael Hanselmann

240 0105bad3 Iustin Pop
    @return: a dict with the following keys (memory values in MiB):
241 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
242 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
243 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
244 0105bad3 Iustin Pop
          - nr_cpus: total number of CPUs
245 0105bad3 Iustin Pop
          - nr_nodes: in a NUMA system, the number of domains
246 0105bad3 Iustin Pop
          - nr_sockets: the number of physical CPU sockets in the node
247 65a6f9b7 Michael Hanselmann

248 65a6f9b7 Michael Hanselmann
    """
249 65a6f9b7 Michael Hanselmann
    # note: in xen 3, memory has changed to total_memory
250 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
251 65a6f9b7 Michael Hanselmann
    if result.failed:
252 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
253 b48909c8 Iustin Pop
                    result.output)
254 65a6f9b7 Michael Hanselmann
      return None
255 65a6f9b7 Michael Hanselmann
256 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
257 65a6f9b7 Michael Hanselmann
    result = {}
258 0105bad3 Iustin Pop
    cores_per_socket = threads_per_core = nr_cpus = None
259 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
260 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
261 65a6f9b7 Michael Hanselmann
262 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
263 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
264 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
265 65a6f9b7 Michael Hanselmann
        if key == 'memory' or key == 'total_memory':
266 65a6f9b7 Michael Hanselmann
          result['memory_total'] = int(val)
267 65a6f9b7 Michael Hanselmann
        elif key == 'free_memory':
268 65a6f9b7 Michael Hanselmann
          result['memory_free'] = int(val)
269 e8a4c138 Iustin Pop
        elif key == 'nr_cpus':
270 0105bad3 Iustin Pop
          nr_cpus = result['cpu_total'] = int(val)
271 0105bad3 Iustin Pop
        elif key == 'nr_nodes':
272 0105bad3 Iustin Pop
          result['cpu_nodes'] = int(val)
273 0105bad3 Iustin Pop
        elif key == 'cores_per_socket':
274 0105bad3 Iustin Pop
          cores_per_socket = int(val)
275 0105bad3 Iustin Pop
        elif key == 'threads_per_core':
276 0105bad3 Iustin Pop
          threads_per_core = int(val)
277 0105bad3 Iustin Pop
278 0105bad3 Iustin Pop
    if (cores_per_socket is not None and
279 0105bad3 Iustin Pop
        threads_per_core is not None and nr_cpus is not None):
280 0105bad3 Iustin Pop
      result['cpu_sockets'] = nr_cpus / (cores_per_socket * threads_per_core)
281 0105bad3 Iustin Pop
282 65a6f9b7 Michael Hanselmann
    dom0_info = self.GetInstanceInfo("Domain-0")
283 65a6f9b7 Michael Hanselmann
    if dom0_info is not None:
284 65a6f9b7 Michael Hanselmann
      result['memory_dom0'] = dom0_info[2]
285 65a6f9b7 Michael Hanselmann
286 65a6f9b7 Michael Hanselmann
    return result
287 65a6f9b7 Michael Hanselmann
288 637ce7f9 Guido Trotter
  @classmethod
289 5431b2e4 Guido Trotter
  def GetShellCommandForConsole(cls, instance, hvparams, beparams):
290 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
291 65a6f9b7 Michael Hanselmann

292 65a6f9b7 Michael Hanselmann
    """
293 04c4330c Alexander Schreiber
    return "xm console %s" % instance.name
294 04c4330c Alexander Schreiber
295 65a6f9b7 Michael Hanselmann
296 65a6f9b7 Michael Hanselmann
  def Verify(self):
297 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
298 65a6f9b7 Michael Hanselmann

299 65a6f9b7 Michael Hanselmann
    For Xen, this verifies that the xend process is running.
300 65a6f9b7 Michael Hanselmann

301 65a6f9b7 Michael Hanselmann
    """
302 e3e66f02 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
303 e3e66f02 Michael Hanselmann
    if result.failed:
304 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
305 65a6f9b7 Michael Hanselmann
306 65a6f9b7 Michael Hanselmann
  @staticmethod
307 7ed85ffe Iustin Pop
  def _GetConfigFileDiskData(block_devices):
308 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
309 65a6f9b7 Michael Hanselmann

310 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
311 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
312 65a6f9b7 Michael Hanselmann

313 c41eea6e Iustin Pop
    @param block_devices: list of tuples (cfdev, rldev):
314 c41eea6e Iustin Pop
        - cfdev: dict containing ganeti config disk part
315 c41eea6e Iustin Pop
        - rldev: ganeti.bdev.BlockDev object
316 65a6f9b7 Michael Hanselmann

317 c41eea6e Iustin Pop
    @return: string containing disk directive for xen instance config file
318 65a6f9b7 Michael Hanselmann

319 65a6f9b7 Michael Hanselmann
    """
320 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
321 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
322 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
323 65a6f9b7 Michael Hanselmann
      }
324 65a6f9b7 Michael Hanselmann
    disk_data = []
325 2864f2d9 Iustin Pop
    if len(block_devices) > 24:
326 2864f2d9 Iustin Pop
      # 'z' - 'a' = 24
327 2864f2d9 Iustin Pop
      raise errors.HypervisorError("Too many disks")
328 2864f2d9 Iustin Pop
    # FIXME: instead of this hardcoding here, each of PVM/HVM should
329 2864f2d9 Iustin Pop
    # directly export their info (currently HVM will just sed this info)
330 2864f2d9 Iustin Pop
    namespace = ["sd" + chr(i + ord('a')) for i in range(24)]
331 069cfbf1 Iustin Pop
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
332 d34b16d7 Iustin Pop
      if cfdev.mode == constants.DISK_RDWR:
333 d34b16d7 Iustin Pop
        mode = "w"
334 d34b16d7 Iustin Pop
      else:
335 d34b16d7 Iustin Pop
        mode = "r"
336 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
337 d34b16d7 Iustin Pop
        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
338 d34b16d7 Iustin Pop
                                  dev_path, sd_name, mode)
339 65a6f9b7 Michael Hanselmann
      else:
340 d34b16d7 Iustin Pop
        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
341 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
342 65a6f9b7 Michael Hanselmann
343 65a6f9b7 Michael Hanselmann
    return disk_data
344 65a6f9b7 Michael Hanselmann
345 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
346 4390ccff Guido Trotter
    """Get instance information to perform a migration.
347 4390ccff Guido Trotter

348 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
349 4390ccff Guido Trotter
    @param instance: instance to be migrated
350 4390ccff Guido Trotter
    @rtype: string
351 4390ccff Guido Trotter
    @return: content of the xen config file
352 4390ccff Guido Trotter

353 4390ccff Guido Trotter
    """
354 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
355 4390ccff Guido Trotter
356 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
357 4390ccff Guido Trotter
    """Prepare to accept an instance.
358 4390ccff Guido Trotter

359 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
360 4390ccff Guido Trotter
    @param instance: instance to be accepted
361 4390ccff Guido Trotter
    @type info: string
362 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
363 4390ccff Guido Trotter
    @type target: string
364 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
365 4390ccff Guido Trotter

366 4390ccff Guido Trotter
    """
367 4390ccff Guido Trotter
    pass
368 4390ccff Guido Trotter
369 4390ccff Guido Trotter
  def FinalizeMigration(self, instance, info, success):
370 4390ccff Guido Trotter
    """Finalize an instance migration.
371 4390ccff Guido Trotter

372 4390ccff Guido Trotter
    After a successful migration we write the xen config file.
373 4390ccff Guido Trotter
    We do nothing on a failure, as we did not change anything at accept time.
374 4390ccff Guido Trotter

375 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
376 4390ccff Guido Trotter
    @param instance: instance whose migration is being aborted
377 4390ccff Guido Trotter
    @type info: string
378 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
379 4390ccff Guido Trotter
    @type success: boolean
380 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
381 4390ccff Guido Trotter

382 4390ccff Guido Trotter
    """
383 4390ccff Guido Trotter
    if success:
384 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
385 4390ccff Guido Trotter
386 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
387 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
388 6e7275c0 Iustin Pop

389 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
390 6e7275c0 Iustin Pop
    currently running.
391 6e7275c0 Iustin Pop

392 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
393 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
394 fdf7f055 Guido Trotter
    @type target: string
395 fdf7f055 Guido Trotter
    @param target: ip address of the target node
396 fdf7f055 Guido Trotter
    @type live: boolean
397 fdf7f055 Guido Trotter
    @param live: perform a live migration
398 fdf7f055 Guido Trotter

399 6e7275c0 Iustin Pop
    """
400 58d38b02 Iustin Pop
    if self.GetInstanceInfo(instance.name) is None:
401 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
402 50716be0 Iustin Pop
403 641ae041 Iustin Pop
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
404 50716be0 Iustin Pop
405 50716be0 Iustin Pop
    if not utils.TcpPing(target, port, live_port_needed=True):
406 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
407 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
408 50716be0 Iustin Pop
409 641ae041 Iustin Pop
    args = ["xm", "migrate", "-p", "%d" % port]
410 6e7275c0 Iustin Pop
    if live:
411 6e7275c0 Iustin Pop
      args.append("-l")
412 58d38b02 Iustin Pop
    args.extend([instance.name, target])
413 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
414 6e7275c0 Iustin Pop
    if result.failed:
415 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
416 58d38b02 Iustin Pop
                                   (instance.name, result.output))
417 53c776b5 Iustin Pop
    # remove old xen file after migration succeeded
418 53c776b5 Iustin Pop
    try:
419 58d38b02 Iustin Pop
      self._RemoveConfigFile(instance.name)
420 c979d253 Iustin Pop
    except EnvironmentError:
421 c979d253 Iustin Pop
      logging.exception("Failure while removing instance config file")
422 6e7275c0 Iustin Pop
423 f5118ade Iustin Pop
  @classmethod
424 f5118ade Iustin Pop
  def PowercycleNode(cls):
425 f5118ade Iustin Pop
    """Xen-specific powercycle.
426 f5118ade Iustin Pop

427 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
428 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
429 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
430 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
431 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
432 f5118ade Iustin Pop
    daemon is not working.
433 f5118ade Iustin Pop

434 f5118ade Iustin Pop
    """
435 f5118ade Iustin Pop
    try:
436 f5118ade Iustin Pop
      cls.LinuxPowercycle()
437 f5118ade Iustin Pop
    finally:
438 f5118ade Iustin Pop
      utils.RunCmd(["xm", "debug", "R"])
439 f5118ade Iustin Pop
440 65a6f9b7 Michael Hanselmann
441 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
442 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
443 65a6f9b7 Michael Hanselmann
444 205ab586 Iustin Pop
  PARAMETERS = {
445 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
446 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
447 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
448 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
449 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
450 205ab586 Iustin Pop
    constants.HV_ROOT_PATH: hv_base.REQUIRED_CHECK,
451 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
452 78411c60 Iustin Pop
    constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
453 205ab586 Iustin Pop
    }
454 f48148c3 Iustin Pop
455 65a6f9b7 Michael Hanselmann
  @classmethod
456 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
457 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
458 65a6f9b7 Michael Hanselmann

459 65a6f9b7 Michael Hanselmann
    """
460 a985b417 Iustin Pop
    hvp = instance.hvparams
461 65a6f9b7 Michael Hanselmann
    config = StringIO()
462 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
463 65a6f9b7 Michael Hanselmann
464 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
465 2f2dbb4b Jun Futagawa
    # parameters.
466 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
467 2f2dbb4b Jun Futagawa
      # bootloader handling
468 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
469 2f2dbb4b Jun Futagawa
      if bootloader_path:
470 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
471 2f2dbb4b Jun Futagawa
      else:
472 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
473 2f2dbb4b Jun Futagawa
                                     " bootloader path")
474 65a6f9b7 Michael Hanselmann
475 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
476 2f2dbb4b Jun Futagawa
      if bootloader_args:
477 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
478 2f2dbb4b Jun Futagawa
    else:
479 2f2dbb4b Jun Futagawa
      # kernel handling
480 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
481 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
482 2f2dbb4b Jun Futagawa
483 2f2dbb4b Jun Futagawa
      # initrd handling
484 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
485 2f2dbb4b Jun Futagawa
      if initrd_path:
486 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
487 65a6f9b7 Michael Hanselmann
488 65a6f9b7 Michael Hanselmann
    # rest of the settings
489 8b3fd458 Iustin Pop
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
490 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
491 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
492 65a6f9b7 Michael Hanselmann
493 65a6f9b7 Michael Hanselmann
    vif_data = []
494 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
495 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
496 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
497 65a6f9b7 Michael Hanselmann
      if ip is not None:
498 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
499 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
500 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
501 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
502 65a6f9b7 Michael Hanselmann
503 7ed85ffe Iustin Pop
    disk_data = cls._GetConfigFileDiskData(block_devices)
504 7ed85ffe Iustin Pop
505 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
506 7ed85ffe Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
507 074ca009 Guido Trotter
508 07813a9e Iustin Pop
    config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
509 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
510 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
511 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
512 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
513 65a6f9b7 Michael Hanselmann
    # just in case it exists
514 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
515 65a6f9b7 Michael Hanselmann
    try:
516 a985b417 Iustin Pop
      utils.WriteFile("/etc/xen/%s" % instance.name, data=config.getvalue())
517 73cd67f4 Guido Trotter
    except EnvironmentError, err:
518 73cd67f4 Guido Trotter
      raise errors.HypervisorError("Cannot write Xen instance confile"
519 73cd67f4 Guido Trotter
                                   " file /etc/xen/%s: %s" %
520 73cd67f4 Guido Trotter
                                   (instance.name, err))
521 73cd67f4 Guido Trotter
522 65a6f9b7 Michael Hanselmann
    return True
523 65a6f9b7 Michael Hanselmann
524 65a6f9b7 Michael Hanselmann
525 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
526 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
527 65a6f9b7 Michael Hanselmann
528 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
529 69b99987 Michael Hanselmann
    constants.VNC_PASSWORD_FILE,
530 69b99987 Michael Hanselmann
    ]
531 3680f662 Guido Trotter
532 205ab586 Iustin Pop
  PARAMETERS = {
533 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
534 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
535 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
536 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
537 016d04b3 Michael Hanselmann
       None, None),
538 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
539 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
540 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
541 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
542 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
543 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
544 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
545 016d04b3 Michael Hanselmann
      (False, utils.IsValidIP,
546 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
547 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
548 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
549 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
550 78411c60 Iustin Pop
    constants.HV_MIGRATION_PORT: hv_base.NET_PORT_CHECK,
551 6b970cef Jun Futagawa
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
552 205ab586 Iustin Pop
    }
553 09ea8710 Iustin Pop
554 65a6f9b7 Michael Hanselmann
  @classmethod
555 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
556 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
557 65a6f9b7 Michael Hanselmann

558 65a6f9b7 Michael Hanselmann
    """
559 a985b417 Iustin Pop
    hvp = instance.hvparams
560 a985b417 Iustin Pop
561 65a6f9b7 Michael Hanselmann
    config = StringIO()
562 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
563 e2ee1cea Iustin Pop
564 e2ee1cea Iustin Pop
    # kernel handling
565 e2ee1cea Iustin Pop
    kpath = hvp[constants.HV_KERNEL_PATH]
566 e2ee1cea Iustin Pop
    config.write("kernel = '%s'\n" % kpath)
567 e2ee1cea Iustin Pop
568 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
569 8b3fd458 Iustin Pop
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
570 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
571 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
572 09ea8710 Iustin Pop
    if hvp[constants.HV_PAE]:
573 a21dda8b Iustin Pop
      config.write("pae = 1\n")
574 a21dda8b Iustin Pop
    else:
575 a21dda8b Iustin Pop
      config.write("pae = 0\n")
576 09ea8710 Iustin Pop
    if hvp[constants.HV_ACPI]:
577 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
578 a21dda8b Iustin Pop
    else:
579 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
580 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
581 09ea8710 Iustin Pop
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
582 a985b417 Iustin Pop
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
583 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
584 97efde45 Guido Trotter
    config.write("usb = 1\n")
585 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
586 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
587 a985b417 Iustin Pop
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
588 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
589 d0c11cf7 Alexander Schreiber
    else:
590 6b405598 Guido Trotter
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
591 65a6f9b7 Michael Hanselmann
592 377d74c9 Guido Trotter
    if instance.network_port > constants.VNC_BASE_PORT:
593 377d74c9 Guido Trotter
      display = instance.network_port - constants.VNC_BASE_PORT
594 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
595 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
596 65a6f9b7 Michael Hanselmann
    else:
597 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
598 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
599 65a6f9b7 Michael Hanselmann
600 6e6bb8d5 Guido Trotter
    vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
601 65a6f9b7 Michael Hanselmann
    try:
602 6e6bb8d5 Guido Trotter
      password = utils.ReadFile(vnc_pwd_file)
603 78f66a17 Guido Trotter
    except EnvironmentError, err:
604 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
605 6e6bb8d5 Guido Trotter
                                   (vnc_pwd_file, err))
606 65a6f9b7 Michael Hanselmann
607 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
608 65a6f9b7 Michael Hanselmann
609 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
610 6b970cef Jun Futagawa
    if hvp[constants.HV_USE_LOCALTIME]:
611 6b970cef Jun Futagawa
      config.write("localtime = 1\n")
612 65a6f9b7 Michael Hanselmann
613 65a6f9b7 Michael Hanselmann
    vif_data = []
614 a985b417 Iustin Pop
    nic_type = hvp[constants.HV_NIC_TYPE]
615 f48148c3 Iustin Pop
    if nic_type is None:
616 f48148c3 Iustin Pop
      # ensure old instances don't change
617 f48148c3 Iustin Pop
      nic_type_str = ", type=ioemu"
618 d08f6067 Guido Trotter
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
619 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
620 f48148c3 Iustin Pop
    else:
621 f48148c3 Iustin Pop
      nic_type_str = ", model=%s, type=ioemu" % nic_type
622 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
623 503b97a9 Guido Trotter
      nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
624 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
625 65a6f9b7 Michael Hanselmann
      if ip is not None:
626 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
627 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
628 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
629 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
630 65a6f9b7 Michael Hanselmann
631 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
632 7ed85ffe Iustin Pop
    disk_data = cls._GetConfigFileDiskData(block_devices)
633 a985b417 Iustin Pop
    disk_type = hvp[constants.HV_DISK_TYPE]
634 d08f6067 Guido Trotter
    if disk_type in (None, constants.HT_DISK_IOEMU):
635 5397e0b7 Alexander Schreiber
      replacement = ",ioemu:hd"
636 5397e0b7 Alexander Schreiber
    else:
637 5397e0b7 Alexander Schreiber
      replacement = ",hd"
638 5397e0b7 Alexander Schreiber
    disk_data = [line.replace(",sd", replacement) for line in disk_data]
639 a985b417 Iustin Pop
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
640 f48148c3 Iustin Pop
    if iso_path:
641 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
642 a21dda8b Iustin Pop
      disk_data.append(iso)
643 a21dda8b Iustin Pop
644 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
645 a21dda8b Iustin Pop
646 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
647 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
648 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
649 65a6f9b7 Michael Hanselmann
    # just in case it exists
650 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
651 65a6f9b7 Michael Hanselmann
    try:
652 73cd67f4 Guido Trotter
      utils.WriteFile("/etc/xen/%s" % instance.name,
653 73cd67f4 Guido Trotter
                      data=config.getvalue())
654 73cd67f4 Guido Trotter
    except EnvironmentError, err:
655 73cd67f4 Guido Trotter
      raise errors.HypervisorError("Cannot write Xen instance confile"
656 73cd67f4 Guido Trotter
                                   " file /etc/xen/%s: %s" %
657 73cd67f4 Guido Trotter
                                   (instance.name, err))
658 73cd67f4 Guido Trotter
659 65a6f9b7 Michael Hanselmann
    return True