Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 0e1e0b6a

History | View | Annotate | Download (28.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 65a6f9b7 Michael Hanselmann
37 65a6f9b7 Michael Hanselmann
38 22d568c2 Guido Trotter
XEND_CONFIG_FILE = "/etc/xen/xend-config.sxp"
39 22d568c2 Guido Trotter
XL_CONFIG_FILE = "/etc/xen/xl.conf"
40 22d568c2 Guido Trotter
VIF_BRIDGE_SCRIPT = "/etc/xen/scripts/vif-bridge"
41 18bf85b1 Michael Hanselmann
_DOM0_NAME = "Domain-0"
42 22d568c2 Guido Trotter
43 22d568c2 Guido Trotter
44 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
45 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
46 65a6f9b7 Michael Hanselmann

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

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

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

73 c2be2532 Guido Trotter
    """
74 c2be2532 Guido Trotter
    return "/etc/xen/%s" % instance_name
75 c2be2532 Guido Trotter
76 5661b908 Iustin Pop
  @classmethod
77 61eb1a46 Guido Trotter
  def _WriteConfigFile(cls, instance, startup_memory, block_devices):
78 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
79 65a6f9b7 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

224 c41eea6e Iustin Pop
    @param instance_name: the instance name
225 c41eea6e Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

419 65a6f9b7 Michael Hanselmann
    """
420 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
421 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
422 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
423 55cc0a44 Michael Hanselmann
                                   user=constants.GANETI_RUNAS,
424 9d9bded1 Michael Hanselmann
                                   command=[pathutils.XM_CONSOLE_WRAPPER,
425 61631293 Stephen Shirley
                                            instance.name])
426 65a6f9b7 Michael Hanselmann
427 65a6f9b7 Michael Hanselmann
  def Verify(self):
428 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
429 65a6f9b7 Michael Hanselmann

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

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

441 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
442 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
443 65a6f9b7 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

520 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
521 6e7275c0 Iustin Pop
    currently running.
522 6e7275c0 Iustin Pop

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

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

563 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
564 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
565 60af751d Andrea Spadaccini
    @type success: bool
566 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
567 60af751d Andrea Spadaccini
    @type live: bool
568 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
569 60af751d Andrea Spadaccini

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

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

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

593 60af751d Andrea Spadaccini
    """
594 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
595 6e7275c0 Iustin Pop
596 f5118ade Iustin Pop
  @classmethod
597 f5118ade Iustin Pop
  def PowercycleNode(cls):
598 f5118ade Iustin Pop
    """Xen-specific powercycle.
599 f5118ade Iustin Pop

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

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

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

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