Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 84ad6b78

History | View | Annotate | Download (41.3 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 397b7844 Dimitris Aragiorgis
import errno
28 d0bb3f24 Michael Hanselmann
import string # pylint: disable=W0402
29 397b7844 Dimitris Aragiorgis
import shutil
30 65a6f9b7 Michael Hanselmann
from cStringIO import StringIO
31 65a6f9b7 Michael Hanselmann
32 65a6f9b7 Michael Hanselmann
from ganeti import constants
33 65a6f9b7 Michael Hanselmann
from ganeti import errors
34 65a6f9b7 Michael Hanselmann
from ganeti import utils
35 a2d32034 Michael Hanselmann
from ganeti.hypervisor import hv_base
36 a744b676 Manuel Franceschini
from ganeti import netutils
37 55cc0a44 Michael Hanselmann
from ganeti import objects
38 9d9bded1 Michael Hanselmann
from ganeti import pathutils
39 65a6f9b7 Michael Hanselmann
40 65a6f9b7 Michael Hanselmann
41 a8e8c0c6 Michael Hanselmann
XEND_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xend-config.sxp")
42 a8e8c0c6 Michael Hanselmann
XL_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xen/xl.conf")
43 a8e8c0c6 Michael Hanselmann
VIF_BRIDGE_SCRIPT = utils.PathJoin(pathutils.XEN_CONFIG_DIR,
44 a8e8c0c6 Michael Hanselmann
                                   "scripts/vif-bridge")
45 18bf85b1 Michael Hanselmann
_DOM0_NAME = "Domain-0"
46 d0bb3f24 Michael Hanselmann
_DISK_LETTERS = string.ascii_lowercase
47 d0bb3f24 Michael Hanselmann
48 d0bb3f24 Michael Hanselmann
_FILE_DRIVER_MAP = {
49 d0bb3f24 Michael Hanselmann
  constants.FD_LOOP: "file",
50 d0bb3f24 Michael Hanselmann
  constants.FD_BLKTAP: "tap:aio",
51 d0bb3f24 Michael Hanselmann
  }
52 22d568c2 Guido Trotter
53 22d568c2 Guido Trotter
54 347fa0f1 Michael Hanselmann
def _CreateConfigCpus(cpu_mask):
55 347fa0f1 Michael Hanselmann
  """Create a CPU config string for Xen's config file.
56 347fa0f1 Michael Hanselmann

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

90 b255379d Michael Hanselmann
  @type fn: callable
91 ff19ac20 Helga Velroyen
  @param fn: Function to query xen for the list of instances
92 ff19ac20 Helga Velroyen
  @type instance_list_errors: list
93 ff19ac20 Helga Velroyen
  @param instance_list_errors: Error list
94 b255379d Michael Hanselmann
  @rtype: list
95 b255379d Michael Hanselmann

96 b255379d Michael Hanselmann
  """
97 b255379d Michael Hanselmann
  result = fn()
98 b255379d Michael Hanselmann
  if result.failed:
99 ff19ac20 Helga Velroyen
    logging.error("Retrieving the instance list from xen failed (%s): %s",
100 ff19ac20 Helga Velroyen
                  result.fail_reason, result.output)
101 ff19ac20 Helga Velroyen
    instance_list_errors.append(result)
102 b255379d Michael Hanselmann
    raise utils.RetryAgain()
103 b255379d Michael Hanselmann
104 b255379d Michael Hanselmann
  # skip over the heading
105 b255379d Michael Hanselmann
  return result.stdout.splitlines()
106 b255379d Michael Hanselmann
107 b255379d Michael Hanselmann
108 2609da63 Helga Velroyen
def _ParseInstanceList(lines, include_node):
109 2609da63 Helga Velroyen
  """Parses the output of listing instances by xen.
110 b255379d Michael Hanselmann

111 b255379d Michael Hanselmann
  @type lines: list
112 2609da63 Helga Velroyen
  @param lines: Result of retrieving the instance list from xen
113 b255379d Michael Hanselmann
  @type include_node: boolean
114 b255379d Michael Hanselmann
  @param include_node: If True, return information for Dom0
115 b255379d Michael Hanselmann
  @return: list of tuple containing (name, id, memory, vcpus, state, time
116 b255379d Michael Hanselmann
    spent)
117 b255379d Michael Hanselmann

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

149 2609da63 Helga Velroyen
  See L{_RunInstanceList} and L{_ParseInstanceList} for parameter details.
150 b255379d Michael Hanselmann

151 b255379d Michael Hanselmann
  """
152 ff19ac20 Helga Velroyen
  instance_list_errors = []
153 b255379d Michael Hanselmann
  try:
154 ff19ac20 Helga Velroyen
    lines = utils.Retry(_RunInstanceList, (0.3, 1.5, 1.0), _timeout,
155 ff19ac20 Helga Velroyen
                        args=(fn, instance_list_errors))
156 b255379d Michael Hanselmann
  except utils.RetryTimeout:
157 ff19ac20 Helga Velroyen
    if instance_list_errors:
158 ff19ac20 Helga Velroyen
      instance_list_result = instance_list_errors.pop()
159 b255379d Michael Hanselmann
160 ff19ac20 Helga Velroyen
      errmsg = ("listing instances failed, timeout exceeded (%s): %s" %
161 ff19ac20 Helga Velroyen
                (instance_list_result.fail_reason, instance_list_result.output))
162 b255379d Michael Hanselmann
    else:
163 ff19ac20 Helga Velroyen
      errmsg = "listing instances failed"
164 b255379d Michael Hanselmann
165 b255379d Michael Hanselmann
    raise errors.HypervisorError(errmsg)
166 b255379d Michael Hanselmann
167 2609da63 Helga Velroyen
  return _ParseInstanceList(lines, include_node)
168 b255379d Michael Hanselmann
169 b255379d Michael Hanselmann
170 06c9a520 Michael Hanselmann
def _ParseNodeInfo(info):
171 06c9a520 Michael Hanselmann
  """Return information about the node.
172 06c9a520 Michael Hanselmann

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

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

232 06c9a520 Michael Hanselmann
  @type info: dict
233 06c9a520 Michael Hanselmann
  @param info: Result from L{_ParseNodeInfo}
234 fac489a5 Helga Velroyen
  @type instance_list: list of tuples
235 fac489a5 Helga Velroyen
  @param instance_list: list of instance information; one tuple per instance
236 06c9a520 Michael Hanselmann
  @rtype: dict
237 06c9a520 Michael Hanselmann

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

262 fac489a5 Helga Velroyen
  @type instance_list: list of tuples
263 fac489a5 Helga Velroyen
  @param instance_list: list of instance information; one tuple per instance
264 fac489a5 Helga Velroyen

265 06c9a520 Michael Hanselmann
  """
266 fac489a5 Helga Velroyen
  return _MergeInstanceInfo(_ParseNodeInfo(info), instance_list)
267 06c9a520 Michael Hanselmann
268 06c9a520 Michael Hanselmann
269 d0bb3f24 Michael Hanselmann
def _GetConfigFileDiskData(block_devices, blockdev_prefix,
270 d0bb3f24 Michael Hanselmann
                           _letters=_DISK_LETTERS):
271 d0bb3f24 Michael Hanselmann
  """Get disk directives for Xen config file.
272 d0bb3f24 Michael Hanselmann

273 d0bb3f24 Michael Hanselmann
  This method builds the xen config disk directive according to the
274 d0bb3f24 Michael Hanselmann
  given disk_template and block_devices.
275 d0bb3f24 Michael Hanselmann

276 d0bb3f24 Michael Hanselmann
  @param block_devices: list of tuples (cfdev, rldev):
277 d0bb3f24 Michael Hanselmann
      - cfdev: dict containing ganeti config disk part
278 ce9283c1 Thomas Thrainer
      - rldev: ganeti.block.bdev.BlockDev object
279 d0bb3f24 Michael Hanselmann
  @param blockdev_prefix: a string containing blockdevice prefix,
280 d0bb3f24 Michael Hanselmann
                          e.g. "sd" for /dev/sda
281 d0bb3f24 Michael Hanselmann

282 d0bb3f24 Michael Hanselmann
  @return: string containing disk directive for xen instance config file
283 d0bb3f24 Michael Hanselmann

284 d0bb3f24 Michael Hanselmann
  """
285 d0bb3f24 Michael Hanselmann
  if len(block_devices) > len(_letters):
286 d0bb3f24 Michael Hanselmann
    raise errors.HypervisorError("Too many disks")
287 d0bb3f24 Michael Hanselmann
288 d0bb3f24 Michael Hanselmann
  disk_data = []
289 d0bb3f24 Michael Hanselmann
290 117a85a0 Raffa Santi
  for sd_suffix, (cfdev, dev_path, _) in zip(_letters, block_devices):
291 d0bb3f24 Michael Hanselmann
    sd_name = blockdev_prefix + sd_suffix
292 d0bb3f24 Michael Hanselmann
293 d0bb3f24 Michael Hanselmann
    if cfdev.mode == constants.DISK_RDWR:
294 d0bb3f24 Michael Hanselmann
      mode = "w"
295 d0bb3f24 Michael Hanselmann
    else:
296 d0bb3f24 Michael Hanselmann
      mode = "r"
297 d0bb3f24 Michael Hanselmann
298 cd3b4ff4 Helga Velroyen
    if cfdev.dev_type in [constants.DT_FILE, constants.DT_SHARED_FILE]:
299 a57e502a Thomas Thrainer
      driver = _FILE_DRIVER_MAP[cfdev.logical_id[0]]
300 d0bb3f24 Michael Hanselmann
    else:
301 d0bb3f24 Michael Hanselmann
      driver = "phy"
302 d0bb3f24 Michael Hanselmann
303 d0bb3f24 Michael Hanselmann
    disk_data.append("'%s:%s,%s,%s'" % (driver, dev_path, sd_name, mode))
304 d0bb3f24 Michael Hanselmann
305 d0bb3f24 Michael Hanselmann
  return disk_data
306 d0bb3f24 Michael Hanselmann
307 d0bb3f24 Michael Hanselmann
308 295ed29b Santi Raffa
def _QuoteCpuidField(data):
309 295ed29b Santi Raffa
  """Add quotes around the CPUID field only if necessary.
310 295ed29b Santi Raffa

311 295ed29b Santi Raffa
  Xen CPUID fields come in two shapes: LIBXL strings, which need quotes around
312 295ed29b Santi Raffa
  them, and lists of XEND strings, which don't.
313 295ed29b Santi Raffa

314 295ed29b Santi Raffa
  @param data: Either type of parameter.
315 295ed29b Santi Raffa
  @return: The quoted version thereof.
316 295ed29b Santi Raffa

317 295ed29b Santi Raffa
  """
318 295ed29b Santi Raffa
  return "'%s'" % data if data.startswith("host") else data
319 295ed29b Santi Raffa
320 295ed29b Santi Raffa
321 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
322 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
323 65a6f9b7 Michael Hanselmann

324 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
325 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
326 65a6f9b7 Michael Hanselmann

327 65a6f9b7 Michael Hanselmann
  """
328 d271c6fd Iustin Pop
  CAN_MIGRATE = True
329 7dd106d3 Iustin Pop
  REBOOT_RETRY_COUNT = 60
330 7dd106d3 Iustin Pop
  REBOOT_RETRY_INTERVAL = 10
331 397b7844 Dimitris Aragiorgis
  _ROOT_DIR = pathutils.RUN_DIR + "/xen-hypervisor"
332 397b7844 Dimitris Aragiorgis
  _NICS_DIR = _ROOT_DIR + "/nic" # contains NICs' info
333 397b7844 Dimitris Aragiorgis
  _DIRS = [_ROOT_DIR, _NICS_DIR]
334 65a6f9b7 Michael Hanselmann
335 3680f662 Guido Trotter
  ANCILLARY_FILES = [
336 22d568c2 Guido Trotter
    XEND_CONFIG_FILE,
337 22d568c2 Guido Trotter
    XL_CONFIG_FILE,
338 22d568c2 Guido Trotter
    VIF_BRIDGE_SCRIPT,
339 3680f662 Guido Trotter
    ]
340 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = [
341 69ab2e12 Guido Trotter
    XL_CONFIG_FILE,
342 3680f662 Guido Trotter
    ]
343 3680f662 Guido Trotter
344 3d942d8b Michael Hanselmann
  def __init__(self, _cfgdir=None, _run_cmd_fn=None, _cmd=None):
345 0a903309 Michael Hanselmann
    hv_base.BaseHypervisor.__init__(self)
346 0a903309 Michael Hanselmann
347 0a903309 Michael Hanselmann
    if _cfgdir is None:
348 0a903309 Michael Hanselmann
      self._cfgdir = pathutils.XEN_CONFIG_DIR
349 0a903309 Michael Hanselmann
    else:
350 0a903309 Michael Hanselmann
      self._cfgdir = _cfgdir
351 0a903309 Michael Hanselmann
352 3d942d8b Michael Hanselmann
    if _run_cmd_fn is None:
353 3d942d8b Michael Hanselmann
      self._run_cmd_fn = utils.RunCmd
354 3d942d8b Michael Hanselmann
    else:
355 3d942d8b Michael Hanselmann
      self._run_cmd_fn = _run_cmd_fn
356 3d942d8b Michael Hanselmann
357 3d942d8b Michael Hanselmann
    self._cmd = _cmd
358 3d942d8b Michael Hanselmann
359 398fd4f6 Helga Velroyen
  def _GetCommand(self, hvparams):
360 d8784f7d Michael Hanselmann
    """Returns Xen command to use.
361 d8784f7d Michael Hanselmann

362 51a95d00 Helga Velroyen
    @type hvparams: dict of strings
363 51a95d00 Helga Velroyen
    @param hvparams: hypervisor parameters
364 51a95d00 Helga Velroyen

365 d8784f7d Michael Hanselmann
    """
366 3d942d8b Michael Hanselmann
    if self._cmd is None:
367 398fd4f6 Helga Velroyen
      if hvparams is None or constants.HV_XEN_CMD not in hvparams:
368 398fd4f6 Helga Velroyen
        raise errors.HypervisorError("Cannot determine xen command.")
369 51a95d00 Helga Velroyen
      else:
370 398fd4f6 Helga Velroyen
        cmd = hvparams[constants.HV_XEN_CMD]
371 3d942d8b Michael Hanselmann
    else:
372 3d942d8b Michael Hanselmann
      cmd = self._cmd
373 3d942d8b Michael Hanselmann
374 3d942d8b Michael Hanselmann
    if cmd not in constants.KNOWN_XEN_COMMANDS:
375 3d942d8b Michael Hanselmann
      raise errors.ProgrammerError("Unknown Xen command '%s'" % cmd)
376 3d942d8b Michael Hanselmann
377 3d942d8b Michael Hanselmann
    return cmd
378 3d942d8b Michael Hanselmann
379 398fd4f6 Helga Velroyen
  def _RunXen(self, args, hvparams):
380 81124130 Michael Hanselmann
    """Wrapper around L{utils.process.RunCmd} to run Xen command.
381 3d942d8b Michael Hanselmann

382 58e356a9 Helga Velroyen
    @type hvparams: dict of strings
383 58e356a9 Helga Velroyen
    @param hvparams: dictionary of hypervisor params
384 81124130 Michael Hanselmann
    @see: L{utils.process.RunCmd}
385 3d942d8b Michael Hanselmann

386 3d942d8b Michael Hanselmann
    """
387 398fd4f6 Helga Velroyen
    cmd = [self._GetCommand(hvparams)]
388 3d942d8b Michael Hanselmann
    cmd.extend(args)
389 3d942d8b Michael Hanselmann
390 3d942d8b Michael Hanselmann
    return self._run_cmd_fn(cmd)
391 3d942d8b Michael Hanselmann
392 0a903309 Michael Hanselmann
  def _ConfigFileName(self, instance_name):
393 c2be2532 Guido Trotter
    """Get the config file name for an instance.
394 c2be2532 Guido Trotter

395 c2be2532 Guido Trotter
    @param instance_name: instance name
396 c2be2532 Guido Trotter
    @type instance_name: str
397 c2be2532 Guido Trotter
    @return: fully qualified path to instance config file
398 c2be2532 Guido Trotter
    @rtype: str
399 c2be2532 Guido Trotter

400 c2be2532 Guido Trotter
    """
401 0a903309 Michael Hanselmann
    return utils.PathJoin(self._cfgdir, instance_name)
402 c2be2532 Guido Trotter
403 5661b908 Iustin Pop
  @classmethod
404 397b7844 Dimitris Aragiorgis
  def _WriteNICInfoFile(cls, instance_name, idx, nic):
405 397b7844 Dimitris Aragiorgis
    """Write the Xen config file for the instance.
406 397b7844 Dimitris Aragiorgis

407 397b7844 Dimitris Aragiorgis
    This version of the function just writes the config file from static data.
408 397b7844 Dimitris Aragiorgis

409 397b7844 Dimitris Aragiorgis
    """
410 397b7844 Dimitris Aragiorgis
    dirs = [(dname, constants.RUN_DIRS_MODE)
411 397b7844 Dimitris Aragiorgis
            for dname in cls._DIRS + [cls._InstanceNICDir(instance_name)]]
412 397b7844 Dimitris Aragiorgis
    utils.EnsureDirs(dirs)
413 397b7844 Dimitris Aragiorgis
414 397b7844 Dimitris Aragiorgis
    cfg_file = cls._InstanceNICFile(instance_name, idx)
415 397b7844 Dimitris Aragiorgis
    data = StringIO()
416 397b7844 Dimitris Aragiorgis
417 397b7844 Dimitris Aragiorgis
    if nic.netinfo:
418 397b7844 Dimitris Aragiorgis
      netinfo = objects.Network.FromDict(nic.netinfo)
419 397b7844 Dimitris Aragiorgis
      data.write("NETWORK_NAME=%s\n" % netinfo.name)
420 397b7844 Dimitris Aragiorgis
      if netinfo.network:
421 397b7844 Dimitris Aragiorgis
        data.write("NETWORK_SUBNET=%s\n" % netinfo.network)
422 397b7844 Dimitris Aragiorgis
      if netinfo.gateway:
423 397b7844 Dimitris Aragiorgis
        data.write("NETWORK_GATEWAY=%s\n" % netinfo.gateway)
424 397b7844 Dimitris Aragiorgis
      if netinfo.network6:
425 397b7844 Dimitris Aragiorgis
        data.write("NETWORK_SUBNET6=%s\n" % netinfo.network6)
426 397b7844 Dimitris Aragiorgis
      if netinfo.gateway6:
427 397b7844 Dimitris Aragiorgis
        data.write("NETWORK_GATEWAY6=%s\n" % netinfo.gateway6)
428 397b7844 Dimitris Aragiorgis
      if netinfo.mac_prefix:
429 397b7844 Dimitris Aragiorgis
        data.write("NETWORK_MAC_PREFIX=%s\n" % netinfo.mac_prefix)
430 397b7844 Dimitris Aragiorgis
      if netinfo.tags:
431 78f99abb Michele Tartara
        data.write("NETWORK_TAGS=%s\n" % r"\ ".join(netinfo.tags))
432 397b7844 Dimitris Aragiorgis
433 397b7844 Dimitris Aragiorgis
    data.write("MAC=%s\n" % nic.mac)
434 397b7844 Dimitris Aragiorgis
    data.write("IP=%s\n" % nic.ip)
435 397b7844 Dimitris Aragiorgis
    data.write("MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
436 397b7844 Dimitris Aragiorgis
    data.write("LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
437 397b7844 Dimitris Aragiorgis
438 397b7844 Dimitris Aragiorgis
    try:
439 397b7844 Dimitris Aragiorgis
      utils.WriteFile(cfg_file, data=data.getvalue())
440 397b7844 Dimitris Aragiorgis
    except EnvironmentError, err:
441 397b7844 Dimitris Aragiorgis
      raise errors.HypervisorError("Cannot write Xen instance configuration"
442 397b7844 Dimitris Aragiorgis
                                   " file %s: %s" % (cfg_file, err))
443 397b7844 Dimitris Aragiorgis
444 397b7844 Dimitris Aragiorgis
  @classmethod
445 397b7844 Dimitris Aragiorgis
  def _InstanceNICDir(cls, instance_name):
446 397b7844 Dimitris Aragiorgis
    """Returns the directory holding the tap device files for a given instance.
447 397b7844 Dimitris Aragiorgis

448 397b7844 Dimitris Aragiorgis
    """
449 397b7844 Dimitris Aragiorgis
    return utils.PathJoin(cls._NICS_DIR, instance_name)
450 397b7844 Dimitris Aragiorgis
451 397b7844 Dimitris Aragiorgis
  @classmethod
452 397b7844 Dimitris Aragiorgis
  def _InstanceNICFile(cls, instance_name, seq):
453 397b7844 Dimitris Aragiorgis
    """Returns the name of the file containing the tap device for a given NIC
454 397b7844 Dimitris Aragiorgis

455 397b7844 Dimitris Aragiorgis
    """
456 397b7844 Dimitris Aragiorgis
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
457 397b7844 Dimitris Aragiorgis
458 397b7844 Dimitris Aragiorgis
  @classmethod
459 c3d839f5 Michael Hanselmann
  def _GetConfig(cls, instance, startup_memory, block_devices):
460 c3d839f5 Michael Hanselmann
    """Build Xen configuration for an instance.
461 65a6f9b7 Michael Hanselmann

462 65a6f9b7 Michael Hanselmann
    """
463 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
464 65a6f9b7 Michael Hanselmann
465 c3d839f5 Michael Hanselmann
  def _WriteConfigFile(self, instance_name, data):
466 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
467 4390ccff Guido Trotter

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

470 4390ccff Guido Trotter
    """
471 1a63f285 Iustin Pop
    # just in case it exists
472 0a903309 Michael Hanselmann
    utils.RemoveFile(utils.PathJoin(self._cfgdir, "auto", instance_name))
473 a8e8c0c6 Michael Hanselmann
474 0a903309 Michael Hanselmann
    cfg_file = self._ConfigFileName(instance_name)
475 1a63f285 Iustin Pop
    try:
476 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
477 1a63f285 Iustin Pop
    except EnvironmentError, err:
478 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
479 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
480 4390ccff Guido Trotter
481 0a903309 Michael Hanselmann
  def _ReadConfigFile(self, instance_name):
482 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
483 4390ccff Guido Trotter

484 4390ccff Guido Trotter
    """
485 0a903309 Michael Hanselmann
    filename = self._ConfigFileName(instance_name)
486 76c364d9 Michael Hanselmann
487 4390ccff Guido Trotter
    try:
488 76c364d9 Michael Hanselmann
      file_content = utils.ReadFile(filename)
489 4390ccff Guido Trotter
    except EnvironmentError, err:
490 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
491 76c364d9 Michael Hanselmann
492 4390ccff Guido Trotter
    return file_content
493 4390ccff Guido Trotter
494 0a903309 Michael Hanselmann
  def _RemoveConfigFile(self, instance_name):
495 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
496 65a6f9b7 Michael Hanselmann

497 65a6f9b7 Michael Hanselmann
    """
498 0a903309 Michael Hanselmann
    utils.RemoveFile(self._ConfigFileName(instance_name))
499 397b7844 Dimitris Aragiorgis
    try:
500 397b7844 Dimitris Aragiorgis
      shutil.rmtree(self._InstanceNICDir(instance_name))
501 397b7844 Dimitris Aragiorgis
    except OSError, err:
502 397b7844 Dimitris Aragiorgis
      if err.errno != errno.ENOENT:
503 397b7844 Dimitris Aragiorgis
        raise
504 65a6f9b7 Michael Hanselmann
505 48bba9de Balazs Lecz
  def _StashConfigFile(self, instance_name):
506 48bba9de Balazs Lecz
    """Move the Xen config file to the log directory and return its new path.
507 48bba9de Balazs Lecz

508 48bba9de Balazs Lecz
    """
509 48bba9de Balazs Lecz
    old_filename = self._ConfigFileName(instance_name)
510 48bba9de Balazs Lecz
    base = ("%s-%s" %
511 48bba9de Balazs Lecz
            (instance_name, utils.TimestampForFilename()))
512 48bba9de Balazs Lecz
    new_filename = utils.PathJoin(pathutils.LOG_XEN_DIR, base)
513 48bba9de Balazs Lecz
    utils.RenameFile(old_filename, new_filename)
514 48bba9de Balazs Lecz
    return new_filename
515 48bba9de Balazs Lecz
516 398fd4f6 Helga Velroyen
  def _GetInstanceList(self, include_node, hvparams):
517 36bebc53 Helga Velroyen
    """Wrapper around module level L{_GetInstanceList}.
518 06b78e8b Michael Hanselmann

519 398fd4f6 Helga Velroyen
    @type hvparams: dict of strings
520 398fd4f6 Helga Velroyen
    @param hvparams: hypervisor parameters to be used on this node
521 398fd4f6 Helga Velroyen

522 06b78e8b Michael Hanselmann
    """
523 398fd4f6 Helga Velroyen
    return _GetInstanceList(lambda: self._RunXen(["list"], hvparams),
524 58e356a9 Helga Velroyen
                            include_node)
525 65a6f9b7 Michael Hanselmann
526 58e356a9 Helga Velroyen
  def ListInstances(self, hvparams=None):
527 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
528 65a6f9b7 Michael Hanselmann

529 65a6f9b7 Michael Hanselmann
    """
530 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(False, hvparams)
531 36bebc53 Helga Velroyen
    names = [info[0] for info in instance_list]
532 65a6f9b7 Michael Hanselmann
    return names
533 65a6f9b7 Michael Hanselmann
534 0bbec3af Helga Velroyen
  def GetInstanceInfo(self, instance_name, hvparams=None):
535 65a6f9b7 Michael Hanselmann
    """Get instance properties.
536 65a6f9b7 Michael Hanselmann

537 0bbec3af Helga Velroyen
    @type instance_name: string
538 c41eea6e Iustin Pop
    @param instance_name: the instance name
539 0bbec3af Helga Velroyen
    @type hvparams: dict of strings
540 0bbec3af Helga Velroyen
    @param hvparams: the instance's hypervisor params
541 c41eea6e Iustin Pop

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

544 65a6f9b7 Michael Hanselmann
    """
545 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(instance_name == _DOM0_NAME, hvparams)
546 65a6f9b7 Michael Hanselmann
    result = None
547 36bebc53 Helga Velroyen
    for data in instance_list:
548 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
549 65a6f9b7 Michael Hanselmann
        result = data
550 65a6f9b7 Michael Hanselmann
        break
551 65a6f9b7 Michael Hanselmann
    return result
552 65a6f9b7 Michael Hanselmann
553 0200a1af Helga Velroyen
  def GetAllInstancesInfo(self, hvparams=None):
554 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
555 65a6f9b7 Michael Hanselmann

556 0200a1af Helga Velroyen
    @type hvparams: dict of strings
557 0200a1af Helga Velroyen
    @param hvparams: hypervisor parameters
558 c41eea6e Iustin Pop
    @return: list of tuples (name, id, memory, vcpus, stat, times)
559 c41eea6e Iustin Pop

560 65a6f9b7 Michael Hanselmann
    """
561 398fd4f6 Helga Velroyen
    return self._GetInstanceList(False, hvparams)
562 65a6f9b7 Michael Hanselmann
563 c3d839f5 Michael Hanselmann
  def _MakeConfigFile(self, instance, startup_memory, block_devices):
564 c3d839f5 Michael Hanselmann
    """Gather configuration details and write to disk.
565 c3d839f5 Michael Hanselmann

566 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
567 c3d839f5 Michael Hanselmann

568 c3d839f5 Michael Hanselmann
    """
569 c3d839f5 Michael Hanselmann
    buf = StringIO()
570 c3d839f5 Michael Hanselmann
    buf.write("# Automatically generated by Ganeti. Do not edit!\n")
571 c3d839f5 Michael Hanselmann
    buf.write("\n")
572 c3d839f5 Michael Hanselmann
    buf.write(self._GetConfig(instance, startup_memory, block_devices))
573 c3d839f5 Michael Hanselmann
    buf.write("\n")
574 c3d839f5 Michael Hanselmann
575 c3d839f5 Michael Hanselmann
    self._WriteConfigFile(instance.name, buf.getvalue())
576 c3d839f5 Michael Hanselmann
577 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
578 c41eea6e Iustin Pop
    """Start an instance.
579 c41eea6e Iustin Pop

580 c41eea6e Iustin Pop
    """
581 0bbec3af Helga Velroyen
    startup_memory = self._InstanceStartupMemory(instance,
582 0bbec3af Helga Velroyen
                                                 hvparams=instance.hvparams)
583 c3d839f5 Michael Hanselmann
584 c3d839f5 Michael Hanselmann
    self._MakeConfigFile(instance, startup_memory, block_devices)
585 c3d839f5 Michael Hanselmann
586 3d942d8b Michael Hanselmann
    cmd = ["create"]
587 323f9095 Stephen Shirley
    if startup_paused:
588 3d942d8b Michael Hanselmann
      cmd.append("-p")
589 3d942d8b Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
590 65a6f9b7 Michael Hanselmann
591 398fd4f6 Helga Velroyen
    result = self._RunXen(cmd, instance.hvparams)
592 65a6f9b7 Michael Hanselmann
    if result.failed:
593 48bba9de Balazs Lecz
      # Move the Xen configuration file to the log directory to avoid
594 48bba9de Balazs Lecz
      # leaving a stale config file behind.
595 48bba9de Balazs Lecz
      stashed_config = self._StashConfigFile(instance.name)
596 48bba9de Balazs Lecz
      raise errors.HypervisorError("Failed to start instance %s: %s (%s). Moved"
597 48bba9de Balazs Lecz
                                   " config file to %s" %
598 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
599 48bba9de Balazs Lecz
                                    result.output, stashed_config))
