Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 1d60fec6

History | View | Annotate | Download (27.1 kB)

1 65a6f9b7 Michael Hanselmann
#
2 65a6f9b7 Michael Hanselmann
#
3 65a6f9b7 Michael Hanselmann
4 783a6c0b Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 65a6f9b7 Michael Hanselmann
36 65a6f9b7 Michael Hanselmann
37 22d568c2 Guido Trotter
XEND_CONFIG_FILE = "/etc/xen/xend-config.sxp"
38 22d568c2 Guido Trotter
XL_CONFIG_FILE = "/etc/xen/xl.conf"
39 22d568c2 Guido Trotter
VIF_BRIDGE_SCRIPT = "/etc/xen/scripts/vif-bridge"
40 18bf85b1 Michael Hanselmann
_DOM0_NAME = "Domain-0"
41 22d568c2 Guido Trotter
42 22d568c2 Guido Trotter
43 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
44 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
45 65a6f9b7 Michael Hanselmann

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

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

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

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

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

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

88 4390ccff Guido Trotter
    """
89 c2be2532 Guido Trotter
    utils.WriteFile(XenHypervisor._ConfigFileName(instance_name), data=data)
90 4390ccff Guido Trotter
91 4390ccff Guido Trotter
  @staticmethod
92 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
93 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
94 4390ccff Guido Trotter

95 4390ccff Guido Trotter
    """
96 4390ccff Guido Trotter
    try:
97 c2be2532 Guido Trotter
      file_content = utils.ReadFile(
98 c2be2532 Guido Trotter
                       XenHypervisor._ConfigFileName(instance_name))
99 4390ccff Guido Trotter
    except EnvironmentError, err:
100 4390ccff Guido Trotter
      raise errors.HypervisorError("Failed to load Xen config file: %s" % err)
101 4390ccff Guido Trotter
    return file_content
102 4390ccff Guido Trotter
103 4390ccff Guido Trotter
  @staticmethod
104 53c776b5 Iustin Pop
  def _RemoveConfigFile(instance_name):
105 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
106 65a6f9b7 Michael Hanselmann

107 65a6f9b7 Michael Hanselmann
    """
108 c2be2532 Guido Trotter
    utils.RemoveFile(XenHypervisor._ConfigFileName(instance_name))
109 65a6f9b7 Michael Hanselmann
110 c4708267 Tsachy Shacham
  @classmethod
111 c4708267 Tsachy Shacham
  def _CreateConfigCpus(cls, cpu_mask):
112 c4708267 Tsachy Shacham
    """Create a CPU config string that's compatible with Xen's
113 c4708267 Tsachy Shacham
    configuration file.
114 c4708267 Tsachy Shacham

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

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

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

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

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

208 65a6f9b7 Michael Hanselmann
    """
209 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
210 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
211 65a6f9b7 Michael Hanselmann
    return names
212 65a6f9b7 Michael Hanselmann
213 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
214 65a6f9b7 Michael Hanselmann
    """Get instance properties.
215 65a6f9b7 Michael Hanselmann

216 c41eea6e Iustin Pop
    @param instance_name: the instance name
217 c41eea6e Iustin Pop

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

220 65a6f9b7 Michael Hanselmann
    """
221 18bf85b1 Michael Hanselmann
    xm_list = self._GetXMList(instance_name == _DOM0_NAME)
222 65a6f9b7 Michael Hanselmann
    result = None
223 65a6f9b7 Michael Hanselmann
    for data in xm_list:
224 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
225 65a6f9b7 Michael Hanselmann
        result = data
226 65a6f9b7 Michael Hanselmann
        break
227 65a6f9b7 Michael Hanselmann
    return result
228 65a6f9b7 Michael Hanselmann
229 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
230 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
231 65a6f9b7 Michael Hanselmann

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

234 65a6f9b7 Michael Hanselmann
    """
235 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
236 65a6f9b7 Michael Hanselmann
    return xm_list
237 65a6f9b7 Michael Hanselmann
238 323f9095 Stephen Shirley
  def StartInstance(self, instance, block_devices, startup_paused):
239 c41eea6e Iustin Pop
    """Start an instance.
240 c41eea6e Iustin Pop

241 c41eea6e Iustin Pop
    """
242 07813a9e Iustin Pop
    self._WriteConfigFile(instance, block_devices)
