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)
49 FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$")
50 TITLE_RE = re.compile(r"^[^\s]+$")
52 #: Verification function for each field type
54 constants.QFT_UNKNOWN: ht.TNone,
55 constants.QFT_TEXT: ht.TString,
56 constants.QFT_BOOL: ht.TBool,
57 constants.QFT_NUMBER: ht.TInt,
58 constants.QFT_UNIT: ht.TInt,
59 constants.QFT_TIMESTAMP: ht.TOr(ht.TInt, ht.TFloat),
60 constants.QFT_OTHER: lambda _: True,
64 def _GetUnknownField(ctx, item): # pylint: disable-msg=W0613
65 """Gets the contents of an unknown field.
68 return (constants.QRFS_UNKNOWN, None)
71 def _GetQueryFields(fielddefs, selected):
72 """Calculates the internal list of selected fields.
74 Unknown fields are returned as L{constants.QFT_UNKNOWN}.
77 @param fielddefs: Field definitions
78 @type selected: list of strings
79 @param selected: List of selected fields
86 fdef = fielddefs[name]
88 fdef = (_MakeField(name, name, constants.QFT_UNKNOWN),
89 None, _GetUnknownField)
98 def GetAllFields(fielddefs):
99 """Extract L{objects.QueryFieldDefinition} from field definitions.
101 @rtype: list of L{objects.QueryFieldDefinition}
104 return [fdef for (fdef, _, _) in fielddefs]
108 def __init__(self, fieldlist, selected):
109 """Initializes this class.
111 The field definition is a dictionary with the field's name as a key and a
112 tuple containing, in order, the field definition object
113 (L{objects.QueryFieldDefinition}, the data kind to help calling code
114 collect data and a retrieval function. The retrieval function is called
115 with two parameters, in order, the data container and the item in container
116 (see L{Query.Query}).
118 Users of this class can call L{RequestedData} before preparing the data
119 container to determine what data is needed.
121 @type fieldlist: dictionary
122 @param fieldlist: Field definitions
123 @type selected: list of strings
124 @param selected: List of selected fields
127 self._fields = _GetQueryFields(fieldlist, selected)
129 def RequestedData(self):
130 """Gets requested kinds of data.
135 return frozenset(datakind
136 for (_, datakind, _) in self._fields
137 if datakind is not None)
140 """Returns the list of fields for this query.
142 Includes unknown fields.
144 @rtype: List of L{objects.QueryFieldDefinition}
147 return GetAllFields(self._fields)
149 def Query(self, ctx):
152 @param ctx: Data container passed to field retrieval functions, must
153 support iteration using C{__iter__}
156 result = [[fn(ctx, item) for (_, _, fn) in self._fields]
161 for (idx, row) in enumerate(result):
162 assert _VerifyResultRow(self._fields, row), \
163 ("Inconsistent result for fields %s in row %s: %r" %
164 (GetAllFields(self._fields), idx, row))
168 def OldStyleQuery(self, ctx):
169 """Query with "old" query result format.
171 See L{Query.Query} for arguments.
174 unknown = set(fdef.name
175 for (fdef, _, _) in self._fields
176 if fdef.kind == constants.QFT_UNKNOWN)
178 raise errors.OpPrereqError("Unknown output fields selected: %s" %
179 (utils.CommaJoin(unknown), ),
182 return [[value for (_, value) in row]
183 for row in self.Query(ctx)]
186 def _VerifyResultRow(fields, row):
187 """Verifies the contents of a query result row.
190 @param fields: Field definitions for result
191 @type row: list of tuples
195 return (len(row) == len(fields) and
196 compat.all((status == constants.QRFS_NORMAL and
197 _VERIFY_FN[fdef.kind](value)) or
198 # Value for an abnormal status must be None
199 (status != constants.QRFS_NORMAL and value is None)
200 for ((status, value), (fdef, _, _)) in zip(row, fields)))
203 def _PrepareFieldList(fields):
204 """Prepares field list for use by L{Query}.
206 Converts the list to a dictionary and does some verification.
208 @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data kind,
210 @param fields: List of fields
212 @return: Field dictionary for L{Query}
216 duplicates = utils.FindDuplicates(fdef.title.lower()
217 for (fdef, _, _) in fields)
218 assert not duplicates, "Duplicate title(s) found: %r" % duplicates
223 (fdef, _, fn) = field
225 assert fdef.name and fdef.title, "Name and title are required"
226 assert FIELD_NAME_RE.match(fdef.name)
227 assert TITLE_RE.match(fdef.title)
229 assert fdef.name not in result, \
230 "Duplicate field name '%s' found" % fdef.name
232 result[fdef.name] = field
234 assert len(result) == len(fields)
235 assert compat.all(name == fdef.name
236 for (name, (fdef, _, _)) in result.items())
241 def GetQueryResponse(query, ctx):
242 """Prepares the response for a query.
244 @type query: L{Query}
245 @param ctx: Data container, see L{Query.Query}
248 return objects.QueryResponse(data=query.Query(ctx),
249 fields=query.GetFields()).ToDict()
252 def QueryFields(fielddefs, selected):
253 """Returns list of available fields.
255 @type fielddefs: dict
256 @param fielddefs: Field definitions
257 @type selected: list of strings
258 @param selected: List of selected fields
259 @return: List of L{objects.QueryFieldDefinition}
263 # Client requests all fields, sort by name
264 fdefs = utils.NiceSort(GetAllFields(fielddefs.values()),
265 key=operator.attrgetter("name"))
267 # Keep order as requested by client
268 fdefs = Query(fielddefs, selected).GetFields()
270 return objects.QueryFieldsResponse(fields=fdefs).ToDict()
273 def _MakeField(name, title, kind):
274 """Wrapper for creating L{objects.QueryFieldDefinition} instances.
276 @param name: Field name as a regular expression
277 @param title: Human-readable title
278 @param kind: Field type
281 return objects.QueryFieldDefinition(name=name, title=title, kind=kind)
284 def _GetNodeRole(node, master_name):
285 """Determine node role.
287 @type node: L{objects.Node}
288 @param node: Node object
289 @type master_name: string
290 @param master_name: Master node name
293 if node.name == master_name:
295 elif node.master_candidate:
305 def _GetItemAttr(attr):
306 """Returns a field function to return an attribute of the item.
308 @param attr: Attribute name
311 getter = operator.attrgetter(attr)
312 return lambda _, item: (constants.QRFS_NORMAL, getter(item))
315 def _GetItemTimestamp(getter):
316 """Returns function for getting timestamp of item.
318 @type getter: callable
319 @param getter: Function to retrieve timestamp attribute
323 """Returns a timestamp of item.
326 timestamp = getter(item)
327 if timestamp is None:
328 # Old configs might not have all timestamps
329 return (constants.QRFS_UNAVAIL, None)
331 return (constants.QRFS_NORMAL, timestamp)
336 def _GetItemTimestampFields(datatype):
337 """Returns common timestamp fields.
339 @param datatype: Field data type for use by L{Query.RequestedData}
343 (_MakeField("ctime", "CTime", constants.QFT_TIMESTAMP), datatype,
344 _GetItemTimestamp(operator.attrgetter("ctime"))),
345 (_MakeField("mtime", "MTime", constants.QFT_TIMESTAMP), datatype,
346 _GetItemTimestamp(operator.attrgetter("mtime"))),
351 """Data container for node data queries.
354 def __init__(self, nodes, live_data, master_name, node_to_primary,
355 node_to_secondary, groups):
356 """Initializes this class.
360 self.live_data = live_data
361 self.master_name = master_name
362 self.node_to_primary = node_to_primary
363 self.node_to_secondary = node_to_secondary
366 # Used for individual rows
367 self.curlive_data = None
370 """Iterate over all nodes.
372 This function has side-effects and only one instance of the resulting
373 generator should be used at a time.
376 for node in self.nodes:
378 self.curlive_data = self.live_data.get(node.name, None)
380 self.curlive_data = None
384 #: Fields that are direct attributes of an L{objects.Node} object
385 _NODE_SIMPLE_FIELDS = {
386 "drained": ("Drained", constants.QFT_BOOL),
387 "master_candidate": ("MasterC", constants.QFT_BOOL),
388 "master_capable": ("MasterCapable", constants.QFT_BOOL),
389 "name": ("Node", constants.QFT_TEXT),
390 "offline": ("Offline", constants.QFT_BOOL),
391 "serial_no": ("SerialNo", constants.QFT_NUMBER),
392 "uuid": ("UUID", constants.QFT_TEXT),
393 "vm_capable": ("VMCapable", constants.QFT_BOOL),
397 #: Fields requiring talking to the node
398 _NODE_LIVE_FIELDS = {
399 "bootid": ("BootID", constants.QFT_TEXT, "bootid"),
400 "cnodes": ("CNodes", constants.QFT_NUMBER, "cpu_nodes"),
401 "csockets": ("CSockets", constants.QFT_NUMBER, "cpu_sockets"),
402 "ctotal": ("CTotal", constants.QFT_NUMBER, "cpu_total"),
403 "dfree": ("DFree", constants.QFT_UNIT, "vg_free"),
404 "dtotal": ("DTotal", constants.QFT_UNIT, "vg_size"),
405 "mfree": ("MFree", constants.QFT_UNIT, "memory_free"),
406 "mnode": ("MNode", constants.QFT_UNIT, "memory_dom0"),
407 "mtotal": ("MTotal", constants.QFT_UNIT, "memory_total"),
411 def _GetNodeGroup(ctx, node):
412 """Returns the name of a node's group.
414 @type ctx: L{NodeQueryData}
415 @type node: L{objects.Node}
416 @param node: Node object
419 ng = ctx.groups.get(node.group, None)
421 # Nodes always have a group, or the configuration is corrupt
422 return (constants.QRFS_UNAVAIL, None)
424 return (constants.QRFS_NORMAL, ng.name)
427 def _GetLiveNodeField(field, kind, ctx, node):
428 """Gets the value of a "live" field from L{NodeQueryData}.
430 @param field: Live field name
431 @param kind: Data kind, one of L{constants.QFT_ALL}
432 @type ctx: L{NodeQueryData}
433 @type node: L{objects.Node}
434 @param node: Node object
438 return (constants.QRFS_OFFLINE, None)
440 if not ctx.curlive_data:
441 return (constants.QRFS_NODATA, None)
444 value = ctx.curlive_data[field]
446 return (constants.QRFS_UNAVAIL, None)
448 if kind == constants.QFT_TEXT:
449 return (constants.QRFS_NORMAL, value)
451 assert kind in (constants.QFT_NUMBER, constants.QFT_UNIT)
453 # Try to convert into number
455 return (constants.QRFS_NORMAL, int(value))
456 except (ValueError, TypeError):
457 logging.exception("Failed to convert node field '%s' (value %r) to int",
459 return (constants.QRFS_UNAVAIL, None)
462 def _BuildNodeFields():
463 """Builds list of fields for node queries.
467 (_MakeField("pip", "PrimaryIP", constants.QFT_TEXT), NQ_CONFIG,
468 lambda ctx, node: (constants.QRFS_NORMAL, node.primary_ip)),
469 (_MakeField("sip", "SecondaryIP", constants.QFT_TEXT), NQ_CONFIG,
470 lambda ctx, node: (constants.QRFS_NORMAL, node.secondary_ip)),
471 (_MakeField("tags", "Tags", constants.QFT_OTHER), NQ_CONFIG,
472 lambda ctx, node: (constants.QRFS_NORMAL, list(node.GetTags()))),
473 (_MakeField("master", "IsMaster", constants.QFT_BOOL), NQ_CONFIG,
474 lambda ctx, node: (constants.QRFS_NORMAL, node.name == ctx.master_name)),
475 (_MakeField("role", "Role", constants.QFT_TEXT), NQ_CONFIG,
476 lambda ctx, node: (constants.QRFS_NORMAL,
477 _GetNodeRole(node, ctx.master_name))),
478 (_MakeField("group", "Group", constants.QFT_TEXT), NQ_GROUP, _GetNodeGroup),
479 (_MakeField("group.uuid", "GroupUUID", constants.QFT_TEXT),
480 NQ_CONFIG, lambda ctx, node: (constants.QRFS_NORMAL, node.group)),
483 def _GetLength(getter):
484 return lambda ctx, node: (constants.QRFS_NORMAL,
485 len(getter(ctx)[node.name]))
487 def _GetList(getter):
488 return lambda ctx, node: (constants.QRFS_NORMAL,
489 list(getter(ctx)[node.name]))
491 # Add fields operating on instance lists
492 for prefix, titleprefix, getter in \
493 [("p", "Pri", operator.attrgetter("node_to_primary")),
494 ("s", "Sec", operator.attrgetter("node_to_secondary"))]:
496 (_MakeField("%sinst_cnt" % prefix, "%sinst" % prefix.upper(),
497 constants.QFT_NUMBER),
498 NQ_INST, _GetLength(getter)),
499 (_MakeField("%sinst_list" % prefix, "%sInstances" % titleprefix,
500 constants.QFT_OTHER),
501 NQ_INST, _GetList(getter)),
505 fields.extend([(_MakeField(name, title, kind), NQ_CONFIG, _GetItemAttr(name))
506 for (name, (title, kind)) in _NODE_SIMPLE_FIELDS.items()])
508 # Add fields requiring live data
510 (_MakeField(name, title, kind), NQ_LIVE,
511 compat.partial(_GetLiveNodeField, nfield, kind))
512 for (name, (title, kind, nfield)) in _NODE_LIVE_FIELDS.items()
516 fields.extend(_GetItemTimestampFields(NQ_CONFIG))
518 return _PrepareFieldList(fields)
521 class InstanceQueryData:
522 """Data container for instance data queries.
525 def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
527 """Initializes this class.
529 @param instances: List of instance objects
530 @param cluster: Cluster object
531 @type disk_usage: dict; instance name as key
532 @param disk_usage: Per-instance disk usage
533 @type offline_nodes: list of strings
534 @param offline_nodes: List of offline nodes
535 @type bad_nodes: list of strings
536 @param bad_nodes: List of faulty nodes
537 @type live_data: dict; instance name as key
538 @param live_data: Per-instance live data
541 assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
542 "Offline nodes not included in bad nodes"
543 assert not (set(live_data.keys()) & set(bad_nodes)), \
544 "Found live data for bad or offline nodes"
546 self.instances = instances
547 self.cluster = cluster
548 self.disk_usage = disk_usage
549 self.offline_nodes = offline_nodes
550 self.bad_nodes = bad_nodes
551 self.live_data = live_data
553 # Used for individual rows
554 self.inst_hvparams = None
555 self.inst_beparams = None
556 self.inst_nicparams = None
559 """Iterate over all instances.
561 This function has side-effects and only one instance of the resulting
562 generator should be used at a time.
565 for inst in self.instances:
566 self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
567 self.inst_beparams = self.cluster.FillBE(inst)
568 self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
569 for nic in inst.nics]
574 def _GetInstOperState(ctx, inst):
575 """Get instance's operational status.
577 @type ctx: L{InstanceQueryData}
578 @type inst: L{objects.Instance}
579 @param inst: Instance object
582 # Can't use QRFS_OFFLINE here as it would describe the instance to be offline
583 # when we actually don't know due to missing data
584 if inst.primary_node in ctx.bad_nodes:
585 return (constants.QRFS_NODATA, None)
587 return (constants.QRFS_NORMAL, bool(ctx.live_data.get(inst.name)))
590 def _GetInstLiveData(name):
591 """Build function for retrieving live data.
594 @param name: Live data field name
598 """Get live data for an instance.
600 @type ctx: L{InstanceQueryData}
601 @type inst: L{objects.Instance}
602 @param inst: Instance object
605 if (inst.primary_node in ctx.bad_nodes or
606 inst.primary_node in ctx.offline_nodes):
607 # Can't use QRFS_OFFLINE here as it would describe the instance to be
608 # offline when we actually don't know due to missing data
609 return (constants.QRFS_NODATA, None)
611 if inst.name in ctx.live_data:
612 data = ctx.live_data[inst.name]
614 return (constants.QRFS_NORMAL, data[name])
616 return (constants.QRFS_UNAVAIL, None)
621 def _GetInstStatus(ctx, inst):
622 """Get instance status.
624 @type ctx: L{InstanceQueryData}
625 @type inst: L{objects.Instance}
626 @param inst: Instance object
629 if inst.primary_node in ctx.offline_nodes:
630 return (constants.QRFS_NORMAL, "ERROR_nodeoffline")
632 if inst.primary_node in ctx.bad_nodes:
633 return (constants.QRFS_NORMAL, "ERROR_nodedown")
635 if bool(ctx.live_data.get(inst.name)):
637 return (constants.QRFS_NORMAL, "running")
639 return (constants.QRFS_NORMAL, "ERROR_up")
642 return (constants.QRFS_NORMAL, "ERROR_down")
644 return (constants.QRFS_NORMAL, "ADMIN_down")
647 def _GetInstDiskSize(index):
648 """Build function for retrieving disk size.
651 @param index: Disk index
655 """Get size of a disk.
657 @type inst: L{objects.Instance}
658 @param inst: Instance object
662 return (constants.QRFS_NORMAL, inst.disks[index].size)
664 return (constants.QRFS_UNAVAIL, None)
669 def _GetInstNic(index, cb):
670 """Build function for calling another function with an instance NIC.
673 @param index: NIC index
679 """Call helper function with instance NIC.
681 @type ctx: L{InstanceQueryData}
682 @type inst: L{objects.Instance}
683 @param inst: Instance object
687 nic = inst.nics[index]
689 return (constants.QRFS_UNAVAIL, None)
691 return cb(ctx, index, nic)
696 def _GetInstNicIp(ctx, _, nic): # pylint: disable-msg=W0613
697 """Get a NIC's IP address.
699 @type ctx: L{InstanceQueryData}
700 @type nic: L{objects.NIC}
701 @param nic: NIC object
705 return (constants.QRFS_UNAVAIL, None)
707 return (constants.QRFS_NORMAL, nic.ip)
710 def _GetInstNicBridge(ctx, index, _):
711 """Get a NIC's bridge.
713 @type ctx: L{InstanceQueryData}
715 @param index: NIC index
718 assert len(ctx.inst_nicparams) >= index
720 nicparams = ctx.inst_nicparams[index]
722 if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
723 return (constants.QRFS_NORMAL, nicparams[constants.NIC_LINK])
725 return (constants.QRFS_UNAVAIL, None)
728 def _GetInstAllNicBridges(ctx, inst):
729 """Get all network bridges for an instance.
731 @type ctx: L{InstanceQueryData}
732 @type inst: L{objects.Instance}
733 @param inst: Instance object
736 assert len(ctx.inst_nicparams) == len(inst.nics)
740 for nicp in ctx.inst_nicparams:
741 if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
742 result.append(nicp[constants.NIC_LINK])
746 assert len(result) == len(inst.nics)
748 return (constants.QRFS_NORMAL, result)
751 def _GetInstNicParam(name):
752 """Build function for retrieving a NIC parameter.
755 @param name: Parameter name
758 def fn(ctx, index, _):
759 """Get a NIC's bridge.
761 @type ctx: L{InstanceQueryData}
762 @type inst: L{objects.Instance}
763 @param inst: Instance object
764 @type nic: L{objects.NIC}
765 @param nic: NIC object
768 assert len(ctx.inst_nicparams) >= index
769 return (constants.QRFS_NORMAL, ctx.inst_nicparams[index][name])
774 def _GetInstanceNetworkFields():
775 """Get instance fields involving network interfaces.
777 @return: List of field definitions used as input for L{_PrepareFieldList}
780 nic_mac_fn = lambda ctx, _, nic: (constants.QRFS_NORMAL, nic.mac)
781 nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
782 nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
786 (_MakeField("ip", "IP_address", constants.QFT_TEXT), IQ_CONFIG,
787 _GetInstNic(0, _GetInstNicIp)),
788 (_MakeField("mac", "MAC_address", constants.QFT_TEXT), IQ_CONFIG,
789 _GetInstNic(0, nic_mac_fn)),
790 (_MakeField("bridge", "Bridge", constants.QFT_TEXT), IQ_CONFIG,
791 _GetInstNic(0, _GetInstNicBridge)),
792 (_MakeField("nic_mode", "NIC_Mode", constants.QFT_TEXT), IQ_CONFIG,
793 _GetInstNic(0, nic_mode_fn)),
794 (_MakeField("nic_link", "NIC_Link", constants.QFT_TEXT), IQ_CONFIG,
795 _GetInstNic(0, nic_link_fn)),
798 (_MakeField("nic.count", "NICs", constants.QFT_NUMBER), IQ_CONFIG,
799 lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.nics))),
800 (_MakeField("nic.macs", "NIC_MACs", constants.QFT_OTHER), IQ_CONFIG,
801 lambda ctx, inst: (constants.QRFS_NORMAL, [nic.mac for nic in inst.nics])),
802 (_MakeField("nic.ips", "NIC_IPs", constants.QFT_OTHER), IQ_CONFIG,
803 lambda ctx, inst: (constants.QRFS_NORMAL, [nic.ip for nic in inst.nics])),
804 (_MakeField("nic.modes", "NIC_modes", constants.QFT_OTHER), IQ_CONFIG,
805 lambda ctx, inst: (constants.QRFS_NORMAL,
806 [nicp[constants.NIC_MODE]
807 for nicp in ctx.inst_nicparams])),
808 (_MakeField("nic.links", "NIC_links", constants.QFT_OTHER), IQ_CONFIG,
809 lambda ctx, inst: (constants.QRFS_NORMAL,
810 [nicp[constants.NIC_LINK]
811 for nicp in ctx.inst_nicparams])),
812 (_MakeField("nic.bridges", "NIC_bridges", constants.QFT_OTHER), IQ_CONFIG,
813 _GetInstAllNicBridges),
817 for i in range(constants.MAX_NICS):
819 (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, constants.QFT_TEXT),
820 IQ_CONFIG, _GetInstNic(i, _GetInstNicIp)),
821 (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, constants.QFT_TEXT),
822 IQ_CONFIG, _GetInstNic(i, nic_mac_fn)),
823 (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, constants.QFT_TEXT),
824 IQ_CONFIG, _GetInstNic(i, nic_mode_fn)),
825 (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, constants.QFT_TEXT),
826 IQ_CONFIG, _GetInstNic(i, nic_link_fn)),
827 (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, constants.QFT_TEXT),
828 IQ_CONFIG, _GetInstNic(i, _GetInstNicBridge)),
834 def _GetInstDiskUsage(ctx, inst):
835 """Get disk usage for an instance.
837 @type ctx: L{InstanceQueryData}
838 @type inst: L{objects.Instance}
839 @param inst: Instance object
842 usage = ctx.disk_usage[inst.name]
847 return (constants.QRFS_NORMAL, usage)
850 def _GetInstanceDiskFields():
851 """Get instance fields involving disks.
853 @return: List of field definitions used as input for L{_PrepareFieldList}
857 (_MakeField("disk_usage", "DiskUsage", constants.QFT_UNIT), IQ_DISKUSAGE,
859 (_MakeField("sda_size", "LegacyDisk/0", constants.QFT_UNIT), IQ_CONFIG,
860 _GetInstDiskSize(0)),
861 (_MakeField("sdb_size", "LegacyDisk/1", constants.QFT_UNIT), IQ_CONFIG,
862 _GetInstDiskSize(1)),
863 (_MakeField("disk.count", "Disks", constants.QFT_NUMBER), IQ_CONFIG,
864 lambda ctx, inst: (constants.QRFS_NORMAL, len(inst.disks))),
865 (_MakeField("disk.sizes", "Disk_sizes", constants.QFT_OTHER), IQ_CONFIG,
866 lambda ctx, inst: (constants.QRFS_NORMAL,
867 [disk.size for disk in inst.disks])),
872 (_MakeField("disk.size/%s" % i, "Disk/%s" % i, constants.QFT_UNIT),
873 IQ_CONFIG, _GetInstDiskSize(i))
874 for i in range(constants.MAX_DISKS)
880 def _GetInstanceParameterFields():
881 """Get instance fields involving parameters.
883 @return: List of field definitions used as input for L{_PrepareFieldList}
886 # TODO: Consider moving titles closer to constants
888 constants.BE_AUTO_BALANCE: "Auto_balance",
889 constants.BE_MEMORY: "Configured_memory",
890 constants.BE_VCPUS: "VCPUs",
894 constants.HV_ACPI: "ACPI",
895 constants.HV_BOOT_ORDER: "Boot_order",
896 constants.HV_CDROM_IMAGE_PATH: "CDROM_image_path",
897 constants.HV_DISK_TYPE: "Disk_type",
898 constants.HV_INITRD_PATH: "Initrd_path",
899 constants.HV_KERNEL_PATH: "Kernel_path",
900 constants.HV_NIC_TYPE: "NIC_type",
901 constants.HV_PAE: "PAE",
902 constants.HV_VNC_BIND_ADDRESS: "VNC_bind_address",
907 (_MakeField("hvparams", "HypervisorParameters", constants.QFT_OTHER),
908 IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_hvparams)),
909 (_MakeField("beparams", "BackendParameters", constants.QFT_OTHER),
910 IQ_CONFIG, lambda ctx, _: (constants.QRFS_NORMAL, ctx.inst_beparams)),
911 (_MakeField("vcpus", "LegacyVCPUs", constants.QFT_NUMBER), IQ_CONFIG,
912 lambda ctx, _: (constants.QRFS_NORMAL,
913 ctx.inst_beparams[constants.BE_VCPUS])),
915 # Unfilled parameters
916 (_MakeField("custom_hvparams", "CustomHypervisorParameters",
917 constants.QFT_OTHER),
918 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.hvparams)),
919 (_MakeField("custom_beparams", "CustomBackendParameters",
920 constants.QFT_OTHER),
921 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL, inst.beparams)),
922 (_MakeField("custom_nicparams", "CustomNicParameters",
923 constants.QFT_OTHER),
924 IQ_CONFIG, lambda ctx, inst: (constants.QRFS_NORMAL,
925 [nic.nicparams for nic in inst.nics])),
929 def _GetInstHvParam(name):
930 return lambda ctx, _: (constants.QRFS_NORMAL,
931 ctx.inst_hvparams.get(name, None))
934 # For now all hypervisor parameters are exported as QFT_OTHER
935 (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name),
936 constants.QFT_OTHER),
937 IQ_CONFIG, _GetInstHvParam(name))
938 for name in constants.HVS_PARAMETERS
939 if name not in constants.HVC_GLOBALS
943 def _GetInstBeParam(name):
944 return lambda ctx, _: (constants.QRFS_NORMAL,
945 ctx.inst_beparams.get(name, None))
948 # For now all backend parameters are exported as QFT_OTHER
949 (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name),
950 constants.QFT_OTHER),
951 IQ_CONFIG, _GetInstBeParam(name))
952 for name in constants.BES_PARAMETERS
958 _INST_SIMPLE_FIELDS = {
959 "disk_template": ("Disk_template", constants.QFT_TEXT),
960 "hypervisor": ("Hypervisor", constants.QFT_TEXT),
961 "name": ("Node", constants.QFT_TEXT),
962 # Depending on the hypervisor, the port can be None
963 "network_port": ("Network_port", constants.QFT_OTHER),
964 "os": ("OS", constants.QFT_TEXT),
965 "serial_no": ("SerialNo", constants.QFT_NUMBER),
966 "uuid": ("UUID", constants.QFT_TEXT),
970 def _BuildInstanceFields():
971 """Builds list of fields for instance queries.
975 (_MakeField("pnode", "Primary_node", constants.QFT_TEXT), IQ_CONFIG,
976 lambda ctx, inst: (constants.QRFS_NORMAL, inst.primary_node)),
977 (_MakeField("snodes", "Secondary_Nodes", constants.QFT_OTHER), IQ_CONFIG,
978 lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.secondary_nodes))),
979 (_MakeField("admin_state", "Autostart", constants.QFT_BOOL), IQ_CONFIG,
980 lambda ctx, inst: (constants.QRFS_NORMAL, inst.admin_up)),
981 (_MakeField("tags", "Tags", constants.QFT_OTHER), IQ_CONFIG,
982 lambda ctx, inst: (constants.QRFS_NORMAL, list(inst.GetTags()))),
986 fields.extend([(_MakeField(name, title, kind), IQ_CONFIG, _GetItemAttr(name))
987 for (name, (title, kind)) in _INST_SIMPLE_FIELDS.items()])
989 # Fields requiring talking to the node
991 (_MakeField("oper_state", "Running", constants.QFT_BOOL), IQ_LIVE,
993 (_MakeField("oper_ram", "RuntimeMemory", constants.QFT_UNIT), IQ_LIVE,
994 _GetInstLiveData("memory")),
995 (_MakeField("oper_vcpus", "RuntimeVCPUs", constants.QFT_NUMBER), IQ_LIVE,
996 _GetInstLiveData("vcpus")),
997 (_MakeField("status", "Status", constants.QFT_TEXT), IQ_LIVE,
1001 fields.extend(_GetInstanceParameterFields())
1002 fields.extend(_GetInstanceDiskFields())
1003 fields.extend(_GetInstanceNetworkFields())
1004 fields.extend(_GetItemTimestampFields(IQ_CONFIG))
1006 return _PrepareFieldList(fields)
1009 class LockQueryData:
1010 """Data container for lock data queries.
1013 def __init__(self, lockdata):
1014 """Initializes this class.
1017 self.lockdata = lockdata
1020 """Iterate over all locks.
1023 return iter(self.lockdata)
1026 def _GetLockOwners(_, data):
1027 """Returns a sorted list of a lock's current owners.
1030 (_, _, owners, _) = data
1033 owners = utils.NiceSort(owners)
1035 return (constants.QRFS_NORMAL, owners)
1038 def _GetLockPending(_, data):
1039 """Returns a sorted list of a lock's pending acquires.
1042 (_, _, _, pending) = data
1045 pending = [(mode, utils.NiceSort(names))
1046 for (mode, names) in pending]
1048 return (constants.QRFS_NORMAL, pending)
1051 def _BuildLockFields():
1052 """Builds list of fields for lock queries.
1055 return _PrepareFieldList([
1056 (_MakeField("name", "Name", constants.QFT_TEXT), None,
1057 lambda ctx, (name, mode, owners, pending): (constants.QRFS_NORMAL, name)),
1058 (_MakeField("mode", "Mode", constants.QFT_OTHER), LQ_MODE,
1059 lambda ctx, (name, mode, owners, pending): (constants.QRFS_NORMAL, mode)),
1060 (_MakeField("owner", "Owner", constants.QFT_OTHER), LQ_OWNER,
1062 (_MakeField("pending", "Pending", constants.QFT_OTHER), LQ_PENDING,
1067 #: Fields available for node queries
1068 NODE_FIELDS = _BuildNodeFields()
1070 #: Fields available for instance queries
1071 INSTANCE_FIELDS = _BuildInstanceFields()
1073 #: Fields available for lock queries
1074 LOCK_FIELDS = _BuildLockFields()
1076 #: All available field lists
1077 ALL_FIELD_LISTS = [NODE_FIELDS, INSTANCE_FIELDS, LOCK_FIELDS]