600 65a6f9b7 Michael Hanselmann
601 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
602 c41eea6e Iustin Pop
    """Stop an instance.
603 c41eea6e Iustin Pop

604 c41eea6e Iustin Pop
    """
605 bbcf7ad0 Iustin Pop
    if name is None:
606 bbcf7ad0 Iustin Pop
      name = instance.name
607 4b8b172d Michael Hanselmann
608 58e356a9 Helga Velroyen
    return self._StopInstance(name, force, instance.hvparams)
609 31da5ab5 Michael Hanselmann
610 58e356a9 Helga Velroyen
  def _StopInstance(self, name, force, hvparams):
611 31da5ab5 Michael Hanselmann
    """Stop an instance.
612 31da5ab5 Michael Hanselmann

613 58e356a9 Helga Velroyen
    @type name: string
614 58e356a9 Helga Velroyen
    @param name: name of the instance to be shutdown
615 58e356a9 Helga Velroyen
    @type force: boolean
616 58e356a9 Helga Velroyen
    @param force: flag specifying whether shutdown should be forced
617 58e356a9 Helga Velroyen
    @type hvparams: dict of string
618 58e356a9 Helga Velroyen
    @param hvparams: hypervisor parameters of the instance
619 58e356a9 Helga Velroyen

620 31da5ab5 Michael Hanselmann
    """
