Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor.py @ 5c947f38

History | View | Annotate | Download (14.1 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
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 a8083063 Iustin Pop
from ganeti.errors import HypervisorError
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
_HT_XEN30 = "xen-3.0"
36 a8083063 Iustin Pop
_HT_FAKE = "fake"
37 a8083063 Iustin Pop
38 a8083063 Iustin Pop
VALID_HTYPES = (_HT_XEN30, _HT_FAKE)
39 a8083063 Iustin Pop
40 a8083063 Iustin Pop
def GetHypervisor():
41 a8083063 Iustin Pop
  """Return a Hypervisor instance.
42 a8083063 Iustin Pop

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

46 a8083063 Iustin Pop
  """
47 a8083063 Iustin Pop
  ht_kind = ssconf.SimpleStore().GetHypervisorType()
48 a8083063 Iustin Pop
  if ht_kind == _HT_XEN30:
49 a8083063 Iustin Pop
    cls = XenHypervisor
50 a8083063 Iustin Pop
  elif ht_kind == _HT_FAKE:
51 a8083063 Iustin Pop
    cls = FakeHypervisor
52 a8083063 Iustin Pop
  else:
53 a8083063 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 a8083063 Iustin Pop
  def ListInstances(self):
76 a8083063 Iustin Pop
    """Get the list of running instances."""
77 a8083063 Iustin Pop
    raise NotImplementedError
78 a8083063 Iustin Pop
79 a8083063 Iustin Pop
  def GetInstanceInfo(self, instance_name):
80 a8083063 Iustin Pop
    """Get instance properties.
81 a8083063 Iustin Pop

82 a8083063 Iustin Pop
    Args:
83 a8083063 Iustin Pop
      instance_name: the instance name
84 a8083063 Iustin Pop

85 a8083063 Iustin Pop
    Returns:
86 a8083063 Iustin Pop
      (name, id, memory, vcpus, state, times)
87 a8083063 Iustin Pop

88 a8083063 Iustin Pop
    """
89 a8083063 Iustin Pop
    raise NotImplementedError
90 a8083063 Iustin Pop
91 a8083063 Iustin Pop
  def GetAllInstancesInfo(self):
92 a8083063 Iustin Pop
    """Get properties of all instances.
93 a8083063 Iustin Pop

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

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

108 a8083063 Iustin Pop
    """
109 a8083063 Iustin Pop
    raise NotImplementedError
110 a8083063 Iustin Pop
111 a8083063 Iustin Pop
  @staticmethod
112 a8083063 Iustin Pop
  def GetShellCommandForConsole(instance_name):
113 a8083063 Iustin Pop
    """Return a command for connecting to the console of an instance.
114 a8083063 Iustin Pop

115 a8083063 Iustin Pop
    """
116 a8083063 Iustin Pop
    raise NotImplementedError
117 a8083063 Iustin Pop
118 a8083063 Iustin Pop
  def Verify(self):
119 a8083063 Iustin Pop
    """Verify the hypervisor.
120 a8083063 Iustin Pop

121 a8083063 Iustin Pop
    """
122 a8083063 Iustin Pop
    raise NotImplementedError
123 a8083063 Iustin Pop
124 a8083063 Iustin Pop
125 a8083063 Iustin Pop
class XenHypervisor(BaseHypervisor):
126 a8083063 Iustin Pop
  """Xen hypervisor interface"""
127 a8083063 Iustin Pop
128 a8083063 Iustin Pop
  @staticmethod
129 a8083063 Iustin Pop
  def _WriteConfigFile(instance, block_devices, extra_args):
130 a8083063 Iustin Pop
    """Create a Xen 3.0 config file.
131 a8083063 Iustin Pop

132 a8083063 Iustin Pop
    """
133 a8083063 Iustin Pop
    config = StringIO()
134 a8083063 Iustin Pop
    config.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
135 a8083063 Iustin Pop
    config.write("kernel = '/boot/vmlinuz-2.6-xenU'\n")
136 a8083063 Iustin Pop
    config.write("memory = %d\n" % instance.memory)
137 a8083063 Iustin Pop
    config.write("vcpus = %d\n" % instance.vcpus)
138 a8083063 Iustin Pop
    config.write("name = '%s'\n" % instance.name)
139 a8083063 Iustin Pop
140 a8083063 Iustin Pop
    vif_data = []
141 a8083063 Iustin Pop
    for nic in instance.nics:
142 a8083063 Iustin Pop
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
143 a8083063 Iustin Pop
      ip = getattr(nic, "ip", None)
144 a8083063 Iustin Pop
      if ip is not None:
145 a8083063 Iustin Pop
        nic_str += ", ip=%s" % ip
146 a8083063 Iustin Pop
      vif_data.append("'%s'" % nic_str)
147 a8083063 Iustin Pop
148 a8083063 Iustin Pop
    config.write("vif = [%s]\n" % ",".join(vif_data))
149 a8083063 Iustin Pop
150 a8083063 Iustin Pop
    disk_data = ["'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
151 a8083063 Iustin Pop
                 for cfdev, rldev in block_devices]
152 a8083063 Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
153 a8083063 Iustin Pop
154 a8083063 Iustin Pop
    config.write("root = '/dev/sda ro'\n")
155 a8083063 Iustin Pop
    config.write("on_poweroff = 'destroy'\n")
156 a8083063 Iustin Pop
    config.write("on_reboot = 'restart'\n")
157 a8083063 Iustin Pop
    config.write("on_crash = 'restart'\n")
158 a8083063 Iustin Pop
    if extra_args:
159 a8083063 Iustin Pop
      config.write("extra = '%s'\n" % extra_args)
160 a8083063 Iustin Pop
    # just in case it exists
161 a8083063 Iustin Pop
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
162 a8083063 Iustin Pop
    f = open("/etc/xen/%s" % instance.name, "w")
163 a8083063 Iustin Pop
    f.write(config.getvalue())
164 a8083063 Iustin Pop
    f.close()
165 a8083063 Iustin Pop
    return True
166 a8083063 Iustin Pop
167 a8083063 Iustin Pop
  @staticmethod
168 a8083063 Iustin Pop
  def _RemoveConfigFile(instance):
169 a8083063 Iustin Pop
    """Remove the xen configuration file.
170 a8083063 Iustin Pop

171 a8083063 Iustin Pop
    """
172 a8083063 Iustin Pop
    utils.RemoveFile("/etc/xen/%s" % instance.name)
173 a8083063 Iustin Pop
174 a8083063 Iustin Pop
  @staticmethod
175 a8083063 Iustin Pop
  def _GetXMList(include_node):
176 a8083063 Iustin Pop
    """Return the list of running instances.
177 a8083063 Iustin Pop

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

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

183 a8083063 Iustin Pop
    """
184 a8083063 Iustin Pop
    for dummy in range(5):
185 a8083063 Iustin Pop
      result = utils.RunCmd(["xm", "list"])
186 a8083063 Iustin Pop
      if not result.failed:
187 a8083063 Iustin Pop
        break
188 a8083063 Iustin Pop
      logger.Error("xm list failed (%s): %s" % (result.fail_reason,
189 a8083063 Iustin Pop
                                                result.output))
190 a8083063 Iustin Pop
      time.sleep(1)
191 a8083063 Iustin Pop
192 a8083063 Iustin Pop
    if result.failed:
193 a8083063 Iustin Pop
      raise HypervisorError("xm list failed, retries exceeded (%s): %s" %
194 a8083063 Iustin Pop
                            (result.fail_reason, result.stderr))
195 a8083063 Iustin Pop
196 a8083063 Iustin Pop
    # skip over the heading and the domain 0 line (optional)
197 a8083063 Iustin Pop
    if include_node:
198 a8083063 Iustin Pop
      to_skip = 1
199 a8083063 Iustin Pop
    else:
200 a8083063 Iustin Pop
      to_skip = 2
201 a8083063 Iustin Pop
    lines = result.stdout.splitlines()[to_skip:]
202 a8083063 Iustin Pop
    result = []
203 a8083063 Iustin Pop
    for line in lines:
204 a8083063 Iustin Pop
      # The format of lines is:
205 a8083063 Iustin Pop
      # Name      ID Mem(MiB) VCPUs State  Time(s)
206 a8083063 Iustin Pop
      # Domain-0   0  3418     4 r-----    266.2
207 a8083063 Iustin Pop
      data = line.split()
208 a8083063 Iustin Pop
      if len(data) != 6:
209 a8083063 Iustin Pop
        raise HypervisorError("Can't parse output of xm list, line: %s" % line)
210 a8083063 Iustin Pop
      try:
211 a8083063 Iustin Pop
        data[1] = int(data[1])
212 a8083063 Iustin Pop
        data[2] = int(data[2])
213 a8083063 Iustin Pop
        data[3] = int(data[3])
214 a8083063 Iustin Pop
        data[5] = float(data[5])
215 a8083063 Iustin Pop
      except ValueError, err:
216 a8083063 Iustin Pop
        raise HypervisorError("Can't parse output of xm list,"
217 a8083063 Iustin Pop
                              " line: %s, error: %s" % (line, err))
218 a8083063 Iustin Pop
      result.append(data)
219 a8083063 Iustin Pop
    return result
220 a8083063 Iustin Pop
221 a8083063 Iustin Pop
  def ListInstances(self):
222 a8083063 Iustin Pop
    """Get the list of running instances.
223 a8083063 Iustin Pop

224 a8083063 Iustin Pop
    """
225 a8083063 Iustin Pop
    xm_list = self._GetXMList(False)
226 a8083063 Iustin Pop
    names = [info[0] for info in xm_list]
227 a8083063 Iustin Pop
    return names
228 a8083063 Iustin Pop
229 a8083063 Iustin Pop
  def GetInstanceInfo(self, instance_name):
230 a8083063 Iustin Pop
    """Get instance properties.
231 a8083063 Iustin Pop

232 a8083063 Iustin Pop
    Args:
233 a8083063 Iustin Pop
      instance_name: the instance name
234 a8083063 Iustin Pop

235 a8083063 Iustin Pop
    Returns:
236 a8083063 Iustin Pop
      (name, id, memory, vcpus, stat, times)
237 a8083063 Iustin Pop
    """
238 a8083063 Iustin Pop
    xm_list = self._GetXMList(instance_name=="Domain-0")
239 a8083063 Iustin Pop
    result = None
240 a8083063 Iustin Pop
    for data in xm_list:
241 a8083063 Iustin Pop
      if data[0] == instance_name:
242 a8083063 Iustin Pop
        result = data
243 a8083063 Iustin Pop
        break
244 a8083063 Iustin Pop
    return result
245 a8083063 Iustin Pop
246 a8083063 Iustin Pop
  def GetAllInstancesInfo(self):
247 a8083063 Iustin Pop
    """Get properties of all instances.
248 a8083063 Iustin Pop

249 a8083063 Iustin Pop
    Returns:
250 a8083063 Iustin Pop
      [(name, id, memory, vcpus, stat, times),...]
251 a8083063 Iustin Pop
    """
252 a8083063 Iustin Pop
    xm_list = self._GetXMList(False)
253 a8083063 Iustin Pop
    return xm_list
254 a8083063 Iustin Pop
255 a8083063 Iustin Pop
  def StartInstance(self, instance, block_devices, extra_args):
256 a8083063 Iustin Pop
    """Start an instance."""
257 a8083063 Iustin Pop
    self._WriteConfigFile(instance, block_devices, extra_args)
258 a8083063 Iustin Pop
    result = utils.RunCmd(["xm", "create", instance.name])
259 a8083063 Iustin Pop
260 a8083063 Iustin Pop
    if result.failed:
261 a8083063 Iustin Pop
      raise HypervisorError("Failed to start instance %s: %s" %
262 a8083063 Iustin Pop
                            (instance.name, result.fail_reason))
263 a8083063 Iustin Pop
264 a8083063 Iustin Pop
  def StopInstance(self, instance, force=False):
265 a8083063 Iustin Pop
    """Stop an instance."""
266 a8083063 Iustin Pop
    self._RemoveConfigFile(instance)
267 a8083063 Iustin Pop
    if force:
268 a8083063 Iustin Pop
      command = ["xm", "destroy", instance.name]
269 a8083063 Iustin Pop
    else:
270 a8083063 Iustin Pop
      command = ["xm", "shutdown", instance.name]
271 a8083063 Iustin Pop
    result = utils.RunCmd(command)
272 a8083063 Iustin Pop
273 a8083063 Iustin Pop
    if result.failed:
274 a8083063 Iustin Pop
      raise HypervisorError("Failed to stop instance %s: %s" %
275 a8083063 Iustin Pop
                            (instance.name, result.fail_reason))
276 a8083063 Iustin Pop
277 a8083063 Iustin Pop
  def GetNodeInfo(self):
278 a8083063 Iustin Pop
    """Return information about the node.
279 a8083063 Iustin Pop

280 a8083063 Iustin Pop
    The return value is a dict, which has to have the following items:
281 a8083063 Iustin Pop
      (all values in MiB)
282 a8083063 Iustin Pop
      - memory_total: the total memory size on the node
283 a8083063 Iustin Pop
      - memory_free: the available memory on the node for instances
284 a8083063 Iustin Pop
      - memory_dom0: the memory used by the node itself, if available
285 a8083063 Iustin Pop

286 a8083063 Iustin Pop
    """
287 a8083063 Iustin Pop
    # note: in xen 3, memory has changed to total_memory
288 a8083063 Iustin Pop
    result = utils.RunCmd(["xm", "info"])
289 a8083063 Iustin Pop
    if result.failed:
290 a8083063 Iustin Pop
      logger.Error("Can't run 'xm info': %s" % result.fail_reason)
291 a8083063 Iustin Pop
      return None
292 a8083063 Iustin Pop
293 a8083063 Iustin Pop
    xmoutput = result.stdout.splitlines()
294 a8083063 Iustin Pop
    result = {}
295 a8083063 Iustin Pop
    for line in xmoutput:
296 a8083063 Iustin Pop
      splitfields = line.split(":", 1)
297 a8083063 Iustin Pop
298 a8083063 Iustin Pop
      if len(splitfields) > 1:
299 a8083063 Iustin Pop
        key = splitfields[0].strip()
300 a8083063 Iustin Pop
        val = splitfields[1].strip()
301 a8083063 Iustin Pop
        if key == 'memory' or key == 'total_memory':
302 a8083063 Iustin Pop
          result['memory_total'] = int(val)
303 a8083063 Iustin Pop
        elif key == 'free_memory':
304 a8083063 Iustin Pop
          result['memory_free'] = int(val)
305 a8083063 Iustin Pop
    dom0_info = self.GetInstanceInfo("Domain-0")
306 a8083063 Iustin Pop
    if dom0_info is not None:
307 a8083063 Iustin Pop
      result['memory_dom0'] = dom0_info[2]
308 a8083063 Iustin Pop
309 a8083063 Iustin Pop
    return result
310 a8083063 Iustin Pop
311 a8083063 Iustin Pop
  @staticmethod
312 a8083063 Iustin Pop
  def GetShellCommandForConsole(instance_name):
313 a8083063 Iustin Pop
    """Return a command for connecting to the console of an instance.
314 a8083063 Iustin Pop

315 a8083063 Iustin Pop
    """
316 a8083063 Iustin Pop
    return "xm console %s" % instance_name
317 a8083063 Iustin Pop
318 a8083063 Iustin Pop
319 a8083063 Iustin Pop
  def Verify(self):
320 a8083063 Iustin Pop
    """Verify the hypervisor.
321 a8083063 Iustin Pop

322 a8083063 Iustin Pop
    For Xen, this verifies that the xend process is running.
323 a8083063 Iustin Pop

324 a8083063 Iustin Pop
    """
325 a8083063 Iustin Pop
    if not utils.CheckDaemonAlive('/var/run/xend.pid', 'xend'):
326 a8083063 Iustin Pop
      return "xend daemon is not running"
327 a8083063 Iustin Pop
328 a8083063 Iustin Pop
329 a8083063 Iustin Pop
class FakeHypervisor(BaseHypervisor):
330 a8083063 Iustin Pop
  """Fake hypervisor interface.
331 a8083063 Iustin Pop

332 a8083063 Iustin Pop
  This can be used for testing the ganeti code without having to have
333 a8083063 Iustin Pop
  a real virtualisation software installed.
334 a8083063 Iustin Pop

335 a8083063 Iustin Pop
  """
336 a8083063 Iustin Pop
  _ROOT_DIR = "/var/run/ganeti-fake-hypervisor"
337 a8083063 Iustin Pop
338 a8083063 Iustin Pop
  def __init__(self):
339 a8083063 Iustin Pop
    BaseHypervisor.__init__(self)
340 a8083063 Iustin Pop
    if not os.path.exists(self._ROOT_DIR):
341 a8083063 Iustin Pop
      os.mkdir(self._ROOT_DIR)
342 a8083063 Iustin Pop
343 a8083063 Iustin Pop
  def ListInstances(self):
344 a8083063 Iustin Pop
    """Get the list of running instances.
345 a8083063 Iustin Pop

346 a8083063 Iustin Pop
    """
347 a8083063 Iustin Pop
    return os.listdir(self._ROOT_DIR)
348 a8083063 Iustin Pop
349 a8083063 Iustin Pop
  def GetInstanceInfo(self, instance_name):
350 a8083063 Iustin Pop
    """Get instance properties.
351 a8083063 Iustin Pop

352 a8083063 Iustin Pop
    Args:
353 a8083063 Iustin Pop
      instance_name: the instance name
354 a8083063 Iustin Pop

355 a8083063 Iustin Pop
    Returns:
356 a8083063 Iustin Pop
      (name, id, memory, vcpus, stat, times)
357 a8083063 Iustin Pop
    """
358 a8083063 Iustin Pop
    file_name = "%s/%s" % (self._ROOT_DIR, instance_name)
359 a8083063 Iustin Pop
    if not os.path.exists(file_name):
360 a8083063 Iustin Pop
      return None
361 a8083063 Iustin Pop
    try:
362 a8083063 Iustin Pop
      fh = file(file_name, "r")
363 a8083063 Iustin Pop
      try:
364 a8083063 Iustin Pop
        inst_id = fh.readline().strip()
365 a8083063 Iustin Pop
        memory = fh.readline().strip()
366 a8083063 Iustin Pop
        vcpus = fh.readline().strip()
367 a8083063 Iustin Pop
        stat = "---b-"
368 a8083063 Iustin Pop
        times = "0"
369 a8083063 Iustin Pop
        return (instance_name, inst_id, memory, vcpus, stat, times)
370 a8083063 Iustin Pop
      finally:
371 a8083063 Iustin Pop
        fh.close()
372 a8083063 Iustin Pop
    except IOError, err:
373 a8083063 Iustin Pop
      raise HypervisorError("Failed to list instance %s: %s" %
374 a8083063 Iustin Pop
                            (instance_name, err))
375 a8083063 Iustin Pop
376 a8083063 Iustin Pop
  def GetAllInstancesInfo(self):
377 a8083063 Iustin Pop
    """Get properties of all instances.
378 a8083063 Iustin Pop

379 a8083063 Iustin Pop
    Returns:
380 a8083063 Iustin Pop
      [(name, id, memory, vcpus, stat, times),...]
381 a8083063 Iustin Pop
    """
382 a8083063 Iustin Pop
    data = []
383 a8083063 Iustin Pop
    for file_name in os.listdir(self._ROOT_DIR):
384 a8083063 Iustin Pop
      try:
385 a8083063 Iustin Pop
        fh = file(self._ROOT_DIR+"/"+file_name, "r")
386 a8083063 Iustin Pop
        inst_id = "-1"
387 a8083063 Iustin Pop
        memory = "0"
388 a8083063 Iustin Pop
        stat = "-----"
389 a8083063 Iustin Pop
        times = "-1"
390 a8083063 Iustin Pop
        try:
391 a8083063 Iustin Pop
          inst_id = fh.readline().strip()
392 a8083063 Iustin Pop
          memory = fh.readline().strip()
393 a8083063 Iustin Pop
          vcpus = fh.readline().strip()
394 a8083063 Iustin Pop
          stat = "---b-"
395 a8083063 Iustin Pop
          times = "0"
396 a8083063 Iustin Pop
        finally:
397 a8083063 Iustin Pop
          fh.close()
398 a8083063 Iustin Pop
        data.append((file_name, inst_id, memory, vcpus, stat, times))
399 a8083063 Iustin Pop
      except IOError, err:
400 a8083063 Iustin Pop
        raise HypervisorError("Failed to list instances: %s" % err)
401 a8083063 Iustin Pop
    return data
402 a8083063 Iustin Pop
403 a8083063 Iustin Pop
  def StartInstance(self, instance, force, extra_args):
404 a8083063 Iustin Pop
    """Start an instance.
405 a8083063 Iustin Pop

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

410 a8083063 Iustin Pop
    """
411 a8083063 Iustin Pop
    file_name = self._ROOT_DIR + "/%s" % instance.name
412 a8083063 Iustin Pop
    if os.path.exists(file_name):
413 a8083063 Iustin Pop
      raise HypervisorError("Failed to start instance %s: %s" %
414 a8083063 Iustin Pop
                            (instance.name, "already running"))
415 a8083063 Iustin Pop
    try:
416 a8083063 Iustin Pop
      fh = file(file_name, "w")
417 a8083063 Iustin Pop
      try:
418 a8083063 Iustin Pop
        fh.write("0\n%d\n%d\n" % (instance.memory, instance.vcpus))
419 a8083063 Iustin Pop
      finally:
420 a8083063 Iustin Pop
        fh.close()
421 a8083063 Iustin Pop
    except IOError, err:
422 a8083063 Iustin Pop
      raise HypervisorError("Failed to start instance %s: %s" %
423 a8083063 Iustin Pop
                            (instance.name, err))
424 a8083063 Iustin Pop
425 a8083063 Iustin Pop
  def StopInstance(self, instance, force=False):
426 a8083063 Iustin Pop
    """Stop an instance.
427 a8083063 Iustin Pop

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

431 a8083063 Iustin Pop
    """
432 a8083063 Iustin Pop
    file_name = self._ROOT_DIR + "/%s" % instance.name
433 a8083063 Iustin Pop
    if not os.path.exists(file_name):
434 a8083063 Iustin Pop
      raise HypervisorError("Failed to stop instance %s: %s" %
435 a8083063 Iustin Pop
                            (instance.name, "not running"))
436 a8083063 Iustin Pop
    utils.RemoveFile(file_name)
437 a8083063 Iustin Pop
438 a8083063 Iustin Pop
  def GetNodeInfo(self):
439 a8083063 Iustin Pop
    """Return information about the node.
440 a8083063 Iustin Pop

441 a8083063 Iustin Pop
    The return value is a dict, which has to have the following items:
442 a8083063 Iustin Pop
      (all values in MiB)
443 a8083063 Iustin Pop
      - memory_total: the total memory size on the node
444 a8083063 Iustin Pop
      - memory_free: the available memory on the node for instances
445 a8083063 Iustin Pop
      - memory_dom0: the memory used by the node itself, if available
446 a8083063 Iustin Pop

447 a8083063 Iustin Pop
    """
448 a8083063 Iustin Pop
    # global ram usage from the xm info command
449 a8083063 Iustin Pop
    # memory                 : 3583
450 a8083063 Iustin Pop
    # free_memory            : 747
451 a8083063 Iustin Pop
    # note: in xen 3, memory has changed to total_memory
452 a8083063 Iustin Pop
    try:
453 a8083063 Iustin Pop
      fh = file("/proc/meminfo")
454 a8083063 Iustin Pop
      try:
455 a8083063 Iustin Pop
        data = fh.readlines()
456 a8083063 Iustin Pop
      finally:
457 a8083063 Iustin Pop
        fh.close()
458 a8083063 Iustin Pop
    except IOError, err:
459 a8083063 Iustin Pop
      raise HypervisorError("Failed to list node info: %s" % err)
460 a8083063 Iustin Pop
461 a8083063 Iustin Pop
    result = {}
462 a8083063 Iustin Pop
    sum_free = 0
463 a8083063 Iustin Pop
    for line in data:
464 a8083063 Iustin Pop
      splitfields = line.split(":", 1)
465 a8083063 Iustin Pop
466 a8083063 Iustin Pop
      if len(splitfields) > 1:
467 a8083063 Iustin Pop
        key = splitfields[0].strip()
468 a8083063 Iustin Pop
        val = splitfields[1].strip()
469 a8083063 Iustin Pop
        if key == 'MemTotal':
470 a8083063 Iustin Pop
          result['memory_total'] = int(val.split()[0])/1024
471 a8083063 Iustin Pop
        elif key in ('MemFree', 'Buffers', 'Cached'):
472 a8083063 Iustin Pop
          sum_free += int(val.split()[0])/1024
473 a8083063 Iustin Pop
        elif key == 'Active':
474 a8083063 Iustin Pop
          result['memory_dom0'] = int(val.split()[0])/1024
475 a8083063 Iustin Pop
476 a8083063 Iustin Pop
    result['memory_free'] = sum_free
477 a8083063 Iustin Pop
    return result
478 a8083063 Iustin Pop
479 a8083063 Iustin Pop
  @staticmethod
480 a8083063 Iustin Pop
  def GetShellCommandForConsole(instance_name):
481 a8083063 Iustin Pop
    """Return a command for connecting to the console of an instance.
482 a8083063 Iustin Pop

483 a8083063 Iustin Pop
    """
484 a8083063 Iustin Pop
    return "echo Console not available for fake hypervisor"
485 a8083063 Iustin Pop
486 a8083063 Iustin Pop
  def Verify(self):
487 a8083063 Iustin Pop
    """Verify the hypervisor.
488 a8083063 Iustin Pop

489 a8083063 Iustin Pop
    For the fake hypervisor, it just checks the existence of the base
490 a8083063 Iustin Pop
    dir.
491 a8083063 Iustin Pop

492 a8083063 Iustin Pop
    """
493 a8083063 Iustin Pop
    if not os.path.exists(self._ROOT_DIR):
494 a8083063 Iustin Pop
      return "The required directory '%s' does not exist." % self._ROOT_DIR