243 2876c2d6 Guido Trotter
    cmd = [constants.XEN_CMD, "create"]
244 323f9095 Stephen Shirley
    if startup_paused:
245 6555373d Guido Trotter
      cmd.extend(["-p"])
246 6555373d Guido Trotter
    cmd.extend([self._ConfigFileName(instance.name)])
247 323f9095 Stephen Shirley
    result = utils.RunCmd(cmd)
248 65a6f9b7 Michael Hanselmann
249 65a6f9b7 Michael Hanselmann
    if result.failed:
250 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
251 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
252 65a6f9b7 Michael Hanselmann
                                    result.output))
253 65a6f9b7 Michael Hanselmann
254 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
255 c41eea6e Iustin Pop
    """Stop an instance.
256 c41eea6e Iustin Pop

257 c41eea6e Iustin Pop
    """
258 bbcf7ad0 Iustin Pop
    if name is None:
259 bbcf7ad0 Iustin Pop
      name = instance.name
260 bbcf7ad0 Iustin Pop
    self._RemoveConfigFile(name)
261 65a6f9b7 Michael Hanselmann
    if force:
262 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "destroy", name]
263 65a6f9b7 Michael Hanselmann
    else:
264 2876c2d6 Guido Trotter
      command = [constants.XEN_CMD, "shutdown", name]
265 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
266 65a6f9b7 Michael Hanselmann
267 65a6f9b7 Michael Hanselmann
    if result.failed:
268 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to stop instance %s: %s, %s" %
269 bbcf7ad0 Iustin Pop
                                   (name, result.fail_reason, result.output))
270 65a6f9b7 Michael Hanselmann
271 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
272 c41eea6e Iustin Pop
    """Reboot an instance.
273 c41eea6e Iustin Pop

274 c41eea6e Iustin Pop
    """
275 7dd106d3 Iustin Pop
    ini_info = self.GetInstanceInfo(instance.name)
276 65a6f9b7 Michael Hanselmann
277 e0561198 Iustin Pop
    if ini_info is None:
278 e0561198 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s,"
279 e0561198 Iustin Pop
                                   " not running" % instance.name)
280 e0561198 Iustin Pop
281 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "reboot", instance.name])
282 65a6f9b7 Michael Hanselmann
    if result.failed:
283 3213d3c8 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: %s, %s" %
284 3213d3c8 Iustin Pop
                                   (instance.name, result.fail_reason,
285 3213d3c8 Iustin Pop
                                    result.output))
286 06b78e8b Michael Hanselmann
287 06b78e8b Michael Hanselmann
    def _CheckInstance():
288 7dd106d3 Iustin Pop
      new_info = self.GetInstanceInfo(instance.name)
289 06b78e8b Michael Hanselmann
290 06b78e8b Michael Hanselmann
      # check if the domain ID has changed or the run time has decreased
291 e0561198 Iustin Pop
      if (new_info is not None and
292 e0561198 Iustin Pop
          (new_info[1] != ini_info[1] or new_info[5] < ini_info[5])):
293 06b78e8b Michael Hanselmann
        return
294 7dd106d3 Iustin Pop
295 06b78e8b Michael Hanselmann
      raise utils.RetryAgain()
296 06b78e8b Michael Hanselmann
297 06b78e8b Michael Hanselmann
    try:
298 06b78e8b Michael Hanselmann
      utils.Retry(_CheckInstance, self.REBOOT_RETRY_INTERVAL,
299 06b78e8b Michael Hanselmann
                  self.REBOOT_RETRY_INTERVAL * self.REBOOT_RETRY_COUNT)
300 06b78e8b Michael Hanselmann
    except utils.RetryTimeout:
301 7dd106d3 Iustin Pop
      raise errors.HypervisorError("Failed to reboot instance %s: instance"
302 7dd106d3 Iustin Pop
                                   " did not reboot in the expected interval" %
303 7dd106d3 Iustin Pop
                                   (instance.name, ))
304 65a6f9b7 Michael Hanselmann
305 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
306 65a6f9b7 Michael Hanselmann
    """Return information about the node.
307 65a6f9b7 Michael Hanselmann

308 0105bad3 Iustin Pop
    @return: a dict with the following keys (memory values in MiB):
309 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
310 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
311 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
312 0105bad3 Iustin Pop
          - nr_cpus: total number of CPUs
313 0105bad3 Iustin Pop
          - nr_nodes: in a NUMA system, the number of domains
314 0105bad3 Iustin Pop
          - nr_sockets: the number of physical CPU sockets in the node
315 34fbc862 Andrea Spadaccini
          - hv_version: the hypervisor version in the form (major, minor)
316 65a6f9b7 Michael Hanselmann

317 65a6f9b7 Michael Hanselmann
    """
318 65a6f9b7 Michael Hanselmann
    # note: in xen 3, memory has changed to total_memory
319 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
320 65a6f9b7 Michael Hanselmann
    if result.failed:
321 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
322 b48909c8 Iustin Pop
                    result.output)
323 65a6f9b7 Michael Hanselmann
      return None
324 65a6f9b7 Michael Hanselmann
325 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
326 65a6f9b7 Michael Hanselmann
    result = {}
327 0105bad3 Iustin Pop
    cores_per_socket = threads_per_core = nr_cpus = None
328 34fbc862 Andrea Spadaccini
    xen_major, xen_minor = None, None
329 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
330 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
331 65a6f9b7 Michael Hanselmann
332 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
333 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
334 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
335 d0c8c01d Iustin Pop
        if key == "memory" or key == "total_memory":
336 d0c8c01d Iustin Pop
          result["memory_total"] = int(val)
337 d0c8c01d Iustin Pop
        elif key == "free_memory":
338 d0c8c01d Iustin Pop
          result["memory_free"] = int(val)
339 d0c8c01d Iustin Pop
        elif key == "nr_cpus":
340 d0c8c01d Iustin Pop
          nr_cpus = result["cpu_total"] = int(val)
341 d0c8c01d Iustin Pop
        elif key == "nr_nodes":
342 d0c8c01d Iustin Pop
          result["cpu_nodes"] = int(val)
343 d0c8c01d Iustin Pop
        elif key == "cores_per_socket":
344 0105bad3 Iustin Pop
          cores_per_socket = int(val)
345 d0c8c01d Iustin Pop
        elif key == "threads_per_core":
346 0105bad3 Iustin Pop
          threads_per_core = int(val)
347 34fbc862 Andrea Spadaccini
        elif key == "xen_major":
348 34fbc862 Andrea Spadaccini
          xen_major = int(val)
349 34fbc862 Andrea Spadaccini
        elif key == "xen_minor":
350 34fbc862 Andrea Spadaccini
          xen_minor = int(val)
351 0105bad3 Iustin Pop
352 0105bad3 Iustin Pop
    if (cores_per_socket is not None and
353 0105bad3 Iustin Pop
        threads_per_core is not None and nr_cpus is not None):
354 d0c8c01d Iustin Pop
      result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
355 0105bad3 Iustin Pop
356 18bf85b1 Michael Hanselmann
    dom0_info = self.GetInstanceInfo(_DOM0_NAME)
357 65a6f9b7 Michael Hanselmann
    if dom0_info is not None:
358 d0c8c01d Iustin Pop
      result["memory_dom0"] = dom0_info[2]
359 1d60fec6 Michael Hanselmann
      result["dom0_cpus"] = dom0_info[3]
360 65a6f9b7 Michael Hanselmann
361 34fbc862 Andrea Spadaccini
    if not (xen_major is None or xen_minor is None):
362 34fbc862 Andrea Spadaccini
      result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
363 34fbc862 Andrea Spadaccini
364 65a6f9b7 Michael Hanselmann
    return result
365 65a6f9b7 Michael Hanselmann
366 637ce7f9 Guido Trotter
  @classmethod
367 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
368 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
369 65a6f9b7 Michael Hanselmann

370 65a6f9b7 Michael Hanselmann
    """
371 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
372 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
373 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
374 55cc0a44 Michael Hanselmann
                                   user=constants.GANETI_RUNAS,
375 61631293 Stephen Shirley
                                   command=[constants.XM_CONSOLE_WRAPPER,
376 61631293 Stephen Shirley
                                            instance.name])
377 65a6f9b7 Michael Hanselmann
378 65a6f9b7 Michael Hanselmann
  def Verify(self):
379 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
380 65a6f9b7 Michael Hanselmann

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

383 65a6f9b7 Michael Hanselmann
    """
384 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
385 e3e66f02 Michael Hanselmann
    if result.failed:
