Update charmhelpers for stable/yoga

Change-Id: Iad3d5bd2dc7d4976a8cb4dd429af45a03330566c
This commit is contained in:
Myles Penner
2024-06-25 07:59:41 -07:00
parent 59404ff046
commit 529baa3146
7 changed files with 102 additions and 37 deletions

View File

@@ -16,6 +16,7 @@ import glob
import re
import subprocess
import socket
import ssl
from functools import partial
@@ -527,19 +528,56 @@ def get_hostname(address, fqdn=True):
return result.split('.')[0]
def port_has_listener(address, port):
class SSLPortCheckInfo(object):
def __init__(self, key, cert, ca_cert, check_hostname=False):
self.key = key
self.cert = cert
self.ca_cert = ca_cert
# NOTE: by default we do not check hostname since the port check is
# typically performed using 0.0.0.0 which will not match the
# certificate. Hence the default for this is False.
self.check_hostname = check_hostname
@property
def ssl_context(self):
context = ssl.create_default_context()
context.check_hostname = self.check_hostname
context.load_cert_chain(self.cert, self.key)
context.load_verify_locations(self.ca_cert)
return context
def port_has_listener(address, port, sslinfo=None):
"""
Returns True if the address:port is open and being listened to,
else False.
else False. By default uses netcat to check ports but if sslinfo is
provided will use an SSL connection instead.
@param address: an IP address or hostname
@param port: integer port
@param sslinfo: optional SSLPortCheckInfo object.
If provided, the check is performed using an ssl
connection.
Note calls 'zc' via a subprocess shell
"""
cmd = ['nc', '-z', address, str(port)]
result = subprocess.call(cmd)
return not (bool(result))
if not sslinfo:
cmd = ['nc', '-z', address, str(port)]
result = subprocess.call(cmd)
return not (bool(result))
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
ssock = sslinfo.ssl_context.wrap_socket(sock,
server_hostname=address)
ssock.connect((address, port))
# this bit is crucial to ensure tls close_notify is sent
ssock.unwrap()
return True
except ConnectionRefusedError:
return False
def assert_charm_supports_ipv6():

View File

@@ -198,6 +198,21 @@ class OSContextGenerator(object):
return self.related
class KeystoneAuditMiddleware(OSContextGenerator):
def __init__(self, service: str) -> None:
self.service_name = service
def __call__(self):
"""Return context dictionary containing configuration status of
audit-middleware and the charm service name.
"""
ctxt = {
'audit_middleware': config('audit-middleware') or False,
'service_name': self.service_name
}
return ctxt
class SharedDBContext(OSContextGenerator):
interfaces = ['shared-db']
@@ -477,7 +492,7 @@ class IdentityServiceContext(OSContextGenerator):
'service_project_id': rdata.get('service_tenant_id'),
'service_domain_id': rdata.get('service_domain_id')})
# we keep all veriables in ctxt for compatibility and
# we keep all variables in ctxt for compatibility and
# add nested dictionary for keystone_authtoken generic
# templating
if keystonemiddleware_os_release:
@@ -489,6 +504,7 @@ class IdentityServiceContext(OSContextGenerator):
# NOTE(jamespage) this is required for >= icehouse
# so a missing value just indicates keystone needs
# upgrading
ctxt['admin_user_id'] = rdata.get('service_user_id')
ctxt['admin_tenant_id'] = rdata.get('service_tenant_id')
ctxt['admin_domain_id'] = rdata.get('service_domain_id')
return ctxt

View File

@@ -0,0 +1,4 @@
{% if audit_middleware -%}
[audit_middleware_notifications]
driver = log
{% endif -%}

View File

@@ -0,0 +1,6 @@
{% if audit_middleware and service_name -%}
[filter:audit]
paste.filter_factory = keystonemiddleware.audit:filter_factory
audit_map_file = /etc/{{ service_name }}/api_audit_map.conf
service_name = {{ service_name }}
{% endif -%}

View File

