Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 8a534fbe

History | View | Annotate | Download (33.1 kB)

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

24 65a6f9b7 Michael Hanselmann
"""
25 65a6f9b7 Michael Hanselmann
26 b48909c8 Iustin Pop
import logging
27 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 b255379d Michael Hanselmann
def _RunXmList(fn, xmllist_errors):
86 b255379d Michael Hanselmann
  """Helper function for L{_GetXmList} to run "xm list".
87 b255379d Michael Hanselmann

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

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

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

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

147 b255379d Michael Hanselmann
  See L{_RunXmList} and L{_ParseXmList} for parameter details.
148 b255379d Michael Hanselmann

149 b255379d Michael Hanselmann
  """
150 b255379d Michael Hanselmann
  xmllist_errors = []
151 b255379d Michael Hanselmann
  try:
152 b255379d Michael Hanselmann
    lines = utils.Retry(_RunXmList, (0.3, 1.5, 1.0), _timeout,
153 b255379d Michael Hanselmann
                        args=(fn, xmllist_errors))
154 b255379d Michael Hanselmann
  except utils.RetryTimeout:
155 b255379d Michael Hanselmann
    if xmllist_errors:
156 b255379d Michael Hanselmann
      xmlist_result = xmllist_errors.pop()
157 b255379d Michael Hanselmann
158 b255379d Michael Hanselmann
      errmsg = ("xm list failed, timeout exceeded (%s): %s" %
159 b255379d Michael Hanselmann
                (xmlist_result.fail_reason, xmlist_result.output))
160 b255379d Michael Hanselmann
    else:
161 b255379d Michael Hanselmann
      errmsg = "xm list failed"
162 b255379d Michael Hanselmann
163 b255379d Michael Hanselmann
    raise errors.HypervisorError(errmsg)
164 b255379d Michael Hanselmann
165 b255379d Michael Hanselmann
  return _ParseXmList(lines, include_node)
166 b255379d Michael Hanselmann
167 b255379d Michael Hanselmann
168 06c9a520 Michael Hanselmann
def _ParseNodeInfo(info):
169 06c9a520 Michael Hanselmann
  """Return information about the node.
170 06c9a520 Michael Hanselmann

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

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

230 06c9a520 Michael Hanselmann
  @type info: dict
231 06c9a520 Michael Hanselmann
  @param info: Result from L{_ParseNodeInfo}
232 06c9a520 Michael Hanselmann
  @type fn: callable
233 06c9a520 Michael Hanselmann
  @param fn: Function returning result of running C{xm list}
234 06c9a520 Michael Hanselmann
  @rtype: dict
235 06c9a520 Michael Hanselmann

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

260 06c9a520 Michael Hanselmann
  """
261 06c9a520 Michael Hanselmann
  return _MergeInstanceInfo(_ParseNodeInfo(info), fn)
262 06c9a520 Michael Hanselmann
263 06c9a520 Michael Hanselmann
264 d0bb3f24 Michael Hanselmann
def _GetConfigFileDiskData(block_devices, blockdev_prefix,
265 d0bb3f24 Michael Hanselmann
                           _letters=_DISK_LETTERS):
266 d0bb3f24 Michael Hanselmann
  """Get disk directives for Xen config file.
267 d0bb3f24 Michael Hanselmann

268 d0bb3f24 Michael Hanselmann
  This method builds the xen config disk directive according to the
269 d0bb3f24 Michael Hanselmann
  given disk_template and block_devices.
270 d0bb3f24 Michael Hanselmann

271 d0bb3f24 Michael Hanselmann
  @param block_devices: list of tuples (cfdev, rldev):
272 d0bb3f24 Michael Hanselmann
      - cfdev: dict containing ganeti config disk part
273 d0bb3f24 Michael Hanselmann
      - rldev: ganeti.bdev.BlockDev object
274 d0bb3f24 Michael Hanselmann
  @param blockdev_prefix: a string containing blockdevice prefix,
275 d0bb3f24 Michael Hanselmann
                          e.g. "sd" for /dev/sda
276 d0bb3f24 Michael Hanselmann

277 d0bb3f24 Michael Hanselmann
  @return: string containing disk directive for xen instance config file
278 d0bb3f24 Michael Hanselmann

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

306 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
307 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
308 65a6f9b7 Michael Hanselmann

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

