Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_base.py @ 43fcf0d3

History | View | Annotate | Download (13.9 kB)

1 65a6f9b7 Michael Hanselmann
#
2 65a6f9b7 Michael Hanselmann
#
3 65a6f9b7 Michael Hanselmann
4 783a6c0b Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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
"""Base class for all hypervisors
23 65a6f9b7 Michael Hanselmann

24 205ab586 Iustin Pop
The syntax for the _CHECK variables and the contents of the PARAMETERS
25 205ab586 Iustin Pop
dict is the same, see the docstring for L{BaseHypervisor.PARAMETERS}.
26 205ab586 Iustin Pop

27 205ab586 Iustin Pop
@var _FILE_CHECK: stub for file checks, without the required flag
28 205ab586 Iustin Pop
@var _DIR_CHECK: stub for directory checks, without the required flag
29 205ab586 Iustin Pop
@var REQ_FILE_CHECK: mandatory file parameter
30 205ab586 Iustin Pop
@var OPT_FILE_CHECK: optional file parameter
31 205ab586 Iustin Pop
@var REQ_DIR_CHECK: mandatory directory parametr
32 205ab586 Iustin Pop
@var OPT_DIR_CHECK: optional directory parameter
33 205ab586 Iustin Pop
@var NO_CHECK: parameter without any checks at all
34 205ab586 Iustin Pop
@var REQUIRED_CHECK: parameter required to exist (and non-false), but
35 205ab586 Iustin Pop
    without other checks; beware that this can't be used for boolean
36 205ab586 Iustin Pop
    parameters, where you should use NO_CHECK or a custom checker
37 205ab586 Iustin Pop

38 65a6f9b7 Michael Hanselmann
"""
39 65a6f9b7 Michael Hanselmann
40 205ab586 Iustin Pop
import os
41 572e52bf Iustin Pop
import re
42 29921401 Iustin Pop
import logging
43 572e52bf Iustin Pop
44 572e52bf Iustin Pop
45 f48148c3 Iustin Pop
from ganeti import errors
46 205ab586 Iustin Pop
from ganeti import utils
47 e71b9ef4 Iustin Pop
from ganeti import constants
48 205ab586 Iustin Pop
49 205ab586 Iustin Pop
50 e3ed5316 Balazs Lecz
def _IsCpuMaskWellFormed(cpu_mask):
51 e3ed5316 Balazs Lecz
  try:
52 e3ed5316 Balazs Lecz
    cpu_list = utils.ParseCpuMask(cpu_mask)
53 e3ed5316 Balazs Lecz
  except errors.ParseError, _:
54 e3ed5316 Balazs Lecz
    return False
55 e3ed5316 Balazs Lecz
  return isinstance(cpu_list, list) and len(cpu_list) > 0
56 e3ed5316 Balazs Lecz
57 e3ed5316 Balazs Lecz
58 205ab586 Iustin Pop
# Read the BaseHypervisor.PARAMETERS docstring for the syntax of the
59 205ab586 Iustin Pop
# _CHECK values
60 205ab586 Iustin Pop
61 205ab586 Iustin Pop
# must be afile
62 17c61836 Guido Trotter
_FILE_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path",
63 205ab586 Iustin Pop
              os.path.isfile, "not found or not a file")
64 205ab586 Iustin Pop
65 823bfa49 Apollon Oikonomopoulos
# must be a file or a URL
66 823bfa49 Apollon Oikonomopoulos
_FILE_OR_URL_CHECK = (utils.IsNormAbsPathOrURL,
67 823bfa49 Apollon Oikonomopoulos
                      "must be an absolute normalized path or a URL",
68 823bfa49 Apollon Oikonomopoulos
                      lambda x: os.path.isfile(x) or
69 823bfa49 Apollon Oikonomopoulos
                      re.match(r'(https?|ftp)://', x),
70 823bfa49 Apollon Oikonomopoulos
                      "not found or not a file or URL")
71 823bfa49 Apollon Oikonomopoulos
72 205ab586 Iustin Pop
# must be a directory
73 17c61836 Guido Trotter
_DIR_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path",
74 205ab586 Iustin Pop
             os.path.isdir, "not found or not a directory")
