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 > >
