Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor.py @ 9ff7e35c

History | View | Annotate | Download (14.2 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 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 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 16450d30 Iustin Pop
    if os.path.exists("/boot/initrd-2.6-xenU"):
137 16450d30 Iustin Pop
      config.write("ramdisk = '/boot/initrd-2.6-xenU'\n")
138 a8083063 Iustin Pop
    config.write("memory = %d\n" % instance.memory)
139 a8083063 Iustin Pop
    config.write("vcpus = %d\n" % instance.vcpus)
140 a8083063 Iustin Pop
    config.write("name = '%s'\n" % instance.name)
141 a8083063 Iustin Pop
142 a8083063 Iustin Pop
    vif_data = []
143 a8083063 Iustin Pop
    for nic in instance.nics:
144 a8083063 Iustin Pop
      nic_str = "mac=%s, bridge=%s" % (nic.mac, nic.bridge)
145 a8083063 Iustin Pop
      ip = getattr(nic, "ip", None)
146 a8083063 Iustin Pop
      if ip is not None:
147 a8083063 Iustin Pop
        nic_str += ", ip=%s" % ip
148 a8083063 Iustin Pop
      vif_data.append("'%s'" % nic_str)
149 a8083063 Iustin Pop
150 a8083063 Iustin Pop
    config.write("vif = [%s]\n" % ",".join(vif_data))
151 a8083063 Iustin Pop
152 a8083063 Iustin Pop
    disk_data = ["'phy:%s,%s,w'" % (rldev.dev_path, cfdev.iv_name)
153 a8083063 Iustin Pop
                 for cfdev, rldev in block_devices]
154 a8083063 Iustin Pop
    config.write("disk = [%s]\n" % ",".join(disk_data))
155 a8083063 Iustin Pop
156 a8083063 Iustin Pop
    config.write("root = '/dev/sda ro'\n")
157 a8083063 Iustin Pop
    config.write("on_poweroff = 'destroy'\n")
158 a8083063 Iustin Pop
    config.write("on_reboot = 'restart'\n")
159 a8083063 Iustin Pop
    config.write("on_crash = 'restart'\n")
160 a8083063 Iustin Pop
    if extra_args:
161 a8083063 Iustin Pop
      config.write("extra = '%s'\n" % extra_args)
162 a8083063 Iustin Pop
    # just in case it exists
163 a8083063 Iustin Pop
    utils.RemoveFile("/etc/xen/auto/%s" % instance.name)
164 a8083063 Iustin Pop
    f = open("/etc/xen/%s" % instance.name, "w")
165 a8083063 Iustin Pop
    f.write(config.getvalue())
166 a8083063 Iustin Pop
    f.close()
167 a8083063 Iustin Pop
    return True
168 a8083063 Iustin Pop
169 a8083063 Iustin Pop
  @staticmethod
170 a8083063 Iustin Pop
  def _RemoveConfigFile(instance):
171 a8083063 Iustin Pop
    """Remove the xen configuration file.
172 a8083063 Iustin Pop

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

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

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

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

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

234 a8083063 Iustin Pop
    Args:
235 a8083063 Iustin Pop
      instance_name: the instance name
236 a8083063 Iustin Pop

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

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

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

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

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

324 a8083063 Iustin Pop
    For Xen, this verifies that the xend process is running.
325 a8083063 Iustin Pop

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

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

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

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

354 a8083063 Iustin Pop
    Args:
355 a8083063 Iustin Pop
      instance_name: the instance name
356 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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