Port all resources to new resource data methods

Change-Id: I9f7e984f5224cee16a2ffd3e9d6b118304766701
Related-Bug: #1306743
This commit is contained in:
Steve Baker 2014-04-18 15:42:31 +12:00
parent 7383f40eb0
commit 9bd4f3fcc5
16 changed files with 86 additions and 152 deletions

View File

@ -15,8 +15,6 @@
import copy
from heat.common import exception
from heat.db.sqlalchemy import api as db_api
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
@ -535,7 +533,7 @@ class WebHook(resource.Resource):
key = rel_to_key.get(link['rel'])
if key is not None:
url = link['href'].encode('utf-8')
db_api.resource_data_set(self, key, url)
self.data_set(key, url)
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
asclient = self.stack.clients.auto_scale()
@ -544,9 +542,10 @@ class WebHook(resource.Resource):
asclient.replace_webhook(**args)
def _resolve_attribute(self, key):
try:
return db_api.resource_data_get(self, key).decode('utf-8')
except exception.NotFound:
v = self.data().get(key)
if v is not None:
return v.decode('utf-8')
else:
return None
def handle_delete(self):

View File

@ -19,7 +19,6 @@ from Crypto.PublicKey import RSA
import paramiko
from heat.common import exception
from heat.db.sqlalchemy import api as db_api
from heat.engine import properties
from heat.engine.resources import nova_utils
from heat.engine.resources import server
@ -141,7 +140,6 @@ bash -x /var/lib/cloud/data/cfn-userdata > /root/cfn-userdata.log 2>&1 ||
def __init__(self, name, json_snippet, stack):
super(CloudServer, self).__init__(name, json_snippet, stack)
self.stack = stack
self._private_key = None
self._server = None
self._distro = None
self._image = None
@ -196,18 +194,13 @@ bash -x /var/lib/cloud/data/cfn-userdata > /root/cfn-userdata.log 2>&1 ||
@property
def private_key(self):
"""Return the private SSH key for the resource."""
if self._private_key is not None:
return self._private_key
if self.id is not None:
self._private_key = db_api.resource_data_get(self, 'private_key')
return self._private_key
return self.data().get('private_key')
@private_key.setter
def private_key(self, private_key):
"""Save the resource's private SSH key to the database."""
self._private_key = private_key
if self.id is not None:
db_api.resource_data_set(self, 'private_key', private_key, True)
self.data_set('private_key', private_key, True)
@property
def has_userdata(self):
@ -320,8 +313,8 @@ bash -x /var/lib/cloud/data/cfn-userdata > /root/cfn-userdata.log 2>&1 ||
def _personality(self):
# Generate SSH public/private keypair for the engine to use
if self._private_key is not None:
rsa = RSA.importKey(self._private_key)
if self.private_key is not None:
rsa = RSA.importKey(self.private_key)
else:
rsa = RSA.generate(1024)
self.private_key = rsa.exportKey()
@ -473,12 +466,7 @@ bash -x /var/lib/cloud/data/cfn-userdata > /root/cfn-userdata.log 2>&1 ||
if name == 'privateIPv4':
return nova_utils.get_ip(self.server, 'private', 4)
if name == 'admin_pass':
try:
return db_api.resource_data_get(self, self.ADMIN_PASS)
except exception.NotFound:
logger.info(_('Administrator password not'
'found for server: %s') % self.name)
return ''
return self.data().get(self.ADMIN_PASS, '')
return super(CloudServer, self)._resolve_attribute(name)
def handle_create(self):
@ -488,9 +476,9 @@ bash -x /var/lib/cloud/data/cfn-userdata > /root/cfn-userdata.log 2>&1 ||
# "enable_instance_password" config option is turned off
if (self.properties.get(self.SAVE_ADMIN_PASS) and
hasattr(server, 'adminPass') and server.adminPass):
db_api.resource_data_set(self, self.ADMIN_PASS,
server.adminPass,
redact=True)
self.data_set(self.ADMIN_PASS,
server.adminPass,
redact=True)
return server

View File