341 d8784f7d Michael Hanselmann
    """
342 3d942d8b Michael Hanselmann
    if self._cmd is None:
343 3d942d8b Michael Hanselmann
      # TODO: Make command a hypervisor parameter
344 3d942d8b Michael Hanselmann
      cmd = constants.XEN_CMD
345 3d942d8b Michael Hanselmann
    else:
346 3d942d8b Michael Hanselmann
      cmd = self._cmd
347 3d942d8b Michael Hanselmann
348 3d942d8b Michael Hanselmann
    if cmd not in constants.KNOWN_XEN_COMMANDS:
349 3d942d8b Michael Hanselmann
      raise errors.ProgrammerError("Unknown Xen command '%s'" % cmd)
350 3d942d8b Michael Hanselmann
351 3d942d8b Michael Hanselmann
    return cmd
352 3d942d8b Michael Hanselmann
353 3d942d8b Michael Hanselmann
  def _RunXen(self, args):
354 81124130 Michael Hanselmann
    """Wrapper around L{utils.process.RunCmd} to run Xen command.
355 3d942d8b Michael Hanselmann

356 81124130 Michael Hanselmann
    @see: L{utils.process.RunCmd}
357 3d942d8b Michael Hanselmann

358 3d942d8b Michael Hanselmann
    """
359 3d942d8b Michael Hanselmann
    cmd = [self._GetCommand()]
360 3d942d8b Michael Hanselmann
    cmd.extend(args)
361 3d942d8b Michael Hanselmann
362 3d942d8b Michael Hanselmann
    return self._run_cmd_fn(cmd)
363 3d942d8b Michael Hanselmann
364 0a903309 Michael Hanselmann
  def _ConfigFileName(self, instance_name):
365 c2be2532 Guido Trotter
    """Get the config file name for an instance.
366 c2be2532 Guido Trotter

367 c2be2532 Guido Trotter
    @param instance_name: instance name
368 c2be2532 Guido Trotter
    @type instance_name: str
369 c2be2532 Guido Trotter
    @return: fully qualified path to instance config file
370 c2be2532 Guido Trotter
    @rtype: str
371 c2be2532 Guido Trotter

372 c2be2532 Guido Trotter
    """
373 0a903309 Michael Hanselmann
    return utils.PathJoin(self._cfgdir, instance_name)
374 c2be2532 Guido Trotter
375 5661b908 Iustin Pop
  @classmethod
376 c3d839f5 Michael Hanselmann
  def _GetConfig(cls, instance, startup_memory, block_devices):
377 c3d839f5 Michael Hanselmann
    """Build Xen configuration for an instance.
378 65a6f9b7 Michael Hanselmann

379 65a6f9b7 Michael Hanselmann
    """
380 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
381 65a6f9b7 Michael Hanselmann
382 c3d839f5 Michael Hanselmann
  def _WriteConfigFile(self, instance_name, data):
383 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
384 4390ccff Guido Trotter

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

387 4390ccff Guido Trotter
    """
388 1a63f285 Iustin Pop
    # just in case it exists
389 0a903309 Michael Hanselmann
    utils.RemoveFile(utils.PathJoin(self._cfgdir, "auto", instance_name))
390 a8e8c0c6 Michael Hanselmann
391 0a903309 Michael Hanselmann
    cfg_file = self._ConfigFileName(instance_name)
392 1a63f285 Iustin Pop
    try:
393 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
394 1a63f285 Iustin Pop
    except EnvironmentError, err:
395 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
396 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
397 4390ccff Guido Trotter
398 0a903309 Michael Hanselmann
  def _ReadConfigFile(self, instance_name):
399 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
400 4390ccff Guido Trotter

401 4390ccff Guido Trotter
    """
402 0a903309 Michael Hanselmann
    filename = self._ConfigFileName(instance_name)
403 76c364d9 Michael Hanselmann
404 4390ccff Guido Trotter
    try:
405 76c364d9 Michael Hanselmann
      file_content = utils.ReadFile(filename)
406 4390ccff Guido Trotter
    except EnvironmentError, err:
407 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
408 76c364d9 Michael Hanselmann
409 4390ccff Guido Trotter
    return file_content
410 4390ccff Guido Trotter
411 0a903309 Michael Hanselmann
  def _RemoveConfigFile(self, instance_name):
412 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
413 65a6f9b7 Michael Hanselmann

414 65a6f9b7 Michael Hanselmann
    """
415 0a903309 Michael Hanselmann
    utils.RemoveFile(self._ConfigFileName(instance_name))
416 65a6f9b7 Michael Hanselmann
417 48bba9de Balazs Lecz
  def _StashConfigFile(self, instance_name):
418 48bba9de Balazs Lecz
    """Move the Xen config file to the log directory and return its new path.
419 48bba9de Balazs Lecz

420 48bba9de Balazs Lecz
    """
421 48bba9de Balazs Lecz
    old_filename = self._ConfigFileName(instance_name)
422 48bba9de Balazs Lecz
    base = ("%s-%s" %
423 48bba9de Balazs Lecz
            (instance_name, utils.TimestampForFilename()))
