Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (29.8 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 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
47 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
48 65a6f9b7 Michael Hanselmann

49 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
50 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
51 65a6f9b7 Michael Hanselmann

52 65a6f9b7 Michael Hanselmann
  """
53 d271c6fd Iustin Pop
  CAN_MIGRATE = True
54 7dd106d3 Iustin Pop
  REBOOT_RETRY_COUNT = 60
55 7dd106d3 Iustin Pop
  REBOOT_RETRY_INTERVAL = 10
56 65a6f9b7 Michael Hanselmann
57 3680f662 Guido Trotter
  ANCILLARY_FILES = [
58 22d568c2 Guido Trotter
    XEND_CONFIG_FILE,
59 22d568c2 Guido Trotter
    XL_CONFIG_FILE,
60 22d568c2 Guido Trotter
    VIF_BRIDGE_SCRIPT,
61 3680f662 Guido Trotter
    ]
62 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = [
63 69ab2e12 Guido Trotter
    XL_CONFIG_FILE,
64 3680f662 Guido Trotter
    ]
65 3680f662 Guido Trotter
66 c2be2532 Guido Trotter
  @staticmethod
67 c2be2532 Guido Trotter
  def _ConfigFileName(instance_name):
68 c2be2532 Guido Trotter
    """Get the config file name for an instance.
69 c2be2532 Guido Trotter

70 c2be2532 Guido Trotter
    @param instance_name: instance name
71 c2be2532 Guido Trotter
    @type instance_name: str
72 c2be2532 Guido Trotter
    @return: fully qualified path to instance config file
73 c2be2532 Guido Trotter
    @rtype: str
74 c2be2532 Guido Trotter

75 c2be2532 Guido Trotter
    """
76 a8e8c0c6 Michael Hanselmann
    return utils.PathJoin(pathutils.XEN_CONFIG_DIR, instance_name)
77 c2be2532 Guido Trotter
78 5661b908 Iustin Pop
  @classmethod
79 61eb1a46 Guido Trotter
  def _WriteConfigFile(cls, instance, startup_memory, block_devices):
80 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
81 65a6f9b7 Michael Hanselmann

82 65a6f9b7 Michael Hanselmann
    """
83 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
84 65a6f9b7 Michael Hanselmann
85 65a6f9b7 Michael Hanselmann
  @staticmethod
86 4390ccff Guido Trotter
  def _WriteConfigFileStatic(instance_name, data):
87 4390ccff Guido Trotter
    """Write the Xen config file for the instance.
88 4390ccff Guido Trotter

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

91 4390ccff Guido Trotter
    """
92 1a63f285 Iustin Pop
    # just in case it exists
93 a8e8c0c6 Michael Hanselmann
    utils.RemoveFile(utils.PathJoin(pathutils.XEN_CONFIG_DIR, "auto",
94 a8e8c0c6 Michael Hanselmann
                                    instance_name))
95 a8e8c0c6 Michael Hanselmann
96 1a63f285 Iustin Pop
    cfg_file = XenHypervisor._ConfigFileName(instance_name)
97 1a63f285 Iustin Pop
    try:
98 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
99 1a63f285 Iustin Pop
    except EnvironmentError, err:
100 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
101 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
102 4390ccff Guido Trotter
103 4390ccff Guido Trotter
  @staticmethod
104 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
105 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
106 4390ccff Guido Trotter

107 4390ccff Guido Trotter
    """
108 4390ccff Guido Trotter
    try:
109 c2be2532 Guido Trotter
      file_content = utils.ReadFile(
110 c2be2532 Guido Trotter
                       XenHypervisor._ConfigFileName(instance_name))
111 4390ccff Guido Trotter
    except EnvironmentError, err:
112 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
113 4390ccff Guido Trotter
    return file_content
114 4390ccff Guido Trotter
115 4390ccff Guido Trotter
  @staticmethod
116 53c776b5 Iustin Pop
  def _RemoveConfigFile(instance_name):
117 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
118 65a6f9b7 Michael Hanselmann

119 65a6f9b7 Michael Hanselmann
    """
120 c2be2532 Guido Trotter
    utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
121 65a6f9b7 Michael Hanselmann
122 c4708267 Tsachy Shacham
  @classmethod
123 c4708267 Tsachy Shacham
  def _CreateConfigCpus(cls, cpu_mask):
124 c4708267 Tsachy Shacham
    """Create a CPU config string that's compatible with Xen's
125 c4708267 Tsachy Shacham
    configuration file.
126 c4708267 Tsachy Shacham

127 c4708267 Tsachy Shacham
    """
128 c4708267 Tsachy Shacham
    # Convert the string CPU mask to a list of list of int's
129 c4708267 Tsachy Shacham
    cpu_list = utils.ParseMultiCpuMask(cpu_mask)
130 c4708267 Tsachy Shacham
131 c4708267 Tsachy Shacham
    if len(cpu_list) == 1:
132 c4708267 Tsachy Shacham
      all_cpu_mapping = cpu_list[0]
133 5b43cc23 Tsachy Shacham
      if all_cpu_mapping == constants.CPU_PINNING_OFF:
134 c4708267 Tsachy Shacham
        # If CPU pinning has 1 entry that's "all", then remove the
135 c4708267 Tsachy Shacham
        # parameter from the config file
136 c4708267 Tsachy Shacham
        return None
137 c4708267 Tsachy Shacham
      else:
138 c4708267 Tsachy Shacham
        # If CPU pinning has one non-all entry, mapping all vCPUS (the entire
139 c4708267 Tsachy Shacham
        # VM) to one physical CPU, using format 'cpu = "C"'
140 c4708267 Tsachy Shacham
        return "cpu = \"%s\"" % ",".join(map(str, all_cpu_mapping))
141 c4708267 Tsachy Shacham
    else:
142 3c286190 Dimitris Aragiorgis
143 c4708267 Tsachy Shacham
      def _GetCPUMap(vcpu):
144 c4708267 Tsachy Shacham
        if vcpu[0] == constants.CPU_PINNING_ALL_VAL:
145 c4708267 Tsachy Shacham
          cpu_map = constants.CPU_PINNING_ALL_XEN
146 c4708267 Tsachy Shacham
        else:
147 c4708267 Tsachy Shacham
          cpu_map = ",".join(map(str, vcpu))
148 c4708267 Tsachy Shacham
        return "\"%s\"" % cpu_map
149 c4708267 Tsachy Shacham
150 c4708267 Tsachy Shacham
      # build the result string in format 'cpus = [ "c", "c", "c" ]',
151 c4708267 Tsachy Shacham
      # where each c is a physical CPU number, a range, a list, or any
152 c4708267 Tsachy Shacham
      # combination
153 c4708267 Tsachy Shacham
      return "cpus = [ %s ]" % ", ".join(map(_GetCPUMap, cpu_list))
154 c4708267 Tsachy Shacham
155 65a6f9b7 Michael Hanselmann
  @staticmethod
156 06b78e8b Michael Hanselmann
  def _RunXmList(xmlist_errors):
157 06b78e8b Michael Hanselmann
    """Helper function for L{_GetXMList} to run "xm list".
158 06b78e8b Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

322 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
323 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
324 2c7a0373 Guido Trotter
    @type mem: int
325 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
326 2c7a0373 Guido Trotter

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

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

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

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

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

437 65a6f9b7 Michael Hanselmann
    """
438 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
439 e3e66f02 Michael Hanselmann
    if result.failed:
440 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
441 65a6f9b7 Michael Hanselmann
442 65a6f9b7 Michael Hanselmann
  @staticmethod
443 525011bc Maciej Bliziński
  def _GetConfigFileDiskData(block_devices, blockdev_prefix):
444 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
445 65a6f9b7 Michael Hanselmann

446 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
447 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
448 65a6f9b7 Michael Hanselmann

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

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

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

484 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
485 4390ccff Guido Trotter
    @param instance: instance to be migrated
486 4390ccff Guido Trotter
    @rtype: string
487 4390ccff Guido Trotter
    @return: content of the xen config file
488 4390ccff Guido Trotter

489 4390ccff Guido Trotter
    """
490 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
491 4390ccff Guido Trotter
492 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
493 4390ccff Guido Trotter
    """Prepare to accept an instance.
494 4390ccff Guido Trotter

495 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
496 4390ccff Guido Trotter
    @param instance: instance to be accepted
497 4390ccff Guido Trotter
    @type info: string
498 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
499 4390ccff Guido Trotter
    @type target: string
500 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
501 4390ccff Guido Trotter

502 4390ccff Guido Trotter
    """
503 4390ccff Guido Trotter
    pass
504 4390ccff Guido Trotter
505 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
506 4390ccff Guido Trotter
    """Finalize an instance migration.
507 4390ccff Guido Trotter

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

511 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
512 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
513 4390ccff Guido Trotter
    @type info: string
514 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
515 4390ccff Guido Trotter
    @type success: boolean
516 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
517 4390ccff Guido Trotter

518 4390ccff Guido Trotter
    """
519 4390ccff Guido Trotter
    if success:
520 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
521 4390ccff Guido Trotter
522 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
523 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
524 6e7275c0 Iustin Pop

525 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
526 6e7275c0 Iustin Pop
    currently running.
527 6e7275c0 Iustin Pop

528 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
529 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
530 fdf7f055 Guido Trotter
    @type target: string
531 fdf7f055 Guido Trotter
    @param target: ip address of the target node
532 fdf7f055 Guido Trotter
    @type live: boolean
533 fdf7f055 Guido Trotter
    @param live: perform a live migration
534 fdf7f055 Guido Trotter

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

568 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
569 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
570 60af751d Andrea Spadaccini
    @type success: bool
571 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
572 60af751d Andrea Spadaccini
    @type live: bool
573 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
574 60af751d Andrea Spadaccini

575 60af751d Andrea Spadaccini
    """
576 60af751d Andrea Spadaccini
    # pylint: disable=W0613
577 60af751d Andrea Spadaccini
    if success:
578 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
579 60af751d Andrea Spadaccini
      try:
580 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
581 60af751d Andrea Spadaccini
      except EnvironmentError:
582 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
583 60af751d Andrea Spadaccini
584 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
585 60af751d Andrea Spadaccini
    """Get the migration status
586 60af751d Andrea Spadaccini

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

591 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
592 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
593 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
594 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
595 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
596 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
597 60af751d Andrea Spadaccini

598 60af751d Andrea Spadaccini
    """
599 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
600 6e7275c0 Iustin Pop
601 f5118ade Iustin Pop
  @classmethod
602 f5118ade Iustin Pop
  def PowercycleNode(cls):
603 f5118ade Iustin Pop
    """Xen-specific powercycle.
604 f5118ade Iustin Pop

605 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
606 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
607 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
608 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
609 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
610 f5118ade Iustin Pop
    daemon is not working.
611 f5118ade Iustin Pop

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

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

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