Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ fc5bb0fe

History | View | Annotate | Download (28.7 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 61eb1a46 Guido Trotter
  def _WriteConfigFile(cls, instance, startup_memory, 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 61eb1a46 Guido Trotter
    startup_memory = self._InstanceStartupMemory(instance)
243 61eb1a46 Guido Trotter
    self._WriteConfigFile(instance, startup_memory, block_devices)
244 2876c2d6 Guido Trotter
    cmd = [constants.XEN_CMD, "create"]
245 323f9095 Stephen Shirley
    if startup_paused:
246 6555373d Guido Trotter
      cmd.extend(["-p"])
247 6555373d Guido Trotter
    cmd.extend([self._ConfigFileName(instance.name)])
248 323f9095 Stephen Shirley
    result = utils.RunCmd(cmd)
249 65a6f9b7 Michael Hanselmann
250 65a6f9b7 Michael Hanselmann
    if result.failed:
251 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
252 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
253 65a6f9b7 Michael Hanselmann
                                    result.output))
254 65a6f9b7 Michael Hanselmann
255 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
256 c41eea6e Iustin Pop
    """Stop an instance.
257 c41eea6e Iustin Pop

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

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

309 2c7a0373 Guido Trotter
    @type instance: L{objects.Instance}
310 2c7a0373 Guido Trotter
    @param instance: instance to be accepted
311 2c7a0373 Guido Trotter
    @type mem: int
312 2c7a0373 Guido Trotter
    @param mem: actual memory size to use for instance runtime
313 2c7a0373 Guido Trotter

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

332 0105bad3 Iustin Pop
    @return: a dict with the following keys (memory values in MiB):
333 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
334 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
335 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
336 0105bad3 Iustin Pop
          - nr_cpus: total number of CPUs
337 0105bad3 Iustin Pop
          - nr_nodes: in a NUMA system, the number of domains
338 0105bad3 Iustin Pop
          - nr_sockets: the number of physical CPU sockets in the node
339 34fbc862 Andrea Spadaccini
          - hv_version: the hypervisor version in the form (major, minor)
340 65a6f9b7 Michael Hanselmann

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

411 65a6f9b7 Michael Hanselmann
    """
412 55cc0a44 Michael Hanselmann
    return objects.InstanceConsole(instance=instance.name,
413 55cc0a44 Michael Hanselmann
                                   kind=constants.CONS_SSH,
414 55cc0a44 Michael Hanselmann
                                   host=instance.primary_node,
415 55cc0a44 Michael Hanselmann
                                   user=constants.GANETI_RUNAS,
416 61631293 Stephen Shirley
                                   command=[constants.XM_CONSOLE_WRAPPER,
417 61631293 Stephen Shirley
                                            instance.name])
418 65a6f9b7 Michael Hanselmann
419 65a6f9b7 Michael Hanselmann
  def Verify(self):
420 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
421 65a6f9b7 Michael Hanselmann

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

424 65a6f9b7 Michael Hanselmann
    """
425 2876c2d6 Guido Trotter
    result = utils.RunCmd([constants.XEN_CMD, "info"])
426 e3e66f02 Michael Hanselmann
    if result.failed:
427 3213d3c8 Iustin Pop
      return "'xm info' failed: %s, %s" % (result.fail_reason, result.output)
428 65a6f9b7 Michael Hanselmann
429 65a6f9b7 Michael Hanselmann
  @staticmethod
430 525011bc Maciej Bliziński
  def _GetConfigFileDiskData(block_devices, blockdev_prefix):
431 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
432 65a6f9b7 Michael Hanselmann

433 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
434 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
435 65a6f9b7 Michael Hanselmann

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

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

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

471 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
472 4390ccff Guido Trotter
    @param instance: instance to be migrated
473 4390ccff Guido Trotter
    @rtype: string
474 4390ccff Guido Trotter
    @return: content of the xen config file
475 4390ccff Guido Trotter

476 4390ccff Guido Trotter
    """
477 4390ccff Guido Trotter
    return self._ReadConfigFile(instance.name)
478 4390ccff Guido Trotter
479 4390ccff Guido Trotter
  def AcceptInstance(self, instance, info, target):
480 4390ccff Guido Trotter
    """Prepare to accept an instance.
481 4390ccff Guido Trotter

482 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
483 4390ccff Guido Trotter
    @param instance: instance to be accepted
484 4390ccff Guido Trotter
    @type info: string
485 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
486 4390ccff Guido Trotter
    @type target: string
487 4390ccff Guido Trotter
    @param target: target host (usually ip), on this node
488 4390ccff Guido Trotter

489 4390ccff Guido Trotter
    """
490 4390ccff Guido Trotter
    pass
491 4390ccff Guido Trotter
492 60af751d Andrea Spadaccini
  def FinalizeMigrationDst(self, instance, info, success):
493 4390ccff Guido Trotter
    """Finalize an instance migration.
494 4390ccff Guido Trotter

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

498 4390ccff Guido Trotter
    @type instance: L{objects.Instance}
499 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
500 4390ccff Guido Trotter
    @type info: string
501 4390ccff Guido Trotter
    @param info: content of the xen config file on the source node
502 4390ccff Guido Trotter
    @type success: boolean
503 4390ccff Guido Trotter
    @param success: whether the migration was a success or a failure
504 4390ccff Guido Trotter

505 4390ccff Guido Trotter
    """
506 4390ccff Guido Trotter
    if success:
