Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 6f1e1921

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

49 347fa0f1 Michael Hanselmann
  """
50 347fa0f1 Michael Hanselmann
  # Convert the string CPU mask to a list of list of int's
51 347fa0f1 Michael Hanselmann
  cpu_list = utils.ParseMultiCpuMask(cpu_mask)
52 347fa0f1 Michael Hanselmann
53 347fa0f1 Michael Hanselmann
  if len(cpu_list) == 1:
54 347fa0f1 Michael Hanselmann
    all_cpu_mapping = cpu_list[0]
55 347fa0f1 Michael Hanselmann
    if all_cpu_mapping == constants.CPU_PINNING_OFF:
56 347fa0f1 Michael Hanselmann
      # If CPU pinning has 1 entry that's "all", then remove the
57 347fa0f1 Michael Hanselmann
      # parameter from the config file
58 347fa0f1 Michael Hanselmann
      return None
59 347fa0f1 Michael Hanselmann
    else:
60 347fa0f1 Michael Hanselmann
      # If CPU pinning has one non-all entry, mapping all vCPUS (the entire
61 347fa0f1 Michael Hanselmann
      # VM) to one physical CPU, using format 'cpu = "C"'
62 347fa0f1 Michael Hanselmann
      return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
63 347fa0f1 Michael Hanselmann
  else:
64 347fa0f1 Michael Hanselmann
65 347fa0f1 Michael Hanselmann
    def _GetCPUMap(vcpu):
66 347fa0f1 Michael Hanselmann
      if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
67 347fa0f1 Michael Hanselmann
        cpu_map = constants.CPU_PINNING_ALL_XEN
68 347fa0f1 Michael Hanselmann
      else:
69 347fa0f1 Michael Hanselmann
        cpu_map = ",".join(map(str, vcpu))
70 347fa0f1 Michael Hanselmann
      return "\"%s\"" % cpu_map
71 347fa0f1 Michael Hanselmann
72 347fa0f1 Michael Hanselmann
    # build the result string in format 'cpus = [ "c", "c", "c" ]',
73 347fa0f1 Michael Hanselmann
    # where each c is a physical CPU number, a range, a list, or any
74 347fa0f1 Michael Hanselmann
    # combination
75 347fa0f1 Michael Hanselmann
    return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
76 347fa0f1 Michael Hanselmann
77 347fa0f1 Michael Hanselmann
78 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
79 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
80 65a6f9b7 Michael Hanselmann

81 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
82 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
83 65a6f9b7 Michael Hanselmann

84 65a6f9b7 Michael Hanselmann
  """
85 d271c6fd Iustin Pop
  CAN_MIGRATE = True
86 7dd106d3 Iustin Pop
  REBOOT_RETRY_COUNT = 60
87 7dd106d3 Iustin Pop
  REBOOT_RETRY_INTERVAL = 10
88 65a6f9b7 Michael Hanselmann
89 3680f662 Guido Trotter
  ANCILLARY_FILES = [
90 22d568c2 Guido Trotter
    XEND_CONFIG_FILE,
91 22d568c2 Guido Trotter
    XL_CONFIG_FILE,
92 22d568c2 Guido Trotter
    VIF_BRIDGE_SCRIPT,
93 3680f662 Guido Trotter
    ]
94 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = [
95 69ab2e12 Guido Trotter
    XL_CONFIG_FILE,
96 3680f662 Guido Trotter
    ]
97 3680f662 Guido Trotter
98 c2be2532 Guido Trotter
  @staticmethod
99 c2be2532 Guido Trotter
  def _ConfigFileName(instance_name):
100 c2be2532 Guido Trotter
    """Get the config file name for an instance.
101 c2be2532 Guido Trotter

102 c2be2532 Guido Trotter
    @param instance_name: instance name
103 c2be2532 Guido Trotter
    @type instance_name: str
104 c2be2532 Guido Trotter
    @return: fully qualified path to instance config file
105 c2be2532 Guido Trotter
    @rtype: str
106 c2be2532 Guido Trotter

107 c2be2532 Guido Trotter
    """
108 a8e8c0c6 Michael Hanselmann
    return utils.PathJoin(pathutils.XEN_CONFIG_DIR, instance_name)
109 c2be2532 Guido Trotter
110 5661b908 Iustin Pop
  @classmethod
111 61eb1a46 Guido Trotter
  def _WriteConfigFile(cls, instance, startup_memory, block_devices):
112 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
113 65a6f9b7 Michael Hanselmann

114 65a6f9b7 Michael Hanselmann
    """
115 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
116 65a6f9b7 Michael Hanselmann
117 65a6f9b7 Michael Hanselmann
  @staticmethod
118 4390ccff Guido Trotter
  def _WriteConfigFileStatic(instance_name, data):
119 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
120 4390ccff Guido Trotter

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

123 4390ccff Guido Trotter
    """
124 1a63f285 Iustin Pop
    # just in case it exists
125 a8e8c0c6 Michael Hanselmann
    utils.RemoveFile(utils.PathJoin(pathutils.XEN_CONFIG_DIR, "auto",
126 a8e8c0c6 Michael Hanselmann
                                    instance_name))
127 a8e8c0c6 Michael Hanselmann
128 1a63f285 Iustin Pop
    cfg_file = XenHypervisor._ConfigFileName(instance_name)