621 65a6f9b7 Michael Hanselmann
    if force:
622 3d942d8b Michael Hanselmann
      action = "destroy"
623 65a6f9b7 Michael Hanselmann
    else:
624 3d942d8b Michael Hanselmann
      action = "shutdown"
625 65a6f9b7 Michael Hanselmann
626 398fd4f6 Helga Velroyen
    result = self._RunXen([action, name], hvparams)
627 65a6f9b7 Michael Hanselmann
    if result.failed:
628 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
629 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
630 65a6f9b7 Michael Hanselmann
631 4b8b172d Michael Hanselmann
    # Remove configuration file if stopping/starting instance was successful
632 4b8b172d Michael Hanselmann
    self._RemoveConfigFile(name)
633 4b8b172d Michael Hanselmann
634 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
635 c41eea6e Iustin Pop
    """Reboot an instance.
636 c41eea6e Iustin Pop

637 c41eea6e Iustin Pop
    """
638 0bbec3af Helga Velroyen
    ini_info = self.GetInstanceInfo(instance.name, hvparams=instance.hvparams)
639 65a6f9b7 Michael Hanselmann
640 e0561198 Iustin Pop
    if ini_info is None:
641 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
642 e0561198 Iustin Pop
                                   " not running" % instance.name)
643 e0561198 Iustin Pop
644 398fd4f6 Helga Velroyen
    result = self._RunXen(["reboot", instance.name], instance.hvparams)
