On Mon, May 30, 2011 at 5:14 PM, Michael Hanselmann <[email protected]> wrote:
> The change is not backwards compatible, see the updated NEWS file.
>
> Signed-off-by: Michael Hanselmann <[email protected]>
> ---
>  NEWS                                |    4 ++++
>  doc/rapi.rst                        |   25 ++++++++-----------------
>  lib/rapi/client.py                  |   33 +++++++++++++++++++++------------
>  lib/rapi/rlib2.py                   |   35 
> ++++++-----------------------------
>  test/ganeti.rapi.client_unittest.py |    6 ++++--
>  5 files changed, 43 insertions(+), 60 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 172277a..56322fb 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -9,6 +9,10 @@ Version 2.5.0 beta1
>  - The default of the ``/2/instances/[instance_name]/rename`` RAPI
>   resource's ``ip_check`` parameter changed from ``True`` to ``False``
>   to match the underlying LUXI interface
> +- The ``/2/nodes/[node_name]/evacuate`` RAPI resource was changed to use
> +  body parameters, see :doc:`RAPI documentation <rapi>`. Neither server
> +  nor RAPI client maintain backwards-compatibility as the underlying
> +  operation changed in an incompatible way.
>  - When creating file-based instances via RAPI, the ``file_driver``
>   parameter no longer defaults to ``loop`` and must be specified
>  - The deprecated "bridge" nic parameter is no longer supported. Use
> diff --git a/doc/rapi.rst b/doc/rapi.rst
> index fbc9970..f5aa245 100644
> --- a/doc/rapi.rst
> +++ b/doc/rapi.rst
> @@ -1161,32 +1161,23 @@ It supports the following commands: ``GET``.
>  ``/2/nodes/[node_name]/evacuate``
>  +++++++++++++++++++++++++++++++++
>
> -Evacuates all secondary instances off a node.
> +Evacuates instances off a node.
>
>  It supports the following commands: ``POST``.
>
>  ``POST``
>  ~~~~~~~~
>
> -To evacuate a node, either one of the ``iallocator`` or ``remote_node``
> -parameters must be passed::
> +Returns a job ID. The result of the job will contain the IDs of the
> +individual jobs submitted to evacuate the node.
>
> -    evacuate?iallocator=[iallocator]
> -    evacuate?remote_node=[nodeX.example.com]
> -
> -The result value will be a list, each element being a triple of the job
> -id (for this specific evacuation), the instance which is being evacuated
> -by this job, and the node to which it is being relocated. In case the
> -node is already empty, the result will be an empty list (without any
> -jobs being submitted).
> +Body parameters:
>
> -And additional parameter ``early_release`` signifies whether to try to
> -parallelize the evacuations, at the risk of increasing I/O contention
> -and increasing the chances of data loss, if the primary node of any of
> -the instances being evacuated is not fully healthy.
> +.. opcode_params:: OP_NODE_EVACUATE
> +   :exclude: nodes
>
> -If the dry-run parameter was specified, then the evacuation jobs were
> -not actually submitted, and the job IDs will be null.
> +Up to and including Ganeti 2.4 query arguments were used. Those are no
> +longer supported.
>
>
>  ``/2/nodes/[node_name]/migrate``
> diff --git a/lib/rapi/client.py b/lib/rapi/client.py
> index d2aa4ac..27dd89d 100644
> --- a/lib/rapi/client.py
> +++ b/lib/rapi/client.py
> @@ -1250,7 +1250,8 @@ class GanetiRapiClient(object): # pylint: 
> disable-msg=R0904
>                              None, None)
>
>   def EvacuateNode(self, node, iallocator=None, remote_node=None,
> -                   dry_run=False, early_release=False):
> +                   dry_run=False, early_release=None,
> +                   primary=None, secondary=None):
>     """Evacuates instances from a Ganeti node.
>
>     @type node: str
> @@ -1263,11 +1264,13 @@ class GanetiRapiClient(object): # pylint: 
> disable-msg=R0904
>     @param dry_run: whether to perform a dry run
>     @type early_release: bool
>     @param early_release: whether to enable parallelization
> +    @type primary: bool
> +    @param primary: Whether to evacuate primary instances
> +    @type secondary: bool
> +    @param secondary: Whether to evacuate secondary instances
>
> -    @rtype: list
> -    @return: list of (job ID, instance name, new secondary node); if
> -        dry_run was specified, then the actual move jobs were not
> -        submitted and the job IDs will be C{None}
> +    @rtype: string
> +    @return: job id
>
>     @raises GanetiApiError: if an iallocator and remote_node are both
>         specified
> @@ -1277,18 +1280,24 @@ class GanetiRapiClient(object): # pylint: 
> disable-msg=R0904
>       raise GanetiApiError("Only one of iallocator or remote_node can be 
> used")
>
>     query = []
> -    if iallocator:
> -      query.append(("iallocator", iallocator))
> -    if remote_node:
> -      query.append(("remote_node", remote_node))
>     if dry_run:
>       query.append(("dry-run", 1))
> -    if early_release:
> -      query.append(("early_release", 1))
> +
> +    body = {}
> +    if iallocator is not None:
> +      body["iallocator"] = iallocator
> +    if remote_node is not None:
> +      body["remote_node"] = remote_node
> +    if early_release is not None:
> +      body["early_release"] = early_release
> +    if primary is not None:
> +      body["primary"] = primary
> +    if secondary is not None:
> +      body["secondary"] = secondary
>
>     return self._SendRequest(HTTP_POST,
>                              ("/%s/nodes/%s/evacuate" %
> -                              (GANETI_RAPI_VERSION, node)), query, None)
> +                              (GANETI_RAPI_VERSION, node)), query, body)
>
>   def MigrateNode(self, node, mode=None, dry_run=False, iallocator=None,
>                   target_node=None):
> diff --git a/lib/rapi/rlib2.py b/lib/rapi/rlib2.py
> index d6bd9ce..b3c5a88 100644
> --- a/lib/rapi/rlib2.py
> +++ b/lib/rapi/rlib2.py
> @@ -414,38 +414,15 @@ class R_2_nodes_name_evacuate(baserlib.R_Generic):
>
>   """
>   def POST(self):
> -    """Evacuate all secondary instances off a node.
> +    """Evacuate all instances off a node.
>
>     """
> -    node_name = self.items[0]
> -    remote_node = self._checkStringVariable("remote_node", default=None)
> -    iallocator = self._checkStringVariable("iallocator", default=None)
> -    early_r = bool(self._checkIntVariable("early_release", default=0))
> -    dry_run = bool(self.dryRun())
> -
> -    cl = baserlib.GetClient()
> -
> -    op = opcodes.OpNodeEvacStrategy(nodes=[node_name],
> -                                    iallocator=iallocator,
> -                                    remote_node=remote_node)
> -
> -    job_id = baserlib.SubmitJob([op], cl)
> -    # we use custom feedback function, instead of print we log the status
> -    result = cli.PollJob(job_id, cl, feedback_fn=baserlib.FeedbackFn)
> +    op = baserlib.FillOpcode(opcodes.OpNodeEvacuate, self.request_body, {
> +      "nodes": [node_name],
> +      "dry_run": self.dryRun(),
> +      })
>
> -    jobs = []
> -    for iname, node in result[0]:
> -      if dry_run:
> -        jid = None
> -      else:
> -        op = opcodes.OpInstanceReplaceDisks(instance_name=iname,
> -                                            remote_node=node, disks=[],
> -                                            mode=constants.REPLACE_DISK_CHG,
> -                                            early_release=early_r)
> -        jid = baserlib.SubmitJob([op])
> -      jobs.append((jid, iname, node))
> -
> -    return jobs
> +    return baserlib.SubmitJob([op])
>
>
>  class R_2_nodes_name_migrate(baserlib.R_Generic):
> diff --git a/test/ganeti.rapi.client_unittest.py 
> b/test/ganeti.rapi.client_unittest.py
> index 23dacf8..844513e 100755
> --- a/test/ganeti.rapi.client_unittest.py
> +++ b/test/ganeti.rapi.client_unittest.py
> @@ -822,13 +822,15 @@ class GanetiRapiClientTests(testutils.GanetiTestCase):
>     self.assertEqual(9876, job_id)
>     self.assertHandler(rlib2.R_2_nodes_name_evacuate)
>     self.assertItems(["node-1"])
> -    self.assertQuery("remote_node", ["node-2"])
> +    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
> +                     { "remote_node": "node-2", })
>
>     self.rapi.AddResponse("8888")
>     job_id = self.client.EvacuateNode("node-3", iallocator="hail", 
> dry_run=True)
>     self.assertEqual(8888, job_id)
>     self.assertItems(["node-3"])
> -    self.assertQuery("iallocator", ["hail"])
> +    self.assertEqual(serializer.LoadJson(self.rapi.GetLastRequestData()),
> +                     { "iallocator": "hail", })
>     self.assertDryRun()
>
>     self.assertRaises(client.GanetiApiError,
> --
> 1.7.3.5

LGTM

>
>

Reply via email to