Package ganeti :: Package hypervisor :: Module hv_base
[hide private]
[frames] | no frames]

Source Code for Module ganeti.hypervisor.hv_base

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2012, 2013 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """Base class for all hypervisors 
 32   
 33  The syntax for the _CHECK variables and the contents of the PARAMETERS 
 34  dict is the same, see the docstring for L{BaseHypervisor.PARAMETERS}. 
 35   
 36  @var _FILE_CHECK: stub for file checks, without the required flag 
 37  @var _DIR_CHECK: stub for directory checks, without the required flag 
 38  @var REQ_FILE_CHECK: mandatory file parameter 
 39  @var OPT_FILE_CHECK: optional file parameter 
 40  @var REQ_DIR_CHECK: mandatory directory parametr 
 41  @var OPT_DIR_CHECK: optional directory parameter 
 42  @var NO_CHECK: parameter without any checks at all 
 43  @var REQUIRED_CHECK: parameter required to exist (and non-false), but 
 44      without other checks; beware that this can't be used for boolean 
 45      parameters, where you should use NO_CHECK or a custom checker 
 46   
 47  """ 
 48   
 49  import os 
 50  import re 
 51  import logging 
 52   
 53   
 54  from ganeti import constants 
 55  from ganeti import errors 
 56  from ganeti import objects 
 57  from ganeti import utils 
