Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 398fd4f6

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

345 51a95d00 Helga Velroyen
    @type hvparams: dict of strings
346 51a95d00 Helga Velroyen
    @param hvparams: hypervisor parameters
347 51a95d00 Helga Velroyen

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

365 58e356a9 Helga Velroyen
    @type hvparams: dict of strings
366 58e356a9 Helga Velroyen
    @param hvparams: dictionary of hypervisor params
367 81124130 Michael Hanselmann
    @see: L{utils.process.RunCmd}
368 3d942d8b Michael Hanselmann

369 3d942d8b Michael Hanselmann
    """
370 398fd4f6 Helga Velroyen
    cmd = [self._GetCommand(hvparams)]
371 3d942d8b Michael Hanselmann
    cmd.extend(args)
372 3d942d8b Michael Hanselmann
373 3d942d8b Michael Hanselmann
    return self._run_cmd_fn(cmd)
374 3d942d8b Michael Hanselmann
375 0a903309 Michael Hanselmann
  def _ConfigFileName(self, instance_name):
376 c2be2532 Guido Trotter
    """Get the config file name for an instance.
377 c2be2532 Guido Trotter

378 c2be2532 Guido Trotter
    @param instance_name: instance name
379 c2be2532 Guido Trotter
    @type instance_name: str
380 c2be2532 Guido Trotter
    @return: fully qualified path to instance config file
381 c2be2532 Guido Trotter
    @rtype: str
382 c2be2532 Guido Trotter

383 c2be2532 Guido Trotter
    """
384 0a903309 Michael Hanselmann
    return utils.PathJoin(self._cfgdir, instance_name)
385 c2be2532 Guido Trotter
386 5661b908 Iustin Pop
  @classmethod
387 c3d839f5 Michael Hanselmann
  def _GetConfig(cls, instance, startup_memory, block_devices):
388 c3d839f5 Michael Hanselmann
    """Build Xen configuration for an instance.
389 65a6f9b7 Michael Hanselmann

390 65a6f9b7 Michael Hanselmann
    """
391 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
392 65a6f9b7 Michael Hanselmann
393 c3d839f5 Michael Hanselmann
  def _WriteConfigFile(self, instance_name, data):
394 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
395 4390ccff Guido Trotter

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

398 4390ccff Guido Trotter
    """
399 1a63f285 Iustin Pop
    # just in case it exists
400 0a903309 Michael Hanselmann
    utils.RemoveFile(utils.PathJoin(self._cfgdir, "auto", instance_name))
401 a8e8c0c6 Michael Hanselmann
402 0a903309 Michael Hanselmann
    cfg_file = self._ConfigFileName(instance_name)
403 1a63f285 Iustin Pop
    try:
404 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
405 1a63f285 Iustin Pop
    except EnvironmentError, err:
406 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
407 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
408 4390ccff Guido Trotter
409 0a903309 Michael Hanselmann
  def _ReadConfigFile(self, instance_name):
410 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
411 4390ccff Guido Trotter

412 4390ccff Guido Trotter
    """
413 0a903309 Michael Hanselmann
    filename = self._ConfigFileName(instance_name)
414 76c364d9 Michael Hanselmann
415 4390ccff Guido Trotter
    try:
416 76c364d9 Michael Hanselmann
      file_content = utils.ReadFile(filename)
417 4390ccff Guido Trotter
    except EnvironmentError, err:
418 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
419 76c364d9 Michael Hanselmann
420 4390ccff Guido Trotter
    return file_content
421 4390ccff Guido Trotter
422 0a903309 Michael Hanselmann
  def _RemoveConfigFile(self, instance_name):
423 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
424 65a6f9b7 Michael Hanselmann

425 65a6f9b7 Michael Hanselmann
    """
426 0a903309 Michael Hanselmann
    utils.RemoveFile(self._ConfigFileName(instance_name))
427 65a6f9b7 Michael Hanselmann
428 48bba9de Balazs Lecz
  def _StashConfigFile(self, instance_name):
429 48bba9de Balazs Lecz
    """Move the Xen config file to the log directory and return its new path.
430 48bba9de Balazs Lecz

431 48bba9de Balazs Lecz
    """
432 48bba9de Balazs Lecz
    old_filename = self._ConfigFileName(instance_name)
