Setup constant generation infrastructure
[ganeti-local] / lib / rapi / client.py
index 9fd81f1..35b1191 100644 (file)
@@ -114,6 +114,50 @@ _INST_REINSTALL_REQV1 = INST_REINSTALL_REQV1
 _NODE_MIGRATE_REQV1 = NODE_MIGRATE_REQV1
 _NODE_EVAC_RES1 = NODE_EVAC_RES1
 
+#: Resolver errors
+ECODE_RESOLVER = "resolver_error"
+
+#: Not enough resources (iallocator failure, disk space, memory, etc.)
+ECODE_NORES = "insufficient_resources"
+
+#: Temporarily out of resources; operation can be tried again
+ECODE_TEMP_NORES = "temp_insufficient_resources"
+
+#: Wrong arguments (at syntax level)
+ECODE_INVAL = "wrong_input"
+
+#: Wrong entity state
+ECODE_STATE = "wrong_state"
+
+#: Entity not found
+ECODE_NOENT = "unknown_entity"
+
+#: Entity already exists
+ECODE_EXISTS = "already_exists"
+
+#: Resource not unique (e.g. MAC or IP duplication)
+ECODE_NOTUNIQUE = "resource_not_unique"
+
+#: Internal cluster error
+ECODE_FAULT = "internal_error"
+
+#: Environment error (e.g. node disk error)
+ECODE_ENVIRON = "environment_error"
+
+#: List of all failure types
+ECODE_ALL = frozenset([
+  ECODE_RESOLVER,
+  ECODE_NORES,
+  ECODE_TEMP_NORES,
+  ECODE_INVAL,
+  ECODE_STATE,
+  ECODE_NOENT,
+  ECODE_EXISTS,
+  ECODE_NOTUNIQUE,
+  ECODE_FAULT,
+  ECODE_ENVIRON,
+  ])
+
 # Older pycURL versions don't have all error constants
 try:
   _CURLE_SSL_CACERT = pycurl.E_SSL_CACERT
@@ -957,11 +1001,11 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                               (GANETI_RAPI_VERSION, instance)), query, None)
 
   def RebootInstance(self, instance, reboot_type=None, ignore_secondaries=None,
-                     dry_run=False):
+                     dry_run=False, reason=None):
     """Reboots an instance.
 
     @type instance: str
-    @param instance: instance to rebot
+    @param instance: instance to reboot
     @type reboot_type: str
     @param reboot_type: one of: hard, soft, full
     @type ignore_secondaries: bool
@@ -969,6 +1013,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
         while re-assembling disks (in hard-reboot mode only)
     @type dry_run: bool
     @param dry_run: whether to perform a dry run
+    @type reason: string
+    @param reason: the reason for the reboot
     @rtype: string
     @return: job id
 
@@ -978,13 +1024,14 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     _AppendIf(query, reboot_type, ("type", reboot_type))
     _AppendIf(query, ignore_secondaries is not None,
               ("ignore_secondaries", ignore_secondaries))
+    _AppendIf(query, reason, ("reason", reason))
 
     return self._SendRequest(HTTP_POST,
                              ("/%s/instances/%s/reboot" %
                               (GANETI_RAPI_VERSION, instance)), query, None)
 
   def ShutdownInstance(self, instance, dry_run=False, no_remember=False,
-                       **kwargs):
+                       reason=None, **kwargs):
     """Shuts down an instance.
 
     @type instance: str
@@ -993,6 +1040,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     @param dry_run: whether to perform a dry run
     @type no_remember: bool
     @param no_remember: if true, will not record the state change
+    @type reason: string
+    @param reason: the reason for the shutdown
     @rtype: string
     @return: job id
 
@@ -1001,13 +1050,15 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     body = kwargs
 
     _AppendDryRunIf(query, dry_run)
-    _AppendIf(query, no_remember, ("no-remember", 1))
+    _AppendIf(query, no_remember, ("no_remember", 1))
+    _AppendIf(query, reason, ("reason", reason))
 
     return self._SendRequest(HTTP_PUT,
                              ("/%s/instances/%s/shutdown" %
                               (GANETI_RAPI_VERSION, instance)), query, body)
 
-  def StartupInstance(self, instance, dry_run=False, no_remember=False):
+  def StartupInstance(self, instance, dry_run=False, no_remember=False,
+                      reason=None):
     """Starts up an instance.
 
     @type instance: str
@@ -1016,13 +1067,16 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     @param dry_run: whether to perform a dry run
     @type no_remember: bool
     @param no_remember: if true, will not record the state change
+    @type reason: string
+    @param reason: the reason for the startup
     @rtype: string
     @return: job id
 
     """
     query = []
     _AppendDryRunIf(query, dry_run)