129 1a63f285 Iustin Pop
    try:
130 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
131 1a63f285 Iustin Pop
    except EnvironmentError, err:
132 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
133 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
134 4390ccff Guido Trotter
135 4390ccff Guido Trotter
  @staticmethod
136 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
137 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
138 4390ccff Guido Trotter

139 4390ccff Guido Trotter
    """
140 76c364d9 Michael Hanselmann
    filename = XenHypervisor._ConfigFileName(instance_name)
141 76c364d9 Michael Hanselmann
142 4390ccff Guido Trotter
    try:
143 76c364d9 Michael Hanselmann
      file_content = utils.ReadFile(filename)
144 4390ccff Guido Trotter
    except EnvironmentError, err:
145 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
146 76c364d9 Michael Hanselmann
147 4390ccff Guido Trotter
    return file_content
148 4390ccff Guido Trotter
149 4390ccff Guido Trotter
  @staticmethod
150 53c776b5 Iustin Pop
  def _RemoveConfigFile(instance_name):
151 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
152 65a6f9b7 Michael Hanselmann

153 65a6f9b7 Michael Hanselmann
    """
154 c2be2532 Guido Trotter
    utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
155 65a6f9b7 Michael Hanselmann
156 65a6f9b7 Michael Hanselmann
  @staticmethod
157 06b78e8b Michael Hanselmann
  def _RunXmList(xmlist_errors):
158 06b78e8b Michael Hanselmann
    """Helper function for L{_GetXMList} to run "xm list".
159 06b78e8b Michael Hanselmann

160 06b78e8b Michael Hanselmann
    """
161 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "list"])
162 06b78e8b Michael Hanselmann
    if result.failed:
163 06b78e8b Michael Hanselmann
      logging.error("xm list failed (%s): %s", result.fail_reason,
164 06b78e8b Michael Hanselmann
                    result.output)
165 06b78e8b Michael Hanselmann
      xmlist_errors.append(result)
166 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
167 06b78e8b Michael Hanselmann
168 06b78e8b Michael Hanselmann
    # skip over the heading
169 06b78e8b Michael Hanselmann
    return result.stdout.splitlines()[1:]
170 06b78e8b Michael Hanselmann
171 06b78e8b Michael Hanselmann
  @classmethod
172 06b78e8b Michael Hanselmann
  def _GetXMList(cls, include_node):
173 65a6f9b7 Michael Hanselmann
    """Return the list of running instances.
174 65a6f9b7 Michael Hanselmann

175 c41eea6e Iustin Pop
    If the include_node argument is True, then we return information
176 65a6f9b7 Michael Hanselmann
    for dom0 also, otherwise we filter that from the return value.
177 65a6f9b7 Michael Hanselmann

178 c41eea6e Iustin Pop
    @return: list of (name, id, memory, vcpus, state, time spent)
179 65a6f9b7 Michael Hanselmann

180 65a6f9b7 Michael Hanselmann
    """
181 06b78e8b Michael Hanselmann
    xmlist_errors = []
182 06b78e8b Michael Hanselmann
    try:
183 06b78e8b Michael Hanselmann
      lines = utils.Retry(cls._RunXmList, 1, 5, args=(xmlist_errors, ))
184 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
185 06b78e8b Michael Hanselmann
      if xmlist_errors:
186 06b78e8b Michael Hanselmann
        xmlist_result = xmlist_errors.pop()
187 65a6f9b7 Michael Hanselmann
188 06b78e8b Michael Hanselmann
        errmsg = ("xm list failed, timeout exceeded (%s): %s" %
189 06b78e8b Michael Hanselmann
                  (xmlist_result.fail_reason, xmlist_result.output))
190 06b78e8b Michael Hanselmann
      else:
191 06b78e8b Michael Hanselmann
        errmsg = "xm list failed"
192 06b78e8b Michael Hanselmann
193 06b78e8b Michael Hanselmann
      raise errors.HypervisorError(errmsg)
194 65a6f9b7 Michael Hanselmann
195 65a6f9b7 Michael Hanselmann
    result = []
196 65a6f9b7 Michael Hanselmann
    for line in lines:
197 65a6f9b7 Michael Hanselmann
      # The format of lines is:
198 65a6f9b7 Michael Hanselmann
      # Name      ID Mem(MiB) VCPUs State  Time(s)
199 65a6f9b7 Michael Hanselmann
      # Domain-0   0  3418     4 r-----    266.2
200 65a6f9b7 Michael Hanselmann
      data = line.split()
201 65a6f9b7 Michael Hanselmann
      if len(data) != 6:
202 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
203 65a6f9b7 Michael Hanselmann
                                     " line: %s" % line)
204 65a6f9b7 Michael Hanselmann
      try:
205 65a6f9b7 Michael Hanselmann
        data[1] = int(data[1])
206 65a6f9b7 Michael Hanselmann
        data[2] = int(data[2])
207 65a6f9b7 Michael Hanselmann
        data[3] = int(data[3])
208 65a6f9b7 Michael Hanselmann
        data[5] = float(data[5])
209 691744c4 Iustin Pop
      except (TypeError, ValueError), err:
210 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
211 65a6f9b7 Michael Hanselmann
                                     " line: %s, error: %s" % (line, err))
