Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 78f99abb

History | View | Annotate | Download (40 kB)

1 65a6f9b7 Michael Hanselmann
#
2 65a6f9b7 Michael Hanselmann
#
3 65a6f9b7 Michael Hanselmann
4 1a63f285 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
5 65a6f9b7 Michael Hanselmann
#
6 65a6f9b7 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 65a6f9b7 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 65a6f9b7 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 65a6f9b7 Michael Hanselmann
# (at your option) any later version.
10 65a6f9b7 Michael Hanselmann
#
11 65a6f9b7 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 65a6f9b7 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 65a6f9b7 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 65a6f9b7 Michael Hanselmann
# General Public License for more details.
15 65a6f9b7 Michael Hanselmann
#
16 65a6f9b7 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 65a6f9b7 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 65a6f9b7 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 65a6f9b7 Michael Hanselmann
# 02110-1301, USA.
20 65a6f9b7 Michael Hanselmann
21 65a6f9b7 Michael Hanselmann
22 65a6f9b7 Michael Hanselmann
"""Xen hypervisors
23 65a6f9b7 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

311 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
312 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
313 65a6f9b7 Michael Hanselmann

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

349 51a95d00 Helga Velroyen
    @type hvparams: dict of strings
350 51a95d00 Helga Velroyen
    @param hvparams: hypervisor parameters
351 51a95d00 Helga Velroyen

352 d8784f7d Michael Hanselmann
    """
353 3d942d8b Michael Hanselmann
    if self._cmd is None:
354 398fd4f6 Helga Velroyen
      if hvparams is None or constants.HV_XEN_CMD not in hvparams:
355 398fd4f6 Helga Velroyen
        raise errors.HypervisorError("Cannot determine xen command.")
356 51a95d00 Helga Velroyen
      else:
357 398fd4f6 Helga Velroyen
        cmd = hvparams[constants.HV_XEN_CMD]
358 3d942d8b Michael Hanselmann
    else:
359 3d942d8b Michael Hanselmann
      cmd = self._cmd
360 3d942d8b Michael Hanselmann
361 3d942d8b Michael Hanselmann
    if cmd not in constants.KNOWN_XEN_COMMANDS:
362 3d942d8b Michael Hanselmann
      raise errors.ProgrammerError("Unknown Xen command '%s'" % cmd)
363 3d942d8b Michael Hanselmann
364 3d942d8b Michael Hanselmann
    return cmd
365 3d942d8b Michael Hanselmann
366 398fd4f6 Helga Velroyen
  def _RunXen(self, args, hvparams):
367 81124130 Michael Hanselmann
    """Wrapper around L{utils.process.RunCmd} to run Xen command.
368 3d942d8b Michael Hanselmann

369 58e356a9 Helga Velroyen
    @type hvparams: dict of strings
370 58e356a9 Helga Velroyen
    @param hvparams: dictionary of hypervisor params
371 81124130 Michael Hanselmann
    @see: L{utils.process.RunCmd}
372 3d942d8b Michael Hanselmann

373 3d942d8b Michael Hanselmann
    """
374 398fd4f6 Helga Velroyen
    cmd = [self._GetCommand(hvparams)]
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 397b7844 Dimitris Aragiorgis
  def _WriteNICInfoFile(cls, instance_name, idx, nic):
392 397b7844 Dimitris Aragiorgis
    """Write the Xen config file for the instance.
393 397b7844 Dimitris Aragiorgis

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

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

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

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

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

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

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

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

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

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

506 398fd4f6 Helga Velroyen
    @type hvparams: dict of strings
507 398fd4f6 Helga Velroyen
    @param hvparams: hypervisor parameters to be used on this node
508 398fd4f6 Helga Velroyen

509 06b78e8b Michael Hanselmann
    """
510 398fd4f6 Helga Velroyen
    return _GetInstanceList(lambda: self._RunXen(["list"], hvparams),
511 58e356a9 Helga Velroyen
                            include_node)
512 65a6f9b7 Michael Hanselmann
513 58e356a9 Helga Velroyen
  def ListInstances(self, hvparams=None):
514 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
515 65a6f9b7 Michael Hanselmann

