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