@ -950,7 +950,7 @@ class CloudServersTest(HeatTestCase):
self.m.VerifyAll()
@mock.patch.object(clients.OpenStackClients, 'nova')
@mock.patch.object(cloud_server.db_api, 'resource_data_set')
@mock.patch.object(resource.Resource, 'data_set')
def test_create_store_admin_pass_resource_data(self,
mock_data_set,
mock_nova):
@ -971,12 +971,12 @@ class CloudServersTest(HeatTestCase):
self.fc.servers.create = mock.Mock(return_value=return_server)
scheduler.TaskRunner(server.create)()
expected_call = mock.call(mock.ANY, server.ADMIN_PASS,
expected_call = mock.call(server.ADMIN_PASS,
'autogenerated', redact=True)
self.assertIn(expected_call, mock_data_set.call_args_list)
@mock.patch.object(clients.OpenStackClients, 'nova')
@mock.patch.object(cloud_server.db_api, 'resource_data_set')
@mock.patch.object(resource.Resource, 'data_set')
def test_create_save_admin_pass_is_false(self,
mock_data_set,
mock_nova):
@ -1002,7 +1002,7 @@ class CloudServersTest(HeatTestCase):
self.assertNotIn(expected_call, mock_data_set.call_args_list)
@mock.patch.object(clients.OpenStackClients, 'nova')
@mock.patch.object(cloud_server.db_api, 'resource_data_set')
@mock.patch.object(resource.Resource, 'data_set')
def test_create_save_admin_pass_defaults_to_false(self,
mock_data_set,
mock_nova):
@ -1028,7 +1028,7 @@ class CloudServersTest(HeatTestCase):
self.assertNotIn(expected_call, mock_data_set.call_args_list)
@mock.patch.object(clients.OpenStackClients, 'nova')
@mock.patch.object(cloud_server.db_api, 'resource_data_set')
@mock.patch.object(resource.Resource, 'data_set')
def test_create_without_adminPass_attribute(self,
mock_data_set,
mock_nova):
@ -1051,9 +1051,9 @@ class CloudServersTest(HeatTestCase):
mock.ANY, redact=mock.ANY)
self.assertNotIn(expected_call, mock_data_set.call_args_list)
@mock.patch.object(cloud_server.db_api, 'resource_data_get')
@mock.patch.object(resource.Resource, 'data')
def test_server_handles_server_without_password(self, mock_data_get):
mock_data_get.side_effect = exception.NotFound('foo')
mock_data_get.return_value = {}
stack_name = 'admin_pass_s'
(t, stack) = self._setup_test_stack(stack_name)
@ -1061,9 +1061,9 @@ class CloudServersTest(HeatTestCase):
t['Resources']['WebServer'], stack)
self.assertEqual('', server.FnGetAtt('admin_pass'))
@mock.patch.object(cloud_server.db_api, 'resource_data_get')
@mock.patch.object(resource.Resource, 'data')
def test_server_has_admin_pass_attribute_available(self, mock_data_get):
mock_data_get.return_value = 'foo'
mock_data_get.return_value = {'admin_pass': 'foo'}
stack_name = 'admin_pass_s'
(t, stack) = self._setup_test_stack(stack_name)

View File

@ -465,7 +465,7 @@ class Resource(object):
'action': self.action,
'status': self.status,
'metadata': self.metadata,
'resource_data': db_api.resource_data_get_all(self)
'resource_data': self.data()
}
def adopt(self, resource_data):

View File

@ -12,7 +12,6 @@
# under the License.
from heat.common import exception
from heat.db import api as db_api
from heat.engine import clients
from heat.engine import constraints
from heat.engine import properties
@ -582,12 +581,12 @@ class LoadBalancer(resource.Resource):
'pool_id': pool,
'address': address,
'protocol_port': protocol_port}})['member']
db_api.resource_data_set(self, member, lb_member['id'])
self.data_set(member, lb_member['id'])
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
if self.MEMBERS in prop_diff:
members = set(prop_diff[self.MEMBERS])
rd_members = db_api.resource_data_get_all(self)
rd_members = self.data()
old_members = set(rd_members.keys())
client = self.neutron()
for member in old_members - members:
@ -597,7 +596,7 @@ class LoadBalancer(resource.Resource):
except NeutronClientException as ex:
if ex.status_code != 404:
raise ex
db_api.resource_data_delete(self, member)
self.data_delete(member)
pool = self.properties[self.POOL_ID]
nova_client = self.nova()
protocol_port = self.properties[self.PROTOCOL_PORT]
@ -608,18 +607,18 @@ class LoadBalancer(resource.Resource):
'pool_id': pool,
'address': address,
'protocol_port': protocol_port}})['member']
db_api.resource_data_set(self, member, lb_member['id'])
self.data_set(member, lb_member['id'])
def handle_delete(self):
client = self.neutron()
for member in self.properties.get(self.MEMBERS):
member_id = db_api.resource_data_get(self, member)
member_id = self.data().get(member)
try:
client.delete_member(member_id)
except NeutronClientException as ex:
if ex.status_code != 404:
raise ex
db_api.resource_data_delete(self, member)
self.data_delete(member)
def resource_mapping():