424 48bba9de Balazs Lecz
    new_filename = utils.PathJoin(pathutils.LOG_XEN_DIR, base)
425 48bba9de Balazs Lecz
    utils.RenameFile(old_filename, new_filename)
426 48bba9de Balazs Lecz
    return new_filename
427 48bba9de Balazs Lecz
428 3d942d8b Michael Hanselmann
  def _GetXmList(self, include_node):
429 b255379d Michael Hanselmann
    """Wrapper around module level L{_GetXmList}.
430 06b78e8b Michael Hanselmann

431 06b78e8b Michael Hanselmann
    """
432 3d942d8b Michael Hanselmann
    return _GetXmList(lambda: self._RunXen(["list"]), include_node)
433 65a6f9b7 Michael Hanselmann
434 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
435 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
436 65a6f9b7 Michael Hanselmann

437 65a6f9b7 Michael Hanselmann
    """
438 b255379d Michael Hanselmann
    xm_list = self._GetXmList(False)
439 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
440 65a6f9b7 Michael Hanselmann
    return names
441 65a6f9b7 Michael Hanselmann
442 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
443 65a6f9b7 Michael Hanselmann
    """Get instance properties.
444 65a6f9b7 Michael Hanselmann

445 c41eea6e Iustin Pop
    @param instance_name: the instance name
446 c41eea6e Iustin Pop

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

449 65a6f9b7 Michael Hanselmann
    """
450 b255379d Michael Hanselmann
    xm_list = self._GetXmList(instance_name == _DOM0_NAME)
451 65a6f9b7 Michael Hanselmann
    result = None
452 65a6f9b7 Michael Hanselmann
    for data in xm_list:
453 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
454 65a6f9b7 Michael Hanselmann
        result = data
455 65a6f9b7 Michael Hanselmann
        break
456 65a6f9b7 Michael Hanselmann
    return result
457 65a6f9b7 Michael Hanselmann
458 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
459 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
460 65a6f9b7 Michael Hanselmann

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

463 65a6f9b7 Michael Hanselmann
    """
464 b255379d Michael Hanselmann
    xm_list = self._GetXmList(False)
465 65a6f9b7 Michael Hanselmann
    return xm_list
466 65a6f9b7 Michael Hanselmann
467 c3d839f5 Michael Hanselmann
  def _MakeConfigFile(self, instance, startup_memory, block_devices):
468 c3d839f5 Michael Hanselmann
    """Gather configuration details and write to disk.
469 c3d839f5 Michael Hanselmann

470 c3d839f5 Michael Hanselmann
    See L{_GetConfig} for arguments.
471 c3d839f5 Michael Hanselmann

472 c3d839f5 Michael Hanselmann
    """
473 c3d839f5 Michael Hanselmann
    buf = StringIO()
474 c3d839f5 Michael Hanselmann
    buf.write("# Automatically generated by Ganeti. Do not edit!\n")
475 c3d839f5 Michael Hanselmann
    buf.write("\n")
476 c3d839f5 Michael Hanselmann
    buf.write(self._GetConfig(instance, startup_memory, block_devices))
477 c3d839f5 Michael Hanselmann
    buf.write("\n")
478 c3d839f5 Michael Hanselmann
479 c3d839f5 Michael Hanselmann
    self._WriteConfigFile(instance.name, buf.getvalue())
480 c3d839f5 Michael Hanselmann
481 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
482 c41eea6e Iustin Pop
    """Start an instance.
483 c41eea6e Iustin Pop

484 c41eea6e Iustin Pop
    """
485 61eb1a46 Guido Trotter
    startup_memory = self._InstanceStartupMemory(instance)
486 c3d839f5 Michael Hanselmann
487 c3d839f5 Michael Hanselmann
    self._MakeConfigFile(instance, startup_memory, block_devices)
488 c3d839f5 Michael Hanselmann
489 3d942d8b Michael Hanselmann
    cmd = ["create"]
490 323f9095 Stephen Shirley
    if startup_paused:
491 3d942d8b Michael Hanselmann
      cmd.append("-p")
492 3d942d8b Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
493 65a6f9b7 Michael Hanselmann
494 3d942d8b Michael Hanselmann
    result = self._RunXen(cmd)
495 65a6f9b7 Michael Hanselmann
    if result.failed:
496 48bba9de Balazs Lecz
      # Move the Xen configuration file to the log directory to avoid
497 48bba9de Balazs Lecz
      # leaving a stale config file behind.
498 48bba9de Balazs Lecz
      stashed_config = self._StashConfigFile(instance.name)
