Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ cd42d0ad

History | View | Annotate | Download (19.3 kB)

1 65a6f9b7 Michael Hanselmann
#
2 65a6f9b7 Michael Hanselmann
#
3 65a6f9b7 Michael Hanselmann
4 65a6f9b7 Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 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 65a6f9b7 Michael Hanselmann
import os
27 65a6f9b7 Michael Hanselmann
import os.path
28 65a6f9b7 Michael Hanselmann
import time
29 b48909c8 Iustin Pop
import logging
30 65a6f9b7 Michael Hanselmann
from cStringIO import StringIO
31 65a6f9b7 Michael Hanselmann
32 65a6f9b7 Michael Hanselmann
from ganeti import constants
33 65a6f9b7 Michael Hanselmann
from ganeti import errors
34 65a6f9b7 Michael Hanselmann
from ganeti import utils
35 a2d32034 Michael Hanselmann
from ganeti.hypervisor import hv_base
36 65a6f9b7 Michael Hanselmann
37 65a6f9b7 Michael Hanselmann
38 a2d32034 Michael Hanselmann
class XenHypervisor(hv_base.BaseHypervisor):
39 65a6f9b7 Michael Hanselmann
  """Xen generic hypervisor interface
40 65a6f9b7 Michael Hanselmann

41 65a6f9b7 Michael Hanselmann
  This is the Xen base class used for both Xen PVM and HVM. It contains
42 65a6f9b7 Michael Hanselmann
  all the functionality that is identical for both.
43 65a6f9b7 Michael Hanselmann

44 65a6f9b7 Michael Hanselmann
  """
45 65a6f9b7 Michael Hanselmann
46 5661b908 Iustin Pop
  @classmethod
47 5661b908 Iustin Pop
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
48 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
49 65a6f9b7 Michael Hanselmann

50 65a6f9b7 Michael Hanselmann
    """
51 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
52 65a6f9b7 Michael Hanselmann
53 65a6f9b7 Michael Hanselmann
  @staticmethod
54 53c776b5 Iustin Pop
  def _RemoveConfigFile(instance_name):
55 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
56 65a6f9b7 Michael Hanselmann

57 65a6f9b7 Michael Hanselmann
    """
58 53c776b5 Iustin Pop
    utils.RemoveFile("/etc/xen/%s" % instance_name)
59 65a6f9b7 Michael Hanselmann
60 65a6f9b7 Michael Hanselmann
  @staticmethod
61 65a6f9b7 Michael Hanselmann
  def _GetXMList(include_node):
62 65a6f9b7 Michael Hanselmann
    """Return the list of running instances.
63 65a6f9b7 Michael Hanselmann

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

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

69 65a6f9b7 Michael Hanselmann
    """
70 65a6f9b7 Michael Hanselmann
    for dummy in range(5):
71 65a6f9b7 Michael Hanselmann
      result = utils.RunCmd(["xm", "list"])
72 65a6f9b7 Michael Hanselmann
      if not result.failed:
73 65a6f9b7 Michael Hanselmann
        break
74 b48909c8 Iustin Pop
      logging.error("xm list failed (%s): %s", result.fail_reason,
75 b48909c8 Iustin Pop
                    result.output)
76 65a6f9b7 Michael Hanselmann
      time.sleep(1)
77 65a6f9b7 Michael Hanselmann
78 65a6f9b7 Michael Hanselmann
    if result.failed:
79 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("xm list failed, retries"
80 65a6f9b7 Michael Hanselmann
                                   " exceeded (%s): %s" %
81 65a6f9b7 Michael Hanselmann
                                   (result.fail_reason, result.stderr))
82 65a6f9b7 Michael Hanselmann
83 65a6f9b7 Michael Hanselmann
    # skip over the heading
84 65a6f9b7 Michael Hanselmann
    lines = result.stdout.splitlines()[1:]
85 65a6f9b7 Michael Hanselmann
    result = []
86 65a6f9b7 Michael Hanselmann
    for line in lines:
87 65a6f9b7 Michael Hanselmann
      # The format of lines is:
88 65a6f9b7 Michael Hanselmann
      # Name      ID Mem(MiB) VCPUs State  Time(s)
89 65a6f9b7 Michael Hanselmann
      # Domain-0   0  3418     4 r-----    266.2
90 65a6f9b7 Michael Hanselmann
      data = line.split()
91 65a6f9b7 Michael Hanselmann
      if len(data) != 6:
92 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
93 65a6f9b7 Michael Hanselmann
                                     " line: %s" % line)
94 65a6f9b7 Michael Hanselmann
      try:
95 65a6f9b7 Michael Hanselmann
        data[1] = int(data[1])