516 65a6f9b7 Michael Hanselmann
    """
517 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(False, hvparams)
518 36bebc53 Helga Velroyen
    names = [info[0] for info in instance_list]
519 65a6f9b7 Michael Hanselmann
    return names
520 65a6f9b7 Michael Hanselmann
521 0bbec3af Helga Velroyen
  def GetInstanceInfo(self, instance_name, hvparams=None):
522 65a6f9b7 Michael Hanselmann
    """Get instance properties.
523 65a6f9b7 Michael Hanselmann

524 0bbec3af Helga Velroyen
    @type instance_name: string
525 c41eea6e Iustin Pop
    @param instance_name: the instance name
526 0bbec3af Helga Velroyen
    @type hvparams: dict of strings
527 0bbec3af Helga Velroyen
    @param hvparams: the instance's hypervisor params
528 c41eea6e Iustin Pop

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

531 65a6f9b7 Michael Hanselmann
    """
532 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(instance_name == _DOM0_NAME, hvparams)
533 65a6f9b7 Michael Hanselmann
    result = None
534 36bebc53 Helga Velroyen
    for data in instance_list:
535 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
536 65a6f9b7 Michael Hanselmann
        result = data
537 65a6f9b7 Michael Hanselmann
        break
538 65a6f9b7 Michael Hanselmann
    return result
539 65a6f9b7 Michael Hanselmann
540 0200a1af Helga Velroyen
  def GetAllInstancesInfo(self, hvparams=None):
541 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
542 65a6f9b7 Michael Hanselmann

543 0200a1af Helga Velroyen
    @type hvparams: dict of strings
544 0200a1af Helga Velroyen
    @param hvparams: hypervisor parameters
545 c41eea6e Iustin Pop
    @return: list of tuples (name, id, memory, vcpus, stat, times)
546 c41eea6e Iustin Pop

547 65a6f9b7 Michael Hanselmann
    """
548 398fd4f6 Helga Velroyen
    return self._GetInstanceList(False, hvparams)
549 65a6f9b7 Michael Hanselmann
550 c3d839f5 Michael Hanselmann
  def _MakeConfigFile(self, instance, startup_memory, block_devices):
551 c3d839f5 Michael Hanselmann
    """Gather configuration details and write to disk.
552 c3d839f5 Michael Hanselmann

553 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
554 c3d839f5 Michael Hanselmann

555 c3d839f5 Michael Hanselmann
    """
556 c3d839f5 Michael Hanselmann
    buf = StringIO()
557 c3d839f5 Michael Hanselmann
    buf.write("# Automatically generated by Ganeti. Do not edit!\n")
558 c3d839f5 Michael Hanselmann
    buf.write("\n")
559 c3d839f5 Michael Hanselmann
    buf.write(self._GetConfig(instance, startup_memory, block_devices))
560 c3d839f5 Michael Hanselmann
    buf.write("\n")
561 c3d839f5 Michael Hanselmann
562 c3d839f5 Michael Hanselmann
    self._WriteConfigFile(instance.name, buf.getvalue())
563 c3d839f5 Michael Hanselmann
564 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
565 c41eea6e Iustin Pop
    """Start an instance.
566 c41eea6e Iustin Pop

567 c41eea6e Iustin Pop
    """
568 0bbec3af Helga Velroyen
    startup_memory = self._InstanceStartupMemory(instance,
569 0bbec3af Helga Velroyen
                                                 hvparams=instance.hvparams)
570 c3d839f5 Michael Hanselmann
571 c3d839f5 Michael Hanselmann
    self._MakeConfigFile(instance, startup_memory, block_devices)
572 c3d839f5 Michael Hanselmann
573 3d942d8b Michael Hanselmann
    cmd = ["create"]
574 323f9095 Stephen Shirley
    if startup_paused:
575 3d942d8b Michael Hanselmann
      cmd.append("-p")
576 3d942d8b Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
577 65a6f9b7 Michael Hanselmann
578 398fd4f6 Helga Velroyen
    result = self._RunXen(cmd, instance.hvparams)
579 65a6f9b7 Michael Hanselmann
    if result.failed:
580 48bba9de Balazs Lecz
      # Move the Xen configuration file to the log directory to avoid
581 48bba9de Balazs Lecz
      # leaving a stale config file behind.