499 48bba9de Balazs Lecz
      raise errors.HypervisorError("Failed to start instance %s: %s (%s). Moved"
500 48bba9de Balazs Lecz
                                   " config file to %s" %
501 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
502 48bba9de Balazs Lecz
                                    result.output, stashed_config))
503 65a6f9b7 Michael Hanselmann
504 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
505 c41eea6e Iustin Pop
    """Stop an instance.
506 c41eea6e Iustin Pop

507 c41eea6e Iustin Pop
    """
508 bbcf7ad0 Iustin Pop
    if name is None:
509 bbcf7ad0 Iustin Pop
      name = instance.name
510 4b8b172d Michael Hanselmann
511 31da5ab5 Michael Hanselmann
    return self._StopInstance(name, force)
512 31da5ab5 Michael Hanselmann
513 31da5ab5 Michael Hanselmann
  def _StopInstance(self, name, force):
514 31da5ab5 Michael Hanselmann
    """Stop an instance.
515 31da5ab5 Michael Hanselmann

516 31da5ab5 Michael Hanselmann
    """
517 65a6f9b7 Michael Hanselmann
    if force:
518 3d942d8b Michael Hanselmann
      action = "destroy"
519 65a6f9b7 Michael Hanselmann
    else:
520 3d942d8b Michael Hanselmann
      action = "shutdown"
521 65a6f9b7 Michael Hanselmann
522 3d942d8b Michael Hanselmann
    result = self._RunXen([action, name])
523 65a6f9b7 Michael Hanselmann
    if result.failed:
524 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
525 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
526 65a6f9b7 Michael Hanselmann
527 4b8b172d Michael Hanselmann
    # Remove configuration file if stopping/starting instance was successful
528 4b8b172d Michael Hanselmann
    self._RemoveConfigFile(name)
529 4b8b172d Michael Hanselmann
530 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
531 c41eea6e Iustin Pop
    """Reboot an instance.
532 c41eea6e Iustin Pop

533 c41eea6e Iustin Pop
    """
534 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
535 65a6f9b7 Michael Hanselmann
536 e0561198 Iustin Pop
    if ini_info is None:
537 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
538 e0561198 Iustin Pop
                                   " not running" % instance.name)
539 e0561198 Iustin Pop
540 3d942d8b Michael Hanselmann
    result = self._RunXen(["reboot", instance.name])
541 65a6f9b7 Michael Hanselmann
    if result.failed:
542 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
543 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
544 3213d3c8 Iustin Pop
                                    result.output))
545 06b78e8b Michael Hanselmann
546 06b78e8b Michael Hanselmann
    def _CheckInstance():
547 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
548 06b78e8b Michael Hanselmann
549 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
550 e0561198 Iustin Pop
      if (new_info is not None and
551 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
552 06b78e8b Michael Hanselmann
        return
553 7dd106d3 Iustin Pop
554 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
555 06b78e8b Michael Hanselmann
556 06b78e8b Michael Hanselmann
    try:
557 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
558 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
559 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
560 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
561 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
562 7dd106d3 Iustin Pop
                                   (instance.name, ))
563 65a6f9b7 Michael Hanselmann
564 2c7a0373 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
565 2c7a0373 Guido Trotter
    """Balloon an instance memory to a certain value.
566 2c7a0373 Guido Trotter

567 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
568 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
569 2c7a0373 Guido Trotter
    @type mem: int
570 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
571 2c7a0373 Guido Trotter

572 2c7a0373 Guido Trotter
    """
573 3d942d8b Michael Hanselmann
    result = self._RunXen(["mem-set", instance.name, mem])
574 2c7a0373 Guido Trotter
    if result.failed:
575 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
576 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
577 2c7a0373 Guido Trotter
                                    result.output))
578 3d942d8b Michael Hanselmann
579 3d942d8b Michael Hanselmann
    # Update configuration file
580 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
581 0a903309 Michael Hanselmann
    cmd.append(self._ConfigFileName(instance.name))
582 3d942d8b Michael Hanselmann
583 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
584 2c7a0373 Guido Trotter
    if result.failed:
585 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
586 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
587 2c7a0373 Guido Trotter
                                    result.output))
588 2c7a0373 Guido Trotter
589 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
590 65a6f9b7 Michael Hanselmann
    """Return information about the node.
591 65a6f9b7 Michael Hanselmann

592 06c9a520 Michael Hanselmann
    @see: L{_GetNodeInfo} and L{_ParseNodeInfo}
593 65a6f9b7 Michael Hanselmann

594 65a6f9b7 Michael Hanselmann
    """
595 3d942d8b Michael Hanselmann
    result = self._RunXen(["info"])
596 65a6f9b7 Michael Hanselmann
    if result.failed:
597 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
598 b48909c8 Iustin Pop
                    result.output)