433 48bba9de Balazs Lecz
    base = ("%s-%s" %
434 48bba9de Balazs Lecz
            (instance_name, utils.TimestampForFilename()))
435 48bba9de Balazs Lecz
    new_filename = utils.PathJoin(pathutils.LOG_XEN_DIR, base)
436 48bba9de Balazs Lecz
    utils.RenameFile(old_filename, new_filename)
437 48bba9de Balazs Lecz
    return new_filename
438 48bba9de Balazs Lecz
439 398fd4f6 Helga Velroyen
  def _GetInstanceList(self, include_node, hvparams):
440 36bebc53 Helga Velroyen
    """Wrapper around module level L{_GetInstanceList}.
441 06b78e8b Michael Hanselmann

442 398fd4f6 Helga Velroyen
    @type hvparams: dict of strings
443 398fd4f6 Helga Velroyen
    @param hvparams: hypervisor parameters to be used on this node
444 398fd4f6 Helga Velroyen

445 06b78e8b Michael Hanselmann
    """
446 398fd4f6 Helga Velroyen
    return _GetInstanceList(lambda: self._RunXen(["list"], hvparams),
447 58e356a9 Helga Velroyen
                            include_node)
448 65a6f9b7 Michael Hanselmann
449 58e356a9 Helga Velroyen
  def ListInstances(self, hvparams=None):
450 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
451 65a6f9b7 Michael Hanselmann

452 65a6f9b7 Michael Hanselmann
    """
453 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(False, hvparams)
454 36bebc53 Helga Velroyen
    names = [info[0] for info in instance_list]
455 65a6f9b7 Michael Hanselmann
    return names
456 65a6f9b7 Michael Hanselmann
457 0bbec3af Helga Velroyen
  def GetInstanceInfo(self, instance_name, hvparams=None):
458 65a6f9b7 Michael Hanselmann
    """Get instance properties.
459 65a6f9b7 Michael Hanselmann

460 0bbec3af Helga Velroyen
    @type instance_name: string
461 c41eea6e Iustin Pop
    @param instance_name: the instance name
462 0bbec3af Helga Velroyen
    @type hvparams: dict of strings
463 0bbec3af Helga Velroyen
    @param hvparams: the instance's hypervisor params
464 c41eea6e Iustin Pop

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

467 65a6f9b7 Michael Hanselmann
    """
468 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(instance_name == _DOM0_NAME, hvparams)
469 65a6f9b7 Michael Hanselmann
    result = None
470 36bebc53 Helga Velroyen
    for data in instance_list:
471 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
472 65a6f9b7 Michael Hanselmann
        result = data
473 65a6f9b7 Michael Hanselmann
        break
474 65a6f9b7 Michael Hanselmann
    return result
475 65a6f9b7 Michael Hanselmann
476 0200a1af Helga Velroyen
  def GetAllInstancesInfo(self, hvparams=None):
477 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
478 65a6f9b7 Michael Hanselmann

479 0200a1af Helga Velroyen
    @type hvparams: dict of strings
480 0200a1af Helga Velroyen
    @param hvparams: hypervisor parameters
481 c41eea6e Iustin Pop
    @return: list of tuples (name, id, memory, vcpus, stat, times)
482 c41eea6e Iustin Pop

483 65a6f9b7 Michael Hanselmann
    """
484 398fd4f6 Helga Velroyen
    return self._GetInstanceList(False, hvparams)
485 65a6f9b7 Michael Hanselmann
486 c3d839f5 Michael Hanselmann
  def _MakeConfigFile(self, instance, startup_memory, block_devices):
487 c3d839f5 Michael Hanselmann
    """Gather configuration details and write to disk.
488 c3d839f5 Michael Hanselmann

489 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
490 c3d839f5 Michael Hanselmann

491 c3d839f5 Michael Hanselmann
    """
492 c3d839f5 Michael Hanselmann
    buf = StringIO()
493 c3d839f5 Michael Hanselmann
    buf.write("# Automatically generated by Ganeti. Do not edit!\n")
494 c3d839f5 Michael Hanselmann
    buf.write("\n")
495 c3d839f5 Michael Hanselmann
    buf.write(self._GetConfig(instance, startup_memory, block_devices))
