Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor.py @ 2a6469d5

History | View | Annotate | Download (18.9 kB)

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

24 a8083063 Iustin Pop
"""
25 a8083063 Iustin Pop
26 a8083063 Iustin Pop
import time
27 a8083063 Iustin Pop
import os
28 a8083063 Iustin Pop
from cStringIO import StringIO
29 a8083063 Iustin Pop
30 a8083063 Iustin Pop
from ganeti import utils
31 a8083063 Iustin Pop
from ganeti import logger
32 a8083063 Iustin Pop
from ganeti import ssconf
33 f00b46bc Michael Hanselmann
from ganeti import constants
34 2a6469d5 Alexander Schreiber
from ganeti import errors
35 a8083063 Iustin Pop
from ganeti.errors import HypervisorError
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
def GetHypervisor():
39 a8083063 Iustin Pop
  """Return a Hypervisor instance.
40 a8083063 Iustin Pop

41 a8083063 Iustin Pop
  This function parses the cluster hypervisor configuration file and
42 a8083063 Iustin Pop
  instantiates a class based on the value of this file.
43 a8083063 Iustin Pop

44 a8083063 Iustin Pop
  """
45 a8083063 Iustin Pop
  ht_kind = ssconf.SimpleStore().GetHypervisorType()
46 631eb662 Alexander Schreiber
  if ht_kind == constants.HT_XEN_PVM30:
47 631eb662 Alexander Schreiber
    cls = XenPvmHypervisor
48 2584d4a4 Alexander Schreiber
  elif ht_kind == constants.HT_FAKE:
49 a8083063 Iustin Pop
    cls = FakeHypervisor
50 2a6469d5 Alexander Schreiber
  elif ht_kind == constants.HT_XEN_HVM31:
51 2a6469d5 Alexander Schreiber
    cls = XenHvmHypervisor
52 a8083063 Iustin Pop
  else:
53 3ecf6786 Iustin Pop
    raise HypervisorError("Unknown hypervisor type '%s'" % ht_kind)
54 a8083063 Iustin Pop
  return cls()
55 a8083063 Iustin Pop
56 a8083063 Iustin Pop
57 a8083063 Iustin Pop
class BaseHypervisor(object):
58 a8083063 Iustin Pop
  """Abstract virtualisation technology interface
59 a8083063 Iustin Pop

60 a8083063 Iustin Pop
  The goal is that all aspects of the virtualisation technology must
61 a8083063 Iustin Pop
  be abstracted away from the rest of code.
62 a8083063 Iustin Pop

63 a8083063 Iustin Pop
  """
64 a8083063 Iustin Pop
  def __init__(self):
65 a8083063 Iustin Pop
    pass
66 a8083063 Iustin Pop
67 a8083063 Iustin Pop
  def StartInstance(self, instance, block_devices, extra_args):
68 a8083063 Iustin Pop
    """Start an instance."""
69 a8083063 Iustin Pop
    raise NotImplementedError
70 a8083063 Iustin Pop
71 a8083063 Iustin Pop
  def StopInstance(self, instance, force=False):
72 a8083063 Iustin Pop
    """Stop an instance."""
73 a8083063 Iustin Pop
    raise NotImplementedError
74 a8083063 Iustin Pop
75 7e1394dc Alexander Schreiber
  def RebootInstance(self, instance):
76 7e1394dc Alexander Schreiber
    """Reboot an instance."""
77 7e1394dc Alexander Schreiber
    raise NotImplementedError
78 7e1394dc Alexander Schreiber
79 a8083063 Iustin Pop
  def ListInstances(self):
80 a8083063 Iustin Pop
    """Get the list of running instances."""
81 a8083063 Iustin Pop
    raise NotImplementedError
82 a8083063 Iustin Pop
83 a8083063 Iustin Pop
  def GetInstanceInfo(self, instance_name):
84 a8083063 Iustin Pop
    """Get instance properties.
85 a8083063 Iustin Pop

86 a8083063 Iustin Pop
    Args:
87 a8083063 Iustin Pop
      instance_name: the instance name
88 a8083063 Iustin Pop

89 a8083063 Iustin Pop
    Returns:
90 a8083063 Iustin Pop
      (name, id, memory, vcpus, state, times)
91 a8083063 Iustin Pop

92 a8083063 Iustin Pop
    """
93 a8083063 Iustin Pop
    raise NotImplementedError
94 a8083063 Iustin Pop
95 a8083063 Iustin Pop
  def GetAllInstancesInfo(self):
96 a8083063 Iustin Pop
    """Get properties of all instances.
97 a8083063 Iustin Pop

98 a8083063 Iustin Pop
    Returns:
99 a8083063 Iustin Pop
      [(name, id, memory, vcpus, stat, times),...]
100 a8083063 Iustin Pop
    """
101 a8083063 Iustin Pop
    raise NotImplementedError
102 a8083063 Iustin Pop
103 a8083063 Iustin Pop
  def GetNodeInfo(self):
104 a8083063 Iustin Pop
    """Return information about the node.
105 a8083063 Iustin Pop

106 a8083063 Iustin Pop
    The return value is a dict, which has to have the following items:
107 a8083063 Iustin Pop
      (all values in MiB)
108 a8083063 Iustin Pop
      - memory_total: the total memory size on the node
109 a8083063 Iustin Pop
      - memory_free: the available memory on the node for instances
110 a8083063 Iustin Pop
      - memory_dom0: the memory used by the node itself, if available
111 a8083063 Iustin Pop

112 a8083063 Iustin Pop
    """
113 a8083063 Iustin Pop
    raise NotImplementedError
114 a8083063 Iustin Pop
115 a8083063 Iustin Pop
  @staticmethod
116 30989e69 Alexander Schreiber
  def GetShellCommandForConsole(instance):
117 a8083063 Iustin Pop
    """Return a command for connecting to the console of an instance.
118 a8083063 Iustin Pop

119 a8083063 Iustin Pop
    """
120 a8083063 Iustin Pop
    raise NotImplementedError
121 a8083063 Iustin Pop
122 a8083063 Iustin Pop
  def Verify(self):
123 a8083063 Iustin Pop
    """Verify the hypervisor.
124 a8083063 Iustin Pop

125 a8083063 Iustin Pop
    """
126 a8083063 Iustin Pop
    raise NotImplementedError
127 a8083063 Iustin Pop
128 a8083063 Iustin Pop
129 a8083063 Iustin Pop
class XenHypervisor(BaseHypervisor):
130 631eb662 Alexander Schreiber
  """Xen generic hypervisor interface
131 631eb662 Alexander Schreiber

132 631eb662 Alexander Schreiber
  This is the Xen base class used for both Xen PVM and HVM. It contains
133 631eb662 Alexander Schreiber
  all the functionality that is identical for both.
134 631eb662 Alexander Schreiber

135 631eb662 Alexander Schreiber
  """
136 a8083063 Iustin Pop
137 a8083063 Iustin Pop
  @staticmethod
138 a8083063 Iustin Pop
  def _WriteConfigFile(instance, block_devices, extra_args):
139 631eb662 Alexander Schreiber
    """A Xen instance config file.
140 a8083063 Iustin Pop

141 a8083063 Iustin Pop
    """
142 631eb662 Alexander Schreiber
    raise NotImplementedError
143 a8083063 Iustin Pop
144 a8083063 Iustin Pop
  @staticmethod
145 a8083063 Iustin Pop
  def _RemoveConfigFile(instance):
146 a8083063 Iustin Pop
    """Remove the xen configuration file.
147 a8083063 Iustin Pop

148 a8083063 Iustin Pop
    """
149 a8083063 Iustin Pop
    utils.RemoveFile("/etc/xen/%s" % instance.name)
150 a8083063 Iustin Pop
151 a8083063 Iustin Pop
  @staticmethod
152 a8083063 Iustin Pop
  def _GetXMList(include_node):
153 a8083063 Iustin Pop
    """Return the list of running instances.
154 a8083063 Iustin Pop

155 a8083063 Iustin Pop
    If the `include_node` argument is True, then we return information
156 a8083063 Iustin Pop
    for dom0 also, otherwise we filter that from the return value.
157 a8083063 Iustin Pop

158 a8083063 Iustin Pop
    The return value is a list of (name, id, memory, vcpus, state, time spent)
159 a8083063 Iustin Pop

160 a8083063 Iustin Pop
    """
161 a8083063 Iustin Pop
    for dummy in range(5):
162 a8083063 Iustin Pop
      result = utils.RunCmd(["xm", "list"])
163 a8083063 Iustin Pop
      if not result.failed:
164 a8083063 Iustin Pop
        break
165 a8083063 Iustin Pop
      logger.Error("xm list failed (%s): %s" % (result.fail_reason,
166 a8083063 Iustin Pop
                                                result.output))
167 a8083063 Iustin Pop
      time.sleep(1)
168 a8083063 Iustin Pop
169 a8083063 Iustin Pop
    if result.failed:
170 a8083063 Iustin Pop
      raise HypervisorError("xm list failed, retries exceeded (%s): %s" %
171 a8083063 Iustin Pop
                            (result.fail_reason, result.stderr))
172 a8083063 Iustin Pop
173 a8083063 Iustin Pop
    # skip over the heading and the domain 0 line (optional)
174 a8083063 Iustin Pop
    if include_node:
175 a8083063 Iustin Pop
      to_skip = 1
176 a8083063 Iustin Pop
    else:
177 a8083063 Iustin Pop
      to_skip = 2
178 a8083063 Iustin Pop
    lines = result.stdout.splitlines()[to_skip:]
179 a8083063 Iustin Pop
    result = []
180 a8083063 Iustin Pop
    for line in lines:
181 a8083063 Iustin Pop
      # The format of lines is:
182 a8083063 Iustin Pop
      # Name      ID Mem(MiB) VCPUs State  Time(s)
183 a8083063 Iustin Pop
      # Domain-0   0  3418     4 r-----    266.2
184 a8083063 Iustin Pop
      data = line.split()
185 a8083063 Iustin Pop
      if len(data) != 6:
186 a8083063 Iustin Pop
        raise HypervisorError("Can't parse output of xm list, line: %s" % line)
187 a8083063 Iustin Pop
      try:
188 a8083063 Iustin Pop
        data[1] = int(data[1])
189 a8083063 Iustin Pop
        data[2] = int(data[2])
190 a8083063 Iustin Pop
        data[3] = int(data[3])
191 a8083063 Iustin Pop
        data[5] = float(data[5])
192 a8083063 Iustin Pop
      except ValueError, err:
193 a8083063 Iustin Pop
        raise HypervisorError("Can't parse output of xm list,"
194 a8083063 Iustin Pop
                              " line: %s, error: %s" % (line, err))
195 a8083063 Iustin Pop
      result.append(data)
196 a8083063 Iustin Pop
    return result
197 a8083063 Iustin Pop
198 a8083063 Iustin Pop
  def ListInstances(self):
199 a8083063 Iustin Pop
    """Get the list of running instances.
