Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ c3d839f5

History | View | Annotate | Download (31 kB)

1 65a6f9b7 Michael Hanselmann
#
2 65a6f9b7 Michael Hanselmann
#
3 65a6f9b7 Michael Hanselmann
4 1a63f285 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 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 d0bb3f24 Michael Hanselmann
import string # pylint: disable=W0402
28 65a6f9b7 Michael Hanselmann
from cStringIO import StringIO
29 65a6f9b7 Michael Hanselmann
30 65a6f9b7 Michael Hanselmann
from ganeti import constants
31 65a6f9b7 Michael Hanselmann
from ganeti import errors
32 65a6f9b7 Michael Hanselmann
from ganeti import utils
33 a2d32034 Michael Hanselmann
from ganeti.hypervisor import hv_base
34 a744b676 Manuel Franceschini
from ganeti import netutils
35 55cc0a44 Michael Hanselmann
from ganeti import objects
36 9d9bded1 Michael Hanselmann
from ganeti import pathutils
37 053c356a Guido Trotter
from ganeti import ssconf
38 65a6f9b7 Michael Hanselmann
39 65a6f9b7 Michael Hanselmann
40 a8e8c0c6 Michael Hanselmann
XEND_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xend-config.sxp")
41 a8e8c0c6 Michael Hanselmann
XL_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xen/xl.conf")
42 a8e8c0c6 Michael Hanselmann
VIF_BRIDGE_SCRIPT = utils.PathJoin(pathutils.XEN_CONFIG_DIR,
43 a8e8c0c6 Michael Hanselmann
                                   "scripts/vif-bridge")
44 18bf85b1 Michael Hanselmann
_DOM0_NAME = "Domain-0"
45 d0bb3f24 Michael Hanselmann
_DISK_LETTERS = string.ascii_lowercase
46 d0bb3f24 Michael Hanselmann
47 d0bb3f24 Michael Hanselmann
_FILE_DRIVER_MAP = {
48 d0bb3f24 Michael Hanselmann
  constants.FD_LOOP: "file",
49 d0bb3f24 Michael Hanselmann
  constants.FD_BLKTAP: "tap:aio",
50 d0bb3f24 Michael Hanselmann
  }
51 22d568c2 Guido Trotter
52 22d568c2 Guido Trotter
53 347fa0f1 Michael Hanselmann
def _CreateConfigCpus(cpu_mask):
54 347fa0f1 Michael Hanselmann
  """Create a CPU config string for Xen's config file.
55 347fa0f1 Michael Hanselmann

56 347fa0f1 Michael Hanselmann
  """
57 347fa0f1 Michael Hanselmann
  # Convert the string CPU mask to a list of list of int's
58 347fa0f1 Michael Hanselmann
  cpu_list = utils.ParseMultiCpuMask(cpu_mask)
59 347fa0f1 Michael Hanselmann
60 347fa0f1 Michael Hanselmann
  if len(cpu_list) == 1:
61 347fa0f1 Michael Hanselmann
    all_cpu_mapping = cpu_list[0]
62 347fa0f1 Michael Hanselmann
    if all_cpu_mapping == constants.CPU_PINNING_OFF:
63 347fa0f1 Michael Hanselmann
      # If CPU pinning has 1 entry that's "all", then remove the
64 347fa0f1 Michael Hanselmann
      # parameter from the config file
65 347fa0f1 Michael Hanselmann
      return None
66 347fa0f1 Michael Hanselmann
    else:
67 347fa0f1 Michael Hanselmann
      # If CPU pinning has one non-all entry, mapping all vCPUS (the entire
68 347fa0f1 Michael Hanselmann
      # VM) to one physical CPU, using format 'cpu = "C"'
69 347fa0f1 Michael Hanselmann
      return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
70 347fa0f1 Michael Hanselmann
  else:
71 347fa0f1 Michael Hanselmann
72 347fa0f1 Michael Hanselmann
    def _GetCPUMap(vcpu):
73 347fa0f1 Michael Hanselmann
      if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
74 347fa0f1 Michael Hanselmann
        cpu_map = constants.CPU_PINNING_ALL_XEN
75 347fa0f1 Michael Hanselmann
      else:
76 347fa0f1 Michael Hanselmann
        cpu_map = ",".join(map(str, vcpu))
77 347fa0f1 Michael Hanselmann
      return "\"%s\"" % cpu_map
78 347fa0f1 Michael Hanselmann
79 347fa0f1 Michael Hanselmann
    # build the result string in format 'cpus = [ "c", "c", "c" ]',
80 347fa0f1 Michael Hanselmann
    # where each c is a physical CPU number, a range, a list, or any
81 347fa0f1 Michael Hanselmann
    # combination
82 347fa0f1 Michael Hanselmann
    return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
83 347fa0f1 Michael Hanselmann
84 347fa0f1 Michael Hanselmann
85 b255379d Michael Hanselmann
def _RunXmList(fn, xmllist_errors):
86 b255379d Michael Hanselmann
  """Helper function for L{_GetXmList} to run "xm list".
87 b255379d Michael Hanselmann

88 b255379d Michael Hanselmann
  @type fn: callable
89 b255379d Michael Hanselmann
  @param fn: Function returning result of running C{xm list}
90 b255379d Michael Hanselmann
  @type xmllist_errors: list
91 b255379d Michael Hanselmann
  @param xmllist_errors: Error list
92 b255379d Michael Hanselmann
  @rtype: list
93 b255379d Michael Hanselmann

94 b255379d Michael Hanselmann
  """
95 b255379d Michael Hanselmann
  result = fn()
96 b255379d Michael Hanselmann
  if result.failed:
97 b255379d Michael Hanselmann
    logging.error("xm list failed (%s): %s", result.fail_reason,
98 b255379d Michael Hanselmann
                  result.output)
99 b255379d Michael Hanselmann
    xmllist_errors.append(result)
100 b255379d Michael Hanselmann
    raise utils.RetryAgain()
101 b255379d Michael Hanselmann
102 b255379d Michael Hanselmann
  # skip over the heading
103 b255379d Michael Hanselmann
  return result.stdout.splitlines()
