Package ganeti :: Module opcodes
[hide private]
[frames] | no frames]

Source Code for Module ganeti.opcodes

   1  # 
   2  # 
   3   
   4  # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc. 
   5  # 
   6  # This program is free software; you can redistribute it and/or modify 
   7  # it under the terms of the GNU General Public License as published by 
   8  # the Free Software Foundation; either version 2 of the License, or 
   9  # (at your option) any later version. 
  10  # 
  11  # This program is distributed in the hope that it will be useful, but 
  12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
  13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
  14  # General Public License for more details. 
  15  # 
  16  # You should have received a copy of the GNU General Public License 
  17  # along with this program; if not, write to the Free Software 
  18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
  19  # 02110-1301, USA. 
  20   
  21   
  22  """OpCodes module 
  23   
  24  This module implements the data structures which define the cluster 
  25  operations - the so-called opcodes. 
  26   
  27  Every operation which modifies the cluster state is expressed via 
  28  opcodes. 
  29   
  30  """ 
  31   
  32  # this are practically structures, so disable the message about too 
  33  # few public methods: 
  34  # pylint: disable=R0903 
  35   
  36  import logging 
  37  import re 
  38  import ipaddr 
  39   
  40  from ganeti import constants 
  41  from ganeti import errors 
  42  from ganeti import ht 
  43  from ganeti import objects 
  44  from ganeti import outils 
  45   
  46   
  47  # Common opcode attributes 
  48   
  49  #: output fields for a query operation 
  50  _POutputFields = ("output_fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), 
  51                    "Selected output fields") 
  52   
  53  #: the shutdown timeout 
  54  _PShutdownTimeout = \ 
  55    ("shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TNonNegativeInt, 
  56     "How long to wait for instance to shut down") 
  57   
  58  #: the force parameter 
  59  _PForce = ("force", False, ht.TBool, "Whether to force the operation") 
  60   
  61  #: a required instance name (for single-instance LUs) 
  62  _PInstanceName = ("instance_name", ht.NoDefault, ht.TNonEmptyString, 
  63                    "Instance name") 
  64   
  65  #: a instance UUID (for single-instance LUs) 
  66  _PInstanceUuid = ("instance_uuid", None, ht.TMaybeString, 
  67                    "Instance UUID") 
  68   
  69  #: Whether to ignore offline nodes 
  70  _PIgnoreOfflineNodes = ("ignore_offline_nodes", False, ht.TBool, 
  71                          "Whether to ignore offline nodes") 
  72   
  73  #: a required node name (for single-node LUs) 
  74  _PNodeName = ("node_name", ht.NoDefault, ht.TNonEmptyString, "Node name") 
  75   
  76  #: a node UUID (for use with _PNodeName) 
  77  _PNodeUuid = ("node_uuid", None, ht.TMaybeString, "Node UUID") 
  78   
  79  #: a required node group name (for single-group LUs) 
  80  _PGroupName = ("group_name", ht.NoDefault, ht.TNonEmptyString, "Group name") 
  81   
  82  #: Migration type (live/non-live) 
  83  _PMigrationMode = ("mode", None, 
  84                     ht.TMaybe(ht.TElemOf(constants.HT_MIGRATION_MODES)), 
  85                     "Migration mode") 
  86   
  87  #: Obsolete 'live' migration mode (boolean) 
  88  _PMigrationLive = ("live", None, ht.TMaybeBool, 
  89                     "Legacy setting for live migration, do not use") 
  90   
  91  #: Tag type 
  92  _PTagKind = ("kind", ht.NoDefault, ht.TElemOf(constants.VALID_TAG_TYPES), 
  93               "Tag kind") 
  94   
  95  #: List of tag strings 
  96  _PTags = ("tags", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), 
  97            "List of tag names") 
  98   
  99  _PForceVariant = ("force_variant", False, ht.TBool, 
 100                    "Whether to force an unknown OS variant") 
 101   
 102  _PWaitForSync = ("wait_for_sync", True, ht.TBool, 
 103                   "Whether to wait for the disk to synchronize") 
 104   
 105  _PWaitForSyncFalse = ("wait_for_sync", False, ht.TBool, 
 106                        "Whether to wait for the disk to synchronize" 
 107                        " (defaults to false)") 
 108   
 109  _PIgnoreConsistency = ("ignore_consistency", False, ht.TBool, 
 110                         "Whether to ignore disk consistency") 
 111   
 112  _PStorageName = ("name", ht.NoDefault, ht.TMaybeString, "Storage name") 
 113   
 114  _PUseLocking = ("use_locking", False, ht.TBool, 
 115                  "Whether to use synchronization") 
 116   
 117  _PNameCheck = ("name_check", True, ht.TBool, "Whether to check name") 
 118   
 119  _PNodeGroupAllocPolicy = \ 
 120    ("alloc_policy", None, 
 121     ht.TMaybe(ht.TElemOf(constants.VALID_ALLOC_POLICIES)), 
 122     "Instance allocation policy") 
 123   
 124  _PGroupNodeParams = ("ndparams", None, ht.TMaybeDict, 
 125                       "Default node parameters for group") 
 126   
 127  _PQueryWhat = ("what", ht.NoDefault, ht.TElemOf(constants.QR_VIA_OP), 
 128                 "Resource(s) to query for") 
 129   
 130  _PEarlyRelease = ("early_release", False, ht.TBool, 
 131                    "Whether to release locks as soon as possible") 
 132   
 133  _PIpCheckDoc = "Whether to ensure instance's IP address is inactive" 
 134   
 135  #: Do not remember instance state changes 
 136  _PNoRemember = ("no_remember", False, ht.TBool, 
 137                  "Do not remember the state change") 
 138   
 139  #: Target node for instance migration/failover 
 140  _PMigrationTargetNode = ("target_node", None, ht.TMaybeString, 
 141                           "Target node for shared-storage instances") 
 142   
 143  _PMigrationTargetNodeUuid = ("target_node_uuid", None, ht.TMaybeString, 
 144                               "Target node UUID for shared-storage instances") 
 145   
 146  _PStartupPaused = ("startup_paused", False, ht.TBool, 
 147                     "Pause instance at startup") 
 148   
 149  _PVerbose = ("verbose", False, ht.TBool, "Verbose mode") 
 150   
 151  # Parameters for cluster verification 
 152  _PDebugSimulateErrors = ("debug_simulate_errors", False, ht.TBool, 
 153                           "Whether to simulate errors (useful for debugging)") 
 154  _PErrorCodes = ("error_codes", False, ht.TBool, "Error codes") 
 155  _PSkipChecks = ("skip_checks", ht.EmptyList, 
 156                  ht.TListOf(ht.TElemOf(constants.VERIFY_OPTIONAL_CHECKS)), 
 157                  "Which checks to skip") 
 158  _PIgnoreErrors = ("ignore_errors", ht.EmptyList, 
 159                    ht.TListOf(ht.TElemOf(constants.CV_ALL_ECODES_STRINGS)), 
 160                    "List of error codes that should be treated as warnings") 
 161   
 162  # Disk parameters 
 163  _PDiskParams = \ 
 164    ("diskparams", None, 
 165     ht.TMaybe(ht.TDictOf(ht.TElemOf(constants.DISK_TEMPLATES), ht.TDict)), 
 166     "Disk templates' parameter defaults") 
 167   
 168  # Parameters for node resource model 
 169  _PHvState = ("hv_state", None, ht.TMaybeDict, "Set hypervisor states") 
 170  _PDiskState = ("disk_state", None, ht.TMaybeDict, "Set disk states") 
 171   
 172  #: Opportunistic locking 
 173  _POpportunisticLocking = \ 
 174    ("opportunistic_locking", False, ht.TBool, 
 175     ("Whether to employ opportunistic locking for nodes, meaning nodes" 
 176      " already locked by another opcode won't be considered for instance" 
 177      " allocation (only when an iallocator is used)")) 
 178   
 179  _PIgnoreIpolicy = ("ignore_ipolicy", False, ht.TBool, 
 180                     "Whether to ignore ipolicy violations") 
 181   
 182  # Allow runtime changes while migrating 
 183  _PAllowRuntimeChgs = ("allow_runtime_changes", True, ht.TBool, 
 184                        "Allow runtime changes (eg. memory ballooning)") 
 185   
 186  #: IAllocator field builder 
 187  _PIAllocFromDesc = lambda desc: ("iallocator", None, ht.TMaybeString, desc) 
 188   
 189  #: a required network name 
 190  _PNetworkName = ("network_name", ht.NoDefault, ht.TNonEmptyString, 
 191                   "Set network name") 
 192   
 193  _PTargetGroups = \ 
 194    ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString), 
 195     "Destination group names or UUIDs (defaults to \"all but current group\")") 
 196   
 197  #: OP_ID conversion regular expression 
 198  _OPID_RE = re.compile("([a-z])([A-Z])") 
 199   
 200  #: Utility function for L{OpClusterSetParams} 
 201  _TestClusterOsListItem = \ 
 202    ht.TAnd(ht.TIsLength(2), ht.TItems([ 
 203      ht.TElemOf(constants.DDMS_VALUES), 
 204      ht.TNonEmptyString, 
 205      ])) 
 206   
 207  _TestClusterOsList = ht.TMaybeListOf(_TestClusterOsListItem) 
 208   
 209  # TODO: Generate check from constants.INIC_PARAMS_TYPES 
 210  #: Utility function for testing NIC definitions 
 211  _TestNicDef = \ 
 212    ht.Comment("NIC parameters")(ht.TDictOf(ht.TElemOf(constants.INIC_PARAMS), 
 213                                            ht.TMaybeString)) 
 214   
 215  _TSetParamsResultItemItems = [ 
 216    ht.Comment("name of changed parameter")(ht.TNonEmptyString), 
 217    ht.Comment("new value")(ht.TAny), 
 218    ] 
 219   
 220  _TSetParamsResult = \ 
 221    ht.TListOf(ht.TAnd(ht.TIsLength(len(_TSetParamsResultItemItems)), 
 222                       ht.TItems(_TSetParamsResultItemItems))) 
 223   
 224  # In the disks option we can provide arbitrary parameters too, which 
 225  # we may not be able to validate at this level, so we just check the 
 226  # format of the dict here and the checks concerning IDISK_PARAMS will 
 227  # happen at the LU level 
 228  _TDiskParams = \ 
 229    ht.Comment("Disk parameters")(ht.TDictOf(ht.TNonEmptyString, 
 230                                             ht.TOr(ht.TNonEmptyString, ht.TInt))) 
 231   
 232  _TQueryRow = \ 
 233    ht.TListOf(ht.TAnd(ht.TIsLength(2), 
 234                       ht.TItems([ht.TElemOf(constants.RS_ALL), 
 235                                  ht.TAny]))) 
 236   
 237  _TQueryResult = ht.TListOf(_TQueryRow) 
 238   
 239  _TOldQueryRow = ht.TListOf(ht.TAny) 
 240   
 241  _TOldQueryResult = ht.TListOf(_TOldQueryRow) 
 242   
 243   
 244  _SUMMARY_PREFIX = { 
 245    "CLUSTER_": "C_", 
 246    "GROUP_": "G_", 
 247    "NODE_": "N_", 
 248    "INSTANCE_": "I_", 
 249    } 
 250   
 251  #: Attribute name for dependencies 
 252  DEPEND_ATTR = "depends" 
 253   
 254  #: Attribute name for comment 
 255  COMMENT_ATTR = "comment" 