View File

@ -14,7 +14,6 @@
from novaclient import exceptions as nova_exceptions
from heat.common import exception
from heat.db import api as db_api
from heat.engine.clients import Clients
from heat.engine import properties
from heat.engine import resource
@ -72,20 +71,15 @@ class KeyPair(resource.Resource):
def __init__(self, name, json_snippet, stack):
super(KeyPair, self).__init__(name, json_snippet, stack)
self._private_key = None
self._public_key = None
@property
def private_key(self):
"""Return the private SSH key for the resource."""
if (self._private_key is None and self.id and
self.properties[self.SAVE_PRIVATE_KEY]):
try:
self._private_key = db_api.resource_data_get(self,
'private_key')
except exception.NotFound:
pass
return self._private_key or ""
if self.properties[self.SAVE_PRIVATE_KEY]:
return self.data().get('private_key', '')
else:
return ''
@property
def public_key(self):
@ -105,9 +99,9 @@ class KeyPair(resource.Resource):
public_key=pub_key)
if (self.properties[self.SAVE_PRIVATE_KEY] and
hasattr(new_keypair, 'private_key')):
db_api.resource_data_set(self, 'private_key',
new_keypair.private_key,
True)
self.data_set('private_key',
new_keypair.private_key,
True)
self.resource_id_set(new_keypair.id)
def handle_delete(self):

View File

@ -16,7 +16,6 @@ import string
from six.moves import xrange
from heat.db import api as db_api
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
@ -86,12 +85,12 @@ class RandomString(resource.Resource):
length = self.properties.get(self.LENGTH)
sequence = self._sequences[self.properties.get(self.SEQUENCE)]
random_string = self._generate_random_string(sequence, length)
db_api.resource_data_set(self, 'value', random_string, redact=True)
self.data_set('value', random_string, redact=True)
self.resource_id_set(random_string)
def _resolve_attribute(self, name):
if name == 'value':
return db_api.resource_data_get(self, 'value')
return self.data().get('value')
def resource_mapping():

View File

@ -17,7 +17,6 @@ from oslo.config import cfg
import uuid
from heat.common import exception
from heat.db import api as db_api
from heat.engine import clients
from heat.engine import constraints
from heat.engine import properties
@ -404,34 +403,22 @@ class Server(stack_user.StackUser):
@property
def access_key(self):
try:
return db_api.resource_data_get(self, 'access_key')
except exception.NotFound:
pass
return self.data().get('access_key')
@property
def secret_key(self):
try:
return db_api.resource_data_get(self, 'secret_key')
except exception.NotFound:
pass
return self.data().get('secret_key')
@property
def password(self):
try:
return db_api.resource_data_get(self, 'password')
except exception.NotFound:
pass
return self.data().get('password')
@password.setter
def password(self, password):
try:
if password is None:
db_api.resource_data_delete(self, 'password')
else:
db_api.resource_data_set(self, 'password', password, True)
except exception.NotFound:
pass
if password is None:
self.data_delete('password')
else:
self.data_set('password', password, True)
@property
def metadata(self):

View File

@ -19,7 +19,6 @@ import uuid
import heatclient.exc as heat_exp
from heat.common import exception
from heat.db import api as db_api
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
@ -353,20 +352,14 @@ class SoftwareDeployment(signal_responder.SignalResponder):
@property
def password(self):
try:
return db_api.resource_data_get(self, 'password')
except exception.NotFound:
pass
return self.data().get('password')
@password.setter
def password(self, password):
try:
if password is None:
db_api.resource_data_delete(self, 'password')
else:
db_api.resource_data_set(self, 'password', password, True)
except exception.NotFound:
pass
if password is None:
self.data_delete('password')
else:
self.data_set('password', password, True)
def check_create_complete(self, sd):
return self._check_complete(sd)

View File

