725 lines
32 KiB
Python
725 lines
32 KiB
Python
import json
|
|
import mock
|
|
import unittest
|
|
|
|
import charmhelpers.contrib.openstack.cert_utils as cert_utils
|
|
|
|
|
|
class CertUtilsTests(unittest.TestCase):
|
|
|
|
def test_CertRequest(self):
|
|
cr = cert_utils.CertRequest()
|
|
self.assertEqual(cr.entries, [])
|
|
self.assertIsNone(cr.hostname_entry)
|
|
|
|
@mock.patch.object(cert_utils, 'local_unit', return_value='unit/2')
|
|
def test_CertRequest_add_entry(self, local_unit):
|
|
cr = cert_utils.CertRequest()
|
|
cr.add_entry('admin', 'admin.openstack.local', ['10.10.10.10'])
|
|
self.assertEqual(
|
|
cr.get_request(),
|
|
{'cert_requests':
|
|
'{"admin.openstack.local": {"sans": ["10.10.10.10"]}}',
|
|
'unit_name': 'unit_2'})
|
|
|
|
@mock.patch.object(cert_utils, 'local_unit', return_value='unit/2')
|
|
@mock.patch.object(cert_utils, 'resolve_network_cidr')
|
|
@mock.patch.object(cert_utils, 'get_vip_in_network')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
def test_CertRequest_add_hostname_cn(self, local_address, get_hostname,
|
|
get_vip_in_network,
|
|
resolve_network_cidr, local_unit):
|
|
resolve_network_cidr.side_effect = lambda x: x
|
|
get_vip_in_network.return_value = '10.1.2.100'
|
|
local_address.return_value = '10.1.2.3'
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
cr = cert_utils.CertRequest()
|
|
cr.add_hostname_cn()
|
|
self.assertEqual(
|
|
cr.get_request(),
|
|
{'cert_requests':
|
|
'{"juju-unit-2": {"sans": ["10.1.2.100", "10.1.2.3"]}}',
|
|
'unit_name': 'unit_2'})
|
|
|
|
@mock.patch.object(cert_utils, 'local_unit', return_value='unit/2')
|
|
@mock.patch.object(cert_utils, 'resolve_network_cidr')
|
|
@mock.patch.object(cert_utils, 'get_vip_in_network')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
def test_CertRequest_add_hostname_cn_ip(self, local_address, get_hostname,
|
|
get_vip_in_network,
|
|
resolve_network_cidr, local_unit):
|
|
resolve_network_cidr.side_effect = lambda x: x
|
|
get_vip_in_network.return_value = '10.1.2.100'
|
|
local_address.return_value = '10.1.2.3'
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
cr = cert_utils.CertRequest()
|
|
cr.add_hostname_cn()
|
|
cr.add_hostname_cn_ip(['10.1.2.4'])
|
|
self.assertEqual(
|
|
cr.get_request(),
|
|
{'cert_requests':
|
|
('{"juju-unit-2": {"sans": ["10.1.2.100", "10.1.2.3", '
|
|
'"10.1.2.4"]}}'),
|
|
'unit_name': 'unit_2'})
|
|
|
|
@mock.patch.object(cert_utils, 'get_certificate_sans')
|
|
@mock.patch.object(cert_utils, 'local_unit', return_value='unit/2')
|
|
@mock.patch.object(cert_utils, 'resolve_network_cidr')
|
|
@mock.patch.object(cert_utils, 'get_vip_in_network')
|
|
@mock.patch.object(cert_utils, 'network_get_primary_address')
|
|
@mock.patch.object(cert_utils, 'resolve_address')
|
|
@mock.patch.object(cert_utils, 'config')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
def test_get_certificate_request(self, local_address, get_hostname,
|
|
config, resolve_address,
|
|
network_get_primary_address,
|
|
get_vip_in_network, resolve_network_cidr,
|
|
local_unit, get_certificate_sans):
|
|
local_address.return_value = '10.1.2.3'
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
_config = {
|
|
'os-internal-hostname': 'internal.openstack.local',
|
|
'os-admin-hostname': 'admin.openstack.local',
|
|
'os-public-hostname': 'public.openstack.local',
|
|
}
|
|
_resolve_address = {
|
|
'int': '10.0.0.2',
|
|
'internal': '10.0.0.2',
|
|
'admin': '10.10.0.2',
|
|
'public': '10.20.0.2',
|
|
}
|
|
_npa = {
|
|
'internal': '10.0.0.3',
|
|
'admin': '10.10.0.3',
|
|
'public': '10.20.0.3',
|
|
}
|
|
_vips = {
|
|
'10.0.0.0/16': '10.0.0.100',
|
|
'10.10.0.0/16': '10.10.0.100',
|
|
'10.20.0.0/16': '10.20.0.100',
|
|
}
|
|
_resolve_nets = {
|
|
'10.0.0.3': '10.0.0.0/16',
|
|
'10.10.0.3': '10.10.0.0/16',
|
|
'10.20.0.3': '10.20.0.0/16',
|
|
}
|
|
get_certificate_sans.return_value = list(set(
|
|
list(_resolve_address.values()) +
|
|
list(_npa.values()) +
|
|
list(_vips.values())))
|
|
expect = {
|
|
'admin.openstack.local': {
|
|
'sans': ['10.10.0.100', '10.10.0.2', '10.10.0.3']},
|
|
'internal.openstack.local': {
|
|
'sans': ['10.0.0.100', '10.0.0.2', '10.0.0.3']},
|
|
'juju-unit-2': {'sans': ['10.1.2.3']},
|
|
'public.openstack.local': {
|
|
'sans': ['10.20.0.100', '10.20.0.2', '10.20.0.3']}}
|
|
self.maxDiff = None
|
|
config.side_effect = lambda x: _config.get(x)
|
|
get_vip_in_network.side_effect = lambda x: _vips.get(x)
|
|
resolve_network_cidr.side_effect = lambda x: _resolve_nets.get(x)
|
|
network_get_primary_address.side_effect = lambda x: _npa.get(x)
|
|
resolve_address.side_effect = \
|
|
lambda endpoint_type: _resolve_address[endpoint_type]
|
|
output = json.loads(
|
|
cert_utils.get_certificate_request()['cert_requests'])
|
|
self.assertEqual(
|
|
output,
|
|
expect)
|
|
get_certificate_sans.assert_called_once_with(
|
|
bindings=['internal', 'admin', 'public'])
|
|
|
|
@mock.patch.object(cert_utils, 'get_certificate_sans')
|
|
@mock.patch.object(cert_utils, 'local_unit', return_value='unit/2')
|
|
@mock.patch.object(cert_utils, 'resolve_network_cidr')
|
|
@mock.patch.object(cert_utils, 'get_vip_in_network')
|
|
@mock.patch.object(cert_utils, 'network_get_primary_address')
|
|
@mock.patch.object(cert_utils, 'resolve_address')
|
|
@mock.patch.object(cert_utils, 'config')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
def test_get_certificate_request_no_hostnames(
|
|
self, local_address, get_hostname, config, resolve_address,
|
|
network_get_primary_address, get_vip_in_network,
|
|
resolve_network_cidr, local_unit, get_certificate_sans):
|
|
local_address.return_value = '10.1.2.3'
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
_config = {
|
|
'os-admin-hostname': 'admin.openstack.local',
|
|
'os-public-hostname': 'public.openstack.local',
|
|
}
|
|
_resolve_address = {
|
|
'int': '10.0.0.2',
|
|
'internal': '10.0.0.2',
|
|
'admin': '10.10.0.2',
|
|
'public': '10.20.0.2',
|
|
}
|
|
_npa = {
|
|
'internal': '10.0.0.3',
|
|
'admin': '10.10.0.3',
|
|
'public': '10.20.0.3',
|
|
'mybinding': '10.30.0.3',
|
|
}
|
|
_vips = {
|
|
'10.0.0.0/16': '10.0.0.100',
|
|
'10.10.0.0/16': '10.10.0.100',
|
|
'10.20.0.0/16': '10.20.0.100',
|
|
}
|
|
_resolve_nets = {
|
|
'10.0.0.3': '10.0.0.0/16',
|
|
'10.10.0.3': '10.10.0.0/16',
|
|
'10.20.0.3': '10.20.0.0/16',
|
|
}
|
|
get_certificate_sans.return_value = list(set(
|
|
list(_resolve_address.values()) +
|
|
list(_npa.values()) +
|
|
list(_vips.values())))
|
|
expect = {
|
|
'admin.openstack.local': {
|
|
'sans': ['10.10.0.100', '10.10.0.2', '10.10.0.3']},
|
|
'juju-unit-2': {'sans': [
|
|
'10.0.0.100', '10.0.0.2', '10.0.0.3', '10.1.2.3', '10.30.0.3']},
|
|
'public.openstack.local': {
|
|
'sans': ['10.20.0.100', '10.20.0.2', '10.20.0.3']}}
|
|
self.maxDiff = None
|
|
config.side_effect = lambda x: _config.get(x)
|
|
get_vip_in_network.side_effect = lambda x: _vips.get(x)
|
|
resolve_network_cidr.side_effect = lambda x: _resolve_nets.get(x)
|
|
network_get_primary_address.side_effect = lambda x: _npa.get(x)
|
|
resolve_address.side_effect = \
|
|
lambda endpoint_type: _resolve_address[endpoint_type]
|
|
output = json.loads(
|
|
cert_utils.get_certificate_request(
|
|
bindings=['mybinding'])['cert_requests'])
|
|
self.assertEqual(
|
|
output,
|
|
expect)
|
|
get_certificate_sans.assert_called_once_with(
|
|
bindings=['mybinding', 'internal', 'admin', 'public'])
|
|
|
|
@mock.patch.object(cert_utils, 'get_certificate_request')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
@mock.patch.object(cert_utils.os, 'symlink')
|
|
@mock.patch.object(cert_utils.os.path, 'isfile')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
def test_create_ip_cert_links(self, get_hostname, isfile,
|
|
symlink, local_address, get_cert_request):
|
|
cert_request = {'cert_requests': {
|
|
'admin.openstack.local': {
|
|
'sans': ['10.10.0.100', '10.10.0.2', '10.10.0.3']},
|
|
'internal.openstack.local': {
|
|
'sans': ['10.0.0.100', '10.0.0.2', '10.0.0.3']},
|
|
'juju-unit-2': {'sans': ['10.1.2.3']},
|
|
'public.openstack.local': {
|
|
'sans': ['10.20.0.100', '10.20.0.2', '10.20.0.3']}}}
|
|
get_cert_request.return_value = cert_request
|
|
_files = {
|
|
'/etc/ssl/cert_juju-unit-2': True,
|
|
'/etc/ssl/cert_10.1.2.3': False,
|
|
'/etc/ssl/cert_admin.openstack.local': True,
|
|
'/etc/ssl/cert_10.10.0.100': False,
|
|
'/etc/ssl/cert_10.10.0.2': False,
|
|
'/etc/ssl/cert_10.10.0.3': False,
|
|
'/etc/ssl/cert_internal.openstack.local': True,
|
|
'/etc/ssl/cert_10.0.0.100': False,
|
|
'/etc/ssl/cert_10.0.0.2': False,
|
|
'/etc/ssl/cert_10.0.0.3': False,
|
|
'/etc/ssl/cert_public.openstack.local': True,
|
|
'/etc/ssl/cert_10.20.0.100': False,
|
|
'/etc/ssl/cert_10.20.0.2': False,
|
|
'/etc/ssl/cert_10.20.0.3': False,
|
|
'/etc/ssl/cert_funky-name': False,
|
|
}
|
|
isfile.side_effect = lambda x: _files[x]
|
|
expected = [
|
|
mock.call('/etc/ssl/cert_admin.openstack.local', '/etc/ssl/cert_10.10.0.100'),
|
|
mock.call('/etc/ssl/key_admin.openstack.local', '/etc/ssl/key_10.10.0.100'),
|
|
mock.call('/etc/ssl/cert_admin.openstack.local', '/etc/ssl/cert_10.10.0.2'),
|
|
mock.call('/etc/ssl/key_admin.openstack.local', '/etc/ssl/key_10.10.0.2'),
|
|
mock.call('/etc/ssl/cert_admin.openstack.local', '/etc/ssl/cert_10.10.0.3'),
|
|
mock.call('/etc/ssl/key_admin.openstack.local', '/etc/ssl/key_10.10.0.3'),
|
|
mock.call('/etc/ssl/cert_internal.openstack.local', '/etc/ssl/cert_10.0.0.100'),
|
|
mock.call('/etc/ssl/key_internal.openstack.local', '/etc/ssl/key_10.0.0.100'),
|
|
mock.call('/etc/ssl/cert_internal.openstack.local', '/etc/ssl/cert_10.0.0.2'),
|
|
mock.call('/etc/ssl/key_internal.openstack.local', '/etc/ssl/key_10.0.0.2'),
|
|
mock.call('/etc/ssl/cert_internal.openstack.local', '/etc/ssl/cert_10.0.0.3'),
|
|
mock.call('/etc/ssl/key_internal.openstack.local', '/etc/ssl/key_10.0.0.3'),
|
|
mock.call('/etc/ssl/cert_juju-unit-2', '/etc/ssl/cert_10.1.2.3'),
|
|
mock.call('/etc/ssl/key_juju-unit-2', '/etc/ssl/key_10.1.2.3'),
|
|
mock.call('/etc/ssl/cert_public.openstack.local', '/etc/ssl/cert_10.20.0.100'),
|
|
mock.call('/etc/ssl/key_public.openstack.local', '/etc/ssl/key_10.20.0.100'),
|
|
mock.call('/etc/ssl/cert_public.openstack.local', '/etc/ssl/cert_10.20.0.2'),
|
|
mock.call('/etc/ssl/key_public.openstack.local', '/etc/ssl/key_10.20.0.2'),
|
|
mock.call('/etc/ssl/cert_public.openstack.local', '/etc/ssl/cert_10.20.0.3'),
|
|
mock.call('/etc/ssl/key_public.openstack.local', '/etc/ssl/key_10.20.0.3')]
|
|
cert_utils.create_ip_cert_links('/etc/ssl')
|
|
symlink.assert_has_calls(expected, any_order=True)
|
|
# Customer hostname
|
|
symlink.reset_mock()
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
cert_utils.create_ip_cert_links(
|
|
'/etc/ssl',
|
|
custom_hostname_link='funky-name')
|
|
expected.extend([
|
|
mock.call('/etc/ssl/cert_juju-unit-2', '/etc/ssl/cert_funky-name'),
|
|
mock.call('/etc/ssl/key_juju-unit-2', '/etc/ssl/key_funky-name'),
|
|
])
|
|
symlink.assert_has_calls(expected, any_order=True)
|
|
get_cert_request.assert_called_with(
|
|
json_encode=False, bindings=['internal', 'admin', 'public'])
|
|
|
|
@mock.patch.object(cert_utils, 'get_certificate_request')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
@mock.patch.object(cert_utils.os, 'symlink')
|
|
@mock.patch.object(cert_utils.os.path, 'isfile')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
def test_create_ip_cert_links_bindings(
|
|
self, get_hostname, isfile, symlink, local_address, get_cert_request):
|
|
cert_request = {'cert_requests': {
|
|
'admin.openstack.local': {
|
|
'sans': ['10.10.0.100', '10.10.0.2', '10.10.0.3']},
|
|
'internal.openstack.local': {
|
|
'sans': ['10.0.0.100', '10.0.0.2', '10.0.0.3']},
|
|
'juju-unit-2': {'sans': ['10.1.2.3']},
|
|
'public.openstack.local': {
|
|
'sans': ['10.20.0.100', '10.20.0.2', '10.20.0.3']}}}
|
|
get_cert_request.return_value = cert_request
|
|
_files = {
|
|
'/etc/ssl/cert_juju-unit-2': True,
|
|
'/etc/ssl/cert_10.1.2.3': False,
|
|
'/etc/ssl/cert_admin.openstack.local': True,
|
|
'/etc/ssl/cert_10.10.0.100': False,
|
|
'/etc/ssl/cert_10.10.0.2': False,
|
|
'/etc/ssl/cert_10.10.0.3': False,
|
|
'/etc/ssl/cert_internal.openstack.local': True,
|
|
'/etc/ssl/cert_10.0.0.100': False,
|
|
'/etc/ssl/cert_10.0.0.2': False,
|
|
'/etc/ssl/cert_10.0.0.3': False,
|
|
'/etc/ssl/cert_public.openstack.local': True,
|
|
'/etc/ssl/cert_10.20.0.100': False,
|
|
'/etc/ssl/cert_10.20.0.2': False,
|
|
'/etc/ssl/cert_10.20.0.3': False,
|
|
'/etc/ssl/cert_funky-name': False,
|
|
}
|
|
isfile.side_effect = lambda x: _files[x]
|
|
expected = [
|
|
mock.call('/etc/ssl/cert_admin.openstack.local', '/etc/ssl/cert_10.10.0.100'),
|
|
mock.call('/etc/ssl/key_admin.openstack.local', '/etc/ssl/key_10.10.0.100'),
|
|
mock.call('/etc/ssl/cert_admin.openstack.local', '/etc/ssl/cert_10.10.0.2'),
|
|
mock.call('/etc/ssl/key_admin.openstack.local', '/etc/ssl/key_10.10.0.2'),
|
|
mock.call('/etc/ssl/cert_admin.openstack.local', '/etc/ssl/cert_10.10.0.3'),
|
|
mock.call('/etc/ssl/key_admin.openstack.local', '/etc/ssl/key_10.10.0.3'),
|
|
mock.call('/etc/ssl/cert_internal.openstack.local', '/etc/ssl/cert_10.0.0.100'),
|
|
mock.call('/etc/ssl/key_internal.openstack.local', '/etc/ssl/key_10.0.0.100'),
|
|
mock.call('/etc/ssl/cert_internal.openstack.local', '/etc/ssl/cert_10.0.0.2'),
|
|
mock.call('/etc/ssl/key_internal.openstack.local', '/etc/ssl/key_10.0.0.2'),
|
|
mock.call('/etc/ssl/cert_internal.openstack.local', '/etc/ssl/cert_10.0.0.3'),
|
|
mock.call('/etc/ssl/key_internal.openstack.local', '/etc/ssl/key_10.0.0.3'),
|
|
mock.call('/etc/ssl/cert_juju-unit-2', '/etc/ssl/cert_10.1.2.3'),
|
|
mock.call('/etc/ssl/key_juju-unit-2', '/etc/ssl/key_10.1.2.3'),
|
|
mock.call('/etc/ssl/cert_public.openstack.local', '/etc/ssl/cert_10.20.0.100'),
|
|
mock.call('/etc/ssl/key_public.openstack.local', '/etc/ssl/key_10.20.0.100'),
|
|
mock.call('/etc/ssl/cert_public.openstack.local', '/etc/ssl/cert_10.20.0.2'),
|
|
mock.call('/etc/ssl/key_public.openstack.local', '/etc/ssl/key_10.20.0.2'),
|
|
mock.call('/etc/ssl/cert_public.openstack.local', '/etc/ssl/cert_10.20.0.3'),
|
|
mock.call('/etc/ssl/key_public.openstack.local', '/etc/ssl/key_10.20.0.3')]
|
|
cert_utils.create_ip_cert_links('/etc/ssl', bindings=['mybindings'])
|
|
symlink.assert_has_calls(expected, any_order=True)
|
|
# Customer hostname
|
|
symlink.reset_mock()
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
cert_utils.create_ip_cert_links(
|
|
'/etc/ssl',
|
|
custom_hostname_link='funky-name', bindings=['mybinding'])
|
|
expected.extend([
|
|
mock.call('/etc/ssl/cert_juju-unit-2', '/etc/ssl/cert_funky-name'),
|
|
mock.call('/etc/ssl/key_juju-unit-2', '/etc/ssl/key_funky-name'),
|
|
])
|
|
symlink.assert_has_calls(expected, any_order=True)
|
|
get_cert_request.assert_called_with(
|
|
json_encode=False, bindings=['mybinding', 'internal', 'admin', 'public'])
|
|
|
|
@mock.patch.object(cert_utils, 'write_file')
|
|
def test_install_certs(self, write_file):
|
|
certs = {
|
|
'admin.openstack.local': {
|
|
'cert': 'ADMINCERT',
|
|
'key': 'ADMINKEY'}}
|
|
cert_utils.install_certs('/etc/ssl', certs, chain='CHAIN')
|
|
expected = [
|
|
mock.call(
|
|
path='/etc/ssl/cert_admin.openstack.local',
|
|
content='ADMINCERT\nCHAIN',
|
|
owner='root', group='root',
|
|
perms=0o640),
|
|
mock.call(
|
|
path='/etc/ssl/key_admin.openstack.local',
|
|
content='ADMINKEY',
|
|
owner='root', group='root',
|
|
perms=0o640),
|
|
]
|
|
write_file.assert_has_calls(expected)
|
|
|
|
@mock.patch.object(cert_utils, 'write_file')
|
|
def test_install_certs_ca(self, write_file):
|
|
certs = {
|
|
'admin.openstack.local': {
|
|
'cert': 'ADMINCERT',
|
|
'key': 'ADMINKEY'}}
|
|
ca = 'MYCA'
|
|
cert_utils.install_certs('/etc/ssl', certs, ca)
|
|
expected = [
|
|
mock.call(
|
|
path='/etc/ssl/cert_admin.openstack.local',
|
|
content='ADMINCERT\nMYCA',
|
|
owner='root', group='root',
|
|
perms=0o640),
|
|
mock.call(
|
|
path='/etc/ssl/key_admin.openstack.local',
|
|
content='ADMINKEY',
|
|
owner='root', group='root',
|
|
perms=0o640),
|
|
]
|
|
write_file.assert_has_calls(expected)
|
|
|
|
@mock.patch.object(cert_utils, '_manage_ca_certs')
|
|
@mock.patch.object(cert_utils, 'remote_service_name')
|
|
@mock.patch.object(cert_utils, 'local_unit')
|
|
@mock.patch.object(cert_utils, 'create_ip_cert_links')
|
|
@mock.patch.object(cert_utils, 'install_certs')
|
|
@mock.patch.object(cert_utils, 'install_ca_cert')
|
|
@mock.patch.object(cert_utils, 'mkdir')
|
|
@mock.patch.object(cert_utils, 'relation_get')
|
|
def test_process_certificates(self, relation_get, mkdir, install_ca_cert,
|
|
install_certs, create_ip_cert_links,
|
|
local_unit, remote_service_name,
|
|
_manage_ca_certs):
|
|
remote_service_name.return_value = 'vault'
|
|
local_unit.return_value = 'devnull/2'
|
|
certs = {
|
|
'admin.openstack.local': {
|
|
'cert': 'ADMINCERT',
|
|
'key': 'ADMINKEY'}}
|
|
_relation_info = {
|
|
'keystone_2.processed_requests': json.dumps(certs),
|
|
'chain': 'MYCHAIN',
|
|
'ca': 'ROOTCA',
|
|
}
|
|
relation_get.return_value = _relation_info
|
|
self.assertFalse(cert_utils.process_certificates(
|
|
'myservice',
|
|
'certificates:2',
|
|
'vault/0',
|
|
custom_hostname_link='funky-name'))
|
|
local_unit.return_value = 'keystone/2'
|
|
self.assertTrue(cert_utils.process_certificates(
|
|
'myservice',
|
|
'certificates:2',
|
|
'vault/0',
|
|
custom_hostname_link='funky-name'))
|
|
_manage_ca_certs.assert_called_once_with(
|
|
'ROOTCA', 'certificates:2')
|
|
install_certs.assert_called_once_with(
|
|
'/etc/apache2/ssl/myservice',
|
|
{'admin.openstack.local': {
|
|
'key': 'ADMINKEY', 'cert': 'ADMINCERT'}},
|
|
'MYCHAIN', user='root', group='root')
|
|
create_ip_cert_links.assert_called_once_with(
|
|
'/etc/apache2/ssl/myservice',
|
|
custom_hostname_link='funky-name',
|
|
bindings=['internal', 'admin', 'public'])
|
|
|
|
@mock.patch.object(cert_utils, '_manage_ca_certs')
|
|
@mock.patch.object(cert_utils, 'remote_service_name')
|
|
@mock.patch.object(cert_utils, 'local_unit')
|
|
@mock.patch.object(cert_utils, 'create_ip_cert_links')
|
|
@mock.patch.object(cert_utils, 'install_certs')
|
|
@mock.patch.object(cert_utils, 'install_ca_cert')
|
|
@mock.patch.object(cert_utils, 'mkdir')
|
|
@mock.patch.object(cert_utils, 'relation_get')
|
|
def test_process_certificates_bindings(
|
|
self, relation_get, mkdir, install_ca_cert,
|
|
install_certs, create_ip_cert_links,
|
|
local_unit, remote_service_name, _manage_ca_certs):
|
|
remote_service_name.return_value = 'vault'
|
|
local_unit.return_value = 'devnull/2'
|
|
certs = {
|
|
'admin.openstack.local': {
|
|
'cert': 'ADMINCERT',
|
|
'key': 'ADMINKEY'}}
|
|
_relation_info = {
|
|
'keystone_2.processed_requests': json.dumps(certs),
|
|
'chain': 'MYCHAIN',
|
|
'ca': 'ROOTCA',
|
|
}
|
|
relation_get.return_value = _relation_info
|
|
self.assertFalse(cert_utils.process_certificates(
|
|
'myservice',
|
|
'certificates:2',
|
|
'vault/0',
|
|
custom_hostname_link='funky-name'))
|
|
local_unit.return_value = 'keystone/2'
|
|
self.assertTrue(cert_utils.process_certificates(
|
|
'myservice',
|
|
'certificates:2',
|
|
'vault/0',
|
|
custom_hostname_link='funky-name',
|
|
bindings=['mybinding']))
|
|
_manage_ca_certs.assert_called_once_with(
|
|
'ROOTCA', 'certificates:2')
|
|
install_certs.assert_called_once_with(
|
|
'/etc/apache2/ssl/myservice',
|
|
{'admin.openstack.local': {
|
|
'key': 'ADMINKEY', 'cert': 'ADMINCERT'}},
|
|
'MYCHAIN', user='root', group='root')
|
|
create_ip_cert_links.assert_called_once_with(
|
|
'/etc/apache2/ssl/myservice',
|
|
custom_hostname_link='funky-name',
|
|
bindings=['mybinding', 'internal', 'admin', 'public'])
|
|
|
|
@mock.patch.object(cert_utils, 'remote_service_name')
|
|
@mock.patch.object(cert_utils, 'relation_ids')
|
|
def test_get_cert_relation_ca_name(self, relation_ids, remote_service_name):
|
|
remote_service_name.return_value = 'vault'
|
|
|
|
# Test with argument:
|
|
self.assertEqual(cert_utils.get_cert_relation_ca_name('certificates:1'),
|
|
'vault_juju_ca_cert')
|
|
remote_service_name.assert_called_once_with(relid='certificates:1')
|
|
remote_service_name.reset_mock()
|
|
|
|
# Test without argument:
|
|
relation_ids.return_value = ['certificates:2']
|
|
self.assertEqual(cert_utils.get_cert_relation_ca_name(),
|
|
'vault_juju_ca_cert')
|
|
remote_service_name.assert_called_once_with(relid='certificates:2')
|
|
remote_service_name.reset_mock()
|
|
|
|
# Test without argument nor 'certificates' relation:
|
|
relation_ids.return_value = []
|
|
self.assertEqual(cert_utils.get_cert_relation_ca_name(), '')
|
|
remote_service_name.assert_not_called()
|
|
|
|
@mock.patch.object(cert_utils, 'remote_service_name')
|
|
@mock.patch.object(cert_utils.os, 'remove')
|
|
@mock.patch.object(cert_utils.os.path, 'exists')
|
|
@mock.patch.object(cert_utils, 'config')
|
|
@mock.patch.object(cert_utils, 'install_ca_cert')
|
|
def test__manage_ca_certs(self, install_ca_cert, config, os_exists,
|
|
os_remove, remote_service_name):
|
|
remote_service_name.return_value = 'vault'
|
|
_config = {}
|
|
config.side_effect = lambda x: _config.get(x)
|
|
os_exists.return_value = False
|
|
cert_utils._manage_ca_certs('CA', 'certificates:2')
|
|
install_ca_cert.assert_called_once_with(
|
|
b'CA',
|
|
name='vault_juju_ca_cert')
|
|
self.assertFalse(os_remove.called)
|
|
# Test old cert removed.
|
|
install_ca_cert.reset_mock()
|
|
os_exists.reset_mock()
|
|
os_exists.return_value = True
|
|
cert_utils._manage_ca_certs('CA', 'certificates:2')
|
|
install_ca_cert.assert_called_once_with(
|
|
b'CA',
|
|
name='vault_juju_ca_cert')
|
|
os_remove.assert_called_once_with(
|
|
'/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt')
|
|
# Test cert is installed from config
|
|
_config['ssl_ca'] = 'Q0FGUk9NQ09ORklHCg=='
|
|
install_ca_cert.reset_mock()
|
|
os_remove.reset_mock()
|
|
os_exists.reset_mock()
|
|
os_exists.return_value = True
|
|
cert_utils._manage_ca_certs('CA', 'certificates:2')
|
|
expected = [
|
|
mock.call(b'CAFROMCONFIG', name='keystone_juju_ca_cert'),
|
|
mock.call(b'CA', name='vault_juju_ca_cert')]
|
|
install_ca_cert.assert_has_calls(expected)
|
|
self.assertFalse(os_remove.called)
|
|
|
|
@mock.patch.object(cert_utils, 'local_unit')
|
|
@mock.patch.object(cert_utils, 'related_units')
|
|
@mock.patch.object(cert_utils, 'relation_ids')
|
|
@mock.patch.object(cert_utils, 'relation_get')
|
|
def test_get_requests_for_local_unit(self, relation_get, relation_ids,
|
|
related_units, local_unit):
|
|
local_unit.return_value = 'rabbitmq-server/2'
|
|
relation_ids.return_value = ['certificates:12']
|
|
related_units.return_value = ['vault/0']
|
|
certs = {
|
|
'juju-cd4bb3-5.lxd': {
|
|
'cert': 'BASECERT',
|
|
'key': 'BASEKEY'},
|
|
'juju-cd4bb3-5.internal': {
|
|
'cert': 'INTERNALCERT',
|
|
'key': 'INTERNALKEY'}}
|
|
_relation_info = {
|
|
'rabbitmq-server_2.processed_requests': json.dumps(certs),
|
|
'chain': 'MYCHAIN',
|
|
'ca': 'ROOTCA',
|
|
}
|
|
relation_get.return_value = _relation_info
|
|
self.assertEqual(
|
|
cert_utils.get_requests_for_local_unit(),
|
|
[{
|
|
'ca': 'ROOTCA',
|
|
'certs': {
|
|
'juju-cd4bb3-5.lxd': {
|
|
'cert': 'BASECERT',
|
|
'key': 'BASEKEY'},
|
|
'juju-cd4bb3-5.internal': {
|
|
'cert': 'INTERNALCERT',
|
|
'key': 'INTERNALKEY'}},
|
|
'chain': 'MYCHAIN'}]
|
|
)
|
|
|
|
@mock.patch.object(cert_utils, 'get_requests_for_local_unit')
|
|
def test_get_bundle_for_cn(self, get_requests_for_local_unit):
|
|
get_requests_for_local_unit.return_value = [{
|
|
'ca': 'ROOTCA',
|
|
'certs': {
|
|
'juju-cd4bb3-5.lxd': {
|
|
'cert': 'BASECERT',
|
|
'key': 'BASEKEY'},
|
|
'juju-cd4bb3-5.internal': {
|
|
'cert': 'INTERNALCERT',
|
|
'key': 'INTERNALKEY'}},
|
|
'chain': 'MYCHAIN'}]
|
|
self.assertEqual(
|
|
cert_utils.get_bundle_for_cn('juju-cd4bb3-5.internal'),
|
|
{
|
|
'ca': 'ROOTCA',
|
|
'cert': 'INTERNALCERT',
|
|
'chain': 'MYCHAIN',
|
|
'key': 'INTERNALKEY'})
|
|
|
|
@mock.patch.object(cert_utils, 'local_unit', return_value='unit/2')
|
|
@mock.patch.object(cert_utils, 'resolve_network_cidr')
|
|
@mock.patch.object(cert_utils, 'get_vip_in_network')
|
|
@mock.patch.object(cert_utils, 'get_relation_ip')
|
|
@mock.patch.object(cert_utils, 'resolve_address')
|
|
@mock.patch.object(cert_utils, 'config')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
def test_get_certificate_sans(self, local_address, get_hostname,
|
|
config, resolve_address,
|
|
get_relation_ip,
|
|
get_vip_in_network, resolve_network_cidr,
|
|
local_unit):
|
|
local_address.return_value = '10.1.2.3'
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
_config = {
|
|
'os-internal-hostname': 'internal.openstack.local',
|
|
'os-admin-hostname': 'admin.openstack.local',
|
|
'os-public-hostname': 'public.openstack.local',
|
|
}
|
|
_resolve_address = {
|
|
'int': '10.0.0.2',
|
|
'internal': '10.0.0.2',
|
|
'admin': '10.10.0.2',
|
|
'public': '10.20.0.2',
|
|
}
|
|
_npa = {
|
|
'internal': '10.0.0.3',
|
|
'admin': '10.10.0.3',
|
|
'public': '10.20.0.3',
|
|
}
|
|
_vips = {
|
|
'10.0.0.0/16': '10.0.0.100',
|
|
'10.10.0.0/16': '10.10.0.100',
|
|
'10.20.0.0/16': '10.20.0.100',
|
|
}
|
|
_resolve_nets = {
|
|
'10.0.0.3': '10.0.0.0/16',
|
|
'10.10.0.3': '10.10.0.0/16',
|
|
'10.20.0.3': '10.20.0.0/16',
|
|
}
|
|
expect = list(set([
|
|
'10.10.0.100', '10.10.0.2', '10.10.0.3',
|
|
'10.0.0.100', '10.0.0.2', '10.0.0.3',
|
|
'10.1.2.3',
|
|
'10.20.0.100', '10.20.0.2', '10.20.0.3']))
|
|
self.maxDiff = None
|
|
config.side_effect = lambda x: _config.get(x)
|
|
get_vip_in_network.side_effect = lambda x: _vips.get(x)
|
|
resolve_network_cidr.side_effect = lambda x: _resolve_nets.get(x)
|
|
get_relation_ip.side_effect = lambda x, cidr_network: _npa.get(x)
|
|
resolve_address.side_effect = \
|
|
lambda endpoint_type: _resolve_address[endpoint_type]
|
|
expected_get_relation_ip_calls = [
|
|
mock.call('internal', cidr_network=None),
|
|
mock.call('admin', cidr_network=None),
|
|
mock.call('public', cidr_network=None)]
|
|
self.assertEqual(cert_utils.get_certificate_sans().sort(),
|
|
expect.sort())
|
|
get_relation_ip.assert_has_calls(
|
|
expected_get_relation_ip_calls, any_order=True)
|
|
|
|
@mock.patch.object(cert_utils, 'local_unit', return_value='unit/2')
|
|
@mock.patch.object(cert_utils, 'resolve_network_cidr')
|
|
@mock.patch.object(cert_utils, 'get_vip_in_network')
|
|
@mock.patch.object(cert_utils, 'get_relation_ip')
|
|
@mock.patch.object(cert_utils, 'resolve_address')
|
|
@mock.patch.object(cert_utils, 'config')
|
|
@mock.patch.object(cert_utils, 'get_hostname')
|
|
@mock.patch.object(cert_utils, 'local_address')
|
|
def test_get_certificate_sans_bindings(
|
|
self, local_address, get_hostname, config, resolve_address,
|
|
get_relation_ip, get_vip_in_network, resolve_network_cidr, local_unit):
|
|
local_address.return_value = '10.1.2.3'
|
|
get_hostname.return_value = 'juju-unit-2'
|
|
_config = {
|
|
'os-internal-hostname': 'internal.openstack.local',
|
|
'os-admin-hostname': 'admin.openstack.local',
|
|
'os-public-hostname': 'public.openstack.local',
|
|
}
|
|
_resolve_address = {
|
|
'int': '10.0.0.2',
|
|
'internal': '10.0.0.2',
|
|
'admin': '10.10.0.2',
|
|
'public': '10.20.0.2',
|
|
}
|
|
_npa = {
|
|
'internal': '10.0.0.3',
|
|
'admin': '10.10.0.3',
|
|
'public': '10.20.0.3',
|
|
}
|
|
_vips = {
|
|
'10.0.0.0/16': '10.0.0.100',
|
|
'10.10.0.0/16': '10.10.0.100',
|
|
'10.20.0.0/16': '10.20.0.100',
|
|
}
|
|
_resolve_nets = {
|
|
'10.0.0.3': '10.0.0.0/16',
|
|
'10.10.0.3': '10.10.0.0/16',
|
|
'10.20.0.3': '10.20.0.0/16',
|
|
}
|
|
expect = list(set([
|
|
'10.10.0.100', '10.10.0.2', '10.10.0.3',
|
|
'10.0.0.100', '10.0.0.2', '10.0.0.3',
|
|
'10.1.2.3',
|
|
'10.20.0.100', '10.20.0.2', '10.20.0.3']))
|
|
self.maxDiff = None
|
|
config.side_effect = lambda x: _config.get(x)
|
|
get_vip_in_network.side_effect = lambda x: _vips.get(x)
|
|
resolve_network_cidr.side_effect = lambda x: _resolve_nets.get(x)
|
|
get_relation_ip.side_effect = lambda x, cidr_network: _npa.get(x)
|
|
resolve_address.side_effect = \
|
|
lambda endpoint_type: _resolve_address[endpoint_type]
|
|
expected_get_relation_ip_calls = [
|
|
mock.call('internal', cidr_network=None),
|
|
mock.call('admin', cidr_network=None),
|
|
mock.call('public', cidr_network=None),
|
|
mock.call('mybinding', cidr_network=None)]
|
|
self.assertEqual(
|
|
cert_utils.get_certificate_sans(bindings=['mybinding']).sort(),
|
|
expect.sort())
|
|
get_relation_ip.assert_has_calls(
|
|
expected_get_relation_ip_calls, any_order=True)
|