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