Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ f2f57b6e

History | View | Annotate | Download (27.5 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 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
319 65a6f9b7 Michael Hanselmann
    if result.failed:
320 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
321 b48909c8 Iustin Pop
                    result.output)
322 65a6f9b7 Michael Hanselmann
      return None
323 65a6f9b7 Michael Hanselmann
324 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
325 65a6f9b7 Michael Hanselmann
    result = {}
326 0105bad3 Iustin Pop
    cores_per_socket = threads_per_core = nr_cpus = None
327 34fbc862 Andrea Spadaccini
    xen_major, xen_minor = None, None
328 16ca6243 Michael Hanselmann
    memory_total = None
329 16ca6243 Michael Hanselmann
    memory_free = None
330 16ca6243 Michael Hanselmann
331 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
332 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
333 65a6f9b7 Michael Hanselmann
334 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
335 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
336 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
337 16ca6243 Michael Hanselmann
338 16ca6243 Michael Hanselmann
        # note: in xen 3, memory has changed to total_memory
339 d0c8c01d Iustin Pop
        if key == "memory" or key == "total_memory":
340 16ca6243 Michael Hanselmann
          memory_total = int(val)
341 d0c8c01d Iustin Pop
        elif key == "free_memory":
342 16ca6243 Michael Hanselmann
          memory_free = int(val)
343 d0c8c01d Iustin Pop
        elif key == "nr_cpus":
344 d0c8c01d Iustin Pop
          nr_cpus = result["cpu_total"] = int(val)
345 d0c8c01d Iustin Pop
        elif key == "nr_nodes":
346 d0c8c01d Iustin Pop
          result["cpu_nodes"] = int(val)
347 d0c8c01d Iustin Pop
        elif key == "cores_per_socket":
348 0105bad3 Iustin Pop
          cores_per_socket = int(val)
349 d0c8c01d Iustin Pop
        elif key == "threads_per_core":
350 0105bad3 Iustin Pop
          threads_per_core = int(val)
351 34fbc862 Andrea Spadaccini
        elif key == "xen_major":
352 34fbc862 Andrea Spadaccini
          xen_major = int(val)
353 34fbc862 Andrea Spadaccini
        elif key == "xen_minor":
354 34fbc862 Andrea Spadaccini
          xen_minor = int(val)
355 0105bad3 Iustin Pop
356 16ca6243 Michael Hanselmann
    if None not in [cores_per_socket, threads_per_core, nr_cpus]:
357 d0c8c01d Iustin Pop
      result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
358 0105bad3 Iustin Pop
359 16ca6243 Michael Hanselmann
    total_instmem = 0
360 16ca6243 Michael Hanselmann
    for (name, _, mem, vcpus, _, _) in self._GetXMList(True):
361 16ca6243 Michael Hanselmann
      if name == _DOM0_NAME:
362 16ca6243 Michael Hanselmann
        result["memory_dom0"] = mem
363 16ca6243 Michael Hanselmann
        result["dom0_cpus"] = vcpus
364 16ca6243 Michael Hanselmann
365 16ca6243 Michael Hanselmann
      # Include Dom0 in total memory usage
366 16ca6243 Michael Hanselmann
      total_instmem += mem
367 16ca6243 Michael Hanselmann
368 16ca6243 Michael Hanselmann
    if memory_free is not None:
369 16ca6243 Michael Hanselmann
      result["memory_free"] = memory_free
370 16ca6243 Michael Hanselmann
371 16ca6243 Michael Hanselmann
    if memory_total is not None:
372 16ca6243 Michael Hanselmann
      result["memory_total"] = memory_total
373 16ca6243 Michael Hanselmann
374 16ca6243 Michael Hanselmann
    # Calculate memory used by hypervisor
375 16ca6243 Michael Hanselmann
    if None not in [memory_total, memory_free, total_instmem]:
376 16ca6243 Michael Hanselmann
      result["memory_hv"] = memory_total - memory_free - total_instmem
377 65a6f9b7 Michael Hanselmann
378 34fbc862 Andrea Spadaccini
    if not (xen_major is None or xen_minor is None):
379 34fbc862 Andrea Spadaccini
      result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
380 34fbc862 Andrea Spadaccini
381 65a6f9b7 Michael Hanselmann
    return result
382 65a6f9b7 Michael Hanselmann
383 637ce7f9 Guido Trotter
  @classmethod
384 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
385 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
386 65a6f9b7 Michael Hanselmann