507 4390ccff Guido Trotter
      self._WriteConfigFileStatic(instance.name, info)
508 4390ccff Guido Trotter
509 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
510 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
511 6e7275c0 Iustin Pop

512 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
513 6e7275c0 Iustin Pop
    currently running.
514 6e7275c0 Iustin Pop

515 58d38b02 Iustin Pop
    @type instance: L{objects.Instance}
516 58d38b02 Iustin Pop
    @param instance: the instance to be migrated
517 fdf7f055 Guido Trotter
    @type target: string
518 fdf7f055 Guido Trotter
    @param target: ip address of the target node
519 fdf7f055 Guido Trotter
    @type live: boolean
520 fdf7f055 Guido Trotter
    @param live: perform a live migration
521 fdf7f055 Guido Trotter

522 6e7275c0 Iustin Pop
    """
523 58d38b02 Iustin Pop
    if self.GetInstanceInfo(instance.name) is None:
524 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
525 50716be0 Iustin Pop
526 641ae041 Iustin Pop
    port = instance.hvparams[constants.HV_MIGRATION_PORT]
527 50716be0 Iustin Pop
528 a744b676 Manuel Franceschini
    if not netutils.TcpPing(target, port, live_port_needed=True):
529 50716be0 Iustin Pop
      raise errors.HypervisorError("Remote host %s not listening on port"
530 50716be0 Iustin Pop
                                   " %s, cannot migrate" % (target, port))
531 50716be0 Iustin Pop
532 6555373d Guido Trotter
    # FIXME: migrate must be upgraded for transitioning to "xl" (xen 4.1).
533 6555373d Guido Trotter
    #  -l doesn't exist anymore
534 6555373d Guido Trotter
    #  -p doesn't exist anymore
535 6555373d Guido Trotter
    #  -C config_file must be passed
536 6555373d Guido Trotter
    #  ssh must recognize the key of the target host for the migration
537 2876c2d6 Guido Trotter
    args = [constants.XEN_CMD, "migrate", "-p", "%d" % port]
538 6e7275c0 Iustin Pop
    if live:
539 6e7275c0 Iustin Pop
      args.append("-l")
540 58d38b02 Iustin Pop
    args.extend([instance.name, target])
541 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
542 6e7275c0 Iustin Pop
    if result.failed:
543 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
544 58d38b02 Iustin Pop
                                   (instance.name, result.output))
545 60af751d Andrea Spadaccini
546 60af751d Andrea Spadaccini
  def FinalizeMigrationSource(self, instance, success, live):
547 60af751d Andrea Spadaccini
    """Finalize the instance migration on the source node.
548 60af751d Andrea Spadaccini

549 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
550 60af751d Andrea Spadaccini
    @param instance: the instance that was migrated
551 60af751d Andrea Spadaccini
    @type success: bool
552 60af751d Andrea Spadaccini
    @param success: whether the migration succeeded or not
553 60af751d Andrea Spadaccini
    @type live: bool
554 60af751d Andrea Spadaccini
    @param live: whether the user requested a live migration or not
555 60af751d Andrea Spadaccini

556 60af751d Andrea Spadaccini
    """
557 60af751d Andrea Spadaccini
    # pylint: disable=W0613
558 60af751d Andrea Spadaccini
    if success:
559 60af751d Andrea Spadaccini
      # remove old xen file after migration succeeded
560 60af751d Andrea Spadaccini
      try:
561 60af751d Andrea Spadaccini
        self._RemoveConfigFile(instance.name)
562 60af751d Andrea Spadaccini
      except EnvironmentError:
563 60af751d Andrea Spadaccini
        logging.exception("Failure while removing instance config file")
564 60af751d Andrea Spadaccini
565 60af751d Andrea Spadaccini
  def GetMigrationStatus(self, instance):
566 60af751d Andrea Spadaccini
    """Get the migration status
567 60af751d Andrea Spadaccini

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

572 60af751d Andrea Spadaccini
    @type instance: L{objects.Instance}
573 60af751d Andrea Spadaccini
    @param instance: the instance that is being migrated
574 60af751d Andrea Spadaccini
    @rtype: L{objects.MigrationStatus}
575 60af751d Andrea Spadaccini
    @return: the status of the current migration (one of
576 60af751d Andrea Spadaccini
             L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
577 60af751d Andrea Spadaccini
             progress info that can be retrieved from the hypervisor
578 60af751d Andrea Spadaccini

579 60af751d Andrea Spadaccini
    """
580 60af751d Andrea Spadaccini
    return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
581 6e7275c0 Iustin Pop
582 f5118ade Iustin Pop
  @classmethod
583 f5118ade Iustin Pop
  def PowercycleNode(cls):
584 f5118ade Iustin Pop
    """Xen-specific powercycle.
585 f5118ade Iustin Pop

586 f5118ade Iustin Pop
    This first does a Linux reboot (which triggers automatically a Xen
587 f5118ade Iustin Pop
    reboot), and if that fails it tries to do a Xen reboot. The reason
588 f5118ade Iustin Pop
    we don't try a Xen reboot first is that the xen reboot launches an
589 f5118ade Iustin Pop
    external command which connects to the Xen hypervisor, and that
590 f5118ade Iustin Pop
    won't work in case the root filesystem is broken and/or the xend
591 f5118ade Iustin Pop
    daemon is not working.
592 f5118ade Iustin Pop

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

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

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