Sync/rebuild for Dalmatian/Epoxy updates

Refresh and rebuild charm for awareness of Dalmatian and Epoxy
Cloud Archive releases.

Change-Id: Ibe82622b94eeb581fae782d5544fd5e98a3f74fe
This commit is contained in:
James Page 2024-11-15 12:09:42 +00:00
parent c9db7fe9a9
commit b4c1a90f4d
No known key found for this signature in database
GPG Key ID: BFECAECBA0E7D8C3
10 changed files with 137 additions and 28 deletions

View File

@ -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():

View File

@ -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']

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

@ -162,6 +162,8 @@ OPENSTACK_CODENAMES = OrderedDict([
('2023.1', 'antelope'), ('2023.1', 'antelope'),
('2023.2', 'bobcat'), ('2023.2', 'bobcat'),
('2024.1', 'caracal'), ('2024.1', 'caracal'),
('2024.2', 'dalmatian'),
('2025.1', 'epoxy'),
]) ])
# The ugly duckling - must list releases oldest to newest # The ugly duckling - must list releases oldest to newest
@ -1207,12 +1209,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 +1232,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 +1247,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 +1307,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 +1318,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 +1336,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

View File

@ -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):

View File

@ -18,7 +18,10 @@
# Charm Helpers Developers <juju@lists.ubuntu.com> # Charm Helpers Developers <juju@lists.ubuntu.com>
import copy import copy
from distutils.version import LooseVersion try:
from distutils.version import LooseVersion
except ImportError:
from looseversion import LooseVersion
from enum import Enum from enum import Enum
from functools import wraps from functools import wraps
from collections import namedtuple, UserDict from collections import namedtuple, UserDict

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)) 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))

View File

@ -254,6 +254,22 @@ CLOUD_ARCHIVE_POCKETS = {
'caracal/proposed': 'jammy-proposed/caracal', 'caracal/proposed': 'jammy-proposed/caracal',
'jammy-caracal/proposed': 'jammy-proposed/caracal', 'jammy-caracal/proposed': 'jammy-proposed/caracal',
'jammy-proposed/caracal': 'jammy-proposed/caracal', 'jammy-proposed/caracal': 'jammy-proposed/caracal',
# dalmatian
'dalmatian': 'noble-updates/dalmatian',
'noble-dalmatian': 'noble-updates/dalmatian',
'noble-dalmatian/updates': 'noble-updates/dalmatian',
'noble-updates/dalmatian': 'noble-updates/dalmatian',
'dalmatian/proposed': 'noble-proposed/dalmatian',
'noble-dalmatian/proposed': 'noble-proposed/dalmatian',
'noble-proposed/dalmatian': 'noble-proposed/dalmatian',
# epoxy
'epoxy': 'noble-updates/epoxy',
'noble-epoxy': 'noble-updates/epoxy',
'noble-epoxy/updates': 'noble-updates/epoxy',
'noble-updates/epoxy': 'noble-updates/epoxy',
'epoxy/proposed': 'noble-proposed/epoxy',
'noble-epoxy/proposed': 'noble-proposed/epoxy',
'noble-proposed/epoxy': 'noble-proposed/epoxy',
# OVN # OVN
'focal-ovn-22.03': 'focal-updates/ovn-22.03', 'focal-ovn-22.03': 'focal-updates/ovn-22.03',
@ -288,6 +304,8 @@ OPENSTACK_RELEASES = (
'antelope', 'antelope',
'bobcat', 'bobcat',
'caracal', 'caracal',
'dalmatian',
'epoxy',
) )
@ -318,6 +336,8 @@ UBUNTU_OPENSTACK_RELEASE = OrderedDict([
('lunar', 'antelope'), ('lunar', 'antelope'),
('mantic', 'bobcat'), ('mantic', 'bobcat'),
('noble', 'caracal'), ('noble', 'caracal'),
('oracular', 'dalmatian'),
('plucky', 'epoxy'),
]) ])

View File

@ -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: