From f95dd50a574823e0ee27d32c383222f7333cca94 Mon Sep 17 00:00:00 2001 From: ShaoHe Feng Date: Fri, 23 Jan 2015 22:22:33 +0800 Subject: [PATCH] Versioned objects - ResourceData Implementation for blueprint versioned-objects. This contains ResourceData. Co-Authored-By: Grzegorz Grasza Co-Authored-By: Michal Jastrzebski (inc0) Change-Id: I129f3b891a8efd728ed55c03286dcc1f8b68c4aa --- heat/engine/resource.py | 10 ++-- heat/objects/resource_data.py | 83 +++++++++++++++++++++++++++++ heat/tests/openstack/test_volume.py | 6 +-- heat/tests/test_nested_stack.py | 7 +-- heat/tests/test_resource.py | 6 ++- heat/tests/test_server.py | 4 +- heat/tests/test_signal.py | 13 ++--- heat/tests/test_stack_user.py | 16 +++--- heat/tests/test_user.py | 10 ++-- 9 files changed, 122 insertions(+), 33 deletions(-) create mode 100644 heat/objects/resource_data.py diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 21407c61cd..4478a67f9c 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -39,6 +39,7 @@ from heat.engine import resources from heat.engine import rsrc_defn from heat.engine import scheduler from heat.engine import support +from heat.objects import resource_data as resource_data_objects from heat.rpc import client as rpc_client cfg.CONF.import_opt('action_retry_limit', 'heat.common.config') @@ -190,7 +191,8 @@ class Resource(object): self.id = resource.id self.uuid = resource.uuid try: - self._data = db_api.resource_data_get_all(self, resource.data) + self._data = resource_data_objects.ResourceData.get_all( + self, resource.data) except exception.NotFound: self._data = {} self._rsrc_metadata = resource.rsrc_metadata @@ -1116,7 +1118,7 @@ class Resource(object): ''' if self._data is None and self.id: try: - self._data = db_api.resource_data_get_all(self) + self._data = resource_data_objects.ResourceData.get_all(self) except exception.NotFound: pass @@ -1124,7 +1126,7 @@ class Resource(object): def data_set(self, key, value, redact=False): '''Save resource's key/value pair to database.''' - db_api.resource_data_set(self, key, value, redact) + resource_data_objects.ResourceData.set(self, key, value, redact) # force fetch all resource data from the database again self._data = None @@ -1135,7 +1137,7 @@ class Resource(object): :returns: True if the key existed to delete ''' try: - db_api.resource_data_delete(self, key) + resource_data_objects.ResourceData.delete(self, key) except exception.NotFound: return False else: diff --git a/heat/objects/resource_data.py b/heat/objects/resource_data.py new file mode 100644 index 0000000000..321d7e4329 --- /dev/null +++ b/heat/objects/resource_data.py @@ -0,0 +1,83 @@ +# Copyright 2014 Intel Corp. +# +# 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. + + +""" +ResourceData object +""" + +from oslo_versionedobjects import base +from oslo_versionedobjects import fields + +from heat.common import exception +from heat.db import api as db_api + + +class ResourceData( + base.VersionedObject, + base.VersionedObjectDictCompat, + base.ComparableVersionedObject, +): + fields = { + 'id': fields.IntegerField(), + 'created_at': fields.DateTimeField(read_only=True), + 'updated_at': fields.DateTimeField(nullable=True), + 'key': fields.StringField(nullable=True), + 'value': fields.StringField(nullable=True), + 'redact': fields.BooleanField(nullable=True), + 'resource_id': fields.IntegerField(nullable=False), + 'decrypt_method': fields.StringField(nullable=True), + } + + @staticmethod + def _from_db_object(sdata, db_sdata): + if db_sdata is None: + return None + for field in sdata.fields: + sdata[field] = db_sdata[field] + sdata.obj_reset_changes() + return sdata + + @classmethod + def get_all(cls, resource, *args, **kwargs): + # this method only returns dict, so we won't use objects mechanism here + return db_api.resource_data_get_all(resource, *args, **kwargs) + + @classmethod + def get_obj(cls, resource, key): + raise exception.NotSupported(feature='ResourceData.get_obj') + + @classmethod + def get_val(cls, resource, key): + return db_api.resource_data_get(resource, key) + + @classmethod + def set(cls, resource, key, value, *args, **kwargs): + db_data = db_api.resource_data_set( + resource, + key, + value, + *args, + **kwargs + ) + return db_data + + @classmethod + def get_by_key(cls, context, resource_id, key): + db_rdata = db_api.resource_data_get_by_key(context, resource_id, key) + return cls._from_db_object(cls(context), db_rdata) + + @classmethod + def delete(cls, resource, key): + return db_api.resource_data_delete(resource, key) diff --git a/heat/tests/openstack/test_volume.py b/heat/tests/openstack/test_volume.py index 46728dc6e7..1fb5ea663a 100644 --- a/heat/tests/openstack/test_volume.py +++ b/heat/tests/openstack/test_volume.py @@ -20,11 +20,11 @@ import six from heat.common import exception from heat.common import template_format -from heat.db import api as db_api from heat.engine.clients.os import cinder from heat.engine.clients.os import glance from heat.engine import rsrc_defn from heat.engine import scheduler +from heat.objects import resource_data as resource_data_object from heat.tests import test_volume_utils as vt_base from heat.tests import utils from heat.tests.v1_1 import fakes as fakes_v1_1 @@ -609,7 +609,7 @@ class CinderVolumeTest(vt_base.BaseVolumeTest): self.assertEqual((rsrc.SNAPSHOT, rsrc.COMPLETE), rsrc.state) self.assertEqual({'backup_id': 'backup-123'}, - db_api.resource_data_get_all(rsrc)) + resource_data_object.ResourceData.get_all(rsrc)) self.m.VerifyAll() @@ -647,7 +647,7 @@ class CinderVolumeTest(vt_base.BaseVolumeTest): self.assertEqual((rsrc.SNAPSHOT, rsrc.FAILED), rsrc.state) self.assertEqual("Error: error", rsrc.status_reason) - self.assertEqual({}, db_api.resource_data_get_all(rsrc)) + self.assertEqual({}, resource_data_object.ResourceData.get_all(rsrc)) self.m.VerifyAll() diff --git a/heat/tests/test_nested_stack.py b/heat/tests/test_nested_stack.py index 2bdf4034f8..146307326e 100644 --- a/heat/tests/test_nested_stack.py +++ b/heat/tests/test_nested_stack.py @@ -21,11 +21,11 @@ import yaml from heat.common import exception from heat.common import template_format from heat.common import urlfetch -from heat.db import api as db_api from heat.engine import parser from heat.engine import resource from heat.engine.resources.aws.cfn import stack as stack_res from heat.engine import rsrc_defn +from heat.objects import resource_data as resource_data_object from heat.tests import common from heat.tests import generic_resource as generic_rsrc from heat.tests import utils @@ -288,8 +288,9 @@ Outputs: res = stack['res'] stack.delete() self.assertEqual((stack.DELETE, stack.COMPLETE), stack.state) - self.assertRaises(exception.NotFound, db_api.resource_data_get, res, - 'test') + self.assertRaises( + exception.NotFound, + resource_data_object.ResourceData.get_val, res, 'test') class NestedStackCrudTest(common.HeatTestCase): diff --git a/heat/tests/test_resource.py b/heat/tests/test_resource.py index d30e3ad086..d4db9f97e4 100644 --- a/heat/tests/test_resource.py +++ b/heat/tests/test_resource.py @@ -34,6 +34,7 @@ from heat.engine import resources from heat.engine import rsrc_defn from heat.engine import scheduler from heat.engine import template +from heat.objects import resource_data as resource_data_object from heat.tests import common from heat.tests import generic_resource as generic_rsrc from heat.tests import utils @@ -1179,8 +1180,9 @@ class ResourceAdoptTest(common.HeatTestCase): } adopt = scheduler.TaskRunner(res.adopt, res_data) adopt() - self.assertEqual("test-value", - db_api.resource_data_get(res, "test-key")) + self.assertEqual( + "test-value", + resource_data_object.ResourceData.get_val(res, "test-key")) self.assertEqual({"os_distro": "test-distro"}, res.metadata_get()) self.assertEqual({"os_distro": "test-distro"}, res.metadata) self.assertEqual((res.ADOPT, res.COMPLETE), res.state) diff --git a/heat/tests/test_server.py b/heat/tests/test_server.py index 0e1cf81664..db4c1f4646 100644 --- a/heat/tests/test_server.py +++ b/heat/tests/test_server.py @@ -23,7 +23,6 @@ from six.moves.urllib import parse as urlparse from heat.common import exception from heat.common.i18n import _ from heat.common import template_format -from heat.db import api as db_api from heat.engine.clients.os import glance from heat.engine.clients.os import neutron from heat.engine.clients.os import nova @@ -34,6 +33,7 @@ from heat.engine import resource from heat.engine.resources.openstack.nova import server as servers from heat.engine import scheduler from heat.engine import template +from heat.objects import resource_data as resource_data_object from heat.tests import common from heat.tests import utils from heat.tests.v1_1 import fakes as fakes_v1_1 @@ -2774,7 +2774,7 @@ class ServersTest(common.HeatTestCase): self.assertEqual((server.SNAPSHOT, server.COMPLETE), server.state) self.assertEqual({'snapshot_image_id': '1'}, - db_api.resource_data_get_all(server)) + resource_data_object.ResourceData.get_all(server)) self.m.VerifyAll() def test_server_dont_validate_personality_if_personality_isnt_set(self): diff --git a/heat/tests/test_signal.py b/heat/tests/test_signal.py index b2743901a9..3ba8b9d673 100644 --- a/heat/tests/test_signal.py +++ b/heat/tests/test_signal.py @@ -18,12 +18,12 @@ from oslo_config import cfg from heat.common import exception from heat.common import template_format -from heat.db import api as db_api from heat.engine import parser from heat.engine import resource from heat.engine.resources import stack_user from heat.engine import scheduler from heat.engine import template +from heat.objects import resource_data as resource_data_object from heat.tests import common from heat.tests import fakes from heat.tests import generic_resource @@ -86,7 +86,7 @@ class SignalTest(common.HeatTestCase): self.stack.create() rsrc = self.stack['signal_handler'] - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual((rsrc.CREATE, rsrc.FAILED), rsrc.state) self.assertIn('Failed', rsrc.status_reason) self.assertEqual('1234', rs_data.get('user_id')) @@ -108,7 +108,7 @@ class SignalTest(common.HeatTestCase): self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) # Ensure the resource data has been stored correctly - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual('mycredential', rs_data.get('credential_id')) self.assertEqual('anaccesskey', rs_data.get('access_key')) self.assertEqual('verysecret', rs_data.get('secret_key')) @@ -129,16 +129,17 @@ class SignalTest(common.HeatTestCase): self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) # Ensure the resource data has been stored correctly - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual('1234', rs_data.get('user_id')) self.assertEqual('1234', rsrc.resource_id) self.assertEqual('1234', rsrc._get_user_id()) # Check user id can still be fetched from resource_id # if the resource data is not there. - db_api.resource_data_delete(rsrc, 'user_id') + resource_data_object.ResourceData.delete(rsrc, 'user_id') self.assertRaises( - exception.NotFound, db_api.resource_data_get, rsrc, 'user_id') + exception.NotFound, resource_data_object.ResourceData.get_val, + rsrc, 'user_id') self.assertEqual('1234', rsrc._get_user_id()) self.m.VerifyAll() diff --git a/heat/tests/test_stack_user.py b/heat/tests/test_stack_user.py index 3471842ecd..21a794bea5 100644 --- a/heat/tests/test_stack_user.py +++ b/heat/tests/test_stack_user.py @@ -17,10 +17,10 @@ import six from heat.common import exception from heat.common import short_id from heat.common import template_format -from heat.db import api as db_api from heat.engine import resource from heat.engine.resources import stack_user from heat.engine import scheduler +from heat.objects import resource_data as resource_data_object from heat.tests import common from heat.tests import fakes from heat.tests import generic_resource @@ -83,7 +83,7 @@ class StackUserTest(common.HeatTestCase): scheduler.TaskRunner(rsrc.create)() self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual({'user_id': 'auser123'}, rs_data) self.m.VerifyAll() @@ -96,7 +96,7 @@ class StackUserTest(common.HeatTestCase): scheduler.TaskRunner(rsrc.create)() self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual({'user_id': 'auser456'}, rs_data) self.m.VerifyAll() @@ -146,7 +146,7 @@ class StackUserTest(common.HeatTestCase): scheduler.TaskRunner(rsrc.create)() self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) - db_api.resource_data_delete(rsrc, 'user_id') + resource_data_object.ResourceData.delete(rsrc, 'user_id') scheduler.TaskRunner(rsrc.delete)() self.assertEqual((rsrc.DELETE, rsrc.COMPLETE), rsrc.state) self.m.VerifyAll() @@ -252,7 +252,7 @@ class StackUserTest(common.HeatTestCase): self.assertEqual(self.fc.credential_id, kp.id) self.assertEqual(self.fc.access, kp.access) self.assertEqual(self.fc.secret, kp.secret) - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual(self.fc.credential_id, rs_data['credential_id']) self.assertEqual(self.fc.access, rs_data['access_key']) self.assertEqual(self.fc.secret, rs_data['secret_key']) @@ -293,7 +293,7 @@ class StackUserTest(common.HeatTestCase): rsrc.data_set('access_key', 'access123') rsrc.data_set('secret_key', 'verysecret') rsrc._delete_keypair() - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual({'user_id': 'auserdel'}, rs_data) self.m.VerifyAll() @@ -325,7 +325,7 @@ class StackUserTest(common.HeatTestCase): rsrc.data_set('access_key', 'access123') rsrc.data_set('secret_key', 'verysecret') rsrc._delete_keypair() - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual({'user_id': 'auserdel'}, rs_data) self.m.VerifyAll() @@ -345,7 +345,7 @@ class StackUserTest(common.HeatTestCase): self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state) rsrc.data_set('credential_id', 'acredential') rsrc._delete_keypair() - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual({'user_id': 'auserdel'}, rs_data) self.m.VerifyAll() diff --git a/heat/tests/test_user.py b/heat/tests/test_user.py index f763387a08..036bddfe30 100644 --- a/heat/tests/test_user.py +++ b/heat/tests/test_user.py @@ -16,10 +16,10 @@ from oslo_config import cfg from heat.common import exception from heat.common import short_id from heat.common import template_format -from heat.db import api as db_api from heat.engine.resources.aws.iam import user from heat.engine.resources.openstack.heat import access_policy as ap from heat.engine import scheduler +from heat.objects import resource_data as resource_data_object from heat.tests import common from heat.tests import fakes from heat.tests import utils @@ -321,7 +321,7 @@ class AccessKeyTest(common.HeatTestCase): rsrc._secret) # Ensure the resource data has been stored correctly - rs_data = db_api.resource_data_get_all(rsrc) + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual(self.fc.secret, rs_data.get('secret_key')) self.assertEqual(self.fc.credential_id, rs_data.get('credential_id')) self.assertEqual(2, len(rs_data.keys())) @@ -355,9 +355,9 @@ class AccessKeyTest(common.HeatTestCase): # Delete the resource data for secret_key, to test that existing # stacks which don't have the resource_data stored will continue # working via retrieving the keypair from keystone - db_api.resource_data_delete(rsrc, 'credential_id') - db_api.resource_data_delete(rsrc, 'secret_key') - rs_data = db_api.resource_data_get_all(rsrc) + resource_data_object.ResourceData.delete(rsrc, 'credential_id') + resource_data_object.ResourceData.delete(rsrc, 'secret_key') + rs_data = resource_data_object.ResourceData.get_all(rsrc) self.assertEqual(0, len(rs_data.keys())) rsrc._secret = None