Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ 47387b1e

History | View | Annotate | Download (19.2 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 65a6f9b7 Michael Hanselmann
  @staticmethod
47 65a6f9b7 Michael Hanselmann
  def _WriteConfigFile(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 65a6f9b7 Michael Hanselmann
    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 65a6f9b7 Michael Hanselmann
    The return value is a 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 65a6f9b7 Michael Hanselmann
    Args:
121 65a6f9b7 Michael Hanselmann
      instance_name: the instance name
122 65a6f9b7 Michael Hanselmann

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

137 65a6f9b7 Michael Hanselmann
    Returns:
138 65a6f9b7 Michael Hanselmann
      [(name, id, memory, vcpus, stat, times),...]
139 65a6f9b7 Michael Hanselmann
    """
140 65a6f9b7 Michael Hanselmann
    xm_list = self._GetXMList(False)
141 65a6f9b7 Michael Hanselmann
    return xm_list
142 65a6f9b7 Michael Hanselmann
143 65a6f9b7 Michael Hanselmann
  def StartInstance(self, instance, block_devices, extra_args):
144 65a6f9b7 Michael Hanselmann
    """Start an instance."""
145 65a6f9b7 Michael Hanselmann
    self._WriteConfigFile(instance, block_devices, extra_args)
146 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "create", instance.name])
147 65a6f9b7 Michael Hanselmann
148 65a6f9b7 Michael Hanselmann
    if result.failed:
149 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
150 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason,
151 65a6f9b7 Michael Hanselmann
                                    result.output))
152 65a6f9b7 Michael Hanselmann
153 65a6f9b7 Michael Hanselmann
  def StopInstance(self, instance, force=False):
154 65a6f9b7 Michael Hanselmann
    """Stop an instance."""
155 65a6f9b7 Michael Hanselmann
    self._RemoveConfigFile(instance)
156 65a6f9b7 Michael Hanselmann
    if force:
157 65a6f9b7 Michael Hanselmann
      command = ["xm", "destroy", instance.name]
158 65a6f9b7 Michael Hanselmann
    else:
159 65a6f9b7 Michael Hanselmann
      command = ["xm", "shutdown", instance.name]
160 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(command)
161 65a6f9b7 Michael Hanselmann
162 65a6f9b7 Michael Hanselmann
    if result.failed:
163 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to stop instance %s: %s" %
164 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
165 65a6f9b7 Michael Hanselmann
166 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
167 65a6f9b7 Michael Hanselmann
    """Reboot an instance."""
168 65a6f9b7 Michael Hanselmann
    result = utils.RunCmd(["xm", "reboot", instance.name])
169 65a6f9b7 Michael Hanselmann
170 65a6f9b7 Michael Hanselmann
    if result.failed:
171 65a6f9b7 Michael Hanselmann
      raise errors.HypervisorError("Failed to reboot instance %s: %s" %
172 65a6f9b7 Michael Hanselmann
                                   (instance.name, result.fail_reason))
173 65a6f9b7 Michael Hanselmann
174 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
175 65a6f9b7 Michael Hanselmann
    """Return information about the node.
176 65a6f9b7 Michael Hanselmann

177 65a6f9b7 Michael Hanselmann
    The return value is a dict, which has to have the following items:
178 65a6f9b7 Michael Hanselmann
      (all values in MiB)
179 65a6f9b7 Michael Hanselmann
      - memory_total: the total memory size on the node
180 65a6f9b7 Michael Hanselmann
      - memory_free: the available memory on the node for instances
181 65a6f9b7 Michael Hanselmann
      - memory_dom0: the memory used by the node itself, if available
182 65a6f9b7 Michael Hanselmann

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

215 65a6f9b7 Michael Hanselmann
    """
216 04c4330c Alexander Schreiber
    return "xm console %s" % instance.name
217 04c4330c Alexander Schreiber
218 65a6f9b7 Michael Hanselmann
219 65a6f9b7 Michael Hanselmann
  def Verify(self):
220 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
221 65a6f9b7 Michael Hanselmann

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

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

233 65a6f9b7 Michael Hanselmann
    This method builds the xen config disk directive according to the
234 65a6f9b7 Michael Hanselmann
    given disk_template and block_devices.
235 65a6f9b7 Michael Hanselmann

236 65a6f9b7 Michael Hanselmann
    Args:
237 65a6f9b7 Michael Hanselmann
      disk_template: String containing instance disk template
238 65a6f9b7 Michael Hanselmann
      block_devices: List[tuple1,tuple2,...]
239 65a6f9b7 Michael Hanselmann
        tuple: (cfdev, rldev)
240 65a6f9b7 Michael Hanselmann
          cfdev: dict containing ganeti config disk part
241 65a6f9b7 Michael Hanselmann
          rldev: ganeti.bdev.BlockDev object
242 65a6f9b7 Michael Hanselmann

243 65a6f9b7 Michael Hanselmann
    Returns:
244 65a6f9b7 Michael Hanselmann
      String containing disk directive for xen instance config file
245 65a6f9b7 Michael Hanselmann

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

271 6e7275c0 Iustin Pop
    Arguments:
272 6e7275c0 Iustin Pop
      - instance: the name of the instance
273 6e7275c0 Iustin Pop
      - target: the ip of the target node
274 6e7275c0 Iustin Pop
      - live: whether to do live migration or not
275 6e7275c0 Iustin Pop

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

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

281 6e7275c0 Iustin Pop
    """
282 6e7275c0 Iustin Pop
    if self.GetInstanceInfo(instance) is None:
283 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
284 6e7275c0 Iustin Pop
    args = ["xm", "migrate"]
285 6e7275c0 Iustin Pop
    if live:
286 6e7275c0 Iustin Pop
      args.append("-l")
287 6e7275c0 Iustin Pop
    args.extend([instance, target])
288 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
289 6e7275c0 Iustin Pop
    if result.failed:
290 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
291 6e7275c0 Iustin Pop
                                   (instance, result.output))
292 6e7275c0 Iustin Pop
293 65a6f9b7 Michael Hanselmann
294 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
295 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
296 65a6f9b7 Michael Hanselmann
297 f48148c3 Iustin Pop
  PARAMETERS = [
298 f48148c3 Iustin Pop
    constants.HV_KERNEL_PATH,
299 f48148c3 Iustin Pop
    constants.HV_INITRD_PATH,
300 f48148c3 Iustin Pop
    ]
301 f48148c3 Iustin Pop
302 f48148c3 Iustin Pop
  @classmethod
303 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
304 f48148c3 Iustin Pop
    """Check the given parameters for validity.
305 f48148c3 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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