cmdlib: Drop use of “len(…) != 0”
[ganeti-local] / lib / confd / querylib.py
index 5e7370e..e231a14 100644 (file)
@@ -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
 
@@ -141,50 +165,72 @@ class NodeRoleQuery(ConfdQuery):
 class InstanceIpToNodePrimaryIpQuery(ConfdQuery):
   """A query for the location of one or more instance's ips.
 
-  Given a list of instance IPs, returns an ordered list with the same
-  number of elements as the input. Each element of the list is a tuple
-  containing the status (success or failure) and the content of the
-  query (IP of the primary node if successful, error constant if not).
-
-  If a string (instance's IP) is given instead of a list it will return
-  a single tuple, as opposed to a 1-element list containing that tuple.
-
   """
   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)...])
+
     """
-    if isinstance(query, list):
-      instances_list = query
+    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:
-      instances_list = [query]
+      logging.debug("Invalid query argument type for: %s", query)
+      return QUERY_ARGUMENT_ERROR
+
     pnodes_list = []
 
     for instance_ip in instances_list:
-      instance = self.reader.GetInstanceByLinkIp(instance_ip, None)
+      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("Invalid instance IP: %s" % 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)
+                      " 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)
+                      " primary IP", pnode)
         pnodes_list.append(QUERY_INTERNAL_ERROR)
         continue
 
       pnodes_list.append((constants.CONFD_REPL_STATUS_OK, pnode_primary_ip))
 
-    # If input was a string, return a tuple instead of a 1-element list
-    if isinstance(query, basestring):
+    # 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