X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/ff4cd4d222215219a445e87f7ea3022c32205e82..61413377c7a1c624c4a5f2c2ec55dbc3d8691896:/lib/query.py diff --git a/lib/query.py b/lib/query.py index 5819981..8d8b667 100644 --- a/lib/query.py +++ b/lib/query.py @@ -63,8 +63,8 @@ from ganeti import ht from ganeti.constants import (QFT_UNKNOWN, QFT_TEXT, QFT_BOOL, QFT_NUMBER, QFT_UNIT, QFT_TIMESTAMP, QFT_OTHER, - QRFS_NORMAL, QRFS_UNKNOWN, QRFS_NODATA, - QRFS_UNAVAIL, QRFS_OFFLINE) + RS_NORMAL, RS_UNKNOWN, RS_NODATA, + RS_UNAVAIL, RS_OFFLINE) # Constants for requesting data from the caller/data provider. Each property @@ -79,7 +79,8 @@ from ganeti.constants import (QFT_UNKNOWN, QFT_TEXT, QFT_BOOL, QFT_NUMBER, (IQ_CONFIG, IQ_LIVE, - IQ_DISKUSAGE) = range(100, 103) + IQ_DISKUSAGE, + IQ_CONSOLE) = range(100, 104) (LQ_MODE, LQ_OWNER, @@ -110,6 +111,16 @@ _FS_NODATA = object() _FS_UNAVAIL = object() _FS_OFFLINE = object() +#: VType to QFT mapping +_VTToQFT = { + # TODO: fix validation of empty strings + constants.VTYPE_STRING: QFT_OTHER, # since VTYPE_STRINGs can be empty + constants.VTYPE_MAYBE_STRING: QFT_OTHER, + constants.VTYPE_BOOL: QFT_BOOL, + constants.VTYPE_SIZE: QFT_UNIT, + constants.VTYPE_INT: QFT_NUMBER, + } + def _GetUnknownField(ctx, item): # pylint: disable-msg=W0613 """Gets the contents of an unknown field. @@ -234,15 +245,15 @@ def _ProcessResult(value): """ if value is _FS_UNKNOWN: - return (QRFS_UNKNOWN, None) + return (RS_UNKNOWN, None) elif value is _FS_NODATA: - return (QRFS_NODATA, None) + return (RS_NODATA, None) elif value is _FS_UNAVAIL: - return (QRFS_UNAVAIL, None) + return (RS_UNAVAIL, None) elif value is _FS_OFFLINE: - return (QRFS_OFFLINE, None) + return (RS_OFFLINE, None) else: - return (QRFS_NORMAL, value) + return (RS_NORMAL, value) def _VerifyResultRow(fields, row): @@ -257,7 +268,7 @@ def _VerifyResultRow(fields, row): assert len(row) == len(fields) errs = [] for ((status, value), (fdef, _, _)) in zip(row, fields): - if status == QRFS_NORMAL: + if status == RS_NORMAL: if not _VERIFY_FN[fdef.kind](value): errs.append("normal field %s fails validation (value is %s)" % (fdef.name, value)) @@ -267,14 +278,18 @@ def _VerifyResultRow(fields, row): (utils.CommaJoin(errors), row)) -def _PrepareFieldList(fields): +def _PrepareFieldList(fields, aliases): """Prepares field list for use by L{Query}. Converts the list to a dictionary and does some verification. - @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data kind, - retrieval function) - @param fields: List of fields, see L{Query.__init__} for a better description + @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data + kind, retrieval function) + @param fields: List of fields, see L{Query.__init__} for a better + description + @type aliases: list of tuples; (alias, target) + @param aliases: list of tuples containing aliases; for each + alias/target pair, a duplicate will be created in the field list @rtype: dict @return: Field dictionary for L{Query} @@ -298,7 +313,15 @@ def _PrepareFieldList(fields): result[fdef.name] = field - assert len(result) == len(fields) + for alias, target in aliases: + assert alias not in result, "Alias %s overrides an existing field" % alias + assert target in result, "Missing target %s for alias %s" % (target, alias) + (fdef, k, fn) = result[target] + fdef = fdef.Copy() + fdef.name = alias + result[alias] = (fdef, k, fn) + + assert len(result) == len(fields) + len(aliases) assert compat.all(name == fdef.name for (name, (fdef, _, _)) in result.items()) @@ -634,7 +657,7 @@ def _BuildNodeFields(): # Add timestamps fields.extend(_GetItemTimestampFields(NQ_CONFIG)) - return _PrepareFieldList(fields) + return _PrepareFieldList(fields, []) class InstanceQueryData: @@ -642,7 +665,7 @@ class InstanceQueryData: """ def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes, - live_data): + live_data, wrongnode_inst, console): """Initializes this class. @param instances: List of instance objects @@ -655,6 +678,10 @@ class InstanceQueryData: @param bad_nodes: List of faulty nodes @type live_data: dict; instance name as key @param live_data: Per-instance live data + @type wrongnode_inst: set + @param wrongnode_inst: Set of instances running on wrong node(s) + @type console: dict; instance name as key + @param console: Per-instance console information """ assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \ @@ -668,6 +695,8 @@ class InstanceQueryData: self.offline_nodes = offline_nodes self.bad_nodes = bad_nodes self.live_data = live_data + self.wrongnode_inst = wrongnode_inst + self.console = console # Used for individual rows self.inst_hvparams = None @@ -698,7 +727,7 @@ def _GetInstOperState(ctx, inst): @param inst: Instance object """ - # Can't use QRFS_OFFLINE here as it would describe the instance to + # Can't use RS_OFFLINE here as it would describe the instance to # be offline when we actually don't know due to missing data if inst.primary_node in ctx.bad_nodes: return _FS_NODATA @@ -723,7 +752,7 @@ def _GetInstLiveData(name): """ if (inst.primary_node in ctx.bad_nodes or inst.primary_node in ctx.offline_nodes): - # Can't use QRFS_OFFLINE here as it would describe the instance to be + # Can't use RS_OFFLINE here as it would describe the instance to be # offline when we actually don't know due to missing data return _FS_NODATA @@ -752,7 +781,9 @@ def _GetInstStatus(ctx, inst): return "ERROR_nodedown" if bool(ctx.live_data.get(inst.name)): - if inst.admin_up: + if inst.name in ctx.wrongnode_inst: + return "ERROR_wrongnode" + elif inst.admin_up: return "running" else: return "ERROR_up" @@ -964,6 +995,22 @@ def _GetInstDiskUsage(ctx, inst): return usage +def _GetInstanceConsole(ctx, inst): + """Get console information for instance. + + @type ctx: L{InstanceQueryData} + @type inst: L{objects.Instance} + @param inst: Instance object + + """ + consinfo = ctx.console[inst.name] + + if consinfo is None: + return _FS_UNAVAIL + + return consinfo + + def _GetInstanceDiskFields(): """Get instance fields involving disks. @@ -973,10 +1020,6 @@ def _GetInstanceDiskFields(): fields = [ (_MakeField("disk_usage", "DiskUsage", QFT_UNIT), IQ_DISKUSAGE, _GetInstDiskUsage), - (_MakeField("sda_size", "LegacyDisk/0", QFT_UNIT), IQ_CONFIG, - _GetInstDiskSize(0)), - (_MakeField("sdb_size", "LegacyDisk/1", QFT_UNIT), IQ_CONFIG, - _GetInstDiskSize(1)), (_MakeField("disk.count", "Disks", QFT_NUMBER), IQ_CONFIG, lambda ctx, inst: len(inst.disks)), (_MakeField("disk.sizes", "Disk_sizes", QFT_OTHER), IQ_CONFIG, @@ -1024,8 +1067,6 @@ def _GetInstanceParameterFields(): IQ_CONFIG, lambda ctx, _: ctx.inst_hvparams), (_MakeField("beparams", "BackendParameters", QFT_OTHER), IQ_CONFIG, lambda ctx, _: ctx.inst_beparams), - (_MakeField("vcpus", "LegacyVCPUs", QFT_NUMBER), IQ_CONFIG, - lambda ctx, _: ctx.inst_beparams[constants.BE_VCPUS]), # Unfilled parameters (_MakeField("custom_hvparams", "CustomHypervisorParameters", QFT_OTHER), @@ -1041,10 +1082,10 @@ def _GetInstanceParameterFields(): return lambda ctx, _: ctx.inst_hvparams.get(name, _FS_UNAVAIL) fields.extend([ - # For now all hypervisor parameters are exported as QFT_OTHER - (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name), QFT_OTHER), + (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name), + _VTToQFT[kind]), IQ_CONFIG, _GetInstHvParam(name)) - for name in constants.HVS_PARAMETERS + for name, kind in constants.HVS_PARAMETER_TYPES.items() if name not in constants.HVC_GLOBALS ]) @@ -1053,10 +1094,10 @@ def _GetInstanceParameterFields(): return lambda ctx, _: ctx.inst_beparams.get(name, None) fields.extend([ - # For now all backend parameters are exported as QFT_OTHER - (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name), QFT_OTHER), - IQ_CONFIG, _GetInstBeParam(name)) - for name in constants.BES_PARAMETERS + (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name), + _VTToQFT[kind]), IQ_CONFIG, + _GetInstBeParam(name)) + for name, kind in constants.BES_PARAMETER_TYPES.items() ]) return fields @@ -1087,6 +1128,8 @@ def _BuildInstanceFields(): _GetItemAttr("admin_up")), (_MakeField("tags", "Tags", QFT_OTHER), IQ_CONFIG, lambda ctx, inst: list(inst.GetTags())), + (_MakeField("console", "Console", QFT_OTHER), IQ_CONSOLE, + _GetInstanceConsole), ] # Add simple fields @@ -1109,7 +1152,13 @@ def _BuildInstanceFields(): fields.extend(_GetInstanceNetworkFields()) fields.extend(_GetItemTimestampFields(IQ_CONFIG)) - return _PrepareFieldList(fields) + aliases = [ + ("vcpus", "be/vcpus"), + ("sda_size", "disk.size/0"), + ("sdb_size", "disk.size/1"), + ] + + return _PrepareFieldList(fields, aliases) class LockQueryData: @@ -1165,7 +1214,7 @@ def _BuildLockFields(): lambda ctx, (name, mode, owners, pending): mode), (_MakeField("owner", "Owner", QFT_OTHER), LQ_OWNER, _GetLockOwners), (_MakeField("pending", "Pending", QFT_OTHER), LQ_PENDING, _GetLockPending), - ]) + ], []) class GroupQueryData: @@ -1237,7 +1286,7 @@ def _BuildGroupFields(): fields.extend(_GetItemTimestampFields(GQ_CONFIG)) - return _PrepareFieldList(fields) + return _PrepareFieldList(fields, []) #: Fields available for node queries