DeprecationWarning fixes for pylint
[ganeti-local] / lib / rapi / connector.py
index 1b9d646..499e2e6 100644 (file)
 
 """
 
 
 """
 
+# pylint: disable=C0103
+
+# C0103: Invalid name, since the R_* names are not conforming
+
 import cgi
 import re
 
 from ganeti import constants
 from ganeti import http
 import cgi
 import re
 
 from ganeti import constants
 from ganeti import http
+from ganeti import utils
 
 from ganeti.rapi import baserlib
 from ganeti.rapi import rlib2
 
 
 from ganeti.rapi import baserlib
 from ganeti.rapi import rlib2
 
+
+_NAME_PATTERN = r"[\w\._-]+"
+_DISK_PATTERN = r"\d+"
+
 # the connection map is created at the end of this file
 CONNECTOR = {}
 
 # the connection map is created at the end of this file
 CONNECTOR = {}
 
@@ -39,12 +48,14 @@ class Mapper:
   """Map resource to method.
 
   """
   """Map resource to method.
 
   """
-  def __init__(self, connector=CONNECTOR):
+  def __init__(self, connector=None):
     """Resource mapper constructor.
 
     @param connector: a dictionary, mapping method name with URL path regexp
 
     """
     """Resource mapper constructor.
 
     @param connector: a dictionary, mapping method name with URL path regexp
 
     """
+    if connector is None:
+      connector = CONNECTOR
     self._connector = connector
 
   def getController(self, uri):
     self._connector = connector
 
   def getController(self, uri):
@@ -59,59 +70,50 @@ class Mapper:
             - args: a dictionary with additional parameters from URL
 
     """
             - args: a dictionary with additional parameters from URL
 
     """
-    if '?' in uri:
-      (path, query) = uri.split('?', 1)
+    if "?" in uri:
+      (path, query) = uri.split("?", 1)
       args = cgi.parse_qs(query)
     else:
       path = uri
       query = None
       args = {}
 
       args = cgi.parse_qs(query)
     else:
       path = uri
       query = None
       args = {}
 
-    result = None
+    # Try to find handler for request path
+    result = utils.FindMatch(self._connector, path)
 
 
-    for key, handler in self._connector.iteritems():
-      # Regex objects
-      if hasattr(key, "match"):
-        m = key.match(path)
-        if m:
-          result = (handler, list(m.groups()), args)
-          break
+    if result is None:
+      raise http.HttpNotFound()
 
 
-      # String objects
-      elif key == path:
-        result = (handler, [], args)
-        break
+    (handler, groups) = result
 
 
-    if result:
-      return result
-    else:
-      raise http.HttpNotFound()
+    return (handler, groups, args)
 
 
 class R_root(baserlib.R_Generic):
   """/ resource.
 
   """
 
 
 class R_root(baserlib.R_Generic):
   """/ resource.
 
   """
-  def GET(self):
+  _ROOT_PATTERN = re.compile("^R_([a-zA-Z0-9]+)$")
+
+  @classmethod
+  def GET(cls):
     """Show the list of mapped resources.
 
     @return: a dictionary with 'name' and 'uri' keys for each of them.
 
     """
     """Show the list of mapped resources.
 
     @return: a dictionary with 'name' and 'uri' keys for each of them.
 
     """
-    root_pattern = re.compile('^R_([a-zA-Z0-9]+)$')
-
     rootlist = []
     for handler in CONNECTOR.values():
     rootlist = []
     for handler in CONNECTOR.values():
-      m = root_pattern.match(handler.__name__)
+      m = cls._ROOT_PATTERN.match(handler.__name__)
       if m:
         name = m.group(1)
       if m:
         name = m.group(1)
-        if name != 'root':
+        if name != "root":
           rootlist.append(name)
 
     return baserlib.BuildUriList(rootlist, "/%s")
 
 
           rootlist.append(name)
 
     return baserlib.BuildUriList(rootlist, "/%s")
 
 
-def _getResources(id):
+def _getResources(id_):
   """Return a list of resources underneath given id.
 
   This is to generalize querying of version resources lists.
   """Return a list of resources underneath given id.
 
   This is to generalize querying of version resources lists.
@@ -119,7 +121,7 @@ def _getResources(id):
   @return: a list of resources names.
 
   """
   @return: a list of resources names.
 
   """
-  r_pattern = re.compile('^R_%s_([a-zA-Z0-9]+)$' % id)
+  r_pattern = re.compile("^R_%s_([a-zA-Z0-9]+)$" % id_)
 
   rlist = []
   for handler in CONNECTOR.values():
 
   rlist = []
   for handler in CONNECTOR.values():
