diff --git a/requirements.txt b/requirements.txt
index 96d5c76..c3ebdd2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
-charm-tools
+#charm-tools
+git+https://github.com/juju/charm-tools#egg=charm-tools
 simplejson
diff --git a/src/actions/actions.py b/src/actions/actions.py
index fc390e8..880a175 100755
--- a/src/actions/actions.py
+++ b/src/actions/actions.py
@@ -24,10 +24,11 @@ basic.bootstrap_charm_deps()
 basic.init_config_states()
 
 import charms.reactive as reactive
-
 import charmhelpers.core.hookenv as hookenv
+import charms_openstack.charm
 
-import charm.openstack.barbican as barbican
+# import the barbican module to get the charm definitions created.
+import charm.openstack.barbican  # noqa
 
 
 def generate_mkek_action(*args):
@@ -41,7 +42,8 @@ def generate_mkek_action(*args):
             "Can't generate an MKEK in associated HSM because HSM is not "
             "available.")
         return
-    barbican.generate_mkek(hsm)
+    with charms_openstack.charm.provide_charm_instance as barbican_charm:
+        barbican_charm.generate_mkek(hsm)
 
 
 def generate_hmac_action(*args):
@@ -54,7 +56,8 @@ def generate_hmac_action(*args):
         hookenv.action_fail(
             "Can't generate an HMAC in associated HSM because HSM is not "
             "available.")
-    barbican.generate_hmac(hsm)
+    with charms_openstack.charm.provide_charm_instance as barbican_charm:
+        barbican_charm.generate_hmac(hsm)
 
 
 # Actions to function mapping, to allow for illegal python action names that
diff --git a/src/lib/charm/openstack/barbican.py b/src/lib/charm/openstack/barbican.py
index cc5e40b..5b10b9f 100644
--- a/src/lib/charm/openstack/barbican.py
+++ b/src/lib/charm/openstack/barbican.py
@@ -19,10 +19,7 @@ from __future__ import absolute_import
 
 import subprocess
 
-import charmhelpers.contrib.openstack.utils as ch_utils
 import charmhelpers.core.hookenv as hookenv
-import charmhelpers.core.unitdata as unitdata
-import charmhelpers.fetch
 
 import charms_openstack.charm
 import charms_openstack.adapters
@@ -38,158 +35,80 @@ BARBICAN_WSGI_CONF = '/etc/apache2/conf-available/barbican-api.conf'
 OPENSTACK_RELEASE_KEY = 'barbican-charm.openstack-release-version'
 
 
-###
-# Handler functions for events that are interesting to the Barbican charms
-
-def install():
-    """Use the singleton from the BarbicanCharm to install the packages on the
-    unit
-    """
-    unitdata.kv().unset(OPENSTACK_RELEASE_KEY)
-    BarbicanCharm.singleton.install()
-
-
-def setup_endpoint(keystone):
-    """When the keystone interface connects, register this unit in the keystone
-    catalogue.
-
-    :param keystone: instance of KeystoneRequires() class from i/f
-    """
-    charm = BarbicanCharm.singleton
-    keystone.register_endpoints(charm.service_type,
-                                charm.region,
-                                charm.public_url,
-                                charm.internal_url,
-                                charm.admin_url)
-
-
-def render_configs(interfaces_list):
-    """Using a list of interfaces, render the configs and, if they have
-    changes, restart the services on the unit.
-
-    :param interfaces_list: [RelationBase] interfaces from reactive
-    """
-    BarbicanCharm.singleton.render_with_interfaces(interfaces_list)
-
-
-def generate_mkek(hsm):
-    """Ask barbican to generate an MKEK in the backend store using the HSM.
-    This assumes that an HSM is available, and configured.  Uses the charm.
-    """
-    BarbicanCharm.singleton.action_generate_mkek(hsm)
-
-
-def generate_hmac(hsm):
-    """Ask barbican to generate an HMAC in the backend store using the HSM.
-    This assumes that an HSM is available, and configured.  Uses the charm.
-    """
-    BarbicanCharm.singleton.action_generate_hmac(hsm)
-
-
-def assess_status():
-    """Just call the BarbicanCharm.singleton.assess_status() command to update
-    status on the unit.
-    """
-    BarbicanCharm.singleton.assess_status()
-
-
-def configure_ssl(keystone=None):
-    """Use the singleton from the BarbicanCharm to configure ssl
-
-    :param keystone: KeystoneRequires() interface class
-    """
-    BarbicanCharm.singleton.configure_ssl(keystone)
+# select the default release function
+charms_openstack.charm.use_defaults('charm.default-select-release')
 
 
 ###
 # Implementation of the Barbican Charm classes
 