212 65a6f9b7 Michael Hanselmann
213 65a6f9b7 Michael Hanselmann
      # skip the Domain-0 (optional)
214 18bf85b1 Michael Hanselmann
      if include_node or data[0] != _DOM0_NAME:
215 65a6f9b7 Michael Hanselmann
        result.append(data)
216 65a6f9b7 Michael Hanselmann
217 65a6f9b7 Michael Hanselmann
    return result
218 65a6f9b7 Michael Hanselmann
219 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
220 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
221 65a6f9b7 Michael Hanselmann

222 65a6f9b7 Michael Hanselmann
    """
223 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
224 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
225 65a6f9b7 Michael Hanselmann
    return names
226 65a6f9b7 Michael Hanselmann
227 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
228 65a6f9b7 Michael Hanselmann
    """Get instance properties.
229 65a6f9b7 Michael Hanselmann

230 c41eea6e Iustin Pop
    @param instance_name: the instance name
231 c41eea6e Iustin Pop

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

234 65a6f9b7 Michael Hanselmann
    """
235 18bf85b1 Michael Hanselmann
    xm_list = self._GetXMList(instance_name == _DOM0_NAME)
236 65a6f9b7 Michael Hanselmann
    result = None
237 65a6f9b7 Michael Hanselmann
    for data in xm_list:
238 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
239 65a6f9b7 Michael Hanselmann
        result = data
240 65a6f9b7 Michael Hanselmann
        break
241 65a6f9b7 Michael Hanselmann
    return result
242 65a6f9b7 Michael Hanselmann
243 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
244 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
245 65a6f9b7 Michael Hanselmann

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

248 65a6f9b7 Michael Hanselmann
    """
249 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
250 65a6f9b7 Michael Hanselmann
    return xm_list
251 65a6f9b7 Michael Hanselmann
252 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
253 c41eea6e Iustin Pop
    """Start an instance.
254 c41eea6e Iustin Pop

255 c41eea6e Iustin Pop
    """
256 61eb1a46 Guido Trotter
    startup_memory = self._InstanceStartupMemory(instance)
257 61eb1a46 Guido Trotter
    self._WriteConfigFile(instance, startup_memory, block_devices)
258 2876c2d6 Guido Trotter
    cmd = [constants.XEN_CMD, "create"]
259 323f9095 Stephen Shirley
    if startup_paused:
260 6555373d Guido Trotter
      cmd.extend(["-p"])
261 6555373d Guido Trotter
    cmd.extend([self._ConfigFileName(instance.name)])
262 323f9095 Stephen Shirley
    result = utils.RunCmd(cmd)
263 65a6f9b7 Michael Hanselmann
264 65a6f9b7 Michael Hanselmann
    if result.failed:
265 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
266 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
267 65a6f9b7 Michael Hanselmann
                                    result.output))
268 65a6f9b7 Michael Hanselmann
269 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
270 c41eea6e Iustin Pop
    """Stop an instance.
271 c41eea6e Iustin Pop

272 c41eea6e Iustin Pop
    """
273 bbcf7ad0 Iustin Pop
    if name is None:
274 bbcf7ad0 Iustin Pop
      name = instance.name
275 4b8b172d Michael Hanselmann
276 65a6f9b7 Michael Hanselmann
    if force:
277 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "destroy", name]
278 65a6f9b7 Michael Hanselmann
    else:
279 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "shutdown", name]
280 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
281 65a6f9b7 Michael Hanselmann
282 65a6f9b7 Michael Hanselmann
    if result.failed:
283 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
284 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
285 65a6f9b7 Michael Hanselmann
286 4b8b172d Michael Hanselmann
    # Remove configuration file if stopping/starting instance was successful
287 4b8b172d Michael Hanselmann
    self._RemoveConfigFile(name)
288 4b8b172d Michael Hanselmann
289 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
290 c41eea6e Iustin Pop
    """Reboot an instance.
291 c41eea6e Iustin Pop

292 c41eea6e Iustin Pop
    """
293 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
294 65a6f9b7 Michael Hanselmann
295 e0561198 Iustin Pop
    if ini_info is None:
296 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
297 e0561198 Iustin Pop
                                   " not running" % instance.name)
298 e0561198 Iustin Pop
299 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
300 65a6f9b7 Michael Hanselmann
    if result.failed:
301 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
302 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
303 3213d3c8 Iustin Pop
                                    result.output))
304 06b78e8b Michael Hanselmann
305 06b78e8b Michael Hanselmann
    def _CheckInstance():
306 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
307 06b78e8b Michael Hanselmann
308 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
309 e0561198 Iustin Pop
      if (new_info is not None and
310 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
311 06b78e8b Michael Hanselmann
        return
312 7dd106d3 Iustin Pop
313 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
314 06b78e8b Michael Hanselmann
315 06b78e8b Michael Hanselmann
    try:
316 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
317 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
318 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
319 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
320 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
321 7dd106d3 Iustin Pop
                                   (instance.name, ))
322 65a6f9b7 Michael Hanselmann
323 2c7a0373 Guido Trotter
  def BalloonInstanceMemory(self, instance, mem):
