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