75 205ab586 Iustin Pop
76 e3ed5316 Balazs Lecz
# CPU mask must be well-formed
77 e3ed5316 Balazs Lecz
# TODO: implement node level check for the CPU mask
78 e3ed5316 Balazs Lecz
_CPU_MASK_CHECK = (_IsCpuMaskWellFormed,
79 e3ed5316 Balazs Lecz
                   "CPU mask definition is not well-formed",
80 e3ed5316 Balazs Lecz
                   None, None)
81 e3ed5316 Balazs Lecz
82 205ab586 Iustin Pop
# nice wrappers for users
83 205ab586 Iustin Pop
REQ_FILE_CHECK = (True, ) + _FILE_CHECK
84 205ab586 Iustin Pop
OPT_FILE_CHECK = (False, ) + _FILE_CHECK
85 823bfa49 Apollon Oikonomopoulos
REQ_FILE_OR_URL_CHECK = (True, ) + _FILE_OR_URL_CHECK
86 823bfa49 Apollon Oikonomopoulos
OPT_FILE_OR_URL_CHECK = (False, ) + _FILE_OR_URL_CHECK
87 205ab586 Iustin Pop
REQ_DIR_CHECK = (True, ) + _DIR_CHECK
88 205ab586 Iustin Pop
OPT_DIR_CHECK = (False, ) + _DIR_CHECK
89 78411c60 Iustin Pop
NET_PORT_CHECK = (True, lambda x: x > 0 and x < 65535, "invalid port number",
90 78411c60 Iustin Pop
                  None, None)
91 e3ed5316 Balazs Lecz
OPT_CPU_MASK_CHECK = (False, ) + _CPU_MASK_CHECK
92 e3ed5316 Balazs Lecz
REQ_CPU_MASK_CHECK = (True, ) + _CPU_MASK_CHECK
93 205ab586 Iustin Pop
94 205ab586 Iustin Pop
# no checks at all
95 205ab586 Iustin Pop
NO_CHECK = (False, None, None, None, None)
96 205ab586 Iustin Pop
97 205ab586 Iustin Pop
# required, but no other checks
98 205ab586 Iustin Pop
REQUIRED_CHECK = (True, None, None, None, None)
99 205ab586 Iustin Pop
100 e71b9ef4 Iustin Pop
# migration type
101 783a6c0b Iustin Pop
MIGRATION_MODE_CHECK = (True, lambda x: x in constants.HT_MIGRATION_MODES,
102 783a6c0b Iustin Pop
                        "invalid migration mode", None, None)
103 e71b9ef4 Iustin Pop
104 d73ef63f Michael Hanselmann
105 205ab586 Iustin Pop
def ParamInSet(required, my_set):
106 205ab586 Iustin Pop
  """Builds parameter checker for set membership.
107 205ab586 Iustin Pop

108 205ab586 Iustin Pop
  @type required: boolean
109 205ab586 Iustin Pop
  @param required: whether this is a required parameter
110 205ab586 Iustin Pop
  @type my_set: tuple, list or set
111 205ab586 Iustin Pop
  @param my_set: allowed values set
112 205ab586 Iustin Pop

113 205ab586 Iustin Pop
  """
114 205ab586 Iustin Pop
  fn = lambda x: x in my_set
115 ab3e6da8 Iustin Pop
  err = ("The value must be one of: %s" % utils.CommaJoin(my_set))
116 205ab586 Iustin Pop
  return (required, fn, err, None, None)