96 65a6f9b7 Michael Hanselmann
        data[2] = int(data[2])
97 65a6f9b7 Michael Hanselmann
        data[3] = int(data[3])
98 65a6f9b7 Michael Hanselmann
        data[5] = float(data[5])
99 65a6f9b7 Michael Hanselmann
      except ValueError, err:
100 65a6f9b7 Michael Hanselmann
        raise errors.HypervisorError("Can't parse output of xm list,"
101 65a6f9b7 Michael Hanselmann
                                     " line: %s, error: %s" % (line, err))
102 65a6f9b7 Michael Hanselmann
103 65a6f9b7 Michael Hanselmann
      # skip the Domain-0 (optional)
104 65a6f9b7 Michael Hanselmann
      if include_node or data[0] != 'Domain-0':
105 65a6f9b7 Michael Hanselmann
        result.append(data)
106 65a6f9b7 Michael Hanselmann
107 65a6f9b7 Michael Hanselmann
    return result
108 65a6f9b7 Michael Hanselmann
109 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
110 65a6f9b7 Michael Hanselmann
    """Get the list of running instances.
111 65a6f9b7 Michael Hanselmann

112 65a6f9b7 Michael Hanselmann
    """
113 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
114 65a6f9b7 Michael Hanselmann
    names = [info[0] for info in xm_list]
115 65a6f9b7 Michael Hanselmann
    return names
116 65a6f9b7 Michael Hanselmann
117 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
118 65a6f9b7 Michael Hanselmann
    """Get instance properties.
119 65a6f9b7 Michael Hanselmann

120 c41eea6e Iustin Pop
    @param instance_name: the instance name
121 c41eea6e Iustin Pop

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

124 65a6f9b7 Michael Hanselmann
    """
125 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(instance_name=="Domain-0")
126 65a6f9b7 Michael Hanselmann
    result = None
127 65a6f9b7 Michael Hanselmann
    for data in xm_list:
128 65a6f9b7 Michael Hanselmann
      if data[0] == instance_name:
129 65a6f9b7 Michael Hanselmann
        result = data
130 65a6f9b7 Michael Hanselmann
        break
131 65a6f9b7 Michael Hanselmann
    return result
132 65a6f9b7 Michael Hanselmann
133 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
134 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
135 65a6f9b7 Michael Hanselmann

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

138 65a6f9b7 Michael Hanselmann
    """
139 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
140 65a6f9b7 Michael Hanselmann
    return xm_list
141 65a6f9b7 Michael Hanselmann
142 65a6f9b7 Michael Hanselmann
  def StartInstance(self, instance, block_devices, extra_args):
143 c41eea6e Iustin Pop
    """Start an instance.
144 c41eea6e Iustin Pop

145 c41eea6e Iustin Pop
    """
146 65a6f9b7 Michael Hanselmann
    self._WriteConfigFile(instance, block_devices, extra_args)
147 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "create", instance.name])
148 65a6f9b7 Michael Hanselmann
149 65a6f9b7 Michael Hanselmann
    if result.failed:
150 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
151 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
152 65a6f9b7 Michael Hanselmann
                                    result.output))
153 65a6f9b7 Michael Hanselmann
154 65a6f9b7 Michael Hanselmann
  def StopInstance(self, instance, force=False):
155 c41eea6e Iustin Pop
    """Stop an instance.
156 c41eea6e Iustin Pop

157 c41eea6e Iustin Pop
    """
158 53c776b5 Iustin Pop
    self._RemoveConfigFile(instance.name)
159 65a6f9b7 Michael Hanselmann
    if force:
160 65a6f9b7 Michael Hanselmann
      command = ["xm", "destroy", instance.name]
161 65a6f9b7 Michael Hanselmann
    else:
162 65a6f9b7 Michael Hanselmann
      command = ["xm", "shutdown", instance.name]
163 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
164 65a6f9b7 Michael Hanselmann
165 65a6f9b7 Michael Hanselmann
    if result.failed:
166 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
167 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
168 65a6f9b7 Michael Hanselmann
169 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
170 c41eea6e Iustin Pop
    """Reboot an instance.
171 c41eea6e Iustin Pop

172 c41eea6e Iustin Pop
    """
173 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "reboot", instance.name])
174 65a6f9b7 Michael Hanselmann
175 65a6f9b7 Michael Hanselmann
    if result.failed:
176 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to reboot instance %s: %s" %
177 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
178 65a6f9b7 Michael Hanselmann
179 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
180 65a6f9b7 Michael Hanselmann
    """Return information about the node.
181 65a6f9b7 Michael Hanselmann

182 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
183 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
184 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
185 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
186 65a6f9b7 Michael Hanselmann

