Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 61e062dd

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 cffbbae7 Michael Hanselmann
from ganeti import vcluster
37 053c356a Guido Trotter
from ganeti import ssconf
38 65a6f9b7 Michael Hanselmann
39 65a6f9b7 Michael Hanselmann
40 cffbbae7 Michael Hanselmann
XEND_CONFIG_FILE = vcluster.AddNodePrefix("/etc/xen/xend-config.sxp")
41 cffbbae7 Michael Hanselmann
XL_CONFIG_FILE = vcluster.AddNodePrefix("/etc/xen/xl.conf")
42 cffbbae7 Michael Hanselmann
VIF_BRIDGE_SCRIPT = vcluster.AddNodePrefix("/etc/xen/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 c2be2532 Guido Trotter
    return "/etc/xen/%s" % 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 1a63f285 Iustin Pop
    utils.RemoveFile("/etc/xen/auto/%s" % instance_name)
94 1a63f285 Iustin Pop
    cfg_file = XenHypervisor._ConfigFileName(instance_name)
95 1a63f285 Iustin Pop
    try:
96 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
97 1a63f285 Iustin Pop
    except EnvironmentError, err:
98 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
99 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
100 4390ccff Guido Trotter
101 4390ccff Guido Trotter
  @staticmethod
102 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
103 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
104 4390ccff Guido Trotter

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

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

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

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

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

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

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

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

227 c41eea6e Iustin Pop
    @param instance_name: the instance name
228 c41eea6e Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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