From c131b2bfd5ac7d01632d4e5f1b25825e31e0aaf5 Mon Sep 17 00:00:00 2001 From: Mehdi Abaakouk Date: Fri, 15 Mar 2013 11:25:57 +0000 Subject: [PATCH] Allow publishing arbitrary headers via the "storage.objects.*.bytes" counter The change allow publishing arbitrary headers via the "storage.objects.*.bytes" counter of the swift middleware. The list of the headers to publish can be configured in the swift middleware filter like this: [filter:ceilometer] use = egg:ceilometer#swift metadata_headers = X_VAR1, x-var2 Change-Id: I26a4a573707a778c5b86d298840e7ae25a95deea --- ceilometer/objectstore/swift_middleware.py | 50 ++++++++++++++----- tests/objectstore/test_swift_middleware.py | 58 ++++++++++++++++++++++ 2 files changed, 96 insertions(+), 12 deletions(-) diff --git a/ceilometer/objectstore/swift_middleware.py b/ceilometer/objectstore/swift_middleware.py index d0f9e589a..071bb1f6a 100644 --- a/ceilometer/objectstore/swift_middleware.py +++ b/ceilometer/objectstore/swift_middleware.py @@ -18,6 +18,23 @@ # See the License for the specific language governing permissions and # limitations under the License. + +""" +Ceilometer Middleware for Swift Proxy + +Configuration: + +In /etc/swift/proxy-server.conf on the main pipeline add "ceilometer" just +before "proxy-server" and add the following filter in the file: + +[filter:ceilometer] +use = egg:ceilometer#swift + +# Some optional configuration +# this allow to publish additional metadata +metadata_headers = X-TEST +""" + from __future__ import absolute_import from oslo.config import cfg @@ -54,6 +71,12 @@ class CeilometerMiddleware(object): def __init__(self, app, conf): self.app = app + + self.metadata_headers = [h.strip().replace('-', '_').lower() + for h in conf.get( + "metadata_headers", + "").split(",") if h.strip()] + service.prepare_service() publisher_manager = dispatch.NameDispatchExtensionManager( namespace=pipeline.PUBLISHER_NAMESPACE, @@ -97,6 +120,19 @@ class CeilometerMiddleware(object): req = REQUEST.Request(env) version, account, container, obj = split_path(req.path, 1, 4, True) now = timeutils.utcnow().isoformat() + + resource_metadata = { + "path": req.path, + "version": version, + "container": container, + "object": obj, + } + + for header in self.metadata_headers: + if header.upper() in req.headers: + resource_metadata['http_header_%s' % header] = req.headers.get( + header.upper()) + with pipeline.PublishContext( context.get_admin_context(), cfg.CONF.counter_source, @@ -112,12 +148,7 @@ class CeilometerMiddleware(object): project_id=env.get('HTTP_X_TENANT_ID'), resource_id=account.partition('AUTH_')[2], timestamp=now, - resource_metadata={ - "path": req.path, - "version": version, - "container": container, - "object": obj, - })]) + resource_metadata=resource_metadata)]) if bytes_sent: publisher([counter.Counter( @@ -129,12 +160,7 @@ class CeilometerMiddleware(object): project_id=env.get('HTTP_X_TENANT_ID'), resource_id=account.partition('AUTH_')[2], timestamp=now, - resource_metadata={ - "path": req.path, - "version": version, - "container": container, - "object": obj, - })]) + resource_metadata=resource_metadata)]) def filter_factory(global_conf, **local_conf): diff --git a/tests/objectstore/test_swift_middleware.py b/tests/objectstore/test_swift_middleware.py index 4b165b7bf..5f5244bbe 100644 --- a/tests/objectstore/test_swift_middleware.py +++ b/tests/objectstore/test_swift_middleware.py @@ -133,3 +133,61 @@ class TestSwiftMiddleware(base.TestCase): self.assertEqual(data.resource_metadata['version'], '1.0') self.assertEqual(data.resource_metadata['container'], 'container') self.assertEqual(data.resource_metadata['object'], None) + + def test_no_metadata_headers(self): + app = swift_middleware.CeilometerMiddleware(FakeApp(), {}) + req = Request.blank('/1.0/account/container', + environ={'REQUEST_METHOD': 'GET'}) + resp = list(app(req.environ, self.start_response)) + counters = self.pipeline_manager.pipelines[0].counters + self.assertEqual(len(counters), 1) + data = counters[0] + http_headers = [k for k in data.resource_metadata.keys() + if k.startswith('http_header_')] + self.assertEqual(len(http_headers), 0) + self.assertEqual(data.resource_metadata['version'], '1.0') + self.assertEqual(data.resource_metadata['container'], 'container') + self.assertEqual(data.resource_metadata['object'], None) + + def test_metadata_headers(self): + app = swift_middleware.CeilometerMiddleware(FakeApp(), { + 'metadata_headers': 'X_VAR1, x-var2, x-var3' + }) + req = Request.blank('/1.0/account/container', + environ={'REQUEST_METHOD': 'GET'}, + headers={ + 'X_VAR1': 'value1', + 'X_VAR2': 'value2' + }) + resp = list(app(req.environ, self.start_response)) + counters = self.pipeline_manager.pipelines[0].counters + self.assertEqual(len(counters), 1) + data = counters[0] + http_headers = [k for k in data.resource_metadata.keys() + if k.startswith('http_header_')] + self.assertEqual(len(http_headers), 2) + self.assertEqual(data.resource_metadata['version'], '1.0') + self.assertEqual(data.resource_metadata['container'], 'container') + self.assertEqual(data.resource_metadata['object'], None) + self.assertEqual(data.resource_metadata['http_header_x_var1'], + 'value1') + self.assertEqual(data.resource_metadata['http_header_x_var2'], + 'value2') + self.assertFalse('http_header_x_var3' in data.resource_metadata) + + def test_metadata_headers_on_not_existing_header(self): + app = swift_middleware.CeilometerMiddleware(FakeApp(), { + 'metadata_headers': 'x-var3' + }) + req = Request.blank('/1.0/account/container', + environ={'REQUEST_METHOD': 'GET'}) + resp = list(app(req.environ, self.start_response)) + counters = self.pipeline_manager.pipelines[0].counters + self.assertEqual(len(counters), 1) + data = counters[0] + http_headers = [k for k in data.resource_metadata.keys() + if k.startswith('http_header_')] + self.assertEqual(len(http_headers), 0) + self.assertEqual(data.resource_metadata['version'], '1.0') + self.assertEqual(data.resource_metadata['container'], 'container') + self.assertEqual(data.resource_metadata['object'], None)