117 f48148c3 Iustin Pop
118 f48148c3 Iustin Pop
119 65a6f9b7 Michael Hanselmann
class BaseHypervisor(object):
120 65a6f9b7 Michael Hanselmann
  """Abstract virtualisation technology interface
121 65a6f9b7 Michael Hanselmann

122 f48148c3 Iustin Pop
  The goal is that all aspects of the virtualisation technology are
123 f48148c3 Iustin Pop
  abstracted away from the rest of code.
124 65a6f9b7 Michael Hanselmann

125 205ab586 Iustin Pop
  @cvar PARAMETERS: a dict of parameter name: check type; the check type is
126 205ab586 Iustin Pop
      a five-tuple containing:
127 205ab586 Iustin Pop
          - the required flag (boolean)
128 205ab586 Iustin Pop
          - a function to check for syntax, that will be used in
129 205ab586 Iustin Pop
            L{CheckParameterSyntax}, in the master daemon process
130 205ab586 Iustin Pop
          - an error message for the above function
131 205ab586 Iustin Pop
          - a function to check for parameter validity on the remote node,
132 205ab586 Iustin Pop
            in the L{ValidateParameters} function
133 205ab586 Iustin Pop
          - an error message for the above function
134 d271c6fd Iustin Pop
  @type CAN_MIGRATE: boolean
135 d271c6fd Iustin Pop
  @cvar CAN_MIGRATE: whether this hypervisor can do migration (either
136 d271c6fd Iustin Pop
      live or non-live)
137 205ab586 Iustin Pop

138 65a6f9b7 Michael Hanselmann
  """
139 205ab586 Iustin Pop
  PARAMETERS = {}
140 e1b8653f Guido Trotter
  ANCILLARY_FILES = []
141 d271c6fd Iustin Pop
  CAN_MIGRATE = False
142 f48148c3 Iustin Pop
143 65a6f9b7 Michael Hanselmann
  def __init__(self):
144 65a6f9b7 Michael Hanselmann
    pass
145 65a6f9b7 Michael Hanselmann
146 07813a9e Iustin Pop
  def StartInstance(self, instance, block_devices):
147 65a6f9b7 Michael Hanselmann
    """Start an instance."""
148 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
149 65a6f9b7 Michael Hanselmann
150 bbcf7ad0 Iustin Pop
  def StopInstance(self, instance, force=False, retry=False, name=None):
151 07b49e41 Guido Trotter
    """Stop an instance
152 07b49e41 Guido Trotter

153 07b49e41 Guido Trotter
    @type instance: L{objects.Instance}
154 07b49e41 Guido Trotter
    @param instance: instance to stop
155 07b49e41 Guido Trotter
    @type force: boolean
156 07b49e41 Guido Trotter
    @param force: whether to do a "hard" stop (destroy)
157 07b49e41 Guido Trotter
    @type retry: boolean
158 07b49e41 Guido Trotter
    @param retry: whether this is just a retry call
159 bbcf7ad0 Iustin Pop
    @type name: string or None
160 bbcf7ad0 Iustin Pop
    @param name: if this parameter is passed, the the instance object
161 bbcf7ad0 Iustin Pop
        should not be used (will be passed as None), and the shutdown
162 bbcf7ad0 Iustin Pop
        must be done by name only
163 07b49e41 Guido Trotter

164 07b49e41 Guido Trotter
    """
165 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
166 65a6f9b7 Michael Hanselmann
167 f28ec899 Guido Trotter
  def CleanupInstance(self, instance_name):
168 f28ec899 Guido Trotter
    """Cleanup after a stopped instance
169 f28ec899 Guido Trotter

170 f28ec899 Guido Trotter
    This is an optional method, used by hypervisors that need to cleanup after
171 f28ec899 Guido Trotter
    an instance has been stopped.
172 f28ec899 Guido Trotter

173 f28ec899 Guido Trotter
    @type instance_name: string
174 f28ec899 Guido Trotter
    @param instance_name: instance name to cleanup after
175 f28ec899 Guido Trotter

176 f28ec899 Guido Trotter
    """
177 f28ec899 Guido Trotter
    pass
178 f28ec899 Guido Trotter
179 65a6f9b7 Michael Hanselmann
  def RebootInstance(self, instance):
180 65a6f9b7 Michael Hanselmann
    """Reboot an instance."""
181 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
182 65a6f9b7 Michael Hanselmann
183 65a6f9b7 Michael Hanselmann
  def ListInstances(self):
184 65a6f9b7 Michael Hanselmann
    """Get the list of running instances."""
