It supports the ``dry-run`` argument.
+``/2/query/[resource]``
++++++++++++++++++++++++
+
+Requests resource information. Available fields can be found in man
+pages and using ``/2/query/[resource]/fields``. The resource is one of
+:pyeval:`utils.CommaJoin(constants.QR_VIA_RAPI)`. See the :doc:`query2
+design document <design-query2>` for more details.
+
+Supports the following commands: ``GET``, ``PUT``.
+
+``GET``
+~~~~~~~
+
+Returns list of included fields and actual data. Takes a query parameter
+named "fields", containing a comma-separated list of field names. Does
+not support filtering.
+
+``PUT``
+~~~~~~~
+
+Returns list of included fields and actual data. The list of requested
+fields can either be given as the query parameter "fields" or as a body
+parameter with the same name. The optional body parameter "filter" can
+be given and must be either ``null`` or a list containing filter
+operators.
+
+
+``/2/query/[resource]/fields``
+++++++++++++++++++++++++++++++
+
+Request list of available fields for a resource. The resource is one of
+:pyeval:`utils.CommaJoin(constants.QR_VIA_RAPI)`. See the
+:doc:`query2 design document <design-query2>` for more details.
+
+Supports the following commands: ``GET``.
+
+``GET``
+~~~~~~~
+
+Returns a list of field descriptions for available fields. Takes an
+optional query parameter named "fields", containing a comma-separated
+list of field names.
+
+
``/2/os``
+++++++++
("/%s/groups/%s/rename" %
(GANETI_RAPI_VERSION, group)), None, body)
-
def AssignGroupNodes(self, group, nodes, force=False, dry_run=False):
"""Assigns nodes to a group.
return self._SendRequest(HTTP_PUT,
("/%s/groups/%s/assign-nodes" %
(GANETI_RAPI_VERSION, group)), query, body)
+
+ def Query(self, what, fields, filter_=None):
+ """Retrieves information about resources.
+
+ @type what: string
+ @param what: Resource name, one of L{constants.QR_VIA_RAPI}
+ @type fields: list of string
+ @param fields: Requested fields
+ @type filter_: None or list
+ @param filter_ Query filter
+
+ @rtype: string
+ @return: job id
+
+ """
+ body = {
+ "fields": fields,
+ }
+
+ if filter_ is not None:
+ body["filter"] = filter_
+
+ return self._SendRequest(HTTP_PUT,
+ ("/%s/query/%s" %
+ (GANETI_RAPI_VERSION, what)), None, body)
+
+ def QueryFields(self, what, fields=None):
+ """Retrieves available fields for a resource.
+
+ @type what: string
+ @param what: Resource name, one of L{constants.QR_VIA_RAPI}
+ @type fields: list of string
+ @param fields: Requested fields
+
+ @rtype: string
+ @return: job id
+
+ """
+ query = []
+
+ if fields is not None:
+ query.append(("fields", ",".join(fields)))
+
+ return self._SendRequest(HTTP_GET,
+ ("/%s/query/%s/fields" %
+ (GANETI_RAPI_VERSION, what)), query, None)
"/2/redistribute-config": rlib2.R_2_redist_config,
"/2/features": rlib2.R_2_features,
"/2/modify": rlib2.R_2_cluster_modify,
+ re.compile(r"^/2/query/(%s)$" % query_res_pattern): rlib2.R_2_query,
+ re.compile(r"^/2/query/(%s)/fields$" % query_res_pattern):
+ rlib2.R_2_query_fields,
}
return console
+def _GetQueryFields(args):
+ """
+
+ """
+ try:
+ fields = args["fields"]
+ except KeyError:
+ raise http.HttpBadRequest("Missing 'fields' query argument")
+
+ return _SplitQueryFields(fields[0])
+
+
+def _SplitQueryFields(fields):
+ """
+
+ """
+ return [i.strip() for i in fields.split(",")]
+
+
+class R_2_query(baserlib.R_Generic):
+ """/2/query/[resource] resource.
+
+ """
+ # Results might contain sensitive information
+ GET_ACCESS = [rapi.RAPI_ACCESS_WRITE]
+
+ def _Query(self, fields, filter_):
+ return baserlib.GetClient().Query(self.items[0], fields, filter_).ToDict()
+
+ def GET(self):
+ """Returns resource information.
+
+ @return: Query result, see L{objects.QueryResponse}
+
+ """
+ return self._Query(_GetQueryFields(self.queryargs), None)
+
+ def PUT(self):
+ """Submits job querying for resources.
+
+ @return: Query result, see L{objects.QueryResponse}
+
+ """
+ body = self.request_body
+
+ baserlib.CheckType(body, dict, "Body contents")
+
+ try:
+ fields = body["fields"]
+ except KeyError:
+ fields = _GetQueryFields(self.queryargs)
+
+ return self._Query(fields, self.request_body.get("filter", None))
+
+
+class R_2_query_fields(baserlib.R_Generic):
+ """/2/query/[resource]/fields resource.
+
+ """
+ def GET(self):
+ """Retrieves list of available fields for a resource.
+
+ @return: List of serialized L{objects.QueryFieldDefinition}
+
+ """
+ try:
+ raw_fields = self.queryargs["fields"]
+ except KeyError:
+ fields = None
+ else:
+ fields = _SplitQueryFields(raw_fields[0])
+
+ return baserlib.GetClient().QueryFields(self.items[0], fields).ToDict()
+
+
class _R_Tags(baserlib.R_Generic):
""" Quasiclass for tagging resources
from ganeti import http
from ganeti import serializer
from ganeti import utils
+from ganeti import query
+from ganeti import objects
from ganeti.rapi import connector
from ganeti.rapi import rlib2
self.assertEqual(data["amount"], amount)
self.assertEqual(self.rapi.CountPending(), 0)
+ def testQuery(self):
+ for idx, what in enumerate(constants.QR_VIA_RAPI):
+ for idx2, filter_ in enumerate([None, ["?", "name"]]):
+ job_id = 11010 + (idx << 4) + (idx2 << 16)
+ fields = sorted(query.ALL_FIELDS[what].keys())[:10]
+
+ self.rapi.AddResponse(str(job_id))
+ self.assertEqual(self.client.Query(what, fields, filter_=filter_),
+ job_id)
+ self.assertItems([what])
+ self.assertHandler(rlib2.R_2_query)
+ self.assertFalse(self.rapi.GetLastHandler().queryargs)
+ data = serializer.LoadJson(self.rapi.GetLastRequestData())
+ self.assertEqual(data["fields"], fields)
+ if filter_ is None:
+ self.assertTrue("filter" not in data)
+ else:
+ self.assertEqual(data["filter"], filter_)
+ self.assertEqual(self.rapi.CountPending(), 0)
+
+ def testQueryFields(self):
+ exp_result = objects.QueryFieldsResponse(fields=[
+ objects.QueryFieldDefinition(name="pnode", title="PNode",
+ kind=constants.QFT_NUMBER),
+ objects.QueryFieldDefinition(name="other", title="Other",
+ kind=constants.QFT_BOOL),
+ ])
+
+ for what in constants.QR_VIA_RAPI:
+ for fields in [None, ["name", "_unknown_"], ["&", "?|"]]:
+ self.rapi.AddResponse(serializer.DumpJson(exp_result.ToDict()))
+ result = self.client.QueryFields(what, fields=fields)
+ self.assertItems([what])
+ self.assertHandler(rlib2.R_2_query_fields)
+ self.assertFalse(self.rapi.GetLastRequestData())
+
+ queryargs = self.rapi.GetLastHandler().queryargs
+ if fields is None:
+ self.assertFalse(queryargs)
+ else:
+ self.assertEqual(queryargs, {
+ "fields": [",".join(fields)],
+ })
+
+ self.assertEqual(objects.QueryFieldsResponse.FromDict(result).ToDict(),
+ exp_result.ToDict())
+
+ self.assertEqual(self.rapi.CountPending(), 0)
+
class RapiTestRunner(unittest.TextTestRunner):
def run(self, *args):