187 65a6f9b7 Michael Hanselmann
    """
188 65a6f9b7 Michael Hanselmann
    # note: in xen 3, memory has changed to total_memory
189 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
190 65a6f9b7 Michael Hanselmann
    if result.failed:
191 b48909c8 Iustin Pop
      logging.error("Can't run 'xm info' (%s): %s", result.fail_reason,
192 b48909c8 Iustin Pop
                    result.output)
193 65a6f9b7 Michael Hanselmann
      return None
194 65a6f9b7 Michael Hanselmann
195 65a6f9b7 Michael Hanselmann
    xmoutput = result.stdout.splitlines()
196 65a6f9b7 Michael Hanselmann
    result = {}
197 65a6f9b7 Michael Hanselmann
    for line in xmoutput:
198 65a6f9b7 Michael Hanselmann
      splitfields = line.split(":", 1)
199 65a6f9b7 Michael Hanselmann
200 65a6f9b7 Michael Hanselmann
      if len(splitfields) > 1:
201 65a6f9b7 Michael Hanselmann
        key = splitfields[0].strip()
202 65a6f9b7 Michael Hanselmann
        val = splitfields[1].strip()
203 65a6f9b7 Michael Hanselmann
        if key == 'memory' or key == 'total_memory':
204 65a6f9b7 Michael Hanselmann
          result['memory_total'] = int(val)
205 65a6f9b7 Michael Hanselmann
        elif key == 'free_memory':
206 65a6f9b7 Michael Hanselmann
          result['memory_free'] = int(val)
207 e8a4c138 Iustin Pop
        elif key == 'nr_cpus':
208 e8a4c138 Iustin Pop
          result['cpu_total'] = int(val)
209 65a6f9b7 Michael Hanselmann
    dom0_info = self.GetInstanceInfo("Domain-0")
210 65a6f9b7 Michael Hanselmann
    if dom0_info is not None:
211 65a6f9b7 Michael Hanselmann
      result['memory_dom0'] = dom0_info[2]
212 65a6f9b7 Michael Hanselmann
213 65a6f9b7 Michael Hanselmann
    return result
214 65a6f9b7 Michael Hanselmann
215 65a6f9b7 Michael Hanselmann
  @staticmethod
216 65a6f9b7 Michael Hanselmann
  def GetShellCommandForConsole(instance):
217 65a6f9b7 Michael Hanselmann
    """Return a command for connecting to the console of an instance.
218 65a6f9b7 Michael Hanselmann

219 65a6f9b7 Michael Hanselmann
    """
220 04c4330c Alexander Schreiber
    return "xm console %s" % instance.name
221 04c4330c Alexander Schreiber
222 65a6f9b7 Michael Hanselmann
223 65a6f9b7 Michael Hanselmann
  def Verify(self):
224 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
225 65a6f9b7 Michael Hanselmann

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

228 65a6f9b7 Michael Hanselmann
    """
229 e3e66f02 Michael Hanselmann
    result = utils.RunCmd(["xm", "info"])
230 e3e66f02 Michael Hanselmann
    if result.failed:
231 e3e66f02 Michael Hanselmann
      return "'xm info' failed: %s" % result.fail_reason
232 65a6f9b7 Michael Hanselmann
233 65a6f9b7 Michael Hanselmann
  @staticmethod
234 65a6f9b7 Michael Hanselmann
  def _GetConfigFileDiskData(disk_template, block_devices):
235 65a6f9b7 Michael Hanselmann
    """Get disk directive for xen config file.
236 65a6f9b7 Michael Hanselmann

237 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
238 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
239 65a6f9b7 Michael Hanselmann

240 c41eea6e Iustin Pop
    @param disk_template: string containing instance disk template
241 c41eea6e Iustin Pop
    @param block_devices: list of tuples (cfdev, rldev):
242 c41eea6e Iustin Pop
        - cfdev: dict containing ganeti config disk part
243 c41eea6e Iustin Pop
        - rldev: ganeti.bdev.BlockDev object
244 65a6f9b7 Michael Hanselmann

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

247 65a6f9b7 Michael Hanselmann
    """
248 65a6f9b7 Michael Hanselmann
    FILE_DRIVER_MAP = {
249 65a6f9b7 Michael Hanselmann
      constants.FD_LOOP: "file",
250 65a6f9b7 Michael Hanselmann
      constants.FD_BLKTAP: "tap:aio",
251 65a6f9b7 Michael Hanselmann
      }
252 65a6f9b7 Michael Hanselmann
    disk_data = []
253 2864f2d9 Iustin Pop
    if len(block_devices) > 24:
254 2864f2d9 Iustin Pop
      # 'z' - 'a' = 24