185 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
186 65a6f9b7 Michael Hanselmann
187 65a6f9b7 Michael Hanselmann
  def GetInstanceInfo(self, instance_name):
188 65a6f9b7 Michael Hanselmann
    """Get instance properties.
189 65a6f9b7 Michael Hanselmann

190 cd42d0ad Guido Trotter
    @type instance_name: string
191 c41eea6e Iustin Pop
    @param instance_name: the instance name
192 65a6f9b7 Michael Hanselmann

193 c41eea6e Iustin Pop
    @return: tuple (name, id, memory, vcpus, state, times)
194 65a6f9b7 Michael Hanselmann

195 65a6f9b7 Michael Hanselmann
    """
196 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
197 65a6f9b7 Michael Hanselmann
198 65a6f9b7 Michael Hanselmann
  def GetAllInstancesInfo(self):
199 65a6f9b7 Michael Hanselmann
    """Get properties of all instances.
200 65a6f9b7 Michael Hanselmann

201 c41eea6e Iustin Pop
    @return: list of tuples (name, id, memory, vcpus, stat, times)
202 c41eea6e Iustin Pop

203 65a6f9b7 Michael Hanselmann
    """
204 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
205 65a6f9b7 Michael Hanselmann
206 65a6f9b7 Michael Hanselmann
  def GetNodeInfo(self):
207 65a6f9b7 Michael Hanselmann
    """Return information about the node.
208 65a6f9b7 Michael Hanselmann

209 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
210 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
211 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
212 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
213 65a6f9b7 Michael Hanselmann

214 65a6f9b7 Michael Hanselmann
    """
215 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
216 65a6f9b7 Michael Hanselmann
217 637ce7f9 Guido Trotter
  @classmethod
218 55cc0a44 Michael Hanselmann
  def GetInstanceConsole(cls, instance, hvparams, beparams):
219 55cc0a44 Michael Hanselmann
    """Return information for connecting to the console of an instance.
220 65a6f9b7 Michael Hanselmann

221 65a6f9b7 Michael Hanselmann
    """
222 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
223 65a6f9b7 Michael Hanselmann
224 e1b8653f Guido Trotter
  @classmethod
225 e1b8653f Guido Trotter
  def GetAncillaryFiles(cls):
226 e1b8653f Guido Trotter
    """Return a list of ancillary files to be copied to all nodes as ancillary
227 e1b8653f Guido Trotter
    configuration files.
228 e1b8653f Guido Trotter

229 e1b8653f Guido Trotter
    @rtype: list of strings
230 e1b8653f Guido Trotter
    @return: list of absolute paths of files to ship cluster-wide
231 e1b8653f Guido Trotter

232 e1b8653f Guido Trotter
    """
233 e1b8653f Guido Trotter
    # By default we return a member variable, so that if an hypervisor has just
234 e1b8653f Guido Trotter
    # a static list of files it doesn't have to override this function.
235 e1b8653f Guido Trotter
    return cls.ANCILLARY_FILES
236 e1b8653f Guido Trotter
237 65a6f9b7 Michael Hanselmann
  def Verify(self):
238 65a6f9b7 Michael Hanselmann
    """Verify the hypervisor.
239 65a6f9b7 Michael Hanselmann

240 65a6f9b7 Michael Hanselmann
    """
241 65a6f9b7 Michael Hanselmann
    raise NotImplementedError
242 6e7275c0 Iustin Pop
243 7260cfbe Iustin Pop
  def MigrationInfo(self, instance): # pylint: disable-msg=R0201,W0613
244 cd42d0ad Guido Trotter
    """Get instance information to perform a migration.
245 cd42d0ad Guido Trotter

246 cd42d0ad Guido Trotter
    By default assume no information is needed.
247 cd42d0ad Guido Trotter

248 cd42d0ad Guido Trotter
    @type instance: L{objects.Instance}
249 cd42d0ad Guido Trotter
    @param instance: instance to be migrated
250 cd42d0ad Guido Trotter
    @rtype: string/data (opaque)
251 cd42d0ad Guido Trotter
    @return: instance migration information - serialized form
252 cd42d0ad Guido Trotter

253 cd42d0ad Guido Trotter
    """
