diff --git a/lib/rapi/client.py b/lib/rapi/client.py index 72e3a51b8a7e017184c0b7a58cc9d3cd813e5096..61a6e71840e5bd241453aa2592e4dcbb18adbb60 100644 --- a/lib/rapi/client.py +++ b/lib/rapi/client.py @@ -351,6 +351,34 @@ class GanetiRapiClient(object): "User-Agent": self.USER_AGENT, } + @staticmethod + def _EncodeQuery(query): + """Encode query values for RAPI URL. + + @type query: list of two-tuples + @param query: Query arguments + @rtype: list + @return: Query list with encoded values + + """ + result = [] + + for name, value in query: + if value is None: + result.append((name, "")) + + elif isinstance(value, bool): + # Boolean values must be encoded as 0 or 1 + result.append((name, int(value))) + + elif isinstance(value, (list, tuple, dict)): + raise ValueError("Invalid query data type %r" % type(value).__name__) + + else: + result.append((name, value)) + + return result + def _SendRequest(self, method, path, query, content): """Sends an HTTP request. @@ -384,7 +412,7 @@ class GanetiRapiClient(object): url = [self._base_url, path] if query: url.append("?") - url.append(urllib.urlencode(query)) + url.append(urllib.urlencode(self._EncodeQuery(query))) req = _RapiRequest(method, "".join(url), self._headers, encoded_content) diff --git a/test/ganeti.rapi.client_unittest.py b/test/ganeti.rapi.client_unittest.py index 8bf9f463b6003d847db8db529474c5ecfcb55702..def0548ce882de936b0314f081e6b014f3d54dc6 100755 --- a/test/ganeti.rapi.client_unittest.py +++ b/test/ganeti.rapi.client_unittest.py @@ -151,6 +151,30 @@ class GanetiRapiClientTests(testutils.GanetiTestCase): def assertDryRun(self): self.assertTrue(self.rapi.GetLastHandler().dryRun()) + def testEncodeQuery(self): + query = [ + ("a", None), + ("b", 1), + ("c", 2), + ("d", "Foo"), + ("e", True), + ] + + expected = [ + ("a", ""), + ("b", 1), + ("c", 2), + ("d", "Foo"), + ("e", 1), + ] + + self.assertEqualValues(self.client._EncodeQuery(query), + expected) + + # invalid types + for i in [[1, 2, 3], {"moo": "boo"}, (1, 2, 3)]: + self.assertRaises(ValueError, self.client._EncodeQuery, [("x", i)]) + def testHttpError(self): self.rapi.AddResponse(None, code=404) try: @@ -255,7 +279,7 @@ class GanetiRapiClientTests(testutils.GanetiTestCase): self.assertItems(["i-bar"]) self.assertDryRun() self.assertQuery("type", ["hard"]) - self.assertQuery("ignore_secondaries", ["True"]) + self.assertQuery("ignore_secondaries", ["1"]) def testShutdownInstance(self): self.rapi.AddResponse("1487") @@ -403,7 +427,7 @@ class GanetiRapiClientTests(testutils.GanetiTestCase): self.client.SetNodeRole("node-foo", "master-candidate", force=True)) self.assertHandler(rlib2.R_2_nodes_name_role) self.assertItems(["node-foo"]) - self.assertQuery("force", ["True"]) + self.assertQuery("force", ["1"]) self.assertEqual("\"master-candidate\"", self.http.last_request.data) self.assertRaises(client.InvalidNodeRole,