582 48bba9de Balazs Lecz
      stashed_config = self._StashConfigFile(instance.name)
583 48bba9de Balazs Lecz
      raise errors.HypervisorError("Failed to start instance %s: %s (%s). Moved"
584 48bba9de Balazs Lecz
                                   " config file to %s" %
585 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
586 48bba9de Balazs Lecz
                                    result.output, stashed_config))
587 65a6f9b7 Michael Hanselmann
588 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
589 c41eea6e Iustin Pop
    """Stop an instance.
590 c41eea6e Iustin Pop

591 c41eea6e Iustin Pop
    """
592 bbcf7ad0 Iustin Pop
    if name is None:
593 bbcf7ad0 Iustin Pop
      name = instance.name
594 4b8b172d Michael Hanselmann
595 58e356a9 Helga Velroyen
    return self._StopInstance(name, force, instance.hvparams)
596 31da5ab5 Michael Hanselmann
597 58e356a9 Helga Velroyen
  def _StopInstance(self, name, force, hvparams):
598 31da5ab5 Michael Hanselmann
    """Stop an instance.
599 31da5ab5 Michael Hanselmann

600 58e356a9 Helga Velroyen
    @type name: string
601 58e356a9 Helga Velroyen
    @param name: name of the instance to be shutdown
602 58e356a9 Helga Velroyen
    @type force: boolean
603 58e356a9 Helga Velroyen
    @param force: flag specifying whether shutdown should be forced
604 58e356a9 Helga Velroyen
    @type hvparams: dict of string
605 58e356a9 Helga Velroyen
    @param hvparams: hypervisor parameters of the instance
606 58e356a9 Helga Velroyen

607 31da5ab5 Michael Hanselmann
    """
608 65a6f9b7 Michael Hanselmann
    if force:
609 3d942d8b Michael Hanselmann
      action = "destroy"
610 65a6f9b7 Michael Hanselmann
    else:
611 3d942d8b Michael Hanselmann
      action = "shutdown"
612 65a6f9b7 Michael Hanselmann
613 398fd4f6 Helga Velroyen
    result = self._RunXen([action, name], hvparams)
614 65a6f9b7 Michael Hanselmann
    if result.failed:
615 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
616 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
617 65a6f9b7 Michael Hanselmann
618 4b8b172d Michael Hanselmann
    # Remove configuration file if stopping/starting instance was successful
619 4b8b172d Michael Hanselmann
    self._RemoveConfigFile(name)
620 4b8b172d Michael Hanselmann
621 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
622 c41eea6e Iustin Pop
    """Reboot an instance.
623 c41eea6e Iustin Pop

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

658 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
659 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
660 2c7a0373 Guido Trotter
    @type mem: int
661 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
662 2c7a0373 Guido Trotter

663 2c7a0373 Guido Trotter
    """
664 398fd4f6 Helga Velroyen
    result = self._RunXen(["mem-set", instance.name, mem], instance.hvparams)
665 2c7a0373 Guido Trotter
    if result.failed:
666 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
667 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
668 2c7a0373 Guido Trotter
                                    result.output))
669 3d942d8b Michael Hanselmann
670 3d942d8b Michael Hanselmann
    # Update configuration file
671 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
672 0a903309 Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
673 3d942d8b Michael Hanselmann
674 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
675 2c7a0373 Guido Trotter
    if result.failed:
676 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
677 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
678 2c7a0373 Guido Trotter
                                    result.output))
679 2c7a0373 Guido Trotter
680 fac489a5 Helga Velroyen
  def GetNodeInfo(self, hvparams=None):
681 65a6f9b7 Michael Hanselmann
    """Return information about the node.
682 65a6f9b7 Michael Hanselmann

683 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
684 65a6f9b7 Michael Hanselmann

685 65a6f9b7 Michael Hanselmann
    """
686 398fd4f6 Helga Velroyen
    result = self._RunXen(["info"], hvparams)
687 65a6f9b7 Michael Hanselmann
    if result.failed:
688 2609da63 Helga Velroyen
      logging.error("Can't retrieve xen hypervisor information (%s): %s",
689 2609da63 Helga Velroyen
                    result.fail_reason, result.output)
