Charmhelper sync for 20.02

Change-Id: I163f9996b57bb9330803e138d4d05d045ee053ea
This commit is contained in:
Liam Young 2020-02-04 16:39:22 +00:00
parent a03fe36fa6
commit d5399356d3
6 changed files with 117 additions and 9 deletions

View File

@ -25,6 +25,7 @@ Helpers for clustering and determining "cluster leadership" and other
clustering-related helpers. clustering-related helpers.
""" """
import functools
import subprocess import subprocess
import os import os
import time import time
@ -281,6 +282,10 @@ def determine_apache_port(public_port, singlenode_mode=False):
return public_port - (i * 10) return public_port - (i * 10)
determine_apache_port_single = functools.partial(
determine_apache_port, singlenode_mode=True)
def get_hacluster_config(exclude_keys=None): def get_hacluster_config(exclude_keys=None):
''' '''
Obtains all relevant configuration from charm configuration required 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) log(msg, DEBUG)
status_set('maintenance', msg) status_set('maintenance', msg)
time.sleep(calculated_wait) 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

@ -52,7 +52,7 @@ class RestrictedPackages(BaseAudit):
def __init__(self, pkgs, **kwargs): def __init__(self, pkgs, **kwargs):
super(RestrictedPackages, self).__init__(**kwargs) super(RestrictedPackages, self).__init__(**kwargs)
if isinstance(pkgs, string_types) or not hasattr(pkgs, '__iter__'): if isinstance(pkgs, string_types) or not hasattr(pkgs, '__iter__'):
self.pkgs = [pkgs] self.pkgs = pkgs.split()
else: else:
self.pkgs = pkgs self.pkgs = pkgs
@ -100,4 +100,5 @@ class RestrictedPackages(BaseAudit):
apt_purge(pkg.name) apt_purge(pkg.name)
def is_virtual_package(self, pkg): def is_virtual_package(self, pkg):
return pkg.has_provides and not pkg.has_versions return (pkg.get('has_provides', False) and
not pkg.get('has_versions', False))

View File

@ -2386,19 +2386,13 @@ class DHCPAgentContext(OSContextGenerator):
:returns: Value to use for ovs_use_veth setting :returns: Value to use for ovs_use_veth setting
:rtype: Bool :rtype: Bool
""" """
# If this is Trust return True
release = lsb_release()['DISTRIB_CODENAME'].lower()
if CompareHostReleases(release) <= 'trusty':
return True
# If there is an existing setting return that
_existing = self.get_existing_ovs_use_veth() _existing = self.get_existing_ovs_use_veth()
if _existing is not None: if _existing is not None:
return _existing return _existing
# If the config value is unset return False
_config = self.parse_ovs_use_veth() _config = self.parse_ovs_use_veth()
if _config is None: if _config is None:
# New better default # New better default
return False return False
# If the config value is set return it
else: else:
return _config return _config

View File

@ -44,6 +44,7 @@ from charmhelpers.core.hookenv import (
INFO, INFO,
ERROR, ERROR,
related_units, related_units,
relation_get,
relation_ids, relation_ids,
relation_set, relation_set,
status_set, status_set,
@ -331,6 +332,10 @@ PACKAGE_CODENAMES = {
DEFAULT_LOOPBACK_SIZE = '5G' DEFAULT_LOOPBACK_SIZE = '5G'
DB_SERIES_UPGRADING_KEY = 'cluster-series-upgrading'
DB_MAINTENANCE_KEYS = [DB_SERIES_UPGRADING_KEY]
class CompareOpenStackReleases(BasicStringComparator): class CompareOpenStackReleases(BasicStringComparator):
"""Provide comparisons of OpenStack releases. """Provide comparisons of OpenStack releases.
@ -1912,3 +1917,33 @@ def set_db_initialised():
""" """
juju_log('Setting db-initialised to True', 'DEBUG') juju_log('Setting db-initialised to True', 'DEBUG')
leader_set({'db-initialised': True}) 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 locale
import os import os
import subprocess import subprocess
import sys
class _container(dict): class _container(dict):
@ -59,6 +60,13 @@ class Cache(object):
def __init__(self, progress=None): def __init__(self, progress=None):
pass pass
def __contains__(self, package):
try:
pkg = self.__getitem__(package)
return pkg is not None
except KeyError:
return False
def __getitem__(self, package): def __getitem__(self, package):
"""Get information about a package from apt and dpkg databases. """Get information about a package from apt and dpkg databases.
@ -178,6 +186,28 @@ class Cache(object):
return pkgs 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(): def init():
"""Compability shim that does nothing.""" """Compability shim that does nothing."""
pass pass

View File

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