599 65a6f9b7 Michael Hanselmann
      return None
600 65a6f9b7 Michael Hanselmann
601 06c9a520 Michael Hanselmann
    return _GetNodeInfo(result.stdout, self._GetXmList)
602 65a6f9b7 Michael Hanselmann
603 637ce7f9 Guido Trotter
  @classmethod
604 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
605 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
606 65a6f9b7 Michael Hanselmann

607 65a6f9b7 Michael Hanselmann
    """
608 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
609 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
610 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
611 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
612 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
613 1f5557ca Guido Trotter
                                            constants.XEN_CMD, instance.name])
614 65a6f9b7 Michael Hanselmann
615 65a6f9b7 Michael Hanselmann
  def Verify(self):
616 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
617 65a6f9b7 Michael Hanselmann

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

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

622 65a6f9b7 Michael Hanselmann
    """
623 3d942d8b Michael Hanselmann
    result = self._RunXen(["info"])
624 e3e66f02 Michael Hanselmann
    if result.failed:
625 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
626 65a6f9b7 Michael Hanselmann
627 cd04dfd2 Michael Hanselmann
    return None
628 cd04dfd2 Michael Hanselmann
629 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
630 4390ccff Guido Trotter
    """Get instance information to perform a migration.
631 4390ccff Guido Trotter

632 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
633 4390ccff Guido Trotter
    @param instance: instance to be migrated
634 4390ccff Guido Trotter
    @rtype: string
635 4390ccff Guido Trotter
    @return: content of the xen config file
636 4390ccff Guido Trotter

637 4390ccff Guido Trotter
    """
638 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
639 4390ccff Guido Trotter
640 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
641 4390ccff Guido Trotter
    """Prepare to accept an instance.
642 4390ccff Guido Trotter

643 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
644 4390ccff Guido Trotter
    @param instance: instance to be accepted
645 4390ccff Guido Trotter
    @type info: string
646 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
647 4390ccff Guido Trotter
    @type target: string
648 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
649 4390ccff Guido Trotter

650 4390ccff Guido Trotter
    """
651 4390ccff Guido Trotter
    pass
652 4390ccff Guido Trotter
653 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
654 4390ccff Guido Trotter
    """Finalize an instance migration.
655 4390ccff Guido Trotter

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

659 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
660 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
661 4390ccff Guido Trotter
    @type info: string
662 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
663 4390ccff Guido Trotter
    @type success: boolean
664 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
665 4390ccff Guido Trotter

666 4390ccff Guido Trotter
    """
667 4390ccff Guido Trotter
    if success:
668 c3d839f5 Michael Hanselmann
      self._WriteConfigFile(instance.name, info)
669 4390ccff Guido Trotter
670 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
671 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
672 6e7275c0 Iustin Pop

673 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
674 6e7275c0 Iustin Pop
    currently running.
675 6e7275c0 Iustin Pop

676 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
677 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
678 fdf7f055 Guido Trotter
    @type target: string
679 fdf7f055 Guido Trotter
    @param target: ip address of the target node
680 fdf7f055 Guido Trotter
    @type live: boolean
681 fdf7f055 Guido Trotter
    @param live: perform a live migration
682 fdf7f055 Guido Trotter

683 6e7275c0 Iustin Pop
    """
684 d8784f7d Michael Hanselmann
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
685 d8784f7d Michael Hanselmann
686 d8784f7d Michael Hanselmann
    # TODO: Pass cluster name via RPC
687 d8784f7d Michael Hanselmann
    cluster_name = ssconf.SimpleStore().GetClusterName()
688 d8784f7d Michael Hanselmann
689 d8784f7d Michael Hanselmann
    return self._MigrateInstance(cluster_name, instance.name, target, port,
690 d8784f7d Michael Hanselmann
                                 live)
691 d8784f7d Michael Hanselmann
692 d8784f7d Michael Hanselmann
  def _MigrateInstance(self, cluster_name, instance_name, target, port, live,
693 d8784f7d Michael Hanselmann
                       _ping_fn=netutils.TcpPing):
694 d8784f7d Michael Hanselmann
    """Migrate an instance to a target node.
695 d8784f7d Michael Hanselmann

696 d8784f7d Michael Hanselmann
    @see: L{MigrateInstance} for details
697 d8784f7d Michael Hanselmann