255 2864f2d9 Iustin Pop
      raise errors.HypervisorError("Too many disks")
256 2864f2d9 Iustin Pop
    # FIXME: instead of this hardcoding here, each of PVM/HVM should
257 2864f2d9 Iustin Pop
    # directly export their info (currently HVM will just sed this info)
258 2864f2d9 Iustin Pop
    namespace = ["sd" + chr(i + ord('a')) for i in range(24)]
259 069cfbf1 Iustin Pop
    for sd_name, (cfdev, dev_path) in zip(namespace, block_devices):
260 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
261 65a6f9b7 Michael Hanselmann
        line = "'%s:%s,%s,w'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
262 069cfbf1 Iustin Pop
                                 dev_path, sd_name)
263 65a6f9b7 Michael Hanselmann
      else:
264 069cfbf1 Iustin Pop
        line = "'phy:%s,%s,w'" % (dev_path, sd_name)
265 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
266 65a6f9b7 Michael Hanselmann
267 65a6f9b7 Michael Hanselmann
    return disk_data
268 65a6f9b7 Michael Hanselmann
269 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
270 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
271 6e7275c0 Iustin Pop

272 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
273 6e7275c0 Iustin Pop
    currently running.
274 6e7275c0 Iustin Pop

275 fdf7f055 Guido Trotter
    @type instance: string
276 fdf7f055 Guido Trotter
    @param instance: instance name
277 fdf7f055 Guido Trotter
    @type target: string
278 fdf7f055 Guido Trotter
    @param target: ip address of the target node
279 fdf7f055 Guido Trotter
    @type live: boolean
280 fdf7f055 Guido Trotter
    @param live: perform a live migration
281 fdf7f055 Guido Trotter

282 6e7275c0 Iustin Pop
    """
283 6e7275c0 Iustin Pop
    if self.GetInstanceInfo(instance) is None:
284 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
285 6e7275c0 Iustin Pop
    args = ["xm", "migrate"]
286 6e7275c0 Iustin Pop
    if live:
287 6e7275c0 Iustin Pop
      args.append("-l")
288 6e7275c0 Iustin Pop
    args.extend([instance, target])
289 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
290 6e7275c0 Iustin Pop
    if result.failed:
291 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
292 6e7275c0 Iustin Pop
                                   (instance, result.output))
293 53c776b5 Iustin Pop
    # remove old xen file after migration succeeded
294 53c776b5 Iustin Pop
    try:
295 53c776b5 Iustin Pop
      self._RemoveConfigFile(instance)
296 53c776b5 Iustin Pop
    except EnvironmentError, err:
297 53c776b5 Iustin Pop
      logger.Error("Failure while removing instance config file: %s" %
298 53c776b5 Iustin Pop
                   str(err))
299 6e7275c0 Iustin Pop
300 65a6f9b7 Michael Hanselmann
301 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
302 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
303 65a6f9b7 Michael Hanselmann
304 f48148c3 Iustin Pop
  PARAMETERS = [
305 f48148c3 Iustin Pop
    constants.HV_KERNEL_PATH,
306 f48148c3 Iustin Pop
    constants.HV_INITRD_PATH,
307 f48148c3 Iustin Pop
    ]
308 f48148c3 Iustin Pop
309 f48148c3 Iustin Pop
  @classmethod
310 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
311 f48148c3 Iustin Pop
    """Check the given parameters for validity.
312 f48148c3 Iustin Pop

313 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
314 f48148c3 Iustin Pop
    kernel.
315 f48148c3 Iustin Pop

316 f48148c3 Iustin Pop
    @type hvparams:  dict
317 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
318 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
319 f48148c3 Iustin Pop

320 f48148c3 Iustin Pop
    """
321 f48148c3 Iustin Pop
    super(XenPvmHypervisor, cls).CheckParameterSyntax(hvparams)
322 f48148c3 Iustin Pop
323 f48148c3 Iustin Pop
    if not hvparams[constants.HV_KERNEL_PATH]:
324 f48148c3 Iustin Pop
      raise errors.HypervisorError("Need a kernel for the instance")
325 f48148c3 Iustin Pop
326 f48148c3 Iustin Pop
    if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
327 f48148c3 Iustin Pop
      raise errors.HypervisorError("The kernel path must an absolute path")
328 f48148c3 Iustin Pop
329 f48148c3 Iustin Pop
    if hvparams[constants.HV_INITRD_PATH]:
330 f48148c3 Iustin Pop
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
331 f48148c3 Iustin Pop
        raise errors.HypervisorError("The initrd path must an absolute path"
332 f48148c3 Iustin Pop
                                     ", if defined")
333 f48148c3 Iustin Pop
334 f48148c3 Iustin Pop
  def ValidateParameters(self, hvparams):
335 f48148c3 Iustin Pop
    """Check the given parameters for validity.
