Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 277a9de7

History | View | Annotate | Download (37.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 865cdc2e Dimitris Aragiorgis
import errno
28 d0bb3f24 Michael Hanselmann
import string # pylint: disable=W0402
29 865cdc2e 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 053c356a Guido Trotter
from ganeti import ssconf
40 65a6f9b7 Michael Hanselmann
41 65a6f9b7 Michael Hanselmann
42 a8e8c0c6 Michael Hanselmann
XEND_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xend-config.sxp")
43 a8e8c0c6 Michael Hanselmann
XL_CONFIG_FILE = utils.PathJoin(pathutils.XEN_CONFIG_DIR, "xen/xl.conf")
44 a8e8c0c6 Michael Hanselmann
VIF_BRIDGE_SCRIPT = utils.PathJoin(pathutils.XEN_CONFIG_DIR,
45 a8e8c0c6 Michael Hanselmann
                                   "scripts/vif-bridge")
46 18bf85b1 Michael Hanselmann
_DOM0_NAME = "Domain-0"
47 d0bb3f24 Michael Hanselmann
_DISK_LETTERS = string.ascii_lowercase
48 d0bb3f24 Michael Hanselmann
49 d0bb3f24 Michael Hanselmann
_FILE_DRIVER_MAP = {
50 d0bb3f24 Michael Hanselmann
  constants.FD_LOOP: "file",
51 d0bb3f24 Michael Hanselmann
  constants.FD_BLKTAP: "tap:aio",
52 7bc2c097 Michele Tartara
  constants.FD_BLKTAP2: "tap2:tapdisk:aio",
53 d0bb3f24 Michael Hanselmann
  }
54 22d568c2 Guido Trotter
55 22d568c2 Guido Trotter
56 347fa0f1 Michael Hanselmann
def _CreateConfigCpus(cpu_mask):
57 347fa0f1 Michael Hanselmann
  """Create a CPU config string for Xen's config file.
58 347fa0f1 Michael Hanselmann

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

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

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

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

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

150 b255379d Michael Hanselmann
  See L{_RunXmList} and L{_ParseXmList} for parameter details.
151 b255379d Michael Hanselmann

152 b255379d Michael Hanselmann
  """
153 b255379d Michael Hanselmann
  xmllist_errors = []
154 b255379d Michael Hanselmann
  try:
155 b255379d Michael Hanselmann
    lines = utils.Retry(_RunXmList, (0.3, 1.5, 1.0), _timeout,
156 b255379d Michael Hanselmann
                        args=(fn, xmllist_errors))
157 b255379d Michael Hanselmann
  except utils.RetryTimeout:
158 b255379d Michael Hanselmann
    if xmllist_errors:
159 b255379d Michael Hanselmann
      xmlist_result = xmllist_errors.pop()
160 b255379d Michael Hanselmann
161 b255379d Michael Hanselmann
      errmsg = ("xm list failed, timeout exceeded (%s): %s" %
162 b255379d Michael Hanselmann
                (xmlist_result.fail_reason, xmlist_result.output))
163 b255379d Michael Hanselmann
    else:
164 b255379d Michael Hanselmann
      errmsg = "xm list failed"
165 b255379d Michael Hanselmann
166 b255379d Michael Hanselmann
    raise errors.HypervisorError(errmsg)
167 b255379d Michael Hanselmann
168 b255379d Michael Hanselmann
  return _ParseXmList(lines, include_node)
169 b255379d Michael Hanselmann
170 b255379d Michael Hanselmann
171 364c350f Jose A. Lopes
def _IsInstanceRunning(instance_info):
172 364c350f Jose A. Lopes
  return instance_info == "r-----" \
173 364c350f Jose A. Lopes
      or instance_info == "-b----"
174 364c350f Jose A. Lopes
175 364c350f Jose A. Lopes
176 364c350f Jose A. Lopes
def _IsInstanceShutdown(instance_info):
177 364c350f Jose A. Lopes
  return instance_info == "---s--"
178 364c350f Jose A. Lopes
179 364c350f Jose A. Lopes
180 06c9a520 Michael Hanselmann
def _ParseNodeInfo(info):
181 06c9a520 Michael Hanselmann
  """Return information about the node.
182 06c9a520 Michael Hanselmann

183 06c9a520 Michael Hanselmann
  @return: a dict with the following keys (memory values in MiB):
184 06c9a520 Michael Hanselmann
        - memory_total: the total memory size on the node
185 06c9a520 Michael Hanselmann
        - memory_free: the available memory on the node for instances
186 06c9a520 Michael Hanselmann
        - nr_cpus: total number of CPUs
187 06c9a520 Michael Hanselmann
        - nr_nodes: in a NUMA system, the number of domains
188 06c9a520 Michael Hanselmann
        - nr_sockets: the number of physical CPU sockets in the node
189 06c9a520 Michael Hanselmann
        - hv_version: the hypervisor version in the form (major, minor)
190 06c9a520 Michael Hanselmann

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

242 06c9a520 Michael Hanselmann
  @type info: dict
243 06c9a520 Michael Hanselmann
  @param info: Result from L{_ParseNodeInfo}
244 06c9a520 Michael Hanselmann
  @type fn: callable
245 06c9a520 Michael Hanselmann
  @param fn: Function returning result of running C{xm list}
246 06c9a520 Michael Hanselmann
  @rtype: dict
247 06c9a520 Michael Hanselmann

248 06c9a520 Michael Hanselmann
  """
249 06c9a520 Michael Hanselmann
  total_instmem = 0
250 06c9a520 Michael Hanselmann
251 06c9a520 Michael Hanselmann
  for (name, _, mem, vcpus, _, _) in fn(True):
252 06c9a520 Michael Hanselmann
    if name == _DOM0_NAME:
253 06c9a520 Michael Hanselmann
      info["memory_dom0"] = mem
254 06c9a520 Michael Hanselmann
      info["dom0_cpus"] = vcpus
255 06c9a520 Michael Hanselmann
256 06c9a520 Michael Hanselmann
    # Include Dom0 in total memory usage
257 06c9a520 Michael Hanselmann
    total_instmem += mem
258 06c9a520 Michael Hanselmann
259 06c9a520 Michael Hanselmann
  memory_free = info.get("memory_free")
260 06c9a520 Michael Hanselmann
  memory_total = info.get("memory_total")
261 06c9a520 Michael Hanselmann
262 06c9a520 Michael Hanselmann
  # Calculate memory used by hypervisor
263 06c9a520 Michael Hanselmann
  if None not in [memory_total, memory_free, total_instmem]:
264 06c9a520 Michael Hanselmann
    info["memory_hv"] = memory_total - memory_free - total_instmem
265 06c9a520 Michael Hanselmann
266 06c9a520 Michael Hanselmann
  return info
267 06c9a520 Michael Hanselmann
268 06c9a520 Michael Hanselmann
269 06c9a520 Michael Hanselmann
def _GetNodeInfo(info, fn):
270 06c9a520 Michael Hanselmann
  """Combines L{_MergeInstanceInfo} and L{_ParseNodeInfo}.
271 06c9a520 Michael Hanselmann

272 06c9a520 Michael Hanselmann
  """
273 06c9a520 Michael Hanselmann
  return _MergeInstanceInfo(_ParseNodeInfo(info), fn)
274 06c9a520 Michael Hanselmann
275 06c9a520 Michael Hanselmann
276 d0bb3f24 Michael Hanselmann
def _GetConfigFileDiskData(block_devices, blockdev_prefix,
277 d0bb3f24 Michael Hanselmann
                           _letters=_DISK_LETTERS):
278 d0bb3f24 Michael Hanselmann
  """Get disk directives for Xen config file.
279 d0bb3f24 Michael Hanselmann

280 d0bb3f24 Michael Hanselmann
  This method builds the xen config disk directive according to the
281 d0bb3f24 Michael Hanselmann
  given disk_template and block_devices.
282 d0bb3f24 Michael Hanselmann

283 d0bb3f24 Michael Hanselmann
  @param block_devices: list of tuples (cfdev, rldev):
284 d0bb3f24 Michael Hanselmann
      - cfdev: dict containing ganeti config disk part
285 d0bb3f24 Michael Hanselmann
      - rldev: ganeti.bdev.BlockDev object
286 d0bb3f24 Michael Hanselmann
  @param blockdev_prefix: a string containing blockdevice prefix,
287 d0bb3f24 Michael Hanselmann
                          e.g. "sd" for /dev/sda
288 d0bb3f24 Michael Hanselmann

289 d0bb3f24 Michael Hanselmann
  @return: string containing disk directive for xen instance config file
290 d0bb3f24 Michael Hanselmann

291 d0bb3f24 Michael Hanselmann
  """
292 d0bb3f24 Michael Hanselmann
  if len(block_devices) > len(_letters):
293 d0bb3f24 Michael Hanselmann
    raise errors.HypervisorError("Too many disks")
294 d0bb3f24 Michael Hanselmann
295 d0bb3f24 Michael Hanselmann
  disk_data = []
296 d0bb3f24 Michael Hanselmann
297 d0bb3f24 Michael Hanselmann
  for sd_suffix, (cfdev, dev_path) in zip(_letters, block_devices):
298 d0bb3f24 Michael Hanselmann
    sd_name = blockdev_prefix + sd_suffix
299 d0bb3f24 Michael Hanselmann
300 d0bb3f24 Michael Hanselmann
    if cfdev.mode == constants.DISK_RDWR:
301 d0bb3f24 Michael Hanselmann
      mode = "w"
302 d0bb3f24 Michael Hanselmann
    else:
303 d0bb3f24 Michael Hanselmann
      mode = "r"
304 d0bb3f24 Michael Hanselmann
305 d0bb3f24 Michael Hanselmann
    if cfdev.dev_type == constants.LD_FILE:
306 d0bb3f24 Michael Hanselmann
      driver = _FILE_DRIVER_MAP[cfdev.physical_id[0]]
307 d0bb3f24 Michael Hanselmann
    else:
308 d0bb3f24 Michael Hanselmann
      driver = "phy"
309 d0bb3f24 Michael Hanselmann
310 d0bb3f24 Michael Hanselmann
    disk_data.append("'%s:%s,%s,%s'" % (driver, dev_path, sd_name, mode))
311 d0bb3f24 Michael Hanselmann
312 d0bb3f24 Michael Hanselmann
  return disk_data
313 d0bb3f24 Michael Hanselmann
314 d0bb3f24 Michael Hanselmann
315 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
316 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
317 65a6f9b7 Michael Hanselmann

318 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
319 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
320 65a6f9b7 Michael Hanselmann

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

356 d8784f7d Michael Hanselmann
    """
357 3d942d8b Michael Hanselmann
    if self._cmd is None:
358 3d942d8b Michael Hanselmann
      # TODO: Make command a hypervisor parameter
359 3d942d8b Michael Hanselmann
      cmd = constants.XEN_CMD
360 3d942d8b Michael Hanselmann
    else:
361 3d942d8b Michael Hanselmann
      cmd = self._cmd
362 3d942d8b Michael Hanselmann
363 3d942d8b Michael Hanselmann
    if cmd not in constants.KNOWN_XEN_COMMANDS:
364 3d942d8b Michael Hanselmann
      raise errors.ProgrammerError("Unknown Xen command '%s'" % cmd)
365 3d942d8b Michael Hanselmann
366 3d942d8b Michael Hanselmann
    return cmd
367 3d942d8b Michael Hanselmann
368 3d942d8b Michael Hanselmann
  def _RunXen(self, args):
369 81124130 Michael Hanselmann
    """Wrapper around L{utils.process.RunCmd} to run Xen command.
370 3d942d8b Michael Hanselmann

371 81124130 Michael Hanselmann
    @see: L{utils.process.RunCmd}
372 3d942d8b Michael Hanselmann

373 3d942d8b Michael Hanselmann
    """
374 3d942d8b Michael Hanselmann
    cmd = [self._GetCommand()]
375 3d942d8b Michael Hanselmann
    cmd.extend(args)
376 3d942d8b Michael Hanselmann
377 3d942d8b Michael Hanselmann
    return self._run_cmd_fn(cmd)
378 3d942d8b Michael Hanselmann
379 0a903309 Michael Hanselmann
  def _ConfigFileName(self, instance_name):
380 c2be2532 Guido Trotter
    """Get the config file name for an instance.
381 c2be2532 Guido Trotter

382 c2be2532 Guido Trotter
    @param instance_name: instance name
383 c2be2532 Guido Trotter
    @type instance_name: str
384 c2be2532 Guido Trotter
    @return: fully qualified path to instance config file
385 c2be2532 Guido Trotter
    @rtype: str
386 c2be2532 Guido Trotter

387 c2be2532 Guido Trotter
    """
388 0a903309 Michael Hanselmann
    return utils.PathJoin(self._cfgdir, instance_name)
389 c2be2532 Guido Trotter
390 5661b908 Iustin Pop
  @classmethod
391 865cdc2e Dimitris Aragiorgis
  def _WriteNICInfoFile(cls, instance_name, idx, nic):
392 865cdc2e Dimitris Aragiorgis
    """Write the Xen config file for the instance.
393 865cdc2e Dimitris Aragiorgis

394 865cdc2e Dimitris Aragiorgis
    This version of the function just writes the config file from static data.
395 865cdc2e Dimitris Aragiorgis

396 865cdc2e Dimitris Aragiorgis
    """
397 865cdc2e Dimitris Aragiorgis
    dirs = [(dname, constants.RUN_DIRS_MODE)
398 865cdc2e Dimitris Aragiorgis
            for dname in cls._DIRS + [cls._InstanceNICDir(instance_name)]]
399 865cdc2e Dimitris Aragiorgis
    utils.EnsureDirs(dirs)
400 865cdc2e Dimitris Aragiorgis
401 865cdc2e Dimitris Aragiorgis
    cfg_file = cls._InstanceNICFile(instance_name, idx)
402 865cdc2e Dimitris Aragiorgis
    data = StringIO()
403 865cdc2e Dimitris Aragiorgis
404 865cdc2e Dimitris Aragiorgis
    if nic.netinfo:
405 865cdc2e Dimitris Aragiorgis
      netinfo = objects.Network.FromDict(nic.netinfo)
406 865cdc2e Dimitris Aragiorgis
      data.write("NETWORK_NAME=%s\n" % netinfo.name)
407 865cdc2e Dimitris Aragiorgis
      if netinfo.network:
408 865cdc2e Dimitris Aragiorgis
        data.write("NETWORK_SUBNET=%s\n" % netinfo.network)
409 865cdc2e Dimitris Aragiorgis
      if netinfo.gateway:
410 865cdc2e Dimitris Aragiorgis
        data.write("NETWORK_GATEWAY=%s\n" % netinfo.gateway)
411 865cdc2e Dimitris Aragiorgis
      if netinfo.network6:
412 865cdc2e Dimitris Aragiorgis
        data.write("NETWORK_SUBNET6=%s\n" % netinfo.network6)
413 865cdc2e Dimitris Aragiorgis
      if netinfo.gateway6:
414 865cdc2e Dimitris Aragiorgis
        data.write("NETWORK_GATEWAY6=%s\n" % netinfo.gateway6)
415 865cdc2e Dimitris Aragiorgis
      if netinfo.mac_prefix:
416 865cdc2e Dimitris Aragiorgis
        data.write("NETWORK_MAC_PREFIX=%s\n" % netinfo.mac_prefix)
417 865cdc2e Dimitris Aragiorgis
      if netinfo.tags:
418 865cdc2e Dimitris Aragiorgis
        data.write("NETWORK_TAGS=%s\n" % "\ ".join(netinfo.tags))
419 865cdc2e Dimitris Aragiorgis
420 865cdc2e Dimitris Aragiorgis
    data.write("MAC=%s\n" % nic.mac)
421 865cdc2e Dimitris Aragiorgis
    data.write("IP=%s\n" % nic.ip)
422 865cdc2e Dimitris Aragiorgis
    data.write("MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
423 865cdc2e Dimitris Aragiorgis
    data.write("LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
424 865cdc2e Dimitris Aragiorgis
425 865cdc2e Dimitris Aragiorgis
    try:
426 865cdc2e Dimitris Aragiorgis
      utils.WriteFile(cfg_file, data=data.getvalue())
427 865cdc2e Dimitris Aragiorgis
    except EnvironmentError, err:
428 865cdc2e Dimitris Aragiorgis
      raise errors.HypervisorError("Cannot write Xen instance configuration"
429 865cdc2e Dimitris Aragiorgis
                                   " file %s: %s" % (cfg_file, err))
430 865cdc2e Dimitris Aragiorgis
431 865cdc2e Dimitris Aragiorgis
  @classmethod
432 865cdc2e Dimitris Aragiorgis
  def _InstanceNICDir(cls, instance_name):
433 865cdc2e Dimitris Aragiorgis
    """Returns the directory holding the tap device files for a given instance.
434 865cdc2e Dimitris Aragiorgis

435 865cdc2e Dimitris Aragiorgis
    """
436 865cdc2e Dimitris Aragiorgis
    return utils.PathJoin(cls._NICS_DIR, instance_name)
437 865cdc2e Dimitris Aragiorgis
438 865cdc2e Dimitris Aragiorgis
  @classmethod
439 865cdc2e Dimitris Aragiorgis
  def _InstanceNICFile(cls, instance_name, seq):
440 865cdc2e Dimitris Aragiorgis
    """Returns the name of the file containing the tap device for a given NIC
441 865cdc2e Dimitris Aragiorgis

442 865cdc2e Dimitris Aragiorgis
    """
443 865cdc2e Dimitris Aragiorgis
    return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
444 865cdc2e Dimitris Aragiorgis
445 865cdc2e Dimitris Aragiorgis
  @classmethod
446 c3d839f5 Michael Hanselmann
  def _GetConfig(cls, instance, startup_memory, block_devices):
447 c3d839f5 Michael Hanselmann
    """Build Xen configuration for an instance.
448 65a6f9b7 Michael Hanselmann

449 65a6f9b7 Michael Hanselmann
    """
450 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
451 65a6f9b7 Michael Hanselmann
452 c3d839f5 Michael Hanselmann
  def _WriteConfigFile(self, instance_name, data):
453 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
454 4390ccff Guido Trotter

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

457 4390ccff Guido Trotter
    """
458 1a63f285 Iustin Pop
    # just in case it exists
459 0a903309 Michael Hanselmann
    utils.RemoveFile(utils.PathJoin(self._cfgdir, "auto", instance_name))
460 a8e8c0c6 Michael Hanselmann
461 0a903309 Michael Hanselmann
    cfg_file = self._ConfigFileName(instance_name)
462 1a63f285 Iustin Pop
    try:
463 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
464 1a63f285 Iustin Pop
    except EnvironmentError, err:
465 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
466 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
467 4390ccff Guido Trotter
468 0a903309 Michael Hanselmann
  def _ReadConfigFile(self, instance_name):
469 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
470 4390ccff Guido Trotter

471 4390ccff Guido Trotter
    """
472 0a903309 Michael Hanselmann
    filename = self._ConfigFileName(instance_name)
473 76c364d9 Michael Hanselmann
474 4390ccff Guido Trotter
    try:
475 76c364d9 Michael Hanselmann
      file_content = utils.ReadFile(filename)
476 4390ccff Guido Trotter
    except EnvironmentError, err:
477 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
478 76c364d9 Michael Hanselmann
479 4390ccff Guido Trotter
    return file_content
480 4390ccff Guido Trotter
481 0a903309 Michael Hanselmann
  def _RemoveConfigFile(self, instance_name):
482 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
483 65a6f9b7 Michael Hanselmann

484 65a6f9b7 Michael Hanselmann
    """
485 0a903309 Michael Hanselmann
    utils.RemoveFile(self._ConfigFileName(instance_name))
486 865cdc2e Dimitris Aragiorgis
    try:
487 865cdc2e Dimitris Aragiorgis
      shutil.rmtree(self._InstanceNICDir(instance_name))
488 865cdc2e Dimitris Aragiorgis
    except OSError, err:
489 865cdc2e Dimitris Aragiorgis
      if err.errno != errno.ENOENT:
490 865cdc2e Dimitris Aragiorgis
        raise
491 65a6f9b7 Michael Hanselmann
492 48bba9de Balazs Lecz
  def _StashConfigFile(self, instance_name):
493 48bba9de Balazs Lecz
    """Move the Xen config file to the log directory and return its new path.
494 48bba9de Balazs Lecz

495 48bba9de Balazs Lecz
    """
496 48bba9de Balazs Lecz
    old_filename = self._ConfigFileName(instance_name)
497 48bba9de Balazs Lecz
    base = ("%s-%s" %
498 48bba9de Balazs Lecz
            (instance_name, utils.TimestampForFilename()))
499 48bba9de Balazs Lecz
    new_filename = utils.PathJoin(pathutils.LOG_XEN_DIR, base)
500 48bba9de Balazs Lecz
    utils.RenameFile(old_filename, new_filename)
501 48bba9de Balazs Lecz
    return new_filename
502 48bba9de Balazs Lecz
503 3d942d8b Michael Hanselmann
  def _GetXmList(self, include_node):
504 b255379d Michael Hanselmann
    """Wrapper around module level L{_GetXmList}.
505 06b78e8b Michael Hanselmann

506 06b78e8b Michael Hanselmann
    """
507 3d942d8b Michael Hanselmann
    return _GetXmList(lambda: self._RunXen(["list"]), include_node)
508 65a6f9b7 Michael Hanselmann
509 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
510 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
511 65a6f9b7 Michael Hanselmann

512 65a6f9b7 Michael Hanselmann
    """
513 b255379d Michael Hanselmann
    xm_list = self._GetXmList(False)
514 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
515 65a6f9b7 Michael Hanselmann
    return names
516 65a6f9b7 Michael Hanselmann
517 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
518 65a6f9b7 Michael Hanselmann
    """Get instance properties.
519 65a6f9b7 Michael Hanselmann

520 c41eea6e Iustin Pop
    @param instance_name: the instance name
521 c41eea6e Iustin Pop

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

524 65a6f9b7 Michael Hanselmann
    """
525 b255379d Michael Hanselmann
    xm_list = self._GetXmList(instance_name == _DOM0_NAME)
526 65a6f9b7 Michael Hanselmann
    result = None
527 65a6f9b7 Michael Hanselmann
    for data in xm_list:
528 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
529 65a6f9b7 Michael Hanselmann
        result = data
530 65a6f9b7 Michael Hanselmann
        break
531 65a6f9b7 Michael Hanselmann
    return result
532 65a6f9b7 Michael Hanselmann
533 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
534 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
535 65a6f9b7 Michael Hanselmann

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

538 65a6f9b7 Michael Hanselmann
    """
539 b255379d Michael Hanselmann
    xm_list = self._GetXmList(False)
540 65a6f9b7 Michael Hanselmann
    return xm_list
541 65a6f9b7 Michael Hanselmann
542 c3d839f5 Michael Hanselmann
  def _MakeConfigFile(self, instance, startup_memory, block_devices):
543 c3d839f5 Michael Hanselmann
    """Gather configuration details and write to disk.
544 c3d839f5 Michael Hanselmann

545 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
546 c3d839f5 Michael Hanselmann

547 c3d839f5 Michael Hanselmann
    """
548 c3d839f5 Michael Hanselmann
    buf = StringIO()
549 c3d839f5 Michael Hanselmann
    buf.write("# Automatically generated by Ganeti. Do not edit!\n")
550 c3d839f5 Michael Hanselmann
    buf.write("\n")
551 c3d839f5 Michael Hanselmann
    buf.write(self._GetConfig(instance, startup_memory, block_devices))
552 c3d839f5 Michael Hanselmann
    buf.write("\n")
553 c3d839f5 Michael Hanselmann
554 c3d839f5 Michael Hanselmann
    self._WriteConfigFile(instance.name, buf.getvalue())
555 c3d839f5 Michael Hanselmann
556 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
557 c41eea6e Iustin Pop
    """Start an instance.
558 c41eea6e Iustin Pop

559 c41eea6e Iustin Pop
    """
560 61eb1a46 Guido Trotter
    startup_memory = self._InstanceStartupMemory(instance)
561 c3d839f5 Michael Hanselmann
562 c3d839f5 Michael Hanselmann
    self._MakeConfigFile(instance, startup_memory, block_devices)
563 c3d839f5 Michael Hanselmann
564 3d942d8b Michael Hanselmann
    cmd = ["create"]
565 323f9095 Stephen Shirley
    if startup_paused:
566 3d942d8b Michael Hanselmann
      cmd.append("-p")
567 3d942d8b Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
568 65a6f9b7 Michael Hanselmann
569 3d942d8b Michael Hanselmann
    result = self._RunXen(cmd)
570 65a6f9b7 Michael Hanselmann
    if result.failed:
571 48bba9de Balazs Lecz
      # Move the Xen configuration file to the log directory to avoid
572 48bba9de Balazs Lecz
      # leaving a stale config file behind.
573 48bba9de Balazs Lecz
      stashed_config = self._StashConfigFile(instance.name)
574 48bba9de Balazs Lecz
      raise errors.HypervisorError("Failed to start instance %s: %s (%s). Moved"
575 48bba9de Balazs Lecz
                                   " config file to %s" %
576 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
577 48bba9de Balazs Lecz
                                    result.output, stashed_config))
