Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 5661b908

History | View | Annotate | Download (19.1 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 65a6f9b7 Michael Hanselmann
  def _RemoveConfigFile(instance):
55 65a6f9b7 Michael Hanselmann
    """Remove the xen configuration file.
56 65a6f9b7 Michael Hanselmann

57 65a6f9b7 Michael Hanselmann
    """
58 65a6f9b7 Michael Hanselmann
    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 65a6f9b7 Michael Hanselmann
    self._RemoveConfigFile(instance)
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 2864f2d9 Iustin Pop
    for sd_name, (cfdev, rldev) 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 2864f2d9 Iustin Pop
                                 rldev.dev_path, sd_name)
263 65a6f9b7 Michael Hanselmann
      else:
264 2864f2d9 Iustin Pop
        line = "'phy:%s,%s,w'" % (rldev.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
    Arguments:
273 6e7275c0 Iustin Pop
      - instance: the name of the instance
274 6e7275c0 Iustin Pop
      - target: the ip of the target node
275 6e7275c0 Iustin Pop
      - live: whether to do live migration or not
276 6e7275c0 Iustin Pop

277 6e7275c0 Iustin Pop
    Returns: none, errors will be signaled by exception.
278 6e7275c0 Iustin Pop

279 6e7275c0 Iustin Pop
    The migration will not be attempted if the instance is not
280 6e7275c0 Iustin Pop
    currently running.
281 6e7275c0 Iustin Pop

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 6e7275c0 Iustin Pop
294 65a6f9b7 Michael Hanselmann
295 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
296 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
297 65a6f9b7 Michael Hanselmann
298 f48148c3 Iustin Pop
  PARAMETERS = [
299 f48148c3 Iustin Pop
    constants.HV_KERNEL_PATH,
300 f48148c3 Iustin Pop
    constants.HV_INITRD_PATH,
301 f48148c3 Iustin Pop
    ]
302 f48148c3 Iustin Pop
303 f48148c3 Iustin Pop
  @classmethod
304 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
305 f48148c3 Iustin Pop
    """Check the given parameters for validity.
306 f48148c3 Iustin Pop

307 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
308 f48148c3 Iustin Pop
    kernel.
309 f48148c3 Iustin Pop

310 f48148c3 Iustin Pop
    @type hvparams:  dict
311 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
312 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
313 f48148c3 Iustin Pop

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

331 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
332 f48148c3 Iustin Pop
    kernel.
333 f48148c3 Iustin Pop

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

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

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

451 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
452 f48148c3 Iustin Pop
    kernel.
453 f48148c3 Iustin Pop

454 f48148c3 Iustin Pop
    @type hvparams:  dict
455 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
456 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
457 f48148c3 Iustin Pop

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

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