-class BarbicanConfigurationAdapter(
-        charms_openstack.adapters.APIConfigurationAdapter):
+# Add some properties to the configuration for templates/code to use with the
+# charm instance.  The config_validator is called when the configuration is
+# loaded, and the properties are to add those names to the config object.
 
-    def __init__(self, port_map=None):
-        super(BarbicanConfigurationAdapter, self).__init__(
-            service_name='barbican',
-            port_map=port_map)
-        if self.keystone_api_version not in ['2', '3', 'none']:
-            raise ValueError(
-                "Unsupported keystone-api-version ({}). It should be 2 or 3"
-                .format(self.keystone_api_version))
-
-    @property
-    def barbican_api_keystone_pipeline(self):
-        if self.keystone_api_version == "2":
-            return 'cors keystone_authtoken context apiapp'
-        else:
-            return 'cors keystone_v3_authtoken context apiapp'
-
-    @property
-    def barbican_api_pipeline(self):
-        return {
-            "2": "cors keystone_authtoken context apiapp",
-            "3": "cors keystone_v3_authtoken context apiapp",
-            "none": "cors unauthenticated-context apiapp"
-        }[self.keystone_api_version]
-
-    @property
-    def barbican_api_keystone_audit_pipeline(self):
-        if self.keystone_api_version == "2":
-            return 'keystone_authtoken context audit apiapp'
-        else:
-            return 'keystone_v3_authtoken context audit apiapp'
+@charms_openstack.adapters.config_property
+def validate_keystone_api_version(config):
+    if config.keystone_api_version not in ['2', '3', 'none']:
+        raise ValueError(
+            "Unsupported keystone-api-version ({}). It should be 2 or 3"
+            .format(config.keystone_api_version))
 
 
-class HSMAdapter(charms_openstack.adapters.OpenStackRelationAdapter):
-    """Adapt the barbican-hsm-plugin relation for use in rendering the config
-    for Barbican.  Note that the HSM relation is optional, so we have a class
-    variable 'exists' that we can test in the template to see if we should
-    render HSM parameters into the template.
-    """
-
-    interface_type = 'hsm'
-
-    @property
-    def library_path(self):
-        """Provide a library_path property to the template if it exists"""
-        try:
-            return self.relation.plugin_data['library_path']
-        except:
-            return ''
-
-    @property
-    def login(self):
-        """Provide a login property to the template if it exists"""
-        try:
-            return self.relation.plugin_data['login']
-        except:
-            return ''
-
-    @property
-    def slot_id(self):
-        """Provide a slot_id property to the template if it exists"""
-        try:
-            return self.relation.plugin_data['slot_id']
-        except:
-            return ''
+@charms_openstack.adapters.config_property
+def barbican_api_keystone_pipeline(config):
+    if config.keystone_api_version == "2":
+        return 'cors keystone_authtoken context apiapp'
+    else:
+        return 'cors keystone_v3_authtoken context apiapp'
 
 
-class BarbicanAdapters(charms_openstack.adapters.OpenStackAPIRelationAdapters):
-    """
-    Adapters class for the Barbican charm.
+@charms_openstack.adapters.config_property
+def barbican_api_pipeline(config):
+    return {
+        "2": "cors keystone_authtoken context apiapp",
+        "3": "cors keystone_v3_authtoken context apiapp",
+        "none": "cors unauthenticated-context apiapp"
+    }[config.keystone_api_version]
 
-    This plumbs in the BarbicanConfigurationAdapter as the ConfigurationAdapter
-    to provide additional properties.
-    """
 
-    relation_adapters = {
-        'hsm': HSMAdapter,
-    }
+@charms_openstack.adapters.config_property
+def barbican_api_keystone_audit_pipeline(config):
+    if config.keystone_api_version == "2":
+        return 'keystone_authtoken context audit apiapp'
+    else:
+        return 'keystone_v3_authtoken context audit apiapp'
 
