Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 0a903309

History | View | Annotate | Download (30.8 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 61eb1a46 Guido Trotter
  def _WriteConfigFile(cls, instance, startup_memory, block_devices):
344 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
345 65a6f9b7 Michael Hanselmann

346 65a6f9b7 Michael Hanselmann
    """
347 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
348 65a6f9b7 Michael Hanselmann
349 0a903309 Michael Hanselmann
  def _WriteConfigFileStatic(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 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
427 c41eea6e Iustin Pop
    """Start an instance.
428 c41eea6e Iustin Pop

429 c41eea6e Iustin Pop
    """
430 61eb1a46 Guido Trotter
    startup_memory = self._InstanceStartupMemory(instance)
431 61eb1a46 Guido Trotter
    self._WriteConfigFile(instance, startup_memory, block_devices)
432 2876c2d6 Guido Trotter
    cmd = [constants.XEN_CMD, "create"]
433 323f9095 Stephen Shirley
    if startup_paused:
434 6555373d Guido Trotter
      cmd.extend(["-p"])
435 6555373d Guido Trotter
    cmd.extend([self._ConfigFileName(instance.name)])
436 323f9095 Stephen Shirley
    result = utils.RunCmd(cmd)
437 65a6f9b7 Michael Hanselmann
438 65a6f9b7 Michael Hanselmann
    if result.failed:
439 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
440 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
441 65a6f9b7 Michael Hanselmann
                                    result.output))
442 65a6f9b7 Michael Hanselmann
443 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
444 c41eea6e Iustin Pop
    """Stop an instance.
445 c41eea6e Iustin Pop

446 c41eea6e Iustin Pop
    """
447 bbcf7ad0 Iustin Pop
    if name is None:
448 bbcf7ad0 Iustin Pop
      name = instance.name
449 bbcf7ad0 Iustin Pop
    self._RemoveConfigFile(name)
450 65a6f9b7 Michael Hanselmann
    if force:
451 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "destroy", name]
452 65a6f9b7 Michael Hanselmann
    else:
453 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "shutdown", name]
454 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
455 65a6f9b7 Michael Hanselmann
456 65a6f9b7 Michael Hanselmann
    if result.failed:
457 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
458 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
459 65a6f9b7 Michael Hanselmann
460 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
461 c41eea6e Iustin Pop
    """Reboot an instance.
462 c41eea6e Iustin Pop

463 c41eea6e Iustin Pop
    """
464 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
465 65a6f9b7 Michael Hanselmann
466 e0561198 Iustin Pop
    if ini_info is None:
467 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
468 e0561198 Iustin Pop
                                   " not running" % instance.name)
469 e0561198 Iustin Pop
470 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
471 65a6f9b7 Michael Hanselmann
    if result.failed:
472 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
473 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
474 3213d3c8 Iustin Pop
                                    result.output))
475 06b78e8b Michael Hanselmann
476 06b78e8b Michael Hanselmann
    def _CheckInstance():
477 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
478 06b78e8b Michael Hanselmann
479 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
480 e0561198 Iustin Pop
      if (new_info is not None and
481 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
482 06b78e8b Michael Hanselmann
        return
483 7dd106d3 Iustin Pop
484 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
485 06b78e8b Michael Hanselmann
486 06b78e8b Michael Hanselmann
    try:
487 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
488 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
489 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
490 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
491 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
492 7dd106d3 Iustin Pop
                                   (instance.name, ))
493 65a6f9b7 Michael Hanselmann
494 2c7a0373 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
495 2c7a0373 Guido Trotter
    """Balloon an instance memory to a certain value.
496 2c7a0373 Guido Trotter

497 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
498 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
499 2c7a0373 Guido Trotter
    @type mem: int
500 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
501 2c7a0373 Guido Trotter

502 2c7a0373 Guido Trotter
    """
503 2c7a0373 Guido Trotter
    cmd = [constants.XEN_CMD, "mem-set", instance.name, mem]
504 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
505 2c7a0373 Guido Trotter
    if result.failed:
506 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
507 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
508 2c7a0373 Guido Trotter
                                    result.output))
509 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
510 0a903309 Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
511 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
512 2c7a0373 Guido Trotter
    if result.failed:
513 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
514 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
515 2c7a0373 Guido Trotter
                                    result.output))
516 2c7a0373 Guido Trotter
517 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
518 65a6f9b7 Michael Hanselmann
    """Return information about the node.
519 65a6f9b7 Michael Hanselmann

520 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
521 65a6f9b7 Michael Hanselmann

522 65a6f9b7 Michael Hanselmann
    """
523 06c9a520 Michael Hanselmann
    # TODO: Abstract running Xen command for testing
524 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
525 65a6f9b7 Michael Hanselmann
    if result.failed:
526 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
527 b48909c8 Iustin Pop
                    result.output)
528 65a6f9b7 Michael Hanselmann
      return None
529 65a6f9b7 Michael Hanselmann
530 06c9a520 Michael Hanselmann
    return _GetNodeInfo(result.stdout, self._GetXmList)
531 65a6f9b7 Michael Hanselmann
532 637ce7f9 Guido Trotter
  @classmethod
533 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
534 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
535 65a6f9b7 Michael Hanselmann

536 65a6f9b7 Michael Hanselmann
    """
537 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
538 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
539 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
540 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
541 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
542 1f5557ca Guido Trotter
                                            constants.XEN_CMD, instance.name])
543 65a6f9b7 Michael Hanselmann
544 65a6f9b7 Michael Hanselmann
  def Verify(self):
