summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ceilometer/polling/dynamic_pollster.py89
-rw-r--r--ceilometer/tests/unit/polling/test_dynamic_pollster.py67
-rw-r--r--doc/source/admin/telemetry-dynamic-pollster.rst10
3 files changed, 161 insertions, 5 deletions
diff --git a/ceilometer/polling/dynamic_pollster.py b/ceilometer/polling/dynamic_pollster.py
index db183308..d3f8563e 100644
--- a/ceilometer/polling/dynamic_pollster.py
+++ b/ceilometer/polling/dynamic_pollster.py
@@ -319,10 +319,39 @@ class PollsterValueMapper(object):
class PollsterDefinition(object):
+ """Represents a dynamic pollster configuration/parameter
+
+ It abstract the job of developers when creating or extending parameters,
+ such as validating parameters name, values and so on.
+ """
def __init__(self, name, required=False, on_missing=lambda df: df.default,
default=None, validation_regex=None, creatable=True,
validator=None):
+ """Create a dynamic pollster configuration/parameter
+
+ :param name: the name of the pollster parameter/configuration.
+ :param required: indicates if the configuration/parameter is
+ optional or not.
+ :param on_missing: function that is executed when the
+ parameter/configuration is missing.
+ :param default: the default value to be used.
+ :param validation_regex: the regular expression used to validate the
+ name of the configuration/parameter.
+ :param creatable: it is an override mechanism to avoid creating
+ a configuration/parameter with the default value. The default
+ is ``True``; therefore, we always use the default value.
+ However, we can disable the use of the default value by
+ setting ``False``. When we set this configuration to
+ ``False``, the parameter is not added to the definition
+ dictionary if not defined by the operator in the pollster
+ YAML configuration file.
+ :param validator: function used to validate the value of the
+ parameter/configuration when it is given by the user. This
+ function signature should receive a value that is the value of
+ the parameter to be validate.
+ """
+
self.name = name
self.required = required
self.on_missing = on_missing
@@ -370,7 +399,7 @@ class PollsterDefinitions(object):
PollsterDefinition(name='user_id_attribute', default="user_id"),
PollsterDefinition(name='resource_id_attribute', default="id"),
PollsterDefinition(name='project_id_attribute', default="project_id"),
- ]
+ PollsterDefinition(name='headers')]
extra_definitions = []
@@ -553,11 +582,27 @@ class PollsterSampleGatherer(object):
def internal_execute_request_get_samples(self, kwargs):
keystone_client = kwargs['keystone_client']
url = self.get_request_linked_samples_url(kwargs)
- resp = keystone_client.session.get(url, authenticated=True)
+
+ request_arguments = self.create_request_arguments()
+ LOG.debug("Executing request against [url=%s] with parameters ["
+ "%s] for pollsters [%s]", url, request_arguments,
+ self.definitions.configurations["name"])
+
+ resp = keystone_client.session.get(url, **request_arguments)
+
if resp.status_code != requests.codes.ok:
resp.raise_for_status()
return resp, url
+ def create_request_arguments(self):
+ request_args = {
+ "authenticated": True
+ }
+ request_headers = self.definitions.configurations['headers']
+ if request_headers:
+ request_args['headers'] = request_headers
+ return request_args
+
def get_request_linked_samples_url(self, kwargs):
next_sample_url = kwargs.get('next_sample_url')
if next_sample_url:
@@ -633,9 +678,13 @@ class NonOpenStackApisSamplesGatherer(PollsterSampleGatherer):
authenticator_arguments = list(map(str.strip, credentials.split(",")))
authenticator_instance = authenticator_class(*authenticator_arguments)
- resp = requests.get(
- url,
- auth=authenticator_instance)
+ request_arguments = self.create_request_arguments()
+ request_arguments["auth"] = authenticator_instance
+
+ LOG.debug("Executing request against [url=%s] with parameters ["
+ "%s] for pollsters [%s]", url, request_arguments,
+ self.definitions.configurations["name"])
+ resp = requests.get(url, **request_arguments)
if resp.status_code != requests.codes.ok:
raise declarative.NonOpenStackApisDynamicPollsterException(
@@ -645,6 +694,36 @@ class NonOpenStackApisSamplesGatherer(PollsterSampleGatherer):
return resp, url
+ def create_request_arguments(self):
+ request_arguments = super(
+ NonOpenStackApisSamplesGatherer, self).create_request_arguments()
+
+ request_arguments.pop("authenticated")
+
+ return request_arguments
+
+ def execute_request_get_samples(self, **kwargs):
+ samples = super(NonOpenStackApisSamplesGatherer,
+ self).execute_request_get_samples(**kwargs)
+
+ if samples:
+ user_id_attribute = self.definitions.configurations[
+ 'user_id_attribute']
+ project_id_attribute = self.definitions.configurations[
+ 'project_id_attribute']
+ resource_id_attribute = self.definitions.configurations[
+ 'resource_id_attribute']
+
+ for request_sample in samples:
+ self.generate_new_attributes_in_sample(
+ request_sample, user_id_attribute, 'user_id')
+ self.generate_new_attributes_in_sample(
+ request_sample, project_id_attribute, 'project_id')
+ self.generate_new_attributes_in_sample(
+ request_sample, resource_id_attribute, 'id')
+
+ return samples
+
def generate_new_attributes_in_sample(
self, sample, attribute_key, new_attribute_key):
if attribute_key:
diff --git a/ceilometer/tests/unit/polling/test_dynamic_pollster.py b/ceilometer/tests/unit/polling/test_dynamic_pollster.py
index aa73ca0f..c8652517 100644
--- a/ceilometer/tests/unit/polling/test_dynamic_pollster.py
+++ b/ceilometer/tests/unit/polling/test_dynamic_pollster.py
@@ -780,3 +780,70 @@ class TestDynamicPollster(base.BaseTestCase):
returned_value = pollster.definitions.sample_extractor.\
retrieve_attribute_nested_value(json_object, key)
self.assertEqual(0, returned_value)
+
+ def test_create_request_arguments_NonOpenStackApisSamplesGatherer(self):
+ pollster_definition = {
+ 'name': "test-pollster", 'sample_type': "gauge", 'unit': "test",
+ 'value_attribute': "volume",
+ 'url_path': "https://test.com/v1/test/endpoint/fake",
+ "module": "someModule",
+ "authentication_object": "objectAuthentication",
+ "authentication_parameters": "authParam",
+ "headers": [{"header1": "val1"}, {"header2": "val2"}]}
+
+ pollster = dynamic_pollster.DynamicPollster(pollster_definition)
+
+ request_args = pollster.definitions.sample_gatherer\
+ .create_request_arguments()
+
+ self.assertTrue("headers" in request_args)
+ self.assertEqual(2, len(request_args["headers"]))
+
+ self.assertEqual(['header1', 'header2'],
+ list(map(lambda h: list(h.keys())[0],
+ request_args["headers"])))
+
+ self.assertEqual(['val1', 'val2'],
+ list(map(lambda h: list(h.values())[0],
+ request_args["headers"])))
+
+ self.assertTrue("authenticated" not in request_args)
+
+ def test_create_request_arguments_PollsterSampleGatherer(self):
+ pollster_definition = copy.deepcopy(
+ self.pollster_definition_only_required_fields)
+ pollster_definition["headers"] = [
+ {"x-openstack-nova-api-version": "2.46"},
+ {"custom_header": "custom"},
+ {"some_other_header": "something"}]
+
+ pollster = dynamic_pollster.DynamicPollster(pollster_definition)
+
+ request_args = pollster.definitions.sample_gatherer\
+ .create_request_arguments()
+
+ self.assertTrue("headers" in request_args)
+ self.assertTrue("authenticated" in request_args)
+ self.assertTrue(request_args["authenticated"])
+
+ self.assertEqual(3, len(request_args["headers"]))
+
+ self.assertEqual(['x-openstack-nova-api-version', 'custom_header',
+ "some_other_header"],
+ list(map(lambda h: list(h.keys())[0],
+ request_args["headers"])))
+
+ self.assertEqual(['2.46', 'custom', 'something'],
+ list(map(lambda h: list(h.values())[0],
+ request_args["headers"])))
+
+ def test_create_request_arguments_PollsterSampleGatherer_no_headers(self):
+ pollster = dynamic_pollster.DynamicPollster(
+ self.pollster_definition_only_required_fields)
+
+ request_args =\
+ pollster.definitions.sample_gatherer.create_request_arguments()
+
+ self.assertTrue("headers" not in request_args)
+ self.assertTrue("authenticated" in request_args)
+ self.assertTrue(request_args["authenticated"])
diff --git a/doc/source/admin/telemetry-dynamic-pollster.rst b/doc/source/admin/telemetry-dynamic-pollster.rst
index 6ed1faa2..62e6dc3e 100644
--- a/doc/source/admin/telemetry-dynamic-pollster.rst
+++ b/doc/source/admin/telemetry-dynamic-pollster.rst
@@ -171,6 +171,16 @@ attributes to define a dynamic pollster:
``response_entries_key`` elements that will be mapped to ``id`` attribute
that is sent to Gnocchi.
+* ``headers``: optional parameter. It is a map (similar to the
+ metadata_mapping) of key and value that can be used to customize the header
+ of the request that is executed against the URL. This configuration works
+ for both OpenStack and non-OpenStack dynamic pollster configuration.
+
+ .. code-block:: yaml
+
+ headers:
+ "x-openstack-nova-api-version": "2.46"
+
The complete YAML configuration to gather data from Magnum (that has been used
as an example) is the following: