Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ ed6d006b

History | View | Annotate | Download (37.1 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 7d4ae909 Dimitris Aragiorgis
  def _WriteNICInfoFile(cls, instance, 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 7d4ae909 Dimitris Aragiorgis
    instance_name = instance.name
398 865cdc2e Dimitris Aragiorgis
    dirs = [(dname, constants.RUN_DIRS_MODE)
399 865cdc2e Dimitris Aragiorgis
            for dname in cls._DIRS + [cls._InstanceNICDir(instance_name)]]
400 865cdc2e Dimitris Aragiorgis
    utils.EnsureDirs(dirs)
401 865cdc2e Dimitris Aragiorgis
402 865cdc2e Dimitris Aragiorgis
    cfg_file = cls._InstanceNICFile(instance_name, idx)
403 865cdc2e Dimitris Aragiorgis
    data = StringIO()
404 865cdc2e Dimitris Aragiorgis
405 7d4ae909 Dimitris Aragiorgis
    data.write("TAGS=%s\n" % "\ ".join(instance.GetTags()))
406 865cdc2e Dimitris Aragiorgis
    if nic.netinfo:
407 865cdc2e Dimitris Aragiorgis
      netinfo = objects.Network.FromDict(nic.netinfo)
408 45ba54c4 Dimitris Aragiorgis
      for k, v in netinfo.HooksDict().iteritems():
409 45ba54c4 Dimitris Aragiorgis
        data.write("%s=%s\n" % (k, v))
410 865cdc2e Dimitris Aragiorgis
411 865cdc2e Dimitris Aragiorgis
    data.write("MAC=%s\n" % nic.mac)
412 6ba0093c Dimitris Aragiorgis
    if nic.ip:
413 6ba0093c Dimitris Aragiorgis
      data.write("IP=%s\n" % nic.ip)
414 6ba0093c Dimitris Aragiorgis
    data.write("INTERFACE_INDEX=%s\n" % str(idx))
415 6ba0093c Dimitris Aragiorgis
    if nic.name:
416 6ba0093c Dimitris Aragiorgis
      data.write("INTERFACE_NAME=%s\n" % nic.name)
417 6ba0093c Dimitris Aragiorgis
    data.write("INTERFACE_UUID=%s\n" % nic.uuid)
418 865cdc2e Dimitris Aragiorgis
    data.write("MODE=%s\n" % nic.nicparams[constants.NIC_MODE])
419 865cdc2e Dimitris Aragiorgis
    data.write("LINK=%s\n" % nic.nicparams[constants.NIC_LINK])
420 865cdc2e Dimitris Aragiorgis
421 865cdc2e Dimitris Aragiorgis
    try:
422 865cdc2e Dimitris Aragiorgis
      utils.WriteFile(cfg_file, data=data.getvalue())
423 865cdc2e Dimitris Aragiorgis
    except EnvironmentError, err:
424 865cdc2e Dimitris Aragiorgis
      raise errors.HypervisorError("Cannot write Xen instance configuration"
425 865cdc2e Dimitris Aragiorgis
                                   " file %s: %s" % (cfg_file, err))
426 865cdc2e Dimitris Aragiorgis
427 865cdc2e Dimitris Aragiorgis
  @classmethod
428 865cdc2e Dimitris Aragiorgis
  def _InstanceNICDir(cls, instance_name):
429 865cdc2e Dimitris Aragiorgis
    """Returns the directory holding the tap device files for a given instance.
430 865cdc2e Dimitris Aragiorgis

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

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

445 65a6f9b7 Michael Hanselmann
    """
446 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
447 65a6f9b7 Michael Hanselmann
448 c3d839f5 Michael Hanselmann
  def _WriteConfigFile(self, instance_name, data):
449 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
450 4390ccff Guido Trotter

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

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

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

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

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

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

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

516 c41eea6e Iustin Pop
    @param instance_name: the instance name
517 c41eea6e Iustin Pop

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

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

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

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

541 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
542 c3d839f5 Michael Hanselmann

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

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

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

587 364c350f Jose A. Lopes
    @type name: string
588 364c350f Jose A. Lopes
    @param name: name of the instance to stop
589 364c350f Jose A. Lopes

590 364c350f Jose A. Lopes
    The '-w' flag waits for shutdown to complete which avoids the need
591 364c350f Jose A. Lopes
    to poll in the case where we want to destroy the domain
592 364c350f Jose A. Lopes
    immediately after shutdown.
593 364c350f Jose A. Lopes

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

606 364c350f Jose A. Lopes
    @type name: string
607 364c350f Jose A. Lopes
    @param name: name of the instance to destroy
608 364c350f Jose A. Lopes

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

621 364c350f Jose A. Lopes
    @type name: string
622 364c350f Jose A. Lopes
    @param name: name of the instance to destroy
623 364c350f Jose A. Lopes

624 364c350f Jose A. Lopes
    @type force: boolean
625 364c350f Jose A. Lopes
    @param force: whether to do a "hard" stop (destroy)
626 364c350f Jose A. Lopes

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

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

679 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
680 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
681 2c7a0373 Guido Trotter
    @type mem: int
682 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
683 2c7a0373 Guido Trotter

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

704 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
705 65a6f9b7 Michael Hanselmann

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

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

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

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

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

744 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
745 4390ccff Guido Trotter
    @param instance: instance to be migrated
746 4390ccff Guido Trotter
    @rtype: string
747 4390ccff Guido Trotter
    @return: content of the xen config file
748 4390ccff Guido Trotter

749 4390ccff Guido Trotter
    """
750 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
751 4390ccff Guido Trotter
752 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
753 4390ccff Guido Trotter
    """Prepare to accept an instance.
754 4390ccff Guido Trotter

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

762 4390ccff Guido Trotter
    """
763 4390ccff Guido Trotter
    pass
764 4390ccff Guido Trotter
765 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
766 4390ccff Guido Trotter
    """Finalize an instance migration.
767 4390ccff Guido Trotter

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

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

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

785 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
786 6e7275c0 Iustin Pop
    currently running.
787 6e7275c0 Iustin Pop

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

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

808 d8784f7d Michael Hanselmann
    @see: L{MigrateInstance} for details
809 d8784f7d Michael Hanselmann

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

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

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

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

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

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

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

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

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

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