separate rndc.key file per application

This change fixes an issue that when the charm-designate is
related to two different designate-bind applications, the same
rndc key file is used for the two different applications.

We fix this by writing an rndc_key_file per application rather than in
a single rndc.key file for all the units.

Closes-Bug: #1995975

Change-Id: I5dafeb2b4dcf9549260081d3674038f836d29f0f
Signed-off-by: David Negreira <david.negreira@canonical.com>
This commit is contained in:
David Negreira 2024-03-25 09:21:14 +00:00
parent 587a772967
commit b5b4d600bd
6 changed files with 99 additions and 10 deletions

View File

@ -87,11 +87,13 @@ class BindRNDCRelationAdapter(openstack_adapters.OpenStackRelationAdapter):
"""
pconfig = []
for slave in self.slave_ips:
unit_name = slave['unit'].replace('/', '_').replace('-', '_')
application_name = slave['unit'].split('/')[0].replace('-', '_')
pconfig.append({
'nameserver': 'nameserver_{}'.format(unit_name),
'pool_target': 'nameserver_{}'.format(unit_name),
'nameserver': 'nameserver_{}'.format(application_name),
'pool_target': 'nameserver_{}'.format(application_name),
'address': slave['address'],
'rndc_key_file': '/etc/designate/rndc_{}.key'.format(
application_name),
})
return pconfig
@ -438,6 +440,28 @@ class DesignateCharm(ch_plugins.PolicydOverridePlugin,
hookenv.log("Problem with 'dns-slaves' config: {}"
.format(str(e)), level=hookenv.ERROR)
def render_relation_rndc_keys(self):
"""Render the rndc keys for each application in the dns-backend
relation
@returns None
"""
try:
applications = []
dns_backend = relations.endpoint_from_flag(
'dns-backend.available').conversations()
for conversation in dns_backend:
application_name = conversation.scope.split(
'/')[0].replace('-', '_')
if application_name not in applications:
applications.append(application_name)
rndckey = conversation.get_remote('rndckey')
self.write_key_file(application_name, rndckey)
except ValueError as e:
hookenv.log("problem writing relation_rndc_keys: {}"
.format(str(e)), level=hookenv.ERROR)
def configure_sink(self):
cmp_os_release = ch_utils.CompareOpenStackReleases(
self.release

View File

@ -225,6 +225,19 @@ def configure_designate_full(*args):
level=hookenv.ERROR)
@reactive.when_not('is-update-status-hook')
@reactive.when('dns-backend.available')
@reactive.when('db.synched')
@reactive.when(*COMPLETE_INTERFACE_STATES)
def configure_dns_backend_rndc_keys(*args):
"""Write the dns-backend relation configuration files and restart
designate-worker to apply the new config.
"""
with charm.provide_charm_instance() as instance:
instance.render_relation_rndc_keys()
host.service_restart('designate-worker')
def _render_sink_configs(instance, interfaces_list):
"""Helper: use the singleton from the DesignateCharm to render sink configs

View File

@ -36,7 +36,7 @@
options:
host: {{ slave.address }}
rndc_host: {{ slave.address }}
rndc_key_file: /etc/designate/rndc.key
rndc_key_file: {{ slave.rndc_key_file }}
{% endfor %}
{% endif %}
{% if options.pool_config %}

View File

@ -36,7 +36,7 @@
options:
host: {{ slave.address }}
rndc_host: {{ slave.address }}
rndc_key_file: /etc/designate/rndc.key
rndc_key_file: {{ slave.rndc_key_file }}
port: 53
{% endfor %}
{% endif %}

View File

@ -44,6 +44,8 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
'leadership.changed.pool-yaml-hash', ),
'reset_shared_db': ('shared-db.setup', ),
'configure_nrpe': ('base-config.rendered', ),
'configure_dns_backend_rndc_keys': (
all_interfaces + ('dns-backend.available', 'db.synched')),
},
'when_not': {
'setup_amqp_req': ('is-update-status-hook', ),
@ -65,6 +67,7 @@ class TestRegisteredHooks(test_utils.TestRegisteredHooks):
'configure_designate_full': ('is-update-status-hook', ),
'expose_rndc_address': ('is-update-status-hook', ),
'cluster_connected': ('is-update-status-hook', ),
'configure_dns_backend_rndc_keys': ('is-update-status-hook', ),
},
'when_any': {
'set_dns_config_available': (

View File

@ -101,15 +101,17 @@ class TestBindRNDCRelationAdapter(Helper):
'slave_ips', new=_slave_ips):
a = designate.BindRNDCRelationAdapter(relation)
expect = [{'address': 'addr1',
'nameserver': 'nameserver_unit_1',
'pool_target': 'nameserver_unit_1'},
'nameserver': 'nameserver_unit',
'pool_target': 'nameserver_unit',
'rndc_key_file': '/etc/designate/rndc_unit.key'},
{'address': 'addr2',
'nameserver': 'nameserver_unit_2',
'pool_target': 'nameserver_unit_2'}]
'nameserver': 'nameserver_unit',
'pool_target': 'nameserver_unit',
'rndc_key_file': '/etc/designate/rndc_unit.key'}]
self.assertEqual(a.pool_config, expect)
self.assertEqual(
a.pool_targets,
'nameserver_unit_1, nameserver_unit_2')
'nameserver_unit, nameserver_unit')
self.assertEqual(a.slave_addresses, 'addr1:53, addr2:53')
def test_rndc_info(self):
@ -269,6 +271,53 @@ class TestDesignateCharm(Helper):
]
self.write_key_file.assert_has_calls(calls)
def test_rndc_keys(self):
def fake_conversations():
conversations = []
Conversation = mock.Mock()
Conversation.key = 'reactive.conversations.dns-backend:65.'
'designate-bind-t1/1'
Conversation.namespace = 'dns-backend:65'
self.patch(Conversation, 'relation_ids',
return_value='dns-backend:65')
Conversation.relation_name = 'dns-backend'
Conversation.scope = 'designate-bind-t1/1'
self.patch(Conversation, 'get_remote', return_value='rndckey1')
conversations.append(Conversation)
Conversation = mock.Mock()
Conversation.key = 'reactive.conversations.dns-backend:66.'
'designate-bind-t0/1'
Conversation.namespace = 'dns-backend:66'
self.patch(Conversation, 'relation_ids',
return_value='dns-backend:66')
Conversation.relation_name = 'dns-backend'
Conversation.scope = 'designate-bind-t0/1'
self.patch(Conversation, 'get_remote', return_value='rndckey2')
conversations.append(Conversation)
return conversations
mock_endpoint_from_flag = mock.MagicMock()
mock_endpoint_from_flag.conversations.side_effect = fake_conversations
def fake_endpoint_from_flag(*args, **kwargs):
return mock_endpoint_from_flag
relation = mock.MagicMock()
self.patch(designate.DesignateCharm, 'write_key_file')
self.patch(designate.relations, 'endpoint_from_flag',
side_effect=fake_endpoint_from_flag)
designate.DesignateConfigurationAdapter(relation)
d = designate.DesignateCharm()
d.render_relation_rndc_keys()
calls = [
mock.call('designate_bind_t1', 'rndckey1'),
mock.call('designate_bind_t0', 'rndckey2'),
]
self.write_key_file.assert_has_calls(calls)
def test_get_domain_id(self):
self.patch(designate.DesignateCharm, 'ensure_api_responding')
self.patch(designate.subprocess, 'check_output')