386 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
387 65a6f9b7 Michael Hanselmann
388 65a6f9b7 Michael Hanselmann
  @staticmethod
389 525011bc Maciej Bliziński
  def _GetConfigFileDiskData(block_devices, blockdev_prefix):
390 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
391 65a6f9b7 Michael Hanselmann

392 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
393 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
394 65a6f9b7 Michael Hanselmann

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

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

403 65a6f9b7 Michael Hanselmann
    """
404 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
405 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
406 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
407 65a6f9b7 Michael Hanselmann
      }
408 65a6f9b7 Michael Hanselmann
    disk_data = []
409 2864f2d9 Iustin Pop
    if len(block_devices) > 24:
410 2864f2d9 Iustin Pop
      # 'z' - 'a' = 24
411 2864f2d9 Iustin Pop
      raise errors.HypervisorError("Too many disks")
412 d0c8c01d Iustin Pop
    namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
413 069cfbf1 Iustin Pop
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
414 d34b16d7 Iustin Pop
      if cfdev.mode == constants.DISK_RDWR:
415 d34b16d7 Iustin Pop
        mode = "w"
416 d34b16d7 Iustin Pop
      else:
417 d34b16d7 Iustin Pop
        mode = "r"
418 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
419 d34b16d7 Iustin Pop
        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
420 d34b16d7 Iustin Pop
                                  dev_path, sd_name, mode)
421 65a6f9b7 Michael Hanselmann
      else:
422 d34b16d7 Iustin Pop
        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
423 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
424 65a6f9b7 Michael Hanselmann
425 65a6f9b7 Michael Hanselmann
    return disk_data
426 65a6f9b7 Michael Hanselmann
427 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
428 4390ccff Guido Trotter
    """Get instance information to perform a migration.
429 4390ccff Guido Trotter

430 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
431 4390ccff Guido Trotter
    @param instance: instance to be migrated
432 4390ccff Guido Trotter
    @rtype: string
433 4390ccff Guido Trotter
    @return: content of the xen config file
434 4390ccff Guido Trotter

435 4390ccff Guido Trotter
    """
436 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
437 4390ccff Guido Trotter
438 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
439 4390ccff Guido Trotter
    """Prepare to accept an instance.
440 4390ccff Guido Trotter

441 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
442 4390ccff Guido Trotter
    @param instance: instance to be accepted
443 4390ccff Guido Trotter
    @type info: string
444 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
445 4390ccff Guido Trotter
    @type target: string
446 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
447 4390ccff Guido Trotter

448 4390ccff Guido Trotter
    """
449 4390ccff Guido Trotter
    pass
450 4390ccff Guido Trotter
451 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
452 4390ccff Guido Trotter
    """Finalize an instance migration.
453 4390ccff Guido Trotter

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

457 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
458 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
459 4390ccff Guido Trotter
    @type info: string
460 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
461 4390ccff Guido Trotter
    @type success: boolean
462 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
463 4390ccff Guido Trotter

464 4390ccff Guido Trotter
    """
465 4390ccff Guido Trotter
    if success:
466 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
467 4390ccff Guido Trotter
468 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
469 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
470 6e7275c0 Iustin Pop

471 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
472 6e7275c0 Iustin Pop
    currently running.
473 6e7275c0 Iustin Pop

474 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
475 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
476 fdf7f055 Guido Trotter
    @type target: string
477 fdf7f055 Guido Trotter
    @param target: ip address of the target node
478 fdf7f055 Guido Trotter
    @type live: boolean
479 fdf7f055 Guido Trotter
    @param live: perform a live migration
480 fdf7f055 Guido Trotter

481 6e7275c0 Iustin Pop
    """
482 58d38b02 Iustin Pop
    if self.GetInstanceInfo(instance.name) is None:
483 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
484 50716be0 Iustin Pop
485 641ae041 Iustin Pop
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
486 50716be0 Iustin Pop
487 a744b676 Manuel Franceschini
    if not netutils.TcpPing(target, port, live_port_needed=True):
488 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
489 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
490 50716be0 Iustin Pop
491 6555373d Guido Trotter
    # FIXME: migrate must be upgraded for transitioning to "xl" (xen 4.1).
492 6555373d Guido Trotter
    #  -l doesn't exist anymore