254 cd42d0ad Guido Trotter
    return ''
255 cd42d0ad Guido Trotter
256 cd42d0ad Guido Trotter
  def AcceptInstance(self, instance, info, target):
257 cd42d0ad Guido Trotter
    """Prepare to accept an instance.
258 cd42d0ad Guido Trotter

259 cd42d0ad Guido Trotter
    By default assume no preparation is needed.
260 cd42d0ad Guido Trotter

261 cd42d0ad Guido Trotter
    @type instance: L{objects.Instance}
262 cd42d0ad Guido Trotter
    @param instance: instance to be accepted
263 cd42d0ad Guido Trotter
    @type info: string/data (opaque)
264 cd42d0ad Guido Trotter
    @param info: migration information, from the source node
265 cd42d0ad Guido Trotter
    @type target: string
266 cd42d0ad Guido Trotter
    @param target: target host (usually ip), on this node
267 cd42d0ad Guido Trotter

268 cd42d0ad Guido Trotter
    """
269 cd42d0ad Guido Trotter
    pass
270 cd42d0ad Guido Trotter
271 cd42d0ad Guido Trotter
  def FinalizeMigration(self, instance, info, success):
272 cd42d0ad Guido Trotter
    """Finalized an instance migration.
273 cd42d0ad Guido Trotter

274 cd42d0ad Guido Trotter
    Should finalize or revert any preparation done to accept the instance.
275 cd42d0ad Guido Trotter
    Since by default we do no preparation, we also don't have anything to do
276 cd42d0ad Guido Trotter

277 cd42d0ad Guido Trotter
    @type instance: L{objects.Instance}
278 fea922fa Guido Trotter
    @param instance: instance whose migration is being finalized
279 cd42d0ad Guido Trotter
    @type info: string/data (opaque)
280 cd42d0ad Guido Trotter
    @param info: migration information, from the source node
281 cd42d0ad Guido Trotter
    @type success: boolean
282 cd42d0ad Guido Trotter
    @param success: whether the migration was a success or a failure
283 cd42d0ad Guido Trotter

284 cd42d0ad Guido Trotter
    """
285 cd42d0ad Guido Trotter
    pass
286 cd42d0ad Guido Trotter
287 58d38b02 Iustin Pop
  def MigrateInstance(self, instance, target, live):
288 6e7275c0 Iustin Pop
    """Migrate an instance.
289 6e7275c0 Iustin Pop

290 3a488770 Iustin Pop
    @type instance: L{objects.Instance}
291 9044275a Michael Hanselmann
    @param instance: the instance to be migrated
292 cd42d0ad Guido Trotter
    @type target: string
293 cd42d0ad Guido Trotter
    @param target: hostname (usually ip) of the target node
294 cd42d0ad Guido Trotter
    @type live: boolean
295 cd42d0ad Guido Trotter
    @param live: whether to do a live or non-live migration
296 6e7275c0 Iustin Pop

297 6e7275c0 Iustin Pop
    """
298 6e7275c0 Iustin Pop
    raise NotImplementedError
299 f48148c3 Iustin Pop
300 f48148c3 Iustin Pop
  @classmethod
301 f48148c3 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
302 f48148c3 Iustin Pop
    """Check the given parameters for validity.
303 f48148c3 Iustin Pop

304 f48148c3 Iustin Pop
    This should check the passed set of parameters for
305 f48148c3 Iustin Pop
    validity. Classes should extend, not replace, this function.
306 f48148c3 Iustin Pop

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

311 f48148c3 Iustin Pop
    """
312 f48148c3 Iustin Pop
    for key in hvparams:
313 f48148c3 Iustin Pop
      if key not in cls.PARAMETERS:
314 205ab586 Iustin Pop
        raise errors.HypervisorError("Parameter '%s' is not supported" % key)
315 205ab586 Iustin Pop
316 205ab586 Iustin Pop
    # cheap tests that run on the master, should not access the world
317 205ab586 Iustin Pop
    for name, (required, check_fn, errstr, _, _) in cls.PARAMETERS.items():
