From 4cd4f2887011ee43ffc7a9d64f839f0c2b61e55a Mon Sep 17 00:00:00 2001 From: Feodor Tersin Date: Wed, 9 Sep 2015 17:52:18 +0300 Subject: [PATCH] Prevent updating os_id of db items Updating of db item's os_id should be disabled. But a special case (None -> smth) should be allowed. Change-Id: I9a38c99d1a5d024ef38339e8d41eff7856cb3ebe --- ec2api/db/sqlalchemy/api.py | 7 ++++++- ec2api/exception.py | 5 +++++ ec2api/tests/unit/test_db_api.py | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/ec2api/db/sqlalchemy/api.py b/ec2api/db/sqlalchemy/api.py index 1a973f22..710ca6f1 100644 --- a/ec2api/db/sqlalchemy/api.py +++ b/ec2api/db/sqlalchemy/api.py @@ -29,6 +29,7 @@ from sqlalchemy.sql import bindparam import ec2api.context from ec2api.db.sqlalchemy import models +from ec2api import exception CONF = cfg.CONF @@ -142,8 +143,12 @@ def add_item_id(context, kind, os_id, project_id=None): def update_item(context, item): item_ref = (model_query(context, models.Item). filter_by(project_id=context.project_id, - id=item["id"]). + id=item['id']). one()) + if item_ref.os_id and item_ref.os_id != item['os_id']: + raise exception.EC2DBInvalidOsIdUpdate(item_id=item['id'], + old_os_id=item_ref.os_id, + new_os_id=item['os_id']) item_ref.update(_pack_item_data(item)) item_ref.save() return _unpack_item_data(item_ref) diff --git a/ec2api/exception.py b/ec2api/exception.py index fbf14991..ea011a8e 100644 --- a/ec2api/exception.py +++ b/ec2api/exception.py @@ -100,6 +100,11 @@ class EC2KeystoneDiscoverFailure(EC2APIException): msg_fmt = _("Could not discover keystone versions.") +class EC2DBInvalidOsIdUpdate(EC2APIException): + msg_fmt = _('Invalid update of os_id of %(item_id)s item ' + 'from %(old_os_id)s to %(new_os_id)s') + + # Internal ec2api metadata exceptions class EC2MetadataException(EC2APIException): diff --git a/ec2api/tests/unit/test_db_api.py b/ec2api/tests/unit/test_db_api.py index ce4d33c8..bb8026a0 100644 --- a/ec2api/tests/unit/test_db_api.py +++ b/ec2api/tests/unit/test_db_api.py @@ -17,6 +17,7 @@ from sqlalchemy.orm import exc as orm_exception from ec2api.api import validator from ec2api.db import api as db_api +from ec2api import exception from ec2api.tests.unit import base from ec2api.tests.unit import fakes from ec2api.tests.unit import matchers @@ -142,6 +143,22 @@ class DbApiTestCase(base.DbTestCase): {'id': fakes.random_ec2_id('fake'), 'key': 'val'}) + def test_update_item_os_id(self): + item = db_api.add_item(self.context, 'fake', {}) + item['os_id'] = 'fake_os_id' + db_api.update_item(self.context, item) + item = db_api.get_item_by_id(self.context, item['id']) + self.assertThat({'os_id': 'fake_os_id'}, + matchers.IsSubDictOf(item)) + item['os_id'] = 'other_fake_os_id' + self.assertRaises(exception.EC2DBInvalidOsIdUpdate, + db_api.update_item, + self.context, item) + item['os_id'] = None + self.assertRaises(exception.EC2DBInvalidOsIdUpdate, + db_api.update_item, + self.context, item) + def test_delete_item(self): item = db_api.add_item(self.context, 'fake', {}) db_api.delete_item(self.context, item['id'])