387 65a6f9b7 Michael Hanselmann
    """
388 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
389 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
390 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
391 55cc0a44 Michael Hanselmann
                                   user=constants.GANETI_RUNAS,
392 61631293 Stephen Shirley
                                   command=[constants.XM_CONSOLE_WRAPPER,
393 61631293 Stephen Shirley
                                            instance.name])
394 65a6f9b7 Michael Hanselmann
395 65a6f9b7 Michael Hanselmann
  def Verify(self):
396 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
397 65a6f9b7 Michael Hanselmann

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

400 65a6f9b7 Michael Hanselmann
    """
401 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
402 e3e66f02 Michael Hanselmann
    if result.failed:
403 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
404 65a6f9b7 Michael Hanselmann
405 65a6f9b7 Michael Hanselmann
  @staticmethod
406 525011bc Maciej Bliziński
  def _GetConfigFileDiskData(block_devices, blockdev_prefix):
407 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
408 65a6f9b7 Michael Hanselmann

409 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
410 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
411 65a6f9b7 Michael Hanselmann

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

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

420 65a6f9b7 Michael Hanselmann
    """
421 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
422 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
423 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
424 65a6f9b7 Michael Hanselmann
      }
425 65a6f9b7 Michael Hanselmann
    disk_data = []
426 2864f2d9 Iustin Pop
    if len(block_devices) > 24:
427 2864f2d9 Iustin Pop
      # 'z' - 'a' = 24
428 2864f2d9 Iustin Pop
      raise errors.HypervisorError("Too many disks")
429 d0c8c01d Iustin Pop
    namespace = [blockdev_prefix + chr(i + ord("a")) for i in range(24)]
430 069cfbf1 Iustin Pop
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
431 d34b16d7 Iustin Pop
      if cfdev.mode == constants.DISK_RDWR:
432 d34b16d7 Iustin Pop
        mode = "w"
433 d34b16d7 Iustin Pop
      else:
434 d34b16d7 Iustin Pop
        mode = "r"
435 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
436 d34b16d7 Iustin Pop
        line = "'%s:%s,%s,%s'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
437 d34b16d7 Iustin Pop
                                  dev_path, sd_name, mode)
438 65a6f9b7 Michael Hanselmann
      else:
439 d34b16d7 Iustin Pop
        line = "'phy:%s,%s,%s'" % (dev_path, sd_name, mode)
440 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
441 65a6f9b7 Michael Hanselmann
442 65a6f9b7 Michael Hanselmann
    return disk_data
443 65a6f9b7 Michael Hanselmann
444 4390ccff Guido Trotter
  def MigrationInfo(self, instance):
445 4390ccff Guido Trotter
    """Get instance information to perform a migration.
446 4390ccff Guido Trotter

447 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
448 4390ccff Guido Trotter
    @param instance: instance to be migrated
449 4390ccff Guido Trotter
    @rtype: string
450 4390ccff Guido Trotter
    @return: content of the xen config file
451 4390ccff Guido Trotter

452 4390ccff Guido Trotter
    """
453 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
454 4390ccff Guido Trotter
455 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
456 4390ccff Guido Trotter
    """Prepare to accept an instance.
457 4390ccff Guido Trotter

458 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
459 4390ccff Guido Trotter
    @param instance: instance to be accepted
460 4390ccff Guido Trotter
    @type info: string
461 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
462 4390ccff Guido Trotter
    @type target: string
463 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
464 4390ccff Guido Trotter

465 4390ccff Guido Trotter
    """
466 4390ccff Guido Trotter
    pass
467 4390ccff Guido Trotter
468 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
469 4390ccff Guido Trotter
    """Finalize an instance migration.
470 4390ccff Guido Trotter

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

474 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
475 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
476 4390ccff Guido Trotter
    @type info: string
477 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
478 4390ccff Guido Trotter
    @type success: boolean
479 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
480 4390ccff Guido Trotter

481 4390ccff Guido Trotter
    """
482 4390ccff Guido Trotter
    if success:
483 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
484 4390ccff Guido Trotter
485 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
486 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
487 6e7275c0 Iustin Pop

488 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
489 6e7275c0 Iustin Pop
    currently running.
490 6e7275c0 Iustin Pop

491 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
492 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
493 fdf7f055 Guido Trotter
    @type target: string
494 fdf7f055 Guido Trotter
    @param target: ip address of the target node
495 fdf7f055 Guido Trotter
    @type live: boolean
496 fdf7f055 Guido Trotter
    @param live: perform a live migration
497 fdf7f055 Guido Trotter

498 6e7275c0 Iustin Pop
    """
499 58d38b02 Iustin Pop
    if self.GetInstanceInfo(instance.name) is None:
500 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
501 50716be0 Iustin Pop
502 641ae041 Iustin Pop
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
503 50716be0 Iustin Pop
504 a744b676 Manuel Franceschini
    if not netutils.TcpPing(target, port, live_port_needed=True):