104 b255379d Michael Hanselmann
105 b255379d Michael Hanselmann
106 b255379d Michael Hanselmann
def _ParseXmList(lines, include_node):
107 b255379d Michael Hanselmann
  """Parses the output of C{xm list}.
108 b255379d Michael Hanselmann

109 b255379d Michael Hanselmann
  @type lines: list
110 b255379d Michael Hanselmann
  @param lines: Output lines of C{xm list}
111 b255379d Michael Hanselmann
  @type include_node: boolean
112 b255379d Michael Hanselmann
  @param include_node: If True, return information for Dom0
113 b255379d Michael Hanselmann
  @return: list of tuple containing (name, id, memory, vcpus, state, time
114 b255379d Michael Hanselmann
    spent)
115 b255379d Michael Hanselmann

116 b255379d Michael Hanselmann
  """
117 b255379d Michael Hanselmann
  result = []
118 b255379d Michael Hanselmann
119 b255379d Michael Hanselmann
  # Iterate through all lines while ignoring header
120 b255379d Michael Hanselmann
  for line in lines[1:]:
121 b255379d Michael Hanselmann
    # The format of lines is:
122 b255379d Michael Hanselmann
    # Name      ID Mem(MiB) VCPUs State  Time(s)
123 b255379d Michael Hanselmann
    # Domain-0   0  3418     4 r-----    266.2
124 b255379d Michael Hanselmann
    data = line.split()
125 b255379d Michael Hanselmann
    if len(data) != 6:
126 b255379d Michael Hanselmann
      raise errors.HypervisorError("Can't parse output of xm list,"
127 b255379d Michael Hanselmann
                                   " line: %s" % line)
128 b255379d Michael Hanselmann
    try:
129 b255379d Michael Hanselmann
      data[1] = int(data[1])
130 b255379d Michael Hanselmann
      data[2] = int(data[2])
131 b255379d Michael Hanselmann
      data[3] = int(data[3])
132 b255379d Michael Hanselmann
      data[5] = float(data[5])
133 b255379d Michael Hanselmann
    except (TypeError, ValueError), err:
134 b255379d Michael Hanselmann
      raise errors.HypervisorError("Can't parse output of xm list,"
135 b255379d Michael Hanselmann
                                   " line: %s, error: %s" % (line, err))
136 b255379d Michael Hanselmann
137 b255379d Michael Hanselmann
    # skip the Domain-0 (optional)
138 b255379d Michael Hanselmann
    if include_node or data[0] != _DOM0_NAME:
139 b255379d Michael Hanselmann
      result.append(data)
140 b255379d Michael Hanselmann
141 b255379d Michael Hanselmann
  return result
142 b255379d Michael Hanselmann
143 b255379d Michael Hanselmann
144 b255379d Michael Hanselmann
def _GetXmList(fn, include_node, _timeout=5):
145 b255379d Michael Hanselmann
  """Return the list of running instances.
146 b255379d Michael Hanselmann

147 b255379d Michael Hanselmann
  See L{_RunXmList} and L{_ParseXmList} for parameter details.
148 b255379d Michael Hanselmann

149 b255379d Michael Hanselmann
  """
150 b255379d Michael Hanselmann
  xmllist_errors = []
151 b255379d Michael Hanselmann
  try:
152 b255379d Michael Hanselmann
    lines = utils.Retry(_RunXmList, (0.3, 1.5, 1.0), _timeout,
153 b255379d Michael Hanselmann
                        args=(fn, xmllist_errors))
154 b255379d Michael Hanselmann
  except utils.RetryTimeout:
155 b255379d Michael Hanselmann
    if xmllist_errors:
156 b255379d Michael Hanselmann
      xmlist_result = xmllist_errors.pop()
157 b255379d Michael Hanselmann
158 b255379d Michael Hanselmann
      errmsg = ("xm list failed, timeout exceeded (%s): %s" %
159 b255379d Michael Hanselmann
                (xmlist_result.fail_reason, xmlist_result.output))
160 b255379d Michael Hanselmann
    else:
161 b255379d Michael Hanselmann
      errmsg = "xm list failed"
162 b255379d Michael Hanselmann
163 b255379d Michael Hanselmann
    raise errors.HypervisorError(errmsg)
164 b255379d Michael Hanselmann
165 b255379d Michael Hanselmann
  return _ParseXmList(lines, include_node)
166 b255379d Michael Hanselmann
167 b255379d Michael Hanselmann
168 06c9a520 Michael Hanselmann
def _ParseNodeInfo(info):
169 06c9a520 Michael Hanselmann
  """Return information about the node.
170 06c9a520 Michael Hanselmann

171 06c9a520 Michael Hanselmann
  @return: a dict with the following keys (memory values in MiB):
172 06c9a520 Michael Hanselmann
        - memory_total: the total memory size on the node
173 06c9a520 Michael Hanselmann
        - memory_free: the available memory on the node for instances
174 06c9a520 Michael Hanselmann
        - nr_cpus: total number of CPUs
175 06c9a520 Michael Hanselmann
        - nr_nodes: in a NUMA system, the number of domains
176 06c9a520 Michael Hanselmann
        - nr_sockets: the number of physical CPU sockets in the node
177 06c9a520 Michael Hanselmann
        - hv_version: the hypervisor version in the form (major, minor)
178 06c9a520 Michael Hanselmann

179 06c9a520 Michael Hanselmann
  """
180 06c9a520 Michael Hanselmann
  result = {}
181 06c9a520 Michael Hanselmann
  cores_per_socket = threads_per_core = nr_cpus = None
182 06c9a520 Michael Hanselmann
  xen_major, xen_minor = None, None
183 06c9a520 Michael Hanselmann
  memory_total = None
184 06c9a520 Michael Hanselmann
  memory_free = None
185 06c9a520 Michael Hanselmann
186 06c9a520 Michael Hanselmann
  for line in info.splitlines():
187 06c9a520 Michael Hanselmann
    fields = line.split(":", 1)
188 06c9a520 Michael Hanselmann
189 06c9a520 Michael Hanselmann
    if len(fields) < 2:
190 06c9a520 Michael Hanselmann
      continue