578 65a6f9b7 Michael Hanselmann
579 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
580 c41eea6e Iustin Pop
    """Stop an instance.
581 c41eea6e Iustin Pop

582 c41eea6e Iustin Pop
    """
583 bbcf7ad0 Iustin Pop
    if name is None:
584 bbcf7ad0 Iustin Pop
      name = instance.name
585 4b8b172d Michael Hanselmann
586 31da5ab5 Michael Hanselmann
    return self._StopInstance(name, force)
587 31da5ab5 Michael Hanselmann
588 364c350f Jose A. Lopes
  def _ShutdownInstance(self, name):
589 364c350f Jose A. Lopes
    """Shutdown an instance if the instance is running.
590 364c350f Jose A. Lopes

591 364c350f Jose A. Lopes
    @type name: string
592 364c350f Jose A. Lopes
    @param name: name of the instance to stop
593 364c350f Jose A. Lopes

594 364c350f Jose A. Lopes
    The '-w' flag waits for shutdown to complete which avoids the need
595 364c350f Jose A. Lopes
    to poll in the case where we want to destroy the domain
596 364c350f Jose A. Lopes
    immediately after shutdown.
597 364c350f Jose A. Lopes

598 364c350f Jose A. Lopes
    """
599 364c350f Jose A. Lopes
    instance_info = self.GetInstanceInfo(name)
