Refactor ca functions

This commit is contained in:
Liam Young
2021-01-24 14:31:29 +00:00
parent a828774c48
commit a20733cd14
4 changed files with 153 additions and 76 deletions

View File

@@ -41,9 +41,7 @@ def wait_for_cacert(model_name=None):
:type model_name: str
"""
logging.info("Waiting for cacert")
cert_file = openstack_utils.get_cert_file_name(
'keystone')
zaza.model.block_until_file_has_contents(
zaza.openstack.utilities.openstack.block_until_ca_exists(
'keystone',
cert_file,
'CERTIFICATE',

View File

@@ -222,9 +222,7 @@ def validate_ca(cacertificate, application="keystone", port=5000):
:returns: None
:rtype: None
"""
cert_file = zaza.openstack.utilities.openstack.get_cert_file_name(
application)
zaza.model.block_until_file_has_contents(
zaza.openstack.utilities.openstack.block_until_ca_exists(
application,
cert_file,
cacertificate.decode().strip())
@@ -238,3 +236,6 @@ def validate_ca(cacertificate, application="keystone", port=5000):
fp.write(cacertificate.decode())
fp.flush()
requests.get('https://{}:{}'.format(ip, str(port)), verify=fp.name)
def get_cert():
print(zaza.openstack.utilities.openstack.get_remote_ca_cert_file('masakari'))

View File

@@ -154,9 +154,7 @@ class VaultTest(BaseVaultTest):
test_config = lifecycle_utils.get_charm_config()
del test_config['target_deploy_status']['vault']
cert_file = zaza.openstack.utilities.openstack.get_cert_file_name(
'keystone')
zaza.model.block_until_file_has_contents(
zaza.openstack.utilities.openstack.block_until_ca_exists(
'keystone',
cert_file,
cacert.decode().strip())

View File

@@ -27,6 +27,7 @@ import logging
import os
import paramiko
import re
import shutil
import six
import subprocess
import sys
@@ -182,7 +183,10 @@ WORKLOAD_STATUS_EXCEPTIONS = {
'ceilometer and gnocchi')}}
# For vault TLS certificates
CACERT_FILENAME_FORMAT = "{}_juju_ca_cert.crt"
CERT_PROVIDORS = ['vault']
LOCAL_CERT_DIR = "tests"
REMOTE_CERT_DIR = "/usr/local/share/ca-certificates"
KEYSTONE_CACERT = "keystone_juju_ca_cert.crt"
KEYSTONE_REMOTE_CACERT = (
"/usr/local/share/ca-certificates/{}".format(KEYSTONE_CACERT))
@@ -197,53 +201,91 @@ REMOTE_CERTIFICATES = [VAULT_REMOTE_CACERT, KEYSTONE_REMOTE_CACERT]
LOCAL_CERTIFICATES = [VAULT_LOCAL_CACERT, KEYSTONE_LOCAL_CACERT]
async def async_get_cert_file_name(app, cert_files=None, block=True,
model_name=None, timeout=2700):
"""Get the name of the CA cert file thats on all units of an application.
:param app: Name of application
:type capp: str
:param cert_files: List of cert files to search for.
:type cert_files: List[str]
:param block: Whether to block until a consistent cert file is found.
:type block: bool
:param model_name: Name of model to run check in
:type model_name: str
:param timeout: Time to wait for consistent file
:type timeout: int
:returns: Credentials dictionary
:rtype: dict
"""
async def _check_for_file(model, cert_files):
units = model.applications[app].units
results = {u.entity_id: [] for u in units}
for unit in units:
try:
for cf in cert_files:
output = await unit.run('test -e "{}"; echo $?'.format(cf))
contents = output.data.get('results')['Stdout']
if "0" in contents:
results[unit.entity_id].append(cf)
except JujuError:
pass
for cert_file in cert_files:
# Check that the certificate file exists on all the units.
if all(cert_file in files for files in results.values()):
return cert_file
async def async_block_until_ca_exists(application_name, ca_cert, model_name=None, timeout=2700):
async def _check_ca_present(model, ca_files):
units = model.applications[application_name].units
print(ca_files)
for ca_file in ca_files:
for unit in units:
print(unit)
print(ca_file)
try:
output = await unit.run('cat {}'.format(ca_file))
contents = output.data.get('results').get('Stdout', '')
if not ca_cert in contents:
print("It's not here!")
print(ca_cert)
print(contents)
break
if ca_cert in contents:
print("It's here!")
# libjuju throws a generic error for connection failure. So we
# cannot differentiate between a connectivity issue and a
# target file not existing error. For now just assume the
# latter.
except JujuError:
continue
else:
return True
else:
return None
if not cert_files:
cert_files = REMOTE_CERTIFICATES
cert_file = None
return False
ca_files = await _async_get_remote_ca_cert_file_candidates(application_name, model_name=model_name)
print(ca_files)
async with zaza.model.run_in_model(model_name) as model:
if block:
await zaza.model.async_block_until(
lambda: _check_for_file(model, cert_files), timeout=timeout)
cert_file = await _check_for_file(model, cert_files)
return cert_file
await zaza.model.async_block_until(
lambda: _check_ca_present(model, ca_files), timeout=timeout)
get_cert_file_name = zaza.model.sync_wrapper(async_get_cert_file_name)
block_until_ca_exists = zaza.model.sync_wrapper(async_block_until_ca_exists)
#async def async_get_cert_file_name(app, cert_files=None, block=True,
# model_name=None, timeout=2700):
# """Get the name of the CA cert file thats on all units of an application.
#
# :param app: Name of application
# :type capp: str
# :param cert_files: List of cert files to search for.
# :type cert_files: List[str]
# :param block: Whether to block until a consistent cert file is found.
# :type block: bool
# :param model_name: Name of model to run check in
# :type model_name: str
# :param timeout: Time to wait for consistent file
# :type timeout: int
# :returns: Credentials dictionary
# :rtype: dict
# """
# async def _check_for_file(model, cert_files):
# units = model.applications[app].units
# results = {u.entity_id: [] for u in units}
# for unit in units:
# try:
# for cf in cert_files:
# output = await unit.run('test -e "{}"; echo $?'.format(cf))
# contents = output.data.get('results')['Stdout']
# if "0" in contents:
# results[unit.entity_id].append(cf)
# except JujuError:
# pass
# for cert_file in cert_files:
# # Check that the certificate file exists on all the units.
# if all(cert_file in files for files in results.values()):
# return cert_file
# else:
# return None
#
# if not cert_files:
# cert_files = REMOTE_CERTIFICATES
# cert_file = None
# async with zaza.model.run_in_model(model_name) as model:
# if block:
# await zaza.model.async_block_until(
# lambda: _check_for_file(model, cert_files), timeout=timeout)
# cert_file = await _check_for_file(model, cert_files)
# return cert_file
#
#get_cert_file_name = zaza.model.sync_wrapper(async_get_cert_file_name)
def get_cacert():
@@ -2010,32 +2052,70 @@ def get_overcloud_auth(address=None, model_name=None):
'OS_PROJECT_DOMAIN_NAME': 'admin_domain',
'API_VERSION': 3,
}
if tls_rid:
cert_file = get_cert_file_name('keystone', model_name=model_name)
unit = model.get_first_unit_name('keystone', model_name=model_name)
# ensure that the path to put the local cacert in actually exists. The
# assumption that 'tests/' exists for, say, mojo is false.
# Needed due to:
# commit: 537473ad3addeaa3d1e4e2d0fd556aeaa4018eb2
_dir = os.path.dirname(cert_file)
if not os.path.exists(_dir):
os.makedirs(_dir)
_local_cert_file = "{}/{}".format(
LOCAL_CERT_DIR,
os.path.basename(cert_file))
model.scp_from_unit(
unit,
cert_file,
_local_cert_file)
if os.path.exists(_local_cert_file):
os.chmod(_local_cert_file, 0o644)
auth_settings['OS_CACERT'] = _local_cert_file
local_ca_cert = get_remote_ca_cert_file('keystone', model_name=model_name)
if ca_cert:
auth_settings['OS_CACERT'] = local_ca_cert
return auth_settings
async def _async_get_remote_ca_cert_file_candidates(application, model_name=None):
cert_files = []
# unit = model.get_first_unit_name(application, model_name=model_name)
units = await model.async_get_units(application, model_name=model_name)
unit = units[0].name
for _providor in CERT_PROVIDORS:
tls_rid = await model.async_get_relation_id(
application,
_providor,
model_name=model_name,
remote_interface_name='certificates')
if tls_rid:
cert_files.append(REMOTE_CERT_DIR + '/' + CACERT_FILENAME_FORMAT.format(_providor))
cert_files.append(REMOTE_CERT_DIR + '/' + KEYSTONE_CACERT)
return cert_files
_get_remote_ca_cert_file_candidates = zaza.model.sync_wrapper(_async_get_remote_ca_cert_file_candidates)
def get_remote_ca_cert_file(application, model_name=None):
# CACERT_FILENAME = "{}_juju_ca_cert.crt"
# cert_files = []
# unit = model.get_first_unit_name(application, model_name=model_name)
# for _providor in CERT_PROVIDORS:
# tls_rid = model.get_relation_id(
# application,
# _providor,
# model_name=model_name,
# remote_interface_name='certificates')
# if tls_rid:
# cert_files.append(CACERT_FILENAME.format(_providor))
# cert_files.append(KEYSTONE_CACERT)
unit = model.get_first_unit_name(application, model_name=model_name)
local_cert_file = None
cert_files = _get_remote_ca_cert_file_candidates(application, model_name=model_name)
for cert_file in cert_files:
_local_cert_file = "{}/{}".format(
LOCAL_CERT_DIR,
os.path.basename(cert_file))
with tempfile.NamedTemporaryFile(mode="w", delete=False) as _tmp_ca_file:
try:
model.scp_from_unit(
unit,
cert_file,
_tmp_ca_file.name)
except JujuError:
continue
# ensure that the path to put the local cacert in actually exists. The
# assumption that 'tests/' exists for, say, mojo is false.
# Needed due to:
# commit: 537473ad3addeaa3d1e4e2d0fd556aeaa4018eb2
_dir = os.path.dirname(_local_cert_file)
if not os.path.exists(_dir):
os.makedirs(_dir)
shutil.move(_tmp_ca_file.name, _local_cert_file)
os.chmod(_local_cert_file, 0o644)
local_cert_file = _local_cert_file
break
return local_cert_file
def get_urllib_opener():
"""Create a urllib opener taking into account proxy settings.