-    _AppendIf(query, no_remember, ("no-remember", 1))
+    _AppendIf(query, no_remember, ("no_remember", 1))
+    _AppendIf(query, reason, ("reason", reason))
 
     return self._SendRequest(HTTP_PUT,
                              ("/%s/instances/%s/startup" %
@@ -1149,7 +1203,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                              ("/%s/instances/%s/export" %
                               (GANETI_RAPI_VERSION, instance)), None, body)
 
-  def MigrateInstance(self, instance, mode=None, cleanup=None):
+  def MigrateInstance(self, instance, mode=None, cleanup=None,
+                      target_node=None):
     """Migrates an instance.
 
     @type instance: string
@@ -1158,6 +1213,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     @param mode: Migration mode
     @type cleanup: bool
     @param cleanup: Whether to clean up a previously failed migration
+    @type target_node: string
+    @param target_node: Target Node for externally mirrored instances
     @rtype: string
     @return: job id
 
@@ -1165,6 +1222,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     body = {}
     _SetItemIf(body, mode is not None, "mode", mode)
     _SetItemIf(body, cleanup is not None, "cleanup", cleanup)
+    _SetItemIf(body, target_node is not None, "target_node", target_node)
 
     return self._SendRequest(HTTP_PUT,
                              ("/%s/instances/%s/migrate" %
@@ -1236,17 +1294,28 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                              ("/%s/instances/%s/console" %
                               (GANETI_RAPI_VERSION, instance)), None, None)
 
-  def GetJobs(self):
+  def GetJobs(self, bulk=False):
     """Gets all jobs for the cluster.
 
+    @type bulk: bool
+    @param bulk: Whether to return detailed information about jobs.
     @rtype: list of int
-    @return: job ids for the cluster
+    @return: List of job ids for the cluster or list of dicts with detailed
+             information about the jobs if bulk parameter was true.
 
     """
-    return [int(j["id"])
-            for j in self._SendRequest(HTTP_GET,
-                                       "/%s/jobs" % GANETI_RAPI_VERSION,
-                                       None, None)]
+    query = []
+    _AppendIf(query, bulk, ("bulk", 1))
+
+    if bulk:
+      return self._SendRequest(HTTP_GET,
+                               "/%s/jobs" % GANETI_RAPI_VERSION,
+                               query, None)
+    else:
+      return [int(j["id"])
+              for j in self._SendRequest(HTTP_GET,
+                                         "/%s/jobs" % GANETI_RAPI_VERSION,
+                                         None, None)]
 
   def GetJobStatus(self, job_id):
     """Gets the status of a job.
@@ -1712,8 +1781,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
   def GetNetwork(self, network):
     """Gets information about a network.
 
-    @type group: str
-    @param group: name of the network whose info to return
+    @type network: str
+    @param network: name of the network whose info to return
 
     @rtype: dict
     @return: info about the network
@@ -1724,12 +1793,12 @@ class GanetiRapiClient(object): # pylint: disable=R0904
                              None, None)
 
   def CreateNetwork(self, network_name, network, gateway=None, network6=None,
-                    gateway6=None, mac_prefix=None, network_type=None,
+                    gateway6=None, mac_prefix=None,
                     add_reserved_ips=None, tags=None, dry_run=False):
     """Creates a new network.
 
-    @type name: str
-    @param name: the name of network to create
+    @type network_name: str
+    @param network_name: the name of network to create
     @type dry_run: bool
     @param dry_run: whether to peform a dry run
 
@@ -1741,10 +1810,10 @@ class GanetiRapiClient(object): # pylint: disable=R0904
     _AppendDryRunIf(query, dry_run)
 
     if add_reserved_ips:
-      add_reserved_ips = add_reserved_ips.split(',')
+      add_reserved_ips = add_reserved_ips.split(",")
 
     if tags:
-      tags = tags.split(',')
+      tags = tags.split(",")
 
     body = {
       "network_name": network_name,
@@ -1753,7 +1822,6 @@ class GanetiRapiClient(object): # pylint: disable=R0904
       "gateway6": gateway6,
       "network6": network6,
       "mac_prefix": mac_prefix,
-      "network_type": network_type,
       "add_reserved_ips": add_reserved_ips,
       "tags": tags,
       }
@@ -1811,8 +1879,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
   def DeleteNetwork(self, network, dry_run=False):
     """Deletes a network.
 
-    @type group: str
-    @param group: the network to delete
+    @type network: str
+    @param network: the network to delete
     @type dry_run: bool
     @param dry_run: whether to peform a dry run