-    def __init__(self, relations):
-        super(BarbicanAdapters, self).__init__(
-            relations,
-            options_instance=BarbicanConfigurationAdapter(
-                port_map=BarbicanCharm.api_ports))
+
+# Adapt the barbican-hsm-plugin relation for use in rendering the config
+# for Barbican.  Note that the HSM relation is optional, so we have a class
+# variable 'exists' that we can test in the template to see if we should
+# render HSM parameters into the template.
+
+@charms_openstack.adapters.adapter_property('hsm')
+def library_path(hsm):
+    """Provide a library_path property to the template if it exists"""
+    try:
+        return hsm.relation.plugin_data['library_path']
+    except:
+        return ''
+
+
+@charms_openstack.adapters.adapter_property('hsm')
+def login(hsm):
+    """Provide a login property to the template if it exists"""
+    try:
+        return hsm.relation.plugin_data['login']
+    except:
+        return ''
+
+
+@charms_openstack.adapters.adapter_property('hsm')
+def slot_id(hsm):
+    """Provide a slot_id property to the template if it exists"""
+    try:
+        return hsm.relation.plugin_data['slot_id']
+    except:
+        return ''
 
 
 class BarbicanCharm(charms_openstack.charm.HAOpenStackCharm):
@@ -220,22 +139,34 @@ class BarbicanCharm(charms_openstack.charm.HAOpenStackCharm):
         BARBICAN_WSGI_CONF: services,
     }
 
-    adapters_class = BarbicanAdapters
     ha_resources = ['vips', 'haproxy']
 
-    def install(self):
-        """Customise the installation, configure the source and then call the
-        parent install() method to install the packages
+    def get_amqp_credentials(self):
+        """Provide the default amqp username and vhost as a tuple.
+
+        :returns (username, host): two strings to send to the amqp provider.
         """
-        # DEBUG - until seed random change lands into xenial cloud archive
-        # BUG #1599550 - barbican + softhsm2 + libssl1.0.0:
-        #  pkcs11:_generate_random() fails
-        # WARNING: This charm can't be released into stable until the bug is
-        # fixed.
-        charmhelpers.fetch.add_source("ppa:ajkavanagh/barbican")
-        self.configure_source()
-        # and do the actual install
-        super(BarbicanCharm, self).install()
+        return (self.config['rabbit-user'], self.config['rabbit-vhost'])
+
+    def get_database_setup(self):
+        """Provide the default database credentials as a list of 3-tuples
+
+        returns a structure of:
+        [
+            {'database': <database>,
+             'username': <username>,
+             'hostname': <hostname of this unit>
+             'prefix': <the optional prefix for the database>, },
+        ]
+
+        :returns [{'database': ...}, ...]: credentials for multiple databases
+        """
+        return [
+            dict(
+                database=self.config['database'],
+                username=self.config['database-user'],
+                hostname=hookenv.unit_private_ip(), )
+        ]
 
     def action_generate_mkek(self, hsm):
         """Generate an MKEK on a connected HSM.  Requires that an HSM is
@@ -308,19 +239,3 @@ class BarbicanCharm(charms_openstack.charm.HAOpenStackCharm):
             required_relations.append('hsm')
         return super(BarbicanCharm, self).states_to_check(
             required_relations=required_relations)
-
-
-# Determine the charm class by the supported release
-@charms_openstack.charm.register_os_release_selector
-def select_release():
-    """Determine the release based on the python-keystonemiddleware that is
-    installed.
-
-    Note that this function caches the release after the first install so that
-    it doesn't need to keep going and getting it from the package information.
-    """
-    release_version = unitdata.kv().get(OPENSTACK_RELEASE_KEY, None)
-    if release_version is None:
-        release_version = ch_utils.os_release('python-keystonemiddleware')
-        unitdata.kv().set(OPENSTACK_RELEASE_KEY, release_version)
-    return release_version
diff --git a/src/reactive/barbican_handlers.py b/src/reactive/barbican_handlers.py
index bdb7cfa..81f20f8 100644
--- a/src/reactive/barbican_handlers.py
+++ b/src/reactive/barbican_handlers.py
@@ -18,46 +18,28 @@ from __future__ import absolute_import
 import charms.reactive as reactive
 import charmhelpers.core.hookenv as hookenv
 
+import charms_openstack.charm as charm
+
 # This charm's library contains all of the handler code associated with