493 6555373d Guido Trotter
    #  -p doesn't exist anymore
494 6555373d Guido Trotter
    #  -C config_file must be passed
495 6555373d Guido Trotter
    #  ssh must recognize the key of the target host for the migration
496 2876c2d6 Guido Trotter
    args = [constants.XEN_CMD, "migrate", "-p", "%d" % port]
497 6e7275c0 Iustin Pop
    if live:
498 6e7275c0 Iustin Pop
      args.append("-l")
499 58d38b02 Iustin Pop
    args.extend([instance.name, target])
500 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
501 6e7275c0 Iustin Pop
    if result.failed:
502 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
503 58d38b02 Iustin Pop
                                   (instance.name, result.output))
504 60af751d Andrea Spadaccini
505 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
506 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
507 60af751d Andrea Spadaccini

508 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
509 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
510 60af751d Andrea Spadaccini
    @type success: bool
511 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
512 60af751d Andrea Spadaccini
    @type live: bool
513 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
514 60af751d Andrea Spadaccini

515 60af751d Andrea Spadaccini
    """
516 60af751d Andrea Spadaccini
    # pylint: disable=W0613
517 60af751d Andrea Spadaccini
    if success:
518 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
519 60af751d Andrea Spadaccini
      try:
520 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
521 60af751d Andrea Spadaccini
      except EnvironmentError:
522 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
523 60af751d Andrea Spadaccini
524 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
525 60af751d Andrea Spadaccini
    """Get the migration status
526 60af751d Andrea Spadaccini

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

531 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
532 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
533 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
534 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
535 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
536 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
537 60af751d Andrea Spadaccini

538 60af751d Andrea Spadaccini
    """
539 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
540 6e7275c0 Iustin Pop
541 f5118ade Iustin Pop
  @classmethod
542 f5118ade Iustin Pop
  def PowercycleNode(cls):
543 f5118ade Iustin Pop
    """Xen-specific powercycle.
544 f5118ade Iustin Pop

545 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
546 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
547 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
548 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
549 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
550 f5118ade Iustin Pop
    daemon is not working.
551 f5118ade Iustin Pop

552 f5118ade Iustin Pop
    """
553 f5118ade Iustin Pop
    try:
554 f5118ade Iustin Pop
      cls.LinuxPowercycle()
555 f5118ade Iustin Pop
    finally:
556 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
557 f5118ade Iustin Pop
558 65a6f9b7 Michael Hanselmann
559 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
560 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
561 65a6f9b7 Michael Hanselmann
562 205ab586 Iustin Pop
  PARAMETERS = {
563 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
564 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
565 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
566 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
567 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
568 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
569 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
570 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
571 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
572 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
573 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
574 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
575 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
576 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
577 205ab586 Iustin Pop
    }
578 f48148c3 Iustin Pop
579 65a6f9b7 Michael Hanselmann
  @classmethod
580 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
581 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
582 65a6f9b7 Michael Hanselmann

583 65a6f9b7 Michael Hanselmann
    """
584 a985b417 Iustin Pop
    hvp = instance.hvparams
585 65a6f9b7 Michael Hanselmann
    config = StringIO()
586 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
587 65a6f9b7 Michael Hanselmann
588 2f2dbb4b Jun Futagawa
    # if bootloader is True, use bootloader instead of kernel and ramdisk
589 2f2dbb4b Jun Futagawa
    # parameters.
590 2f2dbb4b Jun Futagawa
    if hvp[constants.HV_USE_BOOTLOADER]:
591 2f2dbb4b Jun Futagawa
      # bootloader handling
592 2f2dbb4b Jun Futagawa
      bootloader_path = hvp[constants.HV_BOOTLOADER_PATH]
593 2f2dbb4b Jun Futagawa
      if bootloader_path:
594 2f2dbb4b Jun Futagawa
        config.write("bootloader = '%s'\n" % bootloader_path)
595 2f2dbb4b Jun Futagawa
      else:
596 2f2dbb4b Jun Futagawa
        raise errors.HypervisorError("Bootloader enabled, but missing"
597 2f2dbb4b Jun Futagawa
                                     " bootloader path")
598 65a6f9b7 Michael Hanselmann
599 2f2dbb4b Jun Futagawa
      bootloader_args = hvp[constants.HV_BOOTLOADER_ARGS]