645 65a6f9b7 Michael Hanselmann
    if result.failed:
646 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
647 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
648 3213d3c8 Iustin Pop
                                    result.output))
649 06b78e8b Michael Hanselmann
650 06b78e8b Michael Hanselmann
    def _CheckInstance():
651 0bbec3af Helga Velroyen
      new_info = self.GetInstanceInfo(instance.name, hvparams=instance.hvparams)
652 06b78e8b Michael Hanselmann
653 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
654 e0561198 Iustin Pop
      if (new_info is not None and
655 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
656 06b78e8b Michael Hanselmann
        return
657 7dd106d3 Iustin Pop
658 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
659 06b78e8b Michael Hanselmann
660 06b78e8b Michael Hanselmann
    try:
661 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
662 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
663 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
664 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
665 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
666 7dd106d3 Iustin Pop
                                   (instance.name, ))
667 65a6f9b7 Michael Hanselmann
668 2c7a0373 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
669 2c7a0373 Guido Trotter
    """Balloon an instance memory to a certain value.
670 2c7a0373 Guido Trotter

671 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
672 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
673 2c7a0373 Guido Trotter
    @type mem: int
674 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
675 2c7a0373 Guido Trotter

676 2c7a0373 Guido Trotter
    """
677 398fd4f6 Helga Velroyen
    result = self._RunXen(["mem-set", instance.name, mem], instance.hvparams)