-# barbican
-import charm.openstack.barbican as barbican
+# barbican -- we need to import it to get the definitions for the charm.
+import charm.openstack.barbican as barbican  # noqa
 
 
-# use a synthetic state to ensure that it get it to be installed independent of
-# the install hook.
-@reactive.when_not('charm.installed')
-def install_packages():
-    barbican.install()
-    reactive.set_state('charm.installed')
-
-
-@reactive.when('amqp.connected')
-def setup_amqp_req(amqp):
-    """Use the amqp interface to request access to the amqp broker using our
-    local configuration.
-    """
-    amqp.request_access(username=hookenv.config('rabbit-user'),
-                        vhost=hookenv.config('rabbit-vhost'))
-    barbican.assess_status()
-
-
-@reactive.when('shared-db.connected')
-def setup_database(database):
-    """On receiving database credentials, configure the database on the
-    interface.
-    """
-    database.configure(hookenv.config('database'),
-                       hookenv.config('database-user'),
-                       hookenv.unit_private_ip())
-    barbican.assess_status()
-
-
-@reactive.when('identity-service.connected')
-def setup_endpoint(keystone):
-    barbican.setup_endpoint(keystone)
-    barbican.assess_status()
+# Use the charms.openstack defaults for common states and hooks
+charm.use_defaults(
+    'charm.installed',
+    'amqp.connected',
+    'shared-db.connected',
+    'identity-service.connected',
+    'identity-service.available',  # enables SSL support
+    'config.changed',
+    'update-status')
 
 
+# Note that because of the way reactive.when works, (which is to 'find' the
+# __code__ segment of the decorated function, it's very, very difficult to add
+# other kinds of decorators here.  This rules out adding other things into the
+# charm args list.  It is also CPython dependent.
 @reactive.when('shared-db.available')
 @reactive.when('identity-service.available')
 @reactive.when('amqp.available')
@@ -65,25 +47,11 @@ def render_stuff(*args):
     """Render the configuration for Barbican when all the interfaces are
     available.
 
-    Note that the HSM interface is optional (hence the @when_any) and thus is
-    only used if it is available.
+    Note that the HSM interface is optional and thus is only used if it is
+    available.
     """
-    # Get the optional hsm relation, if it is available for rendering.
-    hsm = reactive.RelationBase.from_state('hsm.available')
-    if hsm is not None:
-        args = args + (hsm, )
-    barbican.render_configs(args)
-    barbican.assess_status()
-
-
-@reactive.when('config.changed')
-def config_changed():
-    """When the configuration changes, assess the unit's status to update any
-    juju state required"""
-    barbican.assess_status()
-
-
-@reactive.when('identity-service.available')
-def configure_ssl(keystone):
-    """Configure SSL access to Barbican if requested"""
-    barbican.configure_ssl(keystone)
+    hookenv.log("about to call the render_configs with {}".format(args))
+    with charm.provide_charm_instance() as barbican_charm:
+        barbican_charm.render_with_interfaces(
+            charm.optional_interfaces(args, 'hsm.available'))
+        barbican_charm.assess_status()
diff --git a/unit_tests/test_barbican_handlers.py b/unit_tests/test_barbican_handlers.py
index d9c06ba..332ecca 100644
--- a/unit_tests/test_barbican_handlers.py
+++ b/unit_tests/test_barbican_handlers.py
@@ -15,164 +15,53 @@
 from __future__ import absolute_import
 from __future__ import print_function
 
-import unittest
-
 import mock
 
 import reactive.barbican_handlers as handlers
 
-
-_when_args = {}
-_when_not_args = {}
+import charms_openstack.test_utils as test_utils
 
 
-def mock_hook_factory(d):
+class TestRegisteredHooks(test_utils.TestRegisteredHooks):
 
