diff --git a/gnocchi/indexer/alembic/versions/1c2c61ac1f4c_add_original_resource_id_column.py b/gnocchi/indexer/alembic/versions/1c2c61ac1f4c_add_original_resource_id_column.py new file mode 100644 index 000000000..59632635f --- /dev/null +++ b/gnocchi/indexer/alembic/versions/1c2c61ac1f4c_add_original_resource_id_column.py @@ -0,0 +1,40 @@ +# Copyright 2016 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""add original resource id column + +Revision ID: 1c2c61ac1f4c +Revises: 1f21cbdd6bc2 +Create Date: 2016-01-27 05:57:48.909012 + +""" + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '1c2c61ac1f4c' +down_revision = '62a8dfb139bb' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('resource', sa.Column('original_resource_id', + sa.String(length=255), + nullable=True)) + op.add_column('resource_history', sa.Column('original_resource_id', + sa.String(length=255), + nullable=True)) diff --git a/gnocchi/indexer/sqlalchemy_base.py b/gnocchi/indexer/sqlalchemy_base.py index 8ebab9596..97059c6e9 100644 --- a/gnocchi/indexer/sqlalchemy_base.py +++ b/gnocchi/indexer/sqlalchemy_base.py @@ -245,6 +245,7 @@ class ResourceMixin(ResourceJsonifier): ended_at = sqlalchemy.Column(PreciseTimestamp) user_id = sqlalchemy.Column(sqlalchemy.String(255)) project_id = sqlalchemy.Column(sqlalchemy.String(255)) + original_resource_id = sqlalchemy.Column(sqlalchemy.String(255)) class Resource(ResourceMixin, Base, GnocchiBase): diff --git a/gnocchi/rest/__init__.py b/gnocchi/rest/__init__.py index a64520f10..d34d16923 100644 --- a/gnocchi/rest/__init__.py +++ b/gnocchi/rest/__init__.py @@ -13,6 +13,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +import functools import uuid from oslo_utils import strutils @@ -808,7 +809,17 @@ def ResourceSchema(schema): voluptuous.Optional('metrics'): MetricsSchema, } base_schema.update(schema) - return base_schema + + @functools.wraps(ResourceSchema) + def f(v): + # NOTE(sileht): if that not a dict, lets voluptuous raise errors + if isinstance(v, dict): + rid = v.get('id') + res = voluptuous.Schema(base_schema)(v) + if rid is not None: + res["original_resource_id"] = six.text_type(rid) + return res + return f class ResourceController(rest.RestController): diff --git a/gnocchi/tests/gabbi/gabbits/base.yaml b/gnocchi/tests/gabbi/gabbits/base.yaml index c016f5c37..fb5a88b8c 100644 --- a/gnocchi/tests/gabbi/gabbits/base.yaml +++ b/gnocchi/tests/gabbi/gabbits/base.yaml @@ -121,6 +121,29 @@ tests: project_id: f3d41b770cc14f0bb94a1d5be9c0e3ea created_by_project_id: 99d13f22-3618-4288-82b8-6512ded77e4f +- name: post generic resource bad id + url: /v1/resource/generic + method: post + request_headers: + content-type: application/json + x-user-id: 93180da9-7c15-40d3-a050-a374551e52ee + x-project-id: 99d13f22-3618-4288-82b8-6512ded77e4f + data: + id: 1.2.3.4 + started_at: "2014-01-03T02:02:02.000000" + user_id: 0fbb2314-8461-4b1a-8013-1fc22f6afc9c + project_id: f3d41b77-0cc1-4f0b-b94a-1d5be9c0e3ea + status: 201 + response_headers: + location: $SCHEME://$NETLOC/v1/resource/generic/8d835270-2834-5e55-a693-fd0cf91cba3d + response_json_paths: + type: generic + started_at: "2014-01-03T02:02:02+00:00" + project_id: f3d41b77-0cc1-4f0b-b94a-1d5be9c0e3ea + created_by_project_id: 99d13f22-3618-4288-82b8-6512ded77e4f + id: 8d835270-2834-5e55-a693-fd0cf91cba3d + original_resource_id: 1.2.3.4 + - name: get status denied url: /v1/status - status: 403 \ No newline at end of file + status: 403 diff --git a/gnocchi/tests/test_indexer.py b/gnocchi/tests/test_indexer.py index bd2a9f5e9..45993cb0b 100644 --- a/gnocchi/tests/test_indexer.py +++ b/gnocchi/tests/test_indexer.py @@ -131,6 +131,7 @@ class TestIndexerDriver(tests_base.TestCase): "project_id": None, "started_at": rc.started_at, "ended_at": None, + "original_resource_id": None, "type": "generic", "metrics": {}}, rc.jsonify()) @@ -197,6 +198,7 @@ class TestIndexerDriver(tests_base.TestCase): "host": "foo", "image_ref": image_ref, "flavor_id": "1", + "original_resource_id": None, "metrics": {}}, rc.jsonify()) rg = self.index.get_resource('generic', r1, with_metrics=True) @@ -266,6 +268,7 @@ class TestIndexerDriver(tests_base.TestCase): "project_id": None, "started_at": ts, "ended_at": None, + "original_resource_id": None, "type": "generic", "metrics": {}}, rc.jsonify()) r = self.index.get_resource('generic', r1, with_metrics=True) @@ -296,6 +299,7 @@ class TestIndexerDriver(tests_base.TestCase): "project_id": None, "started_at": rc.started_at, "ended_at": None, + "original_resource_id": None, "type": "generic", "metrics": {'foo': str(e1), 'bar': str(e2)}}, rc.jsonify()) @@ -311,6 +315,7 @@ class TestIndexerDriver(tests_base.TestCase): "ended_at": None, "user_id": None, "project_id": None, + "original_resource_id": None, "metrics": {'foo': str(e1), 'bar': str(e2)}}, r.jsonify()) @@ -361,6 +366,7 @@ class TestIndexerDriver(tests_base.TestCase): "project_id": None, "type": "generic", "started_at": r.started_at, + "original_resource_id": None, "metrics": {}}, r.jsonify()) def test_update_resource_metrics(self): @@ -539,6 +545,7 @@ class TestIndexerDriver(tests_base.TestCase): "created_by_project_id": project, "user_id": None, "project_id": None, + "original_resource_id": None, "type": "generic", "metrics": {'bar': str(e2)}}, r.jsonify()) diff --git a/gnocchi/tests/test_rest.py b/gnocchi/tests/test_rest.py index 017b2ed22..42ddd16e5 100644 --- a/gnocchi/tests/test_rest.py +++ b/gnocchi/tests/test_rest.py @@ -773,6 +773,8 @@ class ResourceTest(RestTest): # Set an id in the attribute self.attributes['id'] = str(uuid.uuid4()) self.resource = self.attributes.copy() + # Set original_resource_id + self.resource['original_resource_id'] = self.resource['id'] if self.auth: self.resource['created_by_user_id'] = TestingApp.USER_ID self.resource['created_by_project_id'] = TestingApp.PROJECT_ID @@ -1443,6 +1445,20 @@ class ResourceTest(RestTest): self.assertGreaterEqual(len(resources), 1) self.assertEqual(result, resources[0]) + def test_search_resource_by_original_resource_id(self): + result = self.app.post_json( + "/v1/resource/" + self.resource_type, + params=self.attributes) + created_resource = json.loads(result.text) + original_id = created_resource['original_resource_id'] + result = self.app.post_json( + "/v1/search/resource/" + self.resource_type, + params={"eq": {"original_resource_id": original_id}}, + status=200) + resources = json.loads(result.text) + self.assertGreaterEqual(len(resources), 1) + self.assertEqual(created_resource, resources[0]) + def test_search_resources_by_user(self): u1 = str(uuid.uuid4()) self.attributes['user_id'] = u1