318 205ab586 Iustin Pop
      if name not in hvparams:
319 205ab586 Iustin Pop
        raise errors.HypervisorError("Parameter '%s' is missing" % name)
320 205ab586 Iustin Pop
      value = hvparams[name]
321 205ab586 Iustin Pop
      if not required and not value:
322 205ab586 Iustin Pop
        continue
323 205ab586 Iustin Pop
      if not value:
324 205ab586 Iustin Pop
        raise errors.HypervisorError("Parameter '%s' is required but"
325 205ab586 Iustin Pop
                                     " is currently not defined" % (name, ))
326 205ab586 Iustin Pop
      if check_fn is not None and not check_fn(value):
327 205ab586 Iustin Pop
        raise errors.HypervisorError("Parameter '%s' fails syntax"
328 205ab586 Iustin Pop
                                     " check: %s (current value: '%s')" %
329 205ab586 Iustin Pop
                                     (name, errstr, value))
330 205ab586 Iustin Pop
331 205ab586 Iustin Pop
  @classmethod
332 205ab586 Iustin Pop
  def ValidateParameters(cls, hvparams):
333 f48148c3 Iustin Pop
    """Check the given parameters for validity.
334 f48148c3 Iustin Pop

335 f48148c3 Iustin Pop
    This should check the passed set of parameters for
336 f48148c3 Iustin Pop
    validity. Classes should extend, not replace, this function.
337 f48148c3 Iustin Pop

338 f48148c3 Iustin Pop
    @type hvparams:  dict
339 f48148c3 Iustin Pop
    @param hvparams: dictionary with parameter names/value
340 f48148c3 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
341 f48148c3 Iustin Pop

342 f48148c3 Iustin Pop
    """
343 205ab586 Iustin Pop
    for name, (required, _, _, check_fn, errstr) in cls.PARAMETERS.items():
344 205ab586 Iustin Pop
      value = hvparams[name]
345 205ab586 Iustin Pop
      if not required and not value:
346 205ab586 Iustin Pop
        continue
347 205ab586 Iustin Pop
      if check_fn is not None and not check_fn(value):
348 205ab586 Iustin Pop
        raise errors.HypervisorError("Parameter '%s' fails"
349 205ab586 Iustin Pop
                                     " validation: %s (current value: '%s')" %
350 205ab586 Iustin Pop
                                     (name, errstr, value))
351 572e52bf Iustin Pop
352 f5118ade Iustin Pop
  @classmethod
353 f5118ade Iustin Pop
  def PowercycleNode(cls):
354 f5118ade Iustin Pop
    """Hard powercycle a node using hypervisor specific methods.
355 f5118ade Iustin Pop

356 f5118ade Iustin Pop
    This method should hard powercycle the node, using whatever
357 f5118ade Iustin Pop
    methods the hypervisor provides. Note that this means that all
358 f5118ade Iustin Pop
    instances running on the node must be stopped too.
359 f5118ade Iustin Pop

360 f5118ade Iustin Pop
    """
361 f5118ade Iustin Pop
    raise NotImplementedError
362 f5118ade Iustin Pop
363 94fed7da Iustin Pop
  @staticmethod
364 94fed7da Iustin Pop
  def GetLinuxNodeInfo():
365 572e52bf Iustin Pop
    """For linux systems, return actual OS information.
366 572e52bf Iustin Pop

367 572e52bf Iustin Pop
    This is an abstraction for all non-hypervisor-based classes, where
368 572e52bf Iustin Pop
    the node actually sees all the memory and CPUs via the /proc
369 572e52bf Iustin Pop
    interface and standard commands. The other case if for example
370 572e52bf Iustin Pop
    xen, where you only see the hardware resources via xen-specific
371 572e52bf Iustin Pop
    tools.
372 572e52bf Iustin Pop

373 572e52bf Iustin Pop
    @return: a dict with the following keys (values in MiB):
374 572e52bf Iustin Pop
          - memory_total: the total memory size on the node
375 572e52bf Iustin Pop
          - memory_free: the available memory on the node for instances
376 572e52bf Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
377 572e52bf Iustin Pop

378 572e52bf Iustin Pop
    """