545 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
546 65a6f9b7 Michael Hanselmann

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

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

551 65a6f9b7 Michael Hanselmann
    """
552 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
553 e3e66f02 Michael Hanselmann
    if result.failed:
554 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
555 65a6f9b7 Michael Hanselmann
556 cd04dfd2 Michael Hanselmann
    return None
557 cd04dfd2 Michael Hanselmann
558 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
559 4390ccff Guido Trotter
    """Get instance information to perform a migration.
560 4390ccff Guido Trotter

561 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
562 4390ccff Guido Trotter
    @param instance: instance to be migrated
563 4390ccff Guido Trotter
    @rtype: string
564 4390ccff Guido Trotter
    @return: content of the xen config file
565 4390ccff Guido Trotter

566 4390ccff Guido Trotter
    """
567 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
568 4390ccff Guido Trotter
569 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
570 4390ccff Guido Trotter
    """Prepare to accept an instance.
571 4390ccff Guido Trotter

572 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
573 4390ccff Guido Trotter
    @param instance: instance to be accepted
574 4390ccff Guido Trotter
    @type info: string
575 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
576 4390ccff Guido Trotter
    @type target: string
577 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
578 4390ccff Guido Trotter

579 4390ccff Guido Trotter
    """
580 4390ccff Guido Trotter
    pass
581 4390ccff Guido Trotter
582 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
583 4390ccff Guido Trotter
    """Finalize an instance migration.
584 4390ccff Guido Trotter

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

588 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
589 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
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 success: boolean
593 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
594 4390ccff Guido Trotter

595 4390ccff Guido Trotter
    """
596 4390ccff Guido Trotter
    if success:
597 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
598 4390ccff Guido Trotter
599 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
600 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
601 6e7275c0 Iustin Pop

602 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
603 6e7275c0 Iustin Pop
    currently running.
604 6e7275c0 Iustin Pop

605 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
606 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
607 fdf7f055 Guido Trotter
    @type target: string
608 fdf7f055 Guido Trotter
    @param target: ip address of the target node
609 fdf7f055 Guido Trotter
    @type live: boolean
610 fdf7f055 Guido Trotter
    @param live: perform a live migration
611 fdf7f055 Guido Trotter

612 6e7275c0 Iustin Pop
    """
613 58d38b02 Iustin Pop
    if self.GetInstanceInfo(instance.name) is None:
614 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
615 50716be0 Iustin Pop
616 641ae041 Iustin Pop
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
617 50716be0 Iustin Pop
618 3135de69 Guido Trotter
    if (constants.XEN_CMD == constants.XEN_CMD_XM and
619 3135de69 Guido Trotter
        not netutils.TcpPing(target, port, live_port_needed=True)):
620 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
621 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
622 50716be0 Iustin Pop
623 0625d08f René Nussbaumer
    args = [constants.XEN_CMD, "migrate"]
624 0625d08f René Nussbaumer
    if constants.XEN_CMD == constants.XEN_CMD_XM:
625 0625d08f René Nussbaumer
      args.extend(["-p", "%d" % port])
626 0625d08f René Nussbaumer
      if live:
627 0625d08f René Nussbaumer
        args.append("-l")
628 0625d08f René Nussbaumer
    elif constants.XEN_CMD == constants.XEN_CMD_XL:
629 053c356a Guido Trotter
      cluster_name = ssconf.SimpleStore().GetClusterName()
630 053c356a Guido Trotter
      args.extend(["-s", constants.XL_SSH_CMD % cluster_name])
631 0625d08f René Nussbaumer
      args.extend(["-C", self._ConfigFileName(instance.name)])
632 0625d08f René Nussbaumer
    else:
633 0625d08f René Nussbaumer
      raise errors.HypervisorError("Unsupported xen command: %s" %
634 0625d08f René Nussbaumer
                                   constants.XEN_CMD)
635 0625d08f René Nussbaumer
636 58d38b02 Iustin Pop
    args.extend([instance.name, target])
637 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
638 6e7275c0 Iustin Pop
    if result.failed:
639 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
640 58d38b02 Iustin Pop
                                   (instance.name, result.output))
641 60af751d Andrea Spadaccini
642 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
643 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
644 60af751d Andrea Spadaccini

645 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
646 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
647 60af751d Andrea Spadaccini
    @type success: bool
648 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
649 60af751d Andrea Spadaccini
    @type live: bool
650 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
651 60af751d Andrea Spadaccini

652 60af751d Andrea Spadaccini
    """
653 60af751d Andrea Spadaccini
    # pylint: disable=W0613
654 60af751d Andrea Spadaccini
    if success:
655 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
656 60af751d Andrea Spadaccini
      try:
657 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
658 60af751d Andrea Spadaccini
      except EnvironmentError:
659 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
660 60af751d Andrea Spadaccini
661 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
662 60af751d Andrea Spadaccini
    """Get the migration status
663 60af751d Andrea Spadaccini

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

668 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
669 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
670 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
671 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
672 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
673 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
674 60af751d Andrea Spadaccini

675 60af751d Andrea Spadaccini
    """
676 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
677 6e7275c0 Iustin Pop
678 f5118ade Iustin Pop
  @classmethod
679 f5118ade Iustin Pop
  def PowercycleNode(cls):
680 f5118ade Iustin Pop
    """Xen-specific powercycle.
681 f5118ade Iustin Pop

682 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
683 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
684 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
685 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
686 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
687 f5118ade Iustin Pop
    daemon is not working.
688 f5118ade Iustin Pop

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

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

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