200 a8083063 Iustin Pop

201 a8083063 Iustin Pop
    """
202 a8083063 Iustin Pop
    xm_list = self._GetXMList(False)
203 a8083063 Iustin Pop
    names = [info[0] for info in xm_list]
204 a8083063 Iustin Pop
    return names
205 a8083063 Iustin Pop
206 a8083063 Iustin Pop
  def GetInstanceInfo(self, instance_name):
207 a8083063 Iustin Pop
    """Get instance properties.
208 a8083063 Iustin Pop

209 a8083063 Iustin Pop
    Args:
210 a8083063 Iustin Pop
      instance_name: the instance name
211 a8083063 Iustin Pop

212 a8083063 Iustin Pop
    Returns:
213 a8083063 Iustin Pop
      (name, id, memory, vcpus, stat, times)
214 a8083063 Iustin Pop
    """
215 a8083063 Iustin Pop
    xm_list = self._GetXMList(instance_name=="Domain-0")
216 a8083063 Iustin Pop
    result = None
217 a8083063 Iustin Pop
    for data in xm_list:
218 a8083063 Iustin Pop
      if data[0] == instance_name:
219 a8083063 Iustin Pop
        result = data
220 a8083063 Iustin Pop
        break
221 a8083063 Iustin Pop
    return result
222 a8083063 Iustin Pop
223 a8083063 Iustin Pop
  def GetAllInstancesInfo(self):
224 a8083063 Iustin Pop
    """Get properties of all instances.
225 a8083063 Iustin Pop

226 a8083063 Iustin Pop
    Returns:
227 a8083063 Iustin Pop
      [(name, id, memory, vcpus, stat, times),...]
228 a8083063 Iustin Pop
    """
229 a8083063 Iustin Pop
    xm_list = self._GetXMList(False)
230 a8083063 Iustin Pop
    return xm_list
231 a8083063 Iustin Pop
232 a8083063 Iustin Pop
  def StartInstance(self, instance, block_devices, extra_args):
233 a8083063 Iustin Pop
    """Start an instance."""
234 a8083063 Iustin Pop
    self._WriteConfigFile(instance, block_devices, extra_args)
235 a8083063 Iustin Pop
    result = utils.RunCmd(["xm", "create", instance.name])
236 a8083063 Iustin Pop
237 a8083063 Iustin Pop
    if result.failed:
238 523687d7 Iustin Pop
      raise HypervisorError("Failed to start instance %s: %s (%s)" %
239 523687d7 Iustin Pop
                            (instance.name, result.fail_reason, result.output))
240 a8083063 Iustin Pop
241 a8083063 Iustin Pop
  def StopInstance(self, instance, force=False):
242 a8083063 Iustin Pop
    """Stop an instance."""
243 a8083063 Iustin Pop
    self._RemoveConfigFile(instance)
244 a8083063 Iustin Pop
    if force:
245 a8083063 Iustin Pop
      command = ["xm", "destroy", instance.name]
246 a8083063 Iustin Pop
    else:
247 a8083063 Iustin Pop
      command = ["xm", "shutdown", instance.name]
248 a8083063 Iustin Pop
    result = utils.RunCmd(command)
249 a8083063 Iustin Pop
250 a8083063 Iustin Pop
    if result.failed:
251 a8083063 Iustin Pop
      raise HypervisorError("Failed to stop instance %s: %s" %
252 a8083063 Iustin Pop
                            (instance.name, result.fail_reason))
253 a8083063 Iustin Pop
254 7e1394dc Alexander Schreiber
  def RebootInstance(self, instance):
255 7e1394dc Alexander Schreiber
    """Reboot an instance."""
256 7e1394dc Alexander Schreiber
    result = utils.RunCmd(["xm", "reboot", instance.name])
257 7e1394dc Alexander Schreiber
258 7e1394dc Alexander Schreiber
    if result.failed:
259 7e1394dc Alexander Schreiber
      raise HypervisorError("Failed to reboot instance %s: %s" %
260 7e1394dc Alexander Schreiber
                            (instance.name, result.fail_reason))
261 7e1394dc Alexander Schreiber
262 a8083063 Iustin Pop
  def GetNodeInfo(self):
263 a8083063 Iustin Pop
    """Return information about the node.
264 a8083063 Iustin Pop

265 a8083063 Iustin Pop
    The return value is a dict, which has to have the following items:
266 a8083063 Iustin Pop
      (all values in MiB)
267 a8083063 Iustin Pop
      - memory_total: the total memory size on the node
268 a8083063 Iustin Pop
      - memory_free: the available memory on the node for instances
269 a8083063 Iustin Pop
      - memory_dom0: the memory used by the node itself, if available
270 a8083063 Iustin Pop

271 a8083063 Iustin Pop
    """
272 a8083063 Iustin Pop
    # note: in xen 3, memory has changed to total_memory
273 a8083063 Iustin Pop
    result = utils.RunCmd(["xm", "info"])
274 a8083063 Iustin Pop
    if result.failed:
275 a8083063 Iustin Pop
      logger.Error("Can't run 'xm info': %s" % result.fail_reason)
276 a8083063 Iustin Pop
      return None
277 a8083063 Iustin Pop
278 a8083063 Iustin Pop
    xmoutput = result.stdout.splitlines()
279 a8083063 Iustin Pop
    result = {}
280 a8083063 Iustin Pop
    for line in xmoutput:
281 a8083063 Iustin Pop
      splitfields = line.split(":", 1)
282 a8083063 Iustin Pop
283 a8083063 Iustin Pop
      if len(splitfields) > 1:
284 a8083063 Iustin Pop
        key = splitfields[0].strip()
285 a8083063 Iustin Pop
        val = splitfields[1].strip()
286 a8083063 Iustin Pop
        if key == 'memory' or key == 'total_memory':
287 a8083063 Iustin Pop
          result['memory_total'] = int(val)
288 a8083063 Iustin Pop
        elif key == 'free_memory':
289 a8083063 Iustin Pop
          result['memory_free'] = int(val)
290 a8083063 Iustin Pop
    dom0_info = self.GetInstanceInfo("Domain-0")
291 a8083063 Iustin Pop
    if dom0_info is not None:
292 a8083063 Iustin Pop
      result['memory_dom0'] = dom0_info[2]
293 a8083063 Iustin Pop
294 a8083063 Iustin Pop
    return result
295 a8083063 Iustin Pop
296 a8083063 Iustin Pop
  @staticmethod
297 30989e69 Alexander Schreiber
  def GetShellCommandForConsole(instance):
298 a8083063 Iustin Pop
    """Return a command for connecting to the console of an instance.
299 a8083063 Iustin Pop

300 a8083063 Iustin Pop
    """
301 631eb662 Alexander Schreiber
    raise NotImplementedError
302 a8083063 Iustin Pop
303 a8083063 Iustin Pop
304 a8083063 Iustin Pop
  def Verify(self):
305 a8083063 Iustin Pop
    """Verify the hypervisor.
306 a8083063 Iustin Pop

307 a8083063 Iustin Pop
    For Xen, this verifies that the xend process is running.
308 a8083063 Iustin Pop

309 a8083063 Iustin Pop
    """
310 a8083063 Iustin Pop
    if not utils.CheckDaemonAlive('/var/run/xend.pid', 'xend'):
311 a8083063 Iustin Pop
      return "xend daemon is not running"
312 a8083063 Iustin Pop
313 a8083063 Iustin Pop
314 631eb662 Alexander Schreiber
class XenPvmHypervisor(XenHypervisor):
315 631eb662 Alexander Schreiber
  """Xen PVM hypervisor interface"""
316 631eb662 Alexander Schreiber
317 631eb662 Alexander Schreiber
  @staticmethod
318 631eb662 Alexander Schreiber
  def _WriteConfigFile(instance, block_devices, extra_args):
319 631eb662 Alexander Schreiber
    """Create a Xen instance config file.
320 631eb662 Alexander Schreiber

321 631eb662 Alexander Schreiber
    """
322 631eb662 Alexander Schreiber
    config = StringIO()
323 631eb662 Alexander Schreiber
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
324 631eb662 Alexander Schreiber
    config.write("kernel = '%s'\n" % constants.XEN_KERNEL)
325 631eb662 Alexander Schreiber
    if os.path.exists(constants.XEN_INITRD):
326 631eb662 Alexander Schreiber
      config.write("ramdisk = '%s'\n" % constants.XEN_INITRD)
327 631eb662 Alexander Schreiber
    config.write("memory = %d\n" % instance.memory)
328 631eb662 Alexander Schreiber
    config.write("vcpus = %d\n" % instance.vcpus)
329 631eb662 Alexander Schreiber
    config.write("name = '%s'\n" % instance.name)
330 631eb662 Alexander Schreiber
331 631eb662 Alexander Schreiber
    vif_data = []
332 631eb662 Alexander Schreiber
    for nic in instance.nics:
333 631eb662 Alexander Schreiber
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
334 631eb662 Alexander Schreiber
      ip = getattr(nic, "ip", None)
335 631eb662 Alexander Schreiber
      if ip is not None:
336 631eb662 Alexander Schreiber
        nic_str += ", ip=%s" % ip
337 631eb662 Alexander Schreiber
      vif_data.append("'%s'" % nic_str)
338 631eb662 Alexander Schreiber
339 631eb662 Alexander Schreiber
    config.write("vif = [%s]\n" % ",".join(vif_data))
340 631eb662 Alexander Schreiber
341 631eb662 Alexander Schreiber
    disk_data = ["'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
342 631eb662 Alexander Schreiber
                 for cfdev, rldev in block_devices]
343 631eb662 Alexander Schreiber
    config.write("disk = [%s]\n" % ",".join(disk_data))
344 631eb662 Alexander Schreiber
345 631eb662 Alexander Schreiber
    config.write("root = '/dev/sda ro'\n")
346 631eb662 Alexander Schreiber
    config.write("on_poweroff = 'destroy'\n")
347 631eb662 Alexander Schreiber
    config.write("on_reboot = 'restart'\n")
348 631eb662 Alexander Schreiber
    config.write("on_crash = 'restart'\n")
349 631eb662 Alexander Schreiber
    if extra_args:
350 631eb662 Alexander Schreiber
      config.write("extra = '%s'\n" % extra_args)
351 631eb662 Alexander Schreiber
    # just in case it exists
352 631eb662 Alexander Schreiber
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
353 01121d61 Alexander Schreiber
    try:
354 01121d61 Alexander Schreiber
      f = open("/etc/xen/%s" % instance.name, "w")
355 01121d61 Alexander Schreiber
      try:
356 01121d61 Alexander Schreiber
        f.write(config.getvalue())
357 01121d61 Alexander Schreiber
      finally:
358 01121d61 Alexander Schreiber
        f.close()
359 01121d61 Alexander Schreiber
    except IOError, err:
360 01121d61 Alexander Schreiber
      raise errors.OpExecError("Cannot write Xen instance confile"
361 01121d61 Alexander Schreiber
                               " file /etc/xen/%s: %s" % (instance.name, err))
362 631eb662 Alexander Schreiber
    return True
363 631eb662 Alexander Schreiber
364 631eb662 Alexander Schreiber
  @staticmethod
365 631eb662 Alexander Schreiber
  def GetShellCommandForConsole(instance):
366 631eb662 Alexander Schreiber
    """Return a command for connecting to the console of an instance.
367 631eb662 Alexander Schreiber

368 631eb662 Alexander Schreiber
    """
369 631eb662 Alexander Schreiber
    return "xm console %s" % instance.name
370 631eb662 Alexander Schreiber
371 631eb662 Alexander Schreiber
372 a8083063 Iustin Pop
class FakeHypervisor(BaseHypervisor):
373 a8083063 Iustin Pop
  """Fake hypervisor interface.
374 a8083063 Iustin Pop

375 a8083063 Iustin Pop
  This can be used for testing the ganeti code without having to have
376 a8083063 Iustin Pop
  a real virtualisation software installed.
377 a8083063 Iustin Pop

378 a8083063 Iustin Pop
  """
379 a8083063 Iustin Pop
  _ROOT_DIR = "/var/run/ganeti-fake-hypervisor"
380 a8083063 Iustin Pop
381 a8083063 Iustin Pop
  def __init__(self):
382 a8083063 Iustin Pop
    BaseHypervisor.__init__(self)
383 a8083063 Iustin Pop
    if not os.path.exists(self._ROOT_DIR):
384 a8083063 Iustin Pop
      os.mkdir(self._ROOT_DIR)
385 a8083063 Iustin Pop
386 a8083063 Iustin Pop
  def ListInstances(self):
387 a8083063 Iustin Pop
    """Get the list of running instances.
388 a8083063 Iustin Pop

389 a8083063 Iustin Pop
    """
390 a8083063 Iustin Pop
    return os.listdir(self._ROOT_DIR)
391 a8083063 Iustin Pop
392 a8083063 Iustin Pop
  def GetInstanceInfo(self, instance_name):
393 a8083063 Iustin Pop
    """Get instance properties.
394 a8083063 Iustin Pop

395 a8083063 Iustin Pop
    Args:
396 a8083063 Iustin Pop
      instance_name: the instance name
397 a8083063 Iustin Pop

398 a8083063 Iustin Pop
    Returns:
399 a8083063 Iustin Pop
      (name, id, memory, vcpus, stat, times)
400 a8083063 Iustin Pop
    """
401 a8083063 Iustin Pop
    file_name = "%s/%s" % (self._ROOT_DIR, instance_name)
402 a8083063 Iustin Pop
    if not os.path.exists(file_name):
403 a8083063 Iustin Pop
      return None
404 a8083063 Iustin Pop
    try:
405 a8083063 Iustin Pop
      fh = file(file_name, "r")
406 a8083063 Iustin Pop
      try:
407 a8083063 Iustin Pop
        inst_id = fh.readline().strip()
408 a8083063 Iustin Pop
        memory = fh.readline().strip()
409 a8083063 Iustin Pop
        vcpus = fh.readline().strip()
410 a8083063 Iustin Pop
        stat = "---b-"
411 a8083063 Iustin Pop
        times = "0"
412 a8083063 Iustin Pop
        return (instance_name, inst_id, memory, vcpus, stat, times)
413 a8083063 Iustin Pop
      finally:
414 a8083063 Iustin Pop
        fh.close()
415 a8083063 Iustin Pop
    except IOError, err:
416 a8083063 Iustin Pop
      raise HypervisorError("Failed to list instance %s: %s" %
417 a8083063 Iustin Pop
                            (instance_name, err))
418 a8083063 Iustin Pop
419 a8083063 Iustin Pop
  def GetAllInstancesInfo(self):
420 a8083063 Iustin Pop
    """Get properties of all instances.
421 a8083063 Iustin Pop

422 a8083063 Iustin Pop
    Returns:
423 a8083063 Iustin Pop
      [(name, id, memory, vcpus, stat, times),...]
