Implement barbican client plugin
This moves the client creation code out of a Clients subclass into its own client plugin. Barbican is not an integrated project so the plugin is not registered if barbicanclient cannot be imported. The code which prevented client errors in _resolve_attribute from being raised has been removed. This will prevent invalid attribute values from being memoized. The base package has been renamed to heat_barbican since stevedore is used for client plugin loading and the base package will be installed by setuptools, the package barbican might clash with the actual Barbican project. Change-Id: I5788fb4618fef0d1c3e39cc98094bb2813e842c5
This commit is contained in:
parent
23893088f1
commit
fd191b7e48
@ -11,7 +11,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from heat.engine import clients as heat_clients
|
from heat.engine.clients import client_plugin
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -22,9 +22,12 @@ except ImportError:
|
|||||||
auth = None
|
auth = None
|
||||||
|
|
||||||
|
|
||||||
class Clients(heat_clients.OpenStackClients):
|
class BarbicanClientPlugin(client_plugin.ClientPlugin):
|
||||||
|
|
||||||
def _barbican(self):
|
def _create(self):
|
||||||
keystone_client = self.client('keystone').client
|
|
||||||
|
keystone_client = self.clients('keystone').client
|
||||||
auth_plugin = auth.KeystoneAuthV2(keystone=keystone_client)
|
auth_plugin = auth.KeystoneAuthV2(keystone=keystone_client)
|
||||||
return barbican_client.Client(auth_plugin=auth_plugin)
|
client = barbican_client.Client(auth_plugin=auth_plugin)
|
||||||
|
|
||||||
|
return client
|
@ -15,12 +15,13 @@ import six
|
|||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.engine import attributes
|
from heat.engine import attributes
|
||||||
|
from heat.engine import clients
|
||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
from heat.engine import properties
|
from heat.engine import properties
|
||||||
from heat.engine import resource
|
from heat.engine import resource
|
||||||
from heat.openstack.common import log as logging
|
from heat.openstack.common import log as logging
|
||||||
|
|
||||||
from .. import clients # noqa
|
from .. import client # noqa
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -104,10 +105,6 @@ class Order(resource.Resource):
|
|||||||
SECRET_REF: attributes.Schema(_('The URI to the created secret.')),
|
SECRET_REF: attributes.Schema(_('The URI to the created secret.')),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name, json_snippet, stack):
|
|
||||||
super(Order, self).__init__(name, json_snippet, stack)
|
|
||||||
self.clients = clients.Clients(self.context)
|
|
||||||
|
|
||||||
def barbican(self):
|
def barbican(self):
|
||||||
return self.clients.client('barbican')
|
return self.clients.client('barbican')
|
||||||
|
|
||||||
@ -136,7 +133,7 @@ class Order(resource.Resource):
|
|||||||
try:
|
try:
|
||||||
self.barbican().orders.delete(self.resource_id)
|
self.barbican().orders.delete(self.resource_id)
|
||||||
self.resource_id_set(None)
|
self.resource_id_set(None)
|
||||||
except clients.barbican_client.HTTPClientError as exc:
|
except client.barbican_client.HTTPClientError as exc:
|
||||||
# This is the only exception the client raises
|
# This is the only exception the client raises
|
||||||
# Inspecting the message to see if it's a 'Not Found'
|
# Inspecting the message to see if it's a 'Not Found'
|
||||||
if 'Not Found' in six.text_type(exc):
|
if 'Not Found' in six.text_type(exc):
|
||||||
@ -145,13 +142,7 @@ class Order(resource.Resource):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def _resolve_attribute(self, name):
|
def _resolve_attribute(self, name):
|
||||||
try:
|
order = self.barbican().orders.get(self.resource_id)
|
||||||
order = self.barbican().orders.get(self.resource_id)
|
|
||||||
except clients.barbican_client.HTTPClientError as exc:
|
|
||||||
LOG.warn(_("Order '%(name)s' not found: %(exc)s") %
|
|
||||||
{'name': self.resource_id, 'exc': six.text_type(exc)})
|
|
||||||
return ''
|
|
||||||
|
|
||||||
return getattr(order, name)
|
return getattr(order, name)
|
||||||
|
|
||||||
|
|
||||||
@ -162,7 +153,7 @@ def resource_mapping():
|
|||||||
|
|
||||||
|
|
||||||
def available_resource_mapping():
|
def available_resource_mapping():
|
||||||
if not clients.barbican_client:
|
if not clients.has_client('barbican'):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
return resource_mapping()
|
return resource_mapping()
|
@ -15,12 +15,13 @@ import six
|
|||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.engine import attributes
|
from heat.engine import attributes
|
||||||
|
from heat.engine import clients
|
||||||
from heat.engine import constraints
|
from heat.engine import constraints
|
||||||
from heat.engine import properties
|
from heat.engine import properties
|
||||||
from heat.engine import resource
|
from heat.engine import resource
|
||||||
from heat.openstack.common import log as logging
|
from heat.openstack.common import log as logging
|
||||||
|
|
||||||
from .. import clients # noqa
|
from .. import client # noqa
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -107,10 +108,6 @@ class Secret(resource.Resource):
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, name, json_snippet, stack):
|
|
||||||
super(Secret, self).__init__(name, json_snippet, stack)
|
|
||||||
self.clients = clients.Clients(self.context)
|
|
||||||
|
|
||||||
def barbican(self):
|
def barbican(self):
|
||||||
return self.clients.client('barbican')
|
return self.clients.client('barbican')
|
||||||
|
|
||||||
@ -141,7 +138,7 @@ class Secret(resource.Resource):
|
|||||||
try:
|
try:
|
||||||
self.barbican().secrets.delete(self.resource_id)
|
self.barbican().secrets.delete(self.resource_id)
|
||||||
self.resource_id_set(None)
|
self.resource_id_set(None)
|
||||||
except clients.barbican_client.HTTPClientError as exc:
|
except client.barbican_client.HTTPClientError as exc:
|
||||||
# This is the only exception the client raises
|
# This is the only exception the client raises
|
||||||
# Inspecting the message to see if it's a 'Not Found'
|
# Inspecting the message to see if it's a 'Not Found'
|
||||||
if 'Not Found' in six.text_type(exc):
|
if 'Not Found' in six.text_type(exc):
|
||||||
@ -150,19 +147,13 @@ class Secret(resource.Resource):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def _resolve_attribute(self, name):
|
def _resolve_attribute(self, name):
|
||||||
try:
|
if name == self.DECRYPTED_PAYLOAD:
|
||||||
if name == self.DECRYPTED_PAYLOAD:
|
return self.barbican().secrets.decrypt(
|
||||||
return self.barbican().secrets.decrypt(
|
self.resource_id)
|
||||||
self.resource_id)
|
|
||||||
|
|
||||||
secret = self.barbican().secrets.get(self.resource_id)
|
secret = self.barbican().secrets.get(self.resource_id)
|
||||||
if name == self.STATUS:
|
if name == self.STATUS:
|
||||||
return secret.status
|
return secret.status
|
||||||
except clients.barbican_client.HTTPClientError as e:
|
|
||||||
msg = _("Failed to resolve '%(name)s' for %(res)s '%(id)s': %(e)s")
|
|
||||||
LOG.warn(msg % {'name': name, 'res': self.__class__.__name__,
|
|
||||||
'id': self.resource_id, 'e': six.text_type(e)})
|
|
||||||
return ''
|
|
||||||
|
|
||||||
|
|
||||||
def resource_mapping():
|
def resource_mapping():
|
||||||
@ -172,7 +163,7 @@ def resource_mapping():
|
|||||||
|
|
||||||
|
|
||||||
def available_resource_mapping():
|
def available_resource_mapping():
|
||||||
if not clients.barbican_client:
|
if not clients.has_client('barbican'):
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
return resource_mapping()
|
return resource_mapping()
|
@ -22,9 +22,9 @@ from heat.engine import scheduler
|
|||||||
from heat.tests.common import HeatTestCase
|
from heat.tests.common import HeatTestCase
|
||||||
from heat.tests import utils
|
from heat.tests import utils
|
||||||
|
|
||||||
|
from .. import client # noqa
|
||||||
from ..resources import order # noqa
|
from ..resources import order # noqa
|
||||||
|
|
||||||
|
|
||||||
stack_template = '''
|
stack_template = '''
|
||||||
heat_template_version: 2013-05-23
|
heat_template_version: 2013-05-23
|
||||||
description: Test template
|
description: Test template
|
||||||
@ -94,17 +94,16 @@ class TestOrder(HeatTestCase):
|
|||||||
self.assertEqual('test-order-ref', res.FnGetAtt('order_ref'))
|
self.assertEqual('test-order-ref', res.FnGetAtt('order_ref'))
|
||||||
self.assertEqual('test-secret-ref', res.FnGetAtt('secret_ref'))
|
self.assertEqual('test-secret-ref', res.FnGetAtt('secret_ref'))
|
||||||
|
|
||||||
@mock.patch.object(order.clients, 'barbican_client', new=mock.Mock())
|
@mock.patch.object(client, 'barbican_client', new=mock.Mock())
|
||||||
def test_attributes_handle_exceptions(self):
|
def test_attributes_handle_exceptions(self):
|
||||||
mock_order = mock.Mock()
|
mock_order = mock.Mock()
|
||||||
self.barbican.orders.get.return_value = mock_order
|
self.barbican.orders.get.return_value = mock_order
|
||||||
res = self._create_resource('foo', self.res_template, self.stack)
|
res = self._create_resource('foo', self.res_template, self.stack)
|
||||||
|
|
||||||
order.clients.barbican_client.HTTPClientError = Exception
|
client.barbican_client.HTTPClientError = Exception
|
||||||
not_found_exc = order.clients.barbican_client.HTTPClientError('boom')
|
self.barbican.orders.get.side_effect = Exception('boom')
|
||||||
self.barbican.orders.get.side_effect = not_found_exc
|
self.assertRaises(client.barbican_client.HTTPClientError,
|
||||||
|
res.FnGetAtt, 'order_ref')
|
||||||
self.assertEqual('', res.FnGetAtt('order_ref'))
|
|
||||||
|
|
||||||
def test_create_order_sets_resource_id(self):
|
def test_create_order_sets_resource_id(self):
|
||||||
self.barbican.orders.create.return_value = 'foo'
|
self.barbican.orders.create.return_value = 'foo'
|
||||||
@ -147,22 +146,22 @@ class TestOrder(HeatTestCase):
|
|||||||
self.assertIsNone(res.resource_id)
|
self.assertIsNone(res.resource_id)
|
||||||
self.barbican.orders.delete.assert_called_once_with('foo')
|
self.barbican.orders.delete.assert_called_once_with('foo')
|
||||||
|
|
||||||
@mock.patch.object(order.clients, 'barbican_client', new=mock.Mock())
|
@mock.patch.object(client, 'barbican_client', new=mock.Mock())
|
||||||
def test_handle_delete_ignores_not_found_errors(self):
|
def test_handle_delete_ignores_not_found_errors(self):
|
||||||
res = self._create_resource('foo', self.res_template, self.stack)
|
res = self._create_resource('foo', self.res_template, self.stack)
|
||||||
|
|
||||||
order.clients.barbican_client.HTTPClientError = Exception
|
client.barbican_client.HTTPClientError = Exception
|
||||||
exc = order.clients.barbican_client.HTTPClientError('Not Found. Nope.')
|
exc = client.barbican_client.HTTPClientError('Not Found. Nope.')
|
||||||
self.barbican.orders.delete.side_effect = exc
|
self.barbican.orders.delete.side_effect = exc
|
||||||
scheduler.TaskRunner(res.delete)()
|
scheduler.TaskRunner(res.delete)()
|
||||||
self.assertTrue(self.barbican.orders.delete.called)
|
self.assertTrue(self.barbican.orders.delete.called)
|
||||||
|
|
||||||
@mock.patch.object(order.clients, 'barbican_client', new=mock.Mock())
|
@mock.patch.object(client, 'barbican_client', new=mock.Mock())
|
||||||
def test_handle_delete_raises_resource_failure_on_error(self):
|
def test_handle_delete_raises_resource_failure_on_error(self):
|
||||||
res = self._create_resource('foo', self.res_template, self.stack)
|
res = self._create_resource('foo', self.res_template, self.stack)
|
||||||
|
|
||||||
order.clients.barbican_client.HTTPClientError = Exception
|
client.barbican_client.HTTPClientError = Exception
|
||||||
exc = order.clients.barbican_client.HTTPClientError('Boom.')
|
exc = client.barbican_client.HTTPClientError('Boom.')
|
||||||
self.barbican.orders.delete.side_effect = exc
|
self.barbican.orders.delete.side_effect = exc
|
||||||
exc = self.assertRaises(exception.ResourceFailure,
|
exc = self.assertRaises(exception.ResourceFailure,
|
||||||
scheduler.TaskRunner(res.delete))
|
scheduler.TaskRunner(res.delete))
|
@ -22,9 +22,9 @@ from heat.engine import scheduler
|
|||||||
from heat.tests.common import HeatTestCase
|
from heat.tests.common import HeatTestCase
|
||||||
from heat.tests import utils
|
from heat.tests import utils
|
||||||
|
|
||||||
|
from .. import client # noqa
|
||||||
from ..resources import secret # noqa
|
from ..resources import secret # noqa
|
||||||
|
|
||||||
|
|
||||||
stack_template = '''
|
stack_template = '''
|
||||||
heat_template_version: 2013-05-23
|
heat_template_version: 2013-05-23
|
||||||
description: Test template
|
description: Test template
|
||||||
@ -83,13 +83,12 @@ class TestSecret(HeatTestCase):
|
|||||||
self.assertEqual('test-status', self.res.FnGetAtt('status'))
|
self.assertEqual('test-status', self.res.FnGetAtt('status'))
|
||||||
self.assertEqual('foo', self.res.FnGetAtt('decrypted_payload'))
|
self.assertEqual('foo', self.res.FnGetAtt('decrypted_payload'))
|
||||||
|
|
||||||
@mock.patch.object(secret.clients, 'barbican_client', new=mock.Mock())
|
@mock.patch.object(client, 'barbican_client', new=mock.Mock())
|
||||||
def test_attributes_handles_exceptions(self):
|
def test_attributes_handles_exceptions(self):
|
||||||
secret.clients.barbican_client.HTTPClientError = Exception
|
client.barbican_client.HTTPClientError = Exception
|
||||||
some_error = secret.clients.barbican_client.HTTPClientError('boom')
|
self.barbican.secrets.get.side_effect = Exception('boom')
|
||||||
secret.Secret.barbican.side_effect = some_error
|
self.assertRaises(client.barbican_client.HTTPClientError,
|
||||||
|
self.res.FnGetAtt, 'order_ref')
|
||||||
self.assertEqual('', self.res.FnGetAtt('status'))
|
|
||||||
|
|
||||||
def test_create_secret_sets_resource_id(self):
|
def test_create_secret_sets_resource_id(self):
|
||||||
self.assertEqual('foo_id', self.res.resource_id)
|
self.assertEqual('foo_id', self.res.resource_id)
|
||||||
@ -164,18 +163,18 @@ class TestSecret(HeatTestCase):
|
|||||||
self.assertIsNone(self.res.resource_id)
|
self.assertIsNone(self.res.resource_id)
|
||||||
mock_delete.assert_called_once_with('foo_id')
|
mock_delete.assert_called_once_with('foo_id')
|
||||||
|
|
||||||
@mock.patch.object(secret.clients, 'barbican_client', new=mock.Mock())
|
@mock.patch.object(client, 'barbican_client', new=mock.Mock())
|
||||||
def test_handle_delete_ignores_not_found_errors(self):
|
def test_handle_delete_ignores_not_found_errors(self):
|
||||||
secret.clients.barbican_client.HTTPClientError = Exception
|
client.barbican_client.HTTPClientError = Exception
|
||||||
exc = secret.clients.barbican_client.HTTPClientError('Not Found.')
|
exc = client.barbican_client.HTTPClientError('Not Found.')
|
||||||
self.barbican.secrets.delete.side_effect = exc
|
self.barbican.secrets.delete.side_effect = exc
|
||||||
scheduler.TaskRunner(self.res.delete)()
|
scheduler.TaskRunner(self.res.delete)()
|
||||||
self.assertTrue(self.barbican.secrets.delete.called)
|
self.assertTrue(self.barbican.secrets.delete.called)
|
||||||
|
|
||||||
@mock.patch.object(secret.clients, 'barbican_client', new=mock.Mock())
|
@mock.patch.object(client, 'barbican_client', new=mock.Mock())
|
||||||
def test_handle_delete_raises_resource_failure_on_error(self):
|
def test_handle_delete_raises_resource_failure_on_error(self):
|
||||||
secret.clients.barbican_client.HTTPClientError = Exception
|
client.barbican_client.HTTPClientError = Exception
|
||||||
exc = secret.clients.barbican_client.HTTPClientError('Boom.')
|
exc = client.barbican_client.HTTPClientError('Boom.')
|
||||||
self.barbican.secrets.delete.side_effect = exc
|
self.barbican.secrets.delete.side_effect = exc
|
||||||
exc = self.assertRaises(exception.ResourceFailure,
|
exc = self.assertRaises(exception.ResourceFailure,
|
||||||
scheduler.TaskRunner(self.res.delete))
|
scheduler.TaskRunner(self.res.delete))
|
@ -17,10 +17,13 @@ classifier =
|
|||||||
Programming Language :: Python :: 2.7
|
Programming Language :: Python :: 2.7
|
||||||
Programming Language :: Python :: 2.6
|
Programming Language :: Python :: 2.6
|
||||||
|
|
||||||
|
packages =
|
||||||
|
heat_barbican
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
# Copy to /usr/lib/heat for plugin loading
|
# Copy to /usr/lib/heat for plugin loading
|
||||||
data_files =
|
data_files =
|
||||||
lib/heat/barbican = barbican/resources/*
|
lib/heat/barbican = heat_barbican/resources/*
|
||||||
|
|
||||||
[global]
|
[global]
|
||||||
setup-hooks =
|
setup-hooks =
|
Loading…
Reference in New Issue
Block a user