698 d8784f7d Michael Hanselmann
    """
699 d8784f7d Michael Hanselmann
    if self.GetInstanceInfo(instance_name) is None:
700 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
701 50716be0 Iustin Pop
702 d8784f7d Michael Hanselmann
    cmd = self._GetCommand()
703 50716be0 Iustin Pop
704 d8784f7d Michael Hanselmann
    if (cmd == constants.XEN_CMD_XM and
705 d8784f7d Michael Hanselmann
        not _ping_fn(target, port, live_port_needed=True)):
706 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
707 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
708 50716be0 Iustin Pop
709 3d942d8b Michael Hanselmann
    args = ["migrate"]
710 3d942d8b Michael Hanselmann
711 d8784f7d Michael Hanselmann
    if cmd == constants.XEN_CMD_XM:
712 0625d08f René Nussbaumer
      args.extend(["-p", "%d" % port])
713 0625d08f René Nussbaumer
      if live:
714 0625d08f René Nussbaumer
        args.append("-l")
715 3d942d8b Michael Hanselmann
716 d8784f7d Michael Hanselmann
    elif cmd == constants.XEN_CMD_XL:
717 d8784f7d Michael Hanselmann
      args.extend([
718 d8784f7d Michael Hanselmann
        "-s", constants.XL_SSH_CMD % cluster_name,
719 d8784f7d Michael Hanselmann
        "-C", self._ConfigFileName(instance_name),
720 d8784f7d Michael Hanselmann
        ])
721 3d942d8b Michael Hanselmann
722 0625d08f René Nussbaumer
    else:
723 d8784f7d Michael Hanselmann
      raise errors.HypervisorError("Unsupported Xen command: %s" % self._cmd)
724 0625d08f René Nussbaumer
725 d8784f7d Michael Hanselmann
    args.extend([instance_name, target])
726 3d942d8b Michael Hanselmann
727 3d942d8b Michael Hanselmann
    result = self._RunXen(args)
728 6e7275c0 Iustin Pop
    if result.failed:
729 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
730 d8784f7d Michael Hanselmann
                                   (instance_name, result.output))
731 60af751d Andrea Spadaccini
732 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
733 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
734 60af751d Andrea Spadaccini

735 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
736 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
737 60af751d Andrea Spadaccini
    @type success: bool
738 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
739 60af751d Andrea Spadaccini
    @type live: bool
740 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
741 60af751d Andrea Spadaccini

742 60af751d Andrea Spadaccini
    """
743 60af751d Andrea Spadaccini
    # pylint: disable=W0613
744 60af751d Andrea Spadaccini
    if success:
745 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
746 60af751d Andrea Spadaccini
      try:
747 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
748 60af751d Andrea Spadaccini
      except EnvironmentError:
749 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
750 60af751d Andrea Spadaccini
751 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
752 60af751d Andrea Spadaccini
    """Get the migration status
753 60af751d Andrea Spadaccini

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

758 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
759 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
760 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
761 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
762 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
763 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
764 60af751d Andrea Spadaccini

765 60af751d Andrea Spadaccini
    """
766 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
767 6e7275c0 Iustin Pop
768 f5118ade Iustin Pop
  @classmethod
769 f5118ade Iustin Pop
  def PowercycleNode(cls):
770 f5118ade Iustin Pop
    """Xen-specific powercycle.
771 f5118ade Iustin Pop

772 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
773 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
774 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
775 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
776 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
777 f5118ade Iustin Pop
    daemon is not working.
778 f5118ade Iustin Pop

779 f5118ade Iustin Pop
    """
780 f5118ade Iustin Pop
    try:
781 f5118ade Iustin Pop
      cls.LinuxPowercycle()
782 f5118ade Iustin Pop
    finally:
783 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
784 f5118ade Iustin Pop
785 65a6f9b7 Michael Hanselmann
786 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
787 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
788 65a6f9b7 Michael Hanselmann
789 205ab586 Iustin Pop
  PARAMETERS = {
790 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
791 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
792 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
793 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
794 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
795 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
796 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
797 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
798 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
799 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
800 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
801 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
802 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
803 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
804 2c368f28 Guido Trotter
    constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
805 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
806 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
807 205ab586 Iustin Pop
    }
808 f48148c3 Iustin Pop
809 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
810 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
811 65a6f9b7 Michael Hanselmann

