Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ fac489a5

History | View | Annotate | Download (36.9 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 51a95d00 Helga Velroyen
  def _GetCommand(self, hvparams=None):
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 51a95d00 Helga Velroyen
      if hvparams is not None:
351 51a95d00 Helga Velroyen
        cmd = hvparams[constants.HV_XEN_CMD]
352 51a95d00 Helga Velroyen
      else:
353 51a95d00 Helga Velroyen
        # TODO: Remove autoconf option once retrieving the command from
354 51a95d00 Helga Velroyen
        # the hvparams is fully implemented.
355 51a95d00 Helga Velroyen
        cmd = constants.XEN_CMD
356 3d942d8b Michael Hanselmann
    else:
357 3d942d8b Michael Hanselmann
      cmd = self._cmd
358 3d942d8b Michael Hanselmann
359 3d942d8b Michael Hanselmann
    if cmd not in constants.KNOWN_XEN_COMMANDS:
360 3d942d8b Michael Hanselmann
      raise errors.ProgrammerError("Unknown Xen command '%s'" % cmd)
361 3d942d8b Michael Hanselmann
362 3d942d8b Michael Hanselmann
    return cmd
363 3d942d8b Michael Hanselmann
364 58e356a9 Helga Velroyen
  def _RunXen(self, args, hvparams=None):
365 81124130 Michael Hanselmann
    """Wrapper around L{utils.process.RunCmd} to run Xen command.
366 3d942d8b Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

459 c41eea6e Iustin Pop
    @param instance_name: the instance name
460 c41eea6e Iustin Pop

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

463 65a6f9b7 Michael Hanselmann
    """
464 36bebc53 Helga Velroyen
    instance_list = self._GetInstanceList(instance_name == _DOM0_NAME)
465 65a6f9b7 Michael Hanselmann
    result = None
466 36bebc53 Helga Velroyen
    for data in instance_list:
467 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
468 65a6f9b7 Michael Hanselmann
        result = data
469 65a6f9b7 Michael Hanselmann
        break
470 65a6f9b7 Michael Hanselmann
    return result
471 65a6f9b7 Michael Hanselmann
472 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
473 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
474 65a6f9b7 Michael Hanselmann

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

477 65a6f9b7 Michael Hanselmann
    """
478 36bebc53 Helga Velroyen
    return self._GetInstanceList(False)
479 65a6f9b7 Michael Hanselmann
480 c3d839f5 Michael Hanselmann
  def _MakeConfigFile(self, instance, startup_memory, block_devices):
481 c3d839f5 Michael Hanselmann
    """Gather configuration details and write to disk.
482 c3d839f5 Michael Hanselmann

483 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
484 c3d839f5 Michael Hanselmann

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

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

520 c41eea6e Iustin Pop
    """
521 bbcf7ad0 Iustin Pop
    if name is None:
522 bbcf7ad0 Iustin Pop
      name = instance.name
523 4b8b172d Michael Hanselmann
524 58e356a9 Helga Velroyen
    return self._StopInstance(name, force, instance.hvparams)
525 31da5ab5 Michael Hanselmann
526 58e356a9 Helga Velroyen
  def _StopInstance(self, name, force, hvparams):
527 31da5ab5 Michael Hanselmann
    """Stop an instance.
528 31da5ab5 Michael Hanselmann

529 58e356a9 Helga Velroyen
    @type name: string
530 58e356a9 Helga Velroyen
    @param name: name of the instance to be shutdown
531 58e356a9 Helga Velroyen
    @type force: boolean
532 58e356a9 Helga Velroyen
    @param force: flag specifying whether shutdown should be forced
533 58e356a9 Helga Velroyen
    @type hvparams: dict of string
534 58e356a9 Helga Velroyen
    @param hvparams: hypervisor parameters of the instance
535 58e356a9 Helga Velroyen

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

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

587 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
588 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
589 2c7a0373 Guido Trotter
    @type mem: int
590 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
591 2c7a0373 Guido Trotter

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

613 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
614 65a6f9b7 Michael Hanselmann

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

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

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

642 75bf3149 Helga Velroyen
    @type hvparams: dict of strings
643 75bf3149 Helga Velroyen
    @param hvparams: hypervisor parameters to be verified against
644 75bf3149 Helga Velroyen

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

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

670 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
671 4390ccff Guido Trotter
    @param instance: instance to be migrated
672 4390ccff Guido Trotter
    @rtype: string
673 4390ccff Guido Trotter
    @return: content of the xen config file
674 4390ccff Guido Trotter

675 4390ccff Guido Trotter
    """
676 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
677 4390ccff Guido Trotter
678 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
679 4390ccff Guido Trotter
    """Prepare to accept an instance.
680 4390ccff Guido Trotter

681 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
682 4390ccff Guido Trotter
    @param instance: instance to be accepted
683 4390ccff Guido Trotter
    @type info: string
684 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
685 4390ccff Guido Trotter
    @type target: string
686 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
687 4390ccff Guido Trotter

688 4390ccff Guido Trotter
    """
689 4390ccff Guido Trotter
    pass
690 4390ccff Guido Trotter
691 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
692 4390ccff Guido Trotter
    """Finalize an instance migration.
693 4390ccff Guido Trotter

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

697 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
698 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
699 4390ccff Guido Trotter
    @type info: string
700 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
701 4390ccff Guido Trotter
    @type success: boolean
702 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
703 4390ccff Guido Trotter

704 4390ccff Guido Trotter
    """
705 4390ccff Guido Trotter
    if success:
706 c3d839f5 Michael Hanselmann
      self._WriteConfigFile(instance.name, info)
707 4390ccff Guido Trotter
708 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
709 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
710 6e7275c0 Iustin Pop

711 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
712 6e7275c0 Iustin Pop
    currently running.
713 6e7275c0 Iustin Pop

714 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
715 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
716 fdf7f055 Guido Trotter
    @type target: string
717 fdf7f055 Guido Trotter
    @param target: ip address of the target node
718 fdf7f055 Guido Trotter
    @type live: boolean
719 fdf7f055 Guido Trotter
    @param live: perform a live migration
720 fdf7f055 Guido Trotter

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

734 d8784f7d Michael Hanselmann
    @see: L{MigrateInstance} for details
735 d8784f7d Michael Hanselmann

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

776 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
777 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
778 60af751d Andrea Spadaccini
    @type success: bool
779 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
780 60af751d Andrea Spadaccini
    @type live: bool
781 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
782 60af751d Andrea Spadaccini

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

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

799 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
800 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
801 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
802 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
803 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
804 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
805 60af751d Andrea Spadaccini

806 60af751d Andrea Spadaccini
    """
807 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
808 6e7275c0 Iustin Pop
809 f5118ade Iustin Pop
  @classmethod
810 f5118ade Iustin Pop
  def PowercycleNode(cls):
811 f5118ade Iustin Pop
    """Xen-specific powercycle.
812 f5118ade Iustin Pop

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

820 f5118ade Iustin Pop
    """
821 f5118ade Iustin Pop
    try:
822 f5118ade Iustin Pop
      cls.LinuxPowercycle()
823 f5118ade Iustin Pop
    finally:
824 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
825 f5118ade Iustin Pop
826 75bf3149 Helga Velroyen
  def _CheckToolstack(self, xen_cmd):
827 75bf3149 Helga Velroyen
    """Check whether the given toolstack is available on the node.
828 75bf3149 Helga Velroyen

829 75bf3149 Helga Velroyen
    @type xen_cmd: string
830 75bf3149 Helga Velroyen
    @param xen_cmd: xen command (e.g. 'xm' or 'xl')
831 75bf3149 Helga Velroyen

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

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

853 75bf3149 Helga Velroyen
    @rtype: bool
854 75bf3149 Helga Velroyen
    @returns: C{True} if 'xl' is enabled, C{False} otherwise
855 75bf3149 Helga Velroyen

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

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

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