379 572e52bf Iustin Pop
    try:
380 3374afa9 Guido Trotter
      data = utils.ReadFile("/proc/meminfo").splitlines()
381 572e52bf Iustin Pop
    except EnvironmentError, err:
382 572e52bf Iustin Pop
      raise errors.HypervisorError("Failed to list node info: %s" % (err,))
383 572e52bf Iustin Pop
384 572e52bf Iustin Pop
    result = {}
385 572e52bf Iustin Pop
    sum_free = 0
386 572e52bf Iustin Pop
    try:
387 572e52bf Iustin Pop
      for line in data:
388 572e52bf Iustin Pop
        splitfields = line.split(":", 1)
389 572e52bf Iustin Pop
390 572e52bf Iustin Pop
        if len(splitfields) > 1:
391 572e52bf Iustin Pop
          key = splitfields[0].strip()
392 572e52bf Iustin Pop
          val = splitfields[1].strip()
393 572e52bf Iustin Pop
          if key == 'MemTotal':
394 572e52bf Iustin Pop
            result['memory_total'] = int(val.split()[0])/1024
395 572e52bf Iustin Pop
          elif key in ('MemFree', 'Buffers', 'Cached'):
396 572e52bf Iustin Pop
            sum_free += int(val.split()[0])/1024
397 572e52bf Iustin Pop
          elif key == 'Active':
398 572e52bf Iustin Pop
            result['memory_dom0'] = int(val.split()[0])/1024
399 572e52bf Iustin Pop
    except (ValueError, TypeError), err:
400 572e52bf Iustin Pop
      raise errors.HypervisorError("Failed to compute memory usage: %s" %
401 572e52bf Iustin Pop
                                   (err,))
402 572e52bf Iustin Pop
    result['memory_free'] = sum_free
403 572e52bf Iustin Pop
404 572e52bf Iustin Pop
    cpu_total = 0
405 572e52bf Iustin Pop
    try:
406 572e52bf Iustin Pop
      fh = open("/proc/cpuinfo")
407 572e52bf Iustin Pop
      try:
408 572e52bf Iustin Pop
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
409 572e52bf Iustin Pop
                                   fh.read()))
410 572e52bf Iustin Pop
      finally:
411 572e52bf Iustin Pop
        fh.close()
412 572e52bf Iustin Pop
    except EnvironmentError, err:
413 572e52bf Iustin Pop
      raise errors.HypervisorError("Failed to list node info: %s" % (err,))
414 572e52bf Iustin Pop
    result['cpu_total'] = cpu_total
415 572e52bf Iustin Pop
    # FIXME: export correct data here
416 572e52bf Iustin Pop
    result['cpu_nodes'] = 1
417 572e52bf Iustin Pop
    result['cpu_sockets'] = 1
418 572e52bf Iustin Pop
419 572e52bf Iustin Pop
    return result
420 f5118ade Iustin Pop
421 f5118ade Iustin Pop
  @classmethod
422 f5118ade Iustin Pop
  def LinuxPowercycle(cls):
423 f5118ade Iustin Pop
    """Linux-specific powercycle method.
424 f5118ade Iustin Pop

425 f5118ade Iustin Pop
    """
426 f5118ade Iustin Pop
    try:
427 f5118ade Iustin Pop
      fd = os.open("/proc/sysrq-trigger", os.O_WRONLY)
428 f5118ade Iustin Pop
      try:
429 f5118ade Iustin Pop
        os.write(fd, "b")
430 f5118ade Iustin Pop
      finally:
431 f5118ade Iustin Pop
        fd.close()
432 f5118ade Iustin Pop
    except OSError:
433 f5118ade Iustin Pop
      logging.exception("Can't open the sysrq-trigger file")
434 f5118ade Iustin Pop
      result = utils.RunCmd(["reboot", "-n", "-f"])
435 f5118ade Iustin Pop
      if not result:
436 f5118ade Iustin Pop
        logging.error("Can't run shutdown: %s", result.output)