Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_xen.py @ b48909c8

History | View | Annotate | Download (18.8 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 65a6f9b7 Michael Hanselmann
    for cfdev, rldev in block_devices:
253 65a6f9b7 Michael Hanselmann
      if cfdev.dev_type == constants.LD_FILE:
254 65a6f9b7 Michael Hanselmann
        line = "'%s:%s,%s,w'" % (FILE_DRIVER_MAP[cfdev.physical_id[0]],
255 65a6f9b7 Michael Hanselmann
                                 rldev.dev_path, cfdev.iv_name)
256 65a6f9b7 Michael Hanselmann
      else:
257 65a6f9b7 Michael Hanselmann
        line = "'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
258 65a6f9b7 Michael Hanselmann
      disk_data.append(line)
259 65a6f9b7 Michael Hanselmann
260 65a6f9b7 Michael Hanselmann
    return disk_data
261 65a6f9b7 Michael Hanselmann
262 6e7275c0 Iustin Pop
  def MigrateInstance(self, instance, target, live):
263 6e7275c0 Iustin Pop
    """Migrate an instance to a target node.
264 6e7275c0 Iustin Pop

265 6e7275c0 Iustin Pop
    Arguments:
266 6e7275c0 Iustin Pop
      - instance: the name of the instance
267 6e7275c0 Iustin Pop
      - target: the ip of the target node
268 6e7275c0 Iustin Pop
      - live: whether to do live migration or not
269 6e7275c0 Iustin Pop

270 6e7275c0 Iustin Pop
    Returns: none, errors will be signaled by exception.
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 6e7275c0 Iustin Pop
    """
276 6e7275c0 Iustin Pop
    if self.GetInstanceInfo(instance) is None:
277 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Instance not running, cannot migrate")
278 6e7275c0 Iustin Pop
    args = ["xm", "migrate"]
279 6e7275c0 Iustin Pop
    if live:
280 6e7275c0 Iustin Pop
      args.append("-l")
281 6e7275c0 Iustin Pop
    args.extend([instance, target])
282 6e7275c0 Iustin Pop
    result = utils.RunCmd(args)
283 6e7275c0 Iustin Pop
    if result.failed:
284 6e7275c0 Iustin Pop
      raise errors.HypervisorError("Failed to migrate instance %s: %s" %
285 6e7275c0 Iustin Pop
                                   (instance, result.output))
286 6e7275c0 Iustin Pop
287 65a6f9b7 Michael Hanselmann
288 65a6f9b7 Michael Hanselmann
class XenPvmHypervisor(XenHypervisor):
289 65a6f9b7 Michael Hanselmann
  """Xen PVM hypervisor interface"""
290 65a6f9b7 Michael Hanselmann
291 f48148c3 Iustin Pop
  PARAMETERS = [
292 f48148c3 Iustin Pop
    constants.HV_KERNEL_PATH,
293 f48148c3 Iustin Pop
    constants.HV_INITRD_PATH,
294 f48148c3 Iustin Pop
    ]
295 f48148c3 Iustin Pop
296 f48148c3 Iustin Pop
  @classmethod
297 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
298 f48148c3 Iustin Pop
    """Check the given parameters for validity.
299 f48148c3 Iustin Pop

300 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
301 f48148c3 Iustin Pop
    kernel.
302 f48148c3 Iustin Pop

303 f48148c3 Iustin Pop
    @type hvparams:  dict
304 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
305 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
306 f48148c3 Iustin Pop

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

324 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
325 f48148c3 Iustin Pop
    kernel.
326 f48148c3 Iustin Pop

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

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

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

444 f48148c3 Iustin Pop
    For the PVM hypervisor, this only check the existence of the
445 f48148c3 Iustin Pop
    kernel.
446 f48148c3 Iustin Pop

447 f48148c3 Iustin Pop
    @type hvparams:  dict
448 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
449 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
450 f48148c3 Iustin Pop

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

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