191 06c9a520 Michael Hanselmann
192 06c9a520 Michael Hanselmann
    (key, val) = map(lambda s: s.strip(), fields)
193 06c9a520 Michael Hanselmann
194 06c9a520 Michael Hanselmann
    # Note: in Xen 3, memory has changed to total_memory
195 06c9a520 Michael Hanselmann
    if key in ("memory", "total_memory"):
196 06c9a520 Michael Hanselmann
      memory_total = int(val)
197 06c9a520 Michael Hanselmann
    elif key == "free_memory":
198 06c9a520 Michael Hanselmann
      memory_free = int(val)
199 06c9a520 Michael Hanselmann
    elif key == "nr_cpus":
200 06c9a520 Michael Hanselmann
      nr_cpus = result["cpu_total"] = int(val)
201 06c9a520 Michael Hanselmann
    elif key == "nr_nodes":
202 06c9a520 Michael Hanselmann
      result["cpu_nodes"] = int(val)
203 06c9a520 Michael Hanselmann
    elif key == "cores_per_socket":
204 06c9a520 Michael Hanselmann
      cores_per_socket = int(val)
205 06c9a520 Michael Hanselmann
    elif key == "threads_per_core":
206 06c9a520 Michael Hanselmann
      threads_per_core = int(val)
207 06c9a520 Michael Hanselmann
    elif key == "xen_major":
208 06c9a520 Michael Hanselmann
      xen_major = int(val)
209 06c9a520 Michael Hanselmann
    elif key == "xen_minor":
210 06c9a520 Michael Hanselmann
      xen_minor = int(val)
211 06c9a520 Michael Hanselmann
212 06c9a520 Michael Hanselmann
  if None not in [cores_per_socket, threads_per_core, nr_cpus]:
213 06c9a520 Michael Hanselmann
    result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
214 06c9a520 Michael Hanselmann
215 06c9a520 Michael Hanselmann
  if memory_free is not None:
216 06c9a520 Michael Hanselmann
    result["memory_free"] = memory_free
217 06c9a520 Michael Hanselmann
218 06c9a520 Michael Hanselmann
  if memory_total is not None:
219 06c9a520 Michael Hanselmann
    result["memory_total"] = memory_total
220 06c9a520 Michael Hanselmann
221 06c9a520 Michael Hanselmann
  if not (xen_major is None or xen_minor is None):
222 06c9a520 Michael Hanselmann
    result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
223 06c9a520 Michael Hanselmann
224 06c9a520 Michael Hanselmann
  return result
225 06c9a520 Michael Hanselmann
226 06c9a520 Michael Hanselmann
227 06c9a520 Michael Hanselmann
def _MergeInstanceInfo(info, fn):
228 06c9a520 Michael Hanselmann
  """Updates node information from L{_ParseNodeInfo} with instance info.
229 06c9a520 Michael Hanselmann

230 06c9a520 Michael Hanselmann
  @type info: dict
231 06c9a520 Michael Hanselmann
  @param info: Result from L{_ParseNodeInfo}
232 06c9a520 Michael Hanselmann
  @type fn: callable
233 06c9a520 Michael Hanselmann
  @param fn: Function returning result of running C{xm list}
234 06c9a520 Michael Hanselmann
  @rtype: dict
235 06c9a520 Michael Hanselmann

236 06c9a520 Michael Hanselmann
  """
237 06c9a520 Michael Hanselmann
  total_instmem = 0
238 06c9a520 Michael Hanselmann
239 06c9a520 Michael Hanselmann
  for (name, _, mem, vcpus, _, _) in fn(True):
240 06c9a520 Michael Hanselmann
    if name == _DOM0_NAME:
241 06c9a520 Michael Hanselmann
      info["memory_dom0"] = mem
242 06c9a520 Michael Hanselmann
      info["dom0_cpus"] = vcpus
243 06c9a520 Michael Hanselmann
244 06c9a520 Michael Hanselmann
    # Include Dom0 in total memory usage
245 06c9a520 Michael Hanselmann
    total_instmem += mem
246 06c9a520 Michael Hanselmann
247 06c9a520 Michael Hanselmann
  memory_free = info.get("memory_free")
248 06c9a520 Michael Hanselmann
  memory_total = info.get("memory_total")
249 06c9a520 Michael Hanselmann
250 06c9a520 Michael Hanselmann
  # Calculate memory used by hypervisor
251 06c9a520 Michael Hanselmann
  if None not in [memory_total, memory_free, total_instmem]:
252 06c9a520 Michael Hanselmann
    info["memory_hv"] = memory_total - memory_free - total_instmem
253 06c9a520 Michael Hanselmann
254 06c9a520 Michael Hanselmann
  return info
255 06c9a520 Michael Hanselmann
256 06c9a520 Michael Hanselmann
257 06c9a520 Michael Hanselmann
def _GetNodeInfo(info, fn):
258 06c9a520 Michael Hanselmann
  """Combines L{_MergeInstanceInfo} and L{_ParseNodeInfo}.
259 06c9a520 Michael Hanselmann

260 06c9a520 Michael Hanselmann
  """
261 06c9a520 Michael Hanselmann
  return _MergeInstanceInfo(_ParseNodeInfo(info), fn)
262 06c9a520 Michael Hanselmann
263 06c9a520 Michael Hanselmann
264 d0bb3f24 Michael Hanselmann
def _GetConfigFileDiskData(block_devices, blockdev_prefix,
265 d0bb3f24 Michael Hanselmann
                           _letters=_DISK_LETTERS):
266 d0bb3f24 Michael Hanselmann
  """Get disk directives for Xen config file.
267 d0bb3f24 Michael Hanselmann

268 d0bb3f24 Michael Hanselmann
  This method builds the xen config disk directive according to the
269 d0bb3f24 Michael Hanselmann
  given disk_template and block_devices.
270 d0bb3f24 Michael Hanselmann

271 d0bb3f24 Michael Hanselmann
  @param block_devices: list of tuples (cfdev, rldev):
272 d0bb3f24 Michael Hanselmann
      - cfdev: dict containing ganeti config disk part
273 d0bb3f24 Michael Hanselmann
      - rldev: ganeti.bdev.BlockDev object
274 d0bb3f24 Michael Hanselmann
  @param blockdev_prefix: a string containing blockdevice prefix,
275 d0bb3f24 Michael Hanselmann
                          e.g. "sd" for /dev/sda
276 d0bb3f24 Michael Hanselmann

277 d0bb3f24 Michael Hanselmann
  @return: string containing disk directive for xen instance config file
278 d0bb3f24 Michael Hanselmann

279 d0bb3f24 Michael Hanselmann
  """
280 d0bb3f24 Michael Hanselmann
  if len(block_devices) > len(_letters):
281 d0bb3f24 Michael Hanselmann
    raise errors.HypervisorError("Too many disks")
282 d0bb3f24 Michael Hanselmann
283 d0bb3f24 Michael Hanselmann
  disk_data = []
284 d0bb3f24 Michael Hanselmann
285 d0bb3f24 Michael Hanselmann
  for sd_suffix, (cfdev, dev_path) in zip(_letters, block_devices):
286 d0bb3f24 Michael Hanselmann
    sd_name = blockdev_prefix + sd_suffix
287 d0bb3f24 Michael Hanselmann
288 d0bb3f24 Michael Hanselmann
    if cfdev.mode == constants.DISK_RDWR:
289 d0bb3f24 Michael Hanselmann
      mode = "w"
290 d0bb3f24 Michael Hanselmann
    else:
291 d0bb3f24 Michael Hanselmann
      mode = "r"
292 d0bb3f24 Michael Hanselmann
293 d0bb3f24 Michael Hanselmann
    if cfdev.dev_type == constants.LD_FILE:
294 d0bb3f24 Michael Hanselmann
      driver = _FILE_DRIVER_MAP[cfdev.physical_id[0]]
295 d0bb3f24 Michael Hanselmann
    else:
296 d0bb3f24 Michael Hanselmann
      driver = "phy"
297 d0bb3f24 Michael Hanselmann
298 d0bb3f24 Michael Hanselmann
    disk_data.append("'%s:%s,%s,%s'" % (driver, dev_path, sd_name, mode))
299 d0bb3f24 Michael Hanselmann
300 d0bb3f24 Michael Hanselmann
  return disk_data
301 d0bb3f24 Michael Hanselmann
302 d0bb3f24 Michael Hanselmann
303 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
304 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
305 65a6f9b7 Michael Hanselmann

306 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
307 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
308 65a6f9b7 Michael Hanselmann

309 65a6f9b7 Michael Hanselmann
  """
310 d271c6fd Iustin Pop
  CAN_MIGRATE = True
311 7dd106d3 Iustin Pop
  REBOOT_RETRY_COUNT = 60
312 7dd106d3 Iustin Pop
  REBOOT_RETRY_INTERVAL = 10
313 65a6f9b7 Michael Hanselmann
314 3680f662 Guido Trotter
  ANCILLARY_FILES = [
315 22d568c2 Guido Trotter
    XEND_CONFIG_FILE,
316 22d568c2 Guido Trotter
    XL_CONFIG_FILE,
317 22d568c2 Guido Trotter
    VIF_BRIDGE_SCRIPT,
318 3680f662 Guido Trotter
    ]
319 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = [
320 69ab2e12 Guido Trotter
    XL_CONFIG_FILE,
321 3680f662 Guido Trotter
    ]
322 3680f662 Guido Trotter
323 0a903309 Michael Hanselmann
  def __init__(self, _cfgdir=None):
324 0a903309 Michael Hanselmann
    hv_base.BaseHypervisor.__init__(self)
325 0a903309 Michael Hanselmann
326 0a903309 Michael Hanselmann
    if _cfgdir is None:
327 0a903309 Michael Hanselmann
      self._cfgdir = pathutils.XEN_CONFIG_DIR
328 0a903309 Michael Hanselmann
    else:
329 0a903309 Michael Hanselmann
      self._cfgdir = _cfgdir
330 0a903309 Michael Hanselmann
331 0a903309 Michael Hanselmann
  def _ConfigFileName(self, instance_name):
332 c2be2532 Guido Trotter
    """Get the config file name for an instance.
333 c2be2532 Guido Trotter

334 c2be2532 Guido Trotter
    @param instance_name: instance name
335 c2be2532 Guido Trotter
    @type instance_name: str
336 c2be2532 Guido Trotter
    @return: fully qualified path to instance config file
337 c2be2532 Guido Trotter
    @rtype: str
338 c2be2532 Guido Trotter

339 c2be2532 Guido Trotter
    """
340 0a903309 Michael Hanselmann
    return utils.PathJoin(self._cfgdir, instance_name)
341 c2be2532 Guido Trotter
342 5661b908 Iustin Pop
  @classmethod
343 c3d839f5 Michael Hanselmann
  def _GetConfig(cls, instance, startup_memory, block_devices):
344 c3d839f5 Michael Hanselmann
    """Build Xen configuration for an instance.
345 65a6f9b7 Michael Hanselmann

346 65a6f9b7 Michael Hanselmann
    """
347 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
348 65a6f9b7 Michael Hanselmann
349 c3d839f5 Michael Hanselmann
  def _WriteConfigFile(self, instance_name, data):
350 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
351 4390ccff Guido Trotter

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

354 4390ccff Guido Trotter
    """
355 1a63f285 Iustin Pop
    # just in case it exists
356 0a903309 Michael Hanselmann
    utils.RemoveFile(utils.PathJoin(self._cfgdir, "auto", instance_name))
357 a8e8c0c6 Michael Hanselmann
358 0a903309 Michael Hanselmann
    cfg_file = self._ConfigFileName(instance_name)
359 1a63f285 Iustin Pop
    try:
360 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
361 1a63f285 Iustin Pop
    except EnvironmentError, err:
362 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
363 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
364 4390ccff Guido Trotter
365 0a903309 Michael Hanselmann
  def _ReadConfigFile(self, instance_name):
366 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
367 4390ccff Guido Trotter

368 4390ccff Guido Trotter
    """
369 0a903309 Michael Hanselmann
    filename = self._ConfigFileName(instance_name)
370 76c364d9 Michael Hanselmann
371 4390ccff Guido Trotter
    try:
372 76c364d9 Michael Hanselmann
      file_content = utils.ReadFile(filename)
373 4390ccff Guido Trotter
    except EnvironmentError, err:
374 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
375 76c364d9 Michael Hanselmann
376 4390ccff Guido Trotter
    return file_content
377 4390ccff Guido Trotter
378 0a903309 Michael Hanselmann
  def _RemoveConfigFile(self, instance_name):
379 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
380 65a6f9b7 Michael Hanselmann

381 65a6f9b7 Michael Hanselmann
    """
382 0a903309 Michael Hanselmann
    utils.RemoveFile(self._ConfigFileName(instance_name))
383 65a6f9b7 Michael Hanselmann
384 65a6f9b7 Michael Hanselmann
  @staticmethod
385 b255379d Michael Hanselmann
  def _GetXmList(include_node):
386 b255379d Michael Hanselmann
    """Wrapper around module level L{_GetXmList}.
387 06b78e8b Michael Hanselmann

388 06b78e8b Michael Hanselmann
    """
389 b255379d Michael Hanselmann
    # TODO: Abstract running Xen command for testing
390 b255379d Michael Hanselmann
    return _GetXmList(lambda: utils.RunCmd([constants.XEN_CMD, "list"]),
391 b255379d Michael Hanselmann
                      include_node)
392 65a6f9b7 Michael Hanselmann
393 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
394 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
395 65a6f9b7 Michael Hanselmann

396 65a6f9b7 Michael Hanselmann
    """
397 b255379d Michael Hanselmann
    xm_list = self._GetXmList(False)
398 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
399 65a6f9b7 Michael Hanselmann
    return names
400 65a6f9b7 Michael Hanselmann
401 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
402 65a6f9b7 Michael Hanselmann
    """Get instance properties.
403 65a6f9b7 Michael Hanselmann

404 c41eea6e Iustin Pop
    @param instance_name: the instance name
405 c41eea6e Iustin Pop

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

408 65a6f9b7 Michael Hanselmann
    """
409 b255379d Michael Hanselmann
    xm_list = self._GetXmList(instance_name == _DOM0_NAME)
410 65a6f9b7 Michael Hanselmann
    result = None
411 65a6f9b7 Michael Hanselmann
    for data in xm_list:
412 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
413 65a6f9b7 Michael Hanselmann
        result = data
414 65a6f9b7 Michael Hanselmann
        break
415 65a6f9b7 Michael Hanselmann
    return result
416 65a6f9b7 Michael Hanselmann
417 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
418 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
419 65a6f9b7 Michael Hanselmann

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

422 65a6f9b7 Michael Hanselmann
    """
423 b255379d Michael Hanselmann
    xm_list = self._GetXmList(False)
424 65a6f9b7 Michael Hanselmann
    return xm_list
425 65a6f9b7 Michael Hanselmann
426 c3d839f5 Michael Hanselmann
  def _MakeConfigFile(self, instance, startup_memory, block_devices):
427 c3d839f5 Michael Hanselmann
    """Gather configuration details and write to disk.
428 c3d839f5 Michael Hanselmann

429 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
430 c3d839f5 Michael Hanselmann

431 c3d839f5 Michael Hanselmann
    """
432 c3d839f5 Michael Hanselmann
    buf = StringIO()
433 c3d839f5 Michael Hanselmann
    buf.write("# Automatically generated by Ganeti. Do not edit!\n")
434 c3d839f5 Michael Hanselmann
    buf.write("\n")
435 c3d839f5 Michael Hanselmann
    buf.write(self._GetConfig(instance, startup_memory, block_devices))
436 c3d839f5 Michael Hanselmann
    buf.write("\n")
437 c3d839f5 Michael Hanselmann
438 c3d839f5 Michael Hanselmann
    self._WriteConfigFile(instance.name, buf.getvalue())
439 c3d839f5 Michael Hanselmann
440 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
441 c41eea6e Iustin Pop
    """Start an instance.
442 c41eea6e Iustin Pop

443 c41eea6e Iustin Pop
    """
444 61eb1a46 Guido Trotter
    startup_memory = self._InstanceStartupMemory(instance)
445 c3d839f5 Michael Hanselmann
446 c3d839f5 Michael Hanselmann
    self._MakeConfigFile(instance, startup_memory, block_devices)
447 c3d839f5 Michael Hanselmann
448 2876c2d6 Guido Trotter
    cmd = [constants.XEN_CMD, "create"]
449 323f9095 Stephen Shirley
    if startup_paused:
450 6555373d Guido Trotter
      cmd.extend(["-p"])
451 6555373d Guido Trotter
    cmd.extend([self._ConfigFileName(instance.name)])
452 323f9095 Stephen Shirley
    result = utils.RunCmd(cmd)
453 65a6f9b7 Michael Hanselmann
454 65a6f9b7 Michael Hanselmann
    if result.failed:
455 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
456 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
457 65a6f9b7 Michael Hanselmann
                                    result.output))
458 65a6f9b7 Michael Hanselmann
459 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
460 c41eea6e Iustin Pop
    """Stop an instance.
461 c41eea6e Iustin Pop

462 c41eea6e Iustin Pop
    """
463 bbcf7ad0 Iustin Pop
    if name is None:
464 bbcf7ad0 Iustin Pop
      name = instance.name
465 bbcf7ad0 Iustin Pop
    self._RemoveConfigFile(name)
466 65a6f9b7 Michael Hanselmann
    if force:
467 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "destroy", name]
468 65a6f9b7 Michael Hanselmann
    else:
469 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "shutdown", name]
470 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
471 65a6f9b7 Michael Hanselmann
472 65a6f9b7 Michael Hanselmann
    if result.failed:
473 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
474 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
475 65a6f9b7 Michael Hanselmann
476 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
477 c41eea6e Iustin Pop
    """Reboot an instance.
478 c41eea6e Iustin Pop

479 c41eea6e Iustin Pop
    """
480 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
481 65a6f9b7 Michael Hanselmann
482 e0561198 Iustin Pop
    if ini_info is None:
483 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
484 e0561198 Iustin Pop
                                   " not running" % instance.name)
485 e0561198 Iustin Pop
486 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
487 65a6f9b7 Michael Hanselmann
    if result.failed:
488 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
489 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
490 3213d3c8 Iustin Pop
                                    result.output))
491 06b78e8b Michael Hanselmann
492 06b78e8b Michael Hanselmann
    def _CheckInstance():
493 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
494 06b78e8b Michael Hanselmann
495 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
496 e0561198 Iustin Pop
      if (new_info is not None and
497 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
498 06b78e8b Michael Hanselmann
        return
499 7dd106d3 Iustin Pop
500 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
501 06b78e8b Michael Hanselmann
502 06b78e8b Michael Hanselmann
    try:
503 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
504 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
505 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
506 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
507 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
508 7dd106d3 Iustin Pop
                                   (instance.name, ))
509 65a6f9b7 Michael Hanselmann
510 2c7a0373 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
511 2c7a0373 Guido Trotter
    """Balloon an instance memory to a certain value.
512 2c7a0373 Guido Trotter

513 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
514 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
515 2c7a0373 Guido Trotter
    @type mem: int
516 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
517 2c7a0373 Guido Trotter

518 2c7a0373 Guido Trotter
    """
519 2c7a0373 Guido Trotter
    cmd = [constants.XEN_CMD, "mem-set", instance.name, mem]
520 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
521 2c7a0373 Guido Trotter
    if result.failed:
522 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
523 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
524 2c7a0373 Guido Trotter
                                    result.output))
525 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
526 0a903309 Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
527 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
528 2c7a0373 Guido Trotter
    if result.failed:
529 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
530 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
531 2c7a0373 Guido Trotter
                                    result.output))
532 2c7a0373 Guido Trotter
533 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
534 65a6f9b7 Michael Hanselmann
    """Return information about the node.
535 65a6f9b7 Michael Hanselmann

536 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
537 65a6f9b7 Michael Hanselmann

538 65a6f9b7 Michael Hanselmann
    """
539 06c9a520 Michael Hanselmann
    # TODO: Abstract running Xen command for testing
540 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
541 65a6f9b7 Michael Hanselmann
    if result.failed:
542 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
543 b48909c8 Iustin Pop
                    result.output)
544 65a6f9b7 Michael Hanselmann
      return None
545 65a6f9b7 Michael Hanselmann
546 06c9a520 Michael Hanselmann
    return _GetNodeInfo(result.stdout, self._GetXmList)
547 65a6f9b7 Michael Hanselmann
548 637ce7f9 Guido Trotter
  @classmethod
549 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
550 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
551 65a6f9b7 Michael Hanselmann

552 65a6f9b7 Michael Hanselmann
    """
553 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
554 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
555 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
556 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
557 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
558 1f5557ca Guido Trotter
                                            constants.XEN_CMD, instance.name])
559 65a6f9b7 Michael Hanselmann
560 65a6f9b7 Michael Hanselmann
  def Verify(self):
561 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
562 65a6f9b7 Michael Hanselmann

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

565 cd04dfd2 Michael Hanselmann
    @return: Problem description if something is wrong, C{None} otherwise
566 cd04dfd2 Michael Hanselmann

567 65a6f9b7 Michael Hanselmann
    """
568 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
569 e3e66f02 Michael Hanselmann
    if result.failed:
570 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
571 65a6f9b7 Michael Hanselmann
572 cd04dfd2 Michael Hanselmann
    return None
573 cd04dfd2 Michael Hanselmann
574 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
575 4390ccff Guido Trotter
    """Get instance information to perform a migration.
576 4390ccff Guido Trotter

577 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
578 4390ccff Guido Trotter
    @param instance: instance to be migrated
579 4390ccff Guido Trotter
    @rtype: string
580 4390ccff Guido Trotter
    @return: content of the xen config file
581 4390ccff Guido Trotter

582 4390ccff Guido Trotter
    """
583 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
584 4390ccff Guido Trotter
585 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
586 4390ccff Guido Trotter
    """Prepare to accept an instance.
587 4390ccff Guido Trotter

588 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
589 4390ccff Guido Trotter
    @param instance: instance to be accepted
590 4390ccff Guido Trotter
    @type info: string
591 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
592 4390ccff Guido Trotter
    @type target: string
593 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
594 4390ccff Guido Trotter

595 4390ccff Guido Trotter
    """
596 4390ccff Guido Trotter
    pass
597 4390ccff Guido Trotter
598 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
599 4390ccff Guido Trotter
    """Finalize an instance migration.
600 4390ccff Guido Trotter

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

604 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
605 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
606 4390ccff Guido Trotter
    @type info: string
607 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
608 4390ccff Guido Trotter
    @type success: boolean
609 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
610 4390ccff Guido Trotter

611 4390ccff Guido Trotter
    """
612 4390ccff Guido Trotter
    if success:
613 c3d839f5 Michael Hanselmann
      self._WriteConfigFile(instance.name, info)
614 4390ccff Guido Trotter
615 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
616 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
617 6e7275c0 Iustin Pop

618 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
619 6e7275c0 Iustin Pop
    currently running.
620 6e7275c0 Iustin Pop

621 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
622 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
623 fdf7f055 Guido Trotter
    @type target: string
624 fdf7f055 Guido Trotter
    @param target: ip address of the target node
625 fdf7f055 Guido Trotter
    @type live: boolean
626 fdf7f055 Guido Trotter
    @param live: perform a live migration
627 fdf7f055 Guido Trotter