690 65a6f9b7 Michael Hanselmann
      return None
691 65a6f9b7 Michael Hanselmann
692 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(True, hvparams)
693 fac489a5 Helga Velroyen
    return _GetNodeInfo(result.stdout, instance_list)
694 65a6f9b7 Michael Hanselmann
695 1c3231aa Thomas Thrainer
  def GetInstanceConsole(self, instance, primary_node, hvparams, beparams):
696 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
697 65a6f9b7 Michael Hanselmann

698 65a6f9b7 Michael Hanselmann
    """
699 8ef418bb Helga Velroyen
    xen_cmd = self._GetCommand(hvparams)
700 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
701 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
702 1c3231aa Thomas Thrainer
                                   host=primary_node.name,
703 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
704 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
705 8ef418bb Helga Velroyen
                                            xen_cmd, instance.name])
706 65a6f9b7 Michael Hanselmann
707 75bf3149 Helga Velroyen
  def Verify(self, hvparams=None):
708 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
709 65a6f9b7 Michael Hanselmann

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

712 75bf3149 Helga Velroyen
    @type hvparams: dict of strings
713 75bf3149 Helga Velroyen
    @param hvparams: hypervisor parameters to be verified against
714 75bf3149 Helga Velroyen

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

717 65a6f9b7 Michael Hanselmann
    """
718 75bf3149 Helga Velroyen
    if hvparams is None:
719 75bf3149 Helga Velroyen
      return "Could not verify the hypervisor, because no hvparams were" \
720 75bf3149 Helga Velroyen
             " provided."
721 75bf3149 Helga Velroyen
722 75bf3149 Helga Velroyen
    if constants.HV_XEN_CMD in hvparams:
723 75bf3149 Helga Velroyen
      xen_cmd = hvparams[constants.HV_XEN_CMD]
724 75bf3149 Helga Velroyen
      try:
725 75bf3149 Helga Velroyen
        self._CheckToolstack(xen_cmd)
726 75bf3149 Helga Velroyen
      except errors.HypervisorError:
727 75bf3149 Helga Velroyen
        return "The configured xen toolstack '%s' is not available on this" \
728 75bf3149 Helga Velroyen
               " node." % xen_cmd
729 75bf3149 Helga Velroyen
730 398fd4f6 Helga Velroyen
    result = self._RunXen(["info"], hvparams)
731 e3e66f02 Michael Hanselmann
    if result.failed:
732 75bf3149 Helga Velroyen
      return "Retrieving information from xen failed: %s, %s" % \
733 75bf3149 Helga Velroyen
        (result.fail_reason, result.output)
734 65a6f9b7 Michael Hanselmann
735 cd04dfd2 Michael Hanselmann
    return None
736 cd04dfd2 Michael Hanselmann
737 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
738 4390ccff Guido Trotter
    """Get instance information to perform a migration.
739 4390ccff Guido Trotter

740 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
741 4390ccff Guido Trotter
    @param instance: instance to be migrated
742 4390ccff Guido Trotter
    @rtype: string
743 4390ccff Guido Trotter
    @return: content of the xen config file
744 4390ccff Guido Trotter

745 4390ccff Guido Trotter
    """
746 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
747 4390ccff Guido Trotter
748 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
749 4390ccff Guido Trotter
    """Prepare to accept an instance.
750 4390ccff Guido Trotter

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

758 4390ccff Guido Trotter
    """
759 4390ccff Guido Trotter
    pass
760 4390ccff Guido Trotter
761 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
762 4390ccff Guido Trotter
    """Finalize an instance migration.
763 4390ccff Guido Trotter

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

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

774 4390ccff Guido Trotter
    """
775 4390ccff Guido Trotter
    if success:
776 c3d839f5 Michael Hanselmann
      self._WriteConfigFile(instance.name, info)
777 4390ccff Guido Trotter
778 bc0a2284 Helga Velroyen
  def MigrateInstance(self, cluster_name, instance, target, live):
779 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
780 6e7275c0 Iustin Pop

781 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
782 6e7275c0 Iustin Pop
    currently running.
783 6e7275c0 Iustin Pop

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

