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):
"""
self.reader = reader
- def Exec(self, query):
+ def Exec(self, query): # pylint: disable-msg=R0201,W0613
"""Process a single UDP request from a client.
Different queries should override this function, which by defaults returns
class PingQuery(ConfdQuery):
"""An empty confd query.
- It will return success on an empty argument, and an error on any other argument.
+ It will return success on an empty argument, and an error on any other
+ argument.
"""
def Exec(self, query):
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
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
+ elif isinstance(query, basestring):
+ # 2.1 beta1 and beta2 mode, to be deprecated for 2.2
+ instances_list = [query]
+ network_link = None
+ mode = constants.CONFD_REQQ_IP
+ else:
+ logging.debug("Invalid query argument type for: %s", query)
+ return QUERY_ARGUMENT_ERROR
+
+ pnodes_list = []
+
+ 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
+
+ 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
+
+ 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
- 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
+ pnodes_list.append((constants.CONFD_REPL_STATUS_OK, pnode_primary_ip))
- 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
+ # 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):
+ """A query for nodes primary IPs.
+
+ It returns the list of nodes primary IPs.
+
+ """
+ def Exec(self, query):
+ """NodesPipsQuery main execution.
+
+ """
+ if query is None:
+ status = constants.CONFD_REPL_STATUS_OK
+ answer = self.reader.GetNodesPrimaryIps()
+ else:
+ status = constants.CONFD_REPL_STATUS_ERROR
+ answer = "non-empty node primary IPs query"
- return constants.CONFD_REPL_STATUS_OK, pnode_primary_ip
+ return status, answer
+
+
+class MasterCandidatesPipsQuery(ConfdQuery):
+ """A query for master candidates primary IPs.
+
+ It returns the list of master candidates primary IPs.
+
+ """
+ def Exec(self, query):
+ """MasterCandidatesPipsQuery main execution.
+
+ """
+ if query is None:
+ status = constants.CONFD_REPL_STATUS_OK
+ answer = self.reader.GetMasterCandidatesPrimaryIps()
+ else:
+ status = constants.CONFD_REPL_STATUS_ERROR
+ answer = "non-empty master candidates primary IPs query"
+
+ return status, answer
+
+
+class InstancesIpsQuery(ConfdQuery):
+ """A query for 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.
+
+ """
+ link = query
+ status = constants.CONFD_REPL_STATUS_OK
+ answer = self.reader.GetInstancesIps(link)
+
+ return status, answer