Charm Helpers Sync
Change-Id: I5db832685ec361e6ebd6ecd888f773b6ed599340
This commit is contained in:
parent
007f302ed6
commit
0094bf072e
@ -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():
|
||||
|
@ -202,6 +202,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']
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
||||
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 = []
|
||||
@ -1228,7 +1230,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.
|
||||
@ -1243,7 +1245,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: {}"
|
||||
@ -1302,7 +1305,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
|
||||
@ -1312,11 +1316,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
|
||||
@ -1327,16 +1334,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
|
||||
|
||||
|
||||
|
@ -17,8 +17,6 @@ from subprocess import (
|
||||
CalledProcessError,
|
||||
check_call,
|
||||
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.
|
||||
'''
|
||||
p = Popen(['pvremove', '-ff', block_device],
|
||||
stdin=PIPE)
|
||||
p.communicate(input='y\n')
|
||||
check_call(['pvremove', '-ff', '--yes', 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))
|
||||
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))
|
||||
|
@ -9,19 +9,13 @@ def get_platform():
|
||||
will be returned (which is the name of the module).
|
||||
This string is used to decide which platform module should be imported.
|
||||
"""
|
||||
# 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()
|
||||
current_platform = _get_current_platform()
|
||||
|
||||
if "Ubuntu" in current_platform:
|
||||
return "ubuntu"
|
||||
elif "CentOS" in current_platform:
|
||||
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.
|
||||
# Or at least it does in some build environments like Travis CI
|
||||
return "ubuntu"
|
||||
@ -36,6 +30,24 @@ def get_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():
|
||||
"""Get Platform from /etc/os-release."""
|
||||
with open(os.path.join(os.sep, 'etc', 'os-release')) as fin:
|
||||
|
Loading…
Reference in New Issue
Block a user