424 a8083063 Iustin Pop
    """
425 a8083063 Iustin Pop
    data = []
426 a8083063 Iustin Pop
    for file_name in os.listdir(self._ROOT_DIR):
427 a8083063 Iustin Pop
      try:
428 a8083063 Iustin Pop
        fh = file(self._ROOT_DIR+"/"+file_name, "r")
429 a8083063 Iustin Pop
        inst_id = "-1"
430 a8083063 Iustin Pop
        memory = "0"
431 a8083063 Iustin Pop
        stat = "-----"
432 a8083063 Iustin Pop
        times = "-1"
433 a8083063 Iustin Pop
        try:
434 a8083063 Iustin Pop
          inst_id = fh.readline().strip()
435 a8083063 Iustin Pop
          memory = fh.readline().strip()
436 a8083063 Iustin Pop
          vcpus = fh.readline().strip()
437 a8083063 Iustin Pop
          stat = "---b-"
438 a8083063 Iustin Pop
          times = "0"
439 a8083063 Iustin Pop
        finally:
440 a8083063 Iustin Pop
          fh.close()
441 a8083063 Iustin Pop
        data.append((file_name, inst_id, memory, vcpus, stat, times))
442 a8083063 Iustin Pop
      except IOError, err:
443 a8083063 Iustin Pop
        raise HypervisorError("Failed to list instances: %s" % err)
444 a8083063 Iustin Pop
    return data
445 a8083063 Iustin Pop
446 a8083063 Iustin Pop
  def StartInstance(self, instance, force, extra_args):
447 a8083063 Iustin Pop
    """Start an instance.
448 a8083063 Iustin Pop

449 a8083063 Iustin Pop
    For the fake hypervisor, it just creates a file in the base dir,
450 a8083063 Iustin Pop
    creating an exception if it already exists. We don't actually
451 a8083063 Iustin Pop
    handle race conditions properly, since these are *FAKE* instances.
452 a8083063 Iustin Pop

453 a8083063 Iustin Pop
    """
454 a8083063 Iustin Pop
    file_name = self._ROOT_DIR + "/%s" % instance.name
455 a8083063 Iustin Pop
    if os.path.exists(file_name):
456 a8083063 Iustin Pop
      raise HypervisorError("Failed to start instance %s: %s" %
457 a8083063 Iustin Pop
                            (instance.name, "already running"))
458 a8083063 Iustin Pop
    try:
459 a8083063 Iustin Pop
      fh = file(file_name, "w")
460 a8083063 Iustin Pop
      try:
461 a8083063 Iustin Pop
        fh.write("0\n%d\n%d\n" % (instance.memory, instance.vcpus))
462 a8083063 Iustin Pop
      finally:
463 a8083063 Iustin Pop
        fh.close()
464 a8083063 Iustin Pop
    except IOError, err:
465 a8083063 Iustin Pop
      raise HypervisorError("Failed to start instance %s: %s" %
466 a8083063 Iustin Pop
                            (instance.name, err))
467 a8083063 Iustin Pop
468 a8083063 Iustin Pop
  def StopInstance(self, instance, force=False):
469 a8083063 Iustin Pop
    """Stop an instance.
470 a8083063 Iustin Pop

471 a8083063 Iustin Pop
    For the fake hypervisor, this just removes the file in the base
472 a8083063 Iustin Pop
    dir, if it exist, otherwise we raise an exception.
473 a8083063 Iustin Pop

474 a8083063 Iustin Pop
    """
475 a8083063 Iustin Pop
    file_name = self._ROOT_DIR + "/%s" % instance.name
476 a8083063 Iustin Pop
    if not os.path.exists(file_name):
477 a8083063 Iustin Pop
      raise HypervisorError("Failed to stop instance %s: %s" %
478 a8083063 Iustin Pop
                            (instance.name, "not running"))
479 a8083063 Iustin Pop
    utils.RemoveFile(file_name)
480 a8083063 Iustin Pop
481 7e1394dc Alexander Schreiber
  def RebootInstance(self, instance):
482 7e1394dc Alexander Schreiber
    """Reboot an instance.
483 7e1394dc Alexander Schreiber

484 7e1394dc Alexander Schreiber
    For the fake hypervisor, this does nothing.
485 7e1394dc Alexander Schreiber

486 7e1394dc Alexander Schreiber
    """
487 7e1394dc Alexander Schreiber
    return
488 7e1394dc Alexander Schreiber
489 a8083063 Iustin Pop
  def GetNodeInfo(self):
490 a8083063 Iustin Pop
    """Return information about the node.
491 a8083063 Iustin Pop

492 a8083063 Iustin Pop
    The return value is a dict, which has to have the following items:
493 a8083063 Iustin Pop
      (all values in MiB)
494 a8083063 Iustin Pop
      - memory_total: the total memory size on the node
495 a8083063 Iustin Pop
      - memory_free: the available memory on the node for instances
496 a8083063 Iustin Pop
      - memory_dom0: the memory used by the node itself, if available
497 a8083063 Iustin Pop

