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