600 2f2dbb4b Jun Futagawa
      if bootloader_args:
601 2f2dbb4b Jun Futagawa
        config.write("bootargs = '%s'\n" % bootloader_args)
602 2f2dbb4b Jun Futagawa
    else:
603 2f2dbb4b Jun Futagawa
      # kernel handling
604 2f2dbb4b Jun Futagawa
      kpath = hvp[constants.HV_KERNEL_PATH]
605 2f2dbb4b Jun Futagawa
      config.write("kernel = '%s'\n" % kpath)
606 2f2dbb4b Jun Futagawa
607 2f2dbb4b Jun Futagawa
      # initrd handling
608 2f2dbb4b Jun Futagawa
      initrd_path = hvp[constants.HV_INITRD_PATH]
609 2f2dbb4b Jun Futagawa
      if initrd_path:
610 2f2dbb4b Jun Futagawa
        config.write("ramdisk = '%s'\n" % initrd_path)
611 65a6f9b7 Michael Hanselmann
612 65a6f9b7 Michael Hanselmann
    # rest of the settings
613 f5a4b9ce Guido Trotter
    config.write("memory = %d\n" % instance.beparams[constants.BE_MAXMEM])
614 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
615 c4708267 Tsachy Shacham
    cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
616 c4708267 Tsachy Shacham
    if cpu_pinning:
617 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
618 c4708267 Tsachy Shacham
619 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
620 65a6f9b7 Michael Hanselmann
621 65a6f9b7 Michael Hanselmann
    vif_data = []
622 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
623 503b97a9 Guido Trotter
      nic_str = "mac=%s" % (nic.mac)
624 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
625 65a6f9b7 Michael Hanselmann
      if ip is not None:
626 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
627 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
628 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
629 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
630 65a6f9b7 Michael Hanselmann
631 525011bc Maciej Bliziński
    disk_data = cls._GetConfigFileDiskData(block_devices,
632 525011bc Maciej Bliziński
                                           hvp[constants.HV_BLOCKDEV_PREFIX])
633 7ed85ffe Iustin Pop
634 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
635 7ed85ffe Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
636 074ca009 Guido Trotter
637 7adf7814 René Nussbaumer
    if hvp[constants.HV_ROOT_PATH]:
638 7adf7814 René Nussbaumer
      config.write("root = '%s'\n" % hvp[constants.HV_ROOT_PATH])
639 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
640 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
641 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
642 990ade2d Stephen Shirley
    else:
643 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
644 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
645 07813a9e Iustin Pop
    config.write("extra = '%s'\n" % hvp[constants.HV_KERNEL_ARGS])
646 65a6f9b7 Michael Hanselmann
    # just in case it exists
647 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
648 65a6f9b7 Michael Hanselmann
    try:
649 c2be2532 Guido Trotter
      utils.WriteFile(cls._ConfigFileName(instance.name),
650 c2be2532 Guido Trotter
                      data=config.getvalue())
651 73cd67f4 Guido Trotter
    except EnvironmentError, err:
652 73cd67f4 Guido Trotter
      raise errors.HypervisorError("Cannot write Xen instance confile"
653 c2be2532 Guido Trotter
                                   " file %s: %s" %
654 c2be2532 Guido Trotter
                                   (cls._ConfigFileName(instance.name), err))
655 73cd67f4 Guido Trotter
656 65a6f9b7 Michael Hanselmann
    return True
657 65a6f9b7 Michael Hanselmann
658 65a6f9b7 Michael Hanselmann
659 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
660 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
661 65a6f9b7 Michael Hanselmann
662 69b99987 Michael Hanselmann
  ANCILLARY_FILES = XenHypervisor.ANCILLARY_FILES + [
663 69b99987 Michael Hanselmann
    constants.VNC_PASSWORD_FILE,
664 69b99987 Michael Hanselmann
    ]
665 69ab2e12 Guido Trotter
  ANCILLARY_FILES_OPT = XenHypervisor.ANCILLARY_FILES_OPT + [
666 69ab2e12 Guido Trotter
    constants.VNC_PASSWORD_FILE,
667 69ab2e12 Guido Trotter
    ]