324 2c7a0373 Guido Trotter
    """Balloon an instance memory to a certain value.
325 2c7a0373 Guido Trotter

326 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
327 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
328 2c7a0373 Guido Trotter
    @type mem: int
329 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
330 2c7a0373 Guido Trotter

331 2c7a0373 Guido Trotter
    """
332 2c7a0373 Guido Trotter
    cmd = [constants.XEN_CMD, "mem-set", instance.name, mem]
333 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
334 2c7a0373 Guido Trotter
    if result.failed:
335 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to balloon instance %s: %s (%s)" %
336 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
337 2c7a0373 Guido Trotter
                                    result.output))
338 2c7a0373 Guido Trotter
    cmd = ["sed", "-ie", "s/^memory.*$/memory = %s/" % mem]
339 2c7a0373 Guido Trotter
    cmd.append(XenHypervisor._ConfigFileName(instance.name))
340 2c7a0373 Guido Trotter
    result = utils.RunCmd(cmd)
341 2c7a0373 Guido Trotter
    if result.failed:
342 2c7a0373 Guido Trotter
      raise errors.HypervisorError("Failed to update memory for %s: %s (%s)" %
343 2c7a0373 Guido Trotter
                                   (instance.name, result.fail_reason,
344 2c7a0373 Guido Trotter
                                    result.output))
345 2c7a0373 Guido Trotter
346 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
347 65a6f9b7 Michael Hanselmann
    """Return information about the node.
348 65a6f9b7 Michael Hanselmann

349 0105bad3 Iustin Pop
    @return: a dict with the following keys (memory values in MiB):
350 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
351 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
352 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
353 0105bad3 Iustin Pop
          - nr_cpus: total number of CPUs
354 0105bad3 Iustin Pop
          - nr_nodes: in a NUMA system, the number of domains
355 0105bad3 Iustin Pop
          - nr_sockets: the number of physical CPU sockets in the node
356 34fbc862 Andrea Spadaccini
          - hv_version: the hypervisor version in the form (major, minor)
357 65a6f9b7 Michael Hanselmann

358 65a6f9b7 Michael Hanselmann
    """
359 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
360 65a6f9b7 Michael Hanselmann
    if result.failed:
361 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
362 b48909c8 Iustin Pop
                    result.output)
363 65a6f9b7 Michael Hanselmann
      return None
364 65a6f9b7 Michael Hanselmann
365 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
366 65a6f9b7 Michael Hanselmann
    result = {}
367 0105bad3 Iustin Pop
    cores_per_socket = threads_per_core = nr_cpus = None
368 34fbc862 Andrea Spadaccini
    xen_major, xen_minor = None, None
369 16ca6243 Michael Hanselmann
    memory_total = None
370 16ca6243 Michael Hanselmann
    memory_free = None
371 16ca6243 Michael Hanselmann
372 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
373 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
374 65a6f9b7 Michael Hanselmann
375 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
376 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
377 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
378 16ca6243 Michael Hanselmann
379 16ca6243 Michael Hanselmann
        # note: in xen 3, memory has changed to total_memory
380 d0c8c01d Iustin Pop
        if key == "memory" or key == "total_memory":
381 16ca6243 Michael Hanselmann
          memory_total = int(val)
382 d0c8c01d Iustin Pop
        elif key == "free_memory":
383 16ca6243 Michael Hanselmann
          memory_free = int(val)
384 d0c8c01d Iustin Pop
        elif key == "nr_cpus":
385 d0c8c01d Iustin Pop
          nr_cpus = result["cpu_total"] = int(val)
386 d0c8c01d Iustin Pop
        elif key == "nr_nodes":
387 d0c8c01d Iustin Pop
          result["cpu_nodes"] = int(val)
388 d0c8c01d Iustin Pop
        elif key == "cores_per_socket":
389 0105bad3 Iustin Pop
          cores_per_socket = int(val)
390 d0c8c01d Iustin Pop
        elif key == "threads_per_core":
391 0105bad3 Iustin Pop
          threads_per_core = int(val)
392 34fbc862 Andrea Spadaccini
        elif key == "xen_major":
393 34fbc862 Andrea Spadaccini
          xen_major = int(val)
394 34fbc862 Andrea Spadaccini
        elif key == "xen_minor":
395 34fbc862 Andrea Spadaccini
          xen_minor = int(val)
396 0105bad3 Iustin Pop
397 16ca6243 Michael Hanselmann
    if None not in [cores_per_socket, threads_per_core, nr_cpus]:
398 d0c8c01d Iustin Pop
      result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
399 0105bad3 Iustin Pop
400 16ca6243 Michael Hanselmann
    total_instmem = 0
401 16ca6243 Michael Hanselmann
    for (name, _, mem, vcpus, _, _) in self._GetXMList(True):
402 16ca6243 Michael Hanselmann
      if name == _DOM0_NAME:
403 16ca6243 Michael Hanselmann
        result["memory_dom0"] = mem
404 16ca6243 Michael Hanselmann
        result["dom0_cpus"] = vcpus
405 16ca6243 Michael Hanselmann
406 16ca6243 Michael Hanselmann
      # Include Dom0 in total memory usage
407 16ca6243 Michael Hanselmann
      total_instmem += mem
408 16ca6243 Michael Hanselmann
409 16ca6243 Michael Hanselmann
    if memory_free is not None:
410 16ca6243 Michael Hanselmann
      result["memory_free"] = memory_free