@@ -132,10 +134,13 @@ def _getResources(id):
 
 
 class R_2(baserlib.R_Generic):
 
 
 class R_2(baserlib.R_Generic):
-  """ /2 resource, the root of the version 2 API.
+  """/2 resource.
+
+  This is the root of the version 2 API.
 
   """
 
   """
-  def GET(self):
+  @staticmethod
+  def GET():
     """Show the list of mapped resources.
 
     @return: a dictionary with 'name' and 'uri' keys for each of them.
     """Show the list of mapped resources.
 
     @return: a dictionary with 'name' and 'uri' keys for each of them.
@@ -144,32 +149,110 @@ class R_2(baserlib.R_Generic):
     return baserlib.BuildUriList(_getResources("2"), "/2/%s")
 
 
     return baserlib.BuildUriList(_getResources("2"), "/2/%s")
 
 
-CONNECTOR.update({
-  "/": R_root,
-
-  "/version": rlib2.R_version,
+def GetHandlers(node_name_pattern, instance_name_pattern,
+                group_name_pattern, job_id_pattern, disk_pattern,
+                query_res_pattern):
+  """Returns all supported resources and their handlers.
 
 
-  "/2": R_2,
-  "/2/jobs": rlib2.R_2_jobs,
-  "/2/nodes": rlib2.R_2_nodes,
-  re.compile(r'^/2/nodes/([\w\._-]+)$'): rlib2.R_2_nodes_name,
-  re.compile(r'^/2/nodes/([\w\._-]+)/tags$'): rlib2.R_2_nodes_name_tags,
-  re.compile(r'^/2/nodes/([\w\._-]+)/role$'): rlib2.R_2_nodes_name_role,
-  re.compile(r'^/2/nodes/([\w\._-]+)/evacuate$'):
+  """
+  # Important note: New resources should always be added under /2. During a
+  # discussion in July 2010 it was decided that having per-resource versions
+  # is more flexible and future-compatible than versioning the whole remote
+  # API.
+  return {
+    "/": R_root,
+
+    "/version": rlib2.R_version,
+
+    "/2": R_2,
+
+    "/2/nodes": rlib2.R_2_nodes,
+    re.compile(r"^/2/nodes/(%s)$" % node_name_pattern):
+      rlib2.R_2_nodes_name,
+    re.compile(r"^/2/nodes/(%s)/tags$" % node_name_pattern):
+      rlib2.R_2_nodes_name_tags,
+    re.compile(r"^/2/nodes/(%s)/role$" % node_name_pattern):
+      rlib2.R_2_nodes_name_role,
+    re.compile(r"^/2/nodes/(%s)/evacuate$" % node_name_pattern):
       rlib2.R_2_nodes_name_evacuate,
       rlib2.R_2_nodes_name_evacuate,
-  "/2/instances": rlib2.R_2_instances,
-  re.compile(r'^/2/instances/([\w\._-]+)$'): rlib2.R_2_instances_name,
-  re.compile(r'^/2/instances/([\w\._-]+)/tags$'): rlib2.R_2_instances_name_tags,
-  re.compile(r'^/2/instances/([\w\._-]+)/reboot$'):
+    re.compile(r"^/2/nodes/(%s)/migrate$" % node_name_pattern):
+      rlib2.R_2_nodes_name_migrate,
+    re.compile(r"^/2/nodes/(%s)/storage$" % node_name_pattern):
+      rlib2.R_2_nodes_name_storage,
+    re.compile(r"^/2/nodes/(%s)/storage/modify$" % node_name_pattern):
+      rlib2.R_2_nodes_name_storage_modify,
+    re.compile(r"^/2/nodes/(%s)/storage/repair$" % node_name_pattern):
+      rlib2.R_2_nodes_name_storage_repair,
+
+    "/2/instances": rlib2.R_2_instances,
+    re.compile(r"^/2/instances/(%s)$" % instance_name_pattern):
+      rlib2.R_2_instances_name,
+    re.compile(r"^/2/instances/(%s)/info$" % instance_name_pattern):
+      rlib2.R_2_instances_name_info,
+    re.compile(r"^/2/instances/(%s)/tags$" % instance_name_pattern):
+      rlib2.R_2_instances_name_tags,
+    re.compile(r"^/2/instances/(%s)/reboot$" % instance_name_pattern):
       rlib2.R_2_instances_name_reboot,
       rlib2.R_2_instances_name_reboot,
-  re.compile(r'^/2/instances/([\w\._-]+)/reinstall$'):
+    re.compile(r"^/2/instances/(%s)/reinstall$" % instance_name_pattern):
       rlib2.R_2_instances_name_reinstall,
       rlib2.R_2_instances_name_reinstall,
-  re.compile(r'^/2/instances/([\w\._-]+)/shutdown$'):
+    re.compile(r"^/2/instances/(%s)/replace-disks$" % instance_name_pattern):
+      rlib2.R_2_instances_name_replace_disks,
+    re.compile(r"^/2/instances/(%s)/shutdown$" % instance_name_pattern):
       rlib2.R_2_instances_name_shutdown,
       rlib2.R_2_instances_name_shutdown,
-  re.compile(r'^/2/instances/([\w\._-]+)/startup$'):
+    re.compile(r"^/2/instances/(%s)/startup$" % instance_name_pattern):
       rlib2.R_2_instances_name_startup,
       rlib2.R_2_instances_name_startup,
-  re.compile(r'/2/jobs/(%s)$' % constants.JOB_ID_TEMPLATE): rlib2.R_2_jobs_id,
-  "/2/tags": rlib2.R_2_tags,
-  "/2/info": rlib2.R_2_info,
-  "/2/os": rlib2.R_2_os,
-  })
+    re.compile(r"^/2/instances/(%s)/activate-disks$" % instance_name_pattern):
+      rlib2.R_2_instances_name_activate_disks,
+    re.compile(r"^/2/instances/(%s)/deactivate-disks$" % instance_name_pattern):
+      rlib2.R_2_instances_name_deactivate_disks,
+    re.compile(r"^/2/instances/(%s)/prepare-export$" % instance_name_pattern):
+      rlib2.R_2_instances_name_prepare_export,
+    re.compile(r"^/2/instances/(%s)/export$" % instance_name_pattern):
+      rlib2.R_2_instances_name_export,
+    re.compile(r"^/2/instances/(%s)/migrate$" % instance_name_pattern):
+      rlib2.R_2_instances_name_migrate,
+    re.compile(r"^/2/instances/(%s)/failover$" % instance_name_pattern):
+      rlib2.R_2_instances_name_failover,
+    re.compile(r"^/2/instances/(%s)/rename$" % instance_name_pattern):
+      rlib2.R_2_instances_name_rename,
+    re.compile(r"^/2/instances/(%s)/modify$" % instance_name_pattern):
+      rlib2.R_2_instances_name_modify,
+    re.compile(r"^/2/instances/(%s)/disk/(%s)/grow$" %
+               (instance_name_pattern, disk_pattern)):
+      rlib2.R_2_instances_name_disk_grow,
+    re.compile(r"^/2/instances/(%s)/console$" % instance_name_pattern):
+      rlib2.R_2_instances_name_console,
+
+    "/2/groups": rlib2.R_2_groups,
+    re.compile(r"^/2/groups/(%s)$" % group_name_pattern):
+      rlib2.R_2_groups_name,
+    re.compile(r"^/2/groups/(%s)/modify$" % group_name_pattern):
+      rlib2.R_2_groups_name_modify,
+    re.compile(r"^/2/groups/(%s)/rename$" % group_name_pattern):
+      rlib2.R_2_groups_name_rename,
+    re.compile(r"^/2/groups/(%s)/assign-nodes$" % group_name_pattern):
+      rlib2.R_2_groups_name_assign_nodes,
+    re.compile(r"^/2/groups/(%s)/tags$" % group_name_pattern):
+      rlib2.R_2_groups_name_tags,
+
+    "/2/jobs": rlib2.R_2_jobs,
+    re.compile(r"^/2/jobs/(%s)$" % job_id_pattern):
+      rlib2.R_2_jobs_id,
+    re.compile(r"^/2/jobs/(%s)/wait$" % job_id_pattern):
+      rlib2.R_2_jobs_id_wait,
+
+    "/2/tags": rlib2.R_2_tags,
+    "/2/info": rlib2.R_2_info,
+    "/2/os": rlib2.R_2_os,
+    "/2/redistribute-config": rlib2.R_2_redist_config,
+    "/2/features": rlib2.R_2_features,
+    "/2/modify": rlib2.R_2_cluster_modify,
+    re.compile(r"^/2/query/(%s)$" % query_res_pattern): rlib2.R_2_query,
+    re.compile(r"^/2/query/(%s)/fields$" % query_res_pattern):
+      rlib2.R_2_query_fields,
+    }
+
+
+CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN,
+                             constants.JOB_ID_TEMPLATE, _DISK_PATTERN,
+                             _NAME_PATTERN))