Fix for not passing CA cert to nova-compute

The charm looked for `keystone_juju_ca_cert` on disk
instead of
`/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt`

Synced charm-helpers for
https://github.com/juju/charm-helpers/pull/570

Change-Id: Ib7cfdadc3a75fca951792ef2c2e2b454b1ad021d
Closes-Bug: #1915504
This commit is contained in:
Aurelien Lourot 2021-02-15 10:52:11 +01:00
parent 0e02c9a207
commit bd3e24f359
6 changed files with 94 additions and 44 deletions

View File

@ -337,10 +337,8 @@ class NRPE(object):
"command": nrpecheck.command,
}
# If we were passed max_check_attempts, add that to the relation data
try:
if nrpecheck.max_check_attempts is not None:
nrpe_monitors[nrpecheck.shortname]['max_check_attempts'] = nrpecheck.max_check_attempts
except AttributeError:
pass
# update-status hooks are configured to firing every 5 minutes by
# default. When nagios-nrpe-server is restarted, the nagios server

View File

@ -47,7 +47,7 @@ from charmhelpers.contrib.network.ip import (
)
from charmhelpers.core.host import (
CA_CERT_DIR,
ca_cert_absolute_path,
install_ca_cert,
mkdir,
write_file,
@ -307,6 +307,26 @@ def install_certs(ssl_dir, certs, chain=None, user='root', group='root'):
content=bundle['key'], perms=0o640)
def get_cert_relation_ca_name(cert_relation_id=None):
"""Determine CA certificate name as provided by relation.
The filename on disk depends on the name chosen for the application on the
providing end of the certificates relation.
:param cert_relation_id: (Optional) Relation id providing the certs
:type cert_relation_id: str
:returns: CA certificate filename without path nor extension
:rtype: str
"""
if cert_relation_id is None:
try:
cert_relation_id = relation_ids('certificates')[0]
except IndexError:
return ''
return '{}_juju_ca_cert'.format(
remote_service_name(relid=cert_relation_id))
def _manage_ca_certs(ca, cert_relation_id):
"""Manage CA certs.
@ -316,7 +336,7 @@ def _manage_ca_certs(ca, cert_relation_id):
:type cert_relation_id: str
"""
config_ssl_ca = config('ssl_ca')
config_cert_file = '{}/{}.crt'.format(CA_CERT_DIR, CONFIG_CA_CERT_FILE)
config_cert_file = ca_cert_absolute_path(CONFIG_CA_CERT_FILE)
if config_ssl_ca:
log("Installing CA certificate from charm ssl_ca config to {}".format(
config_cert_file), INFO)
@ -329,8 +349,7 @@ def _manage_ca_certs(ca, cert_relation_id):
log("Installing CA certificate from certificate relation", INFO)
install_ca_cert(
ca.encode(),
name='{}_juju_ca_cert'.format(
remote_service_name(relid=cert_relation_id)))
name=get_cert_relation_ca_name(cert_relation_id))
def process_certificates(service_name, relation_id, unit,

View File

@ -226,6 +226,17 @@ def relation_id(relation_name=None, service_or_unit=None):
raise ValueError('Must specify neither or both of relation_name and service_or_unit')
def departing_unit():
"""The departing unit for the current relation hook.
Available since juju 2.8.
:returns: the departing unit, or None if the information isn't available.
:rtype: Optional[str]
"""
return os.environ.get('JUJU_DEPARTING_UNIT', None)
def local_unit():
"""Local unit ID"""
return os.environ['JUJU_UNIT_NAME']

View File

@ -1068,6 +1068,17 @@ def modulo_distribution(modulo=3, wait=30, non_zero_wait=False):
return calculated_wait_time
def ca_cert_absolute_path(basename_without_extension):
"""Returns absolute path to CA certificate.
:param basename_without_extension: Filename without extension
:type basename_without_extension: str
:returns: Absolute full path
:rtype: str
"""
return '{}/{}.crt'.format(CA_CERT_DIR, basename_without_extension)
def install_ca_cert(ca_cert, name=None):
"""
Install the given cert as a trusted CA.
@ -1083,7 +1094,7 @@ def install_ca_cert(ca_cert, name=None):
ca_cert = ca_cert.encode('utf8')
if not name:
name = 'juju-{}'.format(charm_name())
cert_file = '{}/{}.crt'.format(CA_CERT_DIR, name)
cert_file = ca_cert_absolute_path(name)
new_hash = hashlib.md5(ca_cert).hexdigest()
if file_hash(cert_file) == new_hash:
return

View File

@ -24,6 +24,7 @@ import uuid
import charmhelpers.contrib.hahelpers.apache as ch_apache
import charmhelpers.contrib.hahelpers.cluster as ch_cluster
import charmhelpers.contrib.network.ip as ch_ip
import charmhelpers.contrib.openstack.cert_utils as ch_cert_utils
import charmhelpers.contrib.openstack.context as ch_context
import charmhelpers.contrib.openstack.ip as ch_openstack_ip
import charmhelpers.contrib.openstack.templating as ch_templating
@ -1035,36 +1036,15 @@ def auth_token_config(setting):
return value
def get_cert_relation_ca_filename():
"""Determine absolute path to CA certificate file as provided by relation.
The filename on disk depends on the name chosen for the application on the
providing end of the certificates relation.
:type cert_relation_id: str
:returns: Absolute path to CA certificate file
:rtype: str
"""
# NOTE(fnordahl): this function belongs together with the c-h cert_utils
# module, however given we at the time of this writing are frozen I'll add
# it here as a tactical measure.
# TODO: move to c-h.contrib.openstack.cert_utils
for cert_relation_id in hookenv.relation_ids('certificates'):
return os.path.join(
ch_host.CA_CERT_DIR,
'{}_juju_ca_cert.crt'
.format(hookenv.remote_service_name(relid=cert_relation_id)))
return ''
def get_ca_cert_b64():
"""Retrieve CA-cert as provided by certificates relation or config.
:returns: Base64 encoded CA-certificate data
:rtype: str
"""
ca_cert_file = (get_cert_relation_ca_filename() or
ca_cert_name = (ch_cert_utils.get_cert_relation_ca_name() or
ch_apache.CONFIG_CA_CERT_FILE)
ca_cert_file = ch_host.ca_cert_absolute_path(ca_cert_name)
try:
with open(ca_cert_file, 'rb') as _in:
return base64.b64encode(_in.read()).decode('utf-8')

View File

@ -717,27 +717,58 @@ class NovaCCUtilsTests(CharmTestCase):
self.assertFalse(rm.called)
_file.write.assert_called_with('|1|= fookey\n')
@patch.object(utils.hookenv, 'remote_service_name')
def test_get_cert_relation_ca_filename(self, mock_remote_service_name):
mock_remote_service_name.return_value = 'namedvault'
self.relation_ids.return_value = ['aRelation']
self.assertEquals(
utils.get_cert_relation_ca_filename(),
'/usr/local/share/ca-certificates/namedvault_juju_ca_cert.crt')
@patch('charmhelpers.contrib.openstack.cert_utils.'
'get_cert_relation_ca_name')
def test_get_ca_cert_b64_from_relation(self, get_cert_relation_ca_name):
# Test input simulating the case where a CA certificate has been
# provided by the 'certificates' relation and installed on disk:
get_cert_relation_ca_name.return_value = 'rel_juju_ca_cert'
open_side_effect = None # file is found
def test_get_ca_cert_b64(self):
with patch_open() as (_open, _file):
_file.readlines = MagicMock()
_file.write = MagicMock()
_file.read.return_value = b'mycert'
_open.side_effect = OSError
self.assertEqual(
utils.get_ca_cert_b64(),
'')
_open.side_effect = None
_open.side_effect = open_side_effect
self.assertEqual(
utils.get_ca_cert_b64(),
'bXljZXJ0')
_open.assert_called_once_with(
'/usr/local/share/ca-certificates/rel_juju_ca_cert.crt', 'rb')
@patch('charmhelpers.contrib.openstack.cert_utils.'
'get_cert_relation_ca_name')
def test_get_ca_cert_b64_from_option(self, get_cert_relation_ca_name):
# Test input simulating the case where a CA certificate has been
# provided by ssl_* option and installed on disk:
get_cert_relation_ca_name.return_value = ''
open_side_effect = None # file is found
with patch_open() as (_open, _file):
_file.readlines = MagicMock()
_file.write = MagicMock()
_file.read.return_value = b'mycert'
_open.side_effect = open_side_effect
self.assertEqual(
utils.get_ca_cert_b64(),
'bXljZXJ0')
_open.assert_called_once_with(
'/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt',
'rb')
@patch('charmhelpers.contrib.openstack.cert_utils.'
'get_cert_relation_ca_name')
def test_get_ca_cert_b64_not_found(self, get_cert_relation_ca_name):
# Test input simulating the case where no CA certificate can be found
# on disk:
get_cert_relation_ca_name.return_value = ''
open_side_effect = OSError
with patch_open() as (_open, _file):
_open.side_effect = open_side_effect
self.assertEqual(
utils.get_ca_cert_b64(),
'')
@patch.object(utils, 'known_hosts')
@patch('subprocess.check_call')