812 65a6f9b7 Michael Hanselmann
    """
813 a985b417 Iustin Pop
    hvp = instance.hvparams
814 65a6f9b7 Michael Hanselmann
    config = StringIO()
815 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
816 65a6f9b7 Michael Hanselmann
817 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
818 2f2dbb4b Jun Futagawa
    # parameters.
819 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
820 2f2dbb4b Jun Futagawa
      # bootloader handling
821 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
822 2f2dbb4b Jun Futagawa
      if bootloader_path:
823 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
824 2f2dbb4b Jun Futagawa
      else:
825 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
826 2f2dbb4b Jun Futagawa
                                     " bootloader path")
827 65a6f9b7 Michael Hanselmann
828 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
829 2f2dbb4b Jun Futagawa
      if bootloader_args:
830 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
831 2f2dbb4b Jun Futagawa
    else:
832 2f2dbb4b Jun Futagawa
      # kernel handling
833 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
834 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
835 2f2dbb4b Jun Futagawa
836 2f2dbb4b Jun Futagawa
      # initrd handling
837 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
838 2f2dbb4b Jun Futagawa
      if initrd_path:
839 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
840 65a6f9b7 Michael Hanselmann
841 65a6f9b7 Michael Hanselmann
    # rest of the settings
842 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
843 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
844 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
845 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
846 c4708267 Tsachy Shacham
    if cpu_pinning:
847 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
848 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
849 8bd977e9 Sébastien Bocahu
    if cpu_cap:
850 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
851 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
852 8bd977e9 Sébastien Bocahu
    if cpu_weight:
853 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
854 c4708267 Tsachy Shacham
855 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
856 65a6f9b7 Michael Hanselmann
857 65a6f9b7 Michael Hanselmann
    vif_data = []
858 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
859 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
860 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
861 65a6f9b7 Michael Hanselmann
      if ip is not None:
862 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
863 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
864 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
865 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
866 65a6f9b7 Michael Hanselmann
867 d0bb3f24 Michael Hanselmann
    disk_data = \
868 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
869 7ed85ffe Iustin Pop
870 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
871 7ed85ffe Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
872 074ca009 Guido Trotter
873 7adf7814 René Nussbaumer
    if hvp[constants.HV_ROOT_PATH]:
874 7adf7814 René Nussbaumer
      config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
875 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
876 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
877 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
878 990ade2d Stephen Shirley
    else:
879 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
880 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
881 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
882 73cd67f4 Guido Trotter
883 c3d839f5 Michael Hanselmann
    return config.getvalue()
884 65a6f9b7 Michael Hanselmann
885 65a6f9b7 Michael Hanselmann
886 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
887 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
888 65a6f9b7 Michael Hanselmann
889 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
890 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
891 69b99987 Michael Hanselmann
    ]
892 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
893 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
894 69ab2e12 Guido Trotter
    ]
895 3680f662 Guido Trotter
896 205ab586 Iustin Pop
  PARAMETERS = {
897 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
898 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
899 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
900 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
901 016d04b3 Michael Hanselmann
       None, None),
902 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
903 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
904 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
905 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
906 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
907 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
908 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
909 8b312c1d Manuel Franceschini
      (False, netutils.IP4Address.IsValid,
910 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
911 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
912 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
913 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
914 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
915 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
916 6b970cef Jun Futagawa
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
917 e695efbf Iustin Pop
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
918 e695efbf Iustin Pop
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
919 87f0aa48 Jack
    # Add PCI passthrough
920 3891c95e Bernardo Dal Seno
    constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
921 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
922 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
923 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
924 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_CAP: hv_base.NO_CHECK,
925 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
926 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65535, "invalid weight", None, None),
927 05440845 Helga Velroyen
    constants.HV_VIF_TYPE:
928 05440845 Helga Velroyen
      hv_base.ParamInSet(False, constants.HT_HVM_VALID_VIF_TYPES),
929 205ab586 Iustin Pop
    }
930 09ea8710 Iustin Pop
931 c3d839f5 Michael Hanselmann
  def _GetConfig(self, instance, startup_memory, block_devices):
932 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
933 65a6f9b7 Michael Hanselmann

934 65a6f9b7 Michael Hanselmann
    """
935 a985b417 Iustin Pop
    hvp = instance.hvparams
936 a985b417 Iustin Pop
937 65a6f9b7 Michael Hanselmann
    config = StringIO()
938 e2ee1cea Iustin Pop
939 e2ee1cea Iustin Pop
    # kernel handling
940 e2ee1cea Iustin Pop
    kpath = hvp[constants.HV_KERNEL_PATH]
941 e2ee1cea Iustin Pop
    config.write("kernel = '%s'\n" % kpath)
942 e2ee1cea Iustin Pop
943 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
944 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
945 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
946 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
947 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
948 c4708267 Tsachy Shacham
    if cpu_pinning:
949 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
950 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
951 8bd977e9 Sébastien Bocahu
    if cpu_cap:
952 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
953 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
954 8bd977e9 Sébastien Bocahu
    if cpu_weight:
955 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
956 c4708267 Tsachy Shacham
957 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
958 09ea8710 Iustin Pop
    if hvp[constants.HV_PAE]:
959 a21dda8b Iustin Pop
      config.write("pae = 1\n")
960 a21dda8b Iustin Pop
    else:
961 a21dda8b Iustin Pop
      config.write("pae = 0\n")