@@ -410,17 +410,6 @@ def get_os_version_codename(codename, version_map=OPENSTACK_CODENAMES):
error_out(e)
def get_os_version_codename_swift(codename):
'''Determine OpenStack version number of swift from codename.'''
# for k, v in six.iteritems(SWIFT_CODENAMES):
for k, v in SWIFT_CODENAMES.items():
if k == codename:
return v[-1]
e = 'Could not derive swift version for '\
'codename: %s' % codename
error_out(e)
def get_swift_codename(version):
'''Determine OpenStack codename that corresponds to swift version.'''
codenames = [k for k, v in SWIFT_CODENAMES.items() if version in v]
@@ -579,7 +568,6 @@ def get_installed_os_version():
return openstack_release().get('OPENSTACK_CODENAME')
@cached
def openstack_release():
"""Return /etc/os-release in a dict."""
d = {}
@@ -841,14 +829,10 @@ def openstack_upgrade_available(package):
if not cur_vers:
# The package has not been installed yet do not attempt upgrade
return False
if "swift" in package:
codename = get_os_codename_install_source(src)
avail_vers = get_os_version_codename_swift(codename)
else:
try:
avail_vers = get_os_version_install_source(src)
except Exception:
avail_vers = cur_vers
try:
avail_vers = get_os_version_install_source(src)
except Exception:
avail_vers = cur_vers
apt.init()
return apt.version_compare(avail_vers, cur_vers) >= 1
@@ -1216,12 +1200,14 @@ def _ows_check_services_running(services, ports):
return ows_check_services_running(services, ports)
def ows_check_services_running(services, ports):
def ows_check_services_running(services, ports, ssl_check_info=None):
"""Check that the services that should be running are actually running
and that any ports specified are being listened to.
@param services: list of strings OR dictionary specifying services/ports
@param ports: list of ports
@param ssl_check_info: SSLPortCheckInfo object. If provided, port checks
will be done using an SSL connection.
@returns state, message: strings or None, None
"""
messages = []
@@ -1237,7 +1223,7 @@ def ows_check_services_running(services, ports):
# also verify that the ports that should be open are open
# NB, that ServiceManager objects only OPTIONALLY have ports
map_not_open, ports_open = (
_check_listening_on_services_ports(services))
_check_listening_on_services_ports(services, ssl_check_info))
if not all(ports_open):
# find which service has missing ports. They are in service
# order which makes it a bit easier.
@@ -1252,7 +1238,8 @@ def ows_check_services_running(services, ports):
if ports is not None:
# and we can also check ports which we don't know the service for
ports_open, ports_open_bools = _check_listening_on_ports_list(ports)
ports_open, ports_open_bools = \
_check_listening_on_ports_list(ports, ssl_check_info)
if not all(ports_open_bools):
messages.append(
"Ports which should be open, but are not: {}"
@@ -1311,7 +1298,8 @@ def _check_running_services(services):
return list(zip(services, services_running)), services_running
def _check_listening_on_services_ports(services, test=False):
def _check_listening_on_services_ports(services, test=False,
ssl_check_info=None):
"""Check that the unit is actually listening (has the port open) on the
ports that the service specifies are open. If test is True then the
function returns the services with ports that are open rather than
@@ -1321,11 +1309,14 @@ def _check_listening_on_services_ports(services, test=False):
@param services: OrderedDict(service: [port, ...], ...)
@param test: default=False, if False, test for closed, otherwise open.
@param ssl_check_info: SSLPortCheckInfo object. If provided, port checks
will be done using an SSL connection.
@returns OrderedDict(service: [port-not-open, ...]...), [boolean]
"""
test = not (not (test)) # ensure test is True or False
all_ports = list(itertools.chain(*services.values()))
ports_states = [port_has_listener('0.0.0.0', p) for p in all_ports]
ports_states = [port_has_listener('0.0.0.0', p, ssl_check_info)
for p in all_ports]
map_ports = OrderedDict()
matched_ports = [p for p, opened in zip(all_ports, ports_states)
if opened == test] # essentially opened xor test
@@ -1336,16 +1327,19 @@ def _check_listening_on_services_ports(services, test=False):
return map_ports, ports_states
def _check_listening_on_ports_list(ports):
def _check_listening_on_ports_list(ports, ssl_check_info=None):
"""Check that the ports list given are being listened to
Returns a list of ports being listened to and a list of the
booleans.
@param ssl_check_info: SSLPortCheckInfo object. If provided, port checks
will be done using an SSL connection.
@param ports: LIST of port numbers.
@returns [(port_num, boolean), ...], [boolean]
"""
ports_open = [port_has_listener('0.0.0.0', p) for p in ports]
ports_open = [port_has_listener('0.0.0.0', p, ssl_check_info)
for p in ports]
return zip(ports, ports_open), ports_open

View File

@@ -159,15 +159,19 @@ def get_osd_settings(relation_name):
return _order_dict_by_key(osd_settings)
def send_application_name(relid=None):
def send_application_name(relid=None, app_name=None):
"""Send the application name down the relation.
:param relid: Relation id to set application name in.
:type relid: str
:param app_name: Application name to send in the relation.
:type app_name: str
"""
if app_name is None:
app_name = application_name()
relation_set(
relation_id=relid,
relation_settings={'application-name': application_name()})
relation_settings={'application-name': app_name})
def send_osd_settings():

View File

@@ -256,8 +256,11 @@ def service_resume(service_name, init_dir="/etc/init",
upstart_file = os.path.join(init_dir, "{}.conf".format(service_name))
sysv_file = os.path.join(initd_dir, service_name)
if init_is_systemd(service_name=service_name):
service('unmask', service_name)
service('enable', service_name)
if service('is-enabled', service_name):
log('service {} already enabled'.format(service_name), level=DEBUG)
else:
service('unmask', service_name)
service('enable', service_name)
elif os.path.exists(upstart_file):
override_path = os.path.join(
init_dir, '{}.override'.format(service_name))