Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ f4529722

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 71fe51f8 Dimitris Aragiorgis
import errno
28 d0bb3f24 Michael Hanselmann
import string # pylint: disable=W0402
29 71fe51f8 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 d0bb3f24 Michael Hanselmann
  }
53 22d568c2 Guido Trotter
54 22d568c2 Guido Trotter
55 347fa0f1 Michael Hanselmann
def _CreateConfigCpus(cpu_mask):
56 347fa0f1 Michael Hanselmann
  """Create a CPU config string for Xen's config file.
57 347fa0f1 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

393 71fe51f8 Dimitris Aragiorgis
    This version of the function just writes the config file from static data.
394 71fe51f8 Dimitris Aragiorgis

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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