1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Module for query operations
23
24 How it works:
25
26 - Add field definitions
27 - See how L{NODE_FIELDS} is built
28 - Each field gets:
29 - Query field definition (L{objects.QueryFieldDefinition}, use
30 L{_MakeField} for creating), containing:
31 - Name, must be lowercase and match L{FIELD_NAME_RE}
32 - Title for tables, must not contain whitespace and match
33 L{TITLE_RE}
34 - Value data type, e.g. L{constants.QFT_NUMBER}
35 - Data request type, see e.g. C{NQ_*}
36 - A retrieval function, see L{Query.__init__} for description
37 - Pass list of fields through L{_PrepareFieldList} for preparation and
38 checks
39 - Instantiate L{Query} with prepared field list definition and selected fields
40 - Call L{Query.RequestedData} to determine what data to collect/compute
41 - Call L{Query.Query} or L{Query.OldStyleQuery} with collected data and use
42 result
43 - Data container must support iteration using C{__iter__}
44 - Items are passed to retrieval functions and can have any format
45 - Call L{Query.GetFields} to get list of definitions for selected fields
46
47 @attention: Retrieval functions must be idempotent. They can be called multiple
48 times, in any order and any number of times. This is important to keep in
49 mind for implementing filters in the future.
50
51 """
52
53 import logging
54 import operator
55 import re
56
57 from ganeti import constants
58 from ganeti import errors
59 from ganeti import utils
60 from ganeti import compat
61 from ganeti import objects
62 from ganeti import ht
63
64 from ganeti.constants import (QFT_UNKNOWN, QFT_TEXT, QFT_BOOL, QFT_NUMBER,
65 QFT_UNIT, QFT_TIMESTAMP, QFT_OTHER,
66 RS_NORMAL, RS_UNKNOWN, RS_NODATA,
67 RS_UNAVAIL, RS_OFFLINE)
68
69
70
71
72
73
74 (NQ_CONFIG,
75 NQ_INST,
76 NQ_LIVE,
77 NQ_GROUP,
78 NQ_OOB) = range(1, 6)
79
80 (IQ_CONFIG,
81 IQ_LIVE,
82 IQ_DISKUSAGE,
83 IQ_CONSOLE) = range(100, 104)
84
85 (LQ_MODE,
86 LQ_OWNER,
87 LQ_PENDING) = range(10, 13)
88
89 (GQ_CONFIG,
90 GQ_NODE,
91 GQ_INST) = range(200, 203)
92
93
94 FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$")
95 TITLE_RE = re.compile(r"^[^\s]+$")
96
97
98 _VERIFY_FN = {
99 QFT_UNKNOWN: ht.TNone,
100 QFT_TEXT: ht.TString,
101 QFT_BOOL: ht.TBool,
102 QFT_NUMBER: ht.TInt,
103 QFT_UNIT: ht.TInt,
104 QFT_TIMESTAMP: ht.TNumber,
105 QFT_OTHER: lambda _: True,
106 }
107
108
109 _FS_UNKNOWN = object()
110 _FS_NODATA = object()
111 _FS_UNAVAIL = object()
112 _FS_OFFLINE = object()
113
114
115 _VTToQFT = {
116
117 constants.VTYPE_STRING: QFT_OTHER,
118 constants.VTYPE_MAYBE_STRING: QFT_OTHER,
119 constants.VTYPE_BOOL: QFT_BOOL,
120 constants.VTYPE_SIZE: QFT_UNIT,
121 constants.VTYPE_INT: QFT_NUMBER,
122 }
123
124
126 """Gets the contents of an unknown field.
127
128 """
129 return _FS_UNKNOWN
130
131
133 """Calculates the internal list of selected fields.
134
135 Unknown fields are returned as L{constants.QFT_UNKNOWN}.
136
137 @type fielddefs: dict
138 @param fielddefs: Field definitions
139 @type selected: list of strings
140 @param selected: List of selected fields
141
142 """
143 result = []
144
145 for name in selected:
146 try:
147 fdef = fielddefs[name]
148 except KeyError:
149 fdef = (_MakeField(name, name, QFT_UNKNOWN), None, _GetUnknownField)
150
151 assert len(fdef) == 3
152
153 result.append(fdef)
154
155 return result
156
157
159 """Extract L{objects.QueryFieldDefinition} from field definitions.
160
161 @rtype: list of L{objects.QueryFieldDefinition}
162
163 """
164 return [fdef for (fdef, _, _) in fielddefs]
165
166
168 - def __init__(self, fieldlist, selected):
169 """Initializes this class.
170
171 The field definition is a dictionary with the field's name as a key and a
172 tuple containing, in order, the field definition object
173 (L{objects.QueryFieldDefinition}, the data kind to help calling code
174 collect data and a retrieval function. The retrieval function is called
175 with two parameters, in order, the data container and the item in container
176 (see L{Query.Query}).
177
178 Users of this class can call L{RequestedData} before preparing the data
179 container to determine what data is needed.
180
181 @type fieldlist: dictionary
182 @param fieldlist: Field definitions
183 @type selected: list of strings
184 @param selected: List of selected fields
185
186 """
187 self._fields = _GetQueryFields(fieldlist, selected)
188
190 """Gets requested kinds of data.
191
192 @rtype: frozenset
193
194 """
195 return frozenset(datakind
196 for (_, datakind, _) in self._fields
197 if datakind is not None)
198
200 """Returns the list of fields for this query.
201
202 Includes unknown fields.
203
204 @rtype: List of L{objects.QueryFieldDefinition}
205
206 """
207 return GetAllFields(self._fields)
208
210 """Execute a query.
211
212 @param ctx: Data container passed to field retrieval functions, must
213 support iteration using C{__iter__}
214
215 """
216 result = [[_ProcessResult(fn(ctx, item)) for (_, _, fn) in self._fields]
217 for item in ctx]
218
219
220 if __debug__:
221 for row in result:
222 _VerifyResultRow(self._fields, row)
223
224 return result
225
227 """Query with "old" query result format.
228
229 See L{Query.Query} for arguments.
230
231 """
232 unknown = set(fdef.name
233 for (fdef, _, _) in self._fields if fdef.kind == QFT_UNKNOWN)
234 if unknown:
235 raise errors.OpPrereqError("Unknown output fields selected: %s" %
236 (utils.CommaJoin(unknown), ),
237 errors.ECODE_INVAL)
238
239 return [[value for (_, value) in row]
240 for row in self.Query(ctx)]
241
242
257
258
260 """Verifies the contents of a query result row.
261
262 @type fields: list
263 @param fields: Field definitions for result
264 @type row: list of tuples
265 @param row: Row data
266
267 """
268 assert len(row) == len(fields)
269 errs = []
270 for ((status, value), (fdef, _, _)) in zip(row, fields):
271 if status == RS_NORMAL:
272 if not _VERIFY_FN[fdef.kind](value):
273 errs.append("normal field %s fails validation (value is %s)" %
274 (fdef.name, value))
275 elif value is not None:
276 errs.append("abnormal field %s has a non-None value" % fdef.name)
277 assert not errs, ("Failed validation: %s in row %s" %
278 (utils.CommaJoin(errors), row))
279
280
282 """Prepares field list for use by L{Query}.
283
284 Converts the list to a dictionary and does some verification.
285
286 @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data
287 kind, retrieval function)
288 @param fields: List of fields, see L{Query.__init__} for a better
289 description
290 @type aliases: list of tuples; (alias, target)
291 @param aliases: list of tuples containing aliases; for each
292 alias/target pair, a duplicate will be created in the field list
293 @rtype: dict
294 @return: Field dictionary for L{Query}
295
296 """
297 if __debug__:
298 duplicates = utils.FindDuplicates(fdef.title.lower()
299 for (fdef, _, _) in fields)
300 assert not duplicates, "Duplicate title(s) found: %r" % duplicates
301
302 result = {}
303
304 for field in fields:
305 (fdef, _, fn) = field
306
307 assert fdef.name and fdef.title, "Name and title are required"
308 assert FIELD_NAME_RE.match(fdef.name)
309 assert TITLE_RE.match(fdef.title)
310 assert callable(fn)
311 assert fdef.name not in result, \
312 "Duplicate field name '%s' found" % fdef.name
313
314 result[fdef.name] = field
315
316 for alias, target in aliases:
317 assert alias not in result, "Alias %s overrides an existing field" % alias
318 assert target in result, "Missing target %s for alias %s" % (target, alias)
319 (fdef, k, fn) = result[target]
320 fdef = fdef.Copy()
321 fdef.name = alias
322 result[alias] = (fdef, k, fn)
323
324 assert len(result) == len(fields) + len(aliases)
325 assert compat.all(name == fdef.name
326 for (name, (fdef, _, _)) in result.items())
327
328 return result
329
330
340
341
343 """Returns list of available fields.
344
345 @type fielddefs: dict
346 @param fielddefs: Field definitions
347 @type selected: list of strings
348 @param selected: List of selected fields
349 @return: List of L{objects.QueryFieldDefinition}
350
351 """
352 if selected is None:
353
354 fdefs = utils.NiceSort(GetAllFields(fielddefs.values()),
355 key=operator.attrgetter("name"))
356 else:
357
358 fdefs = Query(fielddefs, selected).GetFields()
359
360 return objects.QueryFieldsResponse(fields=fdefs).ToDict()
361
362
364 """Wrapper for creating L{objects.QueryFieldDefinition} instances.
365
366 @param name: Field name as a regular expression
367 @param title: Human-readable title
368 @param kind: Field type
369
370 """
371 return objects.QueryFieldDefinition(name=name, title=title, kind=kind)
372
373
375 """Determine node role.
376
377 @type node: L{objects.Node}
378 @param node: Node object
379 @type master_name: string
380 @param master_name: Master node name
381
382 """
383 if node.name == master_name:
384 return "M"
385 elif node.master_candidate:
386 return "C"
387 elif node.drained:
388 return "D"
389 elif node.offline:
390 return "O"
391 else:
392 return "R"
393
394
396 """Returns a field function to return an attribute of the item.
397
398 @param attr: Attribute name
399
400 """
401 getter = operator.attrgetter(attr)
402 return lambda _, item: getter(item)
403
404
406 """Returns function for getting timestamp of item.
407
408 @type getter: callable
409 @param getter: Function to retrieve timestamp attribute
410
411 """
412 def fn(_, item):
413 """Returns a timestamp of item.
414
415 """
416 timestamp = getter(item)
417 if timestamp is None:
418
419 return _FS_UNAVAIL
420 else:
421 return timestamp
422
423 return fn
424
425
427 """Returns common timestamp fields.
428
429 @param datatype: Field data type for use by L{Query.RequestedData}
430
431 """
432 return [
433 (_MakeField("ctime", "CTime", QFT_TIMESTAMP), datatype,
434 _GetItemTimestamp(operator.attrgetter("ctime"))),
435 (_MakeField("mtime", "MTime", QFT_TIMESTAMP), datatype,
436 _GetItemTimestamp(operator.attrgetter("mtime"))),
437 ]
438
439
441 """Data container for node data queries.
442
443 """
444 - def __init__(self, nodes, live_data, master_name, node_to_primary,
445 node_to_secondary, groups, oob_support, cluster):
446 """Initializes this class.
447
448 """
449 self.nodes = nodes
450 self.live_data = live_data
451 self.master_name = master_name
452 self.node_to_primary = node_to_primary
453 self.node_to_secondary = node_to_secondary
454 self.groups = groups
455 self.oob_support = oob_support
456 self.cluster = cluster
457
458
459 self.curlive_data = None
460
462 """Iterate over all nodes.
463
464 This function has side-effects and only one instance of the resulting
465 generator should be used at a time.
466
467 """
468 for node in self.nodes:
469 if self.live_data:
470 self.curlive_data = self.live_data.get(node.name, None)
471 else:
472 self.curlive_data = None
473 yield node
474
475
476
477 _NODE_SIMPLE_FIELDS = {
478 "drained": ("Drained", QFT_BOOL),
479 "master_candidate": ("MasterC", QFT_BOOL),
480 "master_capable": ("MasterCapable", QFT_BOOL),
481 "name": ("Node", QFT_TEXT),
482 "offline": ("Offline", QFT_BOOL),
483 "serial_no": ("SerialNo", QFT_NUMBER),
484 "uuid": ("UUID", QFT_TEXT),
485 "vm_capable": ("VMCapable", QFT_BOOL),
486 }
487
488
489
490
491 _NODE_LIVE_FIELDS = {
492 "bootid": ("BootID", QFT_TEXT, "bootid"),
493 "cnodes": ("CNodes", QFT_NUMBER, "cpu_nodes"),
494 "csockets": ("CSockets", QFT_NUMBER, "cpu_sockets"),
495 "ctotal": ("CTotal", QFT_NUMBER, "cpu_total"),
496 "dfree": ("DFree", QFT_UNIT, "vg_free"),
497 "dtotal": ("DTotal", QFT_UNIT, "vg_size"),
498 "mfree": ("MFree", QFT_UNIT, "memory_free"),
499 "mnode": ("MNode", QFT_UNIT, "memory_dom0"),
500 "mtotal": ("MTotal", QFT_UNIT, "memory_total"),
501 }
502
503
505 """Build function for calling another function with an node group.
506
507 @param cb: The callback to be called with the nodegroup
508
509 """
510 def fn(ctx, node):
511 """Get group data for a node.
512
513 @type ctx: L{NodeQueryData}
514 @type inst: L{objects.Node}
515 @param inst: Node object
516
517 """
518 ng = ctx.groups.get(node.group, None)
519 if ng is None:
520
521 return _FS_UNAVAIL
522
523 return cb(ctx, node, ng)
524
525 return fn
526
527
529 """Returns the name of a node's group.
530
531 @type ctx: L{NodeQueryData}
532 @type node: L{objects.Node}
533 @param node: Node object
534 @type ng: L{objects.NodeGroup}
535 @param ng: The node group this node belongs to
536
537 """
538 return ng.name
539
540
542 """Returns the node powered state
543
544 @type ctx: L{NodeQueryData}
545 @type node: L{objects.Node}
546 @param node: Node object
547
548 """
549 if ctx.oob_support[node.name]:
550 return node.powered
551
552 return _FS_UNAVAIL
553
554
556 """Returns the ndparams for this node.
557
558 @type ctx: L{NodeQueryData}
559 @type node: L{objects.Node}
560 @param node: Node object
561 @type ng: L{objects.NodeGroup}
562 @param ng: The node group this node belongs to
563
564 """
565 return ctx.cluster.SimpleFillND(ng.FillND(node))
566
567
569 """Gets the value of a "live" field from L{NodeQueryData}.
570
571 @param field: Live field name
572 @param kind: Data kind, one of L{constants.QFT_ALL}
573 @type ctx: L{NodeQueryData}
574 @type node: L{objects.Node}
575 @param node: Node object
576
577 """
578 if node.offline:
579 return _FS_OFFLINE
580
581 if not node.vm_capable:
582 return _FS_UNAVAIL
583
584 if not ctx.curlive_data:
585 return _FS_NODATA
586
587 try:
588 value = ctx.curlive_data[field]
589 except KeyError:
590 return _FS_UNAVAIL
591
592 if kind == QFT_TEXT:
593 return value
594
595 assert kind in (QFT_NUMBER, QFT_UNIT)
596
597
598 try:
599 return int(value)
600 except (ValueError, TypeError):
601 logging.exception("Failed to convert node field '%s' (value %r) to int",
602 value, field)
603 return _FS_UNAVAIL
604
605
607 """Builds list of fields for node queries.
608
609 """
610 fields = [
611 (_MakeField("pip", "PrimaryIP", QFT_TEXT), NQ_CONFIG,
612 _GetItemAttr("primary_ip")),
613 (_MakeField("sip", "SecondaryIP", QFT_TEXT), NQ_CONFIG,
614 _GetItemAttr("secondary_ip")),
615 (_MakeField("tags", "Tags", QFT_OTHER), NQ_CONFIG,
616 lambda ctx, node: list(node.GetTags())),
617 (_MakeField("master", "IsMaster", QFT_BOOL), NQ_CONFIG,
618 lambda ctx, node: node.name == ctx.master_name),
619 (_MakeField("role", "Role", QFT_TEXT), NQ_CONFIG,
620 lambda ctx, node: _GetNodeRole(node, ctx.master_name)),
621 (_MakeField("group", "Group", QFT_TEXT), NQ_GROUP,
622 _GetGroup(_GetNodeGroup)),
623 (_MakeField("group.uuid", "GroupUUID", QFT_TEXT),
624 NQ_CONFIG, _GetItemAttr("group")),
625 (_MakeField("powered", "Powered", QFT_BOOL), NQ_OOB, _GetNodePower),
626 (_MakeField("ndparams", "NodeParameters", QFT_OTHER), NQ_GROUP,
627 _GetGroup(_GetNdParams)),
628 (_MakeField("custom_ndparams", "CustomNodeParameters", QFT_OTHER),
629 NQ_GROUP, _GetItemAttr("ndparams")),
630 ]
631
632 def _GetLength(getter):
633 return lambda ctx, node: len(getter(ctx)[node.name])
634
635 def _GetList(getter):
636 return lambda ctx, node: list(getter(ctx)[node.name])
637
638
639 for prefix, titleprefix, getter in \
640 [("p", "Pri", operator.attrgetter("node_to_primary")),
641 ("s", "Sec", operator.attrgetter("node_to_secondary"))]:
642 fields.extend([
643 (_MakeField("%sinst_cnt" % prefix, "%sinst" % prefix.upper(), QFT_NUMBER),
644 NQ_INST, _GetLength(getter)),
645 (_MakeField("%sinst_list" % prefix, "%sInstances" % titleprefix,
646 QFT_OTHER),
647 NQ_INST, _GetList(getter)),
648 ])
649
650
651 fields.extend([(_MakeField(name, title, kind), NQ_CONFIG, _GetItemAttr(name))
652 for (name, (title, kind)) in _NODE_SIMPLE_FIELDS.items()])
653
654
655 fields.extend([
656 (_MakeField(name, title, kind), NQ_LIVE,
657 compat.partial(_GetLiveNodeField, nfield, kind))
658 for (name, (title, kind, nfield)) in _NODE_LIVE_FIELDS.items()
659 ])
660
661
662 fields.extend(_GetItemTimestampFields(NQ_CONFIG))
663
664 return _PrepareFieldList(fields, [])
665
666
668 """Data container for instance data queries.
669
670 """
671 - def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
672 live_data, wrongnode_inst, console):
673 """Initializes this class.
674
675 @param instances: List of instance objects
676 @param cluster: Cluster object
677 @type disk_usage: dict; instance name as key
678 @param disk_usage: Per-instance disk usage
679 @type offline_nodes: list of strings
680 @param offline_nodes: List of offline nodes
681 @type bad_nodes: list of strings
682 @param bad_nodes: List of faulty nodes
683 @type live_data: dict; instance name as key
684 @param live_data: Per-instance live data
685 @type wrongnode_inst: set
686 @param wrongnode_inst: Set of instances running on wrong node(s)
687 @type console: dict; instance name as key
688 @param console: Per-instance console information
689
690 """
691 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
692 "Offline nodes not included in bad nodes"
693 assert not (set(live_data.keys()) & set(bad_nodes)), \
694 "Found live data for bad or offline nodes"
695
696 self.instances = instances
697 self.cluster = cluster
698 self.disk_usage = disk_usage
699 self.offline_nodes = offline_nodes
700 self.bad_nodes = bad_nodes
701 self.live_data = live_data
702 self.wrongnode_inst = wrongnode_inst
703 self.console = console
704
705
706 self.inst_hvparams = None
707 self.inst_beparams = None
708 self.inst_nicparams = None
709
711 """Iterate over all instances.
712
713 This function has side-effects and only one instance of the resulting
714 generator should be used at a time.
715
716 """
717 for inst in self.instances:
718 self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
719 self.inst_beparams = self.cluster.FillBE(inst)
720 self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
721 for nic in inst.nics]
722
723 yield inst
724
725
727 """Get instance's operational status.
728
729 @type ctx: L{InstanceQueryData}
730 @type inst: L{objects.Instance}
731 @param inst: Instance object
732
733 """
734
735
736 if inst.primary_node in ctx.bad_nodes:
737 return _FS_NODATA
738 else:
739 return bool(ctx.live_data.get(inst.name))
740
741
743 """Build function for retrieving live data.
744
745 @type name: string
746 @param name: Live data field name
747
748 """
749 def fn(ctx, inst):
750 """Get live data for an instance.
751
752 @type ctx: L{InstanceQueryData}
753 @type inst: L{objects.Instance}
754 @param inst: Instance object
755
756 """
757 if (inst.primary_node in ctx.bad_nodes or
758 inst.primary_node in ctx.offline_nodes):
759
760
761 return _FS_NODATA
762
763 if inst.name in ctx.live_data:
764 data = ctx.live_data[inst.name]
765 if name in data:
766 return data[name]
767
768 return _FS_UNAVAIL
769
770 return fn
771
772
774 """Get instance status.
775
776 @type ctx: L{InstanceQueryData}
777 @type inst: L{objects.Instance}
778 @param inst: Instance object
779
780 """
781 if inst.primary_node in ctx.offline_nodes:
782 return "ERROR_nodeoffline"
783
784 if inst.primary_node in ctx.bad_nodes:
785 return "ERROR_nodedown"
786
787 if bool(ctx.live_data.get(inst.name)):
788 if inst.name in ctx.wrongnode_inst:
789 return "ERROR_wrongnode"
790 elif inst.admin_up:
791 return "running"
792 else:
793 return "ERROR_up"
794
795 if inst.admin_up:
796 return "ERROR_down"
797
798 return "ADMIN_down"
799
800
802 """Build function for retrieving disk size.
803
804 @type index: int
805 @param index: Disk index
806
807 """
808 def fn(_, inst):
809 """Get size of a disk.
810
811 @type inst: L{objects.Instance}
812 @param inst: Instance object
813
814 """
815 try:
816 return inst.disks[index].size
817 except IndexError:
818 return _FS_UNAVAIL
819
820 return fn
821
822
824 """Build function for calling another function with an instance NIC.
825
826 @type index: int
827 @param index: NIC index
828 @type cb: callable
829 @param cb: Callback
830
831 """
832 def fn(ctx, inst):
833 """Call helper function with instance NIC.
834
835 @type ctx: L{InstanceQueryData}
836 @type inst: L{objects.Instance}
837 @param inst: Instance object
838
839 """
840 try:
841 nic = inst.nics[index]
842 except IndexError:
843 return _FS_UNAVAIL
844
845 return cb(ctx, index, nic)
846
847 return fn
848
849
851 """Get a NIC's IP address.
852
853 @type ctx: L{InstanceQueryData}
854 @type nic: L{objects.NIC}
855 @param nic: NIC object
856
857 """
858 if nic.ip is None:
859 return _FS_UNAVAIL
860 else:
861 return nic.ip
862
863
865 """Get a NIC's bridge.
866
867 @type ctx: L{InstanceQueryData}
868 @type index: int
869 @param index: NIC index
870
871 """
872 assert len(ctx.inst_nicparams) >= index
873
874 nicparams = ctx.inst_nicparams[index]
875
876 if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
877 return nicparams[constants.NIC_LINK]
878 else:
879 return _FS_UNAVAIL
880
881
883 """Get all network bridges for an instance.
884
885 @type ctx: L{InstanceQueryData}
886 @type inst: L{objects.Instance}
887 @param inst: Instance object
888
889 """
890 assert len(ctx.inst_nicparams) == len(inst.nics)
891
892 result = []
893
894 for nicp in ctx.inst_nicparams:
895 if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
896 result.append(nicp[constants.NIC_LINK])
897 else:
898 result.append(None)
899
900 assert len(result) == len(inst.nics)
901
902 return result
903
904
906 """Build function for retrieving a NIC parameter.
907
908 @type name: string
909 @param name: Parameter name
910
911 """
912 def fn(ctx, index, _):
913 """Get a NIC's bridge.
914
915 @type ctx: L{InstanceQueryData}
916 @type inst: L{objects.Instance}
917 @param inst: Instance object
918 @type nic: L{objects.NIC}
919 @param nic: NIC object
920
921 """
922 assert len(ctx.inst_nicparams) >= index
923 return ctx.inst_nicparams[index][name]
924
925 return fn
926
927
929 """Get instance fields involving network interfaces.
930
931 @return: List of field definitions used as input for L{_PrepareFieldList}
932
933 """
934 nic_mac_fn = lambda ctx, _, nic: nic.mac
935 nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
936 nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
937
938 fields = [
939
940 (_MakeField("ip", "IP_address", QFT_TEXT), IQ_CONFIG,
941 _GetInstNic(0, _GetInstNicIp)),
942 (_MakeField("mac", "MAC_address", QFT_TEXT), IQ_CONFIG,
943 _GetInstNic(0, nic_mac_fn)),
944 (_MakeField("bridge", "Bridge", QFT_TEXT), IQ_CONFIG,
945 _GetInstNic(0, _GetInstNicBridge)),
946 (_MakeField("nic_mode", "NIC_Mode", QFT_TEXT), IQ_CONFIG,
947 _GetInstNic(0, nic_mode_fn)),
948 (_MakeField("nic_link", "NIC_Link", QFT_TEXT), IQ_CONFIG,
949 _GetInstNic(0, nic_link_fn)),
950
951
952 (_MakeField("nic.count", "NICs", QFT_NUMBER), IQ_CONFIG,
953 lambda ctx, inst: len(inst.nics)),
954 (_MakeField("nic.macs", "NIC_MACs", QFT_OTHER), IQ_CONFIG,
955 lambda ctx, inst: [nic.mac for nic in inst.nics]),
956 (_MakeField("nic.ips", "NIC_IPs", QFT_OTHER), IQ_CONFIG,
957 lambda ctx, inst: [nic.ip for nic in inst.nics]),
958 (_MakeField("nic.modes", "NIC_modes", QFT_OTHER), IQ_CONFIG,
959 lambda ctx, inst: [nicp[constants.NIC_MODE]
960 for nicp in ctx.inst_nicparams]),
961 (_MakeField("nic.links", "NIC_links", QFT_OTHER), IQ_CONFIG,
962 lambda ctx, inst: [nicp[constants.NIC_LINK]
963 for nicp in ctx.inst_nicparams]),
964 (_MakeField("nic.bridges", "NIC_bridges", QFT_OTHER), IQ_CONFIG,
965 _GetInstAllNicBridges),
966 ]
967
968
969 for i in range(constants.MAX_NICS):
970 fields.extend([
971 (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, QFT_TEXT),
972 IQ_CONFIG, _GetInstNic(i, _GetInstNicIp)),
973 (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, QFT_TEXT),
974 IQ_CONFIG, _GetInstNic(i, nic_mac_fn)),
975 (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, QFT_TEXT),
976 IQ_CONFIG, _GetInstNic(i, nic_mode_fn)),
977 (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, QFT_TEXT),
978 IQ_CONFIG, _GetInstNic(i, nic_link_fn)),
979 (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, QFT_TEXT),
980 IQ_CONFIG, _GetInstNic(i, _GetInstNicBridge)),
981 ])
982
983 return fields
984
985
987 """Get disk usage for an instance.
988
989 @type ctx: L{InstanceQueryData}
990 @type inst: L{objects.Instance}
991 @param inst: Instance object
992
993 """
994 usage = ctx.disk_usage[inst.name]
995
996 if usage is None:
997 usage = 0
998
999 return usage
1000
1001
1003 """Get console information for instance.
1004
1005 @type ctx: L{InstanceQueryData}
1006 @type inst: L{objects.Instance}
1007 @param inst: Instance object
1008
1009 """
1010 consinfo = ctx.console[inst.name]
1011
1012 if consinfo is None:
1013 return _FS_UNAVAIL
1014
1015 return consinfo
1016
1017
1019 """Get instance fields involving disks.
1020
1021 @return: List of field definitions used as input for L{_PrepareFieldList}
1022
1023 """
1024 fields = [
1025 (_MakeField("disk_usage", "DiskUsage", QFT_UNIT), IQ_DISKUSAGE,
1026 _GetInstDiskUsage),
1027 (_MakeField("disk.count", "Disks", QFT_NUMBER), IQ_CONFIG,
1028 lambda ctx, inst: len(inst.disks)),
1029 (_MakeField("disk.sizes", "Disk_sizes", QFT_OTHER), IQ_CONFIG,
1030 lambda ctx, inst: [disk.size for disk in inst.disks]),
1031 ]
1032
1033
1034 fields.extend([
1035 (_MakeField("disk.size/%s" % i, "Disk/%s" % i, QFT_UNIT),
1036 IQ_CONFIG, _GetInstDiskSize(i))
1037 for i in range(constants.MAX_DISKS)
1038 ])
1039
1040 return fields
1041
1042
1044 """Get instance fields involving parameters.
1045
1046 @return: List of field definitions used as input for L{_PrepareFieldList}
1047
1048 """
1049
1050 be_title = {
1051 constants.BE_AUTO_BALANCE: "Auto_balance",
1052 constants.BE_MEMORY: "ConfigMemory",
1053 constants.BE_VCPUS: "ConfigVCPUs",
1054 }
1055
1056 hv_title = {
1057 constants.HV_ACPI: "ACPI",
1058 constants.HV_BOOT_ORDER: "Boot_order",
1059 constants.HV_CDROM_IMAGE_PATH: "CDROM_image_path",
1060 constants.HV_DISK_TYPE: "Disk_type",
1061 constants.HV_INITRD_PATH: "Initrd_path",
1062 constants.HV_KERNEL_PATH: "Kernel_path",
1063 constants.HV_NIC_TYPE: "NIC_type",
1064 constants.HV_PAE: "PAE",
1065 constants.HV_VNC_BIND_ADDRESS: "VNC_bind_address",
1066 }
1067
1068 fields = [
1069
1070 (_MakeField("hvparams", "HypervisorParameters", QFT_OTHER),
1071 IQ_CONFIG, lambda ctx, _: ctx.inst_hvparams),
1072 (_MakeField("beparams", "BackendParameters", QFT_OTHER),
1073 IQ_CONFIG, lambda ctx, _: ctx.inst_beparams),
1074
1075
1076 (_MakeField("custom_hvparams", "CustomHypervisorParameters", QFT_OTHER),
1077 IQ_CONFIG, _GetItemAttr("hvparams")),
1078 (_MakeField("custom_beparams", "CustomBackendParameters", QFT_OTHER),
1079 IQ_CONFIG, _GetItemAttr("beparams")),
1080 (_MakeField("custom_nicparams", "CustomNicParameters", QFT_OTHER),
1081 IQ_CONFIG, lambda ctx, inst: [nic.nicparams for nic in inst.nics]),
1082 ]
1083
1084
1085 def _GetInstHvParam(name):
1086 return lambda ctx, _: ctx.inst_hvparams.get(name, _FS_UNAVAIL)
1087
1088 fields.extend([
1089 (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name),
1090 _VTToQFT[kind]),
1091 IQ_CONFIG, _GetInstHvParam(name))
1092 for name, kind in constants.HVS_PARAMETER_TYPES.items()
1093 if name not in constants.HVC_GLOBALS
1094 ])
1095
1096
1097 def _GetInstBeParam(name):
1098 return lambda ctx, _: ctx.inst_beparams.get(name, None)
1099
1100 fields.extend([
1101 (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name),
1102 _VTToQFT[kind]), IQ_CONFIG,
1103 _GetInstBeParam(name))
1104 for name, kind in constants.BES_PARAMETER_TYPES.items()
1105 ])
1106
1107 return fields
1108
1109
1110 _INST_SIMPLE_FIELDS = {
1111 "disk_template": ("Disk_template", QFT_TEXT),
1112 "hypervisor": ("Hypervisor", QFT_TEXT),
1113 "name": ("Instance", QFT_TEXT),
1114
1115 "network_port": ("Network_port", QFT_OTHER),
1116 "os": ("OS", QFT_TEXT),
1117 "serial_no": ("SerialNo", QFT_NUMBER),
1118 "uuid": ("UUID", QFT_TEXT),
1119 }
1120
1121
1123 """Builds list of fields for instance queries.
1124
1125 """
1126 fields = [
1127 (_MakeField("pnode", "Primary_node", QFT_TEXT), IQ_CONFIG,
1128 _GetItemAttr("primary_node")),
1129 (_MakeField("snodes", "Secondary_Nodes", QFT_OTHER), IQ_CONFIG,
1130 lambda ctx, inst: list(inst.secondary_nodes)),
1131 (_MakeField("admin_state", "Autostart", QFT_BOOL), IQ_CONFIG,
1132 _GetItemAttr("admin_up")),
1133 (_MakeField("tags", "Tags", QFT_OTHER), IQ_CONFIG,
1134 lambda ctx, inst: list(inst.GetTags())),
1135 (_MakeField("console", "Console", QFT_OTHER), IQ_CONSOLE,
1136 _GetInstanceConsole),
1137 ]
1138
1139
1140 fields.extend([(_MakeField(name, title, kind), IQ_CONFIG, _GetItemAttr(name))
1141 for (name, (title, kind)) in _INST_SIMPLE_FIELDS.items()])
1142
1143
1144 fields.extend([
1145 (_MakeField("oper_state", "Running", QFT_BOOL), IQ_LIVE,
1146 _GetInstOperState),
1147 (_MakeField("oper_ram", "Memory", QFT_UNIT), IQ_LIVE,
1148 _GetInstLiveData("memory")),
1149 (_MakeField("oper_vcpus", "VCPUs", QFT_NUMBER), IQ_LIVE,
1150 _GetInstLiveData("vcpus")),
1151 (_MakeField("status", "Status", QFT_TEXT), IQ_LIVE, _GetInstStatus),
1152 ])
1153
1154 fields.extend(_GetInstanceParameterFields())
1155 fields.extend(_GetInstanceDiskFields())
1156 fields.extend(_GetInstanceNetworkFields())
1157 fields.extend(_GetItemTimestampFields(IQ_CONFIG))
1158
1159 aliases = [
1160 ("vcpus", "be/vcpus"),
1161 ("sda_size", "disk.size/0"),
1162 ("sdb_size", "disk.size/1"),
1163 ]
1164
1165 return _PrepareFieldList(fields, aliases)
1166
1167
1169 """Data container for lock data queries.
1170
1171 """
1173 """Initializes this class.
1174
1175 """
1176 self.lockdata = lockdata
1177
1179 """Iterate over all locks.
1180
1181 """
1182 return iter(self.lockdata)
1183
1184
1186 """Returns a sorted list of a lock's current owners.
1187
1188 """
1189 (_, _, owners, _) = data
1190
1191 if owners:
1192 owners = utils.NiceSort(owners)
1193
1194 return owners
1195
1196
1198 """Returns a sorted list of a lock's pending acquires.
1199
1200 """
1201 (_, _, _, pending) = data
1202
1203 if pending:
1204 pending = [(mode, utils.NiceSort(names))
1205 for (mode, names) in pending]
1206
1207 return pending
1208
1209
1211 """Builds list of fields for lock queries.
1212
1213 """
1214 return _PrepareFieldList([
1215 (_MakeField("name", "Name", QFT_TEXT), None,
1216 lambda ctx, (name, mode, owners, pending): name),
1217 (_MakeField("mode", "Mode", QFT_OTHER), LQ_MODE,
1218 lambda ctx, (name, mode, owners, pending): mode),
1219 (_MakeField("owner", "Owner", QFT_OTHER), LQ_OWNER, _GetLockOwners),
1220 (_MakeField("pending", "Pending", QFT_OTHER), LQ_PENDING, _GetLockPending),
1221 ], [])
1222
1223
1225 """Data container for node group data queries.
1226
1227 """
1228 - def __init__(self, groups, group_to_nodes, group_to_instances):
1229 """Initializes this class.
1230
1231 @param groups: List of node group objects
1232 @type group_to_nodes: dict; group UUID as key
1233 @param group_to_nodes: Per-group list of nodes
1234 @type group_to_instances: dict; group UUID as key
1235 @param group_to_instances: Per-group list of (primary) instances
1236
1237 """
1238 self.groups = groups
1239 self.group_to_nodes = group_to_nodes
1240 self.group_to_instances = group_to_instances
1241
1243 """Iterate over all node groups.
1244
1245 """
1246 return iter(self.groups)
1247
1248
1249 _GROUP_SIMPLE_FIELDS = {
1250 "alloc_policy": ("AllocPolicy", QFT_TEXT),
1251 "name": ("Group", QFT_TEXT),
1252 "serial_no": ("SerialNo", QFT_NUMBER),
1253 "uuid": ("UUID", QFT_TEXT),
1254 "ndparams": ("NDParams", QFT_OTHER),
1255 }
1256
1257
1259 """Builds list of fields for node group queries.
1260
1261 """
1262
1263 fields = [(_MakeField(name, title, kind), GQ_CONFIG, _GetItemAttr(name))
1264 for (name, (title, kind)) in _GROUP_SIMPLE_FIELDS.items()]
1265
1266 def _GetLength(getter):
1267 return lambda ctx, group: len(getter(ctx)[group.uuid])
1268
1269 def _GetSortedList(getter):
1270 return lambda ctx, group: utils.NiceSort(getter(ctx)[group.uuid])
1271
1272 group_to_nodes = operator.attrgetter("group_to_nodes")
1273 group_to_instances = operator.attrgetter("group_to_instances")
1274
1275
1276 fields.extend([
1277 (_MakeField("node_cnt", "Nodes", QFT_NUMBER),
1278 GQ_NODE, _GetLength(group_to_nodes)),
1279 (_MakeField("node_list", "NodeList", QFT_OTHER),
1280 GQ_NODE, _GetSortedList(group_to_nodes)),
1281 ])
1282
1283
1284 fields.extend([
1285 (_MakeField("pinst_cnt", "Instances", QFT_NUMBER),
1286 GQ_INST, _GetLength(group_to_instances)),
1287 (_MakeField("pinst_list", "InstanceList", QFT_OTHER),
1288 GQ_INST, _GetSortedList(group_to_instances)),
1289 ])
1290
1291 fields.extend(_GetItemTimestampFields(GQ_CONFIG))
1292
1293 return _PrepareFieldList(fields, [])
1294
1295
1296
1297 NODE_FIELDS = _BuildNodeFields()
1298
1299
1300 INSTANCE_FIELDS = _BuildInstanceFields()
1301
1302
1303 LOCK_FIELDS = _BuildLockFields()
1304
1305
1306 GROUP_FIELDS = _BuildGroupFields()
1307
1308
1309 ALL_FIELD_LISTS = [NODE_FIELDS, INSTANCE_FIELDS, LOCK_FIELDS, GROUP_FIELDS]
1310