@ -12,7 +12,6 @@
# under the License.
from heat.common import exception
from heat.db import api as db_api
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
@ -191,8 +190,8 @@ class AccessKey(resource.Resource):
# Store the secret key, encrypted, in the DB so we don't have lookup
# the user every time someone requests the SecretAccessKey attribute
db_api.resource_data_set(self, 'secret_key', kp.secret, redact=True)
db_api.resource_data_set(self, 'credential_id', kp.id, redact=True)
self.data_set('secret_key', kp.secret, redact=True)
self.data_set('credential_id', kp.id, redact=True)
def handle_delete(self):
self._secret = None
@ -219,20 +218,17 @@ class AccessKey(resource.Resource):
# First try to retrieve the secret from resource_data, but
# for backwards compatibility, fall back to requesting from
# keystone
try:
self._secret = db_api.resource_data_get(self, 'secret_key')
except exception.NotFound:
self._secret = self.data().get('secret_key')
if self._secret is None:
try:
user_id = self._get_user().resource_id
kp = self.keystone().get_ec2_keypair(
user_id=user_id, access=self.resource_id)
self._secret = kp.secret
# Store the key in resource_data
db_api.resource_data_set(self, 'secret_key',
kp.secret, redact=True)
self.data_set('secret_key', kp.secret, redact=True)
# And the ID of the v3 credential
db_api.resource_data_set(self, 'credential_id',
kp.id, redact=True)
self.data_set('credential_id', kp.id, redact=True)
except Exception as ex:
logger.warn(
_('could not get secret for %(username)s '

View File

@ -15,8 +15,6 @@ from keystoneclient.contrib.ec2 import utils as ec2_utils
from oslo.config import cfg
from six.moves.urllib import parse as urlparse
from heat.common import exception
from heat.db import api as db_api
from heat.engine import stack_user
from heat.openstack.common.gettextutils import _
from heat.openstack.common import log as logging
@ -48,10 +46,7 @@ class SignalResponder(stack_user.StackUser):
self._delete_signed_url()
def _delete_signed_url(self):
try:
db_api.resource_data_delete(self, 'ec2_signed_url')
except exception.NotFound:
pass
self.data_delete('ec2_signed_url')
def _get_signed_url(self, signal_type=SIGNAL):
"""Create properly formatted and pre-signed URL.
@ -62,17 +57,14 @@ class SignalResponder(stack_user.StackUser):
:param signal_type: either WAITCONDITION or SIGNAL.
"""
try:
stored = db_api.resource_data_get(self, 'ec2_signed_url')
except exception.NotFound:
stored = None
stored = self.data().get('ec2_signed_url')
if stored is not None:
return stored
try:
access_key = db_api.resource_data_get(self, 'access_key')
secret_key = db_api.resource_data_get(self, 'secret_key')
except exception.NotFound:
access_key = self.data().get('access_key')
secret_key = self.data().get('secret_key')
if not access_key or not secret_key:
logger.warning(_('Cannot generate signed url, '
'no stored access/secret key'))
return
@ -105,5 +97,5 @@ class SignalResponder(stack_user.StackUser):
url = "%s%s?%s" % (signal_url.lower(),
path, qs)
db_api.resource_data_set(self, 'ec2_signed_url', url)
self.data_set('ec2_signed_url', url)
return url

View File

@ -14,7 +14,6 @@
import keystoneclient.exceptions as kc_exception
from heat.common import exception
from heat.db import api as db_api
from heat.engine import resource
from heat.openstack.common.gettextutils import _
from heat.openstack.common import log as logging
@ -49,19 +48,20 @@ class StackUser(resource.Resource):
project_id=self.stack.stack_user_project_id)
# Store the ID in resource data, for compatibility with SignalResponder
db_api.resource_data_set(self, 'user_id', user_id)
self.data_set('user_id', user_id)
def _get_user_id(self):
try:
return db_api.resource_data_get(self, 'user_id')
except exception.NotFound:
user_id = self.data().get('user_id')
if user_id:
return user_id
else:
# FIXME(shardy): This is a legacy hack for backwards compatibility
# remove after an appropriate transitional period...
# Assume this is a resource that was created with
# a previous version of heat and that the resource_id
# is the user_id
if self.resource_id:
db_api.resource_data_set(self, 'user_id', self.resource_id)
self.data_set('user_id', self.resource_id)
return self.resource_id
def handle_delete(self):
@ -87,10 +87,7 @@ class StackUser(resource.Resource):
except kc_exception.NotFound:
pass
for data_key in ('credential_id', 'access_key', 'secret_key'):
try:
db_api.resource_data_delete(self, data_key)
except exception.NotFound:
pass
self.data_delete(data_key)
def handle_suspend(self):
user_id = self._get_user_id()
@ -121,21 +118,17 @@ class StackUser(resource.Resource):
raise exception.Error(_("Error creating ec2 keypair for user %s") %
user_id)
else:
db_api.resource_data_set(self, 'credential_id', kp.id,
redact=True)
db_api.resource_data_set(self, 'access_key', kp.access,
redact=True)
db_api.resource_data_set(self, 'secret_key', kp.secret,
redact=True)
self.data_set('credential_id', kp.id, redact=True)
self.data_set('access_key', kp.access, redact=True)
self.data_set('secret_key', kp.secret, redact=True)
return kp
def _delete_keypair(self):
# Subclasses may optionally call this to delete a keypair created
# via _create_keypair
user_id = self._get_user_id()
try:
credential_id = db_api.resource_data_get(self, 'credential_id')
except exception.NotFound:
credential_id = self.data().get('credential_id')
if not credential_id:
return
try:
@ -147,7 +140,4 @@ class StackUser(resource.Resource):
user_id=user_id, credential_id=credential_id)
for data_key in ('access_key', 'secret_key', 'credential_id'):
try:
db_api.resource_data_delete(self, data_key)
except exception.NotFound:
pass
self.data_delete(data_key)

