Do less work in the update-status hook

This patchset, along with the corresponding ones in charms.openstack
and interface-hacluster reduce the amount of work that the charm does
during an update-status hook.  This also fixes the issue where an
update-status hook triggered activity in the hacluster subordinate due
to data being set on the interface.  There is still work to be done in
this area, as the configs for the charm are still being written on every
update-status hook, although this doesn't result in a restart of any of
the services.  This probably requires a re-think of how the
charm-helpers function runs; patch to charm-helpers coming up soon.

This also fixes bug 1712973 where the update-pools command with empty
pools errors causing the charm to error out and fail.  This is
undesirable, so this condition is caught and logged instead.

Change-Id: I6db68a479dc903ce620ba62c1898247f71d14701
Depends-On: I3717387d1d8d2ab875d51f262efd1df7f2529689
Depends-On: I750f3c41a2f0447a47cfd19bab1d4958de4577f2
Closes-Bug: #1708396
Closes-Bug: #1712973
This commit is contained in:
Alex Kavanagh 2017-08-07 16:46:11 +01:00
parent af969ceb2c
commit 1ef3522f86
4 changed files with 167 additions and 372 deletions

View File

@ -36,173 +36,9 @@ NEUTRON_SINK_FILE = DESIGNATE_DIR + '/conf.d/neutron_sink.cfg'
RC_FILE = '/root/novarc'
def install():
"""Use the singleton from the DesignateCharm to install the packages on the
unit
@returns: None
"""
DesignateCharm.singleton.install()
def db_sync_done():
"""Use the singleton from the DesignateCharm to check if db migration has
been run
@returns: str or None. Str if sync has been done otherwise None
"""
return DesignateCharm.singleton.db_sync_done()
def db_sync():
"""Use the singleton from the DesignateCharm to run db migration
@returns: None
"""
DesignateCharm.singleton.db_sync()
def render_base_config(interfaces_list):
"""Use the singleton from the DesignateCharm to run render_base_config
@param interfaces_list: List of instances of interface classes.
@returns: None
"""
DesignateCharm.singleton.render_base_config(interfaces_list)
def create_initial_servers_and_domains():
"""Use the singleton from the DesignateCharm to run create inital servers
and domains in designate
@returns: None
"""
DesignateCharm.singleton.create_initial_servers_and_domains()
def domain_init_done():
"""Use the singleton from the DesignateCharm to check if inital servers
and domains have been created
@returns: str or None. Str if init has been done otherwise None
"""
return DesignateCharm.singleton.domain_init_done()
def render_full_config(interfaces_list):
"""Use the singleton from the DesignateCharm to render all configs
@param interfaces_list: List of instances of interface classes.
@returns: None
"""
DesignateCharm.singleton.render_full_config(interfaces_list)
def render_sink_configs(interfaces_list):
"""Use the singleton from the DesignateCharm to render sink configs
@param interfaces_list: List of instances of interface classes.
@returns: None
"""
configs = [NOVA_SINK_FILE, NEUTRON_SINK_FILE, DESIGNATE_DEFAULT]
DesignateCharm.singleton.render_with_interfaces(
interfaces_list,
configs=configs)
def register_endpoints(keystone):
"""When the keystone interface connects, register this unit in the keystone
catalogue.
@param keystone: KeystoneRequires() interface class
@returns: None
"""
charm = DesignateCharm.singleton
keystone.register_endpoints(charm.service_type,
charm.region,
charm.public_url,
charm.internal_url,
charm.admin_url)
def configure_ha_resources(hacluster):
"""Use the singleton from the DesignateCharm to run configure ha resources
@param hacluster: OpenstackHAPeers() interface class
@returns: None
"""
DesignateCharm.singleton.configure_ha_resources(hacluster)
def restart_all():
"""Use the singleton from the DesignateCharm to restart all registered
services
@returns: None
"""
DesignateCharm.singleton.restart_all()
def configure_ssl(keystone=None):
"""Use the singleton from the DesignateCharm to configure ssl
@param keystone: KeystoneRequires() interface class
@returns: None
"""
DesignateCharm.singleton.configure_ssl(keystone)
def update_peers(hacluster):
"""Use the singleton from the DesignateCharm to update peers with detials
of this unit
@param hacluster: OpenstackHAPeers() interface class
@returns: None
"""
DesignateCharm.singleton.update_peers(hacluster)
def render_rndc_keys():
"""Use the singleton from the DesignateCharm write out rndc key files
@returns: None
"""
DesignateCharm.singleton.render_rndc_keys()
def assess_status():
"""Just call the DesignateCharm.singleton.assess_status() command to update
status on the unit.
@returns: None
"""
DesignateCharm.singleton.assess_status()
def update_pools():
"""Just call the DesignateCharm.singleton.update_pools() command to update
pool info in the db
@returns: None
"""
DesignateCharm.singleton.update_pools()
def upgrade_if_available(interfaces_list):
"""Just call the DesignateCharm.singleton.upgrade_if_available() command to
update OpenStack package if upgrade is available
@returns: None
"""
DesignateCharm.singleton.upgrade_if_available(interfaces_list)
class DesignateDBAdapter(openstack_adapters.DatabaseRelationAdapter):
"""Get database URIs for the two designate databases"""
def __init__(self, relation):
super(DesignateDBAdapter, self).__init__(relation)
@property
def designate_uri(self):
"""URI for designate DB"""
@ -218,9 +54,6 @@ class BindRNDCRelationAdapter(openstack_adapters.OpenStackRelationAdapter):
interface_type = "dns"
def __init__(self, relation):
super(BindRNDCRelationAdapter, self).__init__(relation)
@property
def slave_ips(self):
"""List of DNS slave address infoprmation
@ -283,10 +116,6 @@ class BindRNDCRelationAdapter(openstack_adapters.OpenStackRelationAdapter):
class DesignateConfigurationAdapter(
openstack_adapters.APIConfigurationAdapter):
def __init__(self, port_map=None, *args, **kwargs):
super(DesignateConfigurationAdapter, self).__init__(
port_map=port_map, service_name='designate', *args, **kwargs)
@property
def pool_config(self):
"""List of DNS slave information from user defined config
@ -416,12 +245,6 @@ class DesignateAdapters(openstack_adapters.OpenStackAPIRelationAdapters):
'dns_backend': BindRNDCRelationAdapter,
}
def __init__(self, relations):
super(DesignateAdapters, self).__init__(
relations,
options_instance=DesignateConfigurationAdapter(
port_map=DesignateCharm.api_ports))
class DesignateCharm(openstack_charm.HAOpenStackCharm):
"""Designate charm"""
@ -631,10 +454,14 @@ class DesignateCharm(openstack_charm.HAOpenStackCharm):
"""Create the nameserver entry and domains based on the charm user
supplied config
NOTE(AJK): This only wants to be done ONCE and by the leader, so we use
leader settings to store that we've done it, after it's successfully
completed.
@returns None
"""
if hookenv.is_leader():
cls.ensure_api_responding()
KEY = 'create_initial_servers_and_domains'
if hookenv.is_leader() and not hookenv.leader_get(KEY):
nova_domain_name = hookenv.config('nova-domain')
neutron_domain_name = hookenv.config('neutron-domain')
with cls.check_zone_ids(nova_domain_name, neutron_domain_name):
@ -654,13 +481,32 @@ class DesignateCharm(openstack_charm.HAOpenStackCharm):
cls.create_domain(
neutron_domain_name,
hookenv.config('neutron-domain-email'))
# if this fails, we weren't the leader any more; another unit may
# attempt to do this too.
hookenv.leader_set(KEY, 'done')
def update_pools(self):
# designate-manage communicates with designate via message bus so no
# need to set OS_ vars
# NOTE(AJK) this runs with every hook (once most relations are up) and
# so if it fails it will be picked up by the next relation change or
# update-status. i.e. it will heal eventually.
if hookenv.is_leader():
cmd = ['designate-manage', 'pool', 'update']
subprocess.check_call(cmd)
try:
cmd = "designate-manage pool update"
# Note(tinwood) that this command may fail if the pools.yaml
# doesn't actually contain any pools. This happens when the
# relation is broken, which errors out the charm. This stops
# this happening and logs the error.
subprocess.check_call(cmd.split(), timeout=60)
except subprocess.CalledProcessError as e:
hookenv.log("designate-manage pool update failed: {}"
.format(str(e)))
except subprocess.TimeoutExpired as e:
# the timeout is if the rabbitmq server has gone away; it just
# retries continuously; this lets the hook complete.
hookenv.log("designate-manage pool command timed out: {}".
format(str(e)))
def custom_assess_status_check(self):
if (not hookenv.config('nameservers') and

View File

@ -12,11 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import subprocess
import charm.openstack.designate as designate
import charms.reactive as reactive
import charmhelpers.core.hookenv as hookenv
from charms_openstack.charm import provide_charm_instance
from charms_openstack.charm.utils import is_data_changed
# If either dns-backend.available is set OR config('dns-slaves') is valid, then
# the following state will be set.
@ -59,33 +63,47 @@ def clear_dns_config_available():
@reactive.when_not('installed')
def install_packages():
"""Install charms packages"""
designate.install()
with provide_charm_instance() as instance:
instance.install()
reactive.set_state('installed')
reactive.remove_state('amqp.requested-access')
reactive.remove_state('shared-db.setup')
reactive.remove_state('base-config.rendered')
reactive.remove_state('db.synched')
@reactive.when('amqp.connected')
@reactive.when_not('amqp.requested-access')
def setup_amqp_req(amqp):
"""Send request fir rabbit access and vhost"""
"""Send request for rabbit access and vhost"""
amqp.request_access(username='designate',
vhost='openstack')
designate.assess_status()
reactive.set_state('amqp.requested-access')
@reactive.when('shared-db.connected')
@reactive.when_not('shared-db.setup')
def setup_database(database):
"""Send request designate accounts and dbs"""
database.configure('designate', 'designate',
prefix='designate')
database.configure('dpm', 'dpm',
prefix='dpm')
designate.assess_status()
reactive.set_state('shared-db.setup')
@reactive.when('identity-service.connected')
def setup_endpoint(keystone):
"""Register endpoints with keystone"""
designate.register_endpoints(keystone)
designate.assess_status()
def maybe_setup_endpoint(keystone):
"""When the keystone interface connects, register this unit in the keystone
catalogue.
"""
with provide_charm_instance() as instance:
args = [instance.service_type, instance.region, instance.public_url,
instance.internal_url, instance.admin_url]
# This function checkes that the data has changed before sending it
with is_data_changed('charms.openstack.register-endpoints', args) as c:
if c:
keystone.register_endpoints(*args)
@reactive.when_not('base-config.rendered')
@ -99,7 +117,8 @@ def configure_designate_basic(*args):
dns_backend = reactive.RelationBase.from_state('dns-backend.available')
if dns_backend is not None:
args = args + (dns_backend, )
designate.render_base_config(args)
with provide_charm_instance() as instance:
instance.render_base_config(args)
reactive.set_state('base-config.rendered')
@ -108,15 +127,19 @@ def configure_designate_basic(*args):
@reactive.when(*COMPLETE_INTERFACE_STATES)
def run_db_migration(*args):
"""Run database migrations"""
designate.db_sync()
if designate.db_sync_done():
reactive.set_state('db.synched')
with provide_charm_instance() as instance:
instance.db_sync()
if instance.db_sync_done():
reactive.set_state('db.synched')
@reactive.when('cluster.available')
def update_peers(cluster):
"""Inform designate peers about this unit"""
designate.update_peers(cluster)
with provide_charm_instance() as instance:
# This function ONLY updates the peers if the data has changed. Thus
# it's okay to call it on every hook invocation.
instance.update_peers(cluster)
@reactive.when('db.synched')
@ -130,25 +153,48 @@ def configure_designate_full(*args):
dns_backend = reactive.RelationBase.from_state('dns-backend.available')
if dns_backend is not None:
args = args + (dns_backend, )
designate.upgrade_if_available(args)
designate.configure_ssl()
designate.render_full_config(args)
designate.create_initial_servers_and_domains()
designate.render_sink_configs(args)
designate.render_rndc_keys()
designate.update_pools()
designate.assess_status()
with provide_charm_instance() as instance:
instance.upgrade_if_available(args)
instance.configure_ssl()
instance.render_full_config(args)
try:
# the following function should only run once for the leader.
instance.create_initial_servers_and_domains()
_render_sink_configs(instance, args)
instance.render_rndc_keys()
instance.update_pools()
except subprocess.CalledProcessError as e:
hookenv.log("ensure_api_responding() errored out: {}"
.format(str(e)),
level=hookenv.ERROR)
def _render_sink_configs(instance, interfaces_list):
"""Helper: use the singleton from the DesignateCharm to render sink configs
@param instance: an instance that has the render_with_intefaces() method
@param interfaces_list: List of instances of interface classes.
@returns: None
"""
configs = [designate.NOVA_SINK_FILE,
designate.NEUTRON_SINK_FILE,
designate.DESIGNATE_DEFAULT]
instance.render_with_interfaces(interfaces_list, configs=configs)
@reactive.when('ha.connected')
def cluster_connected(hacluster):
"""Configure HA resources in corosync"""
designate.configure_ha_resources(hacluster)
designate.assess_status()
with provide_charm_instance() as instance:
instance.configure_ha_resources(hacluster)
@reactive.when('config.changed')
def config_changed():
"""When the configuration changes, assess the unit's status to update any
juju state required"""
designate.assess_status()
@reactive.when_not('dont-set-assess-status')
def run_assess_status_on_every_hook():
"""The call to charm instance.assess_status() sets up the assess status
functionality to be called atexit() of the charm. i.e. as the last thing
it does. Thus, this handle gets called for EVERY hook invocation, which
means that no other handlers need to call the assess_status function.
"""
with provide_charm_instance() as instance:
instance.assess_status()

View File

@ -20,7 +20,7 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
'when': {
'setup_amqp_req': ('amqp.connected', ),
'setup_database': ('shared-db.connected', ),
'setup_endpoint': ('identity-service.connected', ),
'maybe_setup_endpoint': ('identity-service.connected', ),
'configure_ssl': ('identity-service.available', ),
'update_peers': ('cluster.available', ),
'config_changed': ('config.changed', ),
@ -34,10 +34,14 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
'configure_designate_basic': all_interfaces,
},
'when_not': {
'setup_amqp_req': ('amqp.requested-access', ),
'setup_database': ('shared-db.setup', ),
'install_packages': ('installed', ),
'run_db_migration': ('db.synched', ),
'configure_designate_basic': ('base-config.rendered', ),
'create_servers_and_domains': ('domains.created', ),
'run_assess_status_on_every_hook': (
'dont-set-assess-status', ),
},
'when_any': {
'set_dns_config_available': (
@ -58,23 +62,36 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
class TestHandlers(test_utils.PatchHelper):
def _patch_provide_charm_instance(self):
the_charm = mock.MagicMock()
self.patch_object(handlers, 'provide_charm_instance',
name='provide_charm_instance',
new=mock.MagicMock())
self.provide_charm_instance().__enter__.return_value = the_charm
self.provide_charm_instance().__exit__.return_value = None
return the_charm
def test_install_packages(self):
self.patch_object(handlers.designate, 'install')
the_charm = self._patch_provide_charm_instance()
self.patch_object(handlers.reactive, 'set_state')
self.patch_object(handlers.reactive, 'remove_state')
handlers.install_packages()
self.install.assert_called_once_with()
self.set_state.assert_called_once_with('installed')
the_charm.install.assert_called_once_with()
calls = [mock.call('amqp.requested-access'),
mock.call('shared-db.setup'),
mock.call('base-config.rendered'),
mock.call('db.synched')]
self.remove_state.assert_has_calls(calls)
def test_setup_amqp_req(self):
self.patch_object(handlers.designate, 'assess_status')
self.patch_object(handlers.reactive, 'set_state')
amqp = mock.MagicMock()
handlers.setup_amqp_req(amqp)
amqp.request_access.assert_called_once_with(
username='designate', vhost='openstack')
self.assess_status.assert_called_once_with()
self.set_state.assert_called_once_with('amqp.requested-access')
def test_database(self):
self.patch_object(handlers.designate, 'assess_status')
database = mock.MagicMock()
handlers.setup_database(database)
calls = [
@ -88,74 +105,72 @@ class TestHandlers(test_utils.PatchHelper):
prefix='dpm'),
]
database.configure.has_calls(calls)
self.assess_status.assert_called_once_with()
def test_setup_endpoint(self):
self.patch_object(handlers.designate, 'assess_status')
self.patch_object(handlers.designate, 'register_endpoints')
handlers.setup_endpoint('endpoint_object')
self.register_endpoints.assert_called_once_with('endpoint_object')
self.assess_status.assert_called_once_with()
the_charm = self._patch_provide_charm_instance()
the_charm.service_type = 's1'
the_charm.region = 'r1'
the_charm.public_url = 'p1'
the_charm.internal_url = 'i1'
the_charm.admin_url = 'a1'
args = ['s1', 'r1', 'p1', 'i1', 'a1']
self.patch_object(handlers, 'is_data_changed',
name='is_data_changed',
new=mock.MagicMock())
self.is_data_changed().__enter__.return_value = True
self.is_data_changed().__exit__.return_value = None
keystone = mock.MagicMock()
handlers.maybe_setup_endpoint(keystone)
self.is_data_changed.called_once_with(mock.ANY, args)
keystone.register_endpoints.assert_called_once_with(*args)
def test_configure_designate_basic(self):
the_charm = self._patch_provide_charm_instance()
self.patch_object(handlers.reactive, 'set_state')
self.patch_object(handlers.designate, 'render_base_config')
self.patch_object(handlers.reactive.RelationBase, 'from_state',
return_value=None)
handlers.configure_designate_basic('arg1', 'arg2')
self.render_base_config.assert_called_once_with(('arg1', 'arg2', ))
the_charm.render_base_config.assert_called_once_with(
('arg1', 'arg2', ))
self.set_state.assert_called_once_with('base-config.rendered')
def test_run_db_migration(self):
the_charm = self._patch_provide_charm_instance()
self.patch_object(handlers.reactive, 'set_state')
self.patch_object(handlers.designate, 'db_sync')
self.patch_object(handlers.designate, 'db_sync_done')
self.db_sync_done.return_value = False
the_charm.db_sync_done.return_value = False
handlers.run_db_migration('arg1', 'arg2')
self.db_sync.assert_called_once_with()
the_charm.db_sync.assert_called_once_with()
self.assertFalse(self.set_state.called)
self.db_sync.reset_mock()
self.db_sync_done.return_value = True
the_charm.db_sync.reset_mock()
the_charm.db_sync_done.return_value = True
handlers.run_db_migration('arg1', 'arg2')
self.db_sync.assert_called_once_with()
the_charm.db_sync.assert_called_once_with()
self.set_state.assert_called_once_with('db.synched')
def test_update_peers(self):
cluster = mock.MagicMock()
self.patch_object(handlers.designate, 'update_peers')
handlers.update_peers(cluster)
self.update_peers.assert_called_once_with(cluster)
the_charm = self._patch_provide_charm_instance()
handlers.update_peers('cluster')
the_charm.update_peers.assert_called_once_with('cluster')
def test_configure_designate_full(self):
the_charm = self._patch_provide_charm_instance()
self.patch_object(handlers.reactive.RelationBase,
'from_state',
return_value=None)
self.patch_object(handlers.designate, 'upgrade_if_available')
self.patch_object(handlers.designate, 'configure_ssl')
self.patch_object(handlers.designate, 'render_full_config')
self.patch_object(handlers.designate,
'create_initial_servers_and_domains')
self.patch_object(handlers.designate, 'render_sink_configs')
self.patch_object(handlers.designate, 'render_rndc_keys')
self.patch_object(handlers.designate, 'update_pools')
handlers.configure_designate_full('arg1', 'arg2')
self.configure_ssl.assert_called_once_with()
self.render_full_config.assert_called_once_with(('arg1', 'arg2', ))
self.create_initial_servers_and_domains.assert_called_once_with()
self.render_sink_configs.assert_called_once_with(('arg1', 'arg2', ))
self.render_rndc_keys.assert_called_once_with()
self.update_pools.assert_called_once_with()
self.upgrade_if_available.assert_called_once_with(('arg1', 'arg2', ))
the_charm.configure_ssl.assert_called_once_with()
the_charm.render_full_config.assert_called_once_with(
('arg1', 'arg2', ))
the_charm.create_initial_servers_and_domains.assert_called_once_with()
the_charm.render_with_interfaces.assert_called_once_with(
('arg1', 'arg2'), configs=mock.ANY)
the_charm.render_rndc_keys.assert_called_once_with()
the_charm.update_pools.assert_called_once_with()
the_charm.upgrade_if_available.assert_called_once_with(
('arg1', 'arg2', ))
def test_cluster_connected(self):
the_charm = self._patch_provide_charm_instance()
hacluster = mock.MagicMock()
self.patch_object(handlers.designate, 'configure_ha_resources')
self.patch_object(handlers.designate, 'assess_status')
handlers.cluster_connected(hacluster)
self.configure_ha_resources.assert_called_once_with(hacluster)
self.assess_status.assert_called_once_with()
def test_config_changed(self):
self.patch_object(handlers.designate, 'assess_status')
handlers.config_changed()
self.assess_status.assert_called_once_with()
the_charm.configure_ha_resources.assert_called_once_with(hacluster)

View File

@ -71,90 +71,6 @@ class Helper(unittest.TestCase):
setattr(self, name, started)
class TestOpenStackDesignate(Helper):
def test_install(self):
self.patch(designate.DesignateCharm.singleton, 'install')
designate.install()
self.install.assert_called_once_with()
def test_db_sync_done(self):
self.patch(designate.DesignateCharm.singleton, 'db_sync_done')
designate.db_sync_done()
self.db_sync_done.assert_called_once_with()
def test_db_sync(self):
self.patch(designate.DesignateCharm.singleton, 'db_sync')
designate.db_sync()
self.db_sync.assert_called_once_with()
def test_render_base_config(self):
self.patch(designate.DesignateCharm.singleton, 'render_base_config')
designate.render_base_config('interfaces_list')
self.render_base_config.assert_called_once_with('interfaces_list')
def test_domain_init_done(self):
self.patch(designate.DesignateCharm.singleton, 'domain_init_done')
designate.domain_init_done()
self.domain_init_done.assert_called_once_with()
def test_render_full_config(self):
self.patch(designate.DesignateCharm.singleton, 'render_full_config')
designate.render_full_config('interfaces_list')
self.render_full_config.assert_called_once_with('interfaces_list')
def test_register_endpoints(self):
self.patch(designate.DesignateCharm, 'service_type',
new_callable=mock.PropertyMock)
self.patch(designate.DesignateCharm, 'region',
new_callable=mock.PropertyMock)
self.patch(designate.DesignateCharm, 'public_url',
new_callable=mock.PropertyMock)
self.patch(designate.DesignateCharm, 'internal_url',
new_callable=mock.PropertyMock)
self.patch(designate.DesignateCharm, '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()
designate.register_endpoints(keystone)
keystone.register_endpoints.assert_called_once_with(
'type1', 'region1', 'public_url', 'internal_url', 'admin_url')
def test_configure_ha_resources(self):
self.patch(designate.DesignateCharm.singleton, 'db_sync')
designate.db_sync()
self.db_sync.assert_called_once_with()
def test_restart_all(self):
self.patch(designate.DesignateCharm.singleton, 'restart_all')
designate.restart_all()
self.restart_all.assert_called_once_with()
def test_configure_ssl(self):
self.patch(designate.DesignateCharm.singleton, 'configure_ssl')
designate.configure_ssl()
self.configure_ssl.assert_called_once_with(None)
def test_update_peers(self):
self.patch(designate.DesignateCharm.singleton, 'update_peers')
designate.update_peers('cluster')
self.update_peers.assert_called_once_with('cluster')
def test_render_rndc_keys(self):
self.patch(designate.DesignateCharm.singleton, 'render_rndc_keys')
designate.render_rndc_keys()
self.render_rndc_keys.assert_called_once_with()
def test_assess_status(self):
self.patch(designate.DesignateCharm.singleton, 'assess_status')
designate.assess_status()
self.assess_status.assert_called_once_with()
class TestDesignateDBAdapter(Helper):
def fake_get_uri(self, prefix):
@ -279,35 +195,6 @@ class TestDesignateConfigurationAdapter(Helper):
self.assertEqual(a.rndc_master_ip, 'intip')
class TestDesignateAdapters(Helper):
def test_designate_adapters(self):
self.patch(
designate.openstack_adapters.APIConfigurationAdapter,
'get_network_addresses')
cluster_relation = mock.MagicMock()
cluster_relation.relation_name = 'cluster'
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 DesignateConfigurationAdapter
b = designate.DesignateAdapters([amqp_relation,
cluster_relation,
shared_db_relation,
other_relation])
# ensure that the relevant things got put on.
self.assertTrue(
isinstance(
b.other,
designate.openstack_adapters.OpenStackRelationAdapter))
self.assertIsInstance(b.options,
designate.DesignateConfigurationAdapter)
class TestDesignateCharm(Helper):
def test_install(self):
@ -420,6 +307,7 @@ class TestDesignateCharm(Helper):
self.ensure_api_responding.return_value = True
self.patch(designate.hookenv, 'is_leader', return_value=True)
self.patch(designate.hookenv, 'leader_set')
self.patch(designate.hookenv, 'leader_get', return_value=False)
self.patch(designate.DesignateCharm, 'create_server')
self.patch(designate.DesignateCharm, 'create_domain')