411 16ca6243 Michael Hanselmann
412 16ca6243 Michael Hanselmann
    if memory_total is not None:
413 16ca6243 Michael Hanselmann
      result["memory_total"] = memory_total
414 16ca6243 Michael Hanselmann
415 16ca6243 Michael Hanselmann
    # Calculate memory used by hypervisor
416 16ca6243 Michael Hanselmann
    if None not in [memory_total, memory_free, total_instmem]:
417 16ca6243 Michael Hanselmann
      result["memory_hv"] = memory_total - memory_free - total_instmem
418 65a6f9b7 Michael Hanselmann
419 34fbc862 Andrea Spadaccini
    if not (xen_major is None or xen_minor is None):
420 34fbc862 Andrea Spadaccini
      result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
421 34fbc862 Andrea Spadaccini
422 65a6f9b7 Michael Hanselmann
    return result
423 65a6f9b7 Michael Hanselmann
424 637ce7f9 Guido Trotter
  @classmethod
425 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
426 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
427 65a6f9b7 Michael Hanselmann

428 65a6f9b7 Michael Hanselmann
    """
429 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
430 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
431 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
432 052783ff Michael Hanselmann
                                   user=constants.SSH_CONSOLE_USER,
433 b9612abb Iustin Pop
                                   command=[pathutils.XEN_CONSOLE_WRAPPER,
434 1f5557ca Guido Trotter
                                            constants.XEN_CMD, instance.name])
435 65a6f9b7 Michael Hanselmann
436 65a6f9b7 Michael Hanselmann
  def Verify(self):
437 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
438 65a6f9b7 Michael Hanselmann

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

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

443 65a6f9b7 Michael Hanselmann
    """
444 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
445 e3e66f02 Michael Hanselmann
    if result.failed:
446 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
447 65a6f9b7 Michael Hanselmann
448 cd04dfd2 Michael Hanselmann
    return None
449 cd04dfd2 Michael Hanselmann
450 65a6f9b7 Michael Hanselmann
  @staticmethod
451 525011bc Maciej Bliziński
  def _GetConfigFileDiskData(block_devices, blockdev_prefix):
452 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
453 65a6f9b7 Michael Hanselmann

454 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
455 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
456 65a6f9b7 Michael Hanselmann

457 c41eea6e Iustin Pop
    @param block_devices: list of tuples (cfdev, rldev):
458 c41eea6e Iustin Pop
        - cfdev: dict containing ganeti config disk part
459 c41eea6e Iustin Pop
        - rldev: ganeti.bdev.BlockDev object
460 525011bc Maciej Bliziński
    @param blockdev_prefix: a string containing blockdevice prefix,
461 525011bc Maciej Bliziński
                            e.g. "sd" for /dev/sda
462 65a6f9b7 Michael Hanselmann

463 c41eea6e Iustin Pop
    @return: string containing disk directive for xen instance config file
464 65a6f9b7 Michael Hanselmann

465 65a6f9b7 Michael Hanselmann
    """
466 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
467 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
468 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
469 65a6f9b7 Michael Hanselmann
      }
470 65a6f9b7 Michael Hanselmann
    disk_data = []
471 2864f2d9 Iustin Pop
    if len(block_devices) > 24:
472 2864f2d9 Iustin Pop
      # 'z' - 'a' = 24
473 2864f2d9 Iustin Pop
      raise errors.HypervisorError("Too many disks")
474 d0c8c01d Iustin Pop
    namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
475 069cfbf1 Iustin Pop
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
476 d34b16d7 Iustin Pop
      if cfdev.mode == constants.DISK_RDWR:
477 d34b16d7 Iustin Pop
        mode = "w"
478 d34b16d7 Iustin Pop
      else:
479 d34b16d7 Iustin Pop
        mode = "r"
480 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
481 d34b16d7 Iustin Pop
        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
482 d34b16d7 Iustin Pop
                                  dev_path, sd_name, mode)
483 65a6f9b7 Michael Hanselmann
      else:
484 d34b16d7 Iustin Pop
        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
485 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
486 65a6f9b7 Michael Hanselmann
487 65a6f9b7 Michael Hanselmann
    return disk_data
488 65a6f9b7 Michael Hanselmann
489 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
490 4390ccff Guido Trotter
    """Get instance information to perform a migration.
491 4390ccff Guido Trotter

492 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
493 4390ccff Guido Trotter
    @param instance: instance to be migrated
494 4390ccff Guido Trotter
    @rtype: string
495 4390ccff Guido Trotter
    @return: content of the xen config file
496 4390ccff Guido Trotter

497 4390ccff Guido Trotter
    """
498 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
499 4390ccff Guido Trotter
500 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
501 4390ccff Guido Trotter
    """Prepare to accept an instance.
502 4390ccff Guido Trotter

503 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
504 4390ccff Guido Trotter
    @param instance: instance to be accepted
505 4390ccff Guido Trotter
    @type info: string
506 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
507 4390ccff Guido Trotter
    @type target: string
508 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
509 4390ccff Guido Trotter

510 4390ccff Guido Trotter
    """
511 4390ccff Guido Trotter
    pass
512 4390ccff Guido Trotter
513 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
514 4390ccff Guido Trotter
    """Finalize an instance migration.
