Further pylint disables, mostly for Unused args
[ganeti-local] / lib / rapi / baserlib.py
index 0138e64..020d7bc 100644 (file)
 
 """
 
-import ganeti.cli
-import ganeti.opcodes
+# pylint: disable-msg=C0103
+
+# C0103: Invalid name, since the R_* names are not conforming
+
+import logging
 
 from ganeti import luxi
 from ganeti import rapi
 from ganeti import http
+from ganeti import ssconf
+from ganeti import constants
+from ganeti import opcodes
+from ganeti import errors
 
 
 def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
@@ -77,31 +84,43 @@ def MapFields(names, data):
   return dict(zip(names, data))
 
 
-def _Tags_GET(kind, name=""):
+def _Tags_GET(kind, name):
   """Helper function to retrieve tags.
 
   """
-  op = ganeti.opcodes.OpGetTags(kind=kind, name=name)
-  tags = ganeti.cli.SubmitOpCode(op)
+  if kind == constants.TAG_INSTANCE or kind == constants.TAG_NODE:
+    if not name:
+      raise http.HttpBadRequest("Missing name on tag request")
+    cl = GetClient()
+    if kind == constants.TAG_INSTANCE:
+      fn = cl.QueryInstances
+    else:
+      fn = cl.QueryNodes
+    result = fn(names=[name], fields=["tags"], use_locking=False)
+    if not result or not result[0]:
+      raise http.HttpBadGateway("Invalid response from tag query")
+    tags = result[0][0]
+  elif kind == constants.TAG_CLUSTER:
+    ssc = ssconf.SimpleStore()
+    tags = ssc.GetClusterTags()
+
   return list(tags)
 
 
-def _Tags_PUT(kind, tags, name=""):
+def _Tags_PUT(kind, tags, name, dry_run):
   """Helper function to set tags.
 
   """
-  cl = luxi.Client()
-  return cl.SubmitJob([ganeti.opcodes.OpAddTags(kind=kind, name=name,
-                                                tags=tags)])
+  return SubmitJob([opcodes.OpAddTags(kind=kind, name=name,
+                                      tags=tags, dry_run=dry_run)])
 
 
-def _Tags_DELETE(kind, tags, name=""):
+def _Tags_DELETE(kind, tags, name, dry_run):
   """Helper function to delete tags.
 
   """
-  cl = luxi.Client()
-  return cl.SubmitJob([ganeti.opcodes.OpDelTags(kind=kind, name=name,
-                                                tags=tags)])
+  return SubmitJob([opcodes.OpDelTags(kind=kind, name=name,
+                                      tags=tags, dry_run=dry_run)])
 
 
 def MapBulkFields(itemslist, fields):
@@ -147,6 +166,53 @@ def MakeParamsDict(opts, params):
   return result
 
 
+def SubmitJob(op, cl=None):
+  """Generic wrapper for submit job, for better http compatibility.
+
+  @type op: list
+  @param op: the list of opcodes for the job
+  @type cl: None or luxi.Client
+  @param cl: optional luxi client to use
+  @rtype: string
+  @return: the job ID
+
+  """
+  try:
+    if cl is None:
+      cl = GetClient()
+    return cl.SubmitJob(op)
+  except errors.JobQueueFull:
+    raise http.HttpServiceUnavailable("Job queue is full, needs archiving")
+  except errors.JobQueueDrainError:
+    raise http.HttpServiceUnavailable("Job queue is drained, cannot submit")
+  except luxi.NoMasterError, err:
+    raise http.HttpBadGateway("Master seems to unreachable: %s" % str(err))
+  except luxi.TimeoutError, err:
+    raise http.HttpGatewayTimeout("Timeout while talking to the master"
+                                  " daemon. Error: %s" % str(err))
+
+def GetClient():
+  """Geric wrapper for luxi.Client(), for better http compatiblity.
+
+  """
+  try:
+    return luxi.Client()
+  except luxi.NoMasterError, err:
+    raise http.HttpBadGateway("Master seems to unreachable: %s" % str(err))
+
+
+def FeedbackFn(ts, log_type, log_msg): # pylint: disable-msg=W0613
+  """Feedback logging function for http case.
+
+  We don't have a stdout for printing log messages, so log them to the
+  http log at least.
+
+  @param ts: the timestamp (unused)
+
+  """
+  logging.info("%s: %s", log_type, log_msg)
+
+
 class R_Generic(object):
   """Generic class for resources.
 
@@ -175,23 +241,35 @@ class R_Generic(object):
     """
     return self.sn
 
-  def _checkIntVariable(self, name):
+  def _checkIntVariable(self, name, default=0):
     """Return the parsed value of an int argument.
 
     """
-    val = self.queryargs.get(name, 0)
+    val = self.queryargs.get(name, default)
     if isinstance(val, list):
       if val:
         val = val[0]
       else:
-        val = 0
+        val = default
     try:
       val = int(val)
-    except (ValueError, TypeError), err:
+    except (ValueError, TypeError):
       raise http.HttpBadRequest("Invalid value for the"
                                 " '%s' parameter" % (name,))
     return val
 
+  def _checkStringVariable(self, name, default=None):
+    """Return the parsed value of an int argument.
+
+    """
+    val = self.queryargs.get(name, default)
+    if isinstance(val, list):
+      if val:
+        val = val[0]
+      else:
+        val = default
+    return val
+
   def getBodyParameter(self, name, *args):
     """Check and return the value for a given parameter.
 
@@ -220,3 +298,15 @@ class R_Generic(object):
 
     """
     return self._checkIntVariable('bulk')
+
+  def useForce(self):
+    """Check if the request specifies a forced operation.
+
+    """
+    return self._checkIntVariable('force')
+
+  def dryRun(self):
+    """Check if the request specifies dry-run mode.
+
+    """
+    return self._checkIntVariable('dry-run')