4 # Copyright (C) 2010 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 """Module for query operations"""
28 from ganeti import constants
29 from ganeti import errors
30 from ganeti import utils
31 from ganeti import compat
32 from ganeti import objects
39 NQ_GROUP) = range(1, 5)
43 IQ_DISKUSAGE) = range(100, 103)
47 LQ_PENDING) = range(10, 13)
51 GQ_INST) = range(200, 203)
54 FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$")
55 TITLE_RE = re.compile(r"^[^\s]+$")
57 #: Verification function for each field type
59 constants.QFT_UNKNOWN: ht.TNone,
60 constants.QFT_TEXT: ht.TString,
61 constants.QFT_BOOL: ht.TBool,
62 constants.QFT_NUMBER: ht.TInt,
63 constants.QFT_UNIT: ht.TInt,
64 constants.QFT_TIMESTAMP: ht.TOr(ht.TInt, ht.TFloat),
65 constants.QFT_OTHER: lambda _: True,
69 def _GetUnknownField(ctx, item): # pylint: disable-msg=W0613
70 """Gets the contents of an unknown field.
73 return (constants.QRFS_UNKNOWN, None)
76 def _GetQueryFields(fielddefs, selected):
77 """Calculates the internal list of selected fields.
79 Unknown fields are returned as L{constants.QFT_UNKNOWN}.
82 @param fielddefs: Field definitions
83 @type selected: list of strings
84 @param selected: List of selected fields
91 fdef = fielddefs[name]
93 fdef = (_MakeField(name, name, constants.QFT_UNKNOWN),
94 None, _GetUnknownField)
103 def GetAllFields(fielddefs):
104 """Extract L{objects.QueryFieldDefinition} from field definitions.
106 @rtype: list of L{objects.QueryFieldDefinition}
109 return [fdef for (fdef, _, _) in fielddefs]
113 def __init__(self, fieldlist, selected):
114 """Initializes this class.
116 The field definition is a dictionary with the field's name as a key and a
117 tuple containing, in order, the field definition object
118 (L{objects.QueryFieldDefinition}, the data kind to help calling code
119 collect data and a retrieval function. The retrieval function is called
120 with two parameters, in order, the data container and the item in container
121 (see L{Query.Query}).
123 Users of this class can call L{RequestedData} before preparing the data
124 container to determine what data is needed.
126 @type fieldlist: dictionary
127 @param fieldlist: Field definitions
128 @type selected: list of strings
129 @param selected: List of selected fields
132 self._fields = _GetQueryFields(fieldlist, selected)
134 def RequestedData(self):
135 """Gets requested kinds of data.
140 return frozenset(datakind
141 for (_, datakind, _) in self._fields
142 if datakind is not None)
145 """Returns the list of fields for this query.
147 Includes unknown fields.
149 @rtype: List of L{objects.QueryFieldDefinition}
152 return GetAllFields(self._fields)
154 def Query(self, ctx):
157 @param ctx: Data container passed to field retrieval functions, must
158 support iteration using C{__iter__}
161 result = [[fn(ctx, item) for (_, _, fn) in self._fields]
166 for (idx, row) in enumerate(result):
167 assert _VerifyResultRow(self._fields, row), \
168 ("Inconsistent result for fields %s in row %s: %r" %
169 (GetAllFields(self._fields), idx, row))
173 def OldStyleQuery(self, ctx):
174 """Query with "old" query result format.
176 See L{Query.Query} for arguments.
179 unknown = set(fdef.name
180 for (fdef, _, _) in self._fields
181 if fdef.kind == constants.QFT_UNKNOWN)
183 raise errors.OpPrereqError("Unknown output fields selected: %s" %
184 (utils.CommaJoin(unknown), ),
187 return [[value for (_, value) in row]
188 for row in self.Query(ctx)]
191 def _VerifyResultRow(fields, row):
192 """Verifies the contents of a query result row.
195 @param fields: Field definitions for result
196 @type row: list of tuples
200 return (len(row) == len(fields) and
201 compat.all((status == constants.QRFS_NORMAL and
202 _VERIFY_FN[fdef.kind](value)) or
203 # Value for an abnormal status must be None
204 (status != constants.QRFS_NORMAL and value is None)
205 for ((status, value), (fdef, _, _)) in zip(row, fields)))
208 def _PrepareFieldList(fields):
209 """Prepares field list for use by L{Query}.
211 Converts the list to a dictionary and does some verification.
213 @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data kind,
215 @param fields: List of fields
217 @return: Field dictionary for L{Query}
221 duplicates = utils.FindDuplicates(fdef.title.lower()
222 for (fdef, _, _) in fields)
223 assert not duplicates, "Duplicate title(s) found: %r" % duplicates
228 (fdef, _, fn) = field
230 assert fdef.name and fdef.title, "Name and title are required"
231 assert FIELD_NAME_RE.match(fdef.name)
232 assert TITLE_RE.match(fdef.title)
234 assert fdef.name not in result, \
235 "Duplicate field name '%s' found" % fdef.name
237 result[fdef.name] = field
239 assert len(result) == len(fields)
240 assert compat.all(name == fdef.name
241 for (name, (fdef, _, _)) in result.items())
246 def GetQueryResponse(query, ctx):
247 """Prepares the response for a query.
249 @type query: L{Query}
250 @param ctx: Data container, see L{Query.Query}
253 return objects.QueryResponse(data=query.Query(ctx),
254 fields=query.GetFields()).ToDict()
257 def QueryFields(fielddefs, selected):
258 """Returns list of available fields.
260 @type fielddefs: dict
261 @param fielddefs: Field definitions
262 @type selected: list of strings
263 @param selected: List of selected fields
264 @return: List of L{objects.QueryFieldDefinition}
268 # Client requests all fields, sort by name
269 fdefs = utils.NiceSort(GetAllFields(fielddefs.values()),
270 key=operator.attrgetter("name"))
272 # Keep order as requested by client
273 fdefs = Query(fielddefs, selected).GetFields()
275 return objects.QueryFieldsResponse(fields=fdefs).ToDict()
278 def _MakeField(name, title, kind):
279 """Wrapper for creating L{objects.QueryFieldDefinition} instances.
281 @param name: Field name as a regular expression
282 @param title: Human-readable title
283 @param kind: Field type
286 return objects.QueryFieldDefinition(name=name, title=title, kind=kind)
289 def _GetNodeRole(node, master_name):
290 """Determine node role.
292 @type node: L{objects.Node}
293 @param node: Node object
294 @type master_name: string
295 @param master_name: Master node name
298 if node.name == master_name:
300 elif node.master_candidate:
310 def _GetItemAttr(attr):
311 """Returns a field function to return an attribute of the item.
313 @param attr: Attribute name
316 getter = operator.attrgetter(attr)
317 return lambda _, item: (constants.QRFS_NORMAL, getter(item))
320 def _GetItemTimestamp(getter):
321 """Returns function for getting timestamp of item.
323 @type getter: callable
324 @param getter: Function to retrieve timestamp attribute
328 """Returns a timestamp of item.
331 timestamp = getter(item)
332 if timestamp is None:
333 # Old configs might not have all timestamps
334 return (constants.QRFS_UNAVAIL, None)
336 return (constants.QRFS_NORMAL, timestamp)
341 def _GetItemTimestampFields(datatype):
342 """Returns common timestamp fields.
344 @param datatype: Field data type for use by L{Query.RequestedData}
348 (_MakeField("ctime", "CTime", constants.QFT_TIMESTAMP), datatype,
349 _GetItemTimestamp(operator.attrgetter("ctime"))),
350 (_MakeField("mtime", "MTime", constants.QFT_TIMESTAMP), datatype,
351 _GetItemTimestamp(operator.attrgetter("mtime"))),
356 """Data container for node data queries.
359 def __init__(self, nodes, live_data, master_name, node_to_primary,
360 node_to_secondary, groups):
361 """Initializes this class.
365 self.live_data = live_data
366 self.master_name = master_name
367 self.node_to_primary = node_to_primary
368 self.node_to_secondary = node_to_secondary
371 # Used for individual rows
372 self.curlive_data = None
375 """Iterate over all nodes.
377 This function has side-effects and only one instance of the resulting
378 generator should be used at a time.
381 for node in self.nodes:
383 self.curlive_data = self.live_data.get(node.name, None)
385 self.curlive_data = None
389 #: Fields that are direct attributes of an L{objects.Node} object
390 _NODE_SIMPLE_FIELDS = {
391 "drained": ("Drained", constants.QFT_BOOL),
392 "master_candidate": ("MasterC", constants.QFT_BOOL),
393 "master_capable": ("MasterCapable", constants.QFT_BOOL),
394 "name": ("Node", constants.QFT_TEXT),
395 "offline": ("Offline", constants.QFT_BOOL),
396 "serial_no": ("SerialNo", constants.QFT_NUMBER),
397 "uuid": ("UUID", constants.QFT_TEXT),
398 "vm_capable": ("VMCapable", constants.QFT_BOOL),
402 #: Fields requiring talking to the node
403 _NODE_LIVE_FIELDS = {
404 "bootid": ("BootID", constants.QFT_TEXT, "bootid"),
405 "cnodes": ("CNodes", constants.QFT_NUMBER, "cpu_nodes"),
406 "csockets": ("CSockets", constants.QFT_NUMBER, "cpu_sockets"),
407 "ctotal": ("CTotal", constants.QFT_NUMBER, "cpu_total"),
408 "dfree": ("DFree", constants.QFT_UNIT, "vg_free"),
409 "dtotal": ("DTotal", constants.QFT_UNIT, "vg_size"),
410 "mfree": ("MFree", constants.QFT_UNIT, "memory_free"),
411 "mnode": ("MNode", constants.QFT_UNIT, "memory_dom0"),
412 "mtotal": ("MTotal", constants.QFT_UNIT, "memory_total"),
416 def _GetNodeGroup(ctx, node):
417 """Returns the name of a node's group.
419 @type ctx: L{NodeQueryData}
420 @type node: L{objects.Node}
421 @param node: Node object
424 ng = ctx.groups.get(node.group, None)
426 # Nodes always have a group, or the configuration is corrupt
427 return (constants.QRFS_UNAVAIL, None)
429 return (constants.QRFS_NORMAL, ng.name)
432 def _GetLiveNodeField(field, kind, ctx, node):
433 """Gets the value of a "live" field from L{NodeQueryData}.
435 @param field: Live field name
436 @param kind: Data kind, one of L{constants.QFT_ALL}
437 @type ctx: L{NodeQueryData}
438 @type node: L{objects.Node}
439 @param node: Node object
443 return (constants.QRFS_OFFLINE, None)
445 if not ctx.curlive_data:
446 return (constants.QRFS_NODATA, None)
449 value = ctx.curlive_data[field]
451 return (constants.QRFS_UNAVAIL, None)
453 if kind == constants.QFT_TEXT:
454 return (constants.QRFS_NORMAL, value)
456 assert kind in (constants.QFT_NUMBER, constants.QFT_UNIT)
458 # Try to convert into number
460 return (constants.QRFS_NORMAL, int(value))
461 except (ValueError, TypeError):
462 logging.exception("Failed to convert node field '%s' (value %r) to int",
464 return (constants.QRFS_UNAVAIL, None)
467 def _BuildNodeFields():
468 """Builds list of fields for node queries.
472 (_MakeField("pip", "PrimaryIP", constants.QFT_TEXT), NQ_CONFIG,
473 lambda ctx, node: (constants.QRFS_NORMAL, node.primary_ip)),
474 (_MakeField("sip", "SecondaryIP", constants.QFT_TEXT), NQ_CONFIG,
475 lambda ctx, node: (constants.QRFS_NORMAL, node.secondary_ip)),
476 (_MakeField("tags", "Tags", constants.QFT_OTHER), NQ_CONFIG,
477 lambda ctx, node: (constants.QRFS_NORMAL, list(node.GetTags()))),
478 (_MakeField("master", "IsMaster", constants.QFT_BOOL), NQ_CONFIG,
479 lambda ctx, node: (constants.QRFS_NORMAL, node.name == ctx.master_name)),
480 (_MakeField("role", "Role", constants.QFT_TEXT), NQ_CONFIG,
481 lambda ctx, node: (constants.QRFS_NORMAL,
482 _GetNodeRole(node, ctx.master_name))),
483 (_MakeField("group", "Group", constants.QFT_TEXT), NQ_GROUP, _GetNodeGroup),
484 (_MakeField("group.uuid", "GroupUUID", constants.QFT_TEXT),
485 NQ_CONFIG, lambda ctx, node: (constants.QRFS_NORMAL, node.group)),
488 def _GetLength(getter):
489 return lambda ctx, node: (constants.QRFS_NORMAL,
490 len(getter(ctx)[node.name]))
492 def _GetList(getter):
493 return lambda ctx, node: (constants.QRFS_NORMAL,
494 list(getter(ctx)[node.name]))
496 # Add fields operating on instance lists
497 for prefix, titleprefix, getter in \
498 [("p", "Pri", operator.attrgetter("node_to_primary")),
499 ("s", "Sec", operator.attrgetter("node_to_secondary"))]:
501 (_MakeField("%sinst_cnt" % prefix, "%sinst" % prefix.upper(),
502 constants.QFT_NUMBER),
503 NQ_INST, _GetLength(getter)),
504 (_MakeField("%sinst_list" % prefix, "%sInstances" % titleprefix,
505 constants.QFT_OTHER),
506 NQ_INST, _GetList(getter)),
510 fields.extend([(_MakeField(name, title, kind), NQ_CONFIG, _GetItemAttr(name))
511 for (name, (title, kind)) in _NODE_SIMPLE_FIELDS.items()])
513 # Add fields requiring live data
515 (_MakeField(name, title, kind), NQ_LIVE,
516 compat.partial(_GetLiveNodeField, nfield, kind))
517 for (name, (title, kind, nfield)) in _NODE_LIVE_FIELDS.items()
521 fields.extend(_GetItemTimestampFields(NQ_CONFIG))
523 return _PrepareFieldList(fields)
526 class InstanceQueryData:
527 """Data container for instance data queries.
530 def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
532 """Initializes this class.
534 @param instances: List of instance objects
535 @param cluster: Cluster object
536 @type disk_usage: dict; instance name as key
537 @param disk_usage: Per-instance disk usage
538 @type offline_nodes: list of strings
539 @param offline_nodes: List of offline nodes
540 @type bad_nodes: list of strings
541 @param bad_nodes: List of faulty nodes
542 @type live_data: dict; instance name as key
543 @param live_data: Per-instance live data
546 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
547 "Offline nodes not included in bad nodes"
548 assert not (set(live_data.keys()) & set(bad_nodes)), \
549 "Found live data for bad or offline nodes"
551 self.instances = instances
552 self.cluster = cluster
553 self.disk_usage = disk_usage
554 self.offline_nodes = offline_nodes
555 self.bad_nodes = bad_nodes
556 self.live_data = live_data
558 # Used for individual rows
559 self.inst_hvparams = None
560 self.inst_beparams = None
561 self.inst_nicparams = None
564 """Iterate over all instances.
566 This function has side-effects and only one instance of the resulting
567 generator should be used at a time.
570 for inst in self.instances:
571 self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
572 self.inst_beparams = self.cluster.FillBE(inst)
573 self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
574 for nic in inst.nics]
579 def _GetInstOperState(ctx, inst):
580 """Get instance's operational status.
582 @type ctx: L{InstanceQueryData}
583 @type inst: L{objects.Instance}
584 @param inst: Instance object
587 # Can't use QRFS_OFFLINE here as it would describe the instance to be offline
588 # when we actually don't know due to missing data
589 if inst.primary_node in ctx.bad_nodes:
590 return (constants.QRFS_NODATA, None)
592 return (constants.QRFS_NORMAL, bool(ctx.live_data.get(inst.name)))
595 def _GetInstLiveData(name):
596 """Build function for retrieving live data.
599 @param name: Live data field name
603 """Get live data for an instance.
605 @type ctx: L{InstanceQueryData}
606 @type inst: L{objects.Instance}
607 @param inst: Instance object
610 if (inst.primary_node in ctx.bad_nodes or
611 inst.primary_node in ctx.offline_nodes):
612 # Can't use QRFS_OFFLINE here as it would describe the instance to be
613 # offline when we actually don't know due to missing data
614 return (constants.QRFS_NODATA, None)
616 if inst.name in ctx.live_data:
617 data = ctx.live_data[inst.name]
619 return (constants.QRFS_NORMAL, data[name])
621 return (constants.QRFS_UNAVAIL, None)
626 def _GetInstStatus(ctx, inst):
627 """Get instance status.
629 @type ctx: L{InstanceQueryData}
630 @type inst: L{objects.Instance}
631 @param inst: Instance object
634 if inst.primary_node in ctx.offline_nodes:
635 return (constants.QRFS_NORMAL, "ERROR_nodeoffline")
637 if inst.primary_node in ctx.bad_nodes:
638 return (constants.QRFS_NORMAL, "ERROR_nodedown")
640 if bool(ctx.live_data.get(inst.name)):
642 return (constants.QRFS_NORMAL, "running")
644 return (constants.QRFS_NORMAL, "ERROR_up")
647 return (constants.QRFS_NORMAL, "ERROR_down")
649 return (constants.QRFS_NORMAL, "ADMIN_down")
652 def _GetInstDiskSize(index):
653 """Build function for retrieving disk size.
656 @param index: Disk index
660 """Get size of a disk.
662 @type inst: L{objects.Instance}
663 @param inst: Instance object
667 return (constants.QRFS_NORMAL, inst.disks[index].size)
669 return (constants.QRFS_UNAVAIL, None)
674 def _GetInstNic(index, cb):
675 """Build function for calling another function with an instance NIC.
678 @param index: NIC index
684 """Call helper function with instance NIC.
686 @type ctx: L{InstanceQueryData}
687 @type inst: L{objects.Instance}
688 @param inst: Instance object
692 nic = inst.nics[index]
694 return (constants.QRFS_UNAVAIL, None)
696 return cb(ctx, index, nic)
701 def _GetInstNicIp(ctx, _, nic): # pylint: disable-msg=W0613
702 """Get a NIC's IP address.
704 @type ctx: L{InstanceQueryData}
705 @type nic: L{objects.NIC}
706 @param nic: NIC object
710 return (constants.QRFS_UNAVAIL, None)
712 return (constants.QRFS_NORMAL, nic.ip)
715 def _GetInstNicBridge(ctx, index, _):
716 """Get a NIC's bridge.
718 @type ctx: L{InstanceQueryData}
720 @param index: NIC index
723 assert len(ctx.inst_nicparams) >= index
725 nicparams = ctx.inst_nicparams[index]
727 if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
728 return (constants.QRFS_NORMAL, nicparams[constants.NIC_LINK])
730 return (constants.QRFS_UNAVAIL, None)
733 def _GetInstAllNicBridges(ctx, inst):
734 """Get all network bridges for an instance.
736 @type ctx: L{InstanceQueryData}
737 @type inst: L{objects.Instance}
738 @param inst: Instance object
741 assert len(ctx.inst_nicparams) == len(inst.nics)
745 for nicp in ctx.inst_nicparams:
746 if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
747 result.append(nicp[constants.NIC_LINK])
751 assert len(result) == len(inst.nics)
753 return (constants.QRFS_NORMAL, result)
756 def _GetInstNicParam(name):
757 """Build function for retrieving a NIC parameter.
760 @param name: Parameter name
763 def fn(ctx, index, _):
764 """Get a NIC's bridge.
766 @type ctx: L{InstanceQueryData}
767 @type inst: L{objects.Instance}
768 @param inst: Instance object
769 @type nic: L{objects.NIC}
770 @param nic: NIC object
773 assert len(ctx.inst_nicparams) >= index
774 return (constants.QRFS_NORMAL, ctx.inst_nicparams[index][name])
779 def _GetInstanceNetworkFields():
780 """Get instance fields involving network interfaces.
782 @return: List of field definitions used as input for L{_PrepareFieldList}
785 nic_mac_fn = lambda ctx, _, nic: (constants.QRFS_NORMAL, nic.mac)
786 nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
787 nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
791 (_MakeField("ip", "IP_address", constants.QFT_TEXT), IQ_CONFIG,
792 _GetInstNic(0, _GetInstNicIp)),
793 (_MakeField("mac", "MAC_address", constants.QFT_TEXT), IQ_CONFIG,
794 _GetInstNic(0, nic_mac_fn)),
795 (_MakeField("bridge", "Bridge", constants.QFT_TEXT), IQ_CONFIG,
796 _GetInstNic(0, _GetInstNicBridge)),
797 (_MakeField("nic_mode", "NIC_Mode", constants.QFT_TEXT), IQ_CONFIG,
798 _GetInstNic(0, nic_mode_fn)),
799 (_MakeField("nic_link", "NIC_Link", constants.QFT_TEXT), IQ_CONFIG,
800 _GetInstNic(0, nic_link_fn)),
803 (_MakeField("nic.count", "NICs", constants.QFT_NUMBER), IQ_CONFIG,
804 lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.nics))),
805 (_MakeField("nic.macs", "NIC_MACs", constants.QFT_OTHER), IQ_CONFIG,
806 lambda ctx, inst: (constants.QRFS_NORMAL, [nic.mac for nic in inst.nics])),
807 (_MakeField("nic.ips", "NIC_IPs", constants.QFT_OTHER), IQ_CONFIG,
808 lambda ctx, inst: (constants.QRFS_NORMAL, [nic.ip for nic in inst.nics])),
809 (_MakeField("nic.modes", "NIC_modes", constants.QFT_OTHER), IQ_CONFIG,
810 lambda ctx, inst: (constants.QRFS_NORMAL,
811 [nicp[constants.NIC_MODE]
812 for nicp in ctx.inst_nicparams])),
813 (_MakeField("nic.links", "NIC_links", constants.QFT_OTHER), IQ_CONFIG,
814 lambda ctx, inst: (constants.QRFS_NORMAL,
815 [nicp[constants.NIC_LINK]
816 for nicp in ctx.inst_nicparams])),
817 (_MakeField("nic.bridges", "NIC_bridges", constants.QFT_OTHER), IQ_CONFIG,
818 _GetInstAllNicBridges),
822 for i in range(constants.MAX_NICS):
824 (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, constants.QFT_TEXT),
825 IQ_CONFIG, _GetInstNic(i, _GetInstNicIp)),
826 (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, constants.QFT_TEXT),
827 IQ_CONFIG, _GetInstNic(i, nic_mac_fn)),
828 (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, constants.QFT_TEXT),
829 IQ_CONFIG, _GetInstNic(i, nic_mode_fn)),
830 (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, constants.QFT_TEXT),
831 IQ_CONFIG, _GetInstNic(i, nic_link_fn)),
832 (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, constants.QFT_TEXT),
833 IQ_CONFIG, _GetInstNic(i, _GetInstNicBridge)),
839 def _GetInstDiskUsage(ctx, inst):
840 """Get disk usage for an instance.
842 @type ctx: L{InstanceQueryData}
843 @type inst: L{objects.Instance}
844 @param inst: Instance object
847 usage = ctx.disk_usage[inst.name]
852 return (constants.QRFS_NORMAL, usage)
855 def _GetInstanceDiskFields():
856 """Get instance fields involving disks.
858 @return: List of field definitions used as input for L{_PrepareFieldList}
862 (_MakeField("disk_usage", "DiskUsage", constants.QFT_UNIT), IQ_DISKUSAGE,
864 (_MakeField("sda_size", "LegacyDisk/0", constants.QFT_UNIT), IQ_CONFIG,
865 _GetInstDiskSize(0)),
866 (_MakeField("sdb_size", "LegacyDisk/1", constants.QFT_UNIT), IQ_CONFIG,
867 _GetInstDiskSize(1)),
868 (_MakeField("disk.count", "Disks", constants.QFT_NUMBER), IQ_CONFIG,
869 lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.disks))),
870 (_MakeField("disk.sizes", "Disk_sizes", constants.QFT_OTHER), IQ_CONFIG,
871 lambda ctx, inst: (constants.QRFS_NORMAL,
872 [disk.size for disk in inst.disks])),
877 (_MakeField("disk.size/%s" % i, "Disk/%s" % i, constants.QFT_UNIT),
878 IQ_CONFIG, _GetInstDiskSize(i))
879 for i in range(constants.MAX_DISKS)
885 def _GetInstanceParameterFields():
886 """Get instance fields involving parameters.
888 @return: List of field definitions used as input for L{_PrepareFieldList}
891 # TODO: Consider moving titles closer to constants
893 constants.BE_AUTO_BALANCE: "Auto_balance",
894 constants.BE_MEMORY: "Configured_memory",
895 constants.BE_VCPUS: "VCPUs",
899 constants.HV_ACPI: "ACPI",
900 constants.HV_BOOT_ORDER: "Boot_order",
901 constants.HV_CDROM_IMAGE_PATH: "CDROM_image_path",
902 constants.HV_DISK_TYPE: "Disk_type",
903 constants.HV_INITRD_PATH: "Initrd_path",
904 constants.HV_KERNEL_PATH: "Kernel_path",
905 constants.HV_NIC_TYPE: "NIC_type",
906 constants.HV_PAE: "PAE",
907 constants.HV_VNC_BIND_ADDRESS: "VNC_bind_address",
912 (_MakeField("hvparams", "HypervisorParameters", constants.QFT_OTHER),
913 IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_hvparams)),
914 (_MakeField("beparams", "BackendParameters", constants.QFT_OTHER),
915 IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_beparams)),
916 (_MakeField("vcpus", "LegacyVCPUs", constants.QFT_NUMBER), IQ_CONFIG,
917 lambda ctx, _: (constants.QRFS_NORMAL,
918 ctx.inst_beparams[constants.BE_VCPUS])),
920 # Unfilled parameters
921 (_MakeField("custom_hvparams", "CustomHypervisorParameters",
922 constants.QFT_OTHER),
923 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.hvparams)),
924 (_MakeField("custom_beparams", "CustomBackendParameters",
925 constants.QFT_OTHER),
926 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.beparams)),
927 (_MakeField("custom_nicparams", "CustomNicParameters",
928 constants.QFT_OTHER),
929 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL,
930 [nic.nicparams for nic in inst.nics])),
934 def _GetInstHvParam(name):
935 return lambda ctx, _: (constants.QRFS_NORMAL,
936 ctx.inst_hvparams.get(name, None))
939 # For now all hypervisor parameters are exported as QFT_OTHER
940 (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name),
941 constants.QFT_OTHER),
942 IQ_CONFIG, _GetInstHvParam(name))
943 for name in constants.HVS_PARAMETERS
944 if name not in constants.HVC_GLOBALS
948 def _GetInstBeParam(name):
949 return lambda ctx, _: (constants.QRFS_NORMAL,
950 ctx.inst_beparams.get(name, None))
953 # For now all backend parameters are exported as QFT_OTHER
954 (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name),
955 constants.QFT_OTHER),
956 IQ_CONFIG, _GetInstBeParam(name))
957 for name in constants.BES_PARAMETERS
963 _INST_SIMPLE_FIELDS = {
964 "disk_template": ("Disk_template", constants.QFT_TEXT),
965 "hypervisor": ("Hypervisor", constants.QFT_TEXT),
966 "name": ("Node", constants.QFT_TEXT),
967 # Depending on the hypervisor, the port can be None
968 "network_port": ("Network_port", constants.QFT_OTHER),
969 "os": ("OS", constants.QFT_TEXT),
970 "serial_no": ("SerialNo", constants.QFT_NUMBER),
971 "uuid": ("UUID", constants.QFT_TEXT),
975 def _BuildInstanceFields():
976 """Builds list of fields for instance queries.
980 (_MakeField("pnode", "Primary_node", constants.QFT_TEXT), IQ_CONFIG,
981 lambda ctx, inst: (constants.QRFS_NORMAL, inst.primary_node)),
982 (_MakeField("snodes", "Secondary_Nodes", constants.QFT_OTHER), IQ_CONFIG,
983 lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.secondary_nodes))),
984 (_MakeField("admin_state", "Autostart", constants.QFT_BOOL), IQ_CONFIG,
985 lambda ctx, inst: (constants.QRFS_NORMAL, inst.admin_up)),
986 (_MakeField("tags", "Tags", constants.QFT_OTHER), IQ_CONFIG,
987 lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.GetTags()))),
991 fields.extend([(_MakeField(name, title, kind), IQ_CONFIG, _GetItemAttr(name))
992 for (name, (title, kind)) in _INST_SIMPLE_FIELDS.items()])
994 # Fields requiring talking to the node
996 (_MakeField("oper_state", "Running", constants.QFT_BOOL), IQ_LIVE,
998 (_MakeField("oper_ram", "RuntimeMemory", constants.QFT_UNIT), IQ_LIVE,
999 _GetInstLiveData("memory")),
1000 (_MakeField("oper_vcpus", "RuntimeVCPUs", constants.QFT_NUMBER), IQ_LIVE,
1001 _GetInstLiveData("vcpus")),
1002 (_MakeField("status", "Status", constants.QFT_TEXT), IQ_LIVE,
1006 fields.extend(_GetInstanceParameterFields())
1007 fields.extend(_GetInstanceDiskFields())
1008 fields.extend(_GetInstanceNetworkFields())
1009 fields.extend(_GetItemTimestampFields(IQ_CONFIG))
1011 return _PrepareFieldList(fields)
1014 class LockQueryData:
1015 """Data container for lock data queries.
1018 def __init__(self, lockdata):
1019 """Initializes this class.
1022 self.lockdata = lockdata
1025 """Iterate over all locks.
1028 return iter(self.lockdata)
1031 def _GetLockOwners(_, data):
1032 """Returns a sorted list of a lock's current owners.
1035 (_, _, owners, _) = data
1038 owners = utils.NiceSort(owners)
1040 return (constants.QRFS_NORMAL, owners)
1043 def _GetLockPending(_, data):
1044 """Returns a sorted list of a lock's pending acquires.
1047 (_, _, _, pending) = data
1050 pending = [(mode, utils.NiceSort(names))
1051 for (mode, names) in pending]
1053 return (constants.QRFS_NORMAL, pending)
1056 def _BuildLockFields():
1057 """Builds list of fields for lock queries.
1060 return _PrepareFieldList([
1061 (_MakeField("name", "Name", constants.QFT_TEXT), None,
1062 lambda ctx, (name, mode, owners, pending): (constants.QRFS_NORMAL, name)),
1063 (_MakeField("mode", "Mode", constants.QFT_OTHER), LQ_MODE,
1064 lambda ctx, (name, mode, owners, pending): (constants.QRFS_NORMAL, mode)),
1065 (_MakeField("owner", "Owner", constants.QFT_OTHER), LQ_OWNER,
1067 (_MakeField("pending", "Pending", constants.QFT_OTHER), LQ_PENDING,
1072 class GroupQueryData:
1073 """Data container for node group data queries.
1076 def __init__(self, groups, group_to_nodes, group_to_instances):
1077 """Initializes this class.
1079 @param groups: List of node group objects
1080 @type group_to_nodes: dict; group UUID as key
1081 @param group_to_nodes: Per-group list of nodes
1082 @type group_to_instances: dict; group UUID as key
1083 @param group_to_instances: Per-group list of (primary) instances
1086 self.groups = groups
1087 self.group_to_nodes = group_to_nodes
1088 self.group_to_instances = group_to_instances
1091 """Iterate over all node groups.
1094 return iter(self.groups)
1097 _GROUP_SIMPLE_FIELDS = {
1098 "alloc_policy": ("AllocPolicy", constants.QFT_TEXT),
1099 "name": ("Group", constants.QFT_TEXT),
1100 "serial_no": ("SerialNo", constants.QFT_NUMBER),
1101 "uuid": ("UUID", constants.QFT_TEXT),
1105 def _BuildGroupFields():
1106 """Builds list of fields for node group queries.
1110 fields = [(_MakeField(name, title, kind), GQ_CONFIG, _GetItemAttr(name))
1111 for (name, (title, kind)) in _GROUP_SIMPLE_FIELDS.items()]
1113 def _GetLength(getter):
1114 return lambda ctx, group: (constants.QRFS_NORMAL,
1115 len(getter(ctx)[group.uuid]))
1117 def _GetSortedList(getter):
1118 return lambda ctx, group: (constants.QRFS_NORMAL,
1119 utils.NiceSort(getter(ctx)[group.uuid]))
1121 group_to_nodes = operator.attrgetter("group_to_nodes")
1122 group_to_instances = operator.attrgetter("group_to_instances")
1124 # Add fields for nodes
1126 (_MakeField("node_cnt", "Nodes", constants.QFT_NUMBER),
1127 GQ_NODE, _GetLength(group_to_nodes)),
1128 (_MakeField("node_list", "NodeList", constants.QFT_OTHER),
1129 GQ_NODE, _GetSortedList(group_to_nodes)),
1132 # Add fields for instances
1134 (_MakeField("pinst_cnt", "Instances", constants.QFT_NUMBER),
1135 GQ_INST, _GetLength(group_to_instances)),
1136 (_MakeField("pinst_list", "InstanceList", constants.QFT_OTHER),
1137 GQ_INST, _GetSortedList(group_to_instances)),
1140 fields.extend(_GetItemTimestampFields(GQ_CONFIG))
1142 return _PrepareFieldList(fields)
1145 #: Fields available for node queries
1146 NODE_FIELDS = _BuildNodeFields()
1148 #: Fields available for instance queries
1149 INSTANCE_FIELDS = _BuildInstanceFields()
1151 #: Fields available for lock queries
1152 LOCK_FIELDS = _BuildLockFields()
1154 #: Fields available for node group queries
1155 GROUP_FIELDS = _BuildGroupFields()
1157 #: All available field lists
1158 ALL_FIELD_LISTS = [NODE_FIELDS, INSTANCE_FIELDS, LOCK_FIELDS, GROUP_FIELDS]