515 4390ccff Guido Trotter

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

519 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
520 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
521 4390ccff Guido Trotter
    @type info: string
522 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
523 4390ccff Guido Trotter
    @type success: boolean
524 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
525 4390ccff Guido Trotter

526 4390ccff Guido Trotter
    """
527 4390ccff Guido Trotter
    if success:
528 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
529 4390ccff Guido Trotter
530 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
531 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
532 6e7275c0 Iustin Pop

533 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
534 6e7275c0 Iustin Pop
    currently running.
535 6e7275c0 Iustin Pop

536 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
537 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
538 fdf7f055 Guido Trotter
    @type target: string
539 fdf7f055 Guido Trotter
    @param target: ip address of the target node
540 fdf7f055 Guido Trotter
    @type live: boolean
541 fdf7f055 Guido Trotter
    @param live: perform a live migration
542 fdf7f055 Guido Trotter

543 6e7275c0 Iustin Pop
    """
544 58d38b02 Iustin Pop
    if self.GetInstanceInfo(instance.name) is None:
545 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
546 50716be0 Iustin Pop
547 641ae041 Iustin Pop
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
548 50716be0 Iustin Pop
549 3135de69 Guido Trotter
    if (constants.XEN_CMD == constants.XEN_CMD_XM and
550 3135de69 Guido Trotter
        not netutils.TcpPing(target, port, live_port_needed=True)):
551 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
552 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
553 50716be0 Iustin Pop
554 0625d08f René Nussbaumer
    args = [constants.XEN_CMD, "migrate"]
555 0625d08f René Nussbaumer
    if constants.XEN_CMD == constants.XEN_CMD_XM:
556 0625d08f René Nussbaumer
      args.extend(["-p", "%d" % port])
557 0625d08f René Nussbaumer
      if live:
558 0625d08f René Nussbaumer
        args.append("-l")
559 0625d08f René Nussbaumer
    elif constants.XEN_CMD == constants.XEN_CMD_XL:
560 053c356a Guido Trotter
      cluster_name = ssconf.SimpleStore().GetClusterName()
561 053c356a Guido Trotter
      args.extend(["-s", constants.XL_SSH_CMD % cluster_name])
562 0625d08f René Nussbaumer
      args.extend(["-C", self._ConfigFileName(instance.name)])
563 0625d08f René Nussbaumer
    else:
564 0625d08f René Nussbaumer
      raise errors.HypervisorError("Unsupported xen command: %s" %
565 0625d08f René Nussbaumer
                                   constants.XEN_CMD)
566 0625d08f René Nussbaumer
567 58d38b02 Iustin Pop
    args.extend([instance.name, target])
568 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
569 6e7275c0 Iustin Pop
    if result.failed:
570 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
571 58d38b02 Iustin Pop
                                   (instance.name, result.output))
572 60af751d Andrea Spadaccini
573 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
574 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
575 60af751d Andrea Spadaccini

576 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
577 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
578 60af751d Andrea Spadaccini
    @type success: bool
579 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
580 60af751d Andrea Spadaccini
    @type live: bool
581 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
582 60af751d Andrea Spadaccini

583 60af751d Andrea Spadaccini
    """
584 60af751d Andrea Spadaccini
    # pylint: disable=W0613
585 60af751d Andrea Spadaccini
    if success:
586 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
587 60af751d Andrea Spadaccini
      try:
588 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
589 60af751d Andrea Spadaccini
      except EnvironmentError:
590 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
591 60af751d Andrea Spadaccini
592 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
593 60af751d Andrea Spadaccini
    """Get the migration status
594 60af751d Andrea Spadaccini

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

599 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
600 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
601 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
602 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
603 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
604 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
605 60af751d Andrea Spadaccini

606 60af751d Andrea Spadaccini
    """
607 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
608 6e7275c0 Iustin Pop
609 f5118ade Iustin Pop
  @classmethod
610 f5118ade Iustin Pop
  def PowercycleNode(cls):
611 f5118ade Iustin Pop
    """Xen-specific powercycle.
612 f5118ade Iustin Pop

613 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
614 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
615 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
616 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
617 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
618 f5118ade Iustin Pop
    daemon is not working.
619 f5118ade Iustin Pop

620 f5118ade Iustin Pop
    """
621 f5118ade Iustin Pop
    try:
622 f5118ade Iustin Pop
      cls.LinuxPowercycle()
623 f5118ade Iustin Pop
    finally:
624 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
625 f5118ade Iustin Pop
626 65a6f9b7 Michael Hanselmann
627 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
628 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
629 65a6f9b7 Michael Hanselmann
630 205ab586 Iustin Pop
  PARAMETERS = {
631 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
632 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
633 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
634 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
635 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
636 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
637 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
638 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
639 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
640 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
641 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
642 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
643 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
644 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
645 2c368f28 Guido Trotter
    constants.HV_CPU_CAP: hv_base.OPT_NONNEGATIVE_INT_CHECK,
646 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
647 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65536, "invalid weight", None, None),
648 205ab586 Iustin Pop
    }
649 f48148c3 Iustin Pop
650 65a6f9b7 Michael Hanselmann
  @classmethod
651 61eb1a46 Guido Trotter
  def _WriteConfigFile(cls, instance, startup_memory, block_devices):
652 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
653 65a6f9b7 Michael Hanselmann

654 65a6f9b7 Michael Hanselmann
    """