791 6e7275c0 Iustin Pop
    """
792 d8784f7d Michael Hanselmann
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
793 d8784f7d Michael Hanselmann
794 d8784f7d Michael Hanselmann
    return self._MigrateInstance(cluster_name, instance.name, target, port,
795 8351df2f Helga Velroyen
                                 live, instance.hvparams)
796 d8784f7d Michael Hanselmann
797 d8784f7d Michael Hanselmann
  def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
798 8351df2f Helga Velroyen
                       hvparams, _ping_fn=netutils.TcpPing):
799 d8784f7d Michael Hanselmann
    """Migrate an instance to a target node.
800 d8784f7d Michael Hanselmann

801 d8784f7d Michael Hanselmann
    @see: L{MigrateInstance} for details
802 d8784f7d Michael Hanselmann

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

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

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

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

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

873 60af751d Andrea Spadaccini
    """
874 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
875 6e7275c0 Iustin Pop
876 8ef418bb Helga Velroyen
  def PowercycleNode(self, hvparams=None):
877 f5118ade Iustin Pop
    """Xen-specific powercycle.
878 f5118ade Iustin Pop

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

886 8ef418bb Helga Velroyen
    @type hvparams: dict of strings
887 8ef418bb Helga Velroyen
    @param hvparams: hypervisor params to be used on this node
888 8ef418bb Helga Velroyen

889 f5118ade Iustin Pop
    """
890 f5118ade Iustin Pop
    try:
891 8ef418bb Helga Velroyen
      self.LinuxPowercycle()
892 f5118ade Iustin Pop
    finally:
893 8ef418bb Helga Velroyen
      xen_cmd = self._GetCommand(hvparams)
894 8ef418bb Helga Velroyen
      utils.RunCmd([xen_cmd, "debug", "R"])
895 f5118ade Iustin Pop
896 75bf3149 Helga Velroyen
  def _CheckToolstack(self, xen_cmd):
897 75bf3149 Helga Velroyen
    """Check whether the given toolstack is available on the node.
898 75bf3149 Helga Velroyen

899 75bf3149 Helga Velroyen
    @type xen_cmd: string
900 75bf3149 Helga Velroyen
    @param xen_cmd: xen command (e.g. 'xm' or 'xl')
901 75bf3149 Helga Velroyen

902 75bf3149 Helga Velroyen
    """
903 75bf3149 Helga Velroyen
    binary_found = self._CheckToolstackBinary(xen_cmd)
904 75bf3149 Helga Velroyen
    if not binary_found:
905 75bf3149 Helga Velroyen
      raise errors.HypervisorError("No '%s' binary found on node." % xen_cmd)
906 75bf3149 Helga Velroyen
    elif xen_cmd == constants.XEN_CMD_XL:
907 75bf3149 Helga Velroyen
      if not self._CheckToolstackXlConfigured():
908 75bf3149 Helga Velroyen
        raise errors.HypervisorError("Toolstack '%s' is not enabled on this"
909 75bf3149 Helga Velroyen
                                     "node." % xen_cmd)
910 75bf3149 Helga Velroyen
911 75bf3149 Helga Velroyen
  def _CheckToolstackBinary(self, xen_cmd):
912 75bf3149 Helga Velroyen
    """Checks whether the xen command's binary is found on the machine.
913 75bf3149 Helga Velroyen

914 75bf3149 Helga Velroyen
    """
915 75bf3149 Helga Velroyen
    if xen_cmd not in constants.KNOWN_XEN_COMMANDS:
916 75bf3149 Helga Velroyen
      raise errors.HypervisorError("Unknown xen command '%s'." % xen_cmd)
917 75bf3149 Helga Velroyen
    result = self._run_cmd_fn(["which", xen_cmd])
918 75bf3149 Helga Velroyen
    return not result.failed
919 75bf3149 Helga Velroyen
920 75bf3149 Helga Velroyen
  def _CheckToolstackXlConfigured(self):
921 75bf3149 Helga Velroyen
    """Checks whether xl is enabled on an xl-capable node.
922 75bf3149 Helga Velroyen

923 75bf3149 Helga Velroyen
    @rtype: bool
924 75bf3149 Helga Velroyen
    @returns: C{True} if 'xl' is enabled, C{False} otherwise
925 75bf3149 Helga Velroyen

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

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

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