668 3680f662 Guido Trotter
669 205ab586 Iustin Pop
  PARAMETERS = {
670 205ab586 Iustin Pop
    constants.HV_ACPI: hv_base.NO_CHECK,
671 016d04b3 Michael Hanselmann
    constants.HV_BOOT_ORDER: (True, ) +
672 016d04b3 Michael Hanselmann
      (lambda x: x and len(x.strip("acdn")) == 0,
673 016d04b3 Michael Hanselmann
       "Invalid boot order specified, must be one or more of [acdn]",
674 016d04b3 Michael Hanselmann
       None, None),
675 205ab586 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_CHECK,
676 016d04b3 Michael Hanselmann
    constants.HV_DISK_TYPE:
677 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_DISK_TYPES),
678 016d04b3 Michael Hanselmann
    constants.HV_NIC_TYPE:
679 016d04b3 Michael Hanselmann
      hv_base.ParamInSet(True, constants.HT_HVM_VALID_NIC_TYPES),
680 205ab586 Iustin Pop
    constants.HV_PAE: hv_base.NO_CHECK,
681 016d04b3 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS:
682 8b312c1d Manuel Franceschini
      (False, netutils.IP4Address.IsValid,
683 016d04b3 Michael Hanselmann
       "VNC bind address is not a valid IP address", None, None),
684 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
685 205ab586 Iustin Pop
    constants.HV_DEVICE_MODEL: hv_base.REQ_FILE_CHECK,
686 6e6bb8d5 Guido Trotter
    constants.HV_VNC_PASSWORD_FILE: hv_base.REQ_FILE_CHECK,
687 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
688 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
689 6b970cef Jun Futagawa
    constants.HV_USE_LOCALTIME: hv_base.NO_CHECK,
690 e695efbf Iustin Pop
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
691 e695efbf Iustin Pop
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
692 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
693 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
694 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
695 205ab586 Iustin Pop
    }
696 09ea8710 Iustin Pop
697 65a6f9b7 Michael Hanselmann
  @classmethod
698 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
699 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
700 65a6f9b7 Michael Hanselmann