678 2c7a0373 Guido Trotter
    if result.failed:
679 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
680 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
681 2c7a0373 Guido Trotter
                                    result.output))
682 3d942d8b Michael Hanselmann
683 3d942d8b Michael Hanselmann
    # Update configuration file
684 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
685 0a903309 Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
686 3d942d8b Michael Hanselmann
687 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
688 2c7a0373 Guido Trotter
    if result.failed:
689 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
690 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
691 2c7a0373 Guido Trotter
                                    result.output))
692 2c7a0373 Guido Trotter
693 fac489a5 Helga Velroyen
  def GetNodeInfo(self, hvparams=None):
694 65a6f9b7 Michael Hanselmann
    """Return information about the node.
695 65a6f9b7 Michael Hanselmann

696 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
697 65a6f9b7 Michael Hanselmann

698 65a6f9b7 Michael Hanselmann
    """
699 398fd4f6 Helga Velroyen
    result = self._RunXen(["info"], hvparams)
700 65a6f9b7 Michael Hanselmann
    if result.failed:
701 2609da63 Helga Velroyen
      logging.error("Can't retrieve xen hypervisor information (%s): %s",
702 2609da63 Helga Velroyen
                    result.fail_reason, result.output)
703 65a6f9b7 Michael Hanselmann
      return None
704 65a6f9b7 Michael Hanselmann
705 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(True, hvparams)
706 fac489a5 Helga Velroyen
    return _GetNodeInfo(result.stdout, instance_list)
707 65a6f9b7 Michael Hanselmann
708 1c3231aa Thomas Thrainer
  def GetInstanceConsole(self, instance, primary_node, hvparams, beparams):
709 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
710 65a6f9b7 Michael Hanselmann

711 65a6f9b7 Michael Hanselmann
    """
712 8ef418bb Helga Velroyen
    xen_cmd = self._GetCommand(hvparams)
713 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
714 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
715 1c3231aa Thomas Thrainer
                                   host=primary_node.name,
716 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
717 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
718 8ef418bb Helga Velroyen
                                            xen_cmd, instance.name])
719 65a6f9b7 Michael Hanselmann
720 75bf3149 Helga Velroyen
  def Verify(self, hvparams=None):
721 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
722 65a6f9b7 Michael Hanselmann

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

725 75bf3149 Helga Velroyen
    @type hvparams: dict of strings
726 75bf3149 Helga Velroyen
    @param hvparams: hypervisor parameters to be verified against
727 75bf3149 Helga Velroyen

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

730 65a6f9b7 Michael Hanselmann
    """
731 75bf3149 Helga Velroyen
    if hvparams is None:
732 75bf3149 Helga Velroyen
      return "Could not verify the hypervisor, because no hvparams were" \
733 75bf3149 Helga Velroyen
             " provided."
734 75bf3149 Helga Velroyen
735 75bf3149 Helga Velroyen
    if constants.HV_XEN_CMD in hvparams:
736 75bf3149 Helga Velroyen
      xen_cmd = hvparams[constants.HV_XEN_CMD]
737 75bf3149 Helga Velroyen
      try:
738 75bf3149 Helga Velroyen
        self._CheckToolstack(xen_cmd)
739 75bf3149 Helga Velroyen
      except errors.HypervisorError:
740 75bf3149 Helga Velroyen
        return "The configured xen toolstack '%s' is not available on this" \
741 75bf3149 Helga Velroyen
               " node." % xen_cmd
742 75bf3149 Helga Velroyen
743 398fd4f6 Helga Velroyen
    result = self._RunXen(["info"], hvparams)
744 e3e66f02 Michael Hanselmann
    if result.failed:
745 75bf3149 Helga Velroyen
      return "Retrieving information from xen failed: %s, %s" % \
746 75bf3149 Helga Velroyen
        (result.fail_reason, result.output)
747 65a6f9b7 Michael Hanselmann
748 cd04dfd2 Michael Hanselmann
    return None
749 cd04dfd2 Michael Hanselmann
750 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
751 4390ccff Guido Trotter
    """Get instance information to perform a migration.
752 4390ccff Guido Trotter

753 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
754 4390ccff Guido Trotter
    @param instance: instance to be migrated
755 4390ccff Guido Trotter
    @rtype: string
756 4390ccff Guido Trotter
    @return: content of the xen config file
757 4390ccff Guido Trotter

758 4390ccff Guido Trotter
    """
759 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
760 4390ccff Guido Trotter
761 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
762 4390ccff Guido Trotter
    """Prepare to accept an instance.
763 4390ccff Guido Trotter

764 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
765 4390ccff Guido Trotter
    @param instance: instance to be accepted
766 4390ccff Guido Trotter
    @type info: string
767 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
768 4390ccff Guido Trotter
    @type target: string
769 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
770 4390ccff Guido Trotter

771 4390ccff Guido Trotter
    """
772 4390ccff Guido Trotter
    pass
773 4390ccff Guido Trotter
774 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
775 4390ccff Guido Trotter
    """Finalize an instance migration.
776 4390ccff Guido Trotter

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

780 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
781 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
782 4390ccff Guido Trotter
    @type info: string
783 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
784 4390ccff Guido Trotter
    @type success: boolean
785 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
786 4390ccff Guido Trotter

787 4390ccff Guido Trotter
    """
788 4390ccff Guido Trotter
    if success:
789 c3d839f5 Michael Hanselmann
      self._WriteConfigFile(instance.name, info)