962 09ea8710 Iustin Pop
    if hvp[constants.HV_ACPI]:
963 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
964 a21dda8b Iustin Pop
    else:
965 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
966 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
967 09ea8710 Iustin Pop
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
968 a985b417 Iustin Pop
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
969 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
970 97efde45 Guido Trotter
    config.write("usb = 1\n")
971 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
972 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
973 a985b417 Iustin Pop
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
974 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
975 d0c11cf7 Alexander Schreiber
    else:
976 6b405598 Guido Trotter
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
977 65a6f9b7 Michael Hanselmann
978 377d74c9 Guido Trotter
    if instance.network_port > constants.VNC_BASE_PORT:
979 377d74c9 Guido Trotter
      display = instance.network_port - constants.VNC_BASE_PORT
980 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
981 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
982 65a6f9b7 Michael Hanselmann
    else:
983 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
984 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
985 65a6f9b7 Michael Hanselmann
986 6e6bb8d5 Guido Trotter
    vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
987 65a6f9b7 Michael Hanselmann
    try:
988 6e6bb8d5 Guido Trotter
      password = utils.ReadFile(vnc_pwd_file)
989 78f66a17 Guido Trotter
    except EnvironmentError, err:
990 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
991 6e6bb8d5 Guido Trotter
                                   (vnc_pwd_file, err))
992 65a6f9b7 Michael Hanselmann
993 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
994 65a6f9b7 Michael Hanselmann
995 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
996 6b970cef Jun Futagawa
    if hvp[constants.HV_USE_LOCALTIME]:
997 6b970cef Jun Futagawa
      config.write("localtime = 1\n")
998 65a6f9b7 Michael Hanselmann
999 65a6f9b7 Michael Hanselmann
    vif_data = []
1000 05440845 Helga Velroyen
    # Note: what is called 'nic_type' here, is used as value for the xen nic
1001 05440845 Helga Velroyen
    # vif config parameter 'model'. For the xen nic vif parameter 'type', we use
1002 05440845 Helga Velroyen
    # the 'vif_type' to avoid a clash of notation.
1003 a985b417 Iustin Pop
    nic_type = hvp[constants.HV_NIC_TYPE]
1004 05440845 Helga Velroyen
1005 f48148c3 Iustin Pop
    if nic_type is None:
1006 05440845 Helga Velroyen
      vif_type_str = ""
1007 05440845 Helga Velroyen
      if hvp[constants.HV_VIF_TYPE]:
1008 05440845 Helga Velroyen
        vif_type_str = ", type=%s" % hvp[constants.HV_VIF_TYPE]
1009 f48148c3 Iustin Pop
      # ensure old instances don't change
1010 05440845 Helga Velroyen
      nic_type_str = vif_type_str
1011 d08f6067 Guido Trotter
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
1012 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
1013 f48148c3 Iustin Pop
    else:
1014 05440845 Helga Velroyen
      # parameter 'model' is only valid with type 'ioemu'
1015 05440845 Helga Velroyen
      nic_type_str = ", model=%s, type=%s" % \
1016 05440845 Helga Velroyen
        (nic_type, constants.HT_HVM_VIF_IOEMU)
1017 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
1018 503b97a9 Guido Trotter
      nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
1019 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
1020 65a6f9b7 Michael Hanselmann
      if ip is not None:
1021 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
1022 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1023 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
1024 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
1025 65a6f9b7 Michael Hanselmann
1026 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
1027 525011bc Maciej Bliziński
1028 d0bb3f24 Michael Hanselmann
    disk_data = \
1029 d0bb3f24 Michael Hanselmann
      _GetConfigFileDiskData(block_devices, hvp[constants.HV_BLOCKDEV_PREFIX])
1030 525011bc Maciej Bliziński
1031 a985b417 Iustin Pop
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
1032 f48148c3 Iustin Pop
    if iso_path:
1033 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
1034 a21dda8b Iustin Pop
      disk_data.append(iso)
1035 a21dda8b Iustin Pop
1036 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
1037 87f0aa48 Jack
    # Add PCI passthrough
1038 87f0aa48 Jack
    pci_pass_arr = []
1039 87f0aa48 Jack
    pci_pass = hvp[constants.HV_PASSTHROUGH]
1040 87f0aa48 Jack
    if pci_pass:
1041 3891c95e Bernardo Dal Seno
      pci_pass_arr = pci_pass.split(";")
1042 3891c95e Bernardo Dal Seno
      config.write("pci = %s\n" % pci_pass_arr)
1043 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
1044 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
1045 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
1046 990ade2d Stephen Shirley
    else:
1047 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
1048 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
1049 73cd67f4 Guido Trotter
1050 c3d839f5 Michael Hanselmann
    return config.getvalue()