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)
46 FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$")
47 TITLE_RE = re.compile(r"^[^\s]+$")
49 #: Verification function for each field type
51 constants.QFT_UNKNOWN: ht.TNone,
52 constants.QFT_TEXT: ht.TString,
53 constants.QFT_BOOL: ht.TBool,
54 constants.QFT_NUMBER: ht.TInt,
55 constants.QFT_UNIT: ht.TInt,
56 constants.QFT_TIMESTAMP: ht.TOr(ht.TInt, ht.TFloat),
57 constants.QFT_OTHER: lambda _: True,
61 def _GetUnknownField(ctx, item): # pylint: disable-msg=W0613
62 """Gets the contents of an unknown field.
65 return (constants.QRFS_UNKNOWN, None)
68 def _GetQueryFields(fielddefs, selected):
69 """Calculates the internal list of selected fields.
71 Unknown fields are returned as L{constants.QFT_UNKNOWN}.
74 @param fielddefs: Field definitions
75 @type selected: list of strings
76 @param selected: List of selected fields
83 fdef = fielddefs[name]
85 fdef = (_MakeField(name, name, constants.QFT_UNKNOWN),
86 None, _GetUnknownField)
95 def GetAllFields(fielddefs):
96 """Extract L{objects.QueryFieldDefinition} from field definitions.
98 @rtype: list of L{objects.QueryFieldDefinition}
101 return [fdef for (fdef, _, _) in fielddefs]
105 def __init__(self, fieldlist, selected):
106 """Initializes this class.
108 The field definition is a dictionary with the field's name as a key and a
109 tuple containing, in order, the field definition object
110 (L{objects.QueryFieldDefinition}, the data kind to help calling code
111 collect data and a retrieval function. The retrieval function is called
112 with two parameters, in order, the data container and the item in container
113 (see L{Query.Query}).
115 Users of this class can call L{RequestedData} before preparing the data
116 container to determine what data is needed.
118 @type fieldlist: dictionary
119 @param fieldlist: Field definitions
120 @type selected: list of strings
121 @param selected: List of selected fields
124 self._fields = _GetQueryFields(fieldlist, selected)
126 def RequestedData(self):
127 """Gets requested kinds of data.
132 return frozenset(datakind
133 for (_, datakind, _) in self._fields
134 if datakind is not None)
137 """Returns the list of fields for this query.
139 Includes unknown fields.
141 @rtype: List of L{objects.QueryFieldDefinition}
144 return GetAllFields(self._fields)
146 def Query(self, ctx):
149 @param ctx: Data container passed to field retrieval functions, must
150 support iteration using C{__iter__}
153 result = [[fn(ctx, item) for (_, _, fn) in self._fields]
158 for (idx, row) in enumerate(result):
159 assert _VerifyResultRow(self._fields, row), \
160 ("Inconsistent result for fields %s in row %s: %r" %
161 (GetAllFields(self._fields), idx, row))
165 def OldStyleQuery(self, ctx):
166 """Query with "old" query result format.
168 See L{Query.Query} for arguments.
171 unknown = set(fdef.name
172 for (fdef, _, _) in self._fields
173 if fdef.kind == constants.QFT_UNKNOWN)
175 raise errors.OpPrereqError("Unknown output fields selected: %s" %
176 (utils.CommaJoin(unknown), ),
179 return [[value for (_, value) in row]
180 for row in self.Query(ctx)]
183 def _VerifyResultRow(fields, row):
184 """Verifies the contents of a query result row.
187 @param fields: Field definitions for result
188 @type row: list of tuples
192 return (len(row) == len(fields) and
193 compat.all((status == constants.QRFS_NORMAL and
194 _VERIFY_FN[fdef.kind](value)) or
195 # Value for an abnormal status must be None
196 (status != constants.QRFS_NORMAL and value is None)
197 for ((status, value), (fdef, _, _)) in zip(row, fields)))
200 def _PrepareFieldList(fields):
201 """Prepares field list for use by L{Query}.
203 Converts the list to a dictionary and does some verification.
205 @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data kind,
207 @param fields: List of fields
209 @return: Field dictionary for L{Query}
213 duplicates = utils.FindDuplicates(fdef.title.lower()
214 for (fdef, _, _) in fields)
215 assert not duplicates, "Duplicate title(s) found: %r" % duplicates
220 (fdef, _, fn) = field
222 assert fdef.name and fdef.title, "Name and title are required"
223 assert FIELD_NAME_RE.match(fdef.name)
224 assert TITLE_RE.match(fdef.title)
226 assert fdef.name not in result, \
227 "Duplicate field name '%s' found" % fdef.name
229 result[fdef.name] = field
231 assert len(result) == len(fields)
232 assert compat.all(name == fdef.name
233 for (name, (fdef, _, _)) in result.items())
238 def QueryFields(fielddefs, selected):
239 """Returns list of available fields.
241 @type fielddefs: dict
242 @param fielddefs: Field definitions
243 @type selected: list of strings
244 @param selected: List of selected fields
245 @return: List of L{objects.QueryFieldDefinition}
249 # Client requests all fields, sort by name
250 fdefs = utils.NiceSort(GetAllFields(fielddefs.values()),
251 key=operator.attrgetter("name"))
253 # Keep order as requested by client
254 fdefs = Query(fielddefs, selected).GetFields()
256 return objects.QueryFieldsResponse(fields=fdefs).ToDict()
259 def _MakeField(name, title, kind):
260 """Wrapper for creating L{objects.QueryFieldDefinition} instances.
262 @param name: Field name as a regular expression
263 @param title: Human-readable title
264 @param kind: Field type
267 return objects.QueryFieldDefinition(name=name, title=title, kind=kind)
270 def _GetNodeRole(node, master_name):
271 """Determine node role.
273 @type node: L{objects.Node}
274 @param node: Node object
275 @type master_name: string
276 @param master_name: Master node name
279 if node.name == master_name:
281 elif node.master_candidate:
291 def _GetItemAttr(attr):
292 """Returns a field function to return an attribute of the item.
294 @param attr: Attribute name
297 getter = operator.attrgetter(attr)
298 return lambda _, item: (constants.QRFS_NORMAL, getter(item))
301 def _GetItemTimestamp(getter):
302 """Returns function for getting timestamp of item.
304 @type getter: callable
305 @param getter: Function to retrieve timestamp attribute
309 """Returns a timestamp of item.
312 timestamp = getter(item)
313 if timestamp is None:
314 # Old configs might not have all timestamps
315 return (constants.QRFS_UNAVAIL, None)
317 return (constants.QRFS_NORMAL, timestamp)
322 def _GetItemTimestampFields(datatype):
323 """Returns common timestamp fields.
325 @param datatype: Field data type for use by L{Query.RequestedData}
329 (_MakeField("ctime", "CTime", constants.QFT_TIMESTAMP), datatype,
330 _GetItemTimestamp(operator.attrgetter("ctime"))),
331 (_MakeField("mtime", "MTime", constants.QFT_TIMESTAMP), datatype,
332 _GetItemTimestamp(operator.attrgetter("mtime"))),
337 """Data container for node data queries.
340 def __init__(self, nodes, live_data, master_name, node_to_primary,
341 node_to_secondary, groups):
342 """Initializes this class.
346 self.live_data = live_data
347 self.master_name = master_name
348 self.node_to_primary = node_to_primary
349 self.node_to_secondary = node_to_secondary
352 # Used for individual rows
353 self.curlive_data = None
356 """Iterate over all nodes.
358 This function has side-effects and only one instance of the resulting
359 generator should be used at a time.
362 for node in self.nodes:
364 self.curlive_data = self.live_data.get(node.name, None)
366 self.curlive_data = None
370 #: Fields that are direct attributes of an L{objects.Node} object
371 _NODE_SIMPLE_FIELDS = {
372 "drained": ("Drained", constants.QFT_BOOL),
373 "master_candidate": ("MasterC", constants.QFT_BOOL),
374 "master_capable": ("MasterCapable", constants.QFT_BOOL),
375 "name": ("Node", constants.QFT_TEXT),
376 "offline": ("Offline", constants.QFT_BOOL),
377 "serial_no": ("SerialNo", constants.QFT_NUMBER),
378 "uuid": ("UUID", constants.QFT_TEXT),
379 "vm_capable": ("VMCapable", constants.QFT_BOOL),
383 #: Fields requiring talking to the node
384 _NODE_LIVE_FIELDS = {
385 "bootid": ("BootID", constants.QFT_TEXT, "bootid"),
386 "cnodes": ("CNodes", constants.QFT_NUMBER, "cpu_nodes"),
387 "csockets": ("CSockets", constants.QFT_NUMBER, "cpu_sockets"),
388 "ctotal": ("CTotal", constants.QFT_NUMBER, "cpu_total"),
389 "dfree": ("DFree", constants.QFT_UNIT, "vg_free"),
390 "dtotal": ("DTotal", constants.QFT_UNIT, "vg_size"),
391 "mfree": ("MFree", constants.QFT_UNIT, "memory_free"),
392 "mnode": ("MNode", constants.QFT_UNIT, "memory_dom0"),
393 "mtotal": ("MTotal", constants.QFT_UNIT, "memory_total"),
397 def _GetNodeGroup(ctx, node):
398 """Returns the name of a node's group.
400 @type ctx: L{NodeQueryData}
401 @type node: L{objects.Node}
402 @param node: Node object
405 ng = ctx.groups.get(node.group, None)
407 # Nodes always have a group, or the configuration is corrupt
408 return (constants.QRFS_UNAVAIL, None)
410 return (constants.QRFS_NORMAL, ng.name)
413 def _GetLiveNodeField(field, kind, ctx, _):
414 """Gets the value of a "live" field from L{NodeQueryData}.
416 @param field: Live field name
417 @param kind: Data kind, one of L{constants.QFT_ALL}
418 @type ctx: L{NodeQueryData}
421 if not ctx.curlive_data:
422 return (constants.QRFS_NODATA, None)
425 value = ctx.curlive_data[field]
427 return (constants.QRFS_UNAVAIL, None)
429 if kind == constants.QFT_TEXT:
430 return (constants.QRFS_NORMAL, value)
432 assert kind in (constants.QFT_NUMBER, constants.QFT_UNIT)
434 # Try to convert into number
436 return (constants.QRFS_NORMAL, int(value))
437 except (ValueError, TypeError):
438 logging.exception("Failed to convert node field '%s' (value %r) to int",
440 return (constants.QRFS_UNAVAIL, None)
443 def _BuildNodeFields():
444 """Builds list of fields for node queries.
448 (_MakeField("pip", "PrimaryIP", constants.QFT_TEXT), NQ_CONFIG,
449 lambda ctx, node: (constants.QRFS_NORMAL, node.primary_ip)),
450 (_MakeField("sip", "SecondaryIP", constants.QFT_TEXT), NQ_CONFIG,
451 lambda ctx, node: (constants.QRFS_NORMAL, node.secondary_ip)),
452 (_MakeField("tags", "Tags", constants.QFT_OTHER), NQ_CONFIG,
453 lambda ctx, node: (constants.QRFS_NORMAL, list(node.GetTags()))),
454 (_MakeField("master", "IsMaster", constants.QFT_BOOL), NQ_CONFIG,
455 lambda ctx, node: (constants.QRFS_NORMAL, node.name == ctx.master_name)),
456 (_MakeField("role", "Role", constants.QFT_TEXT), NQ_CONFIG,
457 lambda ctx, node: (constants.QRFS_NORMAL,
458 _GetNodeRole(node, ctx.master_name))),
459 (_MakeField("group", "Group", constants.QFT_TEXT), NQ_GROUP, _GetNodeGroup),
460 (_MakeField("group.uuid", "GroupUUID", constants.QFT_TEXT),
461 NQ_CONFIG, lambda ctx, node: (constants.QRFS_NORMAL, node.group)),
464 def _GetLength(getter):
465 return lambda ctx, node: (constants.QRFS_NORMAL,
466 len(getter(ctx)[node.name]))
468 def _GetList(getter):
469 return lambda ctx, node: (constants.QRFS_NORMAL,
470 list(getter(ctx)[node.name]))
472 # Add fields operating on instance lists
473 for prefix, titleprefix, getter in \
474 [("p", "Pri", operator.attrgetter("node_to_primary")),
475 ("s", "Sec", operator.attrgetter("node_to_secondary"))]:
477 (_MakeField("%sinst_cnt" % prefix, "%sinst" % prefix.upper(),
478 constants.QFT_NUMBER),
479 NQ_INST, _GetLength(getter)),
480 (_MakeField("%sinst_list" % prefix, "%sInstances" % titleprefix,
481 constants.QFT_OTHER),
482 NQ_INST, _GetList(getter)),
486 fields.extend([(_MakeField(name, title, kind), NQ_CONFIG, _GetItemAttr(name))
487 for (name, (title, kind)) in _NODE_SIMPLE_FIELDS.items()])
489 # Add fields requiring live data
491 (_MakeField(name, title, kind), NQ_LIVE,
492 compat.partial(_GetLiveNodeField, nfield, kind))
493 for (name, (title, kind, nfield)) in _NODE_LIVE_FIELDS.items()
497 fields.extend(_GetItemTimestampFields(NQ_CONFIG))
499 return _PrepareFieldList(fields)
502 class InstanceQueryData:
503 """Data container for instance data queries.
506 def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
508 """Initializes this class.
510 @param instances: List of instance objects
511 @param cluster: Cluster object
512 @type disk_usage: dict; instance name as key
513 @param disk_usage: Per-instance disk usage
514 @type offline_nodes: list of strings
515 @param offline_nodes: List of offline nodes
516 @type bad_nodes: list of strings
517 @param bad_nodes: List of faulty nodes
518 @type live_data: dict; instance name as key
519 @param live_data: Per-instance live data
522 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
523 "Offline nodes not included in bad nodes"
524 assert not (set(live_data.keys()) & set(bad_nodes)), \
525 "Found live data for bad or offline nodes"
527 self.instances = instances
528 self.cluster = cluster
529 self.disk_usage = disk_usage
530 self.offline_nodes = offline_nodes
531 self.bad_nodes = bad_nodes
532 self.live_data = live_data
534 # Used for individual rows
535 self.inst_hvparams = None
536 self.inst_beparams = None
537 self.inst_nicparams = None
540 """Iterate over all instances.
542 This function has side-effects and only one instance of the resulting
543 generator should be used at a time.
546 for inst in self.instances:
547 self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
548 self.inst_beparams = self.cluster.FillBE(inst)
549 self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
550 for nic in inst.nics]
555 def _GetInstOperState(ctx, inst):
556 """Get instance's operational status.
558 @type ctx: L{InstanceQueryData}
559 @type inst: L{objects.Instance}
560 @param inst: Instance object
563 if inst.primary_node in ctx.bad_nodes:
564 return (constants.QRFS_NODATA, None)
566 return (constants.QRFS_NORMAL, bool(ctx.live_data.get(inst.name)))
569 def _GetInstLiveData(name):
570 """Build function for retrieving live data.
573 @param name: Live data field name
577 """Get live data for an instance.
579 @type ctx: L{InstanceQueryData}
580 @type inst: L{objects.Instance}
581 @param inst: Instance object
584 if (inst.primary_node in ctx.bad_nodes or
585 inst.primary_node in ctx.offline_nodes):
586 return (constants.QRFS_NODATA, None)
588 if inst.name in ctx.live_data:
589 data = ctx.live_data[inst.name]
591 return (constants.QRFS_NORMAL, data[name])
593 return (constants.QRFS_UNAVAIL, None)
598 def _GetInstStatus(ctx, inst):
599 """Get instance status.
601 @type ctx: L{InstanceQueryData}
602 @type inst: L{objects.Instance}
603 @param inst: Instance object
606 if inst.primary_node in ctx.offline_nodes:
607 return (constants.QRFS_NORMAL, "ERROR_nodeoffline")
609 if inst.primary_node in ctx.bad_nodes:
610 return (constants.QRFS_NORMAL, "ERROR_nodedown")
612 if bool(ctx.live_data.get(inst.name)):
614 return (constants.QRFS_NORMAL, "running")
616 return (constants.QRFS_NORMAL, "ERROR_up")
619 return (constants.QRFS_NORMAL, "ERROR_down")
621 return (constants.QRFS_NORMAL, "ADMIN_down")
624 def _GetInstDiskSize(index):
625 """Build function for retrieving disk size.
628 @param index: Disk index
632 """Get size of a disk.
634 @type inst: L{objects.Instance}
635 @param inst: Instance object
639 return (constants.QRFS_NORMAL, inst.disks[index].size)
641 return (constants.QRFS_UNAVAIL, None)
646 def _GetInstNic(index, cb):
647 """Build function for calling another function with an instance NIC.
650 @param index: NIC index
656 """Call helper function with instance NIC.
658 @type ctx: L{InstanceQueryData}
659 @type inst: L{objects.Instance}
660 @param inst: Instance object
664 nic = inst.nics[index]
666 return (constants.QRFS_UNAVAIL, None)
668 return cb(ctx, index, nic)
673 def _GetInstNicIp(ctx, _, nic): # pylint: disable-msg=W0613
674 """Get a NIC's IP address.
676 @type ctx: L{InstanceQueryData}
677 @type nic: L{objects.NIC}
678 @param nic: NIC object
682 return (constants.QRFS_UNAVAIL, None)
684 return (constants.QRFS_NORMAL, nic.ip)
687 def _GetInstNicBridge(ctx, index, _):
688 """Get a NIC's bridge.
690 @type ctx: L{InstanceQueryData}
692 @param index: NIC index
695 assert len(ctx.inst_nicparams) >= index
697 nicparams = ctx.inst_nicparams[index]
699 if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
700 return (constants.QRFS_NORMAL, nicparams[constants.NIC_LINK])
702 return (constants.QRFS_UNAVAIL, None)
705 def _GetInstAllNicBridges(ctx, inst):
706 """Get all network bridges for an instance.
708 @type ctx: L{InstanceQueryData}
709 @type inst: L{objects.Instance}
710 @param inst: Instance object
713 assert len(ctx.inst_nicparams) == len(inst.nics)
717 for nicp in ctx.inst_nicparams:
718 if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
719 result.append(nicp[constants.NIC_LINK])
723 assert len(result) == len(inst.nics)
725 return (constants.QRFS_NORMAL, result)
728 def _GetInstNicParam(name):
729 """Build function for retrieving a NIC parameter.
732 @param name: Parameter name
735 def fn(ctx, index, _):
736 """Get a NIC's bridge.
738 @type ctx: L{InstanceQueryData}
739 @type inst: L{objects.Instance}
740 @param inst: Instance object
741 @type nic: L{objects.NIC}
742 @param nic: NIC object
745 assert len(ctx.inst_nicparams) >= index
746 return (constants.QRFS_NORMAL, ctx.inst_nicparams[index][name])
751 def _GetInstanceNetworkFields():
752 """Get instance fields involving network interfaces.
754 @return: List of field definitions used as input for L{_PrepareFieldList}
757 nic_mac_fn = lambda ctx, _, nic: (constants.QRFS_NORMAL, nic.mac)
758 nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
759 nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
763 (_MakeField("ip", "IP_address", constants.QFT_TEXT), IQ_CONFIG,
764 _GetInstNic(0, _GetInstNicIp)),
765 (_MakeField("mac", "MAC_address", constants.QFT_TEXT), IQ_CONFIG,
766 _GetInstNic(0, nic_mac_fn)),
767 (_MakeField("bridge", "Bridge", constants.QFT_TEXT), IQ_CONFIG,
768 _GetInstNic(0, _GetInstNicBridge)),
769 (_MakeField("nic_mode", "NIC_Mode", constants.QFT_TEXT), IQ_CONFIG,
770 _GetInstNic(0, nic_mode_fn)),
771 (_MakeField("nic_link", "NIC_Link", constants.QFT_TEXT), IQ_CONFIG,
772 _GetInstNic(0, nic_link_fn)),
775 (_MakeField("nic.count", "NICs", constants.QFT_NUMBER), IQ_CONFIG,
776 lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.nics))),
777 (_MakeField("nic.macs", "NIC_MACs", constants.QFT_OTHER), IQ_CONFIG,
778 lambda ctx, inst: (constants.QRFS_NORMAL, [nic.mac for nic in inst.nics])),
779 (_MakeField("nic.ips", "NIC_IPs", constants.QFT_OTHER), IQ_CONFIG,
780 lambda ctx, inst: (constants.QRFS_NORMAL, [nic.ip for nic in inst.nics])),
781 (_MakeField("nic.modes", "NIC_modes", constants.QFT_OTHER), IQ_CONFIG,
782 lambda ctx, inst: (constants.QRFS_NORMAL,
783 [nicp[constants.NIC_MODE]
784 for nicp in ctx.inst_nicparams])),
785 (_MakeField("nic.links", "NIC_links", constants.QFT_OTHER), IQ_CONFIG,
786 lambda ctx, inst: (constants.QRFS_NORMAL,
787 [nicp[constants.NIC_LINK]
788 for nicp in ctx.inst_nicparams])),
789 (_MakeField("nic.bridges", "NIC_bridges", constants.QFT_OTHER), IQ_CONFIG,
790 _GetInstAllNicBridges),
794 for i in range(constants.MAX_NICS):
796 (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, constants.QFT_TEXT),
797 IQ_CONFIG, _GetInstNic(i, _GetInstNicIp)),
798 (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, constants.QFT_TEXT),
799 IQ_CONFIG, _GetInstNic(i, nic_mac_fn)),
800 (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, constants.QFT_TEXT),
801 IQ_CONFIG, _GetInstNic(i, nic_mode_fn)),
802 (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, constants.QFT_TEXT),
803 IQ_CONFIG, _GetInstNic(i, nic_link_fn)),
804 (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, constants.QFT_TEXT),
805 IQ_CONFIG, _GetInstNic(i, _GetInstNicBridge)),
811 def _GetInstDiskUsage(ctx, inst):
812 """Get disk usage for an instance.
814 @type ctx: L{InstanceQueryData}
815 @type inst: L{objects.Instance}
816 @param inst: Instance object
819 usage = ctx.disk_usage[inst.name]
824 return (constants.QRFS_NORMAL, usage)
827 def _GetInstanceDiskFields():
828 """Get instance fields involving disks.
830 @return: List of field definitions used as input for L{_PrepareFieldList}
834 (_MakeField("disk_usage", "DiskUsage", constants.QFT_UNIT), IQ_DISKUSAGE,
836 (_MakeField("sda_size", "LegacyDisk/0", constants.QFT_UNIT), IQ_CONFIG,
837 _GetInstDiskSize(0)),
838 (_MakeField("sdb_size", "LegacyDisk/1", constants.QFT_UNIT), IQ_CONFIG,
839 _GetInstDiskSize(1)),
840 (_MakeField("disk.count", "Disks", constants.QFT_NUMBER), IQ_CONFIG,
841 lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.disks))),
842 (_MakeField("disk.sizes", "Disk_sizes", constants.QFT_OTHER), IQ_CONFIG,
843 lambda ctx, inst: (constants.QRFS_NORMAL,
844 [disk.size for disk in inst.disks])),
849 (_MakeField("disk.size/%s" % i, "Disk/%s" % i, constants.QFT_UNIT),
850 IQ_CONFIG, _GetInstDiskSize(i))
851 for i in range(constants.MAX_DISKS)
857 def _GetInstanceParameterFields():
858 """Get instance fields involving parameters.
860 @return: List of field definitions used as input for L{_PrepareFieldList}
863 # TODO: Consider moving titles closer to constants
865 constants.BE_AUTO_BALANCE: "Auto_balance",
866 constants.BE_MEMORY: "Configured_memory",
867 constants.BE_VCPUS: "VCPUs",
871 constants.HV_ACPI: "ACPI",
872 constants.HV_BOOT_ORDER: "Boot_order",
873 constants.HV_CDROM_IMAGE_PATH: "CDROM_image_path",
874 constants.HV_DISK_TYPE: "Disk_type",
875 constants.HV_INITRD_PATH: "Initrd_path",
876 constants.HV_KERNEL_PATH: "Kernel_path",
877 constants.HV_NIC_TYPE: "NIC_type",
878 constants.HV_PAE: "PAE",
879 constants.HV_VNC_BIND_ADDRESS: "VNC_bind_address",
884 (_MakeField("hvparams", "HypervisorParameters", constants.QFT_OTHER),
885 IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_hvparams)),
886 (_MakeField("beparams", "BackendParameters", constants.QFT_OTHER),
887 IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_beparams)),
888 (_MakeField("vcpus", "LegacyVCPUs", constants.QFT_NUMBER), IQ_CONFIG,
889 lambda ctx, _: (constants.QRFS_NORMAL,
890 ctx.inst_beparams[constants.BE_VCPUS])),
892 # Unfilled parameters
893 (_MakeField("custom_hvparams", "CustomHypervisorParameters",
894 constants.QFT_OTHER),
895 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.hvparams)),
896 (_MakeField("custom_beparams", "CustomBackendParameters",
897 constants.QFT_OTHER),
898 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.beparams)),
899 (_MakeField("custom_nicparams", "CustomNicParameters",
900 constants.QFT_OTHER),
901 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL,
902 [nic.nicparams for nic in inst.nics])),
906 def _GetInstHvParam(name):
907 return lambda ctx, _: (constants.QRFS_NORMAL,
908 ctx.inst_hvparams.get(name, None))
911 # For now all hypervisor parameters are exported as QFT_OTHER
912 (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name),
913 constants.QFT_OTHER),
914 IQ_CONFIG, _GetInstHvParam(name))
915 for name in constants.HVS_PARAMETERS
916 if name not in constants.HVC_GLOBALS
920 def _GetInstBeParam(name):
921 return lambda ctx, _: (constants.QRFS_NORMAL,
922 ctx.inst_beparams.get(name, None))
925 # For now all backend parameters are exported as QFT_OTHER
926 (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name),
927 constants.QFT_OTHER),
928 IQ_CONFIG, _GetInstBeParam(name))
929 for name in constants.BES_PARAMETERS
935 _INST_SIMPLE_FIELDS = {
936 "disk_template": ("Disk_template", constants.QFT_TEXT),
937 "hypervisor": ("Hypervisor", constants.QFT_TEXT),
938 "name": ("Node", constants.QFT_TEXT),
939 # Depending on the hypervisor, the port can be None
940 "network_port": ("Network_port", constants.QFT_OTHER),
941 "os": ("OS", constants.QFT_TEXT),
942 "serial_no": ("SerialNo", constants.QFT_NUMBER),
943 "uuid": ("UUID", constants.QFT_TEXT),
947 def _BuildInstanceFields():
948 """Builds list of fields for instance queries.
952 (_MakeField("pnode", "Primary_node", constants.QFT_TEXT), IQ_CONFIG,
953 lambda ctx, inst: (constants.QRFS_NORMAL, inst.primary_node)),
954 (_MakeField("snodes", "Secondary_Nodes", constants.QFT_OTHER), IQ_CONFIG,
955 lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.secondary_nodes))),
956 (_MakeField("admin_state", "Autostart", constants.QFT_BOOL), IQ_CONFIG,
957 lambda ctx, inst: (constants.QRFS_NORMAL, inst.admin_up)),
958 (_MakeField("tags", "Tags", constants.QFT_OTHER), IQ_CONFIG,
959 lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.GetTags()))),
963 fields.extend([(_MakeField(name, title, kind), IQ_CONFIG, _GetItemAttr(name))
964 for (name, (title, kind)) in _INST_SIMPLE_FIELDS.items()])
966 # Fields requiring talking to the node
968 (_MakeField("oper_state", "Running", constants.QFT_BOOL), IQ_LIVE,
970 (_MakeField("oper_ram", "RuntimeMemory", constants.QFT_UNIT), IQ_LIVE,
971 _GetInstLiveData("memory")),
972 (_MakeField("oper_vcpus", "RuntimeVCPUs", constants.QFT_NUMBER), IQ_LIVE,
973 _GetInstLiveData("vcpus")),
974 (_MakeField("status", "Status", constants.QFT_TEXT), IQ_LIVE,
978 fields.extend(_GetInstanceParameterFields())
979 fields.extend(_GetInstanceDiskFields())
980 fields.extend(_GetInstanceNetworkFields())
981 fields.extend(_GetItemTimestampFields(IQ_CONFIG))
983 return _PrepareFieldList(fields)
986 #: Fields available for node queries
987 NODE_FIELDS = _BuildNodeFields()
989 #: Fields available for instance queries
990 INSTANCE_FIELDS = _BuildInstanceFields()