701 65a6f9b7 Michael Hanselmann
    """
702 a985b417 Iustin Pop
    hvp = instance.hvparams
703 a985b417 Iustin Pop
704 65a6f9b7 Michael Hanselmann
    config = StringIO()
705 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
706 e2ee1cea Iustin Pop
707 e2ee1cea Iustin Pop
    # kernel handling
708 e2ee1cea Iustin Pop
    kpath = hvp[constants.HV_KERNEL_PATH]
709 e2ee1cea Iustin Pop
    config.write("kernel = '%s'\n" % kpath)
710 e2ee1cea Iustin Pop
711 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
712 f5a4b9ce Guido Trotter
    config.write("memory = %d\n" % instance.beparams[constants.BE_MAXMEM])
713 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
714 c4708267 Tsachy Shacham
    cpu_pinning = cls._CreateConfigCpus(hvp[constants.HV_CPU_MASK])
715 c4708267 Tsachy Shacham
    if cpu_pinning:
716 c4708267 Tsachy Shacham
      config.write("%s\n" % cpu_pinning)
717 c4708267 Tsachy Shacham
718 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
719 09ea8710 Iustin Pop
    if hvp[constants.HV_PAE]:
720 a21dda8b Iustin Pop
      config.write("pae = 1\n")
721 a21dda8b Iustin Pop
    else:
722 a21dda8b Iustin Pop
      config.write("pae = 0\n")
723 09ea8710 Iustin Pop
    if hvp[constants.HV_ACPI]:
724 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
725 a21dda8b Iustin Pop
    else:
726 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
727 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
728 09ea8710 Iustin Pop
    config.write("device_model = '%s'\n" % hvp[constants.HV_DEVICE_MODEL])
729 a985b417 Iustin Pop
    config.write("boot = '%s'\n" % hvp[constants.HV_BOOT_ORDER])
730 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
731 97efde45 Guido Trotter
    config.write("usb = 1\n")
732 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
733 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
734 a985b417 Iustin Pop
    if hvp[constants.HV_VNC_BIND_ADDRESS] is None:
735 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
736 d0c11cf7 Alexander Schreiber
    else:
737 6b405598 Guido Trotter
      config.write("vnclisten = '%s'\n" % hvp[constants.HV_VNC_BIND_ADDRESS])
738 65a6f9b7 Michael Hanselmann
739 377d74c9 Guido Trotter
    if instance.network_port > constants.VNC_BASE_PORT:
740 377d74c9 Guido Trotter
      display = instance.network_port - constants.VNC_BASE_PORT
741 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
742 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
743 65a6f9b7 Michael Hanselmann
    else:
744 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
745 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
746 65a6f9b7 Michael Hanselmann
747 6e6bb8d5 Guido Trotter
    vnc_pwd_file = hvp[constants.HV_VNC_PASSWORD_FILE]
748 65a6f9b7 Michael Hanselmann
    try:
749 6e6bb8d5 Guido Trotter
      password = utils.ReadFile(vnc_pwd_file)
750 78f66a17 Guido Trotter
    except EnvironmentError, err:
751 78f66a17 Guido Trotter
      raise errors.HypervisorError("Failed to open VNC password file %s: %s" %
752 6e6bb8d5 Guido Trotter
                                   (vnc_pwd_file, err))
753 65a6f9b7 Michael Hanselmann
754 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
755 65a6f9b7 Michael Hanselmann
756 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
757 6b970cef Jun Futagawa
    if hvp[constants.HV_USE_LOCALTIME]:
758 6b970cef Jun Futagawa
      config.write("localtime = 1\n")
759 65a6f9b7 Michael Hanselmann
760 65a6f9b7 Michael Hanselmann
    vif_data = []
761 a985b417 Iustin Pop
    nic_type = hvp[constants.HV_NIC_TYPE]
762 f48148c3 Iustin Pop
    if nic_type is None:
763 f48148c3 Iustin Pop
      # ensure old instances don't change
764 f48148c3 Iustin Pop
      nic_type_str = ", type=ioemu"
765 d08f6067 Guido Trotter
    elif nic_type == constants.HT_NIC_PARAVIRTUAL:
766 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
767 f48148c3 Iustin Pop
    else:
768 f48148c3 Iustin Pop
      nic_type_str = ", model=%s, type=ioemu" % nic_type
769 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
770 503b97a9 Guido Trotter
      nic_str = "mac=%s%s" % (nic.mac, nic_type_str)
771 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
772 65a6f9b7 Michael Hanselmann
      if ip is not None:
773 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
774 503b97a9 Guido Trotter
      if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
775 503b97a9 Guido Trotter
        nic_str += ", bridge=%s" % nic.nicparams[constants.NIC_LINK]
776 0183a697 Alessandro Cincaglini
      vif_data.append("'%s'" % nic_str)
777 65a6f9b7 Michael Hanselmann
778 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
779 525011bc Maciej Bliziński
780 525011bc Maciej Bliziński
    disk_data = cls._GetConfigFileDiskData(block_devices,
781 525011bc Maciej Bliziński
                                           hvp[constants.HV_BLOCKDEV_PREFIX])
782 525011bc Maciej Bliziński
783 a985b417 Iustin Pop
    iso_path = hvp[constants.HV_CDROM_IMAGE_PATH]
784 f48148c3 Iustin Pop
    if iso_path:
785 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
786 a21dda8b Iustin Pop
      disk_data.append(iso)
787 a21dda8b Iustin Pop
788 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
789 a21dda8b Iustin Pop
790 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
791 990ade2d Stephen Shirley
    if hvp[constants.HV_REBOOT_BEHAVIOR] == constants.INSTANCE_REBOOT_ALLOWED:
792 990ade2d Stephen Shirley
      config.write("on_reboot = 'restart'\n")
793 990ade2d Stephen Shirley
    else:
794 990ade2d Stephen Shirley
      config.write("on_reboot = 'destroy'\n")
795 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
796 65a6f9b7 Michael Hanselmann
    # just in case it exists
797 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
798 65a6f9b7 Michael Hanselmann
    try:
799 c2be2532 Guido Trotter
      utils.WriteFile(cls._ConfigFileName(instance.name),
800 73cd67f4 Guido Trotter
                      data=config.getvalue())
801 73cd67f4 Guido Trotter
    except EnvironmentError, err:
802 73cd67f4 Guido Trotter
      raise errors.HypervisorError("Cannot write Xen instance confile"
803 c2be2532 Guido Trotter
                                   " file %s: %s" %
804 c2be2532 Guido Trotter
                                   (cls._ConfigFileName(instance.name), err))
805 73cd67f4 Guido Trotter
806 65a6f9b7 Michael Hanselmann
    return True