Charmhelper sync for 20.02

Change-Id: I148eb8af40ffe30966f86abb0f26568117f4d838
This commit is contained in:
Liam Young 2020-02-04 16:39:01 +00:00
parent d3512ef320
commit e5f0c5f343
4 changed files with 113 additions and 0 deletions

View File

@ -25,6 +25,7 @@ Helpers for clustering and determining "cluster leadership" and other
clustering-related helpers.
"""
import functools
import subprocess
import os
import time
@ -281,6 +282,10 @@ def determine_apache_port(public_port, singlenode_mode=False):
return public_port - (i * 10)
determine_apache_port_single = functools.partial(
determine_apache_port, singlenode_mode=True)
def get_hacluster_config(exclude_keys=None):
'''
Obtains all relevant configuration from charm configuration required
@ -404,3 +409,43 @@ def distributed_wait(modulo=None, wait=None, operation_name='operation'):
log(msg, DEBUG)
status_set('maintenance', msg)
time.sleep(calculated_wait)
def get_managed_services_and_ports(services, external_ports,
external_services=None,
port_conv_f=determine_apache_port_single):
"""Get the services and ports managed by this charm.
Return only the services and corresponding ports that are managed by this
charm. This excludes haproxy when there is a relation with hacluster. This
is because this charm passes responsability for stopping and starting
haproxy to hacluster.
Similarly, if a relation with hacluster exists then the ports returned by
this method correspond to those managed by the apache server rather than
haproxy.
:param services: List of services.
:type services: List[str]
:param external_ports: List of ports managed by external services.
:type external_ports: List[int]
:param external_services: List of services to be removed if ha relation is
present.
:type external_services: List[str]
:param port_conv_f: Function to apply to ports to calculate the ports
managed by services controlled by this charm.
:type port_convert_func: f()
:returns: A tuple containing a list of services first followed by a list of
ports.
:rtype: Tuple[List[str], List[int]]
"""
if external_services is None:
external_services = ['haproxy']
if relation_ids('ha'):
for svc in external_services:
try:
services.remove(svc)
except ValueError:
pass
external_ports = [port_conv_f(p) for p in external_ports]
return services, external_ports

View File

@ -44,6 +44,7 @@ from charmhelpers.core.hookenv import (
INFO,
ERROR,
related_units,
relation_get,
relation_ids,
relation_set,
status_set,
@ -331,6 +332,10 @@ PACKAGE_CODENAMES = {
DEFAULT_LOOPBACK_SIZE = '5G'
DB_SERIES_UPGRADING_KEY = 'cluster-series-upgrading'
DB_MAINTENANCE_KEYS = [DB_SERIES_UPGRADING_KEY]
class CompareOpenStackReleases(BasicStringComparator):
"""Provide comparisons of OpenStack releases.
@ -1912,3 +1917,33 @@ def set_db_initialised():
"""
juju_log('Setting db-initialised to True', 'DEBUG')
leader_set({'db-initialised': True})
def is_db_maintenance_mode(relid=None):
"""Check relation data from notifications of db in maintenance mode.
:returns: Whether db has notified it is in maintenance mode.
:rtype: bool
"""
juju_log('Checking for maintenance notifications', 'DEBUG')
if relid:
r_ids = [relid]
else:
r_ids = relation_ids('shared-db')
rids_units = [(r, u) for r in r_ids for u in related_units(r)]
notifications = []
for r_id, unit in rids_units:
settings = relation_get(unit=unit, rid=r_id)
for key, value in settings.items():
if value and key in DB_MAINTENANCE_KEYS:
juju_log(
'Unit: {}, Key: {}, Value: {}'.format(unit, key, value),
'DEBUG')
try:
notifications.append(bool_from_string(value))
except ValueError:
juju_log(
'Could not discern bool from {}'.format(value),
'WARN')
pass
return True in notifications

View File

@ -38,6 +38,7 @@ so with this we get rid of the dependency.
import locale
import os
import subprocess
import sys
class _container(dict):
@ -59,6 +60,13 @@ class Cache(object):
def __init__(self, progress=None):
pass
def __contains__(self, package):
try:
pkg = self.__getitem__(package)
return pkg is not None
except KeyError:
return False
def __getitem__(self, package):
"""Get information about a package from apt and dpkg databases.
@ -178,6 +186,28 @@ class Cache(object):
return pkgs
class Config(_container):
def __init__(self):
super(Config, self).__init__(self._populate())
def _populate(self):
cfgs = {}
cmd = ['apt-config', 'dump']
output = subprocess.check_output(cmd,
stderr=subprocess.STDOUT,
universal_newlines=True)
for line in output.splitlines():
if not line.startswith("CommandLine"):
k, v = line.split(" ", 1)
cfgs[k] = v.strip(";").strip("\"")
return cfgs
# Backwards compatibility with old apt_pkg module
sys.modules[__name__].config = Config()
def init():
"""Compability shim that does nothing."""
pass

View File

@ -20,6 +20,9 @@ def get_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"
elif "elementary" in current_platform:
# ElementaryOS fails to run tests locally without this.
return "ubuntu"
else:
raise RuntimeError("This module is not supported on {}."
.format(current_platform))