790 4390ccff Guido Trotter
791 bc0a2284 Helga Velroyen
  def MigrateInstance(self, cluster_name, instance, target, live):
792 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
793 6e7275c0 Iustin Pop

794 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
795 6e7275c0 Iustin Pop
    currently running.
796 6e7275c0 Iustin Pop

797 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
798 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
799 fdf7f055 Guido Trotter
    @type target: string
800 fdf7f055 Guido Trotter
    @param target: ip address of the target node
801 fdf7f055 Guido Trotter
    @type live: boolean
802 fdf7f055 Guido Trotter
    @param live: perform a live migration
803 fdf7f055 Guido Trotter

804 6e7275c0 Iustin Pop
    """
805 d8784f7d Michael Hanselmann
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
806 d8784f7d Michael Hanselmann
807 d8784f7d Michael Hanselmann
    return self._MigrateInstance(cluster_name, instance.name, target, port,
808 8351df2f Helga Velroyen
                                 live, instance.hvparams)
809 d8784f7d Michael Hanselmann
810 d8784f7d Michael Hanselmann
  def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
811 8351df2f Helga Velroyen
                       hvparams, _ping_fn=netutils.TcpPing):
812 d8784f7d Michael Hanselmann
    """Migrate an instance to a target node.
813 d8784f7d Michael Hanselmann

814 d8784f7d Michael Hanselmann
    @see: L{MigrateInstance} for details
815 d8784f7d Michael Hanselmann

816 d8784f7d Michael Hanselmann
    """
817 8351df2f Helga Velroyen
    if hvparams is None:
818 8351df2f Helga Velroyen
      raise errors.HypervisorError("No hvparams provided.")
819 8351df2f Helga Velroyen
820 8351df2f Helga Velroyen
    if self.GetInstanceInfo(instance_name, hvparams=hvparams) is None:
821 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
822 50716be0 Iustin Pop
823 398fd4f6 Helga Velroyen
    cmd = self._GetCommand(hvparams)
824 50716be0 Iustin Pop
825 d8784f7d Michael Hanselmann
    if (cmd == constants.XEN_CMD_XM and
826 d8784f7d Michael Hanselmann
        not _ping_fn(target, port, live_port_needed=True)):
827 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
828 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
829 50716be0 Iustin Pop
830 3d942d8b Michael Hanselmann
    args = ["migrate"]
831 3d942d8b Michael Hanselmann
832 d8784f7d Michael Hanselmann
    if cmd == constants.XEN_CMD_XM:
833 0625d08f René Nussbaumer
      args.extend(["-p", "%d" % port])
834 0625d08f René Nussbaumer
      if live:
835 0625d08f René Nussbaumer
        args.append("-l")
836 3d942d8b Michael Hanselmann
837 d8784f7d Michael Hanselmann
    elif cmd == constants.XEN_CMD_XL:
838 d8784f7d Michael Hanselmann
      args.extend([
839 d8784f7d Michael Hanselmann
        "-s", constants.XL_SSH_CMD % cluster_name,
840 d8784f7d Michael Hanselmann
        "-C", self._ConfigFileName(instance_name),
841 d8784f7d Michael Hanselmann
        ])
842 3d942d8b Michael Hanselmann
843 0625d08f René Nussbaumer
    else:
844 d8784f7d Michael Hanselmann
      raise errors.HypervisorError("Unsupported Xen command: %s" % self._cmd)
845 0625d08f René Nussbaumer
846 d8784f7d Michael Hanselmann
    args.extend([instance_name, target])
847 3d942d8b Michael Hanselmann
848 398fd4f6 Helga Velroyen
    result = self._RunXen(args, hvparams)
849 6e7275c0 Iustin Pop
    if result.failed:
850 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
851 d8784f7d Michael Hanselmann
                                   (instance_name, result.output))
852 60af751d Andrea Spadaccini
853 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
854 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
855 60af751d Andrea Spadaccini

856 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
857 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
858 60af751d Andrea Spadaccini
    @type success: bool
859 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
860 60af751d Andrea Spadaccini
    @type live: bool
861 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
862 60af751d Andrea Spadaccini

863 60af751d Andrea Spadaccini
    """
864 60af751d Andrea Spadaccini
    # pylint: disable=W0613
865 60af751d Andrea Spadaccini
    if success:
866 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
867 60af751d Andrea Spadaccini
      try:
868 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
869 60af751d Andrea Spadaccini
      except EnvironmentError:
870 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
871 60af751d Andrea Spadaccini
872 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
873 60af751d Andrea Spadaccini
    """Get the migration status
874 60af751d Andrea Spadaccini

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

879 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
880 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
881 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
882 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
883 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
884 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
885 60af751d Andrea Spadaccini

886 60af751d Andrea Spadaccini
    """
887 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
888 6e7275c0 Iustin Pop
889 8ef418bb Helga Velroyen
  def PowercycleNode(self, hvparams=None):
890 f5118ade Iustin Pop
    """Xen-specific powercycle.
891 f5118ade Iustin Pop

892 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
893 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
894 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
895 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
896 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
897 f5118ade Iustin Pop
    daemon is not working.
898 f5118ade Iustin Pop

899 8ef418bb Helga Velroyen
    @type hvparams: dict of strings
900 8ef418bb Helga Velroyen
    @param hvparams: hypervisor params to be used on this node
901 8ef418bb Helga Velroyen

902 f5118ade Iustin Pop
    """
903 f5118ade Iustin Pop
    try:
904 8ef418bb Helga Velroyen
      self.LinuxPowercycle()
905 f5118ade Iustin Pop
    finally:
906 8ef418bb Helga Velroyen
      xen_cmd = self._GetCommand(hvparams)
907 8ef418bb Helga Velroyen
      utils.RunCmd([xen_cmd, "debug", "R"])
908 f5118ade Iustin Pop
909 75bf3149 Helga Velroyen
  def _CheckToolstack(self, xen_cmd):
910 75bf3149 Helga Velroyen
    """Check whether the given toolstack is available on the node.
911 75bf3149 Helga Velroyen

912 75bf3149 Helga Velroyen
    @type xen_cmd: string
913 75bf3149 Helga Velroyen
    @param xen_cmd: xen command (e.g. 'xm' or 'xl')
914 75bf3149 Helga Velroyen

915 75bf3149 Helga Velroyen
    """
916 75bf3149 Helga Velroyen
    binary_found = self._CheckToolstackBinary(xen_cmd)
917 75bf3149 Helga Velroyen
    if not binary_found:
918 75bf3149 Helga Velroyen
      raise errors.HypervisorError("No '%s' binary found on node." % xen_cmd)
919 75bf3149 Helga Velroyen
    elif xen_cmd == constants.XEN_CMD_XL:
920 75bf3149 Helga Velroyen
      if not self._CheckToolstackXlConfigured():
921 75bf3149 Helga Velroyen
        raise errors.HypervisorError("Toolstack '%s' is not enabled on this"
922 75bf3149 Helga Velroyen
                                     "node." % xen_cmd)
923 75bf3149 Helga Velroyen
924 75bf3149 Helga Velroyen
  def _CheckToolstackBinary(self, xen_cmd):
925 75bf3149 Helga Velroyen
    """Checks whether the xen command's binary is found on the machine.
926 75bf3149 Helga Velroyen

927 75bf3149 Helga Velroyen
    """
928 75bf3149 Helga Velroyen
    if xen_cmd not in constants.KNOWN_XEN_COMMANDS:
929 75bf3149 Helga Velroyen
      raise errors.HypervisorError("Unknown xen command '%s'." % xen_cmd)
930 75bf3149 Helga Velroyen
    result = self._run_cmd_fn(["which", xen_cmd])
931 75bf3149 Helga Velroyen
    return not result.failed
932 75bf3149 Helga Velroyen
933 75bf3149 Helga Velroyen
  def _CheckToolstackXlConfigured(self):