600 364c350f Jose A. Lopes
601 364c350f Jose A. Lopes
    if instance_info is None or _IsInstanceShutdown(instance_info[4]):
602 364c350f Jose A. Lopes
      logging.info("Failed to shutdown instance %s, not running", name)
603 364c350f Jose A. Lopes
      return None
604 364c350f Jose A. Lopes
605 364c350f Jose A. Lopes
    return self._RunXen(["shutdown", "-w", name])
606 364c350f Jose A. Lopes
607 364c350f Jose A. Lopes
  def _DestroyInstance(self, name):
608 364c350f Jose A. Lopes
    """Destroy an instance if the instance if the instance exists.
609 364c350f Jose A. Lopes

610 364c350f Jose A. Lopes
    @type name: string
611 364c350f Jose A. Lopes
    @param name: name of the instance to destroy
612 364c350f Jose A. Lopes

613 364c350f Jose A. Lopes
    """
614 364c350f Jose A. Lopes
    instance_info = self.GetInstanceInfo(name)
615 364c350f Jose A. Lopes
616 364c350f Jose A. Lopes
    if instance_info is None:
617 364c350f Jose A. Lopes
      logging.info("Failed to destroy instance %s, does not exist", name)
618 364c350f Jose A. Lopes
      return None
619 364c350f Jose A. Lopes
620 364c350f Jose A. Lopes
    return self._RunXen(["destroy", name])
