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