-    def mock_hook(*args, **kwargs):
-
-        def inner(f):
-            # remember what we were passed.  Note that we can't actually
-            # determine the class we're attached to, as the decorator only gets
-            # the function.
-            try:
-                d[f.__name__].append(dict(args=args, kwargs=kwargs))
-            except KeyError:
-                d[f.__name__] = [dict(args=args, kwargs=kwargs)]
-            return f
-        return inner
-    return mock_hook
-
-
-class TestBarbicanHandlers(unittest.TestCase):
-
-    @classmethod
-    def setUpClass(cls):
-        cls._patched_when = mock.patch('charms.reactive.when',
-                                       mock_hook_factory(_when_args))
-        cls._patched_when_started = cls._patched_when.start()
-        cls._patched_when_not = mock.patch('charms.reactive.when_not',
-                                           mock_hook_factory(_when_not_args))
-        cls._patched_when_not_started = cls._patched_when_not.start()
-        # force requires to rerun the mock_hook decorator:
-        # try except is Python2/Python3 compatibility as Python3 has moved
-        # reload to importlib.
-        try:
-            reload(handlers)
-        except NameError:
-            import importlib
-            importlib.reload(handlers)
-
-    @classmethod
-    def tearDownClass(cls):
-        cls._patched_when.stop()
-        cls._patched_when_started = None
-        cls._patched_when = None
-        cls._patched_when_not.stop()
-        cls._patched_when_not_started = None
-        cls._patched_when_not = None
-        # and fix any breakage we did to the module
-        try:
-            reload(handlers)
-        except NameError:
-            import importlib
-            importlib.reload(handlers)
-
-    def setUp(self):
-        self._patches = {}
-        self._patches_start = {}
-
-    def tearDown(self):
-        for k, v in self._patches.items():
-            v.stop()
-            setattr(self, k, None)
-        self._patches = None
-        self._patches_start = None
-
-    def patch(self, obj, attr, return_value=None):
-        mocked = mock.patch.object(obj, attr)
-        self._patches[attr] = mocked
-        started = mocked.start()
-        started.return_value = return_value
-        self._patches_start[attr] = started
-        setattr(self, attr, started)
-
-    def test_registered_hooks(self):
-        # test that the hooks actually registered the relation expressions that
-        # are meaningful for this interface: this is to handle regressions.
-        # The keys are the function names that the hook attaches to.
-        when_patterns = {
-            'setup_amqp_req': ('amqp.connected', ),
-            'setup_database': ('shared-db.connected', ),
-            'setup_endpoint': ('identity-service.connected', ),
-            'render_stuff': ('shared-db.available',
-                             'identity-service.available',
-                             'amqp.available',),
-            'config_changed': ('config.changed', ),
-            'configure_ssl': ('identity-service.available', ),
+    def test_hooks(self):
+        defaults = [
+            'charm.installed',
+            'amqp.connected',
+            'shared-db.connected',
+            'identity-service.connected',
+            'identity-service.available',  # enables SSL support
+            'config.changed',
+            'update-status']
+        hook_set = {
+            'when': {
+                'render_stuff': ('shared-db.available',
+                                 'identity-service.available',
+                                 'amqp.available',),
+            }
         }
-        when_not_patterns = {
-            'install_packages': ('charm.installed', ),
-        }
-        # check the when hooks are attached to the expected functions
-        for t, p in [(_when_args, when_patterns),
-                     (_when_not_args, when_not_patterns)]:
-            for f, args in t.items():
-                # check that function is in patterns
-                # print("f: {}, args: {}".format(f, args))
-                self.assertTrue(f in p.keys())
-                # check that the lists are equal
-                l = [a['args'][0] for a in args]
-                self.assertEqual(l, sorted(p[f]))
+        # test that the hooks were registered via the
+        # reactive.barbican_handlers
+        self.registered_hooks_test_helper(handlers, hook_set, defaults)
 
-    def test_install_packages(self):
-        self.patch(handlers.barbican, 'install')
-        self.patch(handlers.reactive, 'set_state')
-        handlers.install_packages()
-        self.install.assert_called_once_with()
-        self.set_state.assert_called_once_with('charm.installed')
 
-    def test_setup_amqp_req(self):
-        amqp = mock.MagicMock()
-        self.patch(handlers.hookenv, 'config')
-        reply = {
-            'rabbit-user': 'user1',
-            'rabbit-vhost': 'vhost1',
-        }
-        self.config.side_effect = lambda x: reply[x]
-        self.patch(handlers.barbican, 'assess_status')
-        handlers.setup_amqp_req(amqp)
-        amqp.request_access.assert_called_once_with(
-            username='user1', vhost='vhost1')
-        self.assess_status.assert_called_once_with()
-
-    def test_database(self):
-        database = mock.MagicMock()
-        self.patch(handlers.hookenv, 'config')
-        reply = {
-            'database': 'db1',
-            'database-user': 'dbuser1',
-        }
-        self.config.side_effect = lambda x: reply[x]
-        self.patch(handlers.hookenv, 'unit_private_ip', 'private_ip')
-        self.patch(handlers.barbican, 'assess_status')
-        handlers.setup_database(database)
-        database.configure.assert_called_once_with(
-            'db1', 'dbuser1', 'private_ip')
-        self.assess_status.assert_called_once_with()
-
-    def test_setup_endpoint(self):
-        self.patch(handlers.barbican, 'setup_endpoint')
-        self.patch(handlers.barbican, 'assess_status')
-        handlers.setup_endpoint('endpoint_object')
-        self.setup_endpoint.assert_called_once_with('endpoint_object')
-        self.assess_status.assert_called_once_with()
+class TestRenderStuff(test_utils.PatchHelper):
 
     def test_render_stuff(self):
-        self.patch(handlers.barbican, 'render_configs')
-        self.patch(handlers.barbican, 'assess_status')
-        self.patch(handlers.reactive.RelationBase, 'from_state',
-                   return_value='hsm')
+        barbican_charm = mock.MagicMock()
+        self.patch_object(handlers.charm, 'provide_charm_instance',
+                          new=mock.MagicMock())
+        self.provide_charm_instance().__enter__.return_value = barbican_charm
+        self.provide_charm_instance().__exit__.return_value = None
+        self.patch_object(handlers.charm, 'optional_interfaces')
+
+        def _optional_interfaces(args, *interfaces):
+            self.assertEqual(interfaces, ('hsm.available', ))
+            return args + ('hsm', )
+
+        self.optional_interfaces.side_effect = _optional_interfaces
+
         handlers.render_stuff('arg1', 'arg2')
-        self.render_configs.assert_called_once_with(('arg1', 'arg2', 'hsm'))
-        self.assess_status.assert_called_once_with()
-        self.from_state.assert_called_once_with('hsm.available')
+        barbican_charm.render_with_interfaces.assert_called_once_with(
+            ('arg1', 'arg2', 'hsm'))
+        barbican_charm.assess_status.assert_called_once_with()
diff --git a/unit_tests/test_lib_charm_openstack_barbican.py b/unit_tests/test_lib_charm_openstack_barbican.py
index 8c0fd09..27d0f26 100644
--- a/unit_tests/test_lib_charm_openstack_barbican.py
+++ b/unit_tests/test_lib_charm_openstack_barbican.py
@@ -15,151 +15,93 @@
 from __future__ import absolute_import
 from __future__ import print_function
 
-import unittest
-
 import mock
+import charms_openstack.test_utils as test_utils
 
 import charm.openstack.barbican as barbican
 
 
-class Helper(unittest.TestCase):
+class Helper(test_utils.PatchHelper):
 
     def setUp(self):
-        self._patches = {}
-        self._patches_start = {}
-        # patch out the select_release to always return 'mitaka'
-        self.patch(barbican.unitdata, 'kv')
-        _getter = mock.MagicMock()
-        _getter.get.return_value = barbican.BarbicanCharm.release
-        self.kv.return_value = _getter
-
-    def tearDown(self):
-        for k, v in self._patches.items():
-            v.stop()
-            setattr(self, k, None)
-        self._patches = None
-        self._patches_start = None
-
-    def patch(self, obj, attr, return_value=None, **kwargs):
-        mocked = mock.patch.object(obj, attr, **kwargs)
-        self._patches[attr] = mocked
-        started = mocked.start()
-        started.return_value = return_value
-        self._patches_start[attr] = started
-        setattr(self, attr, started)
+        super().setUp()
+        self.patch_release(barbican.BarbicanCharm.release)
 
 
-class TestOpenStackBarbican(Helper):
+class TestCustomProperties(Helper):
 
-    def test_install(self):
-        self.patch(barbican.BarbicanCharm, 'set_config_defined_certs_and_keys')
-        self.patch(barbican.BarbicanCharm.singleton, 'install')
-        barbican.install()
-        self.install.assert_called_once_with()
-
-    def test_setup_endpoint(self):
-        self.patch(barbican.BarbicanCharm, 'set_config_defined_certs_and_keys')
-        self.patch(barbican.BarbicanCharm, 'service_type',
-                   new_callable=mock.PropertyMock)
-        self.patch(barbican.BarbicanCharm, 'region',
-                   new_callable=mock.PropertyMock)
-        self.patch(barbican.BarbicanCharm, 'public_url',
-                   new_callable=mock.PropertyMock)
-        self.patch(barbican.BarbicanCharm, 'internal_url',
-                   new_callable=mock.PropertyMock)
-        self.patch(barbican.BarbicanCharm, 'admin_url',
-                   new_callable=mock.PropertyMock)
-        self.service_type.return_value = 'type1'
-        self.region.return_value = 'region1'
-        self.public_url.return_value = 'public_url'
-        self.internal_url.return_value = 'internal_url'
-        self.admin_url.return_value = 'admin_url'
-        keystone = mock.MagicMock()
-        barbican.setup_endpoint(keystone)
-        keystone.register_endpoints.assert_called_once_with(
-            'type1', 'region1', 'public_url', 'internal_url', 'admin_url')
-
-    def test_render_configs(self):
-        self.patch(barbican.BarbicanCharm, 'set_config_defined_certs_and_keys')
-        self.patch(barbican.BarbicanCharm.singleton, 'render_with_interfaces')
-        barbican.render_configs('interfaces-list')
-        self.render_with_interfaces.assert_called_once_with(
-            'interfaces-list')
-
-
-class TestBarbicanConfigurationAdapter(Helper):
-
-    @mock.patch('charmhelpers.core.hookenv.config')
-    def test_barbican_configuration_adapter(self, config):
-        self.patch(
-            barbican.charms_openstack.adapters.APIConfigurationAdapter,
-            'get_network_addresses')
-        reply = {
-            'keystone-api-version': '2',
-        }
-        config.side_effect = lambda: reply
-        # Make one with no errors, api version 2
-        a = barbican.BarbicanConfigurationAdapter()
-        self.assertEqual(a.barbican_api_keystone_pipeline,
-                         'cors keystone_authtoken context apiapp')
-        self.assertEqual(a.barbican_api_pipeline,
-                         'cors keystone_authtoken context apiapp')
-        # Now test it with api version 3
-        reply['keystone-api-version'] = '3'
-        a = barbican.BarbicanConfigurationAdapter()
-        self.assertEqual(a.barbican_api_keystone_pipeline,
-                         'cors keystone_v3_authtoken context apiapp')
-        self.assertEqual(a.barbican_api_pipeline,
-                         'cors keystone_v3_authtoken context apiapp')
-        # and a 'none' version
-        reply['keystone-api-version'] = 'none'
-        a = barbican.BarbicanConfigurationAdapter()
-        self.assertEqual(a.barbican_api_keystone_pipeline,
-                         'cors keystone_v3_authtoken context apiapp')
-        self.assertEqual(a.barbican_api_pipeline,
-                         'cors unauthenticated-context apiapp')
-        # finally, try to create an invalid one.
-        reply['keystone-api-version'] = None
+    def test_validate_keystone_api_version(self):
+        config = mock.MagicMock()
+        for v in ['2', '3', 'none']:
+            config.keystone_api_version = v
+            barbican.validate_keystone_api_version(config)
+        # ensure that it fails
         with self.assertRaises(ValueError):
-            a = barbican.BarbicanConfigurationAdapter()
+            config.keystone_api_version = 'fail-me'
+            barbican.validate_keystone_api_version(config)
+
+    def test_barbican_api_keystone_pipeline(self):
+        config = mock.MagicMock()
+        config.keystone_api_version = '2'
+        self.assertEqual(barbican.barbican_api_keystone_pipeline(config),
+                         'cors keystone_authtoken context apiapp')
+        config.keystone_api_version = ''
+        self.assertEqual(barbican.barbican_api_keystone_pipeline(config),
+                         'cors keystone_v3_authtoken context apiapp')
+
+    def test_barbican_api_pipeline(self):
+        config = mock.MagicMock()
+        config.keystone_api_version = '2'
+        self.assertEqual(barbican.barbican_api_pipeline(config),
+                         'cors keystone_authtoken context apiapp')
+        config.keystone_api_version = '3'
+        self.assertEqual(barbican.barbican_api_pipeline(config),
+                         'cors keystone_v3_authtoken context apiapp')
+        config.keystone_api_version = 'none'
+        self.assertEqual(barbican.barbican_api_pipeline(config),
+                         'cors unauthenticated-context apiapp')
+
+    def test_barbican_api_keystone_audit_pipeline(self):
+        config = mock.MagicMock()
+        config.keystone_api_version = '2'
+        self.assertEqual(barbican.barbican_api_keystone_audit_pipeline(config),
+                         'keystone_authtoken context audit apiapp')
+        config.keystone_api_version = ''
+        self.assertEqual(barbican.barbican_api_keystone_audit_pipeline(config),
+                         'keystone_v3_authtoken context audit apiapp')
 
 
-class TestBarbicanAdapters(Helper):
+class TestHSMProperties(Helper):
 
-    @mock.patch('charmhelpers.core.hookenv.config')
-    def test_barbican_adapters(self, config):
-        reply = {
-            'keystone-api-version': '2',
-            # for the charms.openstack code, which breaks if we don't have:
-            'os-public-hostname': 'host',
-            'os-internal-hostname': 'internal',
-            'os-admin-hostname': 'admin',
+    def setUp(self):
+        super().setUp()
+        self.data_none = {}
+        self.data_set = {
+            'library_path': 'a-path',
+            'login': 'a-login',
+            'slot_id': 'a-slot_id',
         }
 
-        def cf(key=None):
-            if key is not None:
-                return reply[key]
-            return reply
+    def test_library_path(self):
+        hsm = mock.MagicMock()
+        hsm.relation.plugin_data = self.data_none
+        self.assertEqual(barbican.library_path(hsm), '')
+        hsm.relation.plugin_data = self.data_set
+        self.assertEqual(barbican.library_path(hsm), 'a-path')
 
-        config.side_effect = cf
-        amqp_relation = mock.MagicMock()
-        amqp_relation.relation_name = 'amqp'
-        shared_db_relation = mock.MagicMock()
-        shared_db_relation.relation_name = 'shared_db'
-        other_relation = mock.MagicMock()
-        other_relation.relation_name = 'other'
-        other_relation.thingy = 'help'
-        # verify that the class is created with a BarbicanConfigurationAdapter
-        b = barbican.BarbicanAdapters([amqp_relation,
-                                       shared_db_relation,
-                                       other_relation])
-        # ensure that the relevant things got put on.
-        self.assertTrue(
-            isinstance(
-                b.other,
-                barbican.charms_openstack.adapters.OpenStackRelationAdapter))
-        self.assertTrue(isinstance(b.options,
-                                   barbican.BarbicanConfigurationAdapter))
+    def test_login(self):
+        hsm = mock.MagicMock()
+        hsm.relation.plugin_data = self.data_none
+        self.assertEqual(barbican.login(hsm), '')
+        hsm.relation.plugin_data = self.data_set
+        self.assertEqual(barbican.login(hsm), 'a-login')
+
+    def test_slot_id(self):
+        hsm = mock.MagicMock()
+        hsm.relation.plugin_data = self.data_none
+        self.assertEqual(barbican.slot_id(hsm), '')
+        hsm.relation.plugin_data = self.data_set
+        self.assertEqual(barbican.slot_id(hsm), 'a-slot_id')
 
 
 class TestBarbicanCharm(Helper):
@@ -171,7 +113,7 @@ class TestBarbicanCharm(Helper):
             'login': '1234',
             'slot_id': 'slot1'
         }
-        self.patch(barbican.hookenv, 'config')
+        self.patch_object(barbican.hookenv, 'config')
         config = {
             'mkek-key-length': 5,
             'label-mkek': 'the-label'
@@ -183,8 +125,8 @@ class TestBarbicanCharm(Helper):
             return config
 
         self.config.side_effect = cf
-        self.patch(barbican.subprocess, 'check_call')
-        self.patch(barbican.hookenv, 'log')
+        self.patch_object(barbican.subprocess, 'check_call')
+        self.patch_object(barbican.hookenv, 'log')
         # try generating a an mkek with no failure
         c = barbican.BarbicanCharm()
         c.action_generate_mkek(hsm)
@@ -218,7 +160,7 @@ class TestBarbicanCharm(Helper):
             'login': '1234',
             'slot_id': 'slot1'
         }
-        self.patch(barbican.hookenv, 'config')
+        self.patch_object(barbican.hookenv, 'config')
         config = {
             'hmac-key-length': 5,
             'label-hmac': 'the-label'
@@ -230,8 +172,8 @@ class TestBarbicanCharm(Helper):
             return config
 
         self.config.side_effect = cf
-        self.patch(barbican.subprocess, 'check_call')
-        self.patch(barbican.hookenv, 'log')
+        self.patch_object(barbican.subprocess, 'check_call')
+        self.patch_object(barbican.hookenv, 'log')
         # try generating a an hmac with no failure
         c = barbican.BarbicanCharm()
         c.action_generate_hmac(hsm)