628 6e7275c0 Iustin Pop
    """
629 58d38b02 Iustin Pop
    if self.GetInstanceInfo(instance.name) is None:
630 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
631 50716be0 Iustin Pop
632 641ae041 Iustin Pop
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
633 50716be0 Iustin Pop
634 3135de69 Guido Trotter
    if (constants.XEN_CMD == constants.XEN_CMD_XM and
635 3135de69 Guido Trotter
        not netutils.TcpPing(target, port, live_port_needed=True)):
636 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
637 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
638 50716be0 Iustin Pop
639 0625d08f René Nussbaumer
    args = [constants.XEN_CMD, "migrate"]
640 0625d08f René Nussbaumer
    if constants.XEN_CMD == constants.XEN_CMD_XM:
641 0625d08f René Nussbaumer
      args.extend(["-p", "%d" % port])
642 0625d08f René Nussbaumer
      if live:
643 0625d08f René Nussbaumer
        args.append("-l")
644 0625d08f René Nussbaumer
    elif constants.XEN_CMD == constants.XEN_CMD_XL:
645 053c356a Guido Trotter
      cluster_name = ssconf.SimpleStore().GetClusterName()
646 053c356a Guido Trotter
      args.extend(["-s", constants.XL_SSH_CMD % cluster_name])
647 0625d08f René Nussbaumer
      args.extend(["-C", self._ConfigFileName(instance.name)])
648 0625d08f René Nussbaumer
    else:
649 0625d08f René Nussbaumer
      raise errors.HypervisorError("Unsupported xen command: %s" %
650 0625d08f René Nussbaumer
                                   constants.XEN_CMD)
651 0625d08f René Nussbaumer
652 58d38b02 Iustin Pop
    args.extend([instance.name, target])
653 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
654 6e7275c0 Iustin Pop
    if result.failed:
655 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
656 58d38b02 Iustin Pop
                                   (instance.name, result.output))
657 60af751d Andrea Spadaccini
658 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
659 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
660 60af751d Andrea Spadaccini

661 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
662 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
663 60af751d Andrea Spadaccini
    @type success: bool
664 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
665 60af751d Andrea Spadaccini
    @type live: bool
666 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
667 60af751d Andrea Spadaccini

668 60af751d Andrea Spadaccini
    """
669 60af751d Andrea Spadaccini
    # pylint: disable=W0613
670 60af751d Andrea Spadaccini
    if success:
671 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
672 60af751d Andrea Spadaccini
      try:
673 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
674 60af751d Andrea Spadaccini
      except EnvironmentError:
675 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
676 60af751d Andrea Spadaccini
677 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
678 60af751d Andrea Spadaccini
    """Get the migration status
679 60af751d Andrea Spadaccini

680 60af751d Andrea Spadaccini
    As MigrateInstance for Xen is still blocking, if this method is called it
681 60af751d Andrea Spadaccini
    means that MigrateInstance has completed successfully. So we can safely
682 60af751d Andrea Spadaccini
    assume that the migration was successful and notify this fact to the client.
683 60af751d Andrea Spadaccini

684 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
685 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
686 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
687 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
688 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
689 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
690 60af751d Andrea Spadaccini

691 60af751d Andrea Spadaccini
    """
692 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
693 6e7275c0 Iustin Pop
694 f5118ade Iustin Pop
  @classmethod
695 f5118ade Iustin Pop
  def PowercycleNode(cls):
696 f5118ade Iustin Pop
    """Xen-specific powercycle.
697 f5118ade Iustin Pop

698 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
699 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
700 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
701 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
702 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
703 f5118ade Iustin Pop
    daemon is not working.
704 f5118ade Iustin Pop

705 f5118ade Iustin Pop
    """
706 f5118ade Iustin Pop
    try:
707 f5118ade Iustin Pop
      cls.LinuxPowercycle()
708 f5118ade Iustin Pop
    finally:
709 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
710 f5118ade Iustin Pop
711 65a6f9b7 Michael Hanselmann
712 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
713 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
714 65a6f9b7 Michael Hanselmann
715 205ab586 Iustin Pop
  PARAMETERS = {
716 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
717 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
718 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
719 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
720 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
721 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
722 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
723 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
724 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
725 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
726 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
727 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
728 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
729 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
730 2c368f28 Guido Trotter
    constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
731 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
732 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
733 205ab586 Iustin Pop
    }
734 f48148c3 Iustin Pop
735 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
736 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
737 65a6f9b7 Michael Hanselmann

738 65a6f9b7 Michael Hanselmann
    """
739 a985b417 Iustin Pop
    hvp = instance.hvparams
740 65a6f9b7 Michael Hanselmann
    config = StringIO()
741 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
742 65a6f9b7 Michael Hanselmann
743 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
744 2f2dbb4b Jun Futagawa
    # parameters.
745 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
746 2f2dbb4b Jun Futagawa
      # bootloader handling
747 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
748 2f2dbb4b Jun Futagawa
      if bootloader_path:
749 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
750 2f2dbb4b Jun Futagawa
      else:
751 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
752 2f2dbb4b Jun Futagawa
                                     " bootloader path")
753 65a6f9b7 Michael Hanselmann
754 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
755 2f2dbb4b Jun Futagawa
      if bootloader_args:
756 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
757 2f2dbb4b Jun Futagawa
    else:
758 2f2dbb4b Jun Futagawa
      # kernel handling
759 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
760 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
761 2f2dbb4b Jun Futagawa
762 2f2dbb4b Jun Futagawa
      # initrd handling
763 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
764 2f2dbb4b Jun Futagawa
      if initrd_path:
765 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
766 65a6f9b7 Michael Hanselmann
767 65a6f9b7 Michael Hanselmann
    # rest of the settings
768 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
769 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
770 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
771 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
772 c4708267 Tsachy Shacham
    if cpu_pinning:
773 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
774 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
775 8bd977e9 Sébastien Bocahu
    if cpu_cap:
776 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
777 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
778 8bd977e9 Sébastien Bocahu
    if cpu_weight:
779 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
780 c4708267 Tsachy Shacham
781 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
782 65a6f9b7 Michael Hanselmann
783 65a6f9b7 Michael Hanselmann
    vif_data = []
784 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
785 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
786 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
787 65a6f9b7 Michael Hanselmann
      if ip is not None:
788 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
789 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
790 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
791 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
792 65a6f9b7 Michael Hanselmann
793 d0bb3f24 Michael Hanselmann
    disk_data = \
794 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
795 7ed85ffe Iustin Pop
796 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
797 7ed85ffe Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
798 074ca009 Guido Trotter
799 7adf7814 René Nussbaumer
    if hvp[constants.HV_ROOT_PATH]:
800 7adf7814 René Nussbaumer
      config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
801 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
802 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
803 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
804 990ade2d Stephen Shirley
    else:
805 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
806 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
807 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
808 73cd67f4 Guido Trotter
809 c3d839f5 Michael Hanselmann
    return config.getvalue()
810 65a6f9b7 Michael Hanselmann
811 65a6f9b7 Michael Hanselmann
812 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
813 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
814 65a6f9b7 Michael Hanselmann
815 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
816 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
817 69b99987 Michael Hanselmann
    ]
818 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
819 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
820 69ab2e12 Guido Trotter
    ]
821 3680f662 Guido Trotter
822 205ab586 Iustin Pop
  PARAMETERS = {
823 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
824 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
825 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
826 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
827 016d04b3 Michael Hanselmann
       None, None),
828 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
829 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
830 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
831 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
832 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
833 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
834 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
835 8b312c1d Manuel Franceschini
      (False, netutils.IP4Address.IsValid,
836 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
837 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
838 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
839 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
840 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
841 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
842 6b970cef Jun Futagawa
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
843 e695efbf Iustin Pop
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
844 e695efbf Iustin Pop
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
845 87f0aa48 Jack
    # Add PCI passthrough
846 3891c95e Bernardo Dal Seno
    constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
847 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
848 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
849 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
850 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_CAP: hv_base.NO_CHECK,
851 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
852 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65535, "invalid weight", None, None),
853 205ab586 Iustin Pop
    }
854 09ea8710 Iustin Pop
855 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
856 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
857 65a6f9b7 Michael Hanselmann

858 65a6f9b7 Michael Hanselmann
    """