336 f48148c3 Iustin Pop

337 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
338 f48148c3 Iustin Pop
    kernel.
339 f48148c3 Iustin Pop

340 f48148c3 Iustin Pop
    """
341 f48148c3 Iustin Pop
    super(XenPvmHypervisor, self).ValidateParameters(hvparams)
342 f48148c3 Iustin Pop
343 f48148c3 Iustin Pop
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
344 f48148c3 Iustin Pop
    if not os.path.isfile(kernel_path):
345 f48148c3 Iustin Pop
      raise errors.HypervisorError("Instance kernel '%s' not found or"
346 f48148c3 Iustin Pop
                                   " not a file" % kernel_path)
347 f48148c3 Iustin Pop
    initrd_path = hvparams[constants.HV_INITRD_PATH]
348 f48148c3 Iustin Pop
    if initrd_path and not os.path.isfile(initrd_path):
349 f48148c3 Iustin Pop
      raise errors.HypervisorError("Instance initrd '%s' not found or"
350 f48148c3 Iustin Pop
                                   " not a file" % initrd_path)
351 f48148c3 Iustin Pop
352 65a6f9b7 Michael Hanselmann
  @classmethod
353 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
354 65a6f9b7 Michael Hanselmann
    """Write the Xen config file for the instance.
355 65a6f9b7 Michael Hanselmann

356 65a6f9b7 Michael Hanselmann
    """
357 65a6f9b7 Michael Hanselmann
    config = StringIO()
358 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
359 65a6f9b7 Michael Hanselmann
360 65a6f9b7 Michael Hanselmann
    # kernel handling
361 f48148c3 Iustin Pop
    kpath = instance.hvparams[constants.HV_KERNEL_PATH]
362 65a6f9b7 Michael Hanselmann
    config.write("kernel = '%s'\n" % kpath)
363 65a6f9b7 Michael Hanselmann
364 65a6f9b7 Michael Hanselmann
    # initrd handling
365 f48148c3 Iustin Pop
    initrd_path = instance.hvparams[constants.HV_INITRD_PATH]
366 65a6f9b7 Michael Hanselmann
    if initrd_path:
367 65a6f9b7 Michael Hanselmann
      config.write("ramdisk = '%s'\n" % initrd_path)
368 65a6f9b7 Michael Hanselmann
369 65a6f9b7 Michael Hanselmann
    # rest of the settings
370 8b3fd458 Iustin Pop
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
371 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
372 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
373 65a6f9b7 Michael Hanselmann
374 65a6f9b7 Michael Hanselmann
    vif_data = []
375 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
376 65a6f9b7 Michael Hanselmann
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
377 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
378 65a6f9b7 Michael Hanselmann
      if ip is not None:
379 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
380 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
381 65a6f9b7 Michael Hanselmann
382 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
383 65a6f9b7 Michael Hanselmann
    config.write("disk = [%s]\n" % ",".join(
384 65a6f9b7 Michael Hanselmann
                 cls._GetConfigFileDiskData(instance.disk_template,
385 65a6f9b7 Michael Hanselmann
                                            block_devices)))
386 65a6f9b7 Michael Hanselmann
    config.write("root = '/dev/sda ro'\n")
387 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
388 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
389 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
390 65a6f9b7 Michael Hanselmann
    if extra_args:
391 65a6f9b7 Michael Hanselmann
      config.write("extra = '%s'\n" % extra_args)
392 65a6f9b7 Michael Hanselmann
    # just in case it exists
393 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
394 65a6f9b7 Michael Hanselmann
    try:
395 65a6f9b7 Michael Hanselmann
      f = open("/etc/xen/%s" % instance.name, "w")
396 65a6f9b7 Michael Hanselmann
      try:
397 65a6f9b7 Michael Hanselmann
        f.write(config.getvalue())
398 65a6f9b7 Michael Hanselmann
      finally:
399 65a6f9b7 Michael Hanselmann
        f.close()
400 65a6f9b7 Michael Hanselmann
    except IOError, err:
401 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("Cannot write Xen instance confile"
402 65a6f9b7 Michael Hanselmann
                               " file /etc/xen/%s: %s" % (instance.name, err))
403 65a6f9b7 Michael Hanselmann
    return True
404 65a6f9b7 Michael Hanselmann
405 65a6f9b7 Michael Hanselmann
406 65a6f9b7 Michael Hanselmann
class XenHvmHypervisor(XenHypervisor):
407 65a6f9b7 Michael Hanselmann
  """Xen HVM hypervisor interface"""
408 65a6f9b7 Michael Hanselmann
409 f48148c3 Iustin Pop
  PARAMETERS = [
410 f48148c3 Iustin Pop
    constants.HV_ACPI,
411 f48148c3 Iustin Pop
    constants.HV_BOOT_ORDER,
412 f48148c3 Iustin Pop
    constants.HV_CDROM_IMAGE_PATH,
413 f48148c3 Iustin Pop
    constants.HV_DISK_TYPE,
414 f48148c3 Iustin Pop
    constants.HV_NIC_TYPE,
415 f48148c3 Iustin Pop
    constants.HV_PAE,
416 f48148c3 Iustin Pop
    constants.HV_VNC_BIND_ADDRESS,
417 f48148c3 Iustin Pop
    ]
418 f48148c3 Iustin Pop
419 f48148c3 Iustin Pop
  @classmethod
420 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
421 f48148c3 Iustin Pop
    """Check the given parameter syntax.
