Browse Source

Implemented middleware to augment POSTed metrics with keystone metadata

Change-Id: I4bcb351141200eb113d1b6e990a5ef257aaa4748
Samir Borle 3 years ago
parent
commit
42c9103eb3
3 changed files with 166 additions and 0 deletions
  1. 78
    0
      kiloeyes/middleware/keystone_augmenter.py
  2. 87
    0
      kiloeyes/tests/middleware/test_augmenter.py
  3. 1
    0
      setup.cfg

+ 78
- 0
kiloeyes/middleware/keystone_augmenter.py View File

@@ -0,0 +1,78 @@
1
+# Copyright 2016 Cornell University
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+
16
+import StringIO
17
+try:
18
+    import ujson as json
19
+except ImportError:
20
+    import json
21
+
22
+
23
+class KeystoneAugmenter(object):
24
+    """middleware that adds keystone data to POST-ed metrics.
25
+
26
+       This middleware must be placed in the server pipeline immediately
27
+       following the keystone middleware. If the request coming to the server
28
+       is a POST request on the /v2.0/metrics endpoint, the middleware extracts
29
+       keystone fields from the request,and adds them to the body of the
30
+       metrics JSON objects.
31
+    """
32
+    def __init__(self, app, conf):
33
+        self.app = app
34
+        self.conf = conf
35
+
36
+    def add_keystone_to_metrics(self, env):
37
+        body = env['wsgi.input'].read()
38
+        metrics = json.loads(body)
39
+
40
+        # Add keystone data to metrics
41
+        if isinstance(metrics, list):
42
+            for metric in metrics:
43
+                metric['tenant'] = env['HTTP_X_TENANT']
44
+                metric['tenant_id'] = env['HTTP_X_TENANT_ID']
45
+                metric['user'] = env['HTTP_X_USER']
46
+                metric['user_agent'] = env['HTTP_USER_AGENT']
47
+                metric['project_id'] = env['HTTP_X_PROJECT_ID']
48
+                metric['user_id'] = env['HTTP_X_USER_ID']
49
+
50
+        env['wsgi.input'] = StringIO.StringIO(json.dumps(metrics))
51
+        return env
52
+
53
+    def __call__(self, env, start_response):
54
+        if (env.get('PATH_INFO', '').startswith('/v2.0/metrics') and
55
+                env.get('REQUEST_METHOD', '') == 'POST'):
56
+            # We only check the requests which are posting against metrics
57
+            # endpoint
58
+            try:
59
+                env = self.add_keystone_to_metrics(env)
60
+
61
+                return self.app(env, start_response)
62
+            except Exception:
63
+                pass
64
+            # It is either invalid or exceptioned out while parsing json
65
+            # we will send the request back with 400.
66
+            start_response("400 Bad Request", [], '')
67
+            return []
68
+        else:
69
+            # not a metric post request, move on.
70
+            return self.app(env, start_response)
71
+
72
+
73
+def filter_factory(global_conf, **local_conf):
74
+
75
+    def augmenter_filter(app):
76
+        return KeystoneAugmenter(app, local_conf)
77
+
78
+    return augmenter_filter

+ 87
- 0
kiloeyes/tests/middleware/test_augmenter.py View File

@@ -0,0 +1,87 @@
1
+# Copyright 2016 Cornell University
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+# not use this file except in compliance with the License. You may obtain
5
+# a copy of the License at
6
+#
7
+#      http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+# License for the specific language governing permissions and limitations
13
+# under the License.
14
+
15
+from kiloeyes.middleware import keystone_augmenter
16
+from oslotest import base
17
+
18
+import StringIO
19
+
20
+try:
21
+        import ujson as json
22
+except ImportError:
23
+        import json
24
+
25
+
26
+class TestKeystoneAugmenter(base.BaseTestCase):
27
+
28
+        def setUp(self):
29
+                super(TestKeystoneAugmenter, self).setUp()
30
+                self.augmenter = keystone_augmenter.KeystoneAugmenter({}, {})
31
+
32
+        def test_call(self):
33
+                test_input = [
34
+                    {
35
+                        'name': 'metric1',
36
+                        'timestamp': 125213525352,
37
+                        'dimensions': {'service': 'test_service'}
38
+                    },
39
+                    {
40
+                        'name': 'metric2',
41
+                        'timestamp': 135098109530,
42
+                        'dimensions': {'service': 'test_service'}
43
+                    }
44
+                ]
45
+
46
+                input_json = StringIO.StringIO(json.dumps(test_input))
47
+
48
+                env = {
49
+                    'wsgi.input': input_json,
50
+                    'HTTP_X_TENANT': 'test',
51
+                    'HTTP_X_TENANT_ID': 'testid1',
52
+                    'HTTP_X_USER': 'test_user',
53
+                    'HTTP_USER_AGENT': 'kiloeyes-tester',
54
+                    'HTTP_X_PROJECT_ID': 'projidtest2',
55
+                    'HTTP_X_USER_ID': 'testuid'
56
+                }
57
+
58
+                metrics_expected = [
59
+                    {
60
+                        'name': 'metric1',
61
+                        'timestamp': 125213525352,
62
+                        'dimensions': {'service': 'test_service'},
63
+                        'tenant': 'test',
64
+                        'tenant_id': 'testid1',
65
+                        'user': 'test_user',
66
+                        'user_agent': 'kiloeyes-tester',
67
+                        'project_id': 'projidtest2',
68
+                        'user_id': 'testuid'
69
+                    },
70
+                    {
71
+                        'name': 'metric2',
72
+                        'timestamp': 135098109530,
73
+                        'dimensions': {'service': 'test_service'},
74
+                        'tenant': 'test',
75
+                        'tenant_id': 'testid1',
76
+                        'user': 'test_user',
77
+                        'user_agent': 'kiloeyes-tester',
78
+                        'project_id': 'projidtest2',
79
+                        'user_id': 'testuid'
80
+                    }
81
+                ]
82
+
83
+                augmented_env = self.augmenter.add_keystone_to_metrics(env)
84
+
85
+                metrics_res = json.loads(augmented_env['wsgi.input'].read())
86
+
87
+                self.assertEqual(metrics_expected, metrics_res)

+ 1
- 0
setup.cfg View File

@@ -66,6 +66,7 @@ paste.filter_factory =
66 66
     inspector = kiloeyes.middleware.inspector:filter_factory
67 67
     metric_validator = kiloeyes.middleware.metric_validator:filter_factory
68 68
     meter_validator = kiloeyes.middleware.meter_validator:filter_factory
69
+    keystone_augmenter = kiloeyes.middleware.keystone_augmenter:filter_factory
69 70
 
70 71
 [pbr]
71 72
 warnerrors = True

Loading…
Cancel
Save