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