934 75bf3149 Helga Velroyen
    """Checks whether xl is enabled on an xl-capable node.
935 75bf3149 Helga Velroyen

936 75bf3149 Helga Velroyen
    @rtype: bool
937 75bf3149 Helga Velroyen
    @returns: C{True} if 'xl' is enabled, C{False} otherwise
938 75bf3149 Helga Velroyen

939 75bf3149 Helga Velroyen
    """
940 75bf3149 Helga Velroyen
    result = self._run_cmd_fn([constants.XEN_CMD_XL, "help"])
941 75bf3149 Helga Velroyen
    if not result.failed:
942 75bf3149 Helga Velroyen
      return True
943 75bf3149 Helga Velroyen
    elif result.failed:
944 75bf3149 Helga Velroyen
      if "toolstack" in result.stderr:
945 75bf3149 Helga Velroyen
        return False
946 75bf3149 Helga Velroyen
      # xl fails for some other reason than the toolstack
947 75bf3149 Helga Velroyen
      else:
948 75bf3149 Helga Velroyen
        raise errors.HypervisorError("Cannot run xen ('%s'). Error: %s."
949 75bf3149 Helga Velroyen
                                     % (constants.XEN_CMD_XL, result.stderr))
950 75bf3149 Helga Velroyen
951 65a6f9b7 Michael Hanselmann
952 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
953 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
954 65a6f9b7 Michael Hanselmann
955 205ab586 Iustin Pop
  PARAMETERS = {
956 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
957 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
958 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
959 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
960 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
961 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
962 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
963 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
964 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
965 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
966 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
967 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
968 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
969 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
970 2c368f28 Guido Trotter
    constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
971 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
972 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
973 397b7844 Dimitris Aragiorgis
    constants.HV_VIF_SCRIPT: hv_base.OPT_FILE_CHECK,
974 740394bc Helga Velroyen
    constants.HV_XEN_CMD:
975 740394bc Helga Velroyen
      hv_base.ParamInSet(True, constants.KNOWN_XEN_COMMANDS),
976 295ed29b Santi Raffa
    constants.HV_XEN_CPUID: hv_base.NO_CHECK,
977 b5cad580 Raffa Santi
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
978 205ab586 Iustin Pop
    }
979 f48148c3 Iustin Pop
980 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
981 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
982 65a6f9b7 Michael Hanselmann

983 65a6f9b7 Michael Hanselmann
    """
984 a985b417 Iustin Pop
    hvp = instance.hvparams
985 65a6f9b7 Michael Hanselmann
    config = StringIO()
986 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
987 65a6f9b7 Michael Hanselmann
988 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
989 2f2dbb4b Jun Futagawa
    # parameters.
990 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
991 2f2dbb4b Jun Futagawa
      # bootloader handling
992 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
993 2f2dbb4b Jun Futagawa
      if bootloader_path:
994 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
995 2f2dbb4b Jun Futagawa
      else:
996 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
997 2f2dbb4b Jun Futagawa
                                     " bootloader path")
998 65a6f9b7 Michael Hanselmann
999 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
1000 2f2dbb4b Jun Futagawa
      if bootloader_args:
1001 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
1002 2f2dbb4b Jun Futagawa
    else:
1003 2f2dbb4b Jun Futagawa
      # kernel handling
1004 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
1005 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
1006 2f2dbb4b Jun Futagawa
1007 2f2dbb4b Jun Futagawa
      # initrd handling
1008 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
1009 2f2dbb4b Jun Futagawa
      if initrd_path:
1010 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
1011 65a6f9b7 Michael Hanselmann
1012 65a6f9b7 Michael Hanselmann
    # rest of the settings
1013 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
1014 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
1015 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
1016 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
1017 c4708267 Tsachy Shacham
    if cpu_pinning:
1018 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
1019 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
1020 8bd977e9 Sébastien Bocahu
    if cpu_cap:
1021 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
1022 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
1023 8bd977e9 Sébastien Bocahu
    if cpu_weight:
1024 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
1025 c4708267 Tsachy Shacham
1026 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
1027 65a6f9b7 Michael Hanselmann
1028 65a6f9b7 Michael Hanselmann
    vif_data = []
1029 397b7844 Dimitris Aragiorgis
    for idx, nic in enumerate(instance.nics):
1030 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
1031 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
1032 65a6f9b7 Michael Hanselmann
      if ip is not None:
1033 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
1034 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1035 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
1036 f1f11cef Sebastian Gebhard
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_OVS:
1037 f1f11cef Sebastian Gebhard
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
1038 f1f11cef Sebastian Gebhard
        if nic.nicparams[constants.NIC_VLAN]:
1039 f1f11cef Sebastian Gebhard
          nic_str += "%s" % nic.nicparams[constants.NIC_VLAN]
1040 397b7844 Dimitris Aragiorgis
      if hvp[constants.HV_VIF_SCRIPT]:
1041 397b7844 Dimitris Aragiorgis
        nic_str += ", script=%s" % hvp[constants.HV_VIF_SCRIPT]
1042 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
1043 397b7844 Dimitris Aragiorgis
      self._WriteNICInfoFile(instance.name, idx, nic)
1044 65a6f9b7 Michael Hanselmann
1045 d0bb3f24 Michael Hanselmann
    disk_data = \
1046 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
1047 7ed85ffe Iustin Pop
1048 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
1049 7ed85ffe Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
1050 074ca009 Guido Trotter
1051 7adf7814 René Nussbaumer
    if hvp[constants.HV_ROOT_PATH]:
1052 7adf7814 René Nussbaumer
      config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
1053 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
1054 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
1055 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
1056 990ade2d Stephen Shirley
    else:
1057 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
1058 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
1059 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
1060 73cd67f4 Guido Trotter
1061 295ed29b Santi Raffa
    cpuid = hvp[constants.HV_XEN_CPUID]
1062 295ed29b Santi Raffa
    if cpuid:
1063 295ed29b Santi Raffa
      config.write("cpuid = %s\n" % _QuoteCpuidField(cpuid))
1064 295ed29b Santi Raffa
1065 b5cad580 Raffa Santi
    if hvp[constants.HV_SOUNDHW]:
1066 b5cad580 Raffa Santi
      config.write("soundhw = '%s'\n" % hvp[constants.HV_SOUNDHW])
1067 b5cad580 Raffa Santi
1068 c3d839f5 Michael Hanselmann
    return config.getvalue()
1069 65a6f9b7 Michael Hanselmann
1070 65a6f9b7 Michael Hanselmann
1071 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
1072 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
1073 65a6f9b7 Michael Hanselmann
1074 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
1075 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
1076 69b99987 Michael Hanselmann
    ]
1077 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
1078 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
1079 69ab2e12 Guido Trotter
    ]
1080 3680f662 Guido Trotter
1081 205ab586 Iustin Pop
  PARAMETERS = {
1082 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
1083 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
1084 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
1085 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
1086 016d04b3 Michael Hanselmann
       None, None),
1087 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
1088 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
1089 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
1090 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
1091 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
1092 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
1093 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
1094 8b312c1d Manuel Franceschini
      (False, netutils.IP4Address.IsValid,
1095 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
1096 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
1097 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
1098 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
1099 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
1100 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
1101 6b970cef Jun Futagawa
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
1102 e695efbf Iustin Pop
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
1103 e695efbf Iustin Pop
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
1104 87f0aa48 Jack
    # Add PCI passthrough
1105 3891c95e Bernardo Dal Seno
    constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
1106 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
1107 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
1108 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
1109 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_CAP: hv_base.NO_CHECK,
1110 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
1111 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65535, "invalid weight", None, None),
1112 05440845 Helga Velroyen
    constants.HV_VIF_TYPE:
1113 05440845 Helga Velroyen
      hv_base.ParamInSet(False, constants.HT_HVM_VALID_VIF_TYPES),
1114 397b7844 Dimitris Aragiorgis
    constants.HV_VIF_SCRIPT: hv_base.OPT_FILE_CHECK,
1115 ffc27116 Thomas Thrainer
    constants.HV_VIRIDIAN: hv_base.NO_CHECK,
1116 740394bc Helga Velroyen
    constants.HV_XEN_CMD:
1117 740394bc Helga Velroyen
      hv_base.ParamInSet(True, constants.KNOWN_XEN_COMMANDS),
1118 295ed29b Santi Raffa
    constants.HV_XEN_CPUID: hv_base.NO_CHECK,
1119 b5cad580 Raffa Santi
    constants.HV_SOUNDHW: hv_base.NO_CHECK,
1120 205ab586 Iustin Pop
    }
1121 09ea8710 Iustin Pop
1122 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
1123 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
1124 65a6f9b7 Michael Hanselmann

1125 65a6f9b7 Michael Hanselmann
    """