859 a985b417 Iustin Pop
    hvp = instance.hvparams
860 a985b417 Iustin Pop
861 65a6f9b7 Michael Hanselmann
    config = StringIO()
862 e2ee1cea Iustin Pop
863 e2ee1cea Iustin Pop
    # kernel handling
864 e2ee1cea Iustin Pop
    kpath = hvp[constants.HV_KERNEL_PATH]
865 e2ee1cea Iustin Pop
    config.write("kernel = '%s'\n" % kpath)
866 e2ee1cea Iustin Pop
867 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
868 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
869 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
870 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
871 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
872 c4708267 Tsachy Shacham
    if cpu_pinning:
873 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
874 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
875 8bd977e9 Sébastien Bocahu
    if cpu_cap:
876 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
877 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
878 8bd977e9 Sébastien Bocahu
    if cpu_weight:
879 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
880 c4708267 Tsachy Shacham
881 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
882 09ea8710 Iustin Pop
    if hvp[constants.HV_PAE]:
883 a21dda8b Iustin Pop
      config.write("pae = 1\n")
884 a21dda8b Iustin Pop
    else:
885 a21dda8b Iustin Pop
      config.write("pae = 0\n")
886 09ea8710 Iustin Pop
    if hvp[constants.HV_ACPI]:
887 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
888 a21dda8b Iustin Pop
    else:
889 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
890 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
891 09ea8710 Iustin Pop
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
892 a985b417 Iustin Pop
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
893 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
894 97efde45 Guido Trotter
    config.write("usb = 1\n")
895 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
896 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
897 a985b417 Iustin Pop
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
898 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
899 d0c11cf7 Alexander Schreiber
    else:
900 6b405598 Guido Trotter
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
901 65a6f9b7 Michael Hanselmann
902 377d74c9 Guido Trotter
    if instance.network_port > constants.VNC_BASE_PORT:
903 377d74c9 Guido Trotter
      display = instance.network_port - constants.VNC_BASE_PORT
904 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
905 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
906 65a6f9b7 Michael Hanselmann
    else:
907 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
908 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
909 65a6f9b7 Michael Hanselmann
910 6e6bb8d5 Guido Trotter
    vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
911 65a6f9b7 Michael Hanselmann
    try:
912 6e6bb8d5 Guido Trotter
      password = utils.ReadFile(vnc_pwd_file)
913 78f66a17 Guido Trotter
    except EnvironmentError, err:
914 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
915 6e6bb8d5 Guido Trotter
                                   (vnc_pwd_file, err))
916 65a6f9b7 Michael Hanselmann
917 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
918 65a6f9b7 Michael Hanselmann
919 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
920 6b970cef Jun Futagawa
    if hvp[constants.HV_USE_LOCALTIME]:
921 6b970cef Jun Futagawa
      config.write("localtime = 1\n")
922 65a6f9b7 Michael Hanselmann
923 65a6f9b7 Michael Hanselmann
    vif_data = []
924 a985b417 Iustin Pop
    nic_type = hvp[constants.HV_NIC_TYPE]
925 f48148c3 Iustin Pop
    if nic_type is None:
926 f48148c3 Iustin Pop
      # ensure old instances don't change
927 f48148c3 Iustin Pop
      nic_type_str = ", type=ioemu"
928 d08f6067 Guido Trotter
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
929 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
930 f48148c3 Iustin Pop
    else:
931 f48148c3 Iustin Pop
      nic_type_str = ", model=%s, type=ioemu" % nic_type
932 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
933 503b97a9 Guido Trotter
      nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
934 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
935 65a6f9b7 Michael Hanselmann
      if ip is not None:
936 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
937 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
938 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
939 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
940 65a6f9b7 Michael Hanselmann
941 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
942 525011bc Maciej Bliziński
943 d0bb3f24 Michael Hanselmann
    disk_data = \
944 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
945 525011bc Maciej Bliziński
946 a985b417 Iustin Pop
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
947 f48148c3 Iustin Pop
    if iso_path:
948 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
949 a21dda8b Iustin Pop
      disk_data.append(iso)
950 a21dda8b Iustin Pop
951 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
952 87f0aa48 Jack
    # Add PCI passthrough
953 87f0aa48 Jack
    pci_pass_arr = []
954 87f0aa48 Jack
    pci_pass = hvp[constants.HV_PASSTHROUGH]
955 87f0aa48 Jack
    if pci_pass:
956 3891c95e Bernardo Dal Seno
      pci_pass_arr = pci_pass.split(";")
957 3891c95e Bernardo Dal Seno
      config.write("pci = %s\n" % pci_pass_arr)
958 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
959 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
960 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
961 990ade2d Stephen Shirley
    else:
962 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
963 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
964 73cd67f4 Guido Trotter
965 c3d839f5 Michael Hanselmann
    return config.getvalue()