621 364c350f Jose A. Lopes
622 31da5ab5 Michael Hanselmann
  def _StopInstance(self, name, force):
623 31da5ab5 Michael Hanselmann
    """Stop an instance.
624 31da5ab5 Michael Hanselmann

625 364c350f Jose A. Lopes
    @type name: string
626 364c350f Jose A. Lopes
    @param name: name of the instance to destroy
627 364c350f Jose A. Lopes

628 364c350f Jose A. Lopes
    @type force: boolean
629 364c350f Jose A. Lopes
    @param force: whether to do a "hard" stop (destroy)
630 364c350f Jose A. Lopes

631 31da5ab5 Michael Hanselmann
    """
632 65a6f9b7 Michael Hanselmann
    if force:
633 364c350f Jose A. Lopes
      result = self._DestroyInstance(name)
634 65a6f9b7 Michael Hanselmann
    else:
635 364c350f Jose A. Lopes
      self._ShutdownInstance(name)
636 364c350f Jose A. Lopes
      result = self._DestroyInstance(name)
637 65a6f9b7 Michael Hanselmann
638 364c350f Jose A. Lopes
    if result is not None and result.failed and \
639 364c350f Jose A. Lopes
          self.GetInstanceInfo(name) is not None:
640 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
641 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
642 65a6f9b7 Michael Hanselmann
643 4b8b172d Michael Hanselmann
    # Remove configuration file if stopping/starting instance was successful