256 257 258 -def _NameComponents(name):
259 """Split an opcode class name into its components 260 261 @type name: string 262 @param name: the class name, as OpXxxYyy 263 @rtype: array of strings 264 @return: the components of the name 265 266 """ 267 assert name.startswith("Op") 268 # Note: (?<=[a-z])(?=[A-Z]) would be ideal, since it wouldn't 269 # consume any input, and hence we would just have all the elements 270 # in the list, one by one; but it seems that split doesn't work on 271 # non-consuming input, hence we have to process the input string a 272 # bit 273 name = _OPID_RE.sub(r"\1,\2", name) 274 elems = name.split(",") 275 return elems
276
277 278 -def _NameToId(name):
279 """Convert an opcode class name to an OP_ID. 280 281 @type name: string 282 @param name: the class name, as OpXxxYyy 283 @rtype: string 284 @return: the name in the OP_XXXX_YYYY format 285 286 """ 287 if not name.startswith("Op"): 288 return None 289 return "_".join(n.upper() for n in _NameComponents(name))
290
291 292 -def NameToReasonSrc(name):
293 """Convert an opcode class name to a source string for the reason trail 294 295 @type name: string 296 @param name: the class name, as OpXxxYyy 297 @rtype: string 298 @return: the name in the OP_XXXX_YYYY format 299 300 """ 301 if not name.startswith("Op"): 302 return None 303 return "%s:%s" % (constants.OPCODE_REASON_SRC_OPCODE, 304 "_".join(n.lower() for n in _NameComponents(name)))
305
306 307 -def _GenerateObjectTypeCheck(obj, fields_types):
308 """Helper to generate type checks for objects. 309 310 @param obj: The object to generate type checks 311 @param fields_types: The fields and their types as a dict 312 @return: A ht type check function 313 314 """ 315 assert set(obj.GetAllSlots()) == set(fields_types.keys()), \ 316 "%s != %s" % (set(obj.GetAllSlots()), set(fields_types.keys())) 317 return ht.TStrictDict(True, True, fields_types)
318 319 320 _TQueryFieldDef = \ 321 _GenerateObjectTypeCheck(objects.QueryFieldDefinition, { 322 "name": ht.TNonEmptyString, 323 "title": ht.TNonEmptyString, 324 "kind": ht.TElemOf(constants.QFT_ALL), 325 "doc": ht.TNonEmptyString, 326 })
327 328 329 -def _BuildDiskTemplateCheck(accept_none):
330 """Builds check for disk template. 331 332 @type accept_none: bool 333 @param accept_none: whether to accept None as a correct value 334 @rtype: callable 335 336 """ 337 template_check = ht.TElemOf(constants.DISK_TEMPLATES) 338 339 if accept_none: 340 template_check = ht.TMaybe(template_check) 341 342 return template_check
343
344 345 -def _CheckStorageType(storage_type):
346 """Ensure a given storage type is valid. 347 348 """ 349 if storage_type not in constants.STORAGE_TYPES: 350 raise errors.OpPrereqError("Unknown storage type: %s" % storage_type, 351 errors.ECODE_INVAL) 352 return True
353 354 355 #: Storage type parameter 356 _PStorageType = ("storage_type", ht.NoDefault, _CheckStorageType, 357 "Storage type")
358 359 360 @ht.WithDesc("IPv4 network") 361 -def _CheckCIDRNetNotation(value):
362 """Ensure a given CIDR notation type is valid. 363 364 """ 365 try: 366 ipaddr.IPv4Network(value) 367 except ipaddr.AddressValueError: 368 return False 369 return True
370
371 372 @ht.WithDesc("IPv4 address") 373 -def _CheckCIDRAddrNotation(value):
374 """Ensure a given CIDR notation type is valid. 375 376 """ 377 try: 378 ipaddr.IPv4Address(value) 379 except ipaddr.AddressValueError: 380 return False 381 return True
382
383 384 @ht.WithDesc("IPv6 address") 385 -def _CheckCIDR6AddrNotation(value):
386 """Ensure a given CIDR notation type is valid. 387 388 """ 389 try: 390 ipaddr.IPv6Address(value) 391 except ipaddr.AddressValueError: 392 return False 393 return True
394
395 396 @ht.WithDesc("IPv6 network") 397 -def _CheckCIDR6NetNotation(value):
398 """Ensure a given CIDR notation type is valid. 399 400 """ 401 try: 402 ipaddr.IPv6Network(value) 403 except ipaddr.AddressValueError: 404 return False 405 return True
406 407 408 _TIpAddress4 = ht.TAnd(ht.TString, _CheckCIDRAddrNotation) 409 _TIpAddress6 = ht.TAnd(ht.TString, _CheckCIDR6AddrNotation) 410 _TIpNetwork4 = ht.TAnd(ht.TString, _CheckCIDRNetNotation) 411 _TIpNetwork6 = ht.TAnd(ht.TString, _CheckCIDR6NetNotation) 412 _TMaybeAddr4List = ht.TMaybe(ht.TListOf(_TIpAddress4))
413 414 415 -class _AutoOpParamSlots(outils.AutoSlots):
416 """Meta class for opcode definitions. 417 418 """
419 - def __new__(mcs, name, bases, attrs):
420 """Called when a class should be created. 421 422 @param mcs: The meta class 423 @param name: Name of created class 424 @param bases: Base classes 425 @type attrs: dict 426 @param attrs: Class attributes 427 428 """ 429 assert "OP_ID" not in attrs, "Class '%s' defining OP_ID" % name 430 431 slots = mcs._GetSlots(attrs) 432 assert "OP_DSC_FIELD" not in attrs or attrs["OP_DSC_FIELD"] in slots, \ 433 "Class '%s' uses unknown field in OP_DSC_FIELD" % name 434 assert ("OP_DSC_FORMATTER" not in attrs or 435 callable(attrs["OP_DSC_FORMATTER"])), \ 436 ("Class '%s' uses non-callable in OP_DSC_FORMATTER (%s)" % 437 (name, type(attrs["OP_DSC_FORMATTER"]))) 438 439 attrs["OP_ID"] = _NameToId(name) 440 441 return outils.AutoSlots.__new__(mcs, name, bases, attrs)
442 443 @classmethod
444 - def _GetSlots(mcs, attrs):
445 """Build the slots out of OP_PARAMS. 446 447 """ 448 # Always set OP_PARAMS to avoid duplicates in BaseOpCode.GetAllParams 449 params = attrs.setdefault("OP_PARAMS", []) 450 451 # Use parameter names as slots 452 return [pname for (pname, _, _, _) in params]
453
454 455 -class BaseOpCode(outils.ValidatedSlots):
456 """A simple serializable object. 457 458 This object serves as a parent class for OpCode without any custom 459 field handling. 460 461 """ 462 # pylint: disable=E1101 463 # as OP_ID is dynamically defined 464 __metaclass__ = _AutoOpParamSlots 465
466 - def __getstate__(self):
467 """Generic serializer. 468 469 This method just returns the contents of the instance as a 470 dictionary. 471 472 @rtype: C{dict} 473 @return: the instance attributes and their values 474 475 """ 476 state = {} 477 for name in self.GetAllSlots(): 478 if hasattr(self, name): 479 state[name] = getattr(self, name) 480 return state
481
482 - def __setstate__(self, state):
483 """Generic unserializer. 484 485 This method just restores from the serialized state the attributes 486 of the current instance. 487 488 @param state: the serialized opcode data 489 @type state: C{dict} 490 491 """ 492 if not isinstance(state, dict): 493 raise ValueError("Invalid data to __setstate__: expected dict, got %s" % 494 type(state)) 495 496 for name in self.GetAllSlots(): 497 if name not in state and hasattr(self, name): 498 delattr(self, name) 499 500 for name in state: 501 setattr(self, name, state[name])
502 503 @classmethod
504 - def GetAllParams(cls):
505 """Compute list of all parameters for an opcode. 506 507 """ 508 slots = [] 509 for parent in cls.__mro__: 510 slots.extend(getattr(parent, "OP_PARAMS", [])) 511 return slots
512
513 - def Validate(self, set_defaults): # pylint: disable=W0221
514 """Validate opcode parameters, optionally setting default values. 515 516 @type set_defaults: bool 517 @param set_defaults: Whether to set default values 518 @raise errors.OpPrereqError: When a parameter value doesn't match 519 requirements 520 521 """ 522 for (attr_name, default, test, _) in self.GetAllParams(): 523 assert test == ht.NoType or callable(test) 524 525 if not hasattr(self, attr_name): 526 if default == ht.NoDefault: 527 raise errors.OpPrereqError("Required parameter '%s.%s' missing" % 528 (self.OP_ID, attr_name), 529 errors.ECODE_INVAL) 530 elif set_defaults: 531 if callable(default): 532 dval = default() 533 else: 534 dval = default 535 setattr(self, attr_name, dval) 536 537 if test == ht.NoType: 538 # no tests here 539 continue 540 541 if set_defaults or hasattr(self, attr_name): 542 attr_val = getattr(self, attr_name) 543 if not test(attr_val): 544 logging.error("OpCode %s, parameter %s, has invalid type %s/value" 545 " '%s' expecting type %s", 546 self.OP_ID, attr_name, type(attr_val), attr_val, test) 547 raise errors.OpPrereqError("Parameter '%s.%s' fails validation" % 548 (self.OP_ID, attr_name), 549 errors.ECODE_INVAL)
550
551 552 -def _BuildJobDepCheck(relative):
553 """Builds check for job dependencies (L{DEPEND_ATTR}). 554 555 @type relative: bool 556 @param relative: Whether to accept relative job IDs (negative) 557 @rtype: callable 558 559 """ 560 if relative: 561 job_id = ht.TOr(ht.TJobId, ht.TRelativeJobId) 562 else: 563 job_id = ht.TJobId 564 565 job_dep = \ 566 ht.TAnd(ht.TOr(ht.TList, ht.TTuple), 567 ht.TIsLength(2), 568 ht.TItems([job_id, 569 ht.TListOf(ht.TElemOf(constants.JOBS_FINALIZED))])) 570 571 return ht.TMaybeListOf(job_dep)
572 573 574 TNoRelativeJobDependencies = _BuildJobDepCheck(False) 575 576 #: List of submission status and job ID as returned by C{SubmitManyJobs} 577 _TJobIdListItem = \ 578 ht.TAnd(ht.TIsLength(2), 579 ht.TItems([ht.Comment("success")(ht.TBool), 580 ht.Comment("Job ID if successful, error message" 581 " otherwise")(ht.TOr(ht.TString, 582 ht.TJobId))])) 583 TJobIdList = ht.TListOf(_TJobIdListItem) 584 585 #: Result containing only list of submitted jobs 586 TJobIdListOnly = ht.TStrictDict(True, True, { 587 constants.JOB_IDS_KEY: ht.Comment("List of submitted jobs")(TJobIdList), 588 })
589 590 591 -class OpCode(BaseOpCode):
592 """Abstract OpCode. 593 594 This is the root of the actual OpCode hierarchy. All clases derived 595 from this class should override OP_ID. 596 597 @cvar OP_ID: The ID of this opcode. This should be unique amongst all 598 children of this class. 599 @cvar OP_DSC_FIELD: The name of a field whose value will be included in the 600 string returned by Summary(); see the docstring of that 601 method for details). 602 @cvar OP_DSC_FORMATTER: A callable that should format the OP_DSC_FIELD; if 603 not present, then the field will be simply converted 604 to string 605 @cvar OP_PARAMS: List of opcode attributes, the default values they should 606 get if not already defined, and types they must match. 607 @cvar OP_RESULT: Callable to verify opcode result 608 @cvar WITH_LU: Boolean that specifies whether this should be included in 609 mcpu's dispatch table 610 @ivar dry_run: Whether the LU should be run in dry-run mode, i.e. just 611 the check steps 612 @ivar priority: Opcode priority for queue 613 614 """ 615 # pylint: disable=E1101 616 # as OP_ID is dynamically defined 617 WITH_LU = True 618 OP_PARAMS = [ 619 ("dry_run", None, ht.TMaybeBool, "Run checks only, don't execute"), 620 ("debug_level", None, ht.TMaybe(ht.TNonNegativeInt), "Debug level"), 621 ("priority", constants.OP_PRIO_DEFAULT, 622 ht.TElemOf(constants.OP_PRIO_SUBMIT_VALID), "Opcode priority"), 623 (DEPEND_ATTR, None, _BuildJobDepCheck(True), 624 "Job dependencies; if used through ``SubmitManyJobs`` relative (negative)" 625 " job IDs can be used; see :doc:`design document <design-chained-jobs>`" 626 " for details"), 627 (COMMENT_ATTR, None, ht.TMaybeString, 628 "Comment describing the purpose of the opcode"), 629 (constants.OPCODE_REASON, ht.EmptyList, ht.TMaybeList, 630 "The reason trail, describing why the OpCode is executed"), 631 ] 632 OP_RESULT = None 633
634 - def __getstate__(self):
635 """Specialized getstate for opcodes. 636 637 This method adds to the state dictionary the OP_ID of the class, 638 so that on unload we can identify the correct class for 639 instantiating the opcode. 640 641 @rtype: C{dict} 642 @return: the state as a dictionary 643 644 """ 645 data = BaseOpCode.__getstate__(self) 646 data["OP_ID"] = self.OP_ID 647 return data
648 649 @classmethod
650 - def LoadOpCode(cls, data):
651 """Generic load opcode method. 652 653 The method identifies the correct opcode class from the dict-form 654 by looking for a OP_ID key, if this is not found, or its value is 655 not available in this module as a child of this class, we fail. 656 657 @type data: C{dict} 658 @param data: the serialized opcode 659 660 """ 661 if not isinstance(data, dict): 662 raise ValueError("Invalid data to LoadOpCode (%s)" % type(data)) 663 if "OP_ID" not in data: 664 raise ValueError("Invalid data to LoadOpcode, missing OP_ID") 665 op_id = data["OP_ID"] 666 op_class = None 667 if op_id in OP_MAPPING: 668 op_class = OP_MAPPING[op_id] 669 else: 670 raise ValueError("Invalid data to LoadOpCode: OP_ID %s unsupported" % 671 op_id) 672 op = op_class() 673 new_data = data.copy() 674 del new_data["OP_ID"] 675 op.__setstate__(new_data) 676 return op
677
678 - def Summary(self):
679 """Generates a summary description of this opcode. 680 681 The summary is the value of the OP_ID attribute (without the "OP_" 682 prefix), plus the value of the OP_DSC_FIELD attribute, if one was 683 defined; this field should allow to easily identify the operation 684 (for an instance creation job, e.g., it would be the instance 685 name). 686 687 """ 688 assert self.OP_ID is not None and len(self.OP_ID) > 3 689 # all OP_ID start with OP_, we remove that 690 txt = self.OP_ID[3:] 691 field_name = getattr(self, "OP_DSC_FIELD", None) 692 if field_name: 693 field_value = getattr(self, field_name, None) 694 field_formatter = getattr(self, "OP_DSC_FORMATTER", None) 695 if callable(field_formatter): 696 field_value = field_formatter(field_value) 697 elif isinstance(field_value, (list, tuple)): 698 field_value = ",".join(str(i) for i in field_value) 699 txt = "%s(%s)" % (txt, field_value) 700 return txt
701
702 - def TinySummary(self):
703 """Generates a compact summary description of the opcode. 704 705 """ 706 assert self.OP_ID.startswith("OP_") 707 708 text = self.OP_ID[3:] 709 710 for (prefix, supplement) in _SUMMARY_PREFIX.items(): 711 if text.startswith(prefix): 712 return supplement + text[len(prefix):] 713 714 return text
715
716 717 # cluster opcodes 718 719 -class OpClusterPostInit(OpCode):
720 """Post cluster initialization. 721 722 This opcode does not touch the cluster at all. Its purpose is to run hooks 723 after the cluster has been initialized. 724 725 """ 726 OP_RESULT = ht.TBool
727
728 729 -class OpClusterDestroy(OpCode):
730 """Destroy the cluster. 731 732 This opcode has no other parameters. All the state is irreversibly 733 lost after the execution of this opcode. 734 735 """ 736 OP_RESULT = ht.TNonEmptyString
737
738 739 -class OpClusterQuery(OpCode):
740 """Query cluster information.""" 741 OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TAny)
742
743 744 -class OpClusterVerify(OpCode):
745 """Submits all jobs necessary to verify the cluster. 746 747 """ 748 OP_PARAMS = [ 749 _PDebugSimulateErrors, 750 _PErrorCodes, 751 _PSkipChecks, 752 _PIgnoreErrors, 753 _PVerbose, 754 ("group_name", None, ht.TMaybeString, "Group to verify"), 755 ] 756 OP_RESULT = TJobIdListOnly
757
758 759 -class OpClusterVerifyConfig(OpCode):
760 """Verify the cluster config. 761 762 """ 763 OP_PARAMS = [ 764 _PDebugSimulateErrors, 765 _PErrorCodes, 766 _PIgnoreErrors, 767 _PVerbose, 768 ] 769 OP_RESULT = ht.TBool
770
771 772 -class OpClusterVerifyGroup(OpCode):
773 """Run verify on a node group from the cluster. 774 775 @type skip_checks: C{list} 776 @ivar skip_checks: steps to be skipped from the verify process; this 777 needs to be a subset of 778 L{constants.VERIFY_OPTIONAL_CHECKS}; currently 779 only L{constants.VERIFY_NPLUSONE_MEM} can be passed 780 781 """ 782 OP_DSC_FIELD = "group_name" 783 OP_PARAMS = [ 784 _PGroupName, 785 _PDebugSimulateErrors, 786 _PErrorCodes, 787 _PSkipChecks, 788 _PIgnoreErrors, 789 _PVerbose, 790 ] 791 OP_RESULT = ht.TBool
792
793 794 -class OpClusterVerifyDisks(OpCode):
795 """Verify the cluster disks. 796 797 """ 798 OP_RESULT = TJobIdListOnly
799
800 801 -class OpGroupVerifyDisks(OpCode):
802 """Verifies the status of all disks in a node group. 803 804 Result: a tuple of three elements: 805 - dict of node names with issues (values: error msg) 806 - list of instances with degraded disks (that should be activated) 807 - dict of instances with missing logical volumes (values: (node, vol) 808 pairs with details about the missing volumes) 809 810 In normal operation, all lists should be empty. A non-empty instance 811 list (3rd element of the result) is still ok (errors were fixed) but 812 non-empty node list means some node is down, and probably there are 813 unfixable drbd errors. 814 815 Note that only instances that are drbd-based are taken into 816 consideration. This might need to be revisited in the future. 817 818 """ 819 OP_DSC_FIELD = "group_name" 820 OP_PARAMS = [ 821 _PGroupName, 822 ] 823 OP_RESULT = \ 824 ht.TAnd(ht.TIsLength(3), 825 ht.TItems([ht.TDictOf(ht.TString, ht.TString), 826 ht.TListOf(ht.TString), 827 ht.TDictOf(ht.TString, 828 ht.TListOf(ht.TListOf(ht.TString)))]))
829
830 831 -class OpClusterRepairDiskSizes(OpCode):
832 """Verify the disk sizes of the instances and fixes configuration 833 mimatches. 834 835 Parameters: optional instances list, in case we want to restrict the 836 checks to only a subset of the instances. 837 838 Result: a list of tuples, (instance, disk, parameter, new-size) for changed 839 configurations. 840 841 In normal operation, the list should be empty. 842 843 @type instances: list 844 @ivar instances: the list of instances to check, or empty for all instances 845 846 """ 847 OP_PARAMS = [ 848 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), 849 ] 850 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(4), 851 ht.TItems([ht.TNonEmptyString, 852 ht.TNonNegativeInt, 853 ht.TNonEmptyString, 854 ht.TNonNegativeInt])))
855
856 857 -class OpClusterConfigQuery(OpCode):
858 """Query cluster configuration values.""" 859 OP_PARAMS = [ 860 _POutputFields, 861 ] 862 OP_RESULT = ht.TListOf(ht.TAny)
863
864 865 -class OpClusterRename(OpCode):
866 """Rename the cluster. 867 868 @type name: C{str} 869 @ivar name: The new name of the cluster. The name and/or the master IP 870 address will be changed to match the new name and its IP 871 address. 872 873 """ 874 OP_DSC_FIELD = "name" 875 OP_PARAMS = [ 876 ("name", ht.NoDefault, ht.TNonEmptyString, None), 877 ] 878 OP_RESULT = ht.TNonEmptyString
879
880 881 -class OpClusterSetParams(OpCode):
882 """Change the parameters of the cluster. 883 884 @type vg_name: C{str} or C{None} 885 @ivar vg_name: The new volume group name or None to disable LVM usage. 886 887 """ 888 OP_PARAMS = [ 889 _PForce, 890 _PHvState, 891 _PDiskState, 892 ("vg_name", None, ht.TMaybe(ht.TString), "Volume group name"), 893 ("enabled_hypervisors", None, 894 ht.TMaybe(ht.TAnd(ht.TListOf(ht.TElemOf(constants.HYPER_TYPES)), 895 ht.TTrue)), 896 "List of enabled hypervisors"), 897 ("hvparams", None, 898 ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)), 899 "Cluster-wide hypervisor parameter defaults, hypervisor-dependent"), 900 ("beparams", None, ht.TMaybeDict, 901 "Cluster-wide backend parameter defaults"), 902 ("os_hvp", None, ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)), 903 "Cluster-wide per-OS hypervisor parameter defaults"), 904 ("osparams", None, 905 ht.TMaybe(ht.TDictOf(ht.TNonEmptyString, ht.TDict)), 906 "Cluster-wide OS parameter defaults"), 907 _PDiskParams, 908 ("candidate_pool_size", None, ht.TMaybe(ht.TPositiveInt), 909 "Master candidate pool size"), 910 ("uid_pool", None, ht.NoType, 911 "Set UID pool, must be list of lists describing UID ranges (two items," 912 " start and end inclusive)"), 913 ("add_uids", None, ht.NoType, 914 "Extend UID pool, must be list of lists describing UID ranges (two" 915 " items, start and end inclusive) to be added"), 916 ("remove_uids", None, ht.NoType, 917 "Shrink UID pool, must be list of lists describing UID ranges (two" 918 " items, start and end inclusive) to be removed"), 919 ("maintain_node_health", None, ht.TMaybeBool, 920 "Whether to automatically maintain node health"), 921 ("prealloc_wipe_disks", None, ht.TMaybeBool, 922 "Whether to wipe disks before allocating them to instances"), 923 ("nicparams", None, ht.TMaybeDict, "Cluster-wide NIC parameter defaults"), 924 ("ndparams", None, ht.TMaybeDict, "Cluster-wide node parameter defaults"), 925 ("ipolicy", None, ht.TMaybeDict, 926 "Cluster-wide :ref:`instance policy <rapi-ipolicy>` specs"), 927 ("drbd_helper", None, ht.TMaybe(ht.TString), "DRBD helper program"), 928 ("default_iallocator", None, ht.TMaybe(ht.TString), 929 "Default iallocator for cluster"), 930 ("master_netdev", None, ht.TMaybe(ht.TString), 931 "Master network device"), 932 ("master_netmask", None, ht.TMaybe(ht.TNonNegativeInt), 933 "Netmask of the master IP"), 934 ("reserved_lvs", None, ht.TMaybeListOf(ht.TNonEmptyString), 935 "List of reserved LVs"), 936 ("hidden_os", None, _TestClusterOsList, 937 "Modify list of hidden operating systems: each modification must have" 938 " two items, the operation and the OS name; the operation can be" 939 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)), 940 ("blacklisted_os", None, _TestClusterOsList, 941 "Modify list of blacklisted operating systems: each modification must" 942 " have two items, the operation and the OS name; the operation can be" 943 " ``%s`` or ``%s``" % (constants.DDM_ADD, constants.DDM_REMOVE)), 944 ("use_external_mip_script", None, ht.TMaybeBool, 945 "Whether to use an external master IP address setup script"), 946 ("enabled_disk_templates", None, 947 ht.TMaybe(ht.TAnd(ht.TListOf(ht.TElemOf(constants.DISK_TEMPLATES)), 948 ht.TTrue)), 949 "List of enabled disk templates"), 950 ("modify_etc_hosts", None, ht.TMaybeBool, 951 "Whether the cluster can modify and keep in sync the /etc/hosts files"), 952 ("file_storage_dir", None, ht.TMaybe(ht.TString), 953 "Default directory for storing file-backed disks"), 954 ("shared_file_storage_dir", None, ht.TMaybe(ht.TString), 955 "Default directory for storing shared-file-backed disks"), 956 ] 957 OP_RESULT = ht.TNone
958
959 960 -class OpClusterRedistConf(OpCode):
961 """Force a full push of the cluster configuration. 962 963 """ 964 OP_RESULT = ht.TNone
965
966 967 -class OpClusterActivateMasterIp(OpCode):
968 """Activate the master IP on the master node. 969 970 """ 971 OP_RESULT = ht.TNone
972
973 974 -class OpClusterDeactivateMasterIp(OpCode):
975 """Deactivate the master IP on the master node. 976 977 """ 978 OP_RESULT = ht.TNone
979
980 981 -class OpQuery(OpCode):
982 """Query for resources/items. 983 984 @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP} 985 @ivar fields: List of fields to retrieve 986 @ivar qfilter: Query filter 987 988 """ 989 OP_DSC_FIELD = "what" 990 OP_PARAMS = [ 991 _PQueryWhat, 992 _PUseLocking, 993 ("fields", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), 994 "Requested fields"), 995 ("qfilter", None, ht.TMaybe(ht.TList), 996 "Query filter"), 997 ] 998 OP_RESULT = \ 999 _GenerateObjectTypeCheck(objects.QueryResponse, { 1000 "fields": ht.TListOf(_TQueryFieldDef), 1001 "data": _TQueryResult, 1002 })
1003
1004 1005 -class OpQueryFields(OpCode):
1006 """Query for available resource/item fields. 1007 1008 @ivar what: Resources to query for, must be one of L{constants.QR_VIA_OP} 1009 @ivar fields: List of fields to retrieve 1010 1011 """ 1012 OP_DSC_FIELD = "what" 1013 OP_PARAMS = [ 1014 _PQueryWhat, 1015 ("fields", None, ht.TMaybeListOf(ht.TNonEmptyString), 1016 "Requested fields; if not given, all are returned"), 1017 ] 1018 OP_RESULT = \ 1019 _GenerateObjectTypeCheck(objects.QueryFieldsResponse, { 1020 "fields": ht.TListOf(_TQueryFieldDef), 1021 })
1022
1023 1024 -class OpOobCommand(OpCode):
1025 """Interact with OOB.""" 1026 OP_PARAMS = [ 1027 ("node_names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1028 "List of node names to run the OOB command against"), 1029 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString), 1030 "List of node UUIDs to run the OOB command against"), 1031 ("command", ht.NoDefault, ht.TElemOf(constants.OOB_COMMANDS), 1032 "OOB command to be run"), 1033 ("timeout", constants.OOB_TIMEOUT, ht.TInt, 1034 "Timeout before the OOB helper will be terminated"), 1035 ("ignore_status", False, ht.TBool, 1036 "Ignores the node offline status for power off"), 1037 ("power_delay", constants.OOB_POWER_DELAY, ht.TNonNegativeFloat, 1038 "Time in seconds to wait between powering on nodes"), 1039 ] 1040 # Fixme: Make it more specific with all the special cases in LUOobCommand 1041 OP_RESULT = _TQueryResult
1042
1043 1044 -class OpRestrictedCommand(OpCode):
1045 """Runs a restricted command on node(s). 1046 1047 """ 1048 OP_PARAMS = [ 1049 _PUseLocking, 1050 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), 1051 "Nodes on which the command should be run (at least one)"), 1052 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString), 1053 "Node UUIDs on which the command should be run (at least one)"), 1054 ("command", ht.NoDefault, ht.TNonEmptyString, 1055 "Command name (no parameters)"), 1056 ] 1057 1058 _RESULT_ITEMS = [ 1059 ht.Comment("success")(ht.TBool), 1060 ht.Comment("output or error message")(ht.TString), 1061 ] 1062 1063 OP_RESULT = \ 1064 ht.TListOf(ht.TAnd(ht.TIsLength(len(_RESULT_ITEMS)), 1065 ht.TItems(_RESULT_ITEMS)))
1066
1067 1068 # node opcodes 1069 1070 -class OpNodeRemove(OpCode):
1071 """Remove a node. 1072 1073 @type node_name: C{str} 1074 @ivar node_name: The name of the node to remove. If the node still has 1075 instances on it, the operation will fail. 1076 1077 """ 1078 OP_DSC_FIELD = "node_name" 1079 OP_PARAMS = [ 1080 _PNodeName, 1081 _PNodeUuid 1082 ] 1083 OP_RESULT = ht.TNone
1084
1085 1086 -class OpNodeAdd(OpCode):
1087 """Add a node to the cluster. 1088 1089 @type node_name: C{str} 1090 @ivar node_name: The name of the node to add. This can be a short name, 1091 but it will be expanded to the FQDN. 1092 @type primary_ip: IP address 1093 @ivar primary_ip: The primary IP of the node. This will be ignored when the 1094 opcode is submitted, but will be filled during the node 1095 add (so it will be visible in the job query). 1096 @type secondary_ip: IP address 1097 @ivar secondary_ip: The secondary IP of the node. This needs to be passed 1098 if the cluster has been initialized in 'dual-network' 1099 mode, otherwise it must not be given. 1100 @type readd: C{bool} 1101 @ivar readd: Whether to re-add an existing node to the cluster. If 1102 this is not passed, then the operation will abort if the node 1103 name is already in the cluster; use this parameter to 'repair' 1104 a node that had its configuration broken, or was reinstalled 1105 without removal from the cluster. 1106 @type group: C{str} 1107 @ivar group: The node group to which this node will belong. 1108 @type vm_capable: C{bool} 1109 @ivar vm_capable: The vm_capable node attribute 1110 @type master_capable: C{bool} 1111 @ivar master_capable: The master_capable node attribute 1112 1113 """ 1114 OP_DSC_FIELD = "node_name" 1115 OP_PARAMS = [ 1116 _PNodeName, 1117 _PHvState, 1118 _PDiskState, 1119 ("primary_ip", None, ht.NoType, "Primary IP address"), 1120 ("secondary_ip", None, ht.TMaybeString, "Secondary IP address"), 1121 ("readd", False, ht.TBool, "Whether node is re-added to cluster"), 1122 ("group", None, ht.TMaybeString, "Initial node group"), 1123 ("master_capable", None, ht.TMaybeBool, 1124 "Whether node can become master or master candidate"), 1125 ("vm_capable", None, ht.TMaybeBool, 1126 "Whether node can host instances"), 1127 ("ndparams", None, ht.TMaybeDict, "Node parameters"), 1128 ] 1129 OP_RESULT = ht.TNone
1130
1131 1132 -class OpNodeQuery(OpCode):
1133 """Compute the list of nodes.""" 1134 OP_PARAMS = [ 1135 _POutputFields, 1136 _PUseLocking, 1137 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1138 "Empty list to query all nodes, node names otherwise"), 1139 ] 1140 OP_RESULT = _TOldQueryResult
1141
1142 1143 -class OpNodeQueryvols(OpCode):
1144 """Get list of volumes on node.""" 1145 OP_PARAMS = [ 1146 _POutputFields, 1147 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1148 "Empty list to query all nodes, node names otherwise"), 1149 ] 1150 OP_RESULT = ht.TListOf(ht.TAny)
1151
1152 1153 -class OpNodeQueryStorage(OpCode):
1154 """Get information on storage for node(s).""" 1155 OP_PARAMS = [ 1156 _POutputFields, 1157 _PStorageType, 1158 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "List of nodes"), 1159 ("name", None, ht.TMaybeString, "Storage name"), 1160 ] 1161 OP_RESULT = _TOldQueryResult
1162
1163 1164 -class OpNodeModifyStorage(OpCode):
1165 """Modifies the properies of a storage unit""" 1166 OP_DSC_FIELD = "node_name" 1167 OP_PARAMS = [ 1168 _PNodeName, 1169 _PNodeUuid, 1170 _PStorageType, 1171 _PStorageName, 1172 ("changes", ht.NoDefault, ht.TDict, "Requested changes"), 1173 ] 1174 OP_RESULT = ht.TNone
1175
1176 1177 -class OpRepairNodeStorage(OpCode):
1178 """Repairs the volume group on a node.""" 1179 OP_DSC_FIELD = "node_name" 1180 OP_PARAMS = [ 1181 _PNodeName, 1182 _PNodeUuid, 1183 _PStorageType, 1184 _PStorageName, 1185 _PIgnoreConsistency, 1186 ] 1187 OP_RESULT = ht.TNone
1188
1189 1190 -class OpNodeSetParams(OpCode):
1191 """Change the parameters of a node.""" 1192 OP_DSC_FIELD = "node_name" 1193 OP_PARAMS = [ 1194 _PNodeName, 1195 _PNodeUuid, 1196 _PForce, 1197 _PHvState, 1198 _PDiskState, 1199 ("master_candidate", None, ht.TMaybeBool, 1200 "Whether the node should become a master candidate"), 1201 ("offline", None, ht.TMaybeBool, 1202 "Whether the node should be marked as offline"), 1203 ("drained", None, ht.TMaybeBool, 1204 "Whether the node should be marked as drained"), 1205 ("auto_promote", False, ht.TBool, 1206 "Whether node(s) should be promoted to master candidate if necessary"), 1207 ("master_capable", None, ht.TMaybeBool, 1208 "Denote whether node can become master or master candidate"), 1209 ("vm_capable", None, ht.TMaybeBool, 1210 "Denote whether node can host instances"), 1211 ("secondary_ip", None, ht.TMaybeString, 1212 "Change node's secondary IP address"), 1213 ("ndparams", None, ht.TMaybeDict, "Set node parameters"), 1214 ("powered", None, ht.TMaybeBool, 1215 "Whether the node should be marked as powered"), 1216 ] 1217 OP_RESULT = _TSetParamsResult
1218
1219 1220 -class OpNodePowercycle(OpCode):
1221 """Tries to powercycle a node.""" 1222 OP_DSC_FIELD = "node_name" 1223 OP_PARAMS = [ 1224 _PNodeName, 1225 _PNodeUuid, 1226 _PForce, 1227 ] 1228 OP_RESULT = ht.TMaybeString
1229
1230 1231 -class OpNodeMigrate(OpCode):
1232 """Migrate all instances from a node.""" 1233 OP_DSC_FIELD = "node_name" 1234 OP_PARAMS = [ 1235 _PNodeName, 1236 _PNodeUuid, 1237 _PMigrationMode, 1238 _PMigrationLive, 1239 _PMigrationTargetNode, 1240 _PMigrationTargetNodeUuid, 1241 _PAllowRuntimeChgs, 1242 _PIgnoreIpolicy, 1243 _PIAllocFromDesc("Iallocator for deciding the target node" 1244 " for shared-storage instances"), 1245 ] 1246 OP_RESULT = TJobIdListOnly
1247
1248 1249 -class OpNodeEvacuate(OpCode):
1250 """Evacuate instances off a number of nodes.""" 1251 OP_DSC_FIELD = "node_name" 1252 OP_PARAMS = [ 1253 _PEarlyRelease, 1254 _PNodeName, 1255 _PNodeUuid, 1256 ("remote_node", None, ht.TMaybeString, "New secondary node"), 1257 ("remote_node_uuid", None, ht.TMaybeString, "New secondary node UUID"), 1258 _PIAllocFromDesc("Iallocator for computing solution"), 1259 ("mode", ht.NoDefault, ht.TElemOf(constants.NODE_EVAC_MODES), 1260 "Node evacuation mode"), 1261 ] 1262 OP_RESULT = TJobIdListOnly
1263
1264 1265 # instance opcodes 1266 1267 -class OpInstanceCreate(OpCode):
1268 """Create an instance. 1269 1270 @ivar instance_name: Instance name 1271 @ivar mode: Instance creation mode (one of L{constants.INSTANCE_CREATE_MODES}) 1272 @ivar source_handshake: Signed handshake from source (remote import only) 1273 @ivar source_x509_ca: Source X509 CA in PEM format (remote import only) 1274 @ivar source_instance_name: Previous name of instance (remote import only) 1275 @ivar source_shutdown_timeout: Shutdown timeout used for source instance 1276 (remote import only) 1277 1278 """ 1279 OP_DSC_FIELD = "instance_name" 1280 OP_PARAMS = [ 1281 _PInstanceName, 1282 _PForceVariant, 1283 _PWaitForSync, 1284 _PNameCheck, 1285 _PIgnoreIpolicy, 1286 _POpportunisticLocking, 1287 ("beparams", ht.EmptyDict, ht.TDict, "Backend parameters for instance"), 1288 ("disks", ht.NoDefault, ht.TListOf(_TDiskParams), 1289 "Disk descriptions, for example ``[{\"%s\": 100}, {\"%s\": 5}]``;" 1290 " each disk definition must contain a ``%s`` value and" 1291 " can contain an optional ``%s`` value denoting the disk access mode" 1292 " (%s)" % 1293 (constants.IDISK_SIZE, constants.IDISK_SIZE, constants.IDISK_SIZE, 1294 constants.IDISK_MODE, 1295 " or ".join("``%s``" % i for i in sorted(constants.DISK_ACCESS_SET)))), 1296 ("disk_template", ht.NoDefault, _BuildDiskTemplateCheck(True), 1297 "Disk template"), 1298 ("file_driver", None, ht.TMaybe(ht.TElemOf(constants.FILE_DRIVER)), 1299 "Driver for file-backed disks"), 1300 ("file_storage_dir", None, ht.TMaybeString, 1301 "Directory for storing file-backed disks"), 1302 ("hvparams", ht.EmptyDict, ht.TDict, 1303 "Hypervisor parameters for instance, hypervisor-dependent"), 1304 ("hypervisor", None, ht.TMaybeString, "Hypervisor"), 1305 _PIAllocFromDesc("Iallocator for deciding which node(s) to use"), 1306 ("identify_defaults", False, ht.TBool, 1307 "Reset instance parameters to default if equal"), 1308 ("ip_check", True, ht.TBool, _PIpCheckDoc), 1309 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"), 1310 ("mode", ht.NoDefault, ht.TElemOf(constants.INSTANCE_CREATE_MODES), 1311 "Instance creation mode"), 1312 ("nics", ht.NoDefault, ht.TListOf(_TestNicDef), 1313 "List of NIC (network interface) definitions, for example" 1314 " ``[{}, {}, {\"%s\": \"198.51.100.4\"}]``; each NIC definition can" 1315 " contain the optional values %s" % 1316 (constants.INIC_IP, 1317 ", ".join("``%s``" % i for i in sorted(constants.INIC_PARAMS)))), 1318 ("no_install", None, ht.TMaybeBool, 1319 "Do not install the OS (will disable automatic start)"), 1320 ("osparams", ht.EmptyDict, ht.TDict, "OS parameters for instance"), 1321 ("os_type", None, ht.TMaybeString, "Operating system"), 1322 ("pnode", None, ht.TMaybeString, "Primary node"), 1323 ("pnode_uuid", None, ht.TMaybeString, "Primary node UUID"), 1324 ("snode", None, ht.TMaybeString, "Secondary node"), 1325 ("snode_uuid", None, ht.TMaybeString, "Secondary node UUID"), 1326 ("source_handshake", None, ht.TMaybe(ht.TList), 1327 "Signed handshake from source (remote import only)"), 1328 ("source_instance_name", None, ht.TMaybeString, 1329 "Source instance name (remote import only)"), 1330 ("source_shutdown_timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, 1331 ht.TNonNegativeInt, 1332 "How long source instance was given to shut down (remote import only)"), 1333 ("source_x509_ca", None, ht.TMaybeString, 1334 "Source X509 CA in PEM format (remote import only)"), 1335 ("src_node", None, ht.TMaybeString, "Source node for import"), 1336 ("src_node_uuid", None, ht.TMaybeString, "Source node UUID for import"), 1337 ("src_path", None, ht.TMaybeString, "Source directory for import"), 1338 ("start", True, ht.TBool, "Whether to start instance after creation"), 1339 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Instance tags"), 1340 ] 1341 OP_RESULT = ht.Comment("instance nodes")(ht.TListOf(ht.TNonEmptyString))
1342
1343 1344 -class OpInstanceMultiAlloc(OpCode):
1345 """Allocates multiple instances. 1346 1347 """ 1348 OP_PARAMS = [ 1349 _POpportunisticLocking, 1350 _PIAllocFromDesc("Iallocator used to allocate all the instances"), 1351 ("instances", ht.EmptyList, ht.TListOf(ht.TInstanceOf(OpInstanceCreate)), 1352 "List of instance create opcodes describing the instances to allocate"), 1353 ] 1354 _JOB_LIST = ht.Comment("List of submitted jobs")(TJobIdList) 1355 ALLOCATABLE_KEY = "allocatable" 1356 FAILED_KEY = "allocatable" 1357 OP_RESULT = ht.TStrictDict(True, True, { 1358 constants.JOB_IDS_KEY: _JOB_LIST, 1359 ALLOCATABLE_KEY: ht.TListOf(ht.TNonEmptyString), 1360 FAILED_KEY: ht.TListOf(ht.TNonEmptyString), 1361 }) 1362
1363 - def __getstate__(self):
1364 """Generic serializer. 1365 1366 """ 1367 state = OpCode.__getstate__(self) 1368 if hasattr(self, "instances"): 1369 # pylint: disable=E1101 1370 state["instances"] = [inst.__getstate__() for inst in self.instances] 1371 return state
1372
1373 - def __setstate__(self, state):
1374 """Generic unserializer. 1375 1376 This method just restores from the serialized state the attributes 1377 of the current instance. 1378 1379 @param state: the serialized opcode data 1380 @type state: C{dict} 1381 1382 """ 1383 if not isinstance(state, dict): 1384 raise ValueError("Invalid data to __setstate__: expected dict, got %s" % 1385 type(state)) 1386 1387 if "instances" in state: 1388 state["instances"] = map(OpCode.LoadOpCode, state["instances"]) 1389 1390 return OpCode.__setstate__(self, state)
1391
1392 - def Validate(self, set_defaults):
1393 """Validates this opcode. 1394 1395 We do this recursively. 1396 1397 """ 1398 OpCode.Validate(self, set_defaults) 1399 1400 for inst in self.instances: # pylint: disable=E1101 1401 inst.Validate(set_defaults)
1402
1403 1404 -class OpInstanceReinstall(OpCode):
1405 """Reinstall an instance's OS.""" 1406 OP_DSC_FIELD = "instance_name" 1407 OP_PARAMS = [ 1408 _PInstanceName, 1409 _PInstanceUuid, 1410 _PForceVariant, 1411 ("os_type", None, ht.TMaybeString, "Instance operating system"), 1412 ("osparams", None, ht.TMaybeDict, "Temporary OS parameters"), 1413 ] 1414 OP_RESULT = ht.TNone
1415
1416 1417 -class OpInstanceRemove(OpCode):
1418 """Remove an instance.""" 1419 OP_DSC_FIELD = "instance_name" 1420 OP_PARAMS = [ 1421 _PInstanceName, 1422 _PInstanceUuid, 1423 _PShutdownTimeout, 1424 ("ignore_failures", False, ht.TBool, 1425 "Whether to ignore failures during removal"), 1426 ] 1427 OP_RESULT = ht.TNone
1428
1429 1430 -class OpInstanceRename(OpCode):
1431 """Rename an instance.""" 1432 OP_PARAMS = [ 1433 _PInstanceName, 1434 _PInstanceUuid, 1435 _PNameCheck, 1436 ("new_name", ht.NoDefault, ht.TNonEmptyString, "New instance name"), 1437 ("ip_check", False, ht.TBool, _PIpCheckDoc), 1438 ] 1439 OP_RESULT = ht.Comment("New instance name")(ht.TNonEmptyString)
1440
1441 1442 -class OpInstanceStartup(OpCode):
1443 """Startup an instance.""" 1444 OP_DSC_FIELD = "instance_name" 1445 OP_PARAMS = [ 1446 _PInstanceName, 1447 _PInstanceUuid, 1448 _PForce, 1449 _PIgnoreOfflineNodes, 1450 ("hvparams", ht.EmptyDict, ht.TDict, 1451 "Temporary hypervisor parameters, hypervisor-dependent"), 1452 ("beparams", ht.EmptyDict, ht.TDict, "Temporary backend parameters"), 1453 _PNoRemember, 1454 _PStartupPaused, 1455 ] 1456 OP_RESULT = ht.TNone
1457
1458 1459 -class OpInstanceShutdown(OpCode):
1460 """Shutdown an instance.""" 1461 OP_DSC_FIELD = "instance_name" 1462 OP_PARAMS = [ 1463 _PInstanceName, 1464 _PInstanceUuid, 1465 _PForce, 1466 _PIgnoreOfflineNodes, 1467 ("timeout", constants.DEFAULT_SHUTDOWN_TIMEOUT, ht.TNonNegativeInt, 1468 "How long to wait for instance to shut down"), 1469 _PNoRemember, 1470 ] 1471 OP_RESULT = ht.TNone
1472
1473 1474 -class OpInstanceReboot(OpCode):
1475 """Reboot an instance.""" 1476 OP_DSC_FIELD = "instance_name" 1477 OP_PARAMS = [ 1478 _PInstanceName, 1479 _PInstanceUuid, 1480 _PShutdownTimeout, 1481 ("ignore_secondaries", False, ht.TBool, 1482 "Whether to start the instance even if secondary disks are failing"), 1483 ("reboot_type", ht.NoDefault, ht.TElemOf(constants.REBOOT_TYPES), 1484 "How to reboot instance"), 1485 ] 1486 OP_RESULT = ht.TNone
1487
1488 1489 -class OpInstanceReplaceDisks(OpCode):
1490 """Replace the disks of an instance.""" 1491 OP_DSC_FIELD = "instance_name" 1492 OP_PARAMS = [ 1493 _PInstanceName, 1494 _PInstanceUuid, 1495 _PEarlyRelease, 1496 _PIgnoreIpolicy, 1497 ("mode", ht.NoDefault, ht.TElemOf(constants.REPLACE_MODES), 1498 "Replacement mode"), 1499 ("disks", ht.EmptyList, ht.TListOf(ht.TNonNegativeInt), 1500 "Disk indexes"), 1501 ("remote_node", None, ht.TMaybeString, "New secondary node"), 1502 ("remote_node_uuid", None, ht.TMaybeString, "New secondary node UUID"), 1503 _PIAllocFromDesc("Iallocator for deciding new secondary node"), 1504 ] 1505 OP_RESULT = ht.TNone
1506
1507 1508 -class OpInstanceFailover(OpCode):
1509 """Failover an instance.""" 1510 OP_DSC_FIELD = "instance_name" 1511 OP_PARAMS = [ 1512 _PInstanceName, 1513 _PInstanceUuid, 1514 _PShutdownTimeout, 1515 _PIgnoreConsistency, 1516 _PMigrationTargetNode, 1517 _PMigrationTargetNodeUuid, 1518 _PIgnoreIpolicy, 1519 _PIAllocFromDesc("Iallocator for deciding the target node for" 1520 " shared-storage instances"), 1521 ("cleanup", False, ht.TBool, 1522 "Whether a previously failed failover should be cleaned up"), 1523 ] 1524 OP_RESULT = ht.TNone
1525
1526 1527 -class OpInstanceMigrate(OpCode):
1528 """Migrate an instance. 1529 1530 This migrates (without shutting down an instance) to its secondary 1531 node. 1532 1533 @ivar instance_name: the name of the instance 1534 @ivar mode: the migration mode (live, non-live or None for auto) 1535 1536 """ 1537 OP_DSC_FIELD = "instance_name" 1538 OP_PARAMS = [ 1539 _PInstanceName, 1540 _PInstanceUuid, 1541 _PMigrationMode, 1542 _PMigrationLive, 1543 _PMigrationTargetNode, 1544 _PMigrationTargetNodeUuid, 1545 _PAllowRuntimeChgs, 1546 _PIgnoreIpolicy, 1547 ("cleanup", False, ht.TBool, 1548 "Whether a previously failed migration should be cleaned up"), 1549 _PIAllocFromDesc("Iallocator for deciding the target node for" 1550 " shared-storage instances"), 1551 ("allow_failover", False, ht.TBool, 1552 "Whether we can fallback to failover if migration is not possible"), 1553 ] 1554 OP_RESULT = ht.TNone
1555
1556 1557 -class OpInstanceMove(OpCode):
1558 """Move an instance. 1559 1560 This move (with shutting down an instance and data copying) to an 1561 arbitrary node. 1562 1563 @ivar instance_name: the name of the instance 1564 @ivar target_node: the destination node 1565 1566 """ 1567 OP_DSC_FIELD = "instance_name" 1568 OP_PARAMS = [ 1569 _PInstanceName, 1570 _PInstanceUuid, 1571 _PShutdownTimeout, 1572 _PIgnoreIpolicy, 1573 ("target_node", ht.NoDefault, ht.TNonEmptyString, "Target node"), 1574 ("target_node_uuid", None, ht.TMaybeString, "Target node UUID"), 1575 _PIgnoreConsistency, 1576 ] 1577 OP_RESULT = ht.TNone
1578
1579 1580 -class OpInstanceConsole(OpCode):
1581 """Connect to an instance's console.""" 1582 OP_DSC_FIELD = "instance_name" 1583 OP_PARAMS = [ 1584 _PInstanceName, 1585 _PInstanceUuid, 1586 ] 1587 OP_RESULT = ht.TDict
1588
1589 1590 -class OpInstanceActivateDisks(OpCode):
1591 """Activate an instance's disks.""" 1592 OP_DSC_FIELD = "instance_name" 1593 OP_PARAMS = [ 1594 _PInstanceName, 1595 _PInstanceUuid, 1596 ("ignore_size", False, ht.TBool, "Whether to ignore recorded size"), 1597 _PWaitForSyncFalse, 1598 ] 1599 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(3), 1600 ht.TItems([ht.TNonEmptyString, 1601 ht.TNonEmptyString, 1602 ht.TNonEmptyString])))
1603
1604 1605 -class OpInstanceDeactivateDisks(OpCode):
1606 """Deactivate an instance's disks.""" 1607 OP_DSC_FIELD = "instance_name" 1608 OP_PARAMS = [ 1609 _PInstanceName, 1610 _PInstanceUuid, 1611 _PForce, 1612 ] 1613 OP_RESULT = ht.TNone
1614
1615 1616 -class OpInstanceRecreateDisks(OpCode):
1617 """Recreate an instance's disks.""" 1618 _TDiskChanges = \ 1619 ht.TAnd(ht.TIsLength(2), 1620 ht.TItems([ht.Comment("Disk index")(ht.TNonNegativeInt), 1621 ht.Comment("Parameters")(_TDiskParams)])) 1622 1623 OP_DSC_FIELD = "instance_name" 1624 OP_PARAMS = [ 1625 _PInstanceName, 1626 _PInstanceUuid, 1627 ("disks", ht.EmptyList, 1628 ht.TOr(ht.TListOf(ht.TNonNegativeInt), ht.TListOf(_TDiskChanges)), 1629 "List of disk indexes (deprecated) or a list of tuples containing a disk" 1630 " index and a possibly empty dictionary with disk parameter changes"), 1631 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1632 "New instance nodes, if relocation is desired"), 1633 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString), 1634 "New instance node UUIDs, if relocation is desired"), 1635 _PIAllocFromDesc("Iallocator for deciding new nodes"), 1636 ] 1637 OP_RESULT = ht.TNone
1638
1639 1640 -class OpInstanceQuery(OpCode):
1641 """Compute the list of instances.""" 1642 OP_PARAMS = [ 1643 _POutputFields, 1644 _PUseLocking, 1645 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1646 "Empty list to query all instances, instance names otherwise"), 1647 ] 1648 OP_RESULT = _TOldQueryResult
1649
1650 1651 -class OpInstanceQueryData(OpCode):
1652 """Compute the run-time status of instances.""" 1653 OP_PARAMS = [ 1654 _PUseLocking, 1655 ("instances", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1656 "Instance names"), 1657 ("static", False, ht.TBool, 1658 "Whether to only return configuration data without querying" 1659 " nodes"), 1660 ] 1661 OP_RESULT = ht.TDictOf(ht.TNonEmptyString, ht.TDict)
1662
1663 1664 -def _TestInstSetParamsModList(fn):
1665 """Generates a check for modification lists. 1666 1667 """ 1668 # Old format 1669 # TODO: Remove in version 2.8 including support in LUInstanceSetParams 1670 old_mod_item_fn = \ 1671 ht.TAnd(ht.TIsLength(2), ht.TItems([ 1672 ht.TOr(ht.TElemOf(constants.DDMS_VALUES), ht.TNonNegativeInt), 1673 fn, 1674 ])) 1675 1676 # New format, supporting adding/removing disks/NICs at arbitrary indices 1677 mod_item_fn = \ 1678 ht.TAnd(ht.TIsLength(3), ht.TItems([ 1679 ht.TElemOf(constants.DDMS_VALUES_WITH_MODIFY), 1680 ht.Comment("Device index, can be negative, e.g. -1 for last disk") 1681 (ht.TOr(ht.TInt, ht.TString)), 1682 fn, 1683 ])) 1684 1685 return ht.TOr(ht.Comment("Recommended")(ht.TListOf(mod_item_fn)), 1686 ht.Comment("Deprecated")(ht.TListOf(old_mod_item_fn)))
1687
1688 1689 -class OpInstanceSetParams(OpCode):
1690 """Change the parameters of an instance. 1691 1692 """ 1693 TestNicModifications = _TestInstSetParamsModList(_TestNicDef) 1694 TestDiskModifications = _TestInstSetParamsModList(_TDiskParams) 1695 1696 OP_DSC_FIELD = "instance_name" 1697 OP_PARAMS = [ 1698 _PInstanceName, 1699 _PInstanceUuid, 1700 _PForce, 1701 _PForceVariant, 1702 _PIgnoreIpolicy, 1703 ("nics", ht.EmptyList, TestNicModifications, 1704 "List of NIC changes: each item is of the form" 1705 " ``(op, identifier, settings)``, ``op`` is one of ``%s``, ``%s`` or" 1706 " ``%s``, ``identifier`` can be a zero-based index number (or -1 to refer" 1707 " to the last position), the NIC's UUID of the NIC's name; a" 1708 " deprecated version of this parameter used the form ``(op, settings)``," 1709 " where ``op`` can be ``%s`` to add a new NIC with the specified" 1710 " settings, ``%s`` to remove the last NIC or a number to modify the" 1711 " settings of the NIC with that index" % 1712 (constants.DDM_ADD, constants.DDM_MODIFY, constants.DDM_REMOVE, 1713 constants.DDM_ADD, constants.DDM_REMOVE)), 1714 ("disks", ht.EmptyList, TestDiskModifications, 1715 "List of disk changes; see ``nics``"), 1716 ("beparams", ht.EmptyDict, ht.TDict, "Per-instance backend parameters"), 1717 ("runtime_mem", None, ht.TMaybePositiveInt, "New runtime memory"), 1718 ("hvparams", ht.EmptyDict, ht.TDict, 1719 "Per-instance hypervisor parameters, hypervisor-dependent"), 1720 ("disk_template", None, ht.TMaybe(_BuildDiskTemplateCheck(False)), 1721 "Disk template for instance"), 1722 ("pnode", None, ht.TMaybeString, "New primary node"), 1723 ("pnode_uuid", None, ht.TMaybeString, "New primary node UUID"), 1724 ("remote_node", None, ht.TMaybeString, 1725 "Secondary node (used when changing disk template)"), 1726 ("remote_node_uuid", None, ht.TMaybeString, 1727 "Secondary node UUID (used when changing disk template)"), 1728 ("os_name", None, ht.TMaybeString, 1729 "Change the instance's OS without reinstalling the instance"), 1730 ("osparams", None, ht.TMaybeDict, "Per-instance OS parameters"), 1731 ("wait_for_sync", True, ht.TBool, 1732 "Whether to wait for the disk to synchronize, when changing template"), 1733 ("offline", None, ht.TMaybeBool, "Whether to mark instance as offline"), 1734 ("conflicts_check", True, ht.TBool, "Check for conflicting IPs"), 1735 ] 1736 OP_RESULT = _TSetParamsResult
1737
1738 1739 -class OpInstanceGrowDisk(OpCode):
1740 """Grow a disk of an instance.""" 1741 OP_DSC_FIELD = "instance_name" 1742 OP_PARAMS = [ 1743 _PInstanceName, 1744 _PInstanceUuid, 1745 _PWaitForSync, 1746 ("disk", ht.NoDefault, ht.TInt, "Disk index"), 1747 ("amount", ht.NoDefault, ht.TNonNegativeInt, 1748 "Amount of disk space to add (megabytes)"), 1749 ("absolute", False, ht.TBool, 1750 "Whether the amount parameter is an absolute target or a relative one"), 1751 ] 1752 OP_RESULT = ht.TNone
1753
1754 1755 -class OpInstanceChangeGroup(OpCode):
1756 """Moves an instance to another node group.""" 1757 OP_DSC_FIELD = "instance_name" 1758 OP_PARAMS = [ 1759 _PInstanceName, 1760 _PInstanceUuid, 1761 _PEarlyRelease, 1762 _PIAllocFromDesc("Iallocator for computing solution"), 1763 _PTargetGroups, 1764 ] 1765 OP_RESULT = TJobIdListOnly
1766
1767 1768 # Node group opcodes 1769 1770 -class OpGroupAdd(OpCode):
1771 """Add a node group to the cluster.""" 1772 OP_DSC_FIELD = "group_name" 1773 OP_PARAMS = [ 1774 _PGroupName, 1775 _PNodeGroupAllocPolicy, 1776 _PGroupNodeParams, 1777 _PDiskParams, 1778 _PHvState, 1779 _PDiskState, 1780 ("ipolicy", None, ht.TMaybeDict, 1781 "Group-wide :ref:`instance policy <rapi-ipolicy>` specs"), 1782 ] 1783 OP_RESULT = ht.TNone
1784
1785 1786 -class OpGroupAssignNodes(OpCode):
1787 """Assign nodes to a node group.""" 1788 OP_DSC_FIELD = "group_name" 1789 OP_PARAMS = [ 1790 _PGroupName, 1791 _PForce, 1792 ("nodes", ht.NoDefault, ht.TListOf(ht.TNonEmptyString), 1793 "List of nodes to assign"), 1794 ("node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString), 1795 "List of node UUIDs to assign"), 1796 ] 1797 OP_RESULT = ht.TNone
1798
1799 1800 -class OpGroupQuery(OpCode):
1801 """Compute the list of node groups.""" 1802 OP_PARAMS = [ 1803 _POutputFields, 1804 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1805 "Empty list to query all groups, group names otherwise"), 1806 ] 1807 OP_RESULT = _TOldQueryResult
1808
1809 1810 -class OpGroupSetParams(OpCode):
1811 """Change the parameters of a node group.""" 1812 OP_DSC_FIELD = "group_name" 1813 OP_PARAMS = [ 1814 _PGroupName, 1815 _PNodeGroupAllocPolicy, 1816 _PGroupNodeParams, 1817 _PDiskParams, 1818 _PHvState, 1819 _PDiskState, 1820 ("ipolicy", None, ht.TMaybeDict, "Group-wide instance policy specs"), 1821 ] 1822 OP_RESULT = _TSetParamsResult
1823
1824 1825 -class OpGroupRemove(OpCode):
1826 """Remove a node group from the cluster.""" 1827 OP_DSC_FIELD = "group_name" 1828 OP_PARAMS = [ 1829 _PGroupName, 1830 ] 1831 OP_RESULT = ht.TNone
1832
1833 1834 -class OpGroupRename(OpCode):
1835 """Rename a node group in the cluster.""" 1836 OP_PARAMS = [ 1837 _PGroupName, 1838 ("new_name", ht.NoDefault, ht.TNonEmptyString, "New group name"), 1839 ] 1840 OP_RESULT = ht.Comment("New group name")(ht.TNonEmptyString)
1841
1842 1843 -class OpGroupEvacuate(OpCode):
1844 """Evacuate a node group in the cluster.""" 1845 OP_DSC_FIELD = "group_name" 1846 OP_PARAMS = [ 1847 _PGroupName, 1848 _PEarlyRelease, 1849 _PIAllocFromDesc("Iallocator for computing solution"), 1850 _PTargetGroups, 1851 ] 1852 OP_RESULT = TJobIdListOnly
1853
1854 1855 # OS opcodes 1856 -class OpOsDiagnose(OpCode):
1857 """Compute the list of guest operating systems.""" 1858 OP_PARAMS = [ 1859 _POutputFields, 1860 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1861 "Which operating systems to diagnose"), 1862 ] 1863 OP_RESULT = _TOldQueryResult
1864
1865 1866 # ExtStorage opcodes 1867 -class OpExtStorageDiagnose(OpCode):
1868 """Compute the list of external storage providers.""" 1869 OP_PARAMS = [ 1870 _POutputFields, 1871 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1872 "Which ExtStorage Provider to diagnose"), 1873 ] 1874 OP_RESULT = _TOldQueryResult
1875
1876 1877 # Exports opcodes 1878 -class OpBackupQuery(OpCode):
1879 """Compute the list of exported images.""" 1880 OP_PARAMS = [ 1881 _PUseLocking, 1882 ("nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 1883 "Empty list to query all nodes, node names otherwise"), 1884 ] 1885 OP_RESULT = ht.TDictOf(ht.TNonEmptyString, 1886 ht.TOr(ht.Comment("False on error")(ht.TBool), 1887 ht.TListOf(ht.TNonEmptyString)))
1888
1889 1890 -class OpBackupPrepare(OpCode):
1891 """Prepares an instance export. 1892 1893 @ivar instance_name: Instance name 1894 @ivar mode: Export mode (one of L{constants.EXPORT_MODES}) 1895 1896 """ 1897 OP_DSC_FIELD = "instance_name" 1898 OP_PARAMS = [ 1899 _PInstanceName, 1900 _PInstanceUuid, 1901 ("mode", ht.NoDefault, ht.TElemOf(constants.EXPORT_MODES), 1902 "Export mode"), 1903 ] 1904 OP_RESULT = ht.TMaybeDict
1905
1906 1907 -class OpBackupExport(OpCode):
1908 """Export an instance. 1909 1910 For local exports, the export destination is the node name. For 1911 remote exports, the export destination is a list of tuples, each 1912 consisting of hostname/IP address, port, magic, HMAC and HMAC 1913 salt. The HMAC is calculated using the cluster domain secret over 1914 the value "${index}:${hostname}:${port}". The destination X509 CA 1915 must be a signed certificate. 1916 1917 @ivar mode: Export mode (one of L{constants.EXPORT_MODES}) 1918 @ivar target_node: Export destination 1919 @ivar x509_key_name: X509 key to use (remote export only) 1920 @ivar destination_x509_ca: Destination X509 CA in PEM format (remote export 1921 only) 1922 1923 """ 1924 OP_DSC_FIELD = "instance_name" 1925 OP_PARAMS = [ 1926 _PInstanceName, 1927 _PInstanceUuid, 1928 _PShutdownTimeout, 1929 # TODO: Rename target_node as it changes meaning for different export modes 1930 # (e.g. "destination") 1931 ("target_node", ht.NoDefault, ht.TOr(ht.TNonEmptyString, ht.TList), 1932 "Destination information, depends on export mode"), 1933 ("target_node_uuid", None, ht.TMaybeString, 1934 "Target node UUID (if local export)"), 1935 ("shutdown", True, ht.TBool, "Whether to shutdown instance before export"), 1936 ("remove_instance", False, ht.TBool, 1937 "Whether to remove instance after export"), 1938 ("ignore_remove_failures", False, ht.TBool, 1939 "Whether to ignore failures while removing instances"), 1940 ("mode", constants.EXPORT_MODE_LOCAL, ht.TElemOf(constants.EXPORT_MODES), 1941 "Export mode"), 1942 ("x509_key_name", None, ht.TMaybe(ht.TList), 1943 "Name of X509 key (remote export only)"), 1944 ("destination_x509_ca", None, ht.TMaybeString, 1945 "Destination X509 CA (remote export only)"), 1946 ] 1947 OP_RESULT = \ 1948 ht.TAnd(ht.TIsLength(2), ht.TItems([ 1949 ht.Comment("Finalizing status")(ht.TBool), 1950 ht.Comment("Status for every exported disk")(ht.TListOf(ht.TBool)), 1951 ]))
1952
1953 1954 -class OpBackupRemove(OpCode):
1955 """Remove an instance's export.""" 1956 OP_DSC_FIELD = "instance_name" 1957 OP_PARAMS = [ 1958 _PInstanceName, 1959 _PInstanceUuid, 1960 ] 1961 OP_RESULT = ht.TNone
1962
1963 1964 # Tags opcodes 1965 -class OpTagsGet(OpCode):
1966 """Returns the tags of the given object.""" 1967 OP_DSC_FIELD = "name" 1968 OP_PARAMS = [ 1969 _PTagKind, 1970 # Not using _PUseLocking as the default is different for historical reasons 1971 ("use_locking", True, ht.TBool, "Whether to use synchronization"), 1972 # Name is only meaningful for nodes and instances 1973 ("name", ht.NoDefault, ht.TMaybeString, 1974 "Name of object to retrieve tags from"), 1975 ] 1976 OP_RESULT = ht.TListOf(ht.TNonEmptyString)
1977
1978 1979 -class OpTagsSearch(OpCode):
1980 """Searches the tags in the cluster for a given pattern.""" 1981 OP_DSC_FIELD = "pattern" 1982 OP_PARAMS = [ 1983 ("pattern", ht.NoDefault, ht.TNonEmptyString, 1984 "Search pattern (regular expression)"), 1985 ] 1986 OP_RESULT = ht.TListOf(ht.TAnd(ht.TIsLength(2), ht.TItems([ 1987 ht.TNonEmptyString, 1988 ht.TNonEmptyString, 1989 ])))
1990
1991 1992 -class OpTagsSet(OpCode):
1993 """Add a list of tags on a given object.""" 1994 OP_PARAMS = [ 1995 _PTagKind, 1996 _PTags, 1997 # Name is only meaningful for groups, nodes and instances 1998 ("name", ht.NoDefault, ht.TMaybeString, 1999 "Name of object where tag(s) should be added"), 2000 ] 2001 OP_RESULT = ht.TNone
2002
2003 2004 -class OpTagsDel(OpCode):
2005 """Remove a list of tags from a given object.""" 2006 OP_PARAMS = [ 2007 _PTagKind, 2008 _PTags, 2009 # Name is only meaningful for groups, nodes and instances 2010 ("name", ht.NoDefault, ht.TMaybeString, 2011 "Name of object where tag(s) should be deleted"), 2012 ] 2013 OP_RESULT = ht.TNone
2014
2015 2016 # Test opcodes 2017 -class OpTestDelay(OpCode):
2018 """Sleeps for a configured amount of time. 2019 2020 This is used just for debugging and testing. 2021 2022 Parameters: 2023 - duration: the time to sleep, in seconds 2024 - on_master: if true, sleep on the master 2025 - on_nodes: list of nodes in which to sleep 2026 2027 If the on_master parameter is true, it will execute a sleep on the 2028 master (before any node sleep). 2029 2030 If the on_nodes list is not empty, it will sleep on those nodes 2031 (after the sleep on the master, if that is enabled). 2032 2033 As an additional feature, the case of duration < 0 will be reported 2034 as an execution error, so this opcode can be used as a failure 2035 generator. The case of duration == 0 will not be treated specially. 2036 2037 """ 2038 OP_DSC_FIELD = "duration" 2039 OP_PARAMS = [ 2040 ("duration", ht.NoDefault, ht.TNumber, None), 2041 ("on_master", True, ht.TBool, None), 2042 ("on_nodes", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), 2043 ("on_node_uuids", None, ht.TMaybeListOf(ht.TNonEmptyString), None), 2044 ("repeat", 0, ht.TNonNegativeInt, None), 2045 ] 2046
2047 - def OP_DSC_FORMATTER(self, value): # pylint: disable=C0103,R0201
2048 """Custom formatter for duration. 2049 2050 """ 2051 try: 2052 v = float(value) 2053 except TypeError: 2054 v = value 2055 return str(v)
2056
2057 2058 -class OpTestAllocator(OpCode):
2059 """Allocator framework testing. 2060 2061 This opcode has two modes: 2062 - gather and return allocator input for a given mode (allocate new 2063 or replace secondary) and a given instance definition (direction 2064 'in') 2065 - run a selected allocator for a given operation (as above) and 2066 return the allocator output (direction 'out') 2067 2068 """ 2069 OP_DSC_FIELD = "iallocator" 2070 OP_PARAMS = [ 2071 ("direction", ht.NoDefault, 2072 ht.TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS), None), 2073 ("mode", ht.NoDefault, ht.TElemOf(constants.VALID_IALLOCATOR_MODES), None), 2074 ("name", ht.NoDefault, ht.TNonEmptyString, None), 2075 ("nics", ht.NoDefault, 2076 ht.TMaybeListOf(ht.TDictOf(ht.TElemOf([constants.INIC_MAC, 2077 constants.INIC_IP, 2078 "bridge"]), 2079 ht.TMaybeString)), 2080 None), 2081 ("disks", ht.NoDefault, ht.TMaybe(ht.TList), None), 2082 ("hypervisor", None, ht.TMaybeString, None), 2083 _PIAllocFromDesc(None), 2084 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), None), 2085 ("memory", None, ht.TMaybe(ht.TNonNegativeInt), None), 2086 ("vcpus", None, ht.TMaybe(ht.TNonNegativeInt), None), 2087 ("os", None, ht.TMaybeString, None), 2088 ("disk_template", None, ht.TMaybeString, None), 2089 ("instances", None, ht.TMaybeListOf(ht.TNonEmptyString), None), 2090 ("evac_mode", None, 2091 ht.TMaybe(ht.TElemOf(constants.IALLOCATOR_NEVAC_MODES)), None), 2092 ("target_groups", None, ht.TMaybeListOf(ht.TNonEmptyString), None), 2093 ("spindle_use", 1, ht.TNonNegativeInt, None), 2094 ("count", 1, ht.TNonNegativeInt, None), 2095 ]
2096
2097 2098 -class OpTestJqueue(OpCode):
2099 """Utility opcode to test some aspects of the job queue. 2100 2101 """ 2102 OP_PARAMS = [ 2103 ("notify_waitlock", False, ht.TBool, None), 2104 ("notify_exec", False, ht.TBool, None), 2105 ("log_messages", ht.EmptyList, ht.TListOf(ht.TString), None), 2106 ("fail", False, ht.TBool, None), 2107 ]
2108
2109 2110 -class OpTestDummy(OpCode):
2111 """Utility opcode used by unittests. 2112 2113 """ 2114 OP_PARAMS = [ 2115 ("result", ht.NoDefault, ht.NoType, None), 2116 ("messages", ht.NoDefault, ht.NoType, None), 2117 ("fail", ht.NoDefault, ht.NoType, None), 2118 ("submit_jobs", None, ht.NoType, None), 2119 ] 2120 WITH_LU = False
2121
2122 2123 # Network opcodes 2124 # Add a new network in the cluster 2125 -class OpNetworkAdd(OpCode):
2126 """Add an IP network to the cluster.""" 2127 OP_DSC_FIELD = "network_name" 2128 OP_PARAMS = [ 2129 _PNetworkName, 2130 ("network", ht.NoDefault, _TIpNetwork4, "IPv4 subnet"), 2131 ("gateway", None, ht.TMaybe(_TIpAddress4), "IPv4 gateway"), 2132 ("network6", None, ht.TMaybe(_TIpNetwork6), "IPv6 subnet"), 2133 ("gateway6", None, ht.TMaybe(_TIpAddress6), "IPv6 gateway"), 2134 ("mac_prefix", None, ht.TMaybeString, 2135 "MAC address prefix that overrides cluster one"), 2136 ("add_reserved_ips", None, _TMaybeAddr4List, 2137 "Which IP addresses to reserve"), 2138 ("conflicts_check", True, ht.TBool, 2139 "Whether to check for conflicting IP addresses"), 2140 ("tags", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), "Network tags"), 2141 ] 2142 OP_RESULT = ht.TNone
2143
2144 2145 -class OpNetworkRemove(OpCode):
2146 """Remove an existing network from the cluster. 2147 Must not be connected to any nodegroup. 2148 2149 """ 2150 OP_DSC_FIELD = "network_name" 2151 OP_PARAMS = [ 2152 _PNetworkName, 2153 _PForce, 2154 ] 2155 OP_RESULT = ht.TNone
2156
2157 2158 -class OpNetworkSetParams(OpCode):
2159 """Modify Network's parameters except for IPv4 subnet""" 2160 OP_DSC_FIELD = "network_name" 2161 OP_PARAMS = [ 2162 _PNetworkName, 2163 ("gateway", None, ht.TMaybeValueNone(_TIpAddress4), "IPv4 gateway"), 2164 ("network6", None, ht.TMaybeValueNone(_TIpNetwork6), "IPv6 subnet"), 2165 ("gateway6", None, ht.TMaybeValueNone(_TIpAddress6), "IPv6 gateway"), 2166 ("mac_prefix", None, ht.TMaybeValueNone(ht.TString), 2167 "MAC address prefix that overrides cluster one"), 2168 ("add_reserved_ips", None, _TMaybeAddr4List, 2169 "Which external IP addresses to reserve"), 2170 ("remove_reserved_ips", None, _TMaybeAddr4List, 2171 "Which external IP addresses to release"), 2172 ] 2173 OP_RESULT = ht.TNone
2174
2175 2176 -class OpNetworkConnect(OpCode):
2177 """Connect a Network to a specific Nodegroup with the defined netparams 2178 (mode, link). Nics in this Network will inherit those params. 2179 Produce errors if a NIC (that its not already assigned to a network) 2180 has an IP that is contained in the Network this will produce error unless 2181 --no-conflicts-check is passed. 2182 2183 """ 2184 OP_DSC_FIELD = "network_name" 2185 OP_PARAMS = [ 2186 _PGroupName, 2187 _PNetworkName, 2188 ("network_mode", ht.NoDefault, ht.TElemOf(constants.NIC_VALID_MODES), 2189 "Connectivity mode"), 2190 ("network_link", ht.NoDefault, ht.TString, "Connectivity link"), 2191 ("conflicts_check", True, ht.TBool, "Whether to check for conflicting IPs"), 2192 ] 2193 OP_RESULT = ht.TNone
2194
2195 2196 -class OpNetworkDisconnect(OpCode):
2197 """Disconnect a Network from a Nodegroup. Produce errors if NICs are 2198 present in the Network unless --no-conficts-check option is passed. 2199 2200 """ 2201 OP_DSC_FIELD = "network_name" 2202 OP_PARAMS = [ 2203 _PGroupName, 2204 _PNetworkName, 2205 ] 2206 OP_RESULT = ht.TNone
2207
2208 2209 -class OpNetworkQuery(OpCode):
2210 """Compute the list of networks.""" 2211 OP_PARAMS = [ 2212 _POutputFields, 2213 _PUseLocking, 2214 ("names", ht.EmptyList, ht.TListOf(ht.TNonEmptyString), 2215 "Empty list to query all groups, group names otherwise"), 2216 ] 2217 OP_RESULT = _TOldQueryResult
2218
2219 2220 -def _GetOpList():
2221 """Returns list of all defined opcodes. 2222 2223 Does not eliminate duplicates by C{OP_ID}. 2224 2225 """ 2226 return [v for v in globals().values() 2227 if (isinstance(v, type) and issubclass(v, OpCode) and 2228 hasattr(v, "OP_ID") and v is not OpCode)]
2229 2230 2231 OP_MAPPING = dict((v.OP_ID, v) for v in _GetOpList()) 2232