X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/d01ae714a3f1c72bb18efca9a3c3719e6d1136d8..e9ed4f2e29d5de9a28f060bfc0a6eaf518be7cb0:/lib/confd/querylib.py diff --git a/lib/confd/querylib.py b/lib/confd/querylib.py index 5ede415..e231a14 100644 --- a/lib/confd/querylib.py +++ b/lib/confd/querylib.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2009, Google Inc. +# Copyright (C) 2009 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -33,6 +33,8 @@ QUERY_UNKNOWN_ENTRY_ERROR = (constants.CONFD_REPL_STATUS_ERROR, constants.CONFD_ERROR_UNKNOWN_ENTRY) QUERY_INTERNAL_ERROR = (constants.CONFD_REPL_STATUS_ERROR, constants.CONFD_ERROR_INTERNAL) +QUERY_ARGUMENT_ERROR = (constants.CONFD_REPL_STATUS_ERROR, + constants.CONFD_ERROR_ARGUMENT) class ConfdQuery(object): @@ -48,7 +50,7 @@ class ConfdQuery(object): """ self.reader = reader - def Exec(self, query): + def Exec(self, query): # pylint: disable=R0201,W0613 """Process a single UDP request from a client. Different queries should override this function, which by defaults returns @@ -92,16 +94,38 @@ class ClusterMasterQuery(ConfdQuery): It accepts no arguments, and returns the current cluster master. """ + def _GetMasterNode(self): + return self.reader.GetMasterNode() + def Exec(self, query): """ClusterMasterQuery main execution """ - if query is None: + if isinstance(query, dict): + if constants.CONFD_REQQ_FIELDS in query: + status = constants.CONFD_REPL_STATUS_OK + req_fields = query[constants.CONFD_REQQ_FIELDS] + if not isinstance(req_fields, (list, tuple)): + logging.debug("FIELDS request should be a list") + return QUERY_ARGUMENT_ERROR + + answer = [] + for field in req_fields: + if field == constants.CONFD_REQFIELD_NAME: + answer.append(self._GetMasterNode()) + elif field == constants.CONFD_REQFIELD_IP: + answer.append(self.reader.GetMasterIP()) + elif field == constants.CONFD_REQFIELD_MNODE_PIP: + answer.append(self.reader.GetNodePrimaryIp(self._GetMasterNode())) + else: + logging.debug("missing FIELDS in query dict") + return QUERY_ARGUMENT_ERROR + elif not query: status = constants.CONFD_REPL_STATUS_OK answer = self.reader.GetMasterNode() else: - status = constants.CONFD_REPL_STATUS_ERROR - answer = 'master query accepts no query argument' + logging.debug("Invalid master query argument: not dict or empty") + return QUERY_ARGUMENT_ERROR return status, answer @@ -139,34 +163,77 @@ class NodeRoleQuery(ConfdQuery): class InstanceIpToNodePrimaryIpQuery(ConfdQuery): - """A query for the location of an instance's ip. - - It returns the primary ip of the node hosting the instance having the - requested ip address, or an error if no such address is known. + """A query for the location of one or more instance's ips. """ def Exec(self, query): """InstanceIpToNodePrimaryIpQuery main execution. + @type query: string or dict + @param query: instance ip or dict containing: + constants.CONFD_REQQ_LINK: nic link (optional) + constants.CONFD_REQQ_IPLIST: list of ips + constants.CONFD_REQQ_IP: single ip + (one IP type request is mandatory) + @rtype: (integer, ...) + @return: ((status, answer) or (success, [(status, answer)...]) + """ - instance_ip = query - instance = self.reader.GetInstanceByIp(instance_ip) - if instance is None: - return QUERY_UNKNOWN_ENTRY_ERROR + if isinstance(query, dict): + if constants.CONFD_REQQ_IP in query: + instances_list = [query[constants.CONFD_REQQ_IP]] + mode = constants.CONFD_REQQ_IP + elif constants.CONFD_REQQ_IPLIST in query: + instances_list = query[constants.CONFD_REQQ_IPLIST] + mode = constants.CONFD_REQQ_IPLIST + else: + logging.debug("missing IP or IPLIST in query dict") + return QUERY_ARGUMENT_ERROR + + if constants.CONFD_REQQ_LINK in query: + network_link = query[constants.CONFD_REQQ_LINK] + else: + network_link = None # default will be used + else: + logging.debug("Invalid query argument type for: %s", query) + return QUERY_ARGUMENT_ERROR + + pnodes_list = [] - pnode = self.reader.GetInstancePrimaryNode(instance) - if pnode is None: - # this shouldn't happen - logging.error("Internal configuration inconsistent (instance-to-pnode)") - return QUERY_INTERNAL_ERROR + for instance_ip in instances_list: + if not isinstance(instance_ip, basestring): + logging.debug("Invalid IP type for: %s", instance_ip) + return QUERY_ARGUMENT_ERROR - pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode) - if pnode_primary_ip is None: - # this shouldn't happen - logging.error("Internal configuration inconsistent (node-to-primary-ip)") - return QUERY_INTERNAL_ERROR + instance = self.reader.GetInstanceByLinkIp(instance_ip, network_link) + if not instance: + logging.debug("Unknown instance IP: %s", instance_ip) + pnodes_list.append(QUERY_UNKNOWN_ENTRY_ERROR) + continue - return constants.CONFD_REPL_STATUS_OK, pnode_primary_ip + pnode = self.reader.GetInstancePrimaryNode(instance) + if not pnode: + logging.error("Instance '%s' doesn't have an associated primary" + " node", instance) + pnodes_list.append(QUERY_INTERNAL_ERROR) + continue + + pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode) + if not pnode_primary_ip: + logging.error("Primary node '%s' doesn't have an associated" + " primary IP", pnode) + pnodes_list.append(QUERY_INTERNAL_ERROR) + continue + + pnodes_list.append((constants.CONFD_REPL_STATUS_OK, pnode_primary_ip)) + + # If a single ip was requested, return a single answer, otherwise + # the whole list, with a success status (since each entry has its + # own success/failure) + if mode == constants.CONFD_REQQ_IP: + return pnodes_list[0] + + return constants.CONFD_REPL_STATUS_OK, pnodes_list class NodesPipsQuery(ConfdQuery): @@ -212,19 +279,16 @@ class MasterCandidatesPipsQuery(ConfdQuery): class InstancesIpsQuery(ConfdQuery): """A query for instances IPs. - It returns the list of instances IPs. + It returns the list of IPs of NICs connected to the requested link or all the + instances IPs if no link is submitted. """ def Exec(self, query): """InstancesIpsQuery main execution. """ - if query is None: - status = constants.CONFD_REPL_STATUS_OK - answer = self.reader.GetInstancesIps() - else: - status = constants.CONFD_REPL_STATUS_ERROR - answer = "non-empty instances IPs query" + link = query + status = constants.CONFD_REPL_STATUS_OK + answer = self.reader.GetInstancesIps(link) return status, answer -