644 4b8b172d Michael Hanselmann
    self._RemoveConfigFile(name)
645 4b8b172d Michael Hanselmann
646 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
647 c41eea6e Iustin Pop
    """Reboot an instance.
648 c41eea6e Iustin Pop

649 c41eea6e Iustin Pop
    """
650 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
651 65a6f9b7 Michael Hanselmann
652 e0561198 Iustin Pop
    if ini_info is None:
653 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
654 e0561198 Iustin Pop
                                   " not running" % instance.name)
655 e0561198 Iustin Pop
656 3d942d8b Michael Hanselmann
    result = self._RunXen(["reboot", instance.name])
657 65a6f9b7 Michael Hanselmann
    if result.failed:
658 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
659 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
660 3213d3c8 Iustin Pop
                                    result.output))
661 06b78e8b Michael Hanselmann
662 06b78e8b Michael Hanselmann
    def _CheckInstance():
663 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
664 06b78e8b Michael Hanselmann
665 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
666 e0561198 Iustin Pop
      if (new_info is not None and
667 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
668 06b78e8b Michael Hanselmann
        return
669 7dd106d3 Iustin Pop
670 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
671 06b78e8b Michael Hanselmann
672 06b78e8b Michael Hanselmann
    try:
673 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
674 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
675 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
676 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
677 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
678 7dd106d3 Iustin Pop
                                   (instance.name, ))
