Commit d65f3490 authored by Hrvoje Ribicic's avatar Hrvoje Ribicic

Merge branch 'stable-2.8' into stable-2.9

* stable-2.8
  Add reason parameter to RAPI client functions
Signed-off-by: default avatarHrvoje Ribicic <riba@google.com>
Reviewed-by: default avatarKlaus Aehlig <aehlig@google.com>
parents 4efa6249 8ae4d0de
......@@ -219,6 +219,15 @@ def _AppendForceIf(container, condition):
return _AppendIf(container, condition, (_QPARAM_FORCE, 1))
def _AppendReason(container, reason):
"""Appends an element to the reason trail.
If the user provided a reason, it is added to the reason trail.
"""
return _AppendIf(container, reason, ("reason", reason))
def _SetItemIf(container, condition, item, value):
"""Sets an item if a condition evaluates to truth.
......@@ -577,68 +586,91 @@ class GanetiRapiClient(object): # pylint: disable=R0904
raise
def GetOperatingSystems(self):
def GetOperatingSystems(self, reason=None):
"""Gets the Operating Systems running in the Ganeti cluster.
@rtype: list of str
@return: operating systems
@type reason: string
@param reason: the reason for executing this operation
"""
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_GET, "/%s/os" % GANETI_RAPI_VERSION,
None, None)
query, None)
def GetInfo(self):
def GetInfo(self, reason=None):
"""Gets info about the cluster.
@type reason: string
@param reason: the reason for executing this operation
@rtype: dict
@return: information about the cluster
"""
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_GET, "/%s/info" % GANETI_RAPI_VERSION,
None, None)
query, None)
def RedistributeConfig(self):
def RedistributeConfig(self, reason=None):
"""Tells the cluster to redistribute its configuration files.
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
"/%s/redistribute-config" % GANETI_RAPI_VERSION,
None, None)
query, None)
def ModifyCluster(self, **kwargs):
def ModifyCluster(self, reason=None, **kwargs):
"""Modifies cluster parameters.
More details for parameters can be found in the RAPI documentation.
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
query = []
_AppendReason(query, reason)
body = kwargs
return self._SendRequest(HTTP_PUT,
"/%s/modify" % GANETI_RAPI_VERSION, None, body)
"/%s/modify" % GANETI_RAPI_VERSION, query, body)
def GetClusterTags(self):
def GetClusterTags(self, reason=None):
"""Gets the cluster tags.
@type reason: string
@param reason: the reason for executing this operation
@rtype: list of str
@return: cluster tags
"""
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_GET, "/%s/tags" % GANETI_RAPI_VERSION,
None, None)
query, None)
def AddClusterTags(self, tags, dry_run=False):
def AddClusterTags(self, tags, dry_run=False, reason=None):
"""Adds tags to the cluster.
@type tags: list of str
@param tags: tags to add to the cluster
@type dry_run: bool
@param dry_run: whether to perform a dry run
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -646,32 +678,38 @@ class GanetiRapiClient(object): # pylint: disable=R0904
"""
query = [("tag", t) for t in tags]
_AppendDryRunIf(query, dry_run)
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT, "/%s/tags" % GANETI_RAPI_VERSION,
query, None)
def DeleteClusterTags(self, tags, dry_run=False):
def DeleteClusterTags(self, tags, dry_run=False, reason=None):
"""Deletes tags from the cluster.
@type tags: list of str
@param tags: tags to delete
@type dry_run: bool
@param dry_run: whether to perform a dry run
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
query = [("tag", t) for t in tags]
_AppendDryRunIf(query, dry_run)
_AppendReason(query, reason)
return self._SendRequest(HTTP_DELETE, "/%s/tags" % GANETI_RAPI_VERSION,
query, None)
def GetInstances(self, bulk=False):
def GetInstances(self, bulk=False, reason=None):
"""Gets information about instances on the cluster.
@type bulk: bool
@param bulk: whether to return all information about all instances
@type reason: string
@param reason: the reason for executing this operation
@rtype: list of dict or list of str
@return: if bulk is True, info about the instances, else a list of instances
......@@ -679,6 +717,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
"""
query = []
_AppendIf(query, bulk, ("bulk", 1))
_AppendReason(query, reason)
instances = self._SendRequest(HTTP_GET,
"/%s/instances" % GANETI_RAPI_VERSION,
......@@ -688,33 +727,40 @@ class GanetiRapiClient(object): # pylint: disable=R0904
else:
return [i["id"] for i in instances]
def GetInstance(self, instance):
def GetInstance(self, instance, reason=None):
"""Gets information about an instance.
@type instance: str
@param instance: instance whose info to return
@type reason: string
@param reason: the reason for executing this operation
@rtype: dict
@return: info about the instance
"""
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_GET,
("/%s/instances/%s" %
(GANETI_RAPI_VERSION, instance)), None, None)
(GANETI_RAPI_VERSION, instance)), query, None)
def GetInstanceInfo(self, instance, static=None):
def GetInstanceInfo(self, instance, static=None, reason=None):
"""Gets information about an instance.
@type instance: string
@param instance: Instance name
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: Job ID
"""
query = []
if static is not None:
query = [("static", static)]
else:
query = None
query.append(("static", static))
_AppendReason(query, reason)
return self._SendRequest(HTTP_GET,
("/%s/instances/%s/info" %
......@@ -772,7 +818,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
return alloc
def InstancesMultiAlloc(self, instances, **kwargs):
def InstancesMultiAlloc(self, instances, reason=None, **kwargs):
"""Tries to allocate multiple instances.
More details for parameters can be found in the RAPI documentation.
......@@ -787,13 +833,14 @@ class GanetiRapiClient(object): # pylint: disable=R0904
self._UpdateWithKwargs(body, **kwargs)
_AppendDryRunIf(query, kwargs.get("dry_run"))
_AppendReason(query, reason)
return self._SendRequest(HTTP_POST,
"/%s/instances-multi-alloc" % GANETI_RAPI_VERSION,
query, body)
def CreateInstance(self, mode, name, disk_template, disks, nics,
**kwargs):
reason=None, **kwargs):
"""Creates a new instance.
More details for parameters can be found in the RAPI documentation.
......@@ -811,6 +858,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param nics: List of NIC definitions
@type dry_run: bool
@keyword dry_run: whether to perform a dry run
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -819,6 +868,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
query = []
_AppendDryRunIf(query, kwargs.get("dry_run"))
_AppendReason(query, reason)
if _INST_CREATE_REQV1 in self.GetFeatures():
body = self.InstanceAllocation(mode, name, disk_template, disks, nics,
......@@ -831,11 +881,13 @@ class GanetiRapiClient(object): # pylint: disable=R0904
return self._SendRequest(HTTP_POST, "/%s/instances" % GANETI_RAPI_VERSION,
query, body)
def DeleteInstance(self, instance, dry_run=False):
def DeleteInstance(self, instance, dry_run=False, reason=None):
"""Deletes an instance.
@type instance: str
@param instance: the instance to delete
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -843,60 +895,73 @@ class GanetiRapiClient(object): # pylint: disable=R0904
"""
query = []
_AppendDryRunIf(query, dry_run)
_AppendReason(query, reason)
return self._SendRequest(HTTP_DELETE,
("/%s/instances/%s" %
(GANETI_RAPI_VERSION, instance)), query, None)
def ModifyInstance(self, instance, **kwargs):
def ModifyInstance(self, instance, reason=None, **kwargs):
"""Modifies an instance.
More details for parameters can be found in the RAPI documentation.
@type instance: string
@param instance: Instance name
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
body = kwargs
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/modify" %
(GANETI_RAPI_VERSION, instance)), None, body)
(GANETI_RAPI_VERSION, instance)), query, body)
def ActivateInstanceDisks(self, instance, ignore_size=None):
def ActivateInstanceDisks(self, instance, ignore_size=None, reason=None):
"""Activates an instance's disks.
@type instance: string
@param instance: Instance name
@type ignore_size: bool
@param ignore_size: Whether to ignore recorded size
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
query = []
_AppendIf(query, ignore_size, ("ignore_size", 1))
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/activate-disks" %
(GANETI_RAPI_VERSION, instance)), query, None)
def DeactivateInstanceDisks(self, instance):
def DeactivateInstanceDisks(self, instance, reason=None):
"""Deactivates an instance's disks.
@type instance: string
@param instance: Instance name
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/deactivate-disks" %
(GANETI_RAPI_VERSION, instance)), None, None)
(GANETI_RAPI_VERSION, instance)), query, None)
def RecreateInstanceDisks(self, instance, disks=None, nodes=None):
def RecreateInstanceDisks(self, instance, disks=None, nodes=None,
reason=None):
"""Recreate an instance's disks.
@type instance: string
......@@ -905,6 +970,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param disks: List of disk indexes
@type nodes: list of string
@param nodes: New instance nodes, if relocation is desired
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -913,11 +980,15 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_SetItemIf(body, disks is not None, "disks", disks)
_SetItemIf(body, nodes is not None, "nodes", nodes)
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_POST,
("/%s/instances/%s/recreate-disks" %
(GANETI_RAPI_VERSION, instance)), None, body)
(GANETI_RAPI_VERSION, instance)), query, body)
def GrowInstanceDisk(self, instance, disk, amount, wait_for_sync=None):
def GrowInstanceDisk(self, instance, disk, amount, wait_for_sync=None,
reason=None):
"""Grows a disk of an instance.
More details for parameters can be found in the RAPI documentation.
......@@ -930,6 +1001,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param amount: Grow disk by this amount (MiB)
@type wait_for_sync: bool
@param wait_for_sync: Wait for disk to synchronize
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -940,26 +1013,33 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_SetItemIf(body, wait_for_sync is not None, "wait_for_sync", wait_for_sync)
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_POST,
("/%s/instances/%s/disk/%s/grow" %
(GANETI_RAPI_VERSION, instance, disk)),
None, body)
query, body)
def GetInstanceTags(self, instance):
def GetInstanceTags(self, instance, reason=None):
"""Gets tags for an instance.
@type instance: str
@param instance: instance whose tags to return
@type reason: string
@param reason: the reason for executing this operation
@rtype: list of str
@return: tags for the instance
"""
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_GET,
("/%s/instances/%s/tags" %
(GANETI_RAPI_VERSION, instance)), None, None)
(GANETI_RAPI_VERSION, instance)), query, None)
def AddInstanceTags(self, instance, tags, dry_run=False):
def AddInstanceTags(self, instance, tags, dry_run=False, reason=None):
"""Adds tags to an instance.
@type instance: str
......@@ -968,6 +1048,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param tags: tags to add to the instance
@type dry_run: bool
@param dry_run: whether to perform a dry run
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -975,12 +1057,13 @@ class GanetiRapiClient(object): # pylint: disable=R0904
"""
query = [("tag", t) for t in tags]
_AppendDryRunIf(query, dry_run)
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/tags" %
(GANETI_RAPI_VERSION, instance)), query, None)
def DeleteInstanceTags(self, instance, tags, dry_run=False):
def DeleteInstanceTags(self, instance, tags, dry_run=False, reason=None):
"""Deletes tags from an instance.
@type instance: str
......@@ -989,12 +1072,15 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param tags: tags to delete
@type dry_run: bool
@param dry_run: whether to perform a dry run
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
query = [("tag", t) for t in tags]
_AppendDryRunIf(query, dry_run)
_AppendReason(query, reason)
return self._SendRequest(HTTP_DELETE,
("/%s/instances/%s/tags" %
......@@ -1024,7 +1110,7 @@ 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))
_AppendReason(query, reason)
return self._SendRequest(HTTP_POST,
("/%s/instances/%s/reboot" %
......@@ -1051,7 +1137,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_AppendDryRunIf(query, dry_run)
_AppendIf(query, no_remember, ("no_remember", 1))
_AppendIf(query, reason, ("reason", reason))
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/shutdown" %
......@@ -1076,14 +1162,14 @@ class GanetiRapiClient(object): # pylint: disable=R0904
query = []
_AppendDryRunIf(query, dry_run)
_AppendIf(query, no_remember, ("no_remember", 1))
_AppendIf(query, reason, ("reason", reason))
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/startup" %
(GANETI_RAPI_VERSION, instance)), query, None)
def ReinstallInstance(self, instance, os=None, no_startup=False,
osparams=None):
osparams=None, reason=None):
"""Reinstalls an instance.
@type instance: str
......@@ -1093,10 +1179,15 @@ class GanetiRapiClient(object): # pylint: disable=R0904
current operating system will be installed again
@type no_startup: bool
@param no_startup: Whether to start the instance automatically
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
"""
query = []
_AppendReason(query, reason)
if _INST_REINSTALL_REQV1 in self.GetFeatures():
body = {
"start": not no_startup,
......@@ -1105,7 +1196,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_SetItemIf(body, osparams is not None, "osparams", osparams)
return self._SendRequest(HTTP_POST,
("/%s/instances/%s/reinstall" %
(GANETI_RAPI_VERSION, instance)), None, body)
(GANETI_RAPI_VERSION, instance)), query, body)
# Use old request format
if osparams:
......@@ -1121,7 +1212,7 @@ class GanetiRapiClient(object): # pylint: disable=R0904
(GANETI_RAPI_VERSION, instance)), query, None)
def ReplaceInstanceDisks(self, instance, disks=None, mode=REPLACE_DISK_AUTO,
remote_node=None, iallocator=None):
remote_node=None, iallocator=None, reason=None):
"""Replaces disks on an instance.
@type instance: str
......@@ -1136,6 +1227,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@type iallocator: str or None
@param iallocator: instance allocator plugin to use (for use with
replace_auto mode)
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -1153,36 +1246,42 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_AppendIf(query, remote_node is not None, ("remote_node", remote_node))
_AppendIf(query, iallocator is not None, ("iallocator", iallocator))
_AppendReason(query, reason)
return self._SendRequest(HTTP_POST,
("/%s/instances/%s/replace-disks" %
(GANETI_RAPI_VERSION, instance)), query, None)
def PrepareExport(self, instance, mode):
def PrepareExport(self, instance, mode, reason=None):
"""Prepares an instance for an export.
@type instance: string
@param instance: Instance name
@type mode: string
@param mode: Export mode
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: Job ID
"""
query = [("mode", mode)]
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/prepare-export" %
(GANETI_RAPI_VERSION, instance)), query, None)
def ExportInstance(self, instance, mode, destination, shutdown=None,
remove_instance=None,
x509_key_name=None, destination_x509_ca=None):
x509_key_name=None, destination_x509_ca=None, reason=None):
"""Exports an instance.
@type instance: string
@param instance: Instance name
@type mode: string
@param mode: Export mode
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: Job ID
......@@ -1199,12 +1298,15 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_SetItemIf(body, destination_x509_ca is not None,
"destination_x509_ca", destination_x509_ca)
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/export" %
(GANETI_RAPI_VERSION, instance)), None, body)
(GANETI_RAPI_VERSION, instance)), query, body)
def MigrateInstance(self, instance, mode=None, cleanup=None,
target_node=None):
target_node=None, reason=None):
"""Migrates an instance.
@type instance: string
......@@ -1215,6 +1317,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param cleanup: Whether to clean up a previously failed migration
@type target_node: string
@param target_node: Target Node for externally mirrored instances
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -1224,12 +1328,15 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_SetItemIf(body, cleanup is not None, "cleanup", cleanup)
_SetItemIf(body, target_node is not None, "target_node", target_node)
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/migrate" %
(GANETI_RAPI_VERSION, instance)), None, body)
(GANETI_RAPI_VERSION, instance)), query, body)
def FailoverInstance(self, instance, iallocator=None,
ignore_consistency=None, target_node=None):
ignore_consistency=None, target_node=None, reason=None):
"""Does a failover of an instance.
@type instance: string
......@@ -1241,6 +1348,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param ignore_consistency: Whether to ignore disk consistency
@type target_node: string
@param target_node: Target node for shared-storage instances
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -1251,11 +1360,15 @@ class GanetiRapiClient(object): # pylint: disable=R0904
"ignore_consistency", ignore_consistency)
_SetItemIf(body, target_node is not None, "target_node", target_node)
query = []
_AppendReason(query, reason)
return self._SendRequest(HTTP_PUT,
("/%s/instances/%s/failover" %
(GANETI_RAPI_VERSION, instance)), None, body)
(GANETI_RAPI_VERSION, instance)), query, body)
def RenameInstance(self, instance, new_name, ip_check=None, name_check=None):
def RenameInstance(self, instance, new_name, ip_check=None, name_check=None,
reason=None):
"""Changes the name of an instance.
@type instance: string
......@@ -1266,6 +1379,8 @@ class GanetiRapiClient(object): # pylint: disable=R0904
@param ip_check: Whether to ensure instance's IP address is inactive
@type name_check: bool
@param name_check: Whether to ensure instance's name is resolvable
@type reason: string
@param reason: the reason for executing this operation
@rtype: string
@return: job id
......@@ -1277,22 +1392,29 @@ class GanetiRapiClient(object): # pylint: disable=R0904
_SetItemIf(body, ip_check is not None, "ip_check", ip_check)
_SetItemIf(body, name_check is not None, "name_check", name_check)
query = []
_AppendReason(query, reason)