422 f48148c3 Iustin Pop

423 f48148c3 Iustin Pop
    """
424 f48148c3 Iustin Pop
    super(XenHvmHypervisor, cls).CheckParameterSyntax(hvparams)
425 f48148c3 Iustin Pop
    # boot order verification
426 f48148c3 Iustin Pop
    boot_order = hvparams[constants.HV_BOOT_ORDER]
427 f48148c3 Iustin Pop
    if len(boot_order.strip("acdn")) != 0:
428 f48148c3 Iustin Pop
      raise errors.HypervisorError("Invalid boot order '%s' specified,"
429 f48148c3 Iustin Pop
                                   " must be one or more of [acdn]" %
430 f48148c3 Iustin Pop
                                   boot_order)
431 f48148c3 Iustin Pop
    # device type checks
432 f48148c3 Iustin Pop
    nic_type = hvparams[constants.HV_NIC_TYPE]
433 f48148c3 Iustin Pop
    if nic_type not in constants.HT_HVM_VALID_NIC_TYPES:
434 f48148c3 Iustin Pop
      raise errors.HypervisorError("Invalid NIC type %s specified for Xen HVM"
435 f48148c3 Iustin Pop
                                   " hypervisor" % nic_type)
436 f48148c3 Iustin Pop
    disk_type = hvparams[constants.HV_DISK_TYPE]
437 f48148c3 Iustin Pop
    if disk_type not in constants.HT_HVM_VALID_DISK_TYPES:
438 f48148c3 Iustin Pop
      raise errors.HypervisorError("Invalid disk type %s specified for Xen HVM"
439 f48148c3 Iustin Pop
                                   " hypervisor" % disk_type)
440 f48148c3 Iustin Pop
    # vnc_bind_address verification
441 f48148c3 Iustin Pop
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
442 f48148c3 Iustin Pop
    if vnc_bind_address is not None:
443 f48148c3 Iustin Pop
      if not utils.IsValidIP(vnc_bind_address):
444 f48148c3 Iustin Pop
        raise errors.OpPrereqError("given VNC bind address '%s' doesn't look"
445 f48148c3 Iustin Pop
                                   " like a valid IP address" %
446 f48148c3 Iustin Pop
                                   vnc_bind_address)
447 f48148c3 Iustin Pop
448 f48148c3 Iustin Pop
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
449 f48148c3 Iustin Pop
    if iso_path and not os.path.isabs(iso_path):
450 5661b908 Iustin Pop
      raise errors.HypervisorError("The path to the HVM CDROM image must"
451 5661b908 Iustin Pop
                                   " be an absolute path or None, not %s" %
452 5661b908 Iustin Pop
                                   iso_path)
453 f48148c3 Iustin Pop
454 f48148c3 Iustin Pop
  def ValidateParameters(self, hvparams):
455 f48148c3 Iustin Pop
    """Check the given parameters for validity.
456 f48148c3 Iustin Pop

457 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
458 f48148c3 Iustin Pop
    kernel.
459 f48148c3 Iustin Pop

460 f48148c3 Iustin Pop
    @type hvparams:  dict
461 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
462 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
463 f48148c3 Iustin Pop

464 f48148c3 Iustin Pop
    """
465 f48148c3 Iustin Pop
    super(XenHvmHypervisor, self).ValidateParameters(hvparams)
466 f48148c3 Iustin Pop
467 f48148c3 Iustin Pop
    # hvm_cdrom_image_path verification
468 f48148c3 Iustin Pop
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
469 f48148c3 Iustin Pop
    if iso_path and not os.path.isfile(iso_path):
470 e09fdcfa Iustin Pop
      raise errors.HypervisorError("The HVM CDROM image must either be a"
471 e09fdcfa Iustin Pop
                                   " regular file or a symlink pointing to"
472 e09fdcfa Iustin Pop
                                   " an existing regular file, not %s" %
473 e09fdcfa Iustin Pop
                                   iso_path)
474 f48148c3 Iustin Pop
475 65a6f9b7 Michael Hanselmann
  @classmethod
476 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(cls, instance, block_devices, extra_args):
477 65a6f9b7 Michael Hanselmann
    """Create a Xen 3.1 HVM config file.