679 65a6f9b7 Michael Hanselmann
680 2c7a0373 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
681 2c7a0373 Guido Trotter
    """Balloon an instance memory to a certain value.
682 2c7a0373 Guido Trotter

683 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
684 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
685 2c7a0373 Guido Trotter
    @type mem: int
686 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
687 2c7a0373 Guido Trotter

688 2c7a0373 Guido Trotter
    """
689 3d942d8b Michael Hanselmann
    result = self._RunXen(["mem-set", instance.name, mem])
690 2c7a0373 Guido Trotter
    if result.failed:
691 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
692 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
693 2c7a0373 Guido Trotter
                                    result.output))
694 3d942d8b Michael Hanselmann
695 3d942d8b Michael Hanselmann
    # Update configuration file
696 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
697 0a903309 Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
698 3d942d8b Michael Hanselmann
699 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
700 2c7a0373 Guido Trotter
    if result.failed:
701 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
702 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
703 2c7a0373 Guido Trotter
                                    result.output))
704 2c7a0373 Guido Trotter
705 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
706 65a6f9b7 Michael Hanselmann
    """Return information about the node.
707 65a6f9b7 Michael Hanselmann

708 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
709 65a6f9b7 Michael Hanselmann

710 65a6f9b7 Michael Hanselmann
    """
711 3d942d8b Michael Hanselmann
    result = self._RunXen(["info"])
712 65a6f9b7 Michael Hanselmann
    if result.failed:
713 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
714 b48909c8 Iustin Pop
                    result.output)
715 65a6f9b7 Michael Hanselmann
      return None
716 65a6f9b7 Michael Hanselmann
717 06c9a520 Michael Hanselmann
    return _GetNodeInfo(result.stdout, self._GetXmList)
718 65a6f9b7 Michael Hanselmann
719 637ce7f9 Guido Trotter
  @classmethod
720 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
721 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
722 65a6f9b7 Michael Hanselmann

723 65a6f9b7 Michael Hanselmann
    """
724 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
725 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
726 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
727 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
728 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
729 1f5557ca Guido Trotter
                                            constants.XEN_CMD, instance.name])
730 65a6f9b7 Michael Hanselmann
731 65a6f9b7 Michael Hanselmann
  def Verify(self):
732 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
733 65a6f9b7 Michael Hanselmann

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

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

738 65a6f9b7 Michael Hanselmann
    """
739 3d942d8b Michael Hanselmann
    result = self._RunXen(["info"])
740 e3e66f02 Michael Hanselmann
    if result.failed:
741 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
742 65a6f9b7 Michael Hanselmann
743 cd04dfd2 Michael Hanselmann
    return None
744 cd04dfd2 Michael Hanselmann
745 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
746 4390ccff Guido Trotter
    """Get instance information to perform a migration.
747 4390ccff Guido Trotter

748 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
749 4390ccff Guido Trotter
    @param instance: instance to be migrated
750 4390ccff Guido Trotter
    @rtype: string
751 4390ccff Guido Trotter
    @return: content of the xen config file
752 4390ccff Guido Trotter

753 4390ccff Guido Trotter
    """
754 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
755 4390ccff Guido Trotter
756 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
757 4390ccff Guido Trotter
    """Prepare to accept an instance.
758 4390ccff Guido Trotter

759 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
760 4390ccff Guido Trotter
    @param instance: instance to be accepted
761 4390ccff Guido Trotter
    @type info: string
762 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
763 4390ccff Guido Trotter
    @type target: string
764 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
765 4390ccff Guido Trotter

766 4390ccff Guido Trotter
    """
767 4390ccff Guido Trotter
    pass
768 4390ccff Guido Trotter
769 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
770 4390ccff Guido Trotter
    """Finalize an instance migration.
771 4390ccff Guido Trotter

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

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

782 4390ccff Guido Trotter
    """
783 4390ccff Guido Trotter
    if success:
784 c3d839f5 Michael Hanselmann
      self._WriteConfigFile(instance.name, info)
785 4390ccff Guido Trotter
786 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
787 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
788 6e7275c0 Iustin Pop

789 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
790 6e7275c0 Iustin Pop
    currently running.
791 6e7275c0 Iustin Pop

792 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
793 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
794 fdf7f055 Guido Trotter
    @type target: string
795 fdf7f055 Guido Trotter
    @param target: ip address of the target node
796 fdf7f055 Guido Trotter
    @type live: boolean
797 fdf7f055 Guido Trotter
    @param live: perform a live migration
798 fdf7f055 Guido Trotter

799 6e7275c0 Iustin Pop
    """
800 d8784f7d Michael Hanselmann
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
801 d8784f7d Michael Hanselmann
802 d8784f7d Michael Hanselmann
    # TODO: Pass cluster name via RPC
803 d8784f7d Michael Hanselmann
    cluster_name = ssconf.SimpleStore().GetClusterName()
804 d8784f7d Michael Hanselmann
805 d8784f7d Michael Hanselmann
    return self._MigrateInstance(cluster_name, instance.name, target, port,
806 d8784f7d Michael Hanselmann
                                 live)
807 d8784f7d Michael Hanselmann
808 d8784f7d Michael Hanselmann
  def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
809 d8784f7d Michael Hanselmann
                       _ping_fn=netutils.TcpPing):
810 d8784f7d Michael Hanselmann
    """Migrate an instance to a target node.
811 d8784f7d Michael Hanselmann

812 d8784f7d Michael Hanselmann
    @see: L{MigrateInstance} for details
813 d8784f7d Michael Hanselmann

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

851 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
852 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
853 60af751d Andrea Spadaccini
    @type success: bool
854 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
855 60af751d Andrea Spadaccini
    @type live: bool
856 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
857 60af751d Andrea Spadaccini

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

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

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

881 60af751d Andrea Spadaccini
    """
882 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
883 6e7275c0 Iustin Pop
884 f5118ade Iustin Pop
  @classmethod
885 f5118ade Iustin Pop
  def PowercycleNode(cls):
886 f5118ade Iustin Pop
    """Xen-specific powercycle.
887 f5118ade Iustin Pop

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