505 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
506 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
507 50716be0 Iustin Pop
508 6555373d Guido Trotter
    # FIXME: migrate must be upgraded for transitioning to "xl" (xen 4.1).
509 6555373d Guido Trotter
    #  -l doesn't exist anymore
510 6555373d Guido Trotter
    #  -p doesn't exist anymore
511 6555373d Guido Trotter
    #  -C config_file must be passed
512 6555373d Guido Trotter
    #  ssh must recognize the key of the target host for the migration
513 2876c2d6 Guido Trotter
    args = [constants.XEN_CMD, "migrate", "-p", "%d" % port]
514 6e7275c0 Iustin Pop
    if live:
515 6e7275c0 Iustin Pop
      args.append("-l")
516 58d38b02 Iustin Pop
    args.extend([instance.name, target])
517 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
518 6e7275c0 Iustin Pop
    if result.failed:
519 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
520 58d38b02 Iustin Pop
                                   (instance.name, result.output))
521 60af751d Andrea Spadaccini
522 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
523 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
524 60af751d Andrea Spadaccini

525 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
526 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
527 60af751d Andrea Spadaccini
    @type success: bool
528 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
529 60af751d Andrea Spadaccini
    @type live: bool
530 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
531 60af751d Andrea Spadaccini

532 60af751d Andrea Spadaccini
    """
533 60af751d Andrea Spadaccini
    # pylint: disable=W0613
534 60af751d Andrea Spadaccini
    if success:
535 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
536 60af751d Andrea Spadaccini
      try:
537 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
538 60af751d Andrea Spadaccini
      except EnvironmentError:
539 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
540 60af751d Andrea Spadaccini
541 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
542 60af751d Andrea Spadaccini
    """Get the migration status
543 60af751d Andrea Spadaccini

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

548 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
549 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
550 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
551 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
552 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
553 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
554 60af751d Andrea Spadaccini

555 60af751d Andrea Spadaccini
    """
556 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
557 6e7275c0 Iustin Pop
558 f5118ade Iustin Pop
  @classmethod
559 f5118ade Iustin Pop
  def PowercycleNode(cls):
560 f5118ade Iustin Pop
    """Xen-specific powercycle.
561 f5118ade Iustin Pop

562 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
563 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
564 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
565 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
566 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
567 f5118ade Iustin Pop
    daemon is not working.
568 f5118ade Iustin Pop

569 f5118ade Iustin Pop
    """
570 f5118ade Iustin Pop
    try:
571 f5118ade Iustin Pop
      cls.LinuxPowercycle()
572 f5118ade Iustin Pop
    finally:
573 2876c2d6 Guido Trotter
      utils.RunCmd([constants.XEN_CMD, "debug", "R"])
574 f5118ade Iustin Pop
575 65a6f9b7 Michael Hanselmann
576 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
577 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
578 65a6f9b7 Michael Hanselmann
579 205ab586 Iustin Pop
  PARAMETERS = {
580 2f2dbb4b Jun Futagawa
    constants.HV_USE_BOOTLOADER: hv_base.NO_CHECK,
581 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_PATH: hv_base.OPT_FILE_CHECK,
582 2f2dbb4b Jun Futagawa
    constants.HV_BOOTLOADER_ARGS: hv_base.NO_CHECK,
583 205ab586 Iustin Pop
    constants.HV_KERNEL_PATH: hv_base.REQ_FILE_CHECK,
584 205ab586 Iustin Pop
    constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK,
585 7adf7814 René Nussbaumer
    constants.HV_ROOT_PATH: hv_base.NO_CHECK,
586 205ab586 Iustin Pop
    constants.HV_KERNEL_ARGS: hv_base.NO_CHECK,
587 e2d14329 Andrea Spadaccini
    constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK,
588 783a6c0b Iustin Pop
    constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK,
589 525011bc Maciej Bliziński
    # TODO: Add a check for the blockdev prefix (matching [a-z:] or similar).
590 525011bc Maciej Bliziński
    constants.HV_BLOCKDEV_PREFIX: hv_base.NO_CHECK,
591 990ade2d Stephen Shirley
    constants.HV_REBOOT_BEHAVIOR:
592 c4708267 Tsachy Shacham
      hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
593 c4708267 Tsachy Shacham
    constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
594 205ab586 Iustin Pop
    }
595 f48148c3 Iustin Pop
596 65a6f9b7 Michael Hanselmann
  @classmethod
597 07813a9e Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices):
598 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
599 65a6f9b7 Michael Hanselmann

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

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