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 - def MigrationInfo(self, instance): # pylint: disable=R0201,W0613
430 """Get instance information to perform a migration. 431 432 By default assume no information is needed. 433 434 @type instance: L{objects.Instance} 435 @param instance: instance to be migrated 436 @rtype: string/data (opaque) 437 @return: instance migration information - serialized form 438 439 """ 440 return ""
441
442 - def AcceptInstance(self, instance, info, target):
443 """Prepare to accept an instance. 444 445 By default assume no preparation is needed. 446 447 @type instance: L{objects.Instance} 448 @param instance: instance to be accepted 449 @type info: string/data (opaque) 450 @param info: migration information, from the source node 451 @type target: string 452 @param target: target host (usually ip), on this node 453 454 """ 455 pass
456
457 - def BalloonInstanceMemory(self, instance, mem):
458 """Balloon an instance memory to a certain value. 459 460 @type instance: L{objects.Instance} 461 @param instance: instance to be accepted 462 @type mem: int 463 @param mem: actual memory size to use for instance runtime 464 465 """ 466 raise NotImplementedError
467
468 - def FinalizeMigrationDst(self, instance, info, success):
469 """Finalize the instance migration on the target node. 470 471 Should finalize or revert any preparation done to accept the instance. 472 Since by default we do no preparation, we also don't have anything to do 473 474 @type instance: L{objects.Instance} 475 @param instance: instance whose migration is being finalized 476 @type info: string/data (opaque) 477 @param info: migration information, from the source node 478 @type success: boolean 479 @param success: whether the migration was a success or a failure 480 481 """ 482 pass
483
484 - def MigrateInstance(self, cluster_name, instance, target, live):
485 """Migrate an instance. 486 487 @type cluster_name: string 488 @param cluster_name: name of the cluster 489 @type instance: L{objects.Instance} 490 @param instance: the instance to be migrated 491 @type target: string 492 @param target: hostname (usually ip) of the target node 493 @type live: boolean 494 @param live: whether to do a live or non-live migration 495 496 """ 497 raise NotImplementedError
498
499 - def FinalizeMigrationSource(self, instance, success, live):
500 """Finalize the instance migration on the source node. 501 502 @type instance: L{objects.Instance} 503 @param instance: the instance that was migrated 504 @type success: bool 505 @param success: whether the migration succeeded or not 506 @type live: bool 507 @param live: whether the user requested a live migration or not 508 509 """ 510 pass
511
512 - def GetMigrationStatus(self, instance):
513 """Get the migration status 514 515 @type instance: L{objects.Instance} 516 @param instance: the instance that is being migrated 517 @rtype: L{objects.MigrationStatus} 518 @return: the status of the current migration (one of 519 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional 520 progress info that can be retrieved from the hypervisor 521 522 """ 523 raise NotImplementedError
524
525 - def _InstanceStartupMemory(self, instance):
526 """Get the correct startup memory for an instance 527 528 This function calculates how much memory an instance should be started 529 with, making sure it's a value between the minimum and the maximum memory, 530 but also trying to use no more than the current free memory on the node. 531 532 @type instance: L{objects.Instance} 533 @param instance: the instance that is being started 534 @rtype: integer 535 @return: memory the instance should be started with 536 537 """ 538 free_memory = self.GetNodeInfo(hvparams=instance.hvparams)["memory_free"] 539 max_start_mem = min(instance.beparams[constants.BE_MAXMEM], free_memory) 540 start_mem = max(instance.beparams[constants.BE_MINMEM], max_start_mem) 541 return start_mem
542 543 @classmethod
544 - def CheckParameterSyntax(cls, hvparams):
545 """Check the given parameters for validity. 546 547 This should check the passed set of parameters for 548 validity. Classes should extend, not replace, this function. 549 550 @type hvparams: dict 551 @param hvparams: dictionary with parameter names/value 552 @raise errors.HypervisorError: when a parameter is not valid 553 554 """ 555 for key in hvparams: 556 if key not in cls.PARAMETERS: 557 raise errors.HypervisorError("Parameter '%s' is not supported" % key) 558 559 # cheap tests that run on the master, should not access the world 560 for name, (required, check_fn, errstr, _, _) in cls.PARAMETERS.items(): 561 if name not in hvparams: 562 raise errors.HypervisorError("Parameter '%s' is missing" % name) 563 value = hvparams[name] 564 if not required and not value: 565 continue 566 if not value: 567 raise errors.HypervisorError("Parameter '%s' is required but" 568 " is currently not defined" % (name, )) 569 if check_fn is not None and not check_fn(value): 570 raise errors.HypervisorError("Parameter '%s' fails syntax" 571 " check: %s (current value: '%s')" % 572 (name, errstr, value))
573 574 @classmethod
575 - def ValidateParameters(cls, hvparams):
576 """Check the given parameters for validity. 577 578 This should check the passed set of parameters for 579 validity. Classes should extend, not replace, this function. 580 581 @type hvparams: dict 582 @param hvparams: dictionary with parameter names/value 583 @raise errors.HypervisorError: when a parameter is not valid 584 585 """ 586 for name, (required, _, _, check_fn, errstr) in cls.PARAMETERS.items(): 587 value = hvparams[name] 588 if not required and not value: 589 continue 590 if check_fn is not None and not check_fn(value): 591 raise errors.HypervisorError("Parameter '%s' fails" 592 " validation: %s (current value: '%s')" % 593 (name, errstr, value))
594 595 @classmethod
596 - def PowercycleNode(cls, hvparams=None):
597 """Hard powercycle a node using hypervisor specific methods. 598 599 This method should hard powercycle the node, using whatever 600 methods the hypervisor provides. Note that this means that all 601 instances running on the node must be stopped too. 602 603 @type hvparams: dict of strings 604 @param hvparams: hypervisor params to be used on this node 605 606 """ 607 raise NotImplementedError
608 609 @staticmethod
610 - def GetLinuxNodeInfo(meminfo="/proc/meminfo", cpuinfo="/proc/cpuinfo"):
611 """For linux systems, return actual OS information. 612 613 This is an abstraction for all non-hypervisor-based classes, where 614 the node actually sees all the memory and CPUs via the /proc 615 interface and standard commands. The other case if for example 616 xen, where you only see the hardware resources via xen-specific 617 tools. 618 619 @param meminfo: name of the file containing meminfo 620 @type meminfo: string 621 @param cpuinfo: name of the file containing cpuinfo 622 @type cpuinfo: string 623 @return: a dict with the following keys (values in MiB): 624 - memory_total: the total memory size on the node 625 - memory_free: the available memory on the node for instances 626 - memory_dom0: the memory used by the node itself, if available 627 - cpu_total: total number of CPUs 628 - cpu_dom0: number of CPUs used by the node OS 629 - cpu_nodes: number of NUMA domains 630 - cpu_sockets: number of physical CPU sockets 631 632 """ 633 try: 634 data = utils.ReadFile(meminfo).splitlines() 635 except EnvironmentError, err: 636 raise errors.HypervisorError("Failed to list node info: %s" % (err,)) 637 638 result = {} 639 sum_free = 0 640 try: 641 for line in data: 642 splitfields = line.split(":", 1) 643 644 if len(splitfields) > 1: 645 key = splitfields[0].strip() 646 val = splitfields[1].strip() 647 if key == "MemTotal": 648 result["memory_total"] = int(val.split()[0]) / 1024 649 elif key in ("MemFree", "Buffers", "Cached"): 650 sum_free += int(val.split()[0]) / 1024 651 elif key == "Active": 652 result["memory_dom0"] = int(val.split()[0]) / 1024 653 except (ValueError, TypeError), err: 654 raise errors.HypervisorError("Failed to compute memory usage: %s" % 655 (err,)) 656 result["memory_free"] = sum_free 657 658 cpu_total = 0 659 try: 660 fh = open(cpuinfo) 661 try: 662 cpu_total = len(re.findall(r"(?m)^processor\s*:\s*[0-9]+\s*$", 663 fh.read())) 664 finally: 665 fh.close() 666 except EnvironmentError, err: 667 raise errors.HypervisorError("Failed to list node info: %s" % (err,)) 668 result["cpu_total"] = cpu_total 669 # We assume that the node OS can access all the CPUs 670 result["cpu_dom0"] = cpu_total 671 # FIXME: export correct data here 672 result["cpu_nodes"] = 1 673 result["cpu_sockets"] = 1 674 675 return result
676 677 @classmethod
678 - def LinuxPowercycle(cls):
679 """Linux-specific powercycle method. 680 681 """ 682 try: 683 fd = os.open("/proc/sysrq-trigger", os.O_WRONLY) 684 try: 685 os.write(fd, "b") 686 finally: 687 fd.close() 688 except OSError: 689 logging.exception("Can't open the sysrq-trigger file") 690 result = utils.RunCmd(["reboot", "-n", "-f"]) 691 if not result: 692 logging.error("Can't run shutdown: %s", result.output)
693 694 @staticmethod
695 - def _FormatVerifyResults(msgs):
696 """Formats the verification results, given a list of errors. 697 698 @param msgs: list of errors, possibly empty 699 @return: overall problem description if something is wrong, 700 C{None} otherwise 701 702 """ 703 if msgs: 704 return "; ".join(msgs) 705 else: 706 return None
707 708 # pylint: disable=R0201,W0613
709 - def HotAddDevice(self, instance, dev_type, device, extra, seq):
710 """Hot-add a device. 711 712 """ 713 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
714 715 # pylint: disable=R0201,W0613
716 - def HotDelDevice(self, instance, dev_type, device, extra, seq):
717 """Hot-del a device. 718 719 """ 720 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
721 722 # pylint: disable=R0201,W0613
723 - def HotModDevice(self, instance, dev_type, device, extra, seq):
724 """Hot-mod a device. 725 726 """ 727 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
728 729 # pylint: disable=R0201,W0613
730 - def VerifyHotplugSupport(self, instance, action, dev_type):
731 """Verifies that hotplug is supported. 732 733 Given the target device and hotplug action checks if hotplug is 734 actually supported. 735 736 @type instance: L{objects.Instance} 737 @param instance: the instance object 738 @type action: string 739 @param action: one of the supported hotplug commands 740 @type dev_type: string 741 @param dev_type: one of the supported device types to hotplug 742 @raise errors.HotplugError: if hotplugging is not supported 743 744 """ 745 raise errors.HotplugError("Hotplug is not supported.")
746
747 - def HotplugSupported(self, instance):
748 """Checks if hotplug is supported. 749 750 By default is not. Currently only KVM hypervisor supports it. 751 752 """ 753 raise errors.HotplugError("Hotplug is not supported by this hypervisor")
754