1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 """Module for query operations
32
33 How it works:
34
35 - Add field definitions
36 - See how L{NODE_FIELDS} is built
37 - Each field gets:
38 - Query field definition (L{objects.QueryFieldDefinition}, use
39 L{_MakeField} for creating), containing:
40 - Name, must be lowercase and match L{FIELD_NAME_RE}
41 - Title for tables, must not contain whitespace and match
42 L{TITLE_RE}
43 - Value data type, e.g. L{constants.QFT_NUMBER}
44 - Human-readable description, must not end with punctuation or
45 contain newlines
46 - Data request type, see e.g. C{NQ_*}
47 - OR-ed flags, see C{QFF_*}
48 - A retrieval function, see L{Query.__init__} for description
49 - Pass list of fields through L{_PrepareFieldList} for preparation and
50 checks
51 - Instantiate L{Query} with prepared field list definition and selected fields
52 - Call L{Query.RequestedData} to determine what data to collect/compute
53 - Call L{Query.Query} or L{Query.OldStyleQuery} with collected data and use
54 result
55 - Data container must support iteration using C{__iter__}
56 - Items are passed to retrieval functions and can have any format
57 - Call L{Query.GetFields} to get list of definitions for selected fields
58
59 @attention: Retrieval functions must be idempotent. They can be called multiple
60 times, in any order and any number of times.
61
62 """
63
64 import logging
65 import operator
66 import re
67
68 from ganeti import constants
69 from ganeti import errors
70 from ganeti import utils
71 from ganeti import compat
72 from ganeti import objects
73 from ganeti import ht
74 from ganeti import runtime
75 from ganeti import qlang
76 from ganeti import jstore
77 from ganeti.hypervisor import hv_base
78
79 from ganeti.constants import (QFT_UNKNOWN, QFT_TEXT, QFT_BOOL, QFT_NUMBER,
80 QFT_NUMBER_FLOAT, QFT_UNIT, QFT_TIMESTAMP,
81 QFT_OTHER, RS_NORMAL, RS_UNKNOWN, RS_NODATA,
82 RS_UNAVAIL, RS_OFFLINE)
83
84 (NETQ_CONFIG,
85 NETQ_GROUP,
86 NETQ_STATS,
87 NETQ_INST) = range(300, 304)
88
89
90
91
92
93 (NQ_CONFIG,
94 NQ_INST,
95 NQ_LIVE,
96 NQ_GROUP,
97 NQ_OOB) = range(1, 6)
98
99 (IQ_CONFIG,
100 IQ_LIVE,
101 IQ_DISKUSAGE,
102 IQ_CONSOLE,
103 IQ_NODES,
104 IQ_NETWORKS) = range(100, 106)
105
106 (LQ_MODE,
107 LQ_OWNER,
108 LQ_PENDING) = range(10, 13)
109
110 (GQ_CONFIG,
111 GQ_NODE,
112 GQ_INST,
113 GQ_DISKPARAMS) = range(200, 204)
114
115 (CQ_CONFIG,
116 CQ_QUEUE_DRAINED,
117 CQ_WATCHER_PAUSE) = range(300, 303)
118
119 (JQ_ARCHIVED, ) = range(400, 401)
120
121
122 QFF_HOSTNAME = 0x01
123 QFF_IP_ADDRESS = 0x02
124 QFF_JOB_ID = 0x04
125 QFF_SPLIT_TIMESTAMP = 0x08
126
127 QFF_ALL = (QFF_HOSTNAME | QFF_IP_ADDRESS | QFF_JOB_ID | QFF_SPLIT_TIMESTAMP)
128
129 FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$")
130 TITLE_RE = re.compile(r"^[^\s]+$")
131 DOC_RE = re.compile(r"^[A-Z].*[^.,?!]$")
132
133
134 _VERIFY_FN = {
135 QFT_UNKNOWN: ht.TNone,
136 QFT_TEXT: ht.TString,
137 QFT_BOOL: ht.TBool,
138 QFT_NUMBER: ht.TInt,
139 QFT_NUMBER_FLOAT: ht.TFloat,
140 QFT_UNIT: ht.TInt,
141 QFT_TIMESTAMP: ht.TNumber,
142 QFT_OTHER: lambda _: True,
143 }
144
145
146 _FS_UNKNOWN = object()
147 _FS_NODATA = object()
148 _FS_UNAVAIL = object()
149 _FS_OFFLINE = object()
150
151
152 _FS_ALL = compat.UniqueFrozenset([
153 _FS_UNKNOWN,
154 _FS_NODATA,
155 _FS_UNAVAIL,
156 _FS_OFFLINE,
157 ])
158
159
160 _VTToQFT = {
161
162 constants.VTYPE_STRING: QFT_OTHER,
163 constants.VTYPE_MAYBE_STRING: QFT_OTHER,
164 constants.VTYPE_BOOL: QFT_BOOL,
165 constants.VTYPE_SIZE: QFT_UNIT,
166 constants.VTYPE_INT: QFT_NUMBER,
167 constants.VTYPE_FLOAT: QFT_NUMBER_FLOAT,
168 }
169
170 _SERIAL_NO_DOC = "%s object serial number, incremented on each modification"
171
172
174 """Gets the contents of an unknown field.
175
176 """
177 return _FS_UNKNOWN
178
179
181 """Calculates the internal list of selected fields.
182
183 Unknown fields are returned as L{constants.QFT_UNKNOWN}.
184
185 @type fielddefs: dict
186 @param fielddefs: Field definitions
187 @type selected: list of strings
188 @param selected: List of selected fields
189
190 """
191 result = []
192
193 for name in selected:
194 try:
195 fdef = fielddefs[name]
196 except KeyError:
197 fdef = (_MakeField(name, name, QFT_UNKNOWN, "Unknown field '%s'" % name),
198 None, 0, _GetUnknownField)
199
200 assert len(fdef) == 4
201
202 result.append(fdef)
203
204 return result
205
206
208 """Extract L{objects.QueryFieldDefinition} from field definitions.
209
210 @rtype: list of L{objects.QueryFieldDefinition}
211
212 """
213 return [fdef for (fdef, _, _, _) in fielddefs]
214
215
217 """Class for filter analytics.
218
219 When filters are used, the user of the L{Query} class usually doesn't know
220 exactly which items will be necessary for building the result. It therefore
221 has to prepare and compute the input data for potentially returning
222 everything.
223
224 There are two ways to optimize this. The first, and simpler, is to assign
225 each field a group of data, so that the caller can determine which
226 computations are necessary depending on the data groups requested. The list
227 of referenced groups must also be computed for fields referenced in the
228 filter.
229
230 The second is restricting the items based on a primary key. The primary key
231 is usually a unique name (e.g. a node name). This class extracts all
232 referenced names from a filter. If it encounters any filter condition which
233 disallows such a list to be determined (e.g. a non-equality filter), all
234 names will be requested.
235
236 The end-effect is that any operation other than L{qlang.OP_OR} and
237 L{qlang.OP_EQUAL} will make the query more expensive.
238
239 """
241 """Initializes this class.
242
243 @type namefield: string
244 @param namefield: Field caller is interested in
245
246 """
247 self._namefield = namefield
248
249
250
251 self._allnames = False
252
253
254 self._names = None
255
256
257 self._datakinds = set()
258
260 """Returns all requested values.
261
262 Returns C{None} if list of values can't be determined (e.g. encountered
263 non-equality operators).
264
265 @rtype: list
266
267 """
268 if self._allnames or self._names is None:
269 return None
270
271 return utils.UniqueSequence(self._names)
272
274 """Returns all kinds of data referenced by the filter.
275
276 """
277 return frozenset(self._datakinds)
278
280 """Changes internal state to request all names.
281
282 """
283 self._allnames = True
284 self._names = None
285
287 """Called when handling a logic operation.
288
289 @type op: string
290 @param op: Operator
291
292 """
293 if op != qlang.OP_OR:
294 self._NeedAllNames()
295
297 """Called when handling an unary operation.
298
299 @type op: string
300 @param op: Operator
301
302 """
303 if datakind is not None:
304 self._datakinds.add(datakind)
305
306 self._NeedAllNames()
307
309 """Called when handling a binary operation.
310
311 @type op: string
312 @param op: Operator
313 @type name: string
314 @param name: Left-hand side of operator (field name)
315 @param value: Right-hand side of operator
316
317 """
318 if datakind is not None:
319 self._datakinds.add(datakind)
320
321 if self._allnames:
322 return
323
324
325
326 EQ_OPS = [qlang.OP_EQUAL, qlang.OP_EQUAL_LEGACY]
327 if op in EQ_OPS and name == self._namefield:
328 if self._names is None:
329 self._names = []
330 self._names.append(value)
331 else:
332 self._NeedAllNames()
333
334
336 """Wrapper for logic operator functions.
337
338 """
339 return op_fn(fn(ctx, item) for fn in sentences)
340
341
343 """Wrapper for unary operator functions.
344
345 """
346 return op_fn(inner(ctx, item))
347
348
350 """Wrapper for binary operator functions.
351
352 """
353 return op_fn(retrieval_fn(ctx, item), value)
354
355
357 """Negates the result of a wrapped function.
358
359 """
360 return not fn(lhs, rhs)
361
362
364 """Compiles a regular expression.
365
366 """
367 try:
368 return re.compile(pattern)
369 except re.error, err:
370 raise errors.ParameterError("Invalid regex pattern (%s)" % err)
371
372
374 """Prepares a value for comparison by L{_MakeSplitTimestampComparison}.
375
376 """
377 if ht.TNumber(value):
378 return value
379 else:
380 return utils.MergeTime(value)
381
382
384 """Compares split timestamp values after converting to float.
385
386 """
387 return lambda lhs, rhs: fn(utils.MergeTime(lhs), rhs)
388
389
391 """Prepares flag-specific comparisons using a comparison function.
392
393 """
394 return [
395 (QFF_SPLIT_TIMESTAMP, _MakeSplitTimestampComparison(fn),
396 _PrepareSplitTimestamp),
397 (QFF_JOB_ID, lambda lhs, rhs: fn(jstore.ParseJobId(lhs), rhs),
398 jstore.ParseJobId),
399 (None, fn, None),
400 ]
401
402
404 """Converts a query filter to a callable usable for filtering.
405
406 """
407
408
409
410 _LEVELS_MAX = 10
411
412
413 (_OPTYPE_LOGIC,
414 _OPTYPE_UNARY,
415 _OPTYPE_BINARY) = range(1, 4)
416
417 """Functions for equality checks depending on field flags.
418
419 List of tuples containing flags and a callable receiving the left- and
420 right-hand side of the operator. The flags are an OR-ed value of C{QFF_*}
421 (e.g. L{QFF_HOSTNAME} or L{QFF_SPLIT_TIMESTAMP}).
422
423 Order matters. The first item with flags will be used. Flags are checked
424 using binary AND.
425
426 """
427 _EQUALITY_CHECKS = [
428 (QFF_HOSTNAME,
429 lambda lhs, rhs: utils.MatchNameComponent(rhs, [lhs],
430 case_sensitive=False),
431 None),
432 (QFF_SPLIT_TIMESTAMP, _MakeSplitTimestampComparison(operator.eq),
433 _PrepareSplitTimestamp),
434 (None, operator.eq, None),
435 ]
436
437 """Known operators
438
439 Operator as key (C{qlang.OP_*}), value a tuple of operator group
440 (C{_OPTYPE_*}) and a group-specific value:
441
442 - C{_OPTYPE_LOGIC}: Callable taking any number of arguments; used by
443 L{_HandleLogicOp}
444 - C{_OPTYPE_UNARY}: Always C{None}; details handled by L{_HandleUnaryOp}
445 - C{_OPTYPE_BINARY}: Callable taking exactly two parameters, the left- and
446 right-hand side of the operator, used by L{_HandleBinaryOp}
447
448 """
449 _OPS = {
450
451 qlang.OP_OR: (_OPTYPE_LOGIC, compat.any),
452 qlang.OP_AND: (_OPTYPE_LOGIC, compat.all),
453
454
455 qlang.OP_NOT: (_OPTYPE_UNARY, None),
456 qlang.OP_TRUE: (_OPTYPE_UNARY, None),
457
458
459 qlang.OP_EQUAL: (_OPTYPE_BINARY, _EQUALITY_CHECKS),
460 qlang.OP_EQUAL_LEGACY: (_OPTYPE_BINARY, _EQUALITY_CHECKS),
461 qlang.OP_NOT_EQUAL:
462 (_OPTYPE_BINARY, [(flags, compat.partial(_WrapNot, fn), valprepfn)
463 for (flags, fn, valprepfn) in _EQUALITY_CHECKS]),
464 qlang.OP_LT: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.lt)),
465 qlang.OP_LE: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.le)),
466 qlang.OP_GT: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.gt)),
467 qlang.OP_GE: (_OPTYPE_BINARY, _MakeComparisonChecks(operator.ge)),
468 qlang.OP_REGEXP: (_OPTYPE_BINARY, [
469 (None, lambda lhs, rhs: rhs.search(lhs), _PrepareRegex),
470 ]),
471 qlang.OP_CONTAINS: (_OPTYPE_BINARY, [
472 (None, operator.contains, None),
473 ]),
474 }
475
477 """Initializes this class.
478
479 @param fields: Field definitions (return value of L{_PrepareFieldList})
480
481 """
482 self._fields = fields
483 self._hints = None
484 self._op_handler = None
485
487 """Converts a query filter into a callable function.
488
489 @type hints: L{_FilterHints} or None
490 @param hints: Callbacks doing analysis on filter
491 @type qfilter: list
492 @param qfilter: Filter structure
493 @rtype: callable
494 @return: Function receiving context and item as parameters, returning
495 boolean as to whether item matches filter
496
497 """
498 self._op_handler = {
499 self._OPTYPE_LOGIC:
500 (self._HandleLogicOp, getattr(hints, "NoteLogicOp", None)),
501 self._OPTYPE_UNARY:
502 (self._HandleUnaryOp, getattr(hints, "NoteUnaryOp", None)),
503 self._OPTYPE_BINARY:
504 (self._HandleBinaryOp, getattr(hints, "NoteBinaryOp", None)),
505 }
506
507 try:
508 filter_fn = self._Compile(qfilter, 0)
509 finally:
510 self._op_handler = None
511
512 return filter_fn
513
515 """Inner function for converting filters.
516
517 Calls the correct handler functions for the top-level operator. This
518 function is called recursively (e.g. for logic operators).
519
520 """
521 if not (isinstance(qfilter, (list, tuple)) and qfilter):
522 raise errors.ParameterError("Invalid filter on level %s" % level)
523
524
525 if level >= self._LEVELS_MAX:
526 raise errors.ParameterError("Only up to %s levels are allowed (filter"
527 " nested too deep)" % self._LEVELS_MAX)
528
529
530 operands = qfilter[:]
531 op = operands.pop(0)
532
533 try:
534 (kind, op_data) = self._OPS[op]
535 except KeyError:
536 raise errors.ParameterError("Unknown operator '%s'" % op)
537
538 (handler, hints_cb) = self._op_handler[kind]
539
540 return handler(hints_cb, level, op, op_data, operands)
541
543 """Returns a field definition by name.
544
545 """
546 try:
547 return self._fields[name]
548 except KeyError:
549 raise errors.ParameterError("Unknown field '%s'" % name)
550
552 """Handles logic operators.
553
554 @type hints_fn: callable
555 @param hints_fn: Callback doing some analysis on the filter
556 @type level: integer
557 @param level: Current depth
558 @type op: string
559 @param op: Operator
560 @type op_fn: callable
561 @param op_fn: Function implementing operator
562 @type operands: list
563 @param operands: List of operands
564
565 """
566 if hints_fn:
567 hints_fn(op)
568
569 return compat.partial(_WrapLogicOp, op_fn,
570 [self._Compile(op, level + 1) for op in operands])
571
573 """Handles unary operators.
574
575 @type hints_fn: callable
576 @param hints_fn: Callback doing some analysis on the filter
577 @type level: integer
578 @param level: Current depth
579 @type op: string
580 @param op: Operator
581 @type op_fn: callable
582 @param op_fn: Function implementing operator
583 @type operands: list
584 @param operands: List of operands
585
586 """
587 assert op_fn is None
588
589 if len(operands) != 1:
590 raise errors.ParameterError("Unary operator '%s' expects exactly one"
591 " operand" % op)
592
593 if op == qlang.OP_TRUE:
594 (_, datakind, _, retrieval_fn) = self._LookupField(operands[0])
595
596 if hints_fn:
597 hints_fn(op, datakind)
598
599 op_fn = operator.truth
600 arg = retrieval_fn
601 elif op == qlang.OP_NOT:
602 if hints_fn:
603 hints_fn(op, None)
604
605 op_fn = operator.not_
606 arg = self._Compile(operands[0], level + 1)
607 else:
608 raise errors.ProgrammerError("Can't handle operator '%s'" % op)
609
610 return compat.partial(_WrapUnaryOp, op_fn, arg)
611
613 """Handles binary operators.
614
615 @type hints_fn: callable
616 @param hints_fn: Callback doing some analysis on the filter
617 @type level: integer
618 @param level: Current depth
619 @type op: string
620 @param op: Operator
621 @param op_data: Functions implementing operators
622 @type operands: list
623 @param operands: List of operands
624
625 """
626
627 try:
628 (name, value) = operands
629 except (ValueError, TypeError):
630 raise errors.ParameterError("Invalid binary operator, expected exactly"
631 " two operands")
632
633 (fdef, datakind, field_flags, retrieval_fn) = self._LookupField(name)
634
635 assert fdef.kind != QFT_UNKNOWN
636
637
638
639 verify_fn = _VERIFY_FN[fdef.kind]
640 if not verify_fn(value):
641 raise errors.ParameterError("Unable to compare field '%s' (type '%s')"
642 " with '%s', expected %s" %
643 (name, fdef.kind, value.__class__.__name__,
644 verify_fn))
645
646 if hints_fn:
647 hints_fn(op, datakind, name, value)
648
649 for (fn_flags, fn, valprepfn) in op_data:
650 if fn_flags is None or fn_flags & field_flags:
651
652 if valprepfn:
653 value = valprepfn(value)
654
655 return compat.partial(_WrapBinaryOp, fn, retrieval_fn, value)
656
657 raise errors.ProgrammerError("Unable to find operator implementation"
658 " (op '%s', flags %s)" % (op, field_flags))
659
660
662 """Converts a query filter into a callable function.
663
664 See L{_FilterCompilerHelper} for details.
665
666 @rtype: callable
667
668 """
669 return _FilterCompilerHelper(fields)(hints, qfilter)
670
671
673 - def __init__(self, fieldlist, selected, qfilter=None, namefield=None):
674 """Initializes this class.
675
676 The field definition is a dictionary with the field's name as a key and a
677 tuple containing, in order, the field definition object
678 (L{objects.QueryFieldDefinition}, the data kind to help calling code
679 collect data and a retrieval function. The retrieval function is called
680 with two parameters, in order, the data container and the item in container
681 (see L{Query.Query}).
682
683 Users of this class can call L{RequestedData} before preparing the data
684 container to determine what data is needed.
685
686 @type fieldlist: dictionary
687 @param fieldlist: Field definitions
688 @type selected: list of strings
689 @param selected: List of selected fields
690
691 """
692 assert namefield is None or namefield in fieldlist
693
694 self._fields = _GetQueryFields(fieldlist, selected)
695
696 self._filter_fn = None
697 self._requested_names = None
698 self._filter_datakinds = frozenset()
699
700 if qfilter is not None:
701
702 if namefield:
703 hints = _FilterHints(namefield)
704 else:
705 hints = None
706
707
708 self._filter_fn = _CompileFilter(fieldlist, hints, qfilter)
709 if hints:
710 self._requested_names = hints.RequestedNames()
711 self._filter_datakinds = hints.ReferencedData()
712
713 if namefield is None:
714 self._name_fn = None
715 else:
716 (_, _, _, self._name_fn) = fieldlist[namefield]
717
719 """Returns all names referenced in the filter.
720
721 If there is no filter or operators are preventing determining the exact
722 names, C{None} is returned.
723
724 """
725 return self._requested_names
726
728 """Gets requested kinds of data.
729
730 @rtype: frozenset
731
732 """
733 return (self._filter_datakinds |
734 frozenset(datakind for (_, datakind, _, _) in self._fields
735 if datakind is not None))
736
738 """Returns the list of fields for this query.
739
740 Includes unknown fields.
741
742 @rtype: List of L{objects.QueryFieldDefinition}
743
744 """
745 return GetAllFields(self._fields)
746
747 - def Query(self, ctx, sort_by_name=True):
748 """Execute a query.
749
750 @param ctx: Data container passed to field retrieval functions, must
751 support iteration using C{__iter__}
752 @type sort_by_name: boolean
753 @param sort_by_name: Whether to sort by name or keep the input data's
754 ordering
755
756 """
757 sort = (self._name_fn and sort_by_name)
758
759 result = []
760
761 for idx, item in enumerate(ctx):
762 if not (self._filter_fn is None or self._filter_fn(ctx, item)):
763 continue
764
765 row = [_ProcessResult(fn(ctx, item)) for (_, _, _, fn) in self._fields]
766
767
768 if __debug__:
769 _VerifyResultRow(self._fields, row)
770
771 if sort:
772 (status, name) = _ProcessResult(self._name_fn(ctx, item))
773 assert status == constants.RS_NORMAL
774
775
776 result.append((utils.NiceSortKey(name), idx, row))
777 else:
778 result.append(row)
779
780 if not sort:
781 return result
782
783
784
785
786 result.sort()
787
788 assert not result or (len(result[0]) == 3 and len(result[-1]) == 3)
789
790 return map(operator.itemgetter(2), result)
791
793 """Query with "old" query result format.
794
795 See L{Query.Query} for arguments.
796
797 """
798 unknown = set(fdef.name for (fdef, _, _, _) in self._fields
799 if fdef.kind == QFT_UNKNOWN)
800 if unknown:
801 raise errors.OpPrereqError("Unknown output fields selected: %s" %
802 (utils.CommaJoin(unknown), ),
803 errors.ECODE_INVAL)
804
805 return [[value for (_, value) in row]
806 for row in self.Query(ctx, sort_by_name=sort_by_name)]
807
808
823
824
826 """Verifies the contents of a query result row.
827
828 @type fields: list
829 @param fields: Field definitions for result
830 @type row: list of tuples
831 @param row: Row data
832
833 """
834 assert len(row) == len(fields)
835 errs = []
836 for ((status, value), (fdef, _, _, _)) in zip(row, fields):
837 if status == RS_NORMAL:
838 if not _VERIFY_FN[fdef.kind](value):
839 errs.append("normal field %s fails validation (value is %s)" %
840 (fdef.name, value))
841 elif value is not None:
842 errs.append("abnormal field %s has a non-None value" % fdef.name)
843 assert not errs, ("Failed validation: %s in row %s" %
844 (utils.CommaJoin(errs), row))
845
846
848 """Generates key for field dictionary.
849
850 """
851 assert fdef.name and fdef.title, "Name and title are required"
852 assert FIELD_NAME_RE.match(fdef.name)
853 assert TITLE_RE.match(fdef.title)
854 assert (DOC_RE.match(fdef.doc) and len(fdef.doc.splitlines()) == 1 and
855 fdef.doc.strip() == fdef.doc), \
856 "Invalid description for field '%s'" % fdef.name
857 assert callable(fn)
858 assert (flags & ~QFF_ALL) == 0, "Unknown flags for field '%s'" % fdef.name
859
860 return fdef.name
861
862
864 """Prepares field list for use by L{Query}.
865
866 Converts the list to a dictionary and does some verification.
867
868 @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data
869 kind, retrieval function)
870 @param fields: List of fields, see L{Query.__init__} for a better
871 description
872 @type aliases: list of tuples; (alias, target)
873 @param aliases: list of tuples containing aliases; for each
874 alias/target pair, a duplicate will be created in the field list
875 @rtype: dict
876 @return: Field dictionary for L{Query}
877
878 """
879 if __debug__:
880 duplicates = utils.FindDuplicates(fdef.title.lower()
881 for (fdef, _, _, _) in fields)
882 assert not duplicates, "Duplicate title(s) found: %r" % duplicates
883
884 result = utils.SequenceToDict(fields, key=_FieldDictKey)
885
886 for alias, target in aliases:
887 assert alias not in result, "Alias %s overrides an existing field" % alias
888 assert target in result, "Missing target %s for alias %s" % (target, alias)
889 (fdef, k, flags, fn) = result[target]
890 fdef = fdef.Copy()
891 fdef.name = alias
892 result[alias] = (fdef, k, flags, fn)
893
894 assert len(result) == len(fields) + len(aliases)
895 assert compat.all(name == fdef.name
896 for (name, (fdef, _, _, _)) in result.items())
897
898 return result
899
900
902 """Prepares the response for a query.
903
904 @type query: L{Query}
905 @param ctx: Data container, see L{Query.Query}
906 @type sort_by_name: boolean
907 @param sort_by_name: Whether to sort by name or keep the input data's
908 ordering
909
910 """
911 return objects.QueryResponse(data=query.Query(ctx, sort_by_name=sort_by_name),
912 fields=query.GetFields()).ToDict()
913
914
916 """Returns list of available fields.
917
918 @type fielddefs: dict
919 @param fielddefs: Field definitions
920 @type selected: list of strings
921 @param selected: List of selected fields
922 @return: List of L{objects.QueryFieldDefinition}
923
924 """
925 if selected is None:
926
927 fdefs = utils.NiceSort(GetAllFields(fielddefs.values()),
928 key=operator.attrgetter("name"))
929 else:
930
931 fdefs = Query(fielddefs, selected).GetFields()
932
933 return objects.QueryFieldsResponse(fields=fdefs).ToDict()
934
935
937 """Wrapper for creating L{objects.QueryFieldDefinition} instances.
938
939 @param name: Field name as a regular expression
940 @param title: Human-readable title
941 @param kind: Field type
942 @param doc: Human-readable description
943
944 """
945 return objects.QueryFieldDefinition(name=name, title=title, kind=kind,
946 doc=doc)
947
948
950 """Returns a static value.
951
952 """
953 return value
954
955
961
962
982
983
985 """Returns a field function to return an attribute of the item.
986
987 @param attr: Attribute name
988
989 """
990 getter = operator.attrgetter(attr)
991 return lambda _, item: getter(item)
992
993
995 """Returns a field function to return a not-None attribute of the item.
996
997 If the value is None, then C{_FS_UNAVAIL} will be returned instead.
998
999 @param attr: Attribute name
1000
1001 """
1002 def _helper(_, obj):
1003 val = getattr(obj, attr)
1004 if val is None:
1005 return _FS_UNAVAIL
1006 else:
1007 return val
1008 return _helper
1009
1010
1012 """Return a field function to return an ND parameter out of the context.
1013
1014 """
1015 def _helper(ctx, _):
1016 if ctx.ndparams is None:
1017 return _FS_UNAVAIL
1018 else:
1019 return ctx.ndparams.get(name, None)
1020 return _helper
1021
1022
1039
1040
1042 """Wrapper for converting values.
1043
1044 @param convert: Conversion function receiving value as single parameter
1045 @param fn: Retrieval function
1046
1047 """
1048 value = fn(ctx, item)
1049
1050
1051 if compat.any(value is fs for fs in _FS_ALL):
1052
1053 return value
1054
1055
1056 return convert(value)
1057
1058
1060 """Convenience wrapper for L{_ConvWrapInner}.
1061
1062 @param convert: Conversion function receiving value as single parameter
1063 @param fn: Retrieval function
1064
1065 """
1066 return compat.partial(_ConvWrapInner, convert, fn)
1067
1068
1070 """Returns function for getting timestamp of item.
1071
1072 @type getter: callable
1073 @param getter: Function to retrieve timestamp attribute
1074
1075 """
1076 def fn(_, item):
1077 """Returns a timestamp of item.
1078
1079 """
1080 timestamp = getter(item)
1081 if timestamp is None:
1082
1083 return _FS_UNAVAIL
1084 else:
1085 return timestamp
1086
1087 return fn
1088
1089
1091 """Returns common timestamp fields.
1092
1093 @param datatype: Field data type for use by L{Query.RequestedData}
1094
1095 """
1096 return [
1097 (_MakeField("ctime", "CTime", QFT_TIMESTAMP, "Creation timestamp"),
1098 datatype, 0, _GetItemTimestamp(operator.attrgetter("ctime"))),
1099 (_MakeField("mtime", "MTime", QFT_TIMESTAMP, "Modification timestamp"),
1100 datatype, 0, _GetItemTimestamp(operator.attrgetter("mtime"))),
1101 ]
1102
1103
1105 """Data container for node data queries.
1106
1107 """
1108 - def __init__(self, nodes, live_data, master_uuid, node_to_primary,
1109 node_to_secondary, inst_uuid_to_inst_name, groups, oob_support,
1110 cluster):
1111 """Initializes this class.
1112
1113 """
1114 self.nodes = nodes
1115 self.live_data = live_data
1116 self.master_uuid = master_uuid
1117 self.node_to_primary = node_to_primary
1118 self.node_to_secondary = node_to_secondary
1119 self.inst_uuid_to_inst_name = inst_uuid_to_inst_name
1120 self.groups = groups
1121 self.oob_support = oob_support
1122 self.cluster = cluster
1123
1124
1125 self.curlive_data = None
1126 self.ndparams = None
1127
1129 """Iterate over all nodes.
1130
1131 This function has side-effects and only one instance of the resulting
1132 generator should be used at a time.
1133
1134 """
1135 for node in self.nodes:
1136 group = self.groups.get(node.group, None)
1137 if group is None:
1138 self.ndparams = None
1139 else:
1140 self.ndparams = self.cluster.FillND(node, group)
1141 if self.live_data:
1142 self.curlive_data = self.live_data.get(node.uuid, None)
1143 else:
1144 self.curlive_data = None
1145 yield node
1146
1147
1148
1149 _NODE_SIMPLE_FIELDS = {
1150 "drained": ("Drained", QFT_BOOL, 0, "Whether node is drained"),
1151 "master_candidate": ("MasterC", QFT_BOOL, 0,
1152 "Whether node is a master candidate"),
1153 "master_capable": ("MasterCapable", QFT_BOOL, 0,
1154 "Whether node can become a master candidate"),
1155 "name": ("Node", QFT_TEXT, QFF_HOSTNAME, "Node name"),
1156 "offline": ("Offline", QFT_BOOL, 0, "Whether node is marked offline"),
1157 "serial_no": ("SerialNo", QFT_NUMBER, 0, _SERIAL_NO_DOC % "Node"),
1158 "uuid": ("UUID", QFT_TEXT, 0, "Node UUID"),
1159 "vm_capable": ("VMCapable", QFT_BOOL, 0, "Whether node can host instances"),
1160 }
1161
1162
1163
1164
1165 _NODE_LIVE_FIELDS = {
1166 "bootid": ("BootID", QFT_TEXT, "bootid",
1167 "Random UUID renewed for each system reboot, can be used"
1168 " for detecting reboots by tracking changes"),
1169 "cnodes": ("CNodes", QFT_NUMBER, "cpu_nodes",
1170 "Number of NUMA domains on node (if exported by hypervisor)"),
1171 "cnos": ("CNOs", QFT_NUMBER, "cpu_dom0",
1172 "Number of logical processors used by the node OS (dom0 for Xen)"),
1173 "csockets": ("CSockets", QFT_NUMBER, "cpu_sockets",
1174 "Number of physical CPU sockets (if exported by hypervisor)"),
1175 "ctotal": ("CTotal", QFT_NUMBER, "cpu_total", "Number of logical processors"),
1176 "dfree": ("DFree", QFT_UNIT, "storage_free",
1177 "Available storage space in storage unit"),
1178 "dtotal": ("DTotal", QFT_UNIT, "storage_size",
1179 "Total storage space in storage unit used for instance disk"
1180 " allocation"),
1181 "spfree": ("SpFree", QFT_NUMBER, "spindles_free",
1182 "Available spindles in volume group (exclusive storage only)"),
1183 "sptotal": ("SpTotal", QFT_NUMBER, "spindles_total",
1184 "Total spindles in volume group (exclusive storage only)"),
1185 "mfree": ("MFree", QFT_UNIT, "memory_free",
1186 "Memory available for instance allocations"),
1187 "mnode": ("MNode", QFT_UNIT, "memory_dom0",
1188 "Amount of memory used by node (dom0 for Xen)"),
1189 "mtotal": ("MTotal", QFT_UNIT, "memory_total",
1190 "Total amount of memory of physical machine"),
1191 }
1192
1193
1195 """Build function for calling another function with an node group.
1196
1197 @param cb: The callback to be called with the nodegroup
1198
1199 """
1200 def fn(ctx, node):
1201 """Get group data for a node.
1202
1203 @type ctx: L{NodeQueryData}
1204 @type inst: L{objects.Node}
1205 @param inst: Node object
1206
1207 """
1208 ng = ctx.groups.get(node.group, None)
1209 if ng is None:
1210
1211 return _FS_UNAVAIL
1212
1213 return cb(ctx, node, ng)
1214
1215 return fn
1216
1217
1219 """Returns the name of a node's group.
1220
1221 @type ctx: L{NodeQueryData}
1222 @type node: L{objects.Node}
1223 @param node: Node object
1224 @type ng: L{objects.NodeGroup}
1225 @param ng: The node group this node belongs to
1226
1227 """
1228 return ng.name
1229
1230
1232 """Returns the node powered state
1233
1234 @type ctx: L{NodeQueryData}
1235 @type node: L{objects.Node}
1236 @param node: Node object
1237
1238 """
1239 if ctx.oob_support[node.uuid]:
1240 return node.powered
1241
1242 return _FS_UNAVAIL
1243
1244
1246 """Returns the ndparams for this node.
1247
1248 @type ctx: L{NodeQueryData}
1249 @type node: L{objects.Node}
1250 @param node: Node object
1251 @type ng: L{objects.NodeGroup}
1252 @param ng: The node group this node belongs to
1253
1254 """
1255 return ctx.cluster.SimpleFillND(ng.FillND(node))
1256
1257
1259 """Gets the value of a "live" field from L{NodeQueryData}.
1260
1261 @param field: Live field name
1262 @param kind: Data kind, one of L{constants.QFT_ALL}
1263 @type ctx: L{NodeQueryData}
1264 @type node: L{objects.Node}
1265 @param node: Node object
1266
1267 """
1268 if node.offline:
1269 return _FS_OFFLINE
1270
1271 if not node.vm_capable:
1272 return _FS_UNAVAIL
1273
1274 if not ctx.curlive_data:
1275 return _FS_NODATA
1276
1277 return _GetStatsField(field, kind, ctx.curlive_data)
1278
1279
1281 """Gets a value from live statistics.
1282
1283 If the value is not found, L{_FS_UNAVAIL} is returned. If the field kind is
1284 numeric a conversion to integer is attempted. If that fails, L{_FS_UNAVAIL}
1285 is returned.
1286
1287 @param field: Live field name
1288 @param kind: Data kind, one of L{constants.QFT_ALL}
1289 @type data: dict
1290 @param data: Statistics
1291
1292 """
1293 try:
1294 value = data[field]
1295 except KeyError:
1296 return _FS_UNAVAIL
1297
1298 if kind == QFT_TEXT:
1299 return value
1300
1301 assert kind in (QFT_NUMBER, QFT_UNIT)
1302
1303
1304 try:
1305 return int(value)
1306 except (ValueError, TypeError):
1307 logging.exception("Failed to convert node field '%s' (value %r) to int",
1308 field, value)
1309 return _FS_UNAVAIL
1310
1311
1313 """Builds list of fields for node queries.
1314
1315 """
1316 fields = [
1317 (_MakeField("pip", "PrimaryIP", QFT_TEXT, "Primary IP address"),
1318 NQ_CONFIG, 0, _GetItemAttr("primary_ip")),
1319 (_MakeField("sip", "SecondaryIP", QFT_TEXT, "Secondary IP address"),
1320 NQ_CONFIG, 0, _GetItemAttr("secondary_ip")),
1321 (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), NQ_CONFIG, 0,
1322 lambda ctx, node: list(node.GetTags())),
1323 (_MakeField("master", "IsMaster", QFT_BOOL, "Whether node is master"),
1324 NQ_CONFIG, 0, lambda ctx, node: node.uuid == ctx.master_uuid),
1325 (_MakeField("group", "Group", QFT_TEXT, "Node group"), NQ_GROUP, 0,
1326 _GetGroup(_GetNodeGroup)),
1327 (_MakeField("group.uuid", "GroupUUID", QFT_TEXT, "UUID of node group"),
1328 NQ_CONFIG, 0, _GetItemAttr("group")),
1329 (_MakeField("powered", "Powered", QFT_BOOL,
1330 "Whether node is thought to be powered on"),
1331 NQ_OOB, 0, _GetNodePower),
1332 (_MakeField("ndparams", "NodeParameters", QFT_OTHER,
1333 "Merged node parameters"),
1334 NQ_GROUP, 0, _GetGroup(_GetNdParams)),
1335 (_MakeField("custom_ndparams", "CustomNodeParameters", QFT_OTHER,
1336 "Custom node parameters"),
1337 NQ_GROUP, 0, _GetItemAttr("ndparams")),
1338
1339
1340 (_MakeField("hv_state", "HypervisorState", QFT_OTHER,
1341 "Static hypervisor state for default hypervisor only"),
1342 NQ_CONFIG, 0, _GetItemAttr("hv_state_static")),
1343 (_MakeField("custom_hv_state", "CustomHypervisorState", QFT_OTHER,
1344 "Custom static hypervisor state"),
1345 NQ_CONFIG, 0, _GetItemAttr("hv_state_static")),
1346 (_MakeField("disk_state", "DiskState", QFT_OTHER, "Disk state"),
1347 NQ_CONFIG, 0, _GetItemAttr("disk_state_static")),
1348 ]
1349
1350 fields.extend(_BuildNDFields(False))
1351
1352
1353 role_values = (constants.NR_MASTER, constants.NR_MCANDIDATE,
1354 constants.NR_REGULAR, constants.NR_DRAINED,
1355 constants.NR_OFFLINE)
1356 role_doc = ("Node role; \"%s\" for master, \"%s\" for master candidate,"
1357 " \"%s\" for regular, \"%s\" for drained, \"%s\" for offline" %
1358 role_values)
1359 fields.append((_MakeField("role", "Role", QFT_TEXT, role_doc), NQ_CONFIG, 0,
1360 lambda ctx, node: _GetNodeRole(node, ctx.master_uuid)))
1361 assert set(role_values) == constants.NR_ALL
1362
1363 def _GetLength(getter):
1364 return lambda ctx, node: len(getter(ctx)[node.uuid])
1365
1366 def _GetList(getter):
1367 return lambda ctx, node: utils.NiceSort(
1368 [ctx.inst_uuid_to_inst_name[uuid]
1369 for uuid in getter(ctx)[node.uuid]])
1370
1371
1372 for prefix, titleprefix, docword, getter in \
1373 [("p", "Pri", "primary", operator.attrgetter("node_to_primary")),
1374 ("s", "Sec", "secondary", operator.attrgetter("node_to_secondary"))]:
1375
1376 fields.extend([
1377 (_MakeField("%sinst_cnt" % prefix, "%sinst" % prefix.upper(), QFT_NUMBER,
1378 "Number of instances with this node as %s" % docword),
1379 NQ_INST, 0, _GetLength(getter)),
1380 (_MakeField("%sinst_list" % prefix, "%sInstances" % titleprefix,
1381 QFT_OTHER,
1382 "List of instances with this node as %s" % docword),
1383 NQ_INST, 0, _GetList(getter)),
1384 ])
1385
1386
1387 fields.extend([
1388 (_MakeField(name, title, kind, doc), NQ_CONFIG, flags, _GetItemAttr(name))
1389 for (name, (title, kind, flags, doc)) in _NODE_SIMPLE_FIELDS.items()])
1390
1391
1392 fields.extend([
1393 (_MakeField(name, title, kind, doc), NQ_LIVE, 0,
1394 compat.partial(_GetLiveNodeField, nfield, kind))
1395 for (name, (title, kind, nfield, doc)) in _NODE_LIVE_FIELDS.items()])
1396
1397
1398 fields.extend(_GetItemTimestampFields(NQ_CONFIG))
1399
1400 return _PrepareFieldList(fields, [])
1401
1402
1404 """Data container for instance data queries.
1405
1406 """
1407 - def __init__(self, instances, cluster, disk_usage, offline_node_uuids,
1408 bad_node_uuids, live_data, wrongnode_inst, console, nodes,
1409 groups, networks):
1410 """Initializes this class.
1411
1412 @param instances: List of instance objects
1413 @param cluster: Cluster object
1414 @type disk_usage: dict; instance UUID as key
1415 @param disk_usage: Per-instance disk usage
1416 @type offline_node_uuids: list of strings
1417 @param offline_node_uuids: List of offline nodes
1418 @type bad_node_uuids: list of strings
1419 @param bad_node_uuids: List of faulty nodes
1420 @type live_data: dict; instance UUID as key
1421 @param live_data: Per-instance live data
1422 @type wrongnode_inst: set
1423 @param wrongnode_inst: Set of instances running on wrong node(s)
1424 @type console: dict; instance UUID as key
1425 @param console: Per-instance console information
1426 @type nodes: dict; node UUID as key
1427 @param nodes: Node objects
1428 @type networks: dict; net_uuid as key
1429 @param networks: Network objects
1430
1431 """
1432 assert len(set(bad_node_uuids) & set(offline_node_uuids)) == \
1433 len(offline_node_uuids), \
1434 "Offline nodes not included in bad nodes"
1435 assert not (set(live_data.keys()) & set(bad_node_uuids)), \
1436 "Found live data for bad or offline nodes"
1437
1438 self.instances = instances
1439 self.cluster = cluster
1440 self.disk_usage = disk_usage
1441 self.offline_nodes = offline_node_uuids
1442 self.bad_nodes = bad_node_uuids
1443 self.live_data = live_data
1444 self.wrongnode_inst = wrongnode_inst
1445 self.console = console
1446 self.nodes = nodes
1447 self.groups = groups
1448 self.networks = networks
1449
1450
1451 self.inst_hvparams = None
1452 self.inst_beparams = None
1453 self.inst_osparams = None
1454 self.inst_nicparams = None
1455
1457 """Iterate over all instances.
1458
1459 This function has side-effects and only one instance of the resulting
1460 generator should be used at a time.
1461
1462 """
1463 for inst in self.instances:
1464 self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
1465 self.inst_beparams = self.cluster.FillBE(inst)
1466 self.inst_osparams = self.cluster.SimpleFillOS(inst.os, inst.osparams)
1467 self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
1468 for nic in inst.nics]
1469
1470 yield inst
1471
1472
1474 """Get instance's operational status.
1475
1476 @type ctx: L{InstanceQueryData}
1477 @type inst: L{objects.Instance}
1478 @param inst: Instance object
1479
1480 """
1481
1482
1483 if inst.primary_node in ctx.bad_nodes:
1484 return _FS_NODATA
1485 else:
1486 return bool(ctx.live_data.get(inst.uuid))
1487
1488
1490 """Build function for retrieving live data.
1491
1492 @type name: string
1493 @param name: Live data field name
1494
1495 """
1496 def fn(ctx, inst):
1497 """Get live data for an instance.
1498
1499 @type ctx: L{InstanceQueryData}
1500 @type inst: L{objects.Instance}
1501 @param inst: Instance object
1502
1503 """
1504 if (inst.primary_node in ctx.bad_nodes or
1505 inst.primary_node in ctx.offline_nodes):
1506
1507
1508 return _FS_NODATA
1509
1510 if inst.uuid in ctx.live_data:
1511 data = ctx.live_data[inst.uuid]
1512 if name in data:
1513 return data[name]
1514
1515 return _FS_UNAVAIL
1516
1517 return fn
1518
1519
1543
1544
1555
1556
1558 """Get instance status.
1559
1560 @type ctx: L{InstanceQueryData}
1561 @type inst: L{objects.Instance}
1562 @param inst: Instance object
1563
1564 """
1565 if inst.primary_node in ctx.offline_nodes:
1566 return constants.INSTST_NODEOFFLINE
1567
1568 if inst.primary_node in ctx.bad_nodes:
1569 return constants.INSTST_NODEDOWN
1570
1571 instance_live_data = ctx.live_data.get(inst.uuid)
1572
1573 if bool(instance_live_data):
1574 return _GetLiveInstStatus(ctx, inst, instance_live_data["state"])
1575 else:
1576 return _GetDeadInstStatus(inst)
1577
1578
1580 """Build function for calling another function with an instance Disk.
1581
1582 @type index: int
1583 @param index: Disk index
1584 @type cb: callable
1585 @param cb: Callback
1586
1587 """
1588 def fn(ctx, inst):
1589 """Call helper function with instance Disk.
1590
1591 @type ctx: L{InstanceQueryData}
1592 @type inst: L{objects.Instance}
1593 @param inst: Instance object
1594
1595 """
1596 try:
1597 nic = inst.disks[index]
1598 except IndexError:
1599 return _FS_UNAVAIL
1600
1601 return cb(ctx, index, nic)
1602
1603 return fn
1604
1605
1607 """Get a Disk's size.
1608
1609 @type ctx: L{InstanceQueryData}
1610 @type disk: L{objects.Disk}
1611 @param disk: The Disk object
1612
1613 """
1614 if disk.size is None:
1615 return _FS_UNAVAIL
1616 else:
1617 return disk.size
1618
1619
1621 """Get a Disk's spindles.
1622
1623 @type disk: L{objects.Disk}
1624 @param disk: The Disk object
1625
1626 """
1627 if disk.spindles is None:
1628 return _FS_UNAVAIL
1629 else:
1630 return disk.spindles
1631
1632
1634 """Get a Device's Name.
1635
1636 @type ctx: L{InstanceQueryData}
1637 @type device: L{objects.NIC} or L{objects.Disk}
1638 @param device: The NIC or Disk object
1639
1640 """
1641 if device.name is None:
1642 return _FS_UNAVAIL
1643 else:
1644 return device.name
1645
1646
1648 """Get a Device's UUID.
1649
1650 @type ctx: L{InstanceQueryData}
1651 @type device: L{objects.NIC} or L{objects.Disk}
1652 @param device: The NIC or Disk object
1653
1654 """
1655 if device.uuid is None:
1656 return _FS_UNAVAIL
1657 else:
1658 return device.uuid
1659
1660
1662 """Build function for calling another function with an instance NIC.
1663
1664 @type index: int
1665 @param index: NIC index
1666 @type cb: callable
1667 @param cb: Callback
1668
1669 """
1670 def fn(ctx, inst):
1671 """Call helper function with instance NIC.
1672
1673 @type ctx: L{InstanceQueryData}
1674 @type inst: L{objects.Instance}
1675 @param inst: Instance object
1676
1677 """
1678 try:
1679 nic = inst.nics[index]
1680 except IndexError:
1681 return _FS_UNAVAIL
1682
1683 return cb(ctx, index, nic)
1684
1685 return fn
1686
1687
1689 """Get a NIC's Network.
1690
1691 @type ctx: L{InstanceQueryData}
1692 @type nic: L{objects.NIC}
1693 @param nic: NIC object
1694
1695 """
1696 if nic.network is None:
1697 return _FS_UNAVAIL
1698 else:
1699 return ctx.networks[nic.network].name
1700
1701
1703 """Get a NIC's Network.
1704
1705 @type ctx: L{InstanceQueryData}
1706 @type nic: L{objects.NIC}
1707 @param nic: NIC object
1708
1709 """
1710 if nic.network is None:
1711 return _FS_UNAVAIL
1712 else:
1713 return nic.network
1714
1715
1717 """Get a NIC's IP address.
1718
1719 @type ctx: L{InstanceQueryData}
1720 @type nic: L{objects.NIC}
1721 @param nic: NIC object
1722
1723 """
1724 if nic.ip is None:
1725 return _FS_UNAVAIL
1726 else:
1727 return nic.ip
1728
1729
1731 """Get a NIC's bridge.
1732
1733 @type ctx: L{InstanceQueryData}
1734 @type index: int
1735 @param index: NIC index
1736
1737 """
1738 assert len(ctx.inst_nicparams) >= index
1739
1740 nicparams = ctx.inst_nicparams[index]
1741
1742 if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1743 return nicparams[constants.NIC_LINK]
1744 else:
1745 return _FS_UNAVAIL
1746
1747
1749 """Get a NIC's VLAN.
1750
1751 @type ctx: L{InstanceQueryData}
1752 @type index: int
1753 @param index: NIC index
1754
1755 """
1756 assert len(ctx.inst_nicparams) >= index
1757
1758 nicparams = ctx.inst_nicparams[index]
1759
1760 if nicparams[constants.NIC_MODE] == constants.NIC_MODE_OVS:
1761 return nicparams[constants.NIC_VLAN]
1762 else:
1763 return _FS_UNAVAIL
1764
1765
1767 """Get all network names for an instance.
1768
1769 @type ctx: L{InstanceQueryData}
1770 @type inst: L{objects.Instance}
1771 @param inst: Instance object
1772
1773 """
1774 result = []
1775
1776 for nic in inst.nics:
1777 name = None
1778 if nic.network:
1779 name = ctx.networks[nic.network].name
1780 result.append(name)
1781
1782 assert len(result) == len(inst.nics)
1783
1784 return result
1785
1786
1788 """Get all network VLANs for an instance.
1789
1790 @type ctx: L{InstanceQueryData}
1791 @type inst: L{objects.Instance}
1792 @param inst: Instance object
1793
1794 """
1795 assert len(ctx.inst_nicparams) == len(inst.nics)
1796
1797 result = []
1798
1799 for nicp in ctx.inst_nicparams:
1800 if nicp[constants.NIC_MODE] in \
1801 [constants.NIC_MODE_BRIDGED, constants.NIC_MODE_OVS]:
1802 result.append(nicp[constants.NIC_VLAN])
1803 else:
1804 result.append(None)
1805
1806 assert len(result) == len(inst.nics)
1807
1808 return result
1809
1810
1812 """Get all network bridges for an instance.
1813
1814 @type ctx: L{InstanceQueryData}
1815 @type inst: L{objects.Instance}
1816 @param inst: Instance object
1817
1818 """
1819 assert len(ctx.inst_nicparams) == len(inst.nics)
1820
1821 result = []
1822
1823 for nicp in ctx.inst_nicparams:
1824 if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1825 result.append(nicp[constants.NIC_LINK])
1826 else:
1827 result.append(None)
1828
1829 assert len(result) == len(inst.nics)
1830
1831 return result
1832
1833
1835 """Build function for retrieving a NIC parameter.
1836
1837 @type name: string
1838 @param name: Parameter name
1839
1840 """
1841 def fn(ctx, index, _):
1842 """Get a NIC's bridge.
1843
1844 @type ctx: L{InstanceQueryData}
1845 @type inst: L{objects.Instance}
1846 @param inst: Instance object
1847 @type nic: L{objects.NIC}
1848 @param nic: NIC object
1849
1850 """
1851 assert len(ctx.inst_nicparams) >= index
1852 return ctx.inst_nicparams[index][name]
1853
1854 return fn
1855
1856
1858 """Get instance fields involving network interfaces.
1859
1860 @return: Tuple containing list of field definitions used as input for
1861 L{_PrepareFieldList} and a list of aliases
1862
1863 """
1864 nic_mac_fn = lambda ctx, _, nic: nic.mac
1865 nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
1866 nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
1867
1868 fields = [
1869
1870 (_MakeField("nic.count", "NICs", QFT_NUMBER,
1871 "Number of network interfaces"),
1872 IQ_CONFIG, 0, lambda ctx, inst: len(inst.nics)),
1873 (_MakeField("nic.macs", "NIC_MACs", QFT_OTHER,
1874 "List containing each network interface's MAC address"),
1875 IQ_CONFIG, 0, lambda ctx, inst: [nic.mac for nic in inst.nics]),
1876 (_MakeField("nic.ips", "NIC_IPs", QFT_OTHER,
1877 "List containing each network interface's IP address"),
1878 IQ_CONFIG, 0, lambda ctx, inst: [nic.ip for nic in inst.nics]),
1879 (_MakeField("nic.names", "NIC_Names", QFT_OTHER,
1880 "List containing each network interface's name"),
1881 IQ_CONFIG, 0, lambda ctx, inst: [nic.name for nic in inst.nics]),
1882 (_MakeField("nic.uuids", "NIC_UUIDs", QFT_OTHER,
1883 "List containing each network interface's UUID"),
1884 IQ_CONFIG, 0, lambda ctx, inst: [nic.uuid for nic in inst.nics]),
1885 (_MakeField("nic.modes", "NIC_modes", QFT_OTHER,
1886 "List containing each network interface's mode"), IQ_CONFIG, 0,
1887 lambda ctx, inst: [nicp[constants.NIC_MODE]
1888 for nicp in ctx.inst_nicparams]),
1889 (_MakeField("nic.links", "NIC_links", QFT_OTHER,
1890 "List containing each network interface's link"), IQ_CONFIG, 0,
1891 lambda ctx, inst: [nicp[constants.NIC_LINK]
1892 for nicp in ctx.inst_nicparams]),
1893 (_MakeField("nic.vlans", "NIC_VLANs", QFT_OTHER,
1894 "List containing each network interface's VLAN"),
1895 IQ_CONFIG, 0, _GetInstAllNicVlans),
1896 (_MakeField("nic.bridges", "NIC_bridges", QFT_OTHER,
1897 "List containing each network interface's bridge"),
1898 IQ_CONFIG, 0, _GetInstAllNicBridges),
1899 (_MakeField("nic.networks", "NIC_networks", QFT_OTHER,
1900 "List containing each interface's network"), IQ_CONFIG, 0,
1901 lambda ctx, inst: [nic.network for nic in inst.nics]),
1902 (_MakeField("nic.networks.names", "NIC_networks_names", QFT_OTHER,
1903 "List containing each interface's network"),
1904 IQ_NETWORKS, 0, _GetInstAllNicNetworkNames)
1905 ]
1906
1907
1908 for i in range(constants.MAX_NICS):
1909 numtext = utils.FormatOrdinal(i + 1)
1910 fields.extend([
1911 (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, QFT_TEXT,
1912 "IP address of %s network interface" % numtext),
1913 IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicIp)),
1914 (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, QFT_TEXT,
1915 "MAC address of %s network interface" % numtext),
1916 IQ_CONFIG, 0, _GetInstNic(i, nic_mac_fn)),
1917 (_MakeField("nic.name/%s" % i, "NicName/%s" % i, QFT_TEXT,
1918 "Name address of %s network interface" % numtext),
1919 IQ_CONFIG, 0, _GetInstNic(i, _GetInstDeviceName)),
1920 (_MakeField("nic.uuid/%s" % i, "NicUUID/%s" % i, QFT_TEXT,
1921 "UUID address of %s network interface" % numtext),
1922 IQ_CONFIG, 0, _GetInstNic(i, _GetInstDeviceUUID)),
1923 (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, QFT_TEXT,
1924 "Mode of %s network interface" % numtext),
1925 IQ_CONFIG, 0, _GetInstNic(i, nic_mode_fn)),
1926 (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, QFT_TEXT,
1927 "Link of %s network interface" % numtext),
1928 IQ_CONFIG, 0, _GetInstNic(i, nic_link_fn)),
1929 (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, QFT_TEXT,
1930 "Bridge of %s network interface" % numtext),
1931 IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicBridge)),
1932 (_MakeField("nic.vlan/%s" % i, "NicVLAN/%s" % i, QFT_TEXT,
1933 "VLAN of %s network interface" % numtext),
1934 IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicVLan)),
1935 (_MakeField("nic.network/%s" % i, "NicNetwork/%s" % i, QFT_TEXT,
1936 "Network of %s network interface" % numtext),
1937 IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicNetwork)),
1938 (_MakeField("nic.network.name/%s" % i, "NicNetworkName/%s" % i, QFT_TEXT,
1939 "Network name of %s network interface" % numtext),
1940 IQ_NETWORKS, 0, _GetInstNic(i, _GetInstNicNetworkName)),
1941 ])
1942
1943 aliases = [
1944
1945 ("ip", "nic.ip/0"),
1946 ("mac", "nic.mac/0"),
1947 ("bridge", "nic.bridge/0"),
1948 ("nic_mode", "nic.mode/0"),
1949 ("nic_link", "nic.link/0"),
1950 ("nic_network", "nic.network/0"),
1951 ]
1952
1953 return (fields, aliases)
1954
1955
1957 """Get disk usage for an instance.
1958
1959 @type ctx: L{InstanceQueryData}
1960 @type inst: L{objects.Instance}
1961 @param inst: Instance object
1962
1963 """
1964 usage = ctx.disk_usage[inst.uuid]
1965
1966 if usage is None:
1967 usage = 0
1968
1969 return usage
1970
1971
1973 """Get console information for instance.
1974
1975 @type ctx: L{InstanceQueryData}
1976 @type inst: L{objects.Instance}
1977 @param inst: Instance object
1978
1979 """
1980 consinfo = ctx.console[inst.uuid]
1981
1982 if consinfo is None:
1983 return _FS_UNAVAIL
1984
1985 return consinfo
1986
1987
1989 """Get instance fields involving disks.
1990
1991 @return: List of field definitions used as input for L{_PrepareFieldList}
1992
1993 """
1994 fields = [
1995 (_MakeField("disk_usage", "DiskUsage", QFT_UNIT,
1996 "Total disk space used by instance on each of its nodes;"
1997 " this is not the disk size visible to the instance, but"
1998 " the usage on the node"),
1999 IQ_DISKUSAGE, 0, _GetInstDiskUsage),
2000 (_MakeField("disk.count", "Disks", QFT_NUMBER, "Number of disks"),
2001 IQ_CONFIG, 0, lambda ctx, inst: len(inst.disks)),
2002 (_MakeField("disk.sizes", "Disk_sizes", QFT_OTHER, "List of disk sizes"),
2003 IQ_CONFIG, 0, lambda ctx, inst: [disk.size for disk in inst.disks]),
2004 (_MakeField("disk.spindles", "Disk_spindles", QFT_OTHER,
2005 "List of disk spindles"),
2006 IQ_CONFIG, 0, lambda ctx, inst: [disk.spindles for disk in inst.disks]),
2007 (_MakeField("disk.names", "Disk_names", QFT_OTHER, "List of disk names"),
2008 IQ_CONFIG, 0, lambda ctx, inst: [disk.name for disk in inst.disks]),
2009 (_MakeField("disk.uuids", "Disk_UUIDs", QFT_OTHER, "List of disk UUIDs"),
2010 IQ_CONFIG, 0, lambda ctx, inst: [disk.uuid for disk in inst.disks]),
2011 (_MakeField("disk.storage_ids", "Disk_storage_ids", QFT_OTHER,
2012 "List of disk storage ids"),
2013 IQ_CONFIG, 0, lambda ctx, inst: [disk.storage_id for disk in inst.disks]),
2014 (_MakeField("disk.providers", "Disk_providers", QFT_OTHER,
2015 "List of disk ExtStorage providers"),
2016 IQ_CONFIG, 0, lambda ctx, inst: [disk.provider for disk in inst.disks]),
2017 ]
2018
2019
2020 for i in range(constants.MAX_DISKS):
2021 numtext = utils.FormatOrdinal(i + 1)
2022 fields.extend([
2023 (_MakeField("disk.size/%s" % i, "Disk/%s" % i, QFT_UNIT,
2024 "Disk size of %s disk" % numtext),
2025 IQ_CONFIG, 0, _GetInstDisk(i, _GetInstDiskSize)),
2026 (_MakeField("disk.spindles/%s" % i, "DiskSpindles/%s" % i, QFT_NUMBER,
2027 "Spindles of %s disk" % numtext),
2028 IQ_CONFIG, 0, _GetInstDisk(i, _GetInstDiskSpindles)),
2029 (_MakeField("disk.name/%s" % i, "DiskName/%s" % i, QFT_TEXT,
2030 "Name of %s disk" % numtext),
2031 IQ_CONFIG, 0, _GetInstDisk(i, _GetInstDeviceName)),
2032 (_MakeField("disk.uuid/%s" % i, "DiskUUID/%s" % i, QFT_TEXT,
2033 "UUID of %s disk" % numtext),
2034 IQ_CONFIG, 0, _GetInstDisk(i, _GetInstDeviceUUID))])
2035
2036 return fields
2037
2038
2040 """Get instance fields involving parameters.
2041
2042 @return: List of field definitions used as input for L{_PrepareFieldList}
2043
2044 """
2045 fields = [
2046
2047 (_MakeField("hvparams", "HypervisorParameters", QFT_OTHER,
2048 "Hypervisor parameters (merged)"),
2049 IQ_CONFIG, 0, lambda ctx, _: ctx.inst_hvparams),
2050 (_MakeField("beparams", "BackendParameters", QFT_OTHER,
2051 "Backend parameters (merged)"),
2052 IQ_CONFIG, 0, lambda ctx, _: ctx.inst_beparams),
2053 (_MakeField("osparams", "OpSysParameters", QFT_OTHER,
2054 "Operating system parameters (merged)"),
2055 IQ_CONFIG, 0, lambda ctx, _: ctx.inst_osparams),
2056
2057
2058 (_MakeField("custom_hvparams", "CustomHypervisorParameters", QFT_OTHER,
2059 "Custom hypervisor parameters"),
2060 IQ_CONFIG, 0, _GetItemAttr("hvparams")),
2061 (_MakeField("custom_beparams", "CustomBackendParameters", QFT_OTHER,
2062 "Custom backend parameters",),
2063 IQ_CONFIG, 0, _GetItemAttr("beparams")),
2064 (_MakeField("custom_osparams", "CustomOpSysParameters", QFT_OTHER,
2065 "Custom operating system parameters",),
2066 IQ_CONFIG, 0, _GetItemAttr("osparams")),
2067 (_MakeField("custom_nicparams", "CustomNicParameters", QFT_OTHER,
2068 "Custom network interface parameters"),
2069 IQ_CONFIG, 0, lambda ctx, inst: [nic.nicparams for nic in inst.nics]),
2070 ]
2071
2072
2073 def _GetInstHvParam(name):
2074 return lambda ctx, _: ctx.inst_hvparams.get(name, _FS_UNAVAIL)
2075
2076 fields.extend([
2077 (_MakeField("hv/%s" % name,
2078 constants.HVS_PARAMETER_TITLES.get(name, "hv/%s" % name),
2079 _VTToQFT[kind], "The \"%s\" hypervisor parameter" % name),
2080 IQ_CONFIG, 0, _GetInstHvParam(name))
2081 for name, kind in constants.HVS_PARAMETER_TYPES.items()
2082 if name not in constants.HVC_GLOBALS])
2083
2084
2085 def _GetInstBeParam(name):
2086 return lambda ctx, _: ctx.inst_beparams.get(name, None)
2087
2088 fields.extend([
2089 (_MakeField("be/%s" % name,
2090 constants.BES_PARAMETER_TITLES.get(name, "be/%s" % name),
2091 _VTToQFT[kind], "The \"%s\" backend parameter" % name),
2092 IQ_CONFIG, 0, _GetInstBeParam(name))
2093 for name, kind in constants.BES_PARAMETER_TYPES.items()])
2094
2095 return fields
2096
2097
2098 _INST_SIMPLE_FIELDS = {
2099 "disk_template": ("Disk_template", QFT_TEXT, 0, "Instance disk template"),
2100 "hypervisor": ("Hypervisor", QFT_TEXT, 0, "Hypervisor name"),
2101 "name": ("Instance", QFT_TEXT, QFF_HOSTNAME, "Instance name"),
2102
2103 "network_port": ("Network_port", QFT_OTHER, 0,
2104 "Instance network port if available (e.g. for VNC console)"),
2105 "os": ("OS", QFT_TEXT, 0, "Operating system"),
2106 "serial_no": ("SerialNo", QFT_NUMBER, 0, _SERIAL_NO_DOC % "Instance"),
2107 "uuid": ("UUID", QFT_TEXT, 0, "Instance UUID"),
2108 }
2109
2110
2112 """Gets node name of a node.
2113
2114 @type ctx: L{InstanceQueryData}
2115 @param default: Default value
2116 @type node_uuid: string
2117 @param node_uuid: Node UUID
2118
2119 """
2120 try:
2121 node = ctx.nodes[node_uuid]
2122 except KeyError:
2123 return default
2124 else:
2125 return node.name
2126
2127
2129 """Gets group UUID of an instance node.
2130
2131 @type ctx: L{InstanceQueryData}
2132 @param default: Default value
2133 @type node_uuid: string
2134 @param node_uuid: Node UUID
2135
2136 """
2137 try:
2138 node = ctx.nodes[node_uuid]
2139 except KeyError:
2140 return default
2141 else:
2142 return node.group
2143
2144
2146 """Gets group name of an instance node.
2147
2148 @type ctx: L{InstanceQueryData}
2149 @param default: Default value
2150 @type node_uuid: string
2151 @param node_uuid: Node UUID
2152
2153 """
2154 try:
2155 node = ctx.nodes[node_uuid]
2156 except KeyError:
2157 return default
2158
2159 try:
2160 group = ctx.groups[node.group]
2161 except KeyError:
2162 return default
2163
2164 return group.name
2165
2166
2168 """Builds list of fields for instance queries.
2169
2170 """
2171 fields = [
2172 (_MakeField("pnode", "Primary_node", QFT_TEXT, "Primary node"),
2173 IQ_NODES, QFF_HOSTNAME,
2174 lambda ctx, inst: _GetNodeName(ctx, None, inst.primary_node)),
2175 (_MakeField("pnode.group", "PrimaryNodeGroup", QFT_TEXT,
2176 "Primary node's group"),
2177 IQ_NODES, 0,
2178 lambda ctx, inst: _GetInstNodeGroupName(ctx, _FS_UNAVAIL,
2179 inst.primary_node)),
2180 (_MakeField("pnode.group.uuid", "PrimaryNodeGroupUUID", QFT_TEXT,
2181 "Primary node's group UUID"),
2182 IQ_NODES, 0,
2183 lambda ctx, inst: _GetInstNodeGroup(ctx, _FS_UNAVAIL, inst.primary_node)),
2184
2185 (_MakeField("snodes", "Secondary_Nodes", QFT_OTHER,
2186 "Secondary nodes; usually this will just be one node"),
2187 IQ_NODES, 0,
2188 lambda ctx, inst: map(compat.partial(_GetNodeName, ctx, None),
2189 inst.secondary_nodes)),
2190 (_MakeField("snodes.group", "SecondaryNodesGroups", QFT_OTHER,
2191 "Node groups of secondary nodes"),
2192 IQ_NODES, 0,
2193 lambda ctx, inst: map(compat.partial(_GetInstNodeGroupName, ctx, None),
2194 inst.secondary_nodes)),
2195 (_MakeField("snodes.group.uuid", "SecondaryNodesGroupsUUID", QFT_OTHER,
2196 "Node group UUIDs of secondary nodes"),
2197 IQ_NODES, 0,
2198 lambda ctx, inst: map(compat.partial(_GetInstNodeGroup, ctx, None),
2199 inst.secondary_nodes)),
2200 (_MakeField("admin_state", "InstanceState", QFT_TEXT,
2201 "Desired state of the instance"),
2202 IQ_CONFIG, 0, _GetItemAttr("admin_state")),
2203 (_MakeField("admin_up", "Autostart", QFT_BOOL,
2204 "Desired state of the instance"),
2205 IQ_CONFIG, 0, lambda ctx, inst: inst.admin_state == constants.ADMINST_UP),
2206 (_MakeField("admin_state_source", "InstanceStateSource", QFT_TEXT,
2207 "Who last changed the desired state of the instance"),
2208 IQ_CONFIG, 0, _GetItemAttr("admin_state_source")),
2209 (_MakeField("disks_active", "DisksActive", QFT_BOOL,
2210 "Desired state of the instance disks"),
2211 IQ_CONFIG, 0, _GetItemAttr("disks_active")),
2212 (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), IQ_CONFIG, 0,
2213 lambda ctx, inst: list(inst.GetTags())),
2214 (_MakeField("console", "Console", QFT_OTHER,
2215 "Instance console information"), IQ_CONSOLE, 0,
2216 _GetInstanceConsole),
2217 (_MakeField("forthcoming", "Forthcoming", QFT_BOOL,
2218 "Whether the Instance is forthcoming"), IQ_CONFIG, 0,
2219 lambda _, inst: bool(inst.forthcoming)),
2220 ]
2221
2222
2223 fields.extend([
2224 (_MakeField(name, title, kind, doc), IQ_CONFIG, flags, _GetItemAttr(name))
2225 for (name, (title, kind, flags, doc)) in _INST_SIMPLE_FIELDS.items()])
2226
2227
2228 fields.extend([
2229 (_MakeField("oper_state", "Running", QFT_BOOL, "Actual state of instance"),
2230 IQ_LIVE, 0, _GetInstOperState),
2231 (_MakeField("oper_ram", "Memory", QFT_UNIT,
2232 "Actual memory usage as seen by hypervisor"),
2233 IQ_LIVE, 0, _GetInstLiveData("memory")),
2234 (_MakeField("oper_vcpus", "VCPUs", QFT_NUMBER,
2235 "Actual number of VCPUs as seen by hypervisor"),
2236 IQ_LIVE, 0, _GetInstLiveData("vcpus")),
2237 ])
2238
2239
2240 status_values = (constants.INSTST_RUNNING, constants.INSTST_ADMINDOWN,
2241 constants.INSTST_WRONGNODE, constants.INSTST_ERRORUP,
2242 constants.INSTST_ERRORDOWN, constants.INSTST_NODEDOWN,
2243 constants.INSTST_NODEOFFLINE, constants.INSTST_ADMINOFFLINE,
2244 constants.INSTST_USERDOWN)
2245 status_doc = ("Instance status; \"%s\" if instance is set to be running"
2246 " and actually is, \"%s\" if instance is stopped and"
2247 " is not running, \"%s\" if instance running, but not on its"
2248 " designated primary node, \"%s\" if instance should be"
2249 " stopped, but is actually running, \"%s\" if instance should"
2250 " run, but doesn't, \"%s\" if instance's primary node is down,"
2251 " \"%s\" if instance's primary node is marked offline,"
2252 " \"%s\" if instance is offline and does not use dynamic,"
2253 " \"%s\" if the user shutdown the instance"
2254 " resources" % status_values)
2255 fields.append((_MakeField("status", "Status", QFT_TEXT, status_doc),
2256 IQ_LIVE, 0, _GetInstStatus))
2257
2258 assert set(status_values) == constants.INSTST_ALL, \
2259 "Status documentation mismatch"
2260
2261 (network_fields, network_aliases) = _GetInstanceNetworkFields()
2262
2263 fields.extend(network_fields)
2264 fields.extend(_GetInstanceParameterFields())
2265 fields.extend(_GetInstanceDiskFields())
2266 fields.extend(_GetItemTimestampFields(IQ_CONFIG))
2267
2268 aliases = [
2269 ("vcpus", "be/vcpus"),
2270 ("be/memory", "be/maxmem"),
2271 ("sda_size", "disk.size/0"),
2272 ("sdb_size", "disk.size/1"),
2273 ] + network_aliases
2274
2275 return _PrepareFieldList(fields, aliases)
2276
2277
2279 """Data container for lock data queries.
2280
2281 """
2283 """Initializes this class.
2284
2285 """
2286 self.lockdata = lockdata
2287
2289 """Iterate over all locks.
2290
2291 """
2292 return iter(self.lockdata)
2293
2294
2296 """Returns a sorted list of a lock's current owners.
2297
2298 """
2299 (_, _, owners, _) = data
2300
2301 if owners:
2302 owners = utils.NiceSort(owners)
2303
2304 return owners
2305
2306
2308 """Returns a sorted list of a lock's pending acquires.
2309
2310 """
2311 (_, _, _, pending) = data
2312
2313 if pending:
2314 pending = [(mode, utils.NiceSort(names))
2315 for (mode, names) in pending]
2316
2317 return pending
2318
2319
2321 """Builds list of fields for lock queries.
2322
2323 """
2324 return _PrepareFieldList([
2325
2326 (_MakeField("name", "Name", QFT_TEXT, "Lock name"), None, 0,
2327 lambda ctx, (name, mode, owners, pending): name),
2328 (_MakeField("mode", "Mode", QFT_OTHER,
2329 "Mode in which the lock is currently acquired"
2330 " (exclusive or shared)"),
2331 LQ_MODE, 0, lambda ctx, (name, mode, owners, pending): mode),
2332 (_MakeField("owner", "Owner", QFT_OTHER, "Current lock owner(s)"),
2333 LQ_OWNER, 0, _GetLockOwners),
2334 (_MakeField("pending", "Pending", QFT_OTHER,
2335 "Threads waiting for the lock"),
2336 LQ_PENDING, 0, _GetLockPending),
2337 ], [])
2338
2339
2341 """Data container for node group data queries.
2342
2343 """
2344 - def __init__(self, cluster, groups, group_to_nodes, group_to_instances,
2345 want_diskparams):
2346 """Initializes this class.
2347
2348 @param cluster: Cluster object
2349 @param groups: List of node group objects
2350 @type group_to_nodes: dict; group UUID as key
2351 @param group_to_nodes: Per-group list of nodes
2352 @type group_to_instances: dict; group UUID as key
2353 @param group_to_instances: Per-group list of (primary) instances
2354 @type want_diskparams: bool
2355 @param want_diskparams: Whether diskparamters should be calculated
2356
2357 """
2358 self.groups = groups
2359 self.group_to_nodes = group_to_nodes
2360 self.group_to_instances = group_to_instances
2361 self.cluster = cluster
2362 self.want_diskparams = want_diskparams
2363
2364
2365 self.group_ipolicy = None
2366 self.ndparams = None
2367 self.group_dp = None
2368
2370 """Iterate over all node groups.
2371
2372 This function has side-effects and only one instance of the resulting
2373 generator should be used at a time.
2374
2375 """
2376 for group in self.groups:
2377 self.group_ipolicy = self.cluster.SimpleFillIPolicy(group.ipolicy)
2378 self.ndparams = self.cluster.SimpleFillND(group.ndparams)
2379 if self.want_diskparams:
2380 self.group_dp = self.cluster.SimpleFillDP(group.diskparams)
2381 else:
2382 self.group_dp = None
2383 yield group
2384
2385
2386 _GROUP_SIMPLE_FIELDS = {
2387 "alloc_policy": ("AllocPolicy", QFT_TEXT, "Allocation policy for group"),
2388 "name": ("Group", QFT_TEXT, "Group name"),
2389 "serial_no": ("SerialNo", QFT_NUMBER, _SERIAL_NO_DOC % "Group"),
2390 "uuid": ("UUID", QFT_TEXT, "Group UUID"),
2391 }
2392
2393
2395 """Builds list of fields for node group queries.
2396
2397 """
2398
2399 fields = [(_MakeField(name, title, kind, doc), GQ_CONFIG, 0,
2400 _GetItemAttr(name))
2401 for (name, (title, kind, doc)) in _GROUP_SIMPLE_FIELDS.items()]
2402
2403 def _GetLength(getter):
2404 return lambda ctx, group: len(getter(ctx)[group.uuid])
2405
2406 def _GetSortedList(getter):
2407 return lambda ctx, group: utils.NiceSort(getter(ctx)[group.uuid])
2408
2409 group_to_nodes = operator.attrgetter("group_to_nodes")
2410 group_to_instances = operator.attrgetter("group_to_instances")
2411
2412
2413 fields.extend([
2414 (_MakeField("node_cnt", "Nodes", QFT_NUMBER, "Number of nodes"),
2415 GQ_NODE, 0, _GetLength(group_to_nodes)),
2416 (_MakeField("node_list", "NodeList", QFT_OTHER, "List of nodes"),
2417 GQ_NODE, 0, _GetSortedList(group_to_nodes)),
2418 ])
2419
2420
2421 fields.extend([
2422 (_MakeField("pinst_cnt", "Instances", QFT_NUMBER,
2423 "Number of primary instances"),
2424 GQ_INST, 0, _GetLength(group_to_instances)),
2425 (_MakeField("pinst_list", "InstanceList", QFT_OTHER,
2426 "List of primary instances"),
2427 GQ_INST, 0, _GetSortedList(group_to_instances)),
2428 ])
2429
2430
2431 fields.extend([
2432 (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), GQ_CONFIG, 0,
2433 lambda ctx, group: list(group.GetTags())),
2434 (_MakeField("ipolicy", "InstancePolicy", QFT_OTHER,
2435 "Instance policy limitations (merged)"),
2436 GQ_CONFIG, 0, lambda ctx, _: ctx.group_ipolicy),
2437 (_MakeField("custom_ipolicy", "CustomInstancePolicy", QFT_OTHER,
2438 "Custom instance policy limitations"),
2439 GQ_CONFIG, 0, _GetItemAttr("ipolicy")),
2440 (_MakeField("custom_ndparams", "CustomNDParams", QFT_OTHER,
2441 "Custom node parameters"),
2442 GQ_CONFIG, 0, _GetItemAttr("ndparams")),
2443 (_MakeField("ndparams", "NDParams", QFT_OTHER,
2444 "Node parameters"),
2445 GQ_CONFIG, 0, lambda ctx, _: ctx.ndparams),
2446 (_MakeField("diskparams", "DiskParameters", QFT_OTHER,
2447 "Disk parameters (merged)"),
2448 GQ_DISKPARAMS, 0, lambda ctx, _: ctx.group_dp),
2449 (_MakeField("custom_diskparams", "CustomDiskParameters", QFT_OTHER,
2450 "Custom disk parameters"),
2451 GQ_CONFIG, 0, _GetItemAttr("diskparams")),
2452 (_MakeField("hv_state", "HypervisorState", QFT_OTHER,
2453 "Custom static hypervisor state"),
2454 GQ_CONFIG, 0, _GetItemAttr("hv_state_static")),
2455 (_MakeField("disk_state", "DiskState", QFT_OTHER, "Disk state"),
2456 GQ_CONFIG, 0, _GetItemAttr("disk_state_static")),
2457 ])
2458
2459
2460 fields.extend(_BuildNDFields(True))
2461
2462 fields.extend(_GetItemTimestampFields(GQ_CONFIG))
2463
2464 return _PrepareFieldList(fields, [])
2465
2466
2467 -class OsInfo(objects.ConfigObject):
2468 __slots__ = [
2469 "name",
2470 "valid",
2471 "hidden",
2472 "blacklisted",
2473 "variants",
2474 "api_versions",
2475 "parameters",
2476 "node_status",
2477 "os_hvp",
2478 "osparams",
2479 "trusted"
2480 ]
2481
2482
2484 """Builds list of fields for operating system queries.
2485
2486 """
2487 fields = [
2488 (_MakeField("name", "Name", QFT_TEXT, "Operating system name"),
2489 None, 0, _GetItemAttr("name")),
2490 (_MakeField("valid", "Valid", QFT_BOOL,
2491 "Whether operating system definition is valid"),
2492 None, 0, _GetItemAttr("valid")),
2493 (_MakeField("hidden", "Hidden", QFT_BOOL,
2494 "Whether operating system is hidden"),
2495 None, 0, _GetItemAttr("hidden")),
2496 (_MakeField("blacklisted", "Blacklisted", QFT_BOOL,
2497 "Whether operating system is blacklisted"),
2498 None, 0, _GetItemAttr("blacklisted")),
2499 (_MakeField("variants", "Variants", QFT_OTHER,
2500 "Operating system variants"),
2501 None, 0, _ConvWrap(utils.NiceSort, _GetItemAttr("variants"))),
2502 (_MakeField("api_versions", "ApiVersions", QFT_OTHER,
2503 "Operating system API versions"),
2504 None, 0, _ConvWrap(sorted, _GetItemAttr("api_versions"))),
2505 (_MakeField("parameters", "Parameters", QFT_OTHER,
2506 "Operating system parameters"),
2507 None, 0, _ConvWrap(compat.partial(utils.NiceSort, key=compat.fst),
2508 _GetItemAttr("parameters"))),
2509 (_MakeField("node_status", "NodeStatus", QFT_OTHER,
2510 "Status from node"),
2511 None, 0, _GetItemAttr("node_status")),
2512 (_MakeField("os_hvp", "OsHypervisorParams", QFT_OTHER,
2513 "Operating system specific hypervisor parameters"),
2514 None, 0, _GetItemAttr("os_hvp")),
2515 (_MakeField("osparams", "OsParameters", QFT_OTHER,
2516 "Operating system specific parameters"),
2517 None, 0, _GetItemAttr("osparams")),
2518 (_MakeField("trusted", "Trusted", QFT_BOOL,
2519 "Whether this OS is trusted"),
2520 None, 0, _GetItemAttr("trusted")),
2521 ]
2522
2523 return _PrepareFieldList(fields, [])
2524
2525
2527 __slots__ = [
2528 "name",
2529 "node_status",
2530 "nodegroup_status",
2531 "parameters",
2532 ]
2533
2534
2536 """Builds list of fields for extstorage provider queries.
2537
2538 """
2539 fields = [
2540 (_MakeField("name", "Name", QFT_TEXT, "ExtStorage provider name"),
2541 None, 0, _GetItemAttr("name")),
2542 (_MakeField("node_status", "NodeStatus", QFT_OTHER,
2543 "Status from node"),
2544 None, 0, _GetItemAttr("node_status")),
2545 (_MakeField("nodegroup_status", "NodegroupStatus", QFT_OTHER,
2546 "Overall Nodegroup status"),
2547 None, 0, _GetItemAttr("nodegroup_status")),
2548 (_MakeField("parameters", "Parameters", QFT_OTHER,
2549 "ExtStorage provider parameters"),
2550 None, 0, _GetItemAttr("parameters")),
2551 ]
2552
2553 return _PrepareFieldList(fields, [])
2554
2555
2557 """Return L{_FS_UNAVAIL} if job is None.
2558
2559 When listing specifc jobs (e.g. "gnt-job list 1 2 3"), a job may not be
2560 found, in which case this function converts it to L{_FS_UNAVAIL}.
2561
2562 """
2563 if job is None:
2564 return _FS_UNAVAIL
2565 else:
2566 return fn(job)
2567
2568
2574
2575
2577 """Executes a function per opcode in a job.
2578
2579 """
2580 return map(fn, job.ops)
2581
2582
2588
2589
2591 """Converts unavailable timestamp to L{_FS_UNAVAIL}.
2592
2593 """
2594 timestamp = fn(job)
2595
2596 if timestamp is None:
2597 return _FS_UNAVAIL
2598 else:
2599 return timestamp
2600
2601
2607
2608
2610 """Builds list of fields for job queries.
2611
2612 """
2613 fields = [
2614 (_MakeField("id", "ID", QFT_NUMBER, "Job ID"),
2615 None, QFF_JOB_ID, lambda _, (job_id, job): job_id),
2616 (_MakeField("status", "Status", QFT_TEXT, "Job status"),
2617 None, 0, _JobUnavail(lambda job: job.CalcStatus())),
2618 (_MakeField("priority", "Priority", QFT_NUMBER,
2619 ("Current job priority (%s to %s)" %
2620 (constants.OP_PRIO_LOWEST, constants.OP_PRIO_HIGHEST))),
2621 None, 0, _JobUnavail(lambda job: job.CalcPriority())),
2622 (_MakeField("archived", "Archived", QFT_BOOL, "Whether job is archived"),
2623 JQ_ARCHIVED, 0, lambda _, (job_id, job): job.archived),
2624 (_MakeField("ops", "OpCodes", QFT_OTHER, "List of all opcodes"),
2625 None, 0, _PerJobOp(lambda op: op.input.__getstate__())),
2626 (_MakeField("opresult", "OpCode_result", QFT_OTHER,
2627 "List of opcodes results"),
2628 None, 0, _PerJobOp(operator.attrgetter("result"))),
2629 (_MakeField("opstatus", "OpCode_status", QFT_OTHER,
2630 "List of opcodes status"),
2631 None, 0, _PerJobOp(operator.attrgetter("status"))),
2632 (_MakeField("oplog", "OpCode_log", QFT_OTHER,
2633 "List of opcode output logs"),
2634 None, 0, _PerJobOp(operator.attrgetter("log"))),
2635 (_MakeField("opstart", "OpCode_start", QFT_OTHER,
2636 "List of opcode start timestamps (before acquiring locks)"),
2637 None, 0, _PerJobOp(operator.attrgetter("start_timestamp"))),
2638 (_MakeField("opexec", "OpCode_exec", QFT_OTHER,
2639 "List of opcode execution start timestamps (after acquiring"
2640 " locks)"),
2641 None, 0, _PerJobOp(operator.attrgetter("exec_timestamp"))),
2642 (_MakeField("opend", "OpCode_end", QFT_OTHER,
2643 "List of opcode execution end timestamps"),
2644 None, 0, _PerJobOp(operator.attrgetter("end_timestamp"))),
2645 (_MakeField("oppriority", "OpCode_prio", QFT_OTHER,
2646 "List of opcode priorities"),
2647 None, 0, _PerJobOp(operator.attrgetter("priority"))),
2648 (_MakeField("summary", "Summary", QFT_OTHER,
2649 "List of per-opcode summaries"),
2650 None, 0, _PerJobOp(lambda op: op.input.Summary())),
2651 ]
2652
2653
2654 for (name, attr, title, desc) in [
2655 ("received_ts", "received_timestamp", "Received",
2656 "Timestamp of when job was received"),
2657 ("start_ts", "start_timestamp", "Start", "Timestamp of job start"),
2658 ("end_ts", "end_timestamp", "End", "Timestamp of job end"),
2659 ]:
2660 getter = operator.attrgetter(attr)
2661 fields.extend([
2662 (_MakeField(name, title, QFT_OTHER,
2663 "%s (tuple containing seconds and microseconds)" % desc),
2664 None, QFF_SPLIT_TIMESTAMP, _JobTimestamp(getter)),
2665 ])
2666
2667 return _PrepareFieldList(fields, [])
2668
2669
2671 """Returns an export name if available.
2672
2673 """
2674 if expname is None:
2675 return _FS_NODATA
2676 else:
2677 return expname
2678
2679
2681 """Builds list of fields for exports.
2682
2683 """
2684 fields = [
2685 (_MakeField("node", "Node", QFT_TEXT, "Node name"),
2686 None, QFF_HOSTNAME, lambda _, (node_name, expname): node_name),
2687 (_MakeField("export", "Export", QFT_TEXT, "Export name"),
2688 None, 0, _GetExportName),
2689 ]
2690
2691 return _PrepareFieldList(fields, [])
2692
2693
2694 _CLUSTER_VERSION_FIELDS = {
2695 "software_version": ("SoftwareVersion", QFT_TEXT, constants.RELEASE_VERSION,
2696 "Software version"),
2697 "protocol_version": ("ProtocolVersion", QFT_NUMBER,
2698 constants.PROTOCOL_VERSION,
2699 "RPC protocol version"),
2700 "config_version": ("ConfigVersion", QFT_NUMBER, constants.CONFIG_VERSION,
2701 "Configuration format version"),
2702 "os_api_version": ("OsApiVersion", QFT_NUMBER, max(constants.OS_API_VERSIONS),
2703 "API version for OS template scripts"),
2704 "export_version": ("ExportVersion", QFT_NUMBER, constants.EXPORT_VERSION,
2705 "Import/export file format version"),
2706 "vcs_version": ("VCSVersion", QFT_TEXT, constants.VCS_VERSION,
2707 "VCS version"),
2708 }
2709
2710
2711 _CLUSTER_SIMPLE_FIELDS = {
2712 "cluster_name": ("Name", QFT_TEXT, QFF_HOSTNAME, "Cluster name"),
2713 "volume_group_name": ("VgName", QFT_TEXT, 0, "LVM volume group name"),
2714 }
2715
2716
2718 - def __init__(self, cluster, nodes, drain_flag, watcher_pause):
2719 """Initializes this class.
2720
2721 @type cluster: L{objects.Cluster}
2722 @param cluster: Instance of cluster object
2723 @type nodes: dict; node UUID as key
2724 @param nodes: Node objects
2725 @type drain_flag: bool
2726 @param drain_flag: Whether job queue is drained
2727 @type watcher_pause: number
2728 @param watcher_pause: Until when watcher is paused (Unix timestamp)
2729
2730 """
2731 self._cluster = cluster
2732 self.nodes = nodes
2733 self.drain_flag = drain_flag
2734 self.watcher_pause = watcher_pause
2735
2737 return iter([self._cluster])
2738
2739
2741 """Returns until when watcher is paused (if available).
2742
2743 """
2744 if ctx.watcher_pause is None:
2745 return _FS_UNAVAIL
2746 else:
2747 return ctx.watcher_pause
2748
2749
2751 """Builds list of fields for cluster information.
2752
2753 """
2754 fields = [
2755 (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), CQ_CONFIG, 0,
2756 lambda ctx, cluster: list(cluster.GetTags())),
2757 (_MakeField("architecture", "ArchInfo", QFT_OTHER,
2758 "Architecture information"), None, 0,
2759 lambda ctx, _: runtime.GetArchInfo()),
2760 (_MakeField("drain_flag", "QueueDrained", QFT_BOOL,
2761 "Flag whether job queue is drained"), CQ_QUEUE_DRAINED, 0,
2762 lambda ctx, _: ctx.drain_flag),
2763 (_MakeField("watcher_pause", "WatcherPause", QFT_TIMESTAMP,
2764 "Until when watcher is paused"), CQ_WATCHER_PAUSE, 0,
2765 _ClusterWatcherPause),
2766 (_MakeField("master_node", "Master", QFT_TEXT, "Master node name"),
2767 CQ_CONFIG, QFF_HOSTNAME,
2768 lambda ctx, cluster: _GetNodeName(ctx, None, cluster.master_node)),
2769 (_MakeField("hv_state", "HypervisorState", QFT_OTHER,
2770 "Custom static hypervisor state"),
2771 CQ_CONFIG, 0, _GetItemAttr("hv_state_static")),
2772 (_MakeField("disk_state", "DiskState", QFT_OTHER, "Disk state"),
2773 CQ_CONFIG, 0, _GetItemAttr("disk_state_static")),
2774 ]
2775
2776
2777 fields.extend([
2778 (_MakeField(name, title, kind, doc), CQ_CONFIG, flags, _GetItemAttr(name))
2779 for (name, (title, kind, flags, doc)) in _CLUSTER_SIMPLE_FIELDS.items()
2780 ],)
2781
2782
2783 fields.extend([
2784 (_MakeField(name, title, kind, doc), None, 0, _StaticValue(value))
2785 for (name, (title, kind, value, doc)) in _CLUSTER_VERSION_FIELDS.items()])
2786
2787
2788 fields.extend(_GetItemTimestampFields(CQ_CONFIG))
2789
2790 return _PrepareFieldList(fields, [
2791 ("name", "cluster_name")])
2792
2793
2795 """Data container for network data queries.
2796
2797 """
2798 - def __init__(self, networks, network_to_groups,
2799 network_to_instances, stats):
2800 """Initializes this class.
2801
2802 @param networks: List of network objects
2803 @type network_to_groups: dict; network UUID as key
2804 @param network_to_groups: Per-network list of groups
2805 @type network_to_instances: dict; network UUID as key
2806 @param network_to_instances: Per-network list of instances
2807 @type stats: dict; network UUID as key
2808 @param stats: Per-network usage statistics
2809
2810 """
2811 self.networks = networks
2812 self.network_to_groups = network_to_groups
2813 self.network_to_instances = network_to_instances
2814 self.stats = stats
2815
2817 """Iterate over all networks.
2818
2819 """
2820 for net in self.networks:
2821 if self.stats:
2822 self.curstats = self.stats.get(net.uuid, None)
2823 else:
2824 self.curstats = None
2825 yield net
2826
2827
2828 _NETWORK_SIMPLE_FIELDS = {
2829 "name": ("Network", QFT_TEXT, 0, "Name"),
2830 "network": ("Subnet", QFT_TEXT, 0, "IPv4 subnet"),
2831 "gateway": ("Gateway", QFT_OTHER, 0, "IPv4 gateway"),
2832 "network6": ("IPv6Subnet", QFT_OTHER, 0, "IPv6 subnet"),
2833 "gateway6": ("IPv6Gateway", QFT_OTHER, 0, "IPv6 gateway"),
2834 "mac_prefix": ("MacPrefix", QFT_OTHER, 0, "MAC address prefix"),
2835 "serial_no": ("SerialNo", QFT_NUMBER, 0, _SERIAL_NO_DOC % "Network"),
2836 "uuid": ("UUID", QFT_TEXT, 0, "Network UUID"),
2837 }
2838
2839
2840 _NETWORK_STATS_FIELDS = {
2841 "free_count": ("FreeCount", QFT_NUMBER, 0, "Number of available addresses"),
2842 "reserved_count":
2843 ("ReservedCount", QFT_NUMBER, 0, "Number of reserved addresses"),
2844 "map": ("Map", QFT_TEXT, 0, "Actual mapping"),
2845 "external_reservations":
2846 ("ExternalReservations", QFT_TEXT, 0, "External reservations"),
2847 }
2848
2849
2851 """Gets the value of a "stats" field from L{NetworkQueryData}.
2852
2853 @param field: Field name
2854 @param kind: Data kind, one of L{constants.QFT_ALL}
2855 @type ctx: L{NetworkQueryData}
2856
2857 """
2858 return _GetStatsField(field, kind, ctx.curstats)
2859
2860
2862 """Builds list of fields for network queries.
2863
2864 """
2865 fields = [
2866 (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), IQ_CONFIG, 0,
2867 lambda ctx, inst: list(inst.GetTags())),
2868 ]
2869
2870
2871 fields.extend([
2872 (_MakeField(name, title, kind, doc),
2873 NETQ_CONFIG, 0, _GetItemMaybeAttr(name))
2874 for (name, (title, kind, _, doc)) in _NETWORK_SIMPLE_FIELDS.items()])
2875
2876 def _GetLength(getter):
2877 return lambda ctx, network: len(getter(ctx)[network.uuid])
2878
2879 def _GetSortedList(getter):
2880 return lambda ctx, network: utils.NiceSort(getter(ctx)[network.uuid])
2881
2882 network_to_groups = operator.attrgetter("network_to_groups")
2883 network_to_instances = operator.attrgetter("network_to_instances")
2884
2885
2886 fields.extend([
2887 (_MakeField("group_cnt", "NodeGroups", QFT_NUMBER, "Number of nodegroups"),
2888 NETQ_GROUP, 0, _GetLength(network_to_groups)),
2889 (_MakeField("group_list", "GroupList", QFT_OTHER,
2890 "List of nodegroups (group name, NIC mode, NIC link)"),
2891 NETQ_GROUP, 0, lambda ctx, network: network_to_groups(ctx)[network.uuid]),
2892 ])
2893
2894
2895 fields.extend([
2896 (_MakeField("inst_cnt", "Instances", QFT_NUMBER, "Number of instances"),
2897 NETQ_INST, 0, _GetLength(network_to_instances)),
2898 (_MakeField("inst_list", "InstanceList", QFT_OTHER, "List of instances"),
2899 NETQ_INST, 0, _GetSortedList(network_to_instances)),
2900 ])
2901
2902
2903 fields.extend([
2904 (_MakeField(name, title, kind, doc), NETQ_STATS, 0,
2905 compat.partial(_GetNetworkStatsField, name, kind))
2906 for (name, (title, kind, _, doc)) in _NETWORK_STATS_FIELDS.items()])
2907
2908
2909 fields.extend(_GetItemTimestampFields(IQ_NETWORKS))
2910
2911 return _PrepareFieldList(fields, [])
2912
2913
2914 _FILTER_SIMPLE_FIELDS = {
2915 "watermark": ("Watermark", QFT_NUMBER, 0, "Watermark"),
2916 "priority": ("Priority", QFT_NUMBER, 0, "Priority"),
2917 "predicates": ("Predicates", QFT_OTHER, 0, "Predicates"),
2918 "action": ("Action", QFT_OTHER, 0, "Action"),
2919 "reason_trail": ("ReasonTrail", QFT_OTHER, 0, "Reason trail"),
2920 "uuid": ("UUID", QFT_TEXT, 0, "Network UUID"),
2921 }
2922
2923
2925 """Builds list of fields for job filter queries.
2926
2927 """
2928 fields = [
2929 (_MakeField(name, title, kind, doc), None, 0, _GetItemMaybeAttr(name))
2930 for (name, (title, kind, _, doc)) in _FILTER_SIMPLE_FIELDS.items()
2931 ]
2932
2933 return _PrepareFieldList(fields, [])
2934
2935
2936 CLUSTER_FIELDS = _BuildClusterFields()
2937
2938
2939 NODE_FIELDS = _BuildNodeFields()
2940
2941
2942 INSTANCE_FIELDS = _BuildInstanceFields()
2943
2944
2945 LOCK_FIELDS = _BuildLockFields()
2946
2947
2948 GROUP_FIELDS = _BuildGroupFields()
2949
2950
2951 OS_FIELDS = _BuildOsFields()
2952
2953
2954 EXTSTORAGE_FIELDS = _BuildExtStorageFields()
2955
2956
2957 JOB_FIELDS = _BuildJobFields()
2958
2959
2960 EXPORT_FIELDS = _BuildExportFields()
2961
2962
2963 NETWORK_FIELDS = _BuildNetworkFields()
2964
2965
2966 FILTER_FIELDS = _BuildFilterFields()
2967
2968
2969 ALL_FIELDS = {
2970 constants.QR_CLUSTER: CLUSTER_FIELDS,
2971 constants.QR_INSTANCE: INSTANCE_FIELDS,
2972 constants.QR_NODE: NODE_FIELDS,
2973 constants.QR_LOCK: LOCK_FIELDS,
2974 constants.QR_GROUP: GROUP_FIELDS,
2975 constants.QR_OS: OS_FIELDS,
2976 constants.QR_EXTSTORAGE: EXTSTORAGE_FIELDS,
2977 constants.QR_JOB: JOB_FIELDS,
2978 constants.QR_EXPORT: EXPORT_FIELDS,
2979 constants.QR_NETWORK: NETWORK_FIELDS,
2980 constants.QR_FILTER: FILTER_FIELDS,
2981 }
2982
2983
2984 ALL_FIELD_LISTS = ALL_FIELDS.values()
2985