496 c3d839f5 Michael Hanselmann
    buf.write("\n")
497 c3d839f5 Michael Hanselmann
498 c3d839f5 Michael Hanselmann
    self._WriteConfigFile(instance.name, buf.getvalue())
499 c3d839f5 Michael Hanselmann
500 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
501 c41eea6e Iustin Pop
    """Start an instance.
502 c41eea6e Iustin Pop

503 c41eea6e Iustin Pop
    """
504 0bbec3af Helga Velroyen
    startup_memory = self._InstanceStartupMemory(instance,
505 0bbec3af Helga Velroyen
                                                 hvparams=instance.hvparams)
506 c3d839f5 Michael Hanselmann
507 c3d839f5 Michael Hanselmann
    self._MakeConfigFile(instance, startup_memory, block_devices)
508 c3d839f5 Michael Hanselmann
509 3d942d8b Michael Hanselmann
    cmd = ["create"]
510 323f9095 Stephen Shirley
    if startup_paused:
511 3d942d8b Michael Hanselmann
      cmd.append("-p")
512 3d942d8b Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
513 65a6f9b7 Michael Hanselmann
514 398fd4f6 Helga Velroyen
    result = self._RunXen(cmd, instance.hvparams)
515 65a6f9b7 Michael Hanselmann
    if result.failed:
516 48bba9de Balazs Lecz
      # Move the Xen configuration file to the log directory to avoid
517 48bba9de Balazs Lecz
      # leaving a stale config file behind.
518 48bba9de Balazs Lecz
      stashed_config = self._StashConfigFile(instance.name)
519 48bba9de Balazs Lecz
      raise errors.HypervisorError("Failed to start instance %s: %s (%s). Moved"
520 48bba9de Balazs Lecz
                                   " config file to %s" %
521 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
522 48bba9de Balazs Lecz
                                    result.output, stashed_config))
523 65a6f9b7 Michael Hanselmann
524 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
525 c41eea6e Iustin Pop
    """Stop an instance.
526 c41eea6e Iustin Pop

527 c41eea6e Iustin Pop
    """
528 bbcf7ad0 Iustin Pop
    if name is None:
529 bbcf7ad0 Iustin Pop
      name = instance.name
530 4b8b172d Michael Hanselmann
531 58e356a9 Helga Velroyen
    return self._StopInstance(name, force, instance.hvparams)
532 31da5ab5 Michael Hanselmann
533 58e356a9 Helga Velroyen
  def _StopInstance(self, name, force, hvparams):
534 31da5ab5 Michael Hanselmann
    """Stop an instance.
535 31da5ab5 Michael Hanselmann

536 58e356a9 Helga Velroyen
    @type name: string
537 58e356a9 Helga Velroyen
    @param name: name of the instance to be shutdown
538 58e356a9 Helga Velroyen
    @type force: boolean
539 58e356a9 Helga Velroyen
    @param force: flag specifying whether shutdown should be forced
540 58e356a9 Helga Velroyen
    @type hvparams: dict of string
541 58e356a9 Helga Velroyen
    @param hvparams: hypervisor parameters of the instance
542 58e356a9 Helga Velroyen

543 31da5ab5 Michael Hanselmann
    """
544 65a6f9b7 Michael Hanselmann
    if force:
545 3d942d8b Michael Hanselmann
      action = "destroy"
546 65a6f9b7 Michael Hanselmann
    else:
547 3d942d8b Michael Hanselmann
      action = "shutdown"
548 65a6f9b7 Michael Hanselmann
549 398fd4f6 Helga Velroyen
    result = self._RunXen([action, name], hvparams)
550 65a6f9b7 Michael Hanselmann
    if result.failed:
551 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
552 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
553 65a6f9b7 Michael Hanselmann
554 4b8b172d Michael Hanselmann
    # Remove configuration file if stopping/starting instance was successful
555 4b8b172d Michael Hanselmann
    self._RemoveConfigFile(name)
556 4b8b172d Michael Hanselmann
557 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
558 c41eea6e Iustin Pop
    """Reboot an instance.
559 c41eea6e Iustin Pop

560 c41eea6e Iustin Pop
    """
561 0bbec3af Helga Velroyen
    ini_info = self.GetInstanceInfo(instance.name, hvparams=instance.hvparams)
