Package ganeti :: Package cmdlib :: Module base
[hide private]
[frames] | no frames]

Source Code for Module ganeti.cmdlib.base

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 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 classes and functions for cmdlib.""" 
 32   
 33  import logging 
 34   
 35  from ganeti import errors 
 36  from ganeti import constants 
 37  from ganeti import locking 
 38  from ganeti import query 
 39  from ganeti import utils 
 40  from ganeti.cmdlib.common import ExpandInstanceUuidAndName 
 41   
 42   
43 -class ResultWithJobs(object):
44 """Data container for LU results with jobs. 45 46 Instances of this class returned from L{LogicalUnit.Exec} will be recognized 47 by L{mcpu._ProcessResult}. The latter will then submit the jobs 48 contained in the C{jobs} attribute and include the job IDs in the opcode 49 result. 50 51 """
52 - def __init__(self, jobs, **kwargs):
53 """Initializes this class. 54 55 Additional return values can be specified as keyword arguments. 56 57 @type jobs: list of lists of L{opcode.OpCode} 58 @param jobs: A list of lists of opcode objects 59 60 """ 61 self.jobs = jobs 62 self.other = kwargs
63 64
65 -class LUWConfdClient(object):
66 """Wrapper class for wconfd client calls from LUs. 67 68 Correctly updates the cache of the LU's owned locks 69 when leaving. Also transparently adds the context 70 for resource requests. 71 72 """
73 - def __init__(self, lu):
74 self.lu = lu
75
76 - def TryUpdateLocks(self, req):
77 self.lu.wconfd.Client().TryUpdateLocks(self.lu.wconfdcontext, req) 78 self.lu.wconfdlocks = \ 79 self.lu.wconfd.Client().ListLocks(self.lu.wconfdcontext)
80
81 - def DownGradeLocksLevel(self, level):
82 self.lu.wconfd.Client().DownGradeLocksLevel(self.lu.wconfdcontext, level) 83 self.lu.wconfdlocks = \ 84 self.lu.wconfd.Client().ListLocks(self.lu.wconfdcontext)
85
86 - def FreeLocksLevel(self, level):
87 self.lu.wconfd.Client().FreeLocksLevel(self.lu.wconfdcontext, level) 88 self.lu.wconfdlocks = \ 89 self.lu.wconfd.Client().ListLocks(self.lu.wconfdcontext)
90 91
92 -class LogicalUnit(object): # pylint: disable=R0902
93 """Logical Unit base class. 94 95 Subclasses must follow these rules: 96 - implement ExpandNames 97 - implement CheckPrereq (except when tasklets are used) 98 - implement Exec (except when tasklets are used) 99 - implement BuildHooksEnv 100 - implement BuildHooksNodes 101 - redefine HPATH and HTYPE 102 - optionally redefine their run requirements: 103 REQ_BGL: the LU needs to hold the Big Ganeti Lock exclusively 104 105 Note that all commands require root permissions. 106 107 @ivar dry_run_result: the value (if any) that will be returned to the caller 108 in dry-run mode (signalled by opcode dry_run parameter) 109 110 """ 111 # This class has more than 20 instance variables, but at most have sensible 112 # defaults and are used in a declartive way, this is not a problem. 113 114 HPATH = None 115 HTYPE = None 116 REQ_BGL = True 117
118 - def __init__(self, processor, op, cfg, 119 rpc_runner, wconfdcontext, wconfd):
120 """Constructor for LogicalUnit. 121 122 This needs to be overridden in derived classes in order to check op 123 validity. 124 125 @type wconfdcontext: (int, string) 126 @param wconfdcontext: the identity of the logical unit to represent itself 127 to wconfd when asking for resources; it is given as job id and livelock 128 file. 129 @param wconfd: the wconfd class to use; dependency injection to allow 130 testability. 131 132 """ 133 self.proc = processor 134 self.op = op 135 self.cfg = cfg 136 self.wconfdlocks = [] 137 self.wconfdcontext = wconfdcontext 138 self.rpc = rpc_runner 139 self.wconfd = wconfd # wconfd module to use, for testing 140 141 # Dictionaries used to declare locking needs to mcpu 142 self.needed_locks = None 143 self.share_locks = dict.fromkeys(locking.LEVELS, 0) 144 self.opportunistic_locks = dict.fromkeys(locking.LEVELS, False) 145 self.opportunistic_locks_count = dict.fromkeys(locking.LEVELS, 1) 146 self.dont_collate_locks = dict.fromkeys(locking.LEVELS, False) 147 148 self.add_locks = {} 149 150 # Used to force good behavior when calling helper functions 151 self.recalculate_locks = {} 152 153 # logging 154 self.Log = processor.Log # pylint: disable=C0103 155 self.LogWarning = processor.LogWarning # pylint: disable=C0103 156 self.LogInfo = processor.LogInfo # pylint: disable=C0103 157 self.LogStep = processor.LogStep # pylint: disable=C0103 158 # support for dry-run 159 self.dry_run_result = None 160 # support for generic debug attribute 161 if (not hasattr(self.op, "debug_level") or 162 not isinstance(self.op.debug_level, int)): 163 self.op.debug_level = 0 164 165 # Tasklets 166 self.tasklets = None 167 168 # Validate opcode parameters and set defaults 169 self.op.Validate(True) 170 171 self.CheckArguments()
172
173 - def WConfdClient(self):
174 return LUWConfdClient(self)
175
176 - def owned_locks(self, level):
177 """Return the list of locks owned by the LU at a given level. 178 179 This method assumes that is field wconfdlocks is set correctly 180 by mcpu. 181 182 """ 183 levelprefix = "%s/" % (locking.LEVEL_NAMES[level],) 184 locks = set([lock[0][len(levelprefix):] 185 for lock in self.wconfdlocks 186 if lock[0].startswith(levelprefix)]) 187 expand_fns = { 188 locking.LEVEL_CLUSTER: (lambda: [locking.BGL]), 189 locking.LEVEL_INSTANCE: 190 lambda: self.cfg.GetInstanceNames(self.cfg.GetInstanceList()), 191 locking.LEVEL_NODEGROUP: self.cfg.GetNodeGroupList, 192 locking.LEVEL_NODE: self.cfg.GetNodeList, 193 locking.LEVEL_NODE_RES: self.cfg.GetNodeList, 194 locking.LEVEL_NETWORK: self.cfg.GetNetworkList, 195 } 196 if locking.LOCKSET_NAME in locks: 197 return expand_fns[level]() 198 else: 199 return locks
200
201 - def release_request(self, level, names):
202 """Return a request to release the specified locks of the given level. 203 204 Correctly break up the group lock to do so. 205 206 """ 207 levelprefix = "%s/" % (locking.LEVEL_NAMES[level],) 208 release = [[levelprefix + lock, "release"] for lock in names] 209 210 # if we break up the set-lock, make sure we ask for the rest of it. 211 setlock = levelprefix + locking.LOCKSET_NAME 212 if [setlock, "exclusive"] in self.wconfdlocks: 213 owned = self.owned_locks(level) 214 request = [[levelprefix + lock, "exclusive"] 215 for lock in owned 216 if lock not in names] 217 elif [setlock, "shared"] in self.wconfdlocks: 218 owned = self.owned_locks(level) 219 request = [[levelprefix + lock, "shared"] 220 for lock in owned 221 if lock not in names] 222 else: 223 request = [] 224 225 return release + [[setlock, "release"]] + request
226
227 - def CheckArguments(self):
228 """Check syntactic validity for the opcode arguments. 229 230 This method is for doing a simple syntactic check and ensure 231 validity of opcode parameters, without any cluster-related 232 checks. While the same can be accomplished in ExpandNames and/or 233 CheckPrereq, doing these separate is better because: 234 235 - ExpandNames is left as as purely a lock-related function 236 - CheckPrereq is run after we have acquired locks (and possible 237 waited for them) 238 239 The function is allowed to change the self.op attribute so that 240 later methods can no longer worry about missing parameters. 241 242 """ 243 pass
244
245 - def ExpandNames(self):
246 """Expand names for this LU. 247 248 This method is called before starting to execute the opcode, and it should 249 update all the parameters of the opcode to their canonical form (e.g. a 250 short node name must be fully expanded after this method has successfully 251 completed). This way locking, hooks, logging, etc. can work correctly. 252 253 LUs which implement this method must also populate the self.needed_locks 254 member, as a dict with lock levels as keys, and a list of needed lock names 255 as values. Rules: 256 257 - use an empty dict if you don't need any lock 258 - if you don't need any lock at a particular level omit that 259 level (note that in this case C{DeclareLocks} won't be called 260 at all for that level) 261 - if you need locks at a level, but you can't calculate it in 262 this function, initialise that level with an empty list and do 263 further processing in L{LogicalUnit.DeclareLocks} (see that 264 function's docstring) 265 - don't put anything for the BGL level 266 - if you want all locks at a level use L{locking.ALL_SET} as a value 267 268 If you need to share locks (rather than acquire them exclusively) at one 269 level you can modify self.share_locks, setting a true value (usually 1) for 270 that level. By default locks are not shared. 271 272 This function can also define a list of tasklets, which then will be 273 executed in order instead of the usual LU-level CheckPrereq and Exec 274 functions, if those are not defined by the LU. 275 276 Examples:: 277 278 # Acquire all nodes and one instance 279 self.needed_locks = { 280 locking.LEVEL_NODE: locking.ALL_SET, 281 locking.LEVEL_INSTANCE: ['instance1.example.com'], 282 } 283 # Acquire just two nodes 284 self.needed_locks = { 285 locking.LEVEL_NODE: ['node1-uuid', 'node2-uuid'], 286 } 287 # Acquire no locks 288 self.needed_locks = {} # No, you can't leave it to the default value None 289 290 """ 291 # The implementation of this method is mandatory only if the new LU is 292 # concurrent, so that old LUs don't need to be changed all at the same 293 # time. 294 if self.REQ_BGL: 295 self.needed_locks = {} # Exclusive LUs don't need locks. 296 else: 297 raise NotImplementedError
298
299 - def DeclareLocks(self, level):
300 """Declare LU locking needs for a level 301 302 While most LUs can just declare their locking needs at ExpandNames time, 303 sometimes there's the need to calculate some locks after having acquired 304 the ones before. This function is called just before acquiring locks at a 305 particular level, but after acquiring the ones at lower levels, and permits 306 such calculations. It can be used to modify self.needed_locks, and by 307 default it does nothing. 308 309 This function is only called if you have something already set in 310 self.needed_locks for the level. 311 312 @param level: Locking level which is going to be locked 313 @type level: member of L{ganeti.locking.LEVELS} 314 315 """
316
317 - def CheckPrereq(self):
318 """Check prerequisites for this LU. 319 320 This method should check that the prerequisites for the execution 321 of this LU are fulfilled. It can do internode communication, but 322 it should be idempotent - no cluster or system changes are 323 allowed. 324 325 The method should raise errors.OpPrereqError in case something is 326 not fulfilled. Its return value is ignored. 327 328 This method should also update all the parameters of the opcode to 329 their canonical form if it hasn't been done by ExpandNames before. 330 331 """ 332 if self.tasklets is not None: 333 for (idx, tl) in enumerate(self.tasklets): 334 logging.debug("Checking prerequisites for tasklet %s/%s", 335 idx + 1, len(self.tasklets)) 336 tl.CheckPrereq() 337 else: 338 pass
339
340 - def Exec(self, feedback_fn):
341 """Execute the LU. 342 343 This method should implement the actual work. It should raise 344 errors.OpExecError for failures that are somewhat dealt with in 345 code, or expected. 346 347 """ 348 if self.tasklets is not None: 349 for (idx, tl) in enumerate(self.tasklets): 350 logging.debug("Executing tasklet %s/%s", idx + 1, len(self.tasklets)) 351 tl.Exec(feedback_fn) 352 else: 353 raise NotImplementedError
354
355 - def PrepareRetry(self, _feedback_fn):
356 """Prepare the LU to run again. 357 358 This method is called if the Exec failed for temporarily lacking resources. 359 It is expected to change the state of the LU so that it can be tried again, 360 and also change its locking policy to acquire more resources to have a 361 better chance of suceeding in the retry. 362 363 """ 364 # pylint: disable=R0201 365 raise errors.OpRetryNotSupportedError()
366
367 - def BuildHooksEnv(self):
368 """Build hooks environment for this LU. 369 370 @rtype: dict 371 @return: Dictionary containing the environment that will be used for 372 running the hooks for this LU. The keys of the dict must not be prefixed 373 with "GANETI_"--that'll be added by the hooks runner. The hooks runner 374 will extend the environment with additional variables. If no environment 375 should be defined, an empty dictionary should be returned (not C{None}). 376 @note: If the C{HPATH} attribute of the LU class is C{None}, this function 377 will not be called. 378 379 """ 380 raise NotImplementedError
381
382 - def BuildHooksNodes(self):
383 """Build list of nodes to run LU's hooks. 384 385 @rtype: tuple; (list, list) 386 @return: Tuple containing a list of node UUIDs on which the hook 387 should run before the execution and a list of node UUIDs on which the 388 hook should run after the execution. 389 No nodes should be returned as an empty list (and not None). 390 @note: If the C{HPATH} attribute of the LU class is C{None}, this function 391 will not be called. 392 393 """ 394 raise NotImplementedError
395
396 - def PreparePostHookNodes(self, post_hook_node_uuids):
397 """Extend list of nodes to run the post LU hook. 398 399 This method allows LUs to change the list of node UUIDs on which the 400 post hook should run after the LU has been executed but before the post 401 hook is run. 402 403 @type post_hook_node_uuids: list 404 @param post_hook_node_uuids: The initial list of node UUIDs to run the 405 post hook on, as returned by L{BuildHooksNodes}. 406 @rtype: list 407 @return: list of node UUIDs on which the post hook should run. The default 408 implementation returns the passed in C{post_hook_node_uuids}, but 409 custom implementations can choose to alter the list. 410 411 """ 412 # For consistency with HooksCallBack we ignore the "could be a function" 413 # warning 414 # pylint: disable=R0201 415 return post_hook_node_uuids
416
417 - def HooksCallBack(self, phase, hook_results, feedback_fn, lu_result):
418 """Notify the LU about the results of its hooks. 419 420 This method is called every time a hooks phase is executed, and notifies 421 the Logical Unit about the hooks' result. The LU can then use it to alter 422 its result based on the hooks. By default the method does nothing and the 423 previous result is passed back unchanged but any LU can define it if it 424 wants to use the local cluster hook-scripts somehow. 425 426 @param phase: one of L{constants.HOOKS_PHASE_POST} or 427 L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase 428 @param hook_results: the results of the multi-node hooks rpc call 429 @param feedback_fn: function used send feedback back to the caller 430 @param lu_result: the previous Exec result this LU had, or None 431 in the PRE phase 432 @return: the new Exec result, based on the previous result 433 and hook results 434 435 """ 436 # API must be kept, thus we ignore the unused argument and could 437 # be a function warnings 438 # pylint: disable=W0613,R0201 439 return lu_result
440
441 - def HooksAbortCallBack(self, phase, feedback_fn, exception):
442 """Called when the hooks get aborted by an exception. 443 444 This method is called everytime a hooks phase is aborted by an exception. 445 This exception is most likely of type C{errors.HooksAbort}. However, we 446 keep the design of this function broad enough to handle any kind of 447 exception. 448 449 The intended purpose of this call back is to run any action that is 450 necessary to bring the cluster back to a clean state from the point 451 in time before calling the hook. 452 453 @type phase: string 454 @param phase: one of L{constants.HOOKS_PHASE_POST} or 455 L{constants.HOOKS_PHASE_PRE}; it denotes the hooks phase 456 @type feedback_fn: callable 457 @param feedback_fn: function used send feedback back to the caller 458 @type exception: Exception 459 @param exception: The exception that was raised during the execution of 460 hooks. 461 462 """ 463 pass
464
465 - def _ExpandAndLockInstance(self, allow_forthcoming=False):
466 """Helper function to expand and lock an instance. 467 468 Many LUs that work on an instance take its name in self.op.instance_name 469 and need to expand it and then declare the expanded name for locking. This 470 function does it, and then updates self.op.instance_name to the expanded 471 name. It also initializes needed_locks as a dict, if this hasn't been done 472 before. 473 474 @param allow_forthcoming: if True, do not insist that the intsance be real; 475 the default behaviour is to raise a prerequisite error if the specified 476 instance is forthcoming. 477 478 """ 479 if self.needed_locks is None: 480 self.needed_locks = {} 481 else: 482 assert locking.LEVEL_INSTANCE not in self.needed_locks, \ 483 "_ExpandAndLockInstance called with instance-level locks set" 484 (self.op.instance_uuid, self.op.instance_name) = \ 485 ExpandInstanceUuidAndName(self.cfg, self.op.instance_uuid, 486 self.op.instance_name) 487 self.needed_locks[locking.LEVEL_INSTANCE] = self.op.instance_name 488 if not allow_forthcoming: 489 if self.cfg.GetInstanceInfo(self.op.instance_uuid).forthcoming: 490 raise errors.OpPrereqError( 491 "forthcoming instances not supported for this operation")
492
493 - def _LockInstancesNodes(self, primary_only=False, 494 level=locking.LEVEL_NODE):
495 """Helper function to declare instances' nodes for locking. 496 497 This function should be called after locking one or more instances to lock 498 their nodes. Its effect is populating self.needed_locks[locking.LEVEL_NODE] 499 with all primary or secondary nodes for instances already locked and 500 present in self.needed_locks[locking.LEVEL_INSTANCE]. 501 502 It should be called from DeclareLocks, and for safety only works if 503 self.recalculate_locks[locking.LEVEL_NODE] is set. 504 505 In the future it may grow parameters to just lock some instance's nodes, or 506 to just lock primaries or secondary nodes, if needed. 507 508 If should be called in DeclareLocks in a way similar to:: 509 510 if level == locking.LEVEL_NODE: 511 self._LockInstancesNodes() 512 513 @type primary_only: boolean 514 @param primary_only: only lock primary nodes of locked instances 515 @param level: Which lock level to use for locking nodes 516 517 """ 518 assert level in self.recalculate_locks, \ 519 "_LockInstancesNodes helper function called with no nodes to recalculate" 520 521 # TODO: check if we're really been called with the instance locks held 522 523 # For now we'll replace self.needed_locks[locking.LEVEL_NODE], but in the 524 # future we might want to have different behaviors depending on the value 525 # of self.recalculate_locks[locking.LEVEL_NODE] 526 wanted_node_uuids = [] 527 locked_i = self.owned_locks(locking.LEVEL_INSTANCE) 528 for _, instance in self.cfg.GetMultiInstanceInfoByName(locked_i): 529 wanted_node_uuids.append(instance.primary_node) 530 if not primary_only: 531 wanted_node_uuids.extend( 532 self.cfg.GetInstanceSecondaryNodes(instance.uuid)) 533 534 if self.recalculate_locks[level] == constants.LOCKS_REPLACE: 535 self.needed_locks[level] = wanted_node_uuids 536 elif self.recalculate_locks[level] == constants.LOCKS_APPEND: 537 self.needed_locks[level].extend(wanted_node_uuids) 538 else: 539 raise errors.ProgrammerError("Unknown recalculation mode") 540 541 del self.recalculate_locks[level]
542
543 - def AssertReleasedLocks(self, level):
544 """Raise AssertionError if the LU holds some locks of the given level. 545 546 """ 547 assert not self.owned_locks(level)
548 549
550 -class NoHooksLU(LogicalUnit): # pylint: disable=W0223
551 """Simple LU which runs no hooks. 552 553 This LU is intended as a parent for other LogicalUnits which will 554 run no hooks, in order to reduce duplicate code. 555 556 """ 557 HPATH = None 558 HTYPE = None 559
560 - def BuildHooksEnv(self):
561 """Empty BuildHooksEnv for NoHooksLu. 562 563 This just raises an error. 564 565 """ 566 raise AssertionError("BuildHooksEnv called for NoHooksLUs")
567
568 - def BuildHooksNodes(self):
569 """Empty BuildHooksNodes for NoHooksLU. 570 571 """ 572 raise AssertionError("BuildHooksNodes called for NoHooksLU")
573
574 - def PreparePostHookNodes(self, post_hook_node_uuids):
575 """Empty PreparePostHookNodes for NoHooksLU. 576 577 """ 578 raise AssertionError("PreparePostHookNodes called for NoHooksLU")
579 580
581 -class Tasklet(object):
582 """Tasklet base class. 583 584 Tasklets are subcomponents for LUs. LUs can consist entirely of tasklets or 585 they can mix legacy code with tasklets. Locking needs to be done in the LU, 586 tasklets know nothing about locks. 587 588 Subclasses must follow these rules: 589 - Implement CheckPrereq 590 - Implement Exec 591 592 """
593 - def __init__(self, lu):
594 self.lu = lu 595 596 # Shortcuts 597 self.cfg = lu.cfg 598 self.rpc = lu.rpc
599
600 - def CheckPrereq(self):
601 """Check prerequisites for this tasklets. 602 603 This method should check whether the prerequisites for the execution of 604 this tasklet are fulfilled. It can do internode communication, but it 605 should be idempotent - no cluster or system changes are allowed. 606 607 The method should raise errors.OpPrereqError in case something is not 608 fulfilled. Its return value is ignored. 609 610 This method should also update all parameters to their canonical form if it 611 hasn't been done before. 612 613 """ 614 pass
615
616 - def Exec(self, feedback_fn):
617 """Execute the tasklet. 618 619 This method should implement the actual work. It should raise 620 errors.OpExecError for failures that are somewhat dealt with in code, or 621 expected. 622 623 """ 624 raise NotImplementedError
625 626
627 -class QueryBase(object):
628 """Base for query utility classes. 629 630 """ 631 #: Attribute holding field definitions 632 FIELDS = None 633 634 #: Field to sort by 635 SORT_FIELD = "name" 636
637 - def __init__(self, qfilter, fields, use_locking):
638 """Initializes this class. 639 640 """ 641 self.use_locking = use_locking 642 643 self.query = query.Query(self.FIELDS, fields, qfilter=qfilter, 644 namefield=self.SORT_FIELD) 645 self.requested_data = self.query.RequestedData() 646 self.names = self.query.RequestedNames() 647 648 # Sort only if no names were requested 649 self.sort_by_name = not self.names 650 651 self.do_locking = None 652 self.wanted = None
653
654 - def _GetNames(self, lu, all_names, lock_level):
655 """Helper function to determine names asked for in the query. 656 657 """ 658 if self.do_locking: 659 names = lu.owned_locks(lock_level) 660 else: 661 names = all_names 662 663 if self.wanted == locking.ALL_SET: 664 assert not self.names 665 # caller didn't specify names, so ordering is not important 666 return utils.NiceSort(names) 667 668 # caller specified names and we must keep the same order 669 assert self.names 670 671 missing = set(self.wanted).difference(names) 672 if missing: 673 raise errors.OpExecError("Some items were removed before retrieving" 674 " their data: %s" % missing) 675 676 # Return expanded names 677 return self.wanted
678
679 - def ExpandNames(self, lu):
680 """Expand names for this query. 681 682 See L{LogicalUnit.ExpandNames}. 683 684 """ 685 raise NotImplementedError()
686
687 - def DeclareLocks(self, lu, level):
688 """Declare locks for this query. 689 690 See L{LogicalUnit.DeclareLocks}. 691 692 """ 693 raise NotImplementedError()
694
695 - def _GetQueryData(self, lu):
696 """Collects all data for this query. 697 698 @return: Query data object 699 700 """ 701 raise NotImplementedError()
702
703 - def NewStyleQuery(self, lu):
704 """Collect data and execute query. 705 706 """ 707 return query.GetQueryResponse(self.query, self._GetQueryData(lu), 708 sort_by_name=self.sort_by_name)
709
710 - def OldStyleQuery(self, lu):
711 """Collect data and execute query. 712 713 """ 714 return self.query.OldStyleQuery(self._GetQueryData(lu), 715 sort_by_name=self.sort_by_name)
716