895 f5118ade Iustin Pop
    """
896 f5118ade Iustin Pop
    try:
897 f5118ade Iustin Pop
      cls.LinuxPowercycle()
898 f5118ade Iustin Pop
    finally:
899 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
900 f5118ade Iustin Pop
901 65a6f9b7 Michael Hanselmann
902 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
903 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
904 65a6f9b7 Michael Hanselmann
905 205ab586 Iustin Pop
  PARAMETERS = {
906 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
907 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
908 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
909 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
910 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
911 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
912 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
913 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
914 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
915 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
916 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
917 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
918 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
919 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
920 2c368f28 Guido Trotter
    constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
921 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
922 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
923 865cdc2e Dimitris Aragiorgis
    constants.HV_VIF_SCRIPT: hv_base.OPT_FILE_CHECK,
924 205ab586 Iustin Pop
    }
925 f48148c3 Iustin Pop
926 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
927 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
928 65a6f9b7 Michael Hanselmann

929 65a6f9b7 Michael Hanselmann
    """
930 a985b417 Iustin Pop
    hvp = instance.hvparams
931 65a6f9b7 Michael Hanselmann
    config = StringIO()
932 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
933 65a6f9b7 Michael Hanselmann
934 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
935 2f2dbb4b Jun Futagawa
    # parameters.
936 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
937 2f2dbb4b Jun Futagawa
      # bootloader handling
938 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
939 2f2dbb4b Jun Futagawa
      if bootloader_path:
940 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
941 2f2dbb4b Jun Futagawa
      else:
942 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
943 2f2dbb4b Jun Futagawa
                                     " bootloader path")
944 65a6f9b7 Michael Hanselmann
945 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
946 2f2dbb4b Jun Futagawa
      if bootloader_args:
947 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
948 2f2dbb4b Jun Futagawa
    else:
949 2f2dbb4b Jun Futagawa
      # kernel handling
950 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
951 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
952 2f2dbb4b Jun Futagawa
953 2f2dbb4b Jun Futagawa
      # initrd handling
954 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
955 2f2dbb4b Jun Futagawa
      if initrd_path:
956 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
957 65a6f9b7 Michael Hanselmann
958 65a6f9b7 Michael Hanselmann
    # rest of the settings
959 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
960 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
961 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
962 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
963 c4708267 Tsachy Shacham
    if cpu_pinning:
964 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
965 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
966 8bd977e9 Sébastien Bocahu
    if cpu_cap:
967 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
968 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
969 8bd977e9 Sébastien Bocahu
    if cpu_weight:
970 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
971 c4708267 Tsachy Shacham
972 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
973 65a6f9b7 Michael Hanselmann
974 65a6f9b7 Michael Hanselmann
    vif_data = []
975 865cdc2e Dimitris Aragiorgis
    for idx, nic in enumerate(instance.nics):
976 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
977 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
978 65a6f9b7 Michael Hanselmann
      if ip is not None:
979 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
980 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
981 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
982 865cdc2e Dimitris Aragiorgis
      if hvp[constants.HV_VIF_SCRIPT]:
983 865cdc2e Dimitris Aragiorgis
        nic_str += ", script=%s" % hvp[constants.HV_VIF_SCRIPT]
984 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
985 865cdc2e Dimitris Aragiorgis
      self._WriteNICInfoFile(instance.name, idx, nic)
986 65a6f9b7 Michael Hanselmann
987 d0bb3f24 Michael Hanselmann
    disk_data = \
988 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
989 7ed85ffe Iustin Pop
990 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
991 7ed85ffe Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
992 074ca009 Guido Trotter
993 7adf7814 René Nussbaumer
    if hvp[constants.HV_ROOT_PATH]:
994 7adf7814 René Nussbaumer
      config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
995 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
996 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
997 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
998 990ade2d Stephen Shirley
    else:
999 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
1000 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
1001 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
1002 73cd67f4 Guido Trotter
1003 c3d839f5 Michael Hanselmann
    return config.getvalue()
1004 65a6f9b7 Michael Hanselmann
1005 65a6f9b7 Michael Hanselmann
1006 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
1007 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
1008 65a6f9b7 Michael Hanselmann
1009 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
1010 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
1011 69b99987 Michael Hanselmann
    ]
1012 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
1013 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
1014 69ab2e12 Guido Trotter
    ]
1015 3680f662 Guido Trotter
1016 205ab586 Iustin Pop
  PARAMETERS = {
1017 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
1018 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
1019 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
1020 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
1021 016d04b3 Michael Hanselmann
       None, None),
1022 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
1023 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
1024 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
1025 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
1026 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
1027 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
1028 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
1029 8b312c1d Manuel Franceschini
      (False, netutils.IP4Address.IsValid,
1030 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
1031 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
1032 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
1033 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
1034 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
1035 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
1036 6b970cef Jun Futagawa
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
1037 e695efbf Iustin Pop
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
1038 e695efbf Iustin Pop
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
1039 87f0aa48 Jack
    # Add PCI passthrough
1040 3891c95e Bernardo Dal Seno
    constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
1041 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
1042 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
1043 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
1044 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_CAP: hv_base.NO_CHECK,
1045 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
1046 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65535, "invalid weight", None, None),
1047 05440845 Helga Velroyen
    constants.HV_VIF_TYPE:
1048 05440845 Helga Velroyen
      hv_base.ParamInSet(False, constants.HT_HVM_VALID_VIF_TYPES),
1049 ffc27116 Thomas Thrainer
    constants.HV_VIRIDIAN: hv_base.NO_CHECK,
1050 865cdc2e Dimitris Aragiorgis
    constants.HV_VIF_SCRIPT: hv_base.OPT_FILE_CHECK,
1051 205ab586 Iustin Pop
    }
1052 09ea8710 Iustin Pop
1053 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
1054 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
1055 65a6f9b7 Michael Hanselmann