562 65a6f9b7 Michael Hanselmann
563 e0561198 Iustin Pop
    if ini_info is None:
564 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
565 e0561198 Iustin Pop
                                   " not running" % instance.name)
566 e0561198 Iustin Pop
567 398fd4f6 Helga Velroyen
    result = self._RunXen(["reboot", instance.name], instance.hvparams)
568 65a6f9b7 Michael Hanselmann
    if result.failed:
569 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
570 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
571 3213d3c8 Iustin Pop
                                    result.output))
572 06b78e8b Michael Hanselmann
573 06b78e8b Michael Hanselmann
    def _CheckInstance():
574 0bbec3af Helga Velroyen
      new_info = self.GetInstanceInfo(instance.name, hvparams=instance.hvparams)
575 06b78e8b Michael Hanselmann
576 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
577 e0561198 Iustin Pop
      if (new_info is not None and
578 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
579 06b78e8b Michael Hanselmann
        return
580 7dd106d3 Iustin Pop
581 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
582 06b78e8b Michael Hanselmann
583 06b78e8b Michael Hanselmann
    try:
584 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
585 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
586 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
587 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
588 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
589 7dd106d3 Iustin Pop
                                   (instance.name, ))
590 65a6f9b7 Michael Hanselmann
591 2c7a0373 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
592 2c7a0373 Guido Trotter
    """Balloon an instance memory to a certain value.
593 2c7a0373 Guido Trotter

594 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
595 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
596 2c7a0373 Guido Trotter
    @type mem: int
597 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
598 2c7a0373 Guido Trotter

599 2c7a0373 Guido Trotter
    """
600 398fd4f6 Helga Velroyen
    result = self._RunXen(["mem-set", instance.name, mem], instance.hvparams)
601 2c7a0373 Guido Trotter
    if result.failed:
602 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
603 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
604 2c7a0373 Guido Trotter
                                    result.output))
605 3d942d8b Michael Hanselmann
606 3d942d8b Michael Hanselmann
    # Update configuration file
607 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
608 0a903309 Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
609 3d942d8b Michael Hanselmann
610 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
611 2c7a0373 Guido Trotter
    if result.failed:
612 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
613 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
614 2c7a0373 Guido Trotter
                                    result.output))
615 2c7a0373 Guido Trotter
616 fac489a5 Helga Velroyen
  def GetNodeInfo(self, hvparams=None):
617 65a6f9b7 Michael Hanselmann
    """Return information about the node.
618 65a6f9b7 Michael Hanselmann

619 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
620 65a6f9b7 Michael Hanselmann

621 65a6f9b7 Michael Hanselmann
    """
622 398fd4f6 Helga Velroyen
    result = self._RunXen(["info"], hvparams)
623 65a6f9b7 Michael Hanselmann
    if result.failed:
624 2609da63 Helga Velroyen
      logging.error("Can't retrieve xen hypervisor information (%s): %s",
625 2609da63 Helga Velroyen
                    result.fail_reason, result.output)
626 65a6f9b7 Michael Hanselmann
      return None
627 65a6f9b7 Michael Hanselmann
628 398fd4f6 Helga Velroyen
    instance_list = self._GetInstanceList(True, hvparams)
629 fac489a5 Helga Velroyen
    return _GetNodeInfo(result.stdout, instance_list)
630 65a6f9b7 Michael Hanselmann
631 637ce7f9 Guido Trotter
  @classmethod
632 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
633 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
634 65a6f9b7 Michael Hanselmann

635 65a6f9b7 Michael Hanselmann
    """
636 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
637 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
638 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
639 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
640 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
641 1f5557ca Guido Trotter
                                            constants.XEN_CMD, instance.name])
642 65a6f9b7 Michael Hanselmann
643 75bf3149 Helga Velroyen
  def Verify(self, hvparams=None):
644 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
645 65a6f9b7 Michael Hanselmann

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

648 75bf3149 Helga Velroyen
    @type hvparams: dict of strings
649 75bf3149 Helga Velroyen
    @param hvparams: hypervisor parameters to be verified against
650 75bf3149 Helga Velroyen

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

653 65a6f9b7 Michael Hanselmann
    """
