Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 0625d08f

History | View | Annotate | Download (28.5 kB)

1 65a6f9b7 Michael Hanselmann
#
2 65a6f9b7 Michael Hanselmann
#
3 65a6f9b7 Michael Hanselmann
4 1a63f285 Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc.
5 65a6f9b7 Michael Hanselmann
#
6 65a6f9b7 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 65a6f9b7 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 65a6f9b7 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 65a6f9b7 Michael Hanselmann
# (at your option) any later version.
10 65a6f9b7 Michael Hanselmann
#
11 65a6f9b7 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 65a6f9b7 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 65a6f9b7 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 65a6f9b7 Michael Hanselmann
# General Public License for more details.
15 65a6f9b7 Michael Hanselmann
#
16 65a6f9b7 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 65a6f9b7 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 65a6f9b7 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 65a6f9b7 Michael Hanselmann
# 02110-1301, USA.
20 65a6f9b7 Michael Hanselmann
21 65a6f9b7 Michael Hanselmann
22 65a6f9b7 Michael Hanselmann
"""Xen hypervisors
23 65a6f9b7 Michael Hanselmann

24 65a6f9b7 Michael Hanselmann
"""
25 65a6f9b7 Michael Hanselmann
26 b48909c8 Iustin Pop
import logging
27 65a6f9b7 Michael Hanselmann
from cStringIO import StringIO
28 65a6f9b7 Michael Hanselmann
29 65a6f9b7 Michael Hanselmann
from ganeti import constants
30 65a6f9b7 Michael Hanselmann
from ganeti import errors
31 65a6f9b7 Michael Hanselmann
from ganeti import utils
32 a2d32034 Michael Hanselmann
from ganeti.hypervisor import hv_base
33 a744b676 Manuel Franceschini
from ganeti import netutils
34 55cc0a44 Michael Hanselmann
from ganeti import objects
35 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 1a63f285 Iustin Pop
    # just in case it exists
90 1a63f285 Iustin Pop
    utils.RemoveFile("/etc/xen/auto/%s" % instance_name)
91 1a63f285 Iustin Pop
    cfg_file = XenHypervisor._ConfigFileName(instance_name)
92 1a63f285 Iustin Pop
    try:
93 1a63f285 Iustin Pop
      utils.WriteFile(cfg_file, data=data)
94 1a63f285 Iustin Pop
    except EnvironmentError, err:
95 1a63f285 Iustin Pop
      raise errors.HypervisorError("Cannot write Xen instance configuration"
96 1a63f285 Iustin Pop
                                   " file %s: %s" % (cfg_file, err))
97 4390ccff Guido Trotter
98 4390ccff Guido Trotter
  @staticmethod
99 4390ccff Guido Trotter
  def _ReadConfigFile(instance_name):
100 4390ccff Guido Trotter
    """Returns the contents of the instance config file.
101 4390ccff Guido Trotter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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