1056 65a6f9b7 Michael Hanselmann
    """
1057 a985b417 Iustin Pop
    hvp = instance.hvparams
1058 a985b417 Iustin Pop
1059 65a6f9b7 Michael Hanselmann
    config = StringIO()
1060 e2ee1cea Iustin Pop
1061 e2ee1cea Iustin Pop
    # kernel handling
1062 e2ee1cea Iustin Pop
    kpath = hvp[constants.HV_KERNEL_PATH]
1063 e2ee1cea Iustin Pop
    config.write("kernel = '%s'\n" % kpath)
1064 e2ee1cea Iustin Pop
1065 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
1066 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
1067 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
1068 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
1069 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
1070 c4708267 Tsachy Shacham
    if cpu_pinning:
1071 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
1072 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
1073 8bd977e9 Sébastien Bocahu
    if cpu_cap:
1074 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
1075 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
1076 8bd977e9 Sébastien Bocahu
    if cpu_weight:
1077 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
1078 c4708267 Tsachy Shacham
1079 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
1080 09ea8710 Iustin Pop
    if hvp[constants.HV_PAE]:
1081 a21dda8b Iustin Pop
      config.write("pae = 1\n")
1082 a21dda8b Iustin Pop
    else:
1083 a21dda8b Iustin Pop
      config.write("pae = 0\n")
1084 09ea8710 Iustin Pop
    if hvp[constants.HV_ACPI]:
1085 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
1086 a21dda8b Iustin Pop
    else:
1087 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
1088 ffc27116 Thomas Thrainer
    if hvp[constants.HV_VIRIDIAN]:
1089 ffc27116 Thomas Thrainer
      config.write("viridian = 1\n")
1090 ffc27116 Thomas Thrainer
    else:
1091 ffc27116 Thomas Thrainer
      config.write("viridian = 0\n")
1092 ffc27116 Thomas Thrainer
1093 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
1094 09ea8710 Iustin Pop
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
1095 a985b417 Iustin Pop
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
1096 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
1097 97efde45 Guido Trotter
    config.write("usb = 1\n")
1098 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
1099 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
1100 a985b417 Iustin Pop
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
1101 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
1102 d0c11cf7 Alexander Schreiber
    else:
1103 6b405598 Guido Trotter
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
1104 65a6f9b7 Michael Hanselmann
1105 377d74c9 Guido Trotter
    if instance.network_port > constants.VNC_BASE_PORT:
1106 377d74c9 Guido Trotter
      display = instance.network_port - constants.VNC_BASE_PORT
1107 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
1108 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
1109 65a6f9b7 Michael Hanselmann
    else:
1110 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
1111 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
1112 65a6f9b7 Michael Hanselmann
1113 6e6bb8d5 Guido Trotter
    vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
1114 65a6f9b7 Michael Hanselmann
    try:
1115 6e6bb8d5 Guido Trotter
      password = utils.ReadFile(vnc_pwd_file)
1116 78f66a17 Guido Trotter
    except EnvironmentError, err:
1117 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
1118 6e6bb8d5 Guido Trotter
                                   (vnc_pwd_file, err))
1119 65a6f9b7 Michael Hanselmann
1120 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
1121 65a6f9b7 Michael Hanselmann
1122 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
1123 6b970cef Jun Futagawa
    if hvp[constants.HV_USE_LOCALTIME]:
1124 6b970cef Jun Futagawa
      config.write("localtime = 1\n")
1125 65a6f9b7 Michael Hanselmann
1126 65a6f9b7 Michael Hanselmann
    vif_data = []
1127 05440845 Helga Velroyen
    # Note: what is called 'nic_type' here, is used as value for the xen nic
1128 05440845 Helga Velroyen
    # vif config parameter 'model'. For the xen nic vif parameter 'type', we use
1129 05440845 Helga Velroyen
    # the 'vif_type' to avoid a clash of notation.
1130 a985b417 Iustin Pop
    nic_type = hvp[constants.HV_NIC_TYPE]
1131 05440845 Helga Velroyen
1132 f48148c3 Iustin Pop
    if nic_type is None:
1133 05440845 Helga Velroyen
      vif_type_str = ""
1134 05440845 Helga Velroyen
      if hvp[constants.HV_VIF_TYPE]:
1135 05440845 Helga Velroyen
        vif_type_str = ", type=%s" % hvp[constants.HV_VIF_TYPE]
1136 f48148c3 Iustin Pop
      # ensure old instances don't change
1137 05440845 Helga Velroyen
      nic_type_str = vif_type_str
1138 d08f6067 Guido Trotter
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
1139 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
1140 f48148c3 Iustin Pop
    else:
1141 05440845 Helga Velroyen
      # parameter 'model' is only valid with type 'ioemu'
1142 05440845 Helga Velroyen
      nic_type_str = ", model=%s, type=%s" % \
1143 05440845 Helga Velroyen
        (nic_type, constants.HT_HVM_VIF_IOEMU)
1144 865cdc2e Dimitris Aragiorgis
    for idx, nic in enumerate(instance.nics):
1145 503b97a9 Guido Trotter
      nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
1146 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
1147 65a6f9b7 Michael Hanselmann
      if ip is not None:
1148 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
1149 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1150 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
1151 865cdc2e Dimitris Aragiorgis
      if hvp[constants.HV_VIF_SCRIPT]:
1152 865cdc2e Dimitris Aragiorgis
        nic_str += ", script=%s" % hvp[constants.HV_VIF_SCRIPT]
1153 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
1154 865cdc2e Dimitris Aragiorgis
      self._WriteNICInfoFile(instance.name, idx, nic)
1155 65a6f9b7 Michael Hanselmann
1156 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
1157 525011bc Maciej Bliziński
1158 d0bb3f24 Michael Hanselmann
    disk_data = \
1159 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
1160 525011bc Maciej Bliziński
1161 a985b417 Iustin Pop
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
1162 f48148c3 Iustin Pop
    if iso_path:
1163 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
1164 a21dda8b Iustin Pop
      disk_data.append(iso)
1165 a21dda8b Iustin Pop
1166 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
1167 87f0aa48 Jack
    # Add PCI passthrough
1168 87f0aa48 Jack
    pci_pass_arr = []
1169 87f0aa48 Jack
    pci_pass = hvp[constants.HV_PASSTHROUGH]
1170 87f0aa48 Jack
    if pci_pass:
1171 3891c95e Bernardo Dal Seno
      pci_pass_arr = pci_pass.split(";")
1172 3891c95e Bernardo Dal Seno
      config.write("pci = %s\n" % pci_pass_arr)
1173 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
1174 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
1175 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
1176 990ade2d Stephen Shirley
    else:
1177 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
1178 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
1179 73cd67f4 Guido Trotter
1180 c3d839f5 Michael Hanselmann
    return config.getvalue()