1126 a985b417 Iustin Pop
    hvp = instance.hvparams
1127 a985b417 Iustin Pop
1128 65a6f9b7 Michael Hanselmann
    config = StringIO()
1129 e2ee1cea Iustin Pop
1130 e2ee1cea Iustin Pop
    # kernel handling
1131 e2ee1cea Iustin Pop
    kpath = hvp[constants.HV_KERNEL_PATH]
1132 e2ee1cea Iustin Pop
    config.write("kernel = '%s'\n" % kpath)
1133 e2ee1cea Iustin Pop
1134 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
1135 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
1136 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
1137 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
1138 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
1139 c4708267 Tsachy Shacham
    if cpu_pinning:
1140 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
1141 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
1142 8bd977e9 Sébastien Bocahu
    if cpu_cap:
1143 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
1144 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
1145 8bd977e9 Sébastien Bocahu
    if cpu_weight:
1146 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
1147 c4708267 Tsachy Shacham
1148 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
1149 09ea8710 Iustin Pop
    if hvp[constants.HV_PAE]:
1150 a21dda8b Iustin Pop
      config.write("pae = 1\n")
1151 a21dda8b Iustin Pop
    else:
1152 a21dda8b Iustin Pop
      config.write("pae = 0\n")
1153 09ea8710 Iustin Pop
    if hvp[constants.HV_ACPI]:
1154 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
1155 a21dda8b Iustin Pop
    else:
1156 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
1157 ffc27116 Thomas Thrainer
    if hvp[constants.HV_VIRIDIAN]:
1158 ffc27116 Thomas Thrainer
      config.write("viridian = 1\n")
1159 ffc27116 Thomas Thrainer
    else:
1160 ffc27116 Thomas Thrainer
      config.write("viridian = 0\n")
1161 ffc27116 Thomas Thrainer
1162 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
1163 09ea8710 Iustin Pop
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
1164 a985b417 Iustin Pop
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
1165 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
1166 97efde45 Guido Trotter
    config.write("usb = 1\n")
1167 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
1168 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
1169 a985b417 Iustin Pop
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
1170 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
1171 d0c11cf7 Alexander Schreiber
    else:
1172 6b405598 Guido Trotter
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
1173 65a6f9b7 Michael Hanselmann
1174 377d74c9 Guido Trotter
    if instance.network_port > constants.VNC_BASE_PORT:
1175 377d74c9 Guido Trotter
      display = instance.network_port - constants.VNC_BASE_PORT
1176 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
1177 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
1178 65a6f9b7 Michael Hanselmann
    else:
1179 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
1180 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
1181 65a6f9b7 Michael Hanselmann
1182 6e6bb8d5 Guido Trotter
    vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
1183 65a6f9b7 Michael Hanselmann
    try:
1184 6e6bb8d5 Guido Trotter
      password = utils.ReadFile(vnc_pwd_file)
1185 78f66a17 Guido Trotter
    except EnvironmentError, err:
1186 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
1187 6e6bb8d5 Guido Trotter
                                   (vnc_pwd_file, err))
1188 65a6f9b7 Michael Hanselmann
1189 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
1190 65a6f9b7 Michael Hanselmann
1191 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
1192 6b970cef Jun Futagawa
    if hvp[constants.HV_USE_LOCALTIME]:
1193 6b970cef Jun Futagawa
      config.write("localtime = 1\n")
1194 65a6f9b7 Michael Hanselmann
1195 65a6f9b7 Michael Hanselmann
    vif_data = []
1196 05440845 Helga Velroyen
    # Note: what is called 'nic_type' here, is used as value for the xen nic
1197 05440845 Helga Velroyen
    # vif config parameter 'model'. For the xen nic vif parameter 'type', we use
1198 05440845 Helga Velroyen
    # the 'vif_type' to avoid a clash of notation.
1199 a985b417 Iustin Pop
    nic_type = hvp[constants.HV_NIC_TYPE]
1200 05440845 Helga Velroyen
1201 f48148c3 Iustin Pop
    if nic_type is None:
1202 05440845 Helga Velroyen
      vif_type_str = ""
1203 05440845 Helga Velroyen
      if hvp[constants.HV_VIF_TYPE]:
1204 05440845 Helga Velroyen
        vif_type_str = ", type=%s" % hvp[constants.HV_VIF_TYPE]
1205 f48148c3 Iustin Pop
      # ensure old instances don't change
1206 05440845 Helga Velroyen
      nic_type_str = vif_type_str
1207 d08f6067 Guido Trotter
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
1208 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
1209 f48148c3 Iustin Pop
    else:
1210 05440845 Helga Velroyen
      # parameter 'model' is only valid with type 'ioemu'
1211 05440845 Helga Velroyen
      nic_type_str = ", model=%s, type=%s" % \
1212 05440845 Helga Velroyen
        (nic_type, constants.HT_HVM_VIF_IOEMU)
1213 397b7844 Dimitris Aragiorgis
    for idx, nic in enumerate(instance.nics):
1214 503b97a9 Guido Trotter
      nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
1215 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
1216 65a6f9b7 Michael Hanselmann
      if ip is not None:
1217 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
1218 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1219 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
1220 397b7844 Dimitris Aragiorgis
      if hvp[constants.HV_VIF_SCRIPT]:
1221 397b7844 Dimitris Aragiorgis
        nic_str += ", script=%s" % hvp[constants.HV_VIF_SCRIPT]
1222 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
1223 397b7844 Dimitris Aragiorgis
      self._WriteNICInfoFile(instance.name, idx, nic)
1224 65a6f9b7 Michael Hanselmann
1225 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
1226 525011bc Maciej Bliziński
1227 d0bb3f24 Michael Hanselmann
    disk_data = \
1228 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
1229 525011bc Maciej Bliziński
1230 a985b417 Iustin Pop
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
1231 f48148c3 Iustin Pop
    if iso_path:
1232 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
1233 a21dda8b Iustin Pop
      disk_data.append(iso)
1234 a21dda8b Iustin Pop
1235 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
1236 87f0aa48 Jack
    # Add PCI passthrough
1237 87f0aa48 Jack
    pci_pass_arr = []
1238 87f0aa48 Jack
    pci_pass = hvp[constants.HV_PASSTHROUGH]
1239 87f0aa48 Jack
    if pci_pass:
1240 3891c95e Bernardo Dal Seno
      pci_pass_arr = pci_pass.split(";")
1241 3891c95e Bernardo Dal Seno
      config.write("pci = %s\n" % pci_pass_arr)
1242 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
1243 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
1244 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
1245 990ade2d Stephen Shirley
    else:
1246 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
1247 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
1248 73cd67f4 Guido Trotter
1249 295ed29b Santi Raffa
    cpuid = hvp[constants.HV_XEN_CPUID]
1250 295ed29b Santi Raffa
    if cpuid:
1251 295ed29b Santi Raffa
      config.write("cpuid = %s\n" % _QuoteCpuidField(cpuid))
1252 295ed29b Santi Raffa
1253 b5cad580 Raffa Santi
    if hvp[constants.HV_SOUNDHW]:
1254 b5cad580 Raffa Santi
      config.write("soundhw = '%s'\n" % hvp[constants.HV_SOUNDHW])
1255 b5cad580 Raffa Santi
1256 c3d839f5 Michael Hanselmann
    return config.getvalue()