478 65a6f9b7 Michael Hanselmann

479 65a6f9b7 Michael Hanselmann
    """
480 65a6f9b7 Michael Hanselmann
    config = StringIO()
481 65a6f9b7 Michael Hanselmann
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
482 65a6f9b7 Michael Hanselmann
    config.write("kernel = '/usr/lib/xen/boot/hvmloader'\n")
483 65a6f9b7 Michael Hanselmann
    config.write("builder = 'hvm'\n")
484 8b3fd458 Iustin Pop
    config.write("memory = %d\n" % instance.beparams[constants.BE_MEMORY])
485 8b3fd458 Iustin Pop
    config.write("vcpus = %d\n" % instance.beparams[constants.BE_VCPUS])
486 65a6f9b7 Michael Hanselmann
    config.write("name = '%s'\n" % instance.name)
487 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_PAE]:
488 a21dda8b Iustin Pop
      config.write("pae = 1\n")
489 a21dda8b Iustin Pop
    else:
490 a21dda8b Iustin Pop
      config.write("pae = 0\n")
491 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_ACPI]:
492 a21dda8b Iustin Pop
      config.write("acpi = 1\n")
493 a21dda8b Iustin Pop
    else:
494 a21dda8b Iustin Pop
      config.write("acpi = 0\n")
495 65a6f9b7 Michael Hanselmann
    config.write("apic = 1\n")
496 65a6f9b7 Michael Hanselmann
    arch = os.uname()[4]
497 65a6f9b7 Michael Hanselmann
    if '64' in arch:
498 65a6f9b7 Michael Hanselmann
      config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
499 65a6f9b7 Michael Hanselmann
    else:
500 65a6f9b7 Michael Hanselmann
      config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
501 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_BOOT_ORDER] is None:
502 65a6f9b7 Michael Hanselmann
      config.write("boot = '%s'\n" % constants.HT_HVM_DEFAULT_BOOT_ORDER)
503 65a6f9b7 Michael Hanselmann
    else:
504 f48148c3 Iustin Pop
      config.write("boot = '%s'\n" % instance.hvparams["boot_order"])
505 65a6f9b7 Michael Hanselmann
    config.write("sdl = 0\n")
506 97efde45 Guido Trotter
    config.write("usb = 1\n")
507 97efde45 Guido Trotter
    config.write("usbdevice = 'tablet'\n")
508 65a6f9b7 Michael Hanselmann
    config.write("vnc = 1\n")
509 f48148c3 Iustin Pop
    if instance.hvparams[constants.HV_VNC_BIND_ADDRESS] is None:
510 d0c11cf7 Alexander Schreiber
      config.write("vnclisten = '%s'\n" % constants.VNC_DEFAULT_BIND_ADDRESS)
511 d0c11cf7 Alexander Schreiber
    else:
512 f48148c3 Iustin Pop
      config.write("vnclisten = '%s'\n" %
513 f48148c3 Iustin Pop
                   instance.hvparams["vnc_bind_address"])
514 65a6f9b7 Michael Hanselmann
515 65a6f9b7 Michael Hanselmann
    if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
516 65a6f9b7 Michael Hanselmann
      display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
517 65a6f9b7 Michael Hanselmann
      config.write("vncdisplay = %s\n" % display)
518 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 0\n")
519 65a6f9b7 Michael Hanselmann
    else:
520 65a6f9b7 Michael Hanselmann
      config.write("# vncdisplay = 1\n")
521 65a6f9b7 Michael Hanselmann
      config.write("vncunused = 1\n")
522 65a6f9b7 Michael Hanselmann
523 65a6f9b7 Michael Hanselmann
    try:
524 65a6f9b7 Michael Hanselmann
      password_file = open(constants.VNC_PASSWORD_FILE, "r")
525 65a6f9b7 Michael Hanselmann
      try:
526 65a6f9b7 Michael Hanselmann
        password = password_file.readline()
527 65a6f9b7 Michael Hanselmann
      finally:
528 65a6f9b7 Michael Hanselmann
        password_file.close()
529 65a6f9b7 Michael Hanselmann
    except IOError:
530 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("failed to open VNC password file %s " %
531 65a6f9b7 Michael Hanselmann
                               constants.VNC_PASSWORD_FILE)
532 65a6f9b7 Michael Hanselmann
533 65a6f9b7 Michael Hanselmann
    config.write("vncpasswd = '%s'\n" % password.rstrip())
534 65a6f9b7 Michael Hanselmann
535 65a6f9b7 Michael Hanselmann
    config.write("serial = 'pty'\n")
536 65a6f9b7 Michael Hanselmann
    config.write("localtime = 1\n")
537 65a6f9b7 Michael Hanselmann
538 65a6f9b7 Michael Hanselmann
    vif_data = []
539 f48148c3 Iustin Pop
    nic_type = instance.hvparams[constants.HV_NIC_TYPE]
540 f48148c3 Iustin Pop
    if nic_type is None:
541 f48148c3 Iustin Pop
      # ensure old instances don't change
542 f48148c3 Iustin Pop
      nic_type_str = ", type=ioemu"
543 f48148c3 Iustin Pop
    elif nic_type == constants.HT_HVM_DEV_PARAVIRTUAL:
544 f48148c3 Iustin Pop
      nic_type_str = ", type=paravirtualized"
545 f48148c3 Iustin Pop
    else:
546 f48148c3 Iustin Pop
      nic_type_str = ", model=%s, type=ioemu" % nic_type
547 65a6f9b7 Michael Hanselmann
    for nic in instance.nics:
548 f48148c3 Iustin Pop
      nic_str = "mac=%s, bridge=%s%s" % (nic.mac, nic.bridge, nic_type_str)
549 65a6f9b7 Michael Hanselmann
      ip = getattr(nic, "ip", None)
550 65a6f9b7 Michael Hanselmann
      if ip is not None:
551 65a6f9b7 Michael Hanselmann
        nic_str += ", ip=%s" % ip
552 65a6f9b7 Michael Hanselmann
      vif_data.append("'%s'" % nic_str)
553 65a6f9b7 Michael Hanselmann
554 65a6f9b7 Michael Hanselmann
    config.write("vif = [%s]\n" % ",".join(vif_data))
555 a21dda8b Iustin Pop
    disk_data = cls._GetConfigFileDiskData(instance.disk_template,
556 a21dda8b Iustin Pop
                                            block_devices)
557 f48148c3 Iustin Pop
    disk_type = instance.hvparams[constants.HV_DISK_TYPE]
558 f48148c3 Iustin Pop
    if disk_type in (None, constants.HT_HVM_DEV_IOEMU):
559 5397e0b7 Alexander Schreiber
      replacement = ",ioemu:hd"
560 5397e0b7 Alexander Schreiber
    else:
561 5397e0b7 Alexander Schreiber
      replacement = ",hd"
562 5397e0b7 Alexander Schreiber
    disk_data = [line.replace(",sd", replacement) for line in disk_data]
563 f48148c3 Iustin Pop
    iso_path = instance.hvparams[constants.HV_CDROM_IMAGE_PATH]
564 f48148c3 Iustin Pop
    if iso_path:
565 f48148c3 Iustin Pop
      iso = "'file:%s,hdc:cdrom,r'" % iso_path
566 a21dda8b Iustin Pop
      disk_data.append(iso)
567 a21dda8b Iustin Pop
568 a21dda8b Iustin Pop
    config.write("disk = [%s]\n" % (",".join(disk_data)))
569 a21dda8b Iustin Pop
570 65a6f9b7 Michael Hanselmann
    config.write("on_poweroff = 'destroy'\n")
571 65a6f9b7 Michael Hanselmann
    config.write("on_reboot = 'restart'\n")
572 65a6f9b7 Michael Hanselmann
    config.write("on_crash = 'restart'\n")
573 65a6f9b7 Michael Hanselmann
    if extra_args:
574 65a6f9b7 Michael Hanselmann
      config.write("extra = '%s'\n" % extra_args)
575 65a6f9b7 Michael Hanselmann
    # just in case it exists
576 65a6f9b7 Michael Hanselmann
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
577 65a6f9b7 Michael Hanselmann
    try:
578 65a6f9b7 Michael Hanselmann
      f = open("/etc/xen/%s" % instance.name, "w")
579 65a6f9b7 Michael Hanselmann
      try:
580 65a6f9b7 Michael Hanselmann
        f.write(config.getvalue())
581 65a6f9b7 Michael Hanselmann
      finally:
582 65a6f9b7 Michael Hanselmann
        f.close()
583 65a6f9b7 Michael Hanselmann
    except IOError, err:
584 65a6f9b7 Michael Hanselmann
      raise errors.OpExecError("Cannot write Xen instance confile"
585 65a6f9b7 Michael Hanselmann
                               " file /etc/xen/%s: %s" % (instance.name, err))
586 65a6f9b7 Michael Hanselmann
    return True