654 75bf3149 Helga Velroyen
    if hvparams is None:
655 75bf3149 Helga Velroyen
      return "Could not verify the hypervisor, because no hvparams were" \
656 75bf3149 Helga Velroyen
             " provided."
657 75bf3149 Helga Velroyen
658 75bf3149 Helga Velroyen
    if constants.HV_XEN_CMD in hvparams:
659 75bf3149 Helga Velroyen
      xen_cmd = hvparams[constants.HV_XEN_CMD]
660 75bf3149 Helga Velroyen
      try:
661 75bf3149 Helga Velroyen
        self._CheckToolstack(xen_cmd)
662 75bf3149 Helga Velroyen
      except errors.HypervisorError:
663 75bf3149 Helga Velroyen
        return "The configured xen toolstack '%s' is not available on this" \
664 75bf3149 Helga Velroyen
               " node." % xen_cmd
665 75bf3149 Helga Velroyen
666 398fd4f6 Helga Velroyen
    result = self._RunXen(["info"], hvparams)
667 e3e66f02 Michael Hanselmann
    if result.failed:
668 75bf3149 Helga Velroyen
      return "Retrieving information from xen failed: %s, %s" % \
669 75bf3149 Helga Velroyen
        (result.fail_reason, result.output)
670 65a6f9b7 Michael Hanselmann
671 cd04dfd2 Michael Hanselmann
    return None
672 cd04dfd2 Michael Hanselmann
673 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
674 4390ccff Guido Trotter
    """Get instance information to perform a migration.
675 4390ccff Guido Trotter

676 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
677 4390ccff Guido Trotter
    @param instance: instance to be migrated
678 4390ccff Guido Trotter
    @rtype: string
679 4390ccff Guido Trotter
    @return: content of the xen config file
680 4390ccff Guido Trotter

681 4390ccff Guido Trotter
    """
682 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
683 4390ccff Guido Trotter
684 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
685 4390ccff Guido Trotter
    """Prepare to accept an instance.
686 4390ccff Guido Trotter

687 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
688 4390ccff Guido Trotter
    @param instance: instance to be accepted
689 4390ccff Guido Trotter
    @type info: string
690 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
691 4390ccff Guido Trotter
    @type target: string
692 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
693 4390ccff Guido Trotter

694 4390ccff Guido Trotter
    """
695 4390ccff Guido Trotter
    pass
696 4390ccff Guido Trotter
697 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
698 4390ccff Guido Trotter
    """Finalize an instance migration.
699 4390ccff Guido Trotter

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

703 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
704 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
705 4390ccff Guido Trotter
    @type info: string
706 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
707 4390ccff Guido Trotter
    @type success: boolean
708 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
709 4390ccff Guido Trotter

710 4390ccff Guido Trotter
    """
711 4390ccff Guido Trotter
    if success:
712 c3d839f5 Michael Hanselmann
      self._WriteConfigFile(instance.name, info)
713 4390ccff Guido Trotter
714 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
715 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
716 6e7275c0 Iustin Pop

717 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
718 6e7275c0 Iustin Pop
    currently running.
719 6e7275c0 Iustin Pop

720 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
721 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
722 fdf7f055 Guido Trotter
    @type target: string
723 fdf7f055 Guido Trotter
    @param target: ip address of the target node
724 fdf7f055 Guido Trotter
    @type live: boolean
725 fdf7f055 Guido Trotter
    @param live: perform a live migration
726 fdf7f055 Guido Trotter

727 6e7275c0 Iustin Pop
    """
728 d8784f7d Michael Hanselmann
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
729 d8784f7d Michael Hanselmann
730 d8784f7d Michael Hanselmann
    # TODO: Pass cluster name via RPC
731 d8784f7d Michael Hanselmann
    cluster_name = ssconf.SimpleStore().GetClusterName()
732 d8784f7d Michael Hanselmann
733 d8784f7d Michael Hanselmann
    return self._MigrateInstance(cluster_name, instance.name, target, port,
734 8351df2f Helga Velroyen
                                 live, instance.hvparams)
735 d8784f7d Michael Hanselmann
736 d8784f7d Michael Hanselmann
  def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
737 8351df2f Helga Velroyen
                       hvparams, _ping_fn=netutils.TcpPing):
738 d8784f7d Michael Hanselmann
    """Migrate an instance to a target node.