498 a8083063 Iustin Pop
    """
499 a8083063 Iustin Pop
    # global ram usage from the xm info command
500 a8083063 Iustin Pop
    # memory                 : 3583
501 a8083063 Iustin Pop
    # free_memory            : 747
502 a8083063 Iustin Pop
    # note: in xen 3, memory has changed to total_memory
503 a8083063 Iustin Pop
    try:
504 a8083063 Iustin Pop
      fh = file("/proc/meminfo")
505 a8083063 Iustin Pop
      try:
506 a8083063 Iustin Pop
        data = fh.readlines()
507 a8083063 Iustin Pop
      finally:
508 a8083063 Iustin Pop
        fh.close()
509 a8083063 Iustin Pop
    except IOError, err:
510 a8083063 Iustin Pop
      raise HypervisorError("Failed to list node info: %s" % err)
511 a8083063 Iustin Pop
512 a8083063 Iustin Pop
    result = {}
513 a8083063 Iustin Pop
    sum_free = 0
514 a8083063 Iustin Pop
    for line in data:
515 a8083063 Iustin Pop
      splitfields = line.split(":", 1)
516 a8083063 Iustin Pop
517 a8083063 Iustin Pop
      if len(splitfields) > 1:
518 a8083063 Iustin Pop
        key = splitfields[0].strip()
519 a8083063 Iustin Pop
        val = splitfields[1].strip()
520 a8083063 Iustin Pop
        if key == 'MemTotal':
521 a8083063 Iustin Pop
          result['memory_total'] = int(val.split()[0])/1024
522 a8083063 Iustin Pop
        elif key in ('MemFree', 'Buffers', 'Cached'):
523 a8083063 Iustin Pop
          sum_free += int(val.split()[0])/1024
524 a8083063 Iustin Pop
        elif key == 'Active':
525 a8083063 Iustin Pop
          result['memory_dom0'] = int(val.split()[0])/1024
526 a8083063 Iustin Pop
527 a8083063 Iustin Pop
    result['memory_free'] = sum_free
528 a8083063 Iustin Pop
    return result
529 a8083063 Iustin Pop
530 a8083063 Iustin Pop
  @staticmethod
531 30989e69 Alexander Schreiber
  def GetShellCommandForConsole(instance):
532 a8083063 Iustin Pop
    """Return a command for connecting to the console of an instance.
533 a8083063 Iustin Pop

534 a8083063 Iustin Pop
    """
535 a8083063 Iustin Pop
    return "echo Console not available for fake hypervisor"
536 a8083063 Iustin Pop
537 a8083063 Iustin Pop
  def Verify(self):
538 a8083063 Iustin Pop
    """Verify the hypervisor.
539 a8083063 Iustin Pop

540 a8083063 Iustin Pop
    For the fake hypervisor, it just checks the existence of the base
541 a8083063 Iustin Pop
    dir.
542 a8083063 Iustin Pop

543 a8083063 Iustin Pop
    """
544 a8083063 Iustin Pop
    if not os.path.exists(self._ROOT_DIR):
545 a8083063 Iustin Pop
      return "The required directory '%s' does not exist." % self._ROOT_DIR
546 2a6469d5 Alexander Schreiber
547 2a6469d5 Alexander Schreiber
548 2a6469d5 Alexander Schreiber
class XenHvmHypervisor(XenHypervisor):
549 2a6469d5 Alexander Schreiber
  """Xen HVM hypervisor interface"""
550 2a6469d5 Alexander Schreiber
551 2a6469d5 Alexander Schreiber
  @staticmethod
552 2a6469d5 Alexander Schreiber
  def _WriteConfigFile(instance, block_devices, extra_args):
553 2a6469d5 Alexander Schreiber
    """Create a Xen 3.1 HVM config file.
554 2a6469d5 Alexander Schreiber

555 2a6469d5 Alexander Schreiber
    """
556 2a6469d5 Alexander Schreiber
    config = StringIO()
557 2a6469d5 Alexander Schreiber
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
558 2a6469d5 Alexander Schreiber
    config.write("kernel = '/usr/lib/xen/boot/hvmloader'\n")
559 2a6469d5 Alexander Schreiber
    config.write("builder = 'hvm'\n")
560 2a6469d5 Alexander Schreiber
    config.write("memory = %d\n" % instance.memory)
561 2a6469d5 Alexander Schreiber
    config.write("vcpus = %d\n" % instance.vcpus)
562 2a6469d5 Alexander Schreiber
    config.write("name = '%s'\n" % instance.name)
563 2a6469d5 Alexander Schreiber
    config.write("pae = 1\n")
564 2a6469d5 Alexander Schreiber
    config.write("acpi = 1\n")
565 2a6469d5 Alexander Schreiber
    config.write("apic = 1\n")
566 2a6469d5 Alexander Schreiber
    arch = os.uname()[4]
567 2a6469d5 Alexander Schreiber
    if '64' in arch:
568 2a6469d5 Alexander Schreiber
      config.write("device_model = '/usr/lib64/xen/bin/qemu-dm'\n")
569 2a6469d5 Alexander Schreiber
    else:
570 2a6469d5 Alexander Schreiber
      config.write("device_model = '/usr/lib/xen/bin/qemu-dm'\n")
571 2a6469d5 Alexander Schreiber
    config.write("boot = 'dc'\n")
572 2a6469d5 Alexander Schreiber
    config.write("sdl = 0\n")
573 2a6469d5 Alexander Schreiber
    config.write("vnc = 1\n")
574 2a6469d5 Alexander Schreiber
    config.write("vnclisten = '0.0.0.0'\n")
575 2a6469d5 Alexander Schreiber
576 2a6469d5 Alexander Schreiber
    if instance.network_port > constants.HT_HVM_VNC_BASE_PORT:
577 2a6469d5 Alexander Schreiber
      display = instance.network_port - constants.HT_HVM_VNC_BASE_PORT
578 2a6469d5 Alexander Schreiber
      config.write("vncdisplay = %s\n" % display)
579 2a6469d5 Alexander Schreiber
      config.write("vncunused = 0\n")
580 2a6469d5 Alexander Schreiber
    else:
581 2a6469d5 Alexander Schreiber
      config.write("# vncdisplay = 1\n")
582 2a6469d5 Alexander Schreiber
      config.write("vncunused = 1\n")
583 2a6469d5 Alexander Schreiber
584 2a6469d5 Alexander Schreiber
    try:
585 2a6469d5 Alexander Schreiber
      password_file = open(constants.VNC_PASSWORD_FILE, "r")
586 2a6469d5 Alexander Schreiber
      try:
587 2a6469d5 Alexander Schreiber
        password = password_file.readline()
588 2a6469d5 Alexander Schreiber
      finally:
589 2a6469d5 Alexander Schreiber
        password_file.close()
590 2a6469d5 Alexander Schreiber
    except IOError:
591 2a6469d5 Alexander Schreiber
      raise errors.OpExecError("failed to open VNC password file %s " %
592 2a6469d5 Alexander Schreiber
                               constants.VNC_PASSWORD_FILE)
593 2a6469d5 Alexander Schreiber
594 2a6469d5 Alexander Schreiber
    config.write("vncpasswd = '%s'\n" % password.rstrip())
595 2a6469d5 Alexander Schreiber
596 2a6469d5 Alexander Schreiber
    config.write("serial = 'pty'\n")
597 2a6469d5 Alexander Schreiber
    config.write("localtime = 1\n")
598 2a6469d5 Alexander Schreiber
599 2a6469d5 Alexander Schreiber
    vif_data = []
600 2a6469d5 Alexander Schreiber
    for nic in instance.nics:
601 2a6469d5 Alexander Schreiber
      nic_str = "mac=%s, bridge=%s, type=ioemu" % (nic.mac, nic.bridge)
602 2a6469d5 Alexander Schreiber
      ip = getattr(nic, "ip", None)
603 2a6469d5 Alexander Schreiber
      if ip is not None:
604 2a6469d5 Alexander Schreiber
        nic_str += ", ip=%s" % ip
605 2a6469d5 Alexander Schreiber
      vif_data.append("'%s'" % nic_str)
606 2a6469d5 Alexander Schreiber
607 2a6469d5 Alexander Schreiber
    config.write("vif = [%s]\n" % ",".join(vif_data))
608 2a6469d5 Alexander Schreiber
609 2a6469d5 Alexander Schreiber
    disk_data = ["'phy:%s,%s,w'" %
610 2a6469d5 Alexander Schreiber
                 (rldev.dev_path, cfdev.iv_name.replace("sd", "ioemu:hd"))
611 2a6469d5 Alexander Schreiber
                 for cfdev, rldev in block_devices]
612 2a6469d5 Alexander Schreiber
    iso = "'file:/srv/ganeti/iso/hvm-install.iso,hdc:cdrom,r'"
613 2a6469d5 Alexander Schreiber
    config.write("disk = [%s, %s]\n" % (",".join(disk_data), iso) )
614 2a6469d5 Alexander Schreiber
615 2a6469d5 Alexander Schreiber
    config.write("on_poweroff = 'destroy'\n")
616 2a6469d5 Alexander Schreiber
    config.write("on_reboot = 'restart'\n")
617 2a6469d5 Alexander Schreiber
    config.write("on_crash = 'restart'\n")
618 2a6469d5 Alexander Schreiber
    if extra_args:
619 2a6469d5 Alexander Schreiber
      config.write("extra = '%s'\n" % extra_args)
620 2a6469d5 Alexander Schreiber
    # just in case it exists
621 2a6469d5 Alexander Schreiber
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
622 2a6469d5 Alexander Schreiber
    try:
623 2a6469d5 Alexander Schreiber
      f = open("/etc/xen/%s" % instance.name, "w")
624 2a6469d5 Alexander Schreiber
      try:
625 2a6469d5 Alexander Schreiber
        f.write(config.getvalue())
626 2a6469d5 Alexander Schreiber
      finally:
627 2a6469d5 Alexander Schreiber
        f.close()
628 2a6469d5 Alexander Schreiber
    except IOError, err:
629 2a6469d5 Alexander Schreiber
      raise errors.OpExecError("Cannot write Xen instance confile"
630 2a6469d5 Alexander Schreiber
                               " file /etc/xen/%s: %s" % (instance.name, err))
631 2a6469d5 Alexander Schreiber
    return True
632 2a6469d5 Alexander Schreiber
633 2a6469d5 Alexander Schreiber
  @staticmethod
634 2a6469d5 Alexander Schreiber
  def GetShellCommandForConsole(instance):
635 2a6469d5 Alexander Schreiber
    """Return a command for connecting to the console of an instance.
636 2a6469d5 Alexander Schreiber

637 2a6469d5 Alexander Schreiber
    """
638 2a6469d5 Alexander Schreiber
    if instance.network_port is None:
639 2a6469d5 Alexander Schreiber
      raise errors.OpExecError("no console port defined for %s"
640 2a6469d5 Alexander Schreiber
                               % instance.name)
641 2a6469d5 Alexander Schreiber
    else:
642 2a6469d5 Alexander Schreiber
      raise errors.OpExecError("no PTY console, connect to %s:%s via VNC"
643 2a6469d5 Alexander Schreiber
                               % (instance.primary_node,
644 2a6469d5 Alexander Schreiber
                                  instance.network_port))