58 59 60 -def _IsCpuMaskWellFormed(cpu_mask):
61 """Verifies if the given single CPU mask is valid 62 63 The single CPU mask should be in the form "a,b,c,d", where each 64 letter is a positive number or range. 65 66 """ 67 try: 68 cpu_list = utils.ParseCpuMask(cpu_mask) 69 except errors.ParseError, _: 70 return False 71 return isinstance(cpu_list, list) and len(cpu_list) > 0
72
73 74 -def _IsMultiCpuMaskWellFormed(cpu_mask):
75 """Verifies if the given multiple CPU mask is valid 76 77 A valid multiple CPU mask is in the form "a:b:c:d", where each 78 letter is a single CPU mask. 79 80 """ 81 try: 82 utils.ParseMultiCpuMask(cpu_mask) 83 except errors.ParseError, _: 84 return False 85 86 return True
87 88 89 # Read the BaseHypervisor.PARAMETERS docstring for the syntax of the 90 # _CHECK values 91 92 # must be a file 93 _FILE_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path", 94 os.path.isfile, "not found or not a file") 95 96 # must be a file or a URL 97 _FILE_OR_URL_CHECK = (lambda x: utils.IsNormAbsPath(x) or utils.IsUrl(x), 98 "must be an absolute normalized path or a URL", 99 lambda x: os.path.isfile(x) or utils.IsUrl(x), 100 "not found or not a file or URL") 101 102 # must be a directory 103 _DIR_CHECK = (utils.IsNormAbsPath, "must be an absolute normalized path", 104 os.path.isdir, "not found or not a directory") 105 106 # CPU mask must be well-formed 107 # TODO: implement node level check for the CPU mask 108 _CPU_MASK_CHECK = (_IsCpuMaskWellFormed, 109 "CPU mask definition is not well-formed", 110 None, None) 111 112 # Multiple CPU mask must be well-formed 113 _MULTI_CPU_MASK_CHECK = (_IsMultiCpuMaskWellFormed, 114 "Multiple CPU mask definition is not well-formed", 115 None, None) 116 117 # Check for validity of port number 118 _NET_PORT_CHECK = (lambda x: 0 < x < 65535, "invalid port number", 119 None, None) 120 121 # Check if number of queues is in safe range 122 _VIRTIO_NET_QUEUES_CHECK = (lambda x: 0 < x < 9, "invalid number of queues", 123 None, None) 124 125 # Check that an integer is non negative 126 _NONNEGATIVE_INT_CHECK = (lambda x: x >= 0, "cannot be negative", None, None) 127 128 # nice wrappers for users 129 REQ_FILE_CHECK = (True, ) + _FILE_CHECK 130 OPT_FILE_CHECK = (False, ) + _FILE_CHECK 131 REQ_FILE_OR_URL_CHECK = (True, ) + _FILE_OR_URL_CHECK 132 OPT_FILE_OR_URL_CHECK = (False, ) + _FILE_OR_URL_CHECK 133 REQ_DIR_CHECK = (True, ) + _DIR_CHECK 134 OPT_DIR_CHECK = (False, ) + _DIR_CHECK 135 REQ_NET_PORT_CHECK = (True, ) + _NET_PORT_CHECK 136 OPT_NET_PORT_CHECK = (False, ) + _NET_PORT_CHECK 137 REQ_VIRTIO_NET_QUEUES_CHECK = (True, ) + _VIRTIO_NET_QUEUES_CHECK 138 OPT_VIRTIO_NET_QUEUES_CHECK = (False, ) + _VIRTIO_NET_QUEUES_CHECK 139 REQ_CPU_MASK_CHECK = (True, ) + _CPU_MASK_CHECK 140 OPT_CPU_MASK_CHECK = (False, ) + _CPU_MASK_CHECK 141 REQ_MULTI_CPU_MASK_CHECK = (True, ) + _MULTI_CPU_MASK_CHECK 142 OPT_MULTI_CPU_MASK_CHECK = (False, ) + _MULTI_CPU_MASK_CHECK 143 REQ_NONNEGATIVE_INT_CHECK = (True, ) + _NONNEGATIVE_INT_CHECK 144 OPT_NONNEGATIVE_INT_CHECK = (False, ) + _NONNEGATIVE_INT_CHECK 145 146 # no checks at all 147 NO_CHECK = (False, None, None, None, None) 148 149 # required, but no other checks 150 REQUIRED_CHECK = (True, None, None, None, None) 151 152 # migration type 153 MIGRATION_MODE_CHECK = (True, lambda x: x in constants.HT_MIGRATION_MODES, 154 "invalid migration mode", None, None)
155 156 157 -def ParamInSet(required, my_set):
158 """Builds parameter checker for set membership. 159 160 @type required: boolean 161 @param required: whether this is a required parameter 162 @type my_set: tuple, list or set 163 @param my_set: allowed values set 164 165 """ 166 fn = lambda x: x in my_set 167 err = ("The value must be one of: %s" % utils.CommaJoin(my_set)) 168 return (required, fn, err, None, None)
169
170 171 -def GenerateTapName():
172 """Generate a TAP network interface name for a NIC. 173 174 This helper function generates a special TAP network interface 175 name for NICs that are meant to be used in instance communication. 176 This function checks the existing TAP interfaces in order to find 177 a unique name for the new TAP network interface. The TAP network 178 interface names are of the form 'gnt.com.%d', where '%d' is a 179 unique number within the node. 180 181 @rtype: string 182 @return: TAP network interface name, or the empty string if the 183 NIC is not used in instance communication 184 185 """ 186 result = utils.RunCmd(["ip", "link", "show"]) 187 188 if result.failed: 189 raise errors.HypervisorError("Failed to list TUN/TAP interfaces") 190 191 idxs = set() 192 193 for line in result.output.splitlines()[0::2]: 194 parts = line.split(": ") 195 196 if len(parts) < 2: 197 raise errors.HypervisorError("Failed to parse TUN/TAP interfaces") 198 199 r = re.match(r"gnt\.com\.([0-9]+)", parts[1]) 200 201 if r is not None: 202 idxs.add(int(r.group(1))) 203 204 if idxs: 205 idx = max(idxs) + 1 206 else: 207 idx = 0 208 209 return "gnt.com.%d" % idx
210
211 212 -def ConfigureNIC(cmd, instance, seq, nic, tap):
213 """Run the network configuration script for a specified NIC 214 215 @type cmd: string 216 @param cmd: command to run 217 @type instance: instance object 218 @param instance: instance we're acting on 219 @type seq: int 220 @param seq: nic sequence number 221 @type nic: nic object 222 @param nic: nic we're acting on 223 @type tap: str 224 @param tap: the host's tap interface this NIC corresponds to 225 226 """ 227 env = { 228 "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"], 229 "INSTANCE": instance.name, 230 "MAC": nic.mac, 231 "MODE": nic.nicparams[constants.NIC_MODE], 232 "INTERFACE": tap, 233 "INTERFACE_INDEX": str(seq), 234 "INTERFACE_UUID": nic.uuid, 235 "TAGS": " ".join(instance.GetTags()), 236 } 237 238 if nic.ip: 239 env["IP"] = nic.ip 240 241 if nic.name: 242 env["INTERFACE_NAME"] = nic.name 243 244 if nic.nicparams[constants.NIC_LINK]: 245 env["LINK"] = nic.nicparams[constants.NIC_LINK] 246 247 if constants.NIC_VLAN in nic.nicparams: 248 env["VLAN"] = nic.nicparams[constants.NIC_VLAN] 249 250 if nic.network: 251 n = objects.Network.FromDict(nic.netinfo) 252 env.update(n.HooksDict()) 253 254 if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED: 255 env["BRIDGE"] = nic.nicparams[constants.NIC_LINK] 256 257 result = utils.RunCmd(cmd, env=env) 258 if result.failed: 259 raise errors.HypervisorError("Failed to configure interface %s: %s;" 260 " network configuration script output: %s" % 261 (tap, result.fail_reason, result.output))
262
263 264 -class HvInstanceState(object):
265 RUNNING = 0 266 SHUTDOWN = 1 267 268 @staticmethod
269 - def IsRunning(s):
270 return s == HvInstanceState.RUNNING
271 272 @staticmethod
273 - def IsShutdown(s):
274 return s == HvInstanceState.SHUTDOWN
275
276 277 -class BaseHypervisor(object):
278 """Abstract virtualisation technology interface 279 280 The goal is that all aspects of the virtualisation technology are 281 abstracted away from the rest of code. 282 283 @cvar PARAMETERS: a dict of parameter name: check type; the check type is 284 a five-tuple containing: 285 - the required flag (boolean) 286 - a function to check for syntax, that will be used in 287 L{CheckParameterSyntax}, in the master daemon process 288 - an error message for the above function 289 - a function to check for parameter validity on the remote node, 290 in the L{ValidateParameters} function 291 - an error message for the above function 292 @type CAN_MIGRATE: boolean 293 @cvar CAN_MIGRATE: whether this hypervisor can do migration (either 294 live or non-live) 295 296 """ 297 PARAMETERS = {} 298 ANCILLARY_FILES = [] 299 ANCILLARY_FILES_OPT = [] 300 CAN_MIGRATE = False 301
302 - def StartInstance(self, instance, block_devices, startup_paused):
303 """Start an instance.""" 304 raise NotImplementedError
305
306 - def StopInstance(self, instance, force=False, retry=False, name=None, 307 timeout=None):
308 """Stop an instance 309 310 @type instance: L{objects.Instance} 311 @param instance: instance to stop 312 @type force: boolean 313 @param force: whether to do a "hard" stop (destroy) 314 @type retry: boolean 315 @param retry: whether this is just a retry call 316 @type name: string or None 317 @param name: if this parameter is passed, the the instance object 318 should not be used (will be passed as None), and the shutdown 319 must be done by name only 320 @type timeout: int or None 321 @param timeout: if the parameter is not None, a soft shutdown operation will 322 be killed after the specified number of seconds. A hard (forced) 323 shutdown cannot have a timeout 324 @raise errors.HypervisorError: when a parameter is not valid or 325 the instance failed to be stopped 326 327 """ 328 raise NotImplementedError
329
330 - def CleanupInstance(self, instance_name):
331 """Cleanup after a stopped instance 332 333 This is an optional method, used by hypervisors that need to cleanup after 334 an instance has been stopped. 335 336 @type instance_name: string 337 @param instance_name: instance name to cleanup after 338 339 """ 340 pass
341
342 - def RebootInstance(self, instance):
343 """Reboot an instance.""" 344 raise NotImplementedError
345
346 - def ListInstances(self, hvparams=None):
347 """Get the list of running instances.""" 348 raise NotImplementedError
349
350 - def GetInstanceInfo(self, instance_name, hvparams=None):
351 """Get instance properties. 352 353 @type instance_name: string 354 @param instance_name: the instance name 355 @type hvparams: dict of strings 356 @param hvparams: hvparams to be used with this instance 357 358 @rtype: (string, string, int, int, HvInstanceState, int) 359 @return: tuple (name, id, memory, vcpus, state, times) 360 361 """ 362 raise NotImplementedError
363
364 - def GetAllInstancesInfo(self, hvparams=None):
365 """Get properties of all instances. 366 367 @type hvparams: dict of strings 368 @param hvparams: hypervisor parameter 369 370 @rtype: (string, string, int, int, HvInstanceState, int) 371 @return: list of tuples (name, id, memory, vcpus, state, times) 372 373 """ 374 raise NotImplementedError
375
376 - def GetNodeInfo(self, hvparams=None):
377 """Return information about the node. 378 379 @type hvparams: dict of strings 380 @param hvparams: hypervisor parameters 381 382 @return: a dict with at least the following keys (memory values in MiB): 383 - memory_total: the total memory size on the node 384 - memory_free: the available memory on the node for instances 385 - memory_dom0: the memory used by the node itself, if available 386 - cpu_total: total number of CPUs 387 - cpu_dom0: number of CPUs used by the node OS 388 - cpu_nodes: number of NUMA domains 389 - cpu_sockets: number of physical CPU sockets 390 391 """ 392 raise NotImplementedError
393 394 @classmethod
395 - def GetInstanceConsole(cls, instance, primary_node, node_group, 396 hvparams, beparams):
397 """Return information for connecting to the console of an instance. 398 399 """ 400 raise NotImplementedError
401 402 @classmethod
403 - def GetAncillaryFiles(cls):
404 """Return a list of ancillary files to be copied to all nodes as ancillary 405 configuration files. 406 407 @rtype: (list of absolute paths, list of absolute paths) 408 @return: (all files, optional files) 409 410 """ 411 # By default we return a member variable, so that if an hypervisor has just 412 # a static list of files it doesn't have to override this function. 413 assert set(cls.ANCILLARY_FILES).issuperset(cls.ANCILLARY_FILES_OPT), \ 414 "Optional ancillary files must be a subset of ancillary files" 415 416 return (cls.ANCILLARY_FILES, cls.ANCILLARY_FILES_OPT)
417
418 - def Verify(self, hvparams=None):
419 """Verify the hypervisor. 420 421 @type hvparams: dict of strings 422 @param hvparams: hypervisor parameters to be verified against 423 424 @return: Problem description if something is wrong, C{None} otherwise 425 426 """ 427 raise NotImplementedError
428 429 @staticmethod
430 - def VersionsSafeForMigration(src, target):
431 """Decide if migration between those version is likely to suceed. 432 433 Given two versions of a hypervisor, give a guess whether live migration 434 from the one version to the other version is likely to succeed. The current 435 436 """ 437 if src == target: 438 return True 439 440 return False
441
442 - def MigrationInfo(self, instance): # pylint: disable=R0201,W0613
443 """Get instance information to perform a migration. 444 445 By default assume no information is needed. 446 447 @type instance: L{objects.Instance} 448 @param instance: instance to be migrated 449 @rtype: string/data (opaque) 450 @return: instance migration information - serialized form 451 452 """ 453 return ""
454
455 - def AcceptInstance(self, instance, info, target):
456 """Prepare to accept an instance. 457 458 By default assume no preparation is needed. 459 460 @type instance: L{objects.Instance} 461 @param instance: instance to be accepted 462 @type info: string/data (opaque) 463 @param info: migration information, from the source node 464 @type target: string 465 @param target: target host (usually ip), on this node 466 467 """ 468 pass
469
470 - def BalloonInstanceMemory(self, instance, mem):
471 """Balloon an instance memory to a certain value. 472 473 @type instance: L{objects.Instance} 474 @param instance: instance to be accepted 475 @type mem: int 476 @param mem: actual memory size to use for instance runtime 477 478 """ 479 raise NotImplementedError
480
481 - def FinalizeMigrationDst(self, instance, info, success):
482 """Finalize the instance migration on the target node. 483 484 Should finalize or revert any preparation done to accept the instance. 485 Since by default we do no preparation, we also don't have anything to do 486 487 @type instance: L{objects.Instance} 488 @param instance: instance whose migration is being finalized 489 @type info: string/data (opaque) 490 @param info: migration information, from the source node 491 @type success: boolean 492 @param success: whether the migration was a success or a failure 493 494 """ 495 pass
496
497 - def MigrateInstance(self, cluster_name, instance, target, live):
498 """Migrate an instance. 499 500 @type cluster_name: string 501 @param cluster_name: name of the cluster 502 @type instance: L{objects.Instance} 503 @param instance: the instance to be migrated 504 @type target: string 505 @param target: hostname (usually ip) of the target node 506 @type live: boolean 507 @param live: whether to do a live or non-live migration 508 509 """ 510 raise NotImplementedError
511
512 - def FinalizeMigrationSource(self, instance, success, live):
513 """Finalize the instance migration on the source node. 514 515 @type instance: L{objects.Instance} 516 @param instance: the instance that was migrated 517 @type success: bool 518 @param success: whether the migration succeeded or not 519 @type live: bool 520 @param live: whether the user requested a live migration or not 521 522 """ 523 pass
524
525 - def GetMigrationStatus(self, instance):
526 """Get the migration status 527 528 @type instance: L{objects.Instance} 529 @param instance: the instance that is being migrated 530 @rtype: L{objects.MigrationStatus} 531 @return: the status of the current migration (one of 532 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional 533 progress info that can be retrieved from the hypervisor 534 535 """ 536 raise NotImplementedError
537
538 - def _InstanceStartupMemory(self, instance):
539 """Get the correct startup memory for an instance 540 541 This function calculates how much memory an instance should be started 542 with, making sure it's a value between the minimum and the maximum memory, 543 but also trying to use no more than the current free memory on the node. 544 545 @type instance: L{objects.Instance} 546 @param instance: the instance that is being started 547 @rtype: integer 548 @return: memory the instance should be started with 549 550 """ 551 free_memory = self.GetNodeInfo(hvparams=instance.hvparams)["memory_free"] 552 max_start_mem = min(instance.beparams[constants.BE_MAXMEM], free_memory) 553 start_mem = max(instance.beparams[constants.BE_MINMEM], max_start_mem) 554 return start_mem
555 556 @classmethod
557 - def _IsParamValueUnspecified(cls, param_value):
558 """Check if the parameter value is a kind of value meaning unspecified. 559 560 This function checks if the parameter value is a kind of value meaning 561 unspecified. 562 563 @type param_value: any 564 @param param_value: the parameter value that needs to be checked 565 @rtype: bool 566 @return: True if the parameter value is a kind of value meaning unspecified, 567 False otherwise 568 569 """ 570 return param_value is None \ 571 or isinstance(param_value, basestring) and param_value == ""
572 573 @classmethod
574 - def CheckParameterSyntax(cls, hvparams):
575 """Check the given parameters for validity. 576 577 This should check the passed set of parameters for 578 validity. Classes should extend, not replace, this function. 579 580 @type hvparams: dict 581 @param hvparams: dictionary with parameter names/value 582 @raise errors.HypervisorError: when a parameter is not valid 583 584 """ 585 for key in hvparams: 586 if key not in cls.PARAMETERS: 587 raise errors.HypervisorError("Parameter '%s' is not supported" % key) 588 589 # cheap tests that run on the master, should not access the world 590 for name, (required, check_fn, errstr, _, _) in cls.PARAMETERS.items(): 591 if name not in hvparams: 592 raise errors.HypervisorError("Parameter '%s' is missing" % name) 593 value = hvparams[name] 594 if not required and cls._IsParamValueUnspecified(value): 595 continue 596 if cls._IsParamValueUnspecified(value): 597 raise errors.HypervisorError("Parameter '%s' is required but" 598 " is currently not defined" % (name, )) 599 if check_fn is not None and not check_fn(value): 600 raise errors.HypervisorError("Parameter '%s' fails syntax" 601 " check: %s (current value: '%s')" % 602 (name, errstr, value))
603 604 @classmethod
605 - def ValidateParameters(cls, hvparams):
606 """Check the given parameters for validity. 607 608 This should check the passed set of parameters for 609 validity. Classes should extend, not replace, this function. 610 611 @type hvparams: dict 612 @param hvparams: dictionary with parameter names/value 613 @raise errors.HypervisorError: when a parameter is not valid 614 615 """ 616 for name, (required, _, _, check_fn, errstr) in cls.PARAMETERS.items(): 617 value = hvparams[name] 618 if not required and cls._IsParamValueUnspecified(value): 619 continue 620 if check_fn is not None and not check_fn(value): 621 raise errors.HypervisorError("Parameter '%s' fails" 622 " validation: %s (current value: '%s')" % 623 (name, errstr, value))
624 625 @classmethod
626 - def PowercycleNode(cls, hvparams=None):
627 """Hard powercycle a node using hypervisor specific methods. 628 629 This method should hard powercycle the node, using whatever 630 methods the hypervisor provides. Note that this means that all 631 instances running on the node must be stopped too. 632 633 @type hvparams: dict of strings 634 @param hvparams: hypervisor params to be used on this node 635 636 """ 637 raise NotImplementedError
638 639 @staticmethod
640 - def GetLinuxNodeInfo(meminfo="/proc/meminfo", cpuinfo="/proc/cpuinfo"):
641 """For linux systems, return actual OS information. 642 643 This is an abstraction for all non-hypervisor-based classes, where 644 the node actually sees all the memory and CPUs via the /proc 645 interface and standard commands. The other case if for example 646 xen, where you only see the hardware resources via xen-specific 647 tools. 648 649 @param meminfo: name of the file containing meminfo 650 @type meminfo: string 651 @param cpuinfo: name of the file containing cpuinfo 652 @type cpuinfo: string 653 @return: a dict with the following keys (values in MiB): 654 - memory_total: the total memory size on the node 655 - memory_free: the available memory on the node for instances 656 - memory_dom0: the memory used by the node itself, if available 657 - cpu_total: total number of CPUs 658 - cpu_dom0: number of CPUs used by the node OS 659 - cpu_nodes: number of NUMA domains 660 - cpu_sockets: number of physical CPU sockets 661 662 """ 663 try: 664 data = utils.ReadFile(meminfo).splitlines() 665 except EnvironmentError, err: 666 raise errors.HypervisorError("Failed to list node info: %s" % (err,)) 667 668 result = {} 669 sum_free = 0 670 try: 671 for line in data: 672 splitfields = line.split(":", 1) 673 674 if len(splitfields) > 1: 675 key = splitfields[0].strip() 676 val = splitfields[1].strip() 677 if key == "MemTotal": 678 result["memory_total"] = int(val.split()[0]) / 1024 679 elif key in ("MemFree", "Buffers", "Cached"): 680 sum_free += int(val.split()[0]) / 1024 681 elif key == "Active": 682 result["memory_dom0"] = int(val.split()[0]) / 1024 683 except (ValueError, TypeError), err: 684 raise errors.HypervisorError("Failed to compute memory usage: %s" % 685 (err,)) 686 result["memory_free"] = sum_free 687 688 cpu_total = 0 689 try: 690 fh = open(cpuinfo) 691 try: 692 cpu_total = len(re.findall(r"(?m)^processor\s*:\s*[0-9]+\s*$", 693 fh.read())) 694 finally: 695 fh.close() 696 except EnvironmentError, err: 697 raise errors.HypervisorError("Failed to list node info: %s" % (err,)) 698 result["cpu_total"] = cpu_total 699 # We assume that the node OS can access all the CPUs 700 result["cpu_dom0"] = cpu_total 701 # FIXME: export correct data here 702 result["cpu_nodes"] = 1 703 result["cpu_sockets"] = 1 704 705 return result
706 707 @classmethod
708 - def LinuxPowercycle(cls):
709 """Linux-specific powercycle method. 710 711 """ 712 try: 713 fd = os.open("/proc/sysrq-trigger", os.O_WRONLY) 714 try: 715 os.write(fd, "b") 716 finally: 717 fd.close() 718 except OSError: 719 logging.exception("Can't open the sysrq-trigger file") 720 result = utils.RunCmd(["reboot", "-n", "-f"]) 721 if not result: 722 logging.error("Can't run shutdown: %s", result.output)
723 724 @staticmethod
725 - def _FormatVerifyResults(msgs):
726 """Formats the verification results, given a list of errors. 727 728 @param msgs: list of errors, possibly empty 729 @return: overall problem description if something is wrong, 730 C{None} otherwise 731 732 """ 733 if msgs: 734 return "; ".join(msgs) 735 else: 736 return None
737 738 # pylint: disable=R0201,W0613
739 - def HotAddDevice(self, instance, dev_type, device, extra, seq):
740 """Hot-add a device. 741 742 """ 743 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
744 745 # pylint: disable=R0201,W0613
746 - def HotDelDevice(self, instance, dev_type, device, extra, seq):
747 """Hot-del a device. 748 749 """ 750 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
751 752 # pylint: disable=R0201,W0613
753 - def HotModDevice(self, instance, dev_type, device, extra, seq):
754 """Hot-mod a device. 755 756 """ 757 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
758 759 # pylint: disable=R0201,W0613
760 - def VerifyHotplugSupport(self, instance, action, dev_type):
761 """Verifies that hotplug is supported. 762 763 Given the target device and hotplug action checks if hotplug is 764 actually supported. 765 766 @type instance: L{objects.Instance} 767 @param instance: the instance object 768 @type action: string 769 @param action: one of the supported hotplug commands 770 @type dev_type: string 771 @param dev_type: one of the supported device types to hotplug 772 @raise errors.HotplugError: if hotplugging is not supported 773 774 """ 775 raise errors.HotplugError("Hotplug is not supported.")
776
777 - def HotplugSupported(self, instance):
778 """Checks if hotplug is supported. 779 780 By default is not. Currently only KVM hypervisor supports it. 781 782 """ 783 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
784