655 a985b417 Iustin Pop
    hvp = instance.hvparams
656 65a6f9b7 Michael Hanselmann
    config = StringIO()
657 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
658 65a6f9b7 Michael Hanselmann
659 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
660 2f2dbb4b Jun Futagawa
    # parameters.
661 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
662 2f2dbb4b Jun Futagawa
      # bootloader handling
663 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
664 2f2dbb4b Jun Futagawa
      if bootloader_path:
665 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
666 2f2dbb4b Jun Futagawa
      else:
667 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
668 2f2dbb4b Jun Futagawa
                                     " bootloader path")
669 65a6f9b7 Michael Hanselmann
670 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
671 2f2dbb4b Jun Futagawa
      if bootloader_args:
672 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
673 2f2dbb4b Jun Futagawa
    else:
674 2f2dbb4b Jun Futagawa
      # kernel handling
675 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
676 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
677 2f2dbb4b Jun Futagawa
678 2f2dbb4b Jun Futagawa
      # initrd handling
679 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
680 2f2dbb4b Jun Futagawa
      if initrd_path:
681 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
682 65a6f9b7 Michael Hanselmann
683 65a6f9b7 Michael Hanselmann
    # rest of the settings
684 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
685 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
686 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
687 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
688 c4708267 Tsachy Shacham
    if cpu_pinning:
689 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
690 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
691 8bd977e9 Sébastien Bocahu
    if cpu_cap:
692 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
693 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
694 8bd977e9 Sébastien Bocahu
    if cpu_weight:
695 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
696 c4708267 Tsachy Shacham
697 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
698 65a6f9b7 Michael Hanselmann
699 65a6f9b7 Michael Hanselmann
    vif_data = []
700 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
701 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
702 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
703 65a6f9b7 Michael Hanselmann
      if ip is not None:
704 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
705 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
706 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
707 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
708 65a6f9b7 Michael Hanselmann
709 525011bc Maciej Bliziński
    disk_data = cls._GetConfigFileDiskData(block_devices,
710 525011bc Maciej Bliziński
                                           hvp[constants.HV_BLOCKDEV_PREFIX])
711 7ed85ffe Iustin Pop
712 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
713 7ed85ffe Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
714 074ca009 Guido Trotter
715 7adf7814 René Nussbaumer
    if hvp[constants.HV_ROOT_PATH]:
716 7adf7814 René Nussbaumer
      config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
717 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
718 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
719 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
720 990ade2d Stephen Shirley
    else:
721 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
722 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
723 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
724 1a63f285 Iustin Pop
    cls._WriteConfigFileStatic(instance.name, config.getvalue())
725 73cd67f4 Guido Trotter
726 65a6f9b7 Michael Hanselmann
    return True
727 65a6f9b7 Michael Hanselmann
728 65a6f9b7 Michael Hanselmann
729 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
730 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
731 65a6f9b7 Michael Hanselmann
732 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
733 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
734 69b99987 Michael Hanselmann
    ]
735 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
736 9d9bded1 Michael Hanselmann
    pathutils.VNC_PASSWORD_FILE,
737 69ab2e12 Guido Trotter
    ]
738 3680f662 Guido Trotter
739 205ab586 Iustin Pop
  PARAMETERS = {
740 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
741 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
742 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
743 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
744 016d04b3 Michael Hanselmann
       None, None),
745 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
746 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
747 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
748 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
749 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
750 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
751 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
752 8b312c1d Manuel Franceschini
      (False, netutils.IP4Address.IsValid,
753 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
754 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
755 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
756 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
757 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
758 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
759 6b970cef Jun Futagawa
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
760 e695efbf Iustin Pop
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
761 e695efbf Iustin Pop
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
762 87f0aa48 Jack
    # Add PCI passthrough
763 3891c95e Bernardo Dal Seno
    constants.HV_PASSTHROUGH: hv_base.NO_CHECK,
764 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
765 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
766 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
767 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_CAP: hv_base.NO_CHECK,
768 8bd977e9 Sébastien Bocahu
    constants.HV_CPU_WEIGHT:
769 8bd977e9 Sébastien Bocahu
      (False, lambda x: 0 < x < 65535, "invalid weight", None, None),
770 205ab586 Iustin Pop
    }
771 09ea8710 Iustin Pop
772 65a6f9b7 Michael Hanselmann
  @classmethod
773 61eb1a46 Guido Trotter
  def _WriteConfigFile(cls, instance, startup_memory, block_devices):
774 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
775 65a6f9b7 Michael Hanselmann