739 d8784f7d Michael Hanselmann

740 d8784f7d Michael Hanselmann
    @see: L{MigrateInstance} for details
741 d8784f7d Michael Hanselmann

742 d8784f7d Michael Hanselmann
    """
743 8351df2f Helga Velroyen
    if hvparams is None:
744 8351df2f Helga Velroyen
      raise errors.HypervisorError("No hvparams provided.")
745 8351df2f Helga Velroyen
746 8351df2f Helga Velroyen
    if self.GetInstanceInfo(instance_name, hvparams=hvparams) is None:
747 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
748 50716be0 Iustin Pop
749 398fd4f6 Helga Velroyen
    cmd = self._GetCommand(hvparams)
750 50716be0 Iustin Pop
751 d8784f7d Michael Hanselmann
    if (cmd == constants.XEN_CMD_XM and
752 d8784f7d Michael Hanselmann
        not _ping_fn(target, port, live_port_needed=True)):
753 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
754 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
755 50716be0 Iustin Pop
756 3d942d8b Michael Hanselmann
    args = ["migrate"]
757 3d942d8b Michael Hanselmann
758 d8784f7d Michael Hanselmann
    if cmd == constants.XEN_CMD_XM:
759 0625d08f René Nussbaumer
      args.extend(["-p", "%d" % port])
760 0625d08f René Nussbaumer
      if live:
761 0625d08f René Nussbaumer
        args.append("-l")
762 3d942d8b Michael Hanselmann
763 d8784f7d Michael Hanselmann
    elif cmd == constants.XEN_CMD_XL:
764 d8784f7d Michael Hanselmann
      args.extend([
765 d8784f7d Michael Hanselmann
        "-s", constants.XL_SSH_CMD % cluster_name,
766 d8784f7d Michael Hanselmann
        "-C", self._ConfigFileName(instance_name),
767 d8784f7d Michael Hanselmann
        ])
768 3d942d8b Michael Hanselmann
769 0625d08f René Nussbaumer
    else:
770 d8784f7d Michael Hanselmann
      raise errors.HypervisorError("Unsupported Xen command: %s" % self._cmd)
771 0625d08f René Nussbaumer
772 d8784f7d Michael Hanselmann
    args.extend([instance_name, target])
773 3d942d8b Michael Hanselmann
774 398fd4f6 Helga Velroyen
    result = self._RunXen(args, hvparams)
775 6e7275c0 Iustin Pop
    if result.failed:
776 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
777 d8784f7d Michael Hanselmann
                                   (instance_name, result.output))
778 60af751d Andrea Spadaccini
779 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
780 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
781 60af751d Andrea Spadaccini

782 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
783 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
784 60af751d Andrea Spadaccini
    @type success: bool
785 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
786 60af751d Andrea Spadaccini
    @type live: bool
787 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
788 60af751d Andrea Spadaccini

789 60af751d Andrea Spadaccini
    """
790 60af751d Andrea Spadaccini
    # pylint: disable=W0613
791 60af751d Andrea Spadaccini
    if success:
792 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
793 60af751d Andrea Spadaccini
      try:
794 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
795 60af751d Andrea Spadaccini
      except EnvironmentError:
796 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
797 60af751d Andrea Spadaccini
798 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
799 60af751d Andrea Spadaccini
    """Get the migration status
800 60af751d Andrea Spadaccini

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

805 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
806 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
807 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
808 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
809 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
810 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
811 60af751d Andrea Spadaccini

812 60af751d Andrea Spadaccini
    """
813 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
814 6e7275c0 Iustin Pop
815 f5118ade Iustin Pop
  @classmethod
816 f5118ade Iustin Pop
  def PowercycleNode(cls):
817 f5118ade Iustin Pop
    """Xen-specific powercycle.
818 f5118ade Iustin Pop

819 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
820 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
821 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
822 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
823 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
824 f5118ade Iustin Pop
    daemon is not working.
825 f5118ade Iustin Pop

826 f5118ade Iustin Pop
    """
827 f5118ade Iustin Pop
    try:
828 f5118ade Iustin Pop
      cls.LinuxPowercycle()
829 f5118ade Iustin Pop
    finally:
830 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
831 f5118ade Iustin Pop
832 75bf3149 Helga Velroyen
  def _CheckToolstack(self, xen_cmd):
833 75bf3149 Helga Velroyen
    """Check whether the given toolstack is available on the node.
834 75bf3149 Helga Velroyen

835 75bf3149 Helga Velroyen
    @type xen_cmd: string
836 75bf3149 Helga Velroyen
    @param xen_cmd: xen command (e.g. 'xm' or 'xl')
837 75bf3149 Helga Velroyen

838 75bf3149 Helga Velroyen
    """
839 75bf3149 Helga Velroyen
    binary_found = self._CheckToolstackBinary(xen_cmd)
840 75bf3149 Helga Velroyen
    if not binary_found:
841 75bf3149 Helga Velroyen
      raise errors.HypervisorError("No '%s' binary found on node." % xen_cmd)
842 75bf3149 Helga Velroyen
    elif xen_cmd == constants.XEN_CMD_XL:
843 75bf3149 Helga Velroyen
      if not self._CheckToolstackXlConfigured():
844 75bf3149 Helga Velroyen
        raise errors.HypervisorError("Toolstack '%s' is not enabled on this"
845 75bf3149 Helga Velroyen
                                     "node." % xen_cmd)
846 75bf3149 Helga Velroyen
847 75bf3149 Helga Velroyen
  def _CheckToolstackBinary(self, xen_cmd):
848 75bf3149 Helga Velroyen
    """Checks whether the xen command's binary is found on the machine.
849 75bf3149 Helga Velroyen

850 75bf3149 Helga Velroyen
    """
851 75bf3149 Helga Velroyen
    if xen_cmd not in constants.KNOWN_XEN_COMMANDS:
852 75bf3149 Helga Velroyen
      raise errors.HypervisorError("Unknown xen command '%s'." % xen_cmd)
853 75bf3149 Helga Velroyen
    result = self._run_cmd_fn(["which", xen_cmd])
854 75bf3149 Helga Velroyen
    return not result.failed
855 75bf3149 Helga Velroyen
856 75bf3149 Helga Velroyen
  def _CheckToolstackXlConfigured(self):
857 75bf3149 Helga Velroyen
    """Checks whether xl is enabled on an xl-capable node.
858 75bf3149 Helga Velroyen

859 75bf3149 Helga Velroyen
    @rtype: bool
860 75bf3149 Helga Velroyen
    @returns: C{True} if 'xl' is enabled, C{False} otherwise
861 75bf3149 Helga Velroyen

862 75bf3149 Helga Velroyen
    """
863 75bf3149 Helga Velroyen
    result = self._run_cmd_fn([constants.XEN_CMD_XL, "help"])
864 75bf3149 Helga Velroyen
    if not result.failed:
865 75bf3149 Helga Velroyen
      return True
866 75bf3149 Helga Velroyen
    elif result.failed:
867 75bf3149 Helga Velroyen
      if "toolstack" in result.stderr:
868 75bf3149 Helga Velroyen
        return False
869 75bf3149 Helga Velroyen
      # xl fails for some other reason than the toolstack
870 75bf3149 Helga Velroyen
      else:
871 75bf3149 Helga Velroyen
        raise errors.HypervisorError("Cannot run xen ('%s'). Error: %s."
872 75bf3149 Helga Velroyen
                                     % (constants.XEN_CMD_XL, result.stderr))
873 75bf3149 Helga Velroyen
874 65a6f9b7 Michael Hanselmann
875 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
876 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
877 65a6f9b7 Michael Hanselmann
878 205ab586 Iustin Pop
  PARAMETERS = {
879 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
880 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
881 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
882 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
883 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
884 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
885 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
886 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
887 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
888 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
889 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
890 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
891 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
892 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
893 2c368f28 Guido Trotter
    constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
894 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
895 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
896 740394bc Helga Velroyen
    constants.HV_XEN_CMD:
897 740394bc Helga Velroyen
      hv_base.ParamInSet(True, constants.KNOWN_XEN_COMMANDS),
898 205ab586 Iustin Pop
    }
899 f48148c3 Iustin Pop
900 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
901 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
902 65a6f9b7 Michael Hanselmann

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

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