Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 91ae95fd

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 22d568c2 Guido Trotter
41 22d568c2 Guido Trotter
42 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
43 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
44 65a6f9b7 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

316 65a6f9b7 Michael Hanselmann
    """
317 65a6f9b7 Michael Hanselmann
    # note: in xen 3, memory has changed to total_memory
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 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
329 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
330 65a6f9b7 Michael Hanselmann
331 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
332 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
333 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
334 d0c8c01d Iustin Pop
        if key == "memory" or key == "total_memory":
335 d0c8c01d Iustin Pop
          result["memory_total"] = int(val)
336 d0c8c01d Iustin Pop
        elif key == "free_memory":
337 d0c8c01d Iustin Pop
          result["memory_free"] = int(val)
338 d0c8c01d Iustin Pop
        elif key == "nr_cpus":
339 d0c8c01d Iustin Pop
          nr_cpus = result["cpu_total"] = int(val)
340 d0c8c01d Iustin Pop
        elif key == "nr_nodes":
341 d0c8c01d Iustin Pop
          result["cpu_nodes"] = int(val)
342 d0c8c01d Iustin Pop
        elif key == "cores_per_socket":
343 0105bad3 Iustin Pop
          cores_per_socket = int(val)
344 d0c8c01d Iustin Pop
        elif key == "threads_per_core":
345 0105bad3 Iustin Pop
          threads_per_core = int(val)
346 34fbc862 Andrea Spadaccini
        elif key == "xen_major":
347 34fbc862 Andrea Spadaccini
          xen_major = int(val)
348 34fbc862 Andrea Spadaccini
        elif key == "xen_minor":
349 34fbc862 Andrea Spadaccini
          xen_minor = int(val)
350 0105bad3 Iustin Pop
351 0105bad3 Iustin Pop
    if (cores_per_socket is not None and
352 0105bad3 Iustin Pop
        threads_per_core is not None and nr_cpus is not None):
353 d0c8c01d Iustin Pop
      result["cpu_sockets"] = nr_cpus / (cores_per_socket * threads_per_core)
354 0105bad3 Iustin Pop
355 65a6f9b7 Michael Hanselmann
    dom0_info = self.GetInstanceInfo("Domain-0")
356 65a6f9b7 Michael Hanselmann
    if dom0_info is not None:
357 d0c8c01d Iustin Pop
      result["memory_dom0"] = dom0_info[2]
358 65a6f9b7 Michael Hanselmann
359 34fbc862 Andrea Spadaccini
    if not (xen_major is None or xen_minor is None):
360 34fbc862 Andrea Spadaccini
      result[constants.HV_NODEINFO_KEY_VERSION] = (xen_major, xen_minor)
361 34fbc862 Andrea Spadaccini
362 65a6f9b7 Michael Hanselmann
    return result
363 65a6f9b7 Michael Hanselmann
364 637ce7f9 Guido Trotter
  @classmethod
365 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
366 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
367 65a6f9b7 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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