776 65a6f9b7 Michael Hanselmann
    """
777 a985b417 Iustin Pop
    hvp = instance.hvparams
778 a985b417 Iustin Pop
779 65a6f9b7 Michael Hanselmann
    config = StringIO()
780 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
781 e2ee1cea Iustin Pop
782 e2ee1cea Iustin Pop
    # kernel handling
783 e2ee1cea Iustin Pop
    kpath = hvp[constants.HV_KERNEL_PATH]
784 e2ee1cea Iustin Pop
    config.write("kernel = '%s'\n" % kpath)
785 e2ee1cea Iustin Pop
786 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
787 61eb1a46 Guido Trotter
    config.write("memory = %d\n" % startup_memory)
788 80121c83 Guido Trotter
    config.write("maxmem = %d\n" % instance.beparams[constants.BE_MAXMEM])
789 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
790 347fa0f1 Michael Hanselmann
    cpu_pinning = _CreateConfigCpus(hvp[constants.HV_CPU_MASK])
791 c4708267 Tsachy Shacham
    if cpu_pinning:
792 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
793 8bd977e9 Sébastien Bocahu
    cpu_cap = hvp[constants.HV_CPU_CAP]
794 8bd977e9 Sébastien Bocahu
    if cpu_cap:
795 8bd977e9 Sébastien Bocahu
      config.write("cpu_cap=%d\n" % cpu_cap)
796 8bd977e9 Sébastien Bocahu
    cpu_weight = hvp[constants.HV_CPU_WEIGHT]
797 8bd977e9 Sébastien Bocahu
    if cpu_weight:
798 8bd977e9 Sébastien Bocahu
      config.write("cpu_weight=%d\n" % cpu_weight)
799 c4708267 Tsachy Shacham
800 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
801 09ea8710 Iustin Pop
    if hvp[constants.HV_PAE]:
802 a21dda8b Iustin Pop
      config.write("pae = 1\n")
803 a21dda8b Iustin Pop
    else:
804 a21dda8b Iustin Pop
      config.write("pae = 0\n")
805 09ea8710 Iustin Pop
    if hvp[constants.HV_ACPI]:
806 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
807 a21dda8b Iustin Pop
    else:
808 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
809 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
810 09ea8710 Iustin Pop
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
811 a985b417 Iustin Pop
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
812 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
813 97efde45 Guido Trotter
    config.write("usb = 1\n")
814 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
815 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
816 a985b417 Iustin Pop
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
817 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
818 d0c11cf7 Alexander Schreiber
    else:
819 6b405598 Guido Trotter
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
820 65a6f9b7 Michael Hanselmann
821 377d74c9 Guido Trotter
    if instance.network_port > constants.VNC_BASE_PORT:
822 377d74c9 Guido Trotter
      display = instance.network_port - constants.VNC_BASE_PORT
823 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
824 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
825 65a6f9b7 Michael Hanselmann
    else:
826 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
827 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
828 65a6f9b7 Michael Hanselmann
829 6e6bb8d5 Guido Trotter
    vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
830 65a6f9b7 Michael Hanselmann
    try:
831 6e6bb8d5 Guido Trotter
      password = utils.ReadFile(vnc_pwd_file)
832 78f66a17 Guido Trotter
    except EnvironmentError, err:
833 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
834 6e6bb8d5 Guido Trotter
                                   (vnc_pwd_file, err))
835 65a6f9b7 Michael Hanselmann
836 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
837 65a6f9b7 Michael Hanselmann
838 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
839 6b970cef Jun Futagawa
    if hvp[constants.HV_USE_LOCALTIME]:
840 6b970cef Jun Futagawa
      config.write("localtime = 1\n")
841 65a6f9b7 Michael Hanselmann
842 65a6f9b7 Michael Hanselmann
    vif_data = []
843 a985b417 Iustin Pop
    nic_type = hvp[constants.HV_NIC_TYPE]
844 f48148c3 Iustin Pop
    if nic_type is None:
845 f48148c3 Iustin Pop
      # ensure old instances don't change
846 f48148c3 Iustin Pop
      nic_type_str = ", type=ioemu"
847 d08f6067 Guido Trotter
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
848 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
849 f48148c3 Iustin Pop
    else:
850 f48148c3 Iustin Pop
      nic_type_str = ", model=%s, type=ioemu" % nic_type
851 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
852 503b97a9 Guido Trotter
      nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
853 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
854 65a6f9b7 Michael Hanselmann
      if ip is not None:
855 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
856 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
857 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
858 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
859 65a6f9b7 Michael Hanselmann
860 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
861 525011bc Maciej Bliziński
862 525011bc Maciej Bliziński
    disk_data = cls._GetConfigFileDiskData(block_devices,
863 525011bc Maciej Bliziński
                                           hvp[constants.HV_BLOCKDEV_PREFIX])
864 525011bc Maciej Bliziński
865 a985b417 Iustin Pop
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
866 f48148c3 Iustin Pop
    if iso_path:
867 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
868 a21dda8b Iustin Pop
      disk_data.append(iso)
869 a21dda8b Iustin Pop
870 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
871 87f0aa48 Jack
    # Add PCI passthrough
872 87f0aa48 Jack
    pci_pass_arr = []
873 87f0aa48 Jack
    pci_pass = hvp[constants.HV_PASSTHROUGH]
874 87f0aa48 Jack
    if pci_pass:
875 3891c95e Bernardo Dal Seno
      pci_pass_arr = pci_pass.split(";")
876 3891c95e Bernardo Dal Seno
      config.write("pci = %s\n" % pci_pass_arr)
877 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
878 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
879 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
880 990ade2d Stephen Shirley
    else:
881 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
882 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
883 1a63f285 Iustin Pop
    cls._WriteConfigFileStatic(instance.name, config.getvalue())
884 73cd67f4 Guido Trotter
885 65a6f9b7 Michael Hanselmann
    return True