Charm Helpers Sync
Needed to make the charm understand jammy-caracal codename. Change-Id: Ib186097c1f9ecd000c1e145038bde5f819cd7b72
This commit is contained in:
parent
17f9d5ceb3
commit
7b74aba099
@ -16,6 +16,7 @@ import glob
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
@ -527,19 +528,56 @@ def get_hostname(address, fqdn=True):
|
|||||||
return result.split('.')[0]
|
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,
|
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 address: an IP address or hostname
|
||||||
@param port: integer port
|
@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
|
Note calls 'zc' via a subprocess shell
|
||||||
"""
|
"""
|
||||||
cmd = ['nc', '-z', address, str(port)]
|
if not sslinfo:
|
||||||
result = subprocess.call(cmd)
|
cmd = ['nc', '-z', address, str(port)]
|
||||||
return not (bool(result))
|
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():
|
def assert_charm_supports_ipv6():
|
||||||
|
@ -202,6 +202,21 @@ class OSContextGenerator(object):
|
|||||||
return self.related
|
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):
|
class SharedDBContext(OSContextGenerator):
|
||||||
interfaces = ['shared-db']
|
interfaces = ['shared-db']
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
{% if audit_middleware -%}
|
||||||
|
[audit_middleware_notifications]
|
||||||
|
driver = log
|
||||||
|
{% endif -%}
|
@ -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 -%}
|
@ -1207,12 +1207,14 @@ def _ows_check_services_running(services, ports):
|
|||||||
return 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
|
"""Check that the services that should be running are actually running
|
||||||
and that any ports specified are being listened to.
|
and that any ports specified are being listened to.
|
||||||
|
|
||||||
@param services: list of strings OR dictionary specifying services/ports
|
@param services: list of strings OR dictionary specifying services/ports
|
||||||
@param ports: list of 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
|
@returns state, message: strings or None, None
|
||||||
"""
|
"""
|
||||||
messages = []
|
messages = []
|
||||||
@ -1228,7 +1230,7 @@ def ows_check_services_running(services, ports):
|
|||||||
# also verify that the ports that should be open are open
|
# also verify that the ports that should be open are open
|
||||||
# NB, that ServiceManager objects only OPTIONALLY have ports
|
# NB, that ServiceManager objects only OPTIONALLY have ports
|
||||||
map_not_open, ports_open = (
|
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):
|
if not all(ports_open):
|
||||||
# find which service has missing ports. They are in service
|
# find which service has missing ports. They are in service
|
||||||
# order which makes it a bit easier.
|
# order which makes it a bit easier.
|
||||||
@ -1243,7 +1245,8 @@ def ows_check_services_running(services, ports):
|
|||||||
|
|
||||||
if ports is not None:
|
if ports is not None:
|
||||||
# and we can also check ports which we don't know the service for
|
# 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):
|
if not all(ports_open_bools):
|
||||||
messages.append(
|
messages.append(
|
||||||
"Ports which should be open, but are not: {}"
|
"Ports which should be open, but are not: {}"
|
||||||
@ -1302,7 +1305,8 @@ def _check_running_services(services):
|
|||||||
return list(zip(services, services_running)), services_running
|
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
|
"""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
|
ports that the service specifies are open. If test is True then the
|
||||||
function returns the services with ports that are open rather than
|
function returns the services with ports that are open rather than
|
||||||
@ -1312,11 +1316,14 @@ def _check_listening_on_services_ports(services, test=False):
|
|||||||
|
|
||||||
@param services: OrderedDict(service: [port, ...], ...)
|
@param services: OrderedDict(service: [port, ...], ...)
|
||||||
@param test: default=False, if False, test for closed, otherwise open.
|
@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]
|
@returns OrderedDict(service: [port-not-open, ...]...), [boolean]
|
||||||
"""
|
"""
|
||||||
test = not (not (test)) # ensure test is True or False
|
test = not (not (test)) # ensure test is True or False
|
||||||
all_ports = list(itertools.chain(*services.values()))
|
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()
|
map_ports = OrderedDict()
|
||||||
matched_ports = [p for p, opened in zip(all_ports, ports_states)
|
matched_ports = [p for p, opened in zip(all_ports, ports_states)
|
||||||
if opened == test] # essentially opened xor test
|
if opened == test] # essentially opened xor test
|
||||||
@ -1327,16 +1334,19 @@ def _check_listening_on_services_ports(services, test=False):
|
|||||||
return map_ports, ports_states
|
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
|
"""Check that the ports list given are being listened to
|
||||||
|
|
||||||
Returns a list of ports being listened to and a list of the
|
Returns a list of ports being listened to and a list of the
|
||||||
booleans.
|
booleans.
|
||||||
|
|
||||||
|
@param ssl_check_info: SSLPortCheckInfo object. If provided, port checks
|
||||||
|
will be done using an SSL connection.
|
||||||
@param ports: LIST of port numbers.
|
@param ports: LIST of port numbers.
|
||||||
@returns [(port_num, boolean), ...], [boolean]
|
@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
|
return zip(ports, ports_open), ports_open
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,8 +17,6 @@ from subprocess import (
|
|||||||
CalledProcessError,
|
CalledProcessError,
|
||||||
check_call,
|
check_call,
|
||||||
check_output,
|
check_output,
|
||||||
Popen,
|
|
||||||
PIPE,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -58,9 +56,7 @@ def remove_lvm_physical_volume(block_device):
|
|||||||
|
|
||||||
:param block_device: str: Full path of block device to scrub.
|
:param block_device: str: Full path of block device to scrub.
|
||||||
'''
|
'''
|
||||||
p = Popen(['pvremove', '-ff', block_device],
|
check_call(['pvremove', '-ff', '--yes', block_device])
|
||||||
stdin=PIPE)
|
|
||||||
p.communicate(input='y\n')
|
|
||||||
|
|
||||||
|
|
||||||
def list_lvm_volume_group(block_device):
|
def list_lvm_volume_group(block_device):
|
||||||
|
@ -256,8 +256,11 @@ def service_resume(service_name, init_dir="/etc/init",
|
|||||||
upstart_file = os.path.join(init_dir, "{}.conf".format(service_name))
|
upstart_file = os.path.join(init_dir, "{}.conf".format(service_name))
|
||||||
sysv_file = os.path.join(initd_dir, service_name)
|
sysv_file = os.path.join(initd_dir, service_name)
|
||||||
if init_is_systemd(service_name=service_name):
|
if init_is_systemd(service_name=service_name):
|
||||||
service('unmask', service_name)
|
if service('is-enabled', service_name):
|
||||||
service('enable', 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):
|
elif os.path.exists(upstart_file):
|
||||||
override_path = os.path.join(
|
override_path = os.path.join(
|
||||||
init_dir, '{}.override'.format(service_name))
|
init_dir, '{}.override'.format(service_name))
|
||||||
|
@ -9,19 +9,13 @@ def get_platform():
|
|||||||
will be returned (which is the name of the module).
|
will be returned (which is the name of the module).
|
||||||
This string is used to decide which platform module should be imported.
|
This string is used to decide which platform module should be imported.
|
||||||
"""
|
"""
|
||||||
# linux_distribution is deprecated and will be removed in Python 3.7
|
current_platform = _get_current_platform()
|
||||||
# Warnings *not* disabled, as we certainly need to fix this.
|
|
||||||
if hasattr(platform, 'linux_distribution'):
|
|
||||||
tuple_platform = platform.linux_distribution()
|
|
||||||
current_platform = tuple_platform[0]
|
|
||||||
else:
|
|
||||||
current_platform = _get_platform_from_fs()
|
|
||||||
|
|
||||||
if "Ubuntu" in current_platform:
|
if "Ubuntu" in current_platform:
|
||||||
return "ubuntu"
|
return "ubuntu"
|
||||||
elif "CentOS" in current_platform:
|
elif "CentOS" in current_platform:
|
||||||
return "centos"
|
return "centos"
|
||||||
elif "debian" in current_platform:
|
elif "debian" in current_platform or "Debian" in current_platform:
|
||||||
# Stock Python does not detect Ubuntu and instead returns debian.
|
# Stock Python does not detect Ubuntu and instead returns debian.
|
||||||
# Or at least it does in some build environments like Travis CI
|
# Or at least it does in some build environments like Travis CI
|
||||||
return "ubuntu"
|
return "ubuntu"
|
||||||
@ -36,6 +30,24 @@ def get_platform():
|
|||||||
.format(current_platform))
|
.format(current_platform))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_current_platform():
|
||||||
|
"""Return the current platform information for the OS.
|
||||||
|
|
||||||
|
Attempts to lookup linux distribution information from the platform
|
||||||
|
module for releases of python < 3.7. For newer versions of python,
|
||||||
|
the platform is determined from the /etc/os-release file.
|
||||||
|
"""
|
||||||
|
# linux_distribution is deprecated and will be removed in Python 3.7
|
||||||
|
# Warnings *not* disabled, as we certainly need to fix this.
|
||||||
|
if hasattr(platform, 'linux_distribution'):
|
||||||
|
tuple_platform = platform.linux_distribution()
|
||||||
|
current_platform = tuple_platform[0]
|
||||||
|
else:
|
||||||
|
current_platform = _get_platform_from_fs()
|
||||||
|
|
||||||
|
return current_platform
|
||||||
|
|
||||||
|
|
||||||
def _get_platform_from_fs():
|
def _get_platform_from_fs():
|
||||||
"""Get Platform from /etc/os-release."""
|
"""Get Platform from /etc/os-release."""
|
||||||
with open(os.path.join(os.sep, 'etc', 'os-release')) as fin:
|
with open(os.path.join(os.sep, 'etc', 'os-release')) as fin:
|
||||||
|
Loading…
Reference in New Issue
Block a user