View File

@ -166,9 +166,7 @@ class ResourceTest(HeatTestCase):
def test_abandon_with_resource_data(self):
tmpl = {'Type': 'Foo'}
res = generic_rsrc.GenericResource('test_resource', tmpl, self.stack)
self.m.StubOutWithMock(db_api, 'resource_data_get_all')
db_api.resource_data_get_all(res).AndReturn({"test-key": "test-value"})
self.m.ReplayAll()
res._data = {"test-key": "test-value"}
expected = {
'action': 'INIT',
@ -181,7 +179,6 @@ class ResourceTest(HeatTestCase):
}
actual = res.prepare_abandon()
self.assertEqual(expected, actual)
self.m.VerifyAll()
def test_state_set_invalid(self):
tmpl = {'Type': 'Foo'}

View File

@ -629,7 +629,7 @@ class ServersTest(HeatTestCase):
'os-collect-config': {
'heat': {
'auth_url': 'http://server.test:5000/v2.0',
'password': None,
'password': server.password,
'project_id': '8888',
'resource_name': 'WebServer',
'stack_id': 'software_config_s/%s' % stack.id,

View File

@ -293,9 +293,9 @@ class StackUserTest(HeatTestCase):
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
db_api.resource_data_set(rsrc, 'credential_id', 'acredential')
db_api.resource_data_set(rsrc, 'access_key', 'access123')
db_api.resource_data_set(rsrc, 'secret_key', 'verysecret')
rsrc.data_set('credential_id', 'acredential')
rsrc.data_set('access_key', 'access123')
rsrc.data_set('secret_key', 'verysecret')
rsrc._delete_keypair()
rs_data = db_api.resource_data_get_all(rsrc)
self.assertEqual({'user_id': 'auserdel'}, rs_data)
@ -325,9 +325,9 @@ class StackUserTest(HeatTestCase):
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
db_api.resource_data_set(rsrc, 'credential_id', 'acredential')
db_api.resource_data_set(rsrc, 'access_key', 'access123')
db_api.resource_data_set(rsrc, 'secret_key', 'verysecret')
rsrc.data_set('credential_id', 'acredential')
rsrc.data_set('access_key', 'access123')
rsrc.data_set('secret_key', 'verysecret')
rsrc._delete_keypair()
rs_data = db_api.resource_data_get_all(rsrc)
self.assertEqual({'user_id': 'auserdel'}, rs_data)
@ -347,7 +347,7 @@ class StackUserTest(HeatTestCase):
scheduler.TaskRunner(rsrc.create)()
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
db_api.resource_data_set(rsrc, 'credential_id', 'acredential')
rsrc.data_set('credential_id', 'acredential')
rsrc._delete_keypair()
rs_data = db_api.resource_data_get_all(rsrc)
self.assertEqual({'user_id': 'auserdel'}, rs_data)

View File

@ -443,7 +443,7 @@ class WaitConditionHandleTest(HeatTestCase):
rsrc = self.stack['WaitHandle']
# clear the url
db_api.resource_data_set(rsrc, 'ec2_signed_url', None, False)
rsrc.data_set('ec2_signed_url', None, False)
rsrc.created_time = created_time
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)