Charmhelper sync before 1604 testing
Change-Id: I87e827449ac2eaf8652979c5219ef43b60fbe7f7
This commit is contained in:
parent
03c3d96765
commit
e33eb802c8
@ -20,7 +20,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from subprocess import check_call
|
from subprocess import check_call, CalledProcessError
|
||||||
|
|
||||||
import six
|
import six
|
||||||
import yaml
|
import yaml
|
||||||
@ -45,6 +45,7 @@ from charmhelpers.core.hookenv import (
|
|||||||
INFO,
|
INFO,
|
||||||
WARNING,
|
WARNING,
|
||||||
ERROR,
|
ERROR,
|
||||||
|
status_set,
|
||||||
)
|
)
|
||||||
|
|
||||||
from charmhelpers.core.sysctl import create as sysctl_create
|
from charmhelpers.core.sysctl import create as sysctl_create
|
||||||
@ -1491,3 +1492,92 @@ class InternalEndpointContext(OSContextGenerator):
|
|||||||
"""
|
"""
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
return {'use_internal_endpoints': config('use-internal-endpoints')}
|
return {'use_internal_endpoints': config('use-internal-endpoints')}
|
||||||
|
|
||||||
|
|
||||||
|
class AppArmorContext(OSContextGenerator):
|
||||||
|
"""Base class for apparmor contexts."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._ctxt = None
|
||||||
|
self.aa_profile = None
|
||||||
|
self.aa_utils_packages = ['apparmor-utils']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ctxt(self):
|
||||||
|
if self._ctxt is not None:
|
||||||
|
return self._ctxt
|
||||||
|
self._ctxt = self._determine_ctxt()
|
||||||
|
return self._ctxt
|
||||||
|
|
||||||
|
def _determine_ctxt(self):
|
||||||
|
"""
|
||||||
|
Validate aa-profile-mode settings is disable, enforce, or complain.
|
||||||
|
|
||||||
|
:return ctxt: Dictionary of the apparmor profile or None
|
||||||
|
"""
|
||||||
|
if config('aa-profile-mode') in ['disable', 'enforce', 'complain']:
|
||||||
|
ctxt = {'aa-profile-mode': config('aa-profile-mode')}
|
||||||
|
else:
|
||||||
|
ctxt = None
|
||||||
|
return ctxt
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return self.ctxt
|
||||||
|
|
||||||
|
def install_aa_utils(self):
|
||||||
|
"""
|
||||||
|
Install packages required for apparmor configuration.
|
||||||
|
"""
|
||||||
|
log("Installing apparmor utils.")
|
||||||
|
ensure_packages(self.aa_utils_packages)
|
||||||
|
|
||||||
|
def manually_disable_aa_profile(self):
|
||||||
|
"""
|
||||||
|
Manually disable an apparmor profile.
|
||||||
|
|
||||||
|
If aa-profile-mode is set to disabled (default) this is required as the
|
||||||
|
template has been written but apparmor is yet unaware of the profile
|
||||||
|
and aa-disable aa-profile fails. Without this the profile would kick
|
||||||
|
into enforce mode on the next service restart.
|
||||||
|
|
||||||
|
"""
|
||||||
|
profile_path = '/etc/apparmor.d'
|
||||||
|
disable_path = '/etc/apparmor.d/disable'
|
||||||
|
if not os.path.lexists(os.path.join(disable_path, self.aa_profile)):
|
||||||
|
os.symlink(os.path.join(profile_path, self.aa_profile),
|
||||||
|
os.path.join(disable_path, self.aa_profile))
|
||||||
|
|
||||||
|
def setup_aa_profile(self):
|
||||||
|
"""
|
||||||
|
Setup an apparmor profile.
|
||||||
|
The ctxt dictionary will contain the apparmor profile mode and
|
||||||
|
the apparmor profile name.
|
||||||
|
Makes calls out to aa-disable, aa-complain, or aa-enforce to setup
|
||||||
|
the apparmor profile.
|
||||||
|
"""
|
||||||
|
self()
|
||||||
|
if not self.ctxt:
|
||||||
|
log("Not enabling apparmor Profile")
|
||||||
|
return
|
||||||
|
self.install_aa_utils()
|
||||||
|
cmd = ['aa-{}'.format(self.ctxt['aa-profile-mode'])]
|
||||||
|
cmd.append(self.ctxt['aa-profile'])
|
||||||
|
log("Setting up the apparmor profile for {} in {} mode."
|
||||||
|
"".format(self.ctxt['aa-profile'], self.ctxt['aa-profile-mode']))
|
||||||
|
try:
|
||||||
|
check_call(cmd)
|
||||||
|
except CalledProcessError as e:
|
||||||
|
# If aa-profile-mode is set to disabled (default) manual
|
||||||
|
# disabling is required as the template has been written but
|
||||||
|
# apparmor is yet unaware of the profile and aa-disable aa-profile
|
||||||
|
# fails. If aa-disable learns to read profile files first this can
|
||||||
|
# be removed.
|
||||||
|
if self.ctxt['aa-profile-mode'] == 'disable':
|
||||||
|
log("Manually disabling the apparmor profile for {}."
|
||||||
|
"".format(self.ctxt['aa-profile']))
|
||||||
|
self.manually_disable_aa_profile()
|
||||||
|
return
|
||||||
|
status_set('blocked', "Apparmor profile {} failed to be set to {}."
|
||||||
|
"".format(self.ctxt['aa-profile'],
|
||||||
|
self.ctxt['aa-profile-mode']))
|
||||||
|
raise e
|
||||||
|
@ -137,7 +137,7 @@ SWIFT_CODENAMES = OrderedDict([
|
|||||||
('liberty',
|
('liberty',
|
||||||
['2.3.0', '2.4.0', '2.5.0']),
|
['2.3.0', '2.4.0', '2.5.0']),
|
||||||
('mitaka',
|
('mitaka',
|
||||||
['2.5.0', '2.6.0']),
|
['2.5.0', '2.6.0', '2.7.0']),
|
||||||
])
|
])
|
||||||
|
|
||||||
# >= Liberty version->codename mapping
|
# >= Liberty version->codename mapping
|
||||||
@ -156,6 +156,7 @@ PACKAGE_CODENAMES = {
|
|||||||
]),
|
]),
|
||||||
'keystone': OrderedDict([
|
'keystone': OrderedDict([
|
||||||
('8.0', 'liberty'),
|
('8.0', 'liberty'),
|
||||||
|
('8.1', 'liberty'),
|
||||||
('9.0', 'mitaka'),
|
('9.0', 'mitaka'),
|
||||||
]),
|
]),
|
||||||
'horizon-common': OrderedDict([
|
'horizon-common': OrderedDict([
|
||||||
@ -1534,7 +1535,8 @@ def make_assess_status_func(*args, **kwargs):
|
|||||||
return _assess_status_func
|
return _assess_status_func
|
||||||
|
|
||||||
|
|
||||||
def pausable_restart_on_change(restart_map, stopstart=False):
|
def pausable_restart_on_change(restart_map, stopstart=False,
|
||||||
|
restart_functions=None):
|
||||||
"""A restart_on_change decorator that checks to see if the unit is
|
"""A restart_on_change decorator that checks to see if the unit is
|
||||||
paused. If it is paused then the decorated function doesn't fire.
|
paused. If it is paused then the decorated function doesn't fire.
|
||||||
|
|
||||||
@ -1567,6 +1569,7 @@ def pausable_restart_on_change(restart_map, stopstart=False):
|
|||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
# otherwise, normal restart_on_change functionality
|
# otherwise, normal restart_on_change functionality
|
||||||
return restart_on_change_helper(
|
return restart_on_change_helper(
|
||||||
(lambda: f(*args, **kwargs)), restart_map, stopstart)
|
(lambda: f(*args, **kwargs)), restart_map, stopstart,
|
||||||
|
restart_functions)
|
||||||
return wrapped_f
|
return wrapped_f
|
||||||
return wrap
|
return wrap
|
||||||
|
@ -128,6 +128,13 @@ def service(action, service_name):
|
|||||||
return subprocess.call(cmd) == 0
|
return subprocess.call(cmd) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def systemv_services_running():
|
||||||
|
output = subprocess.check_output(
|
||||||
|
['service', '--status-all'],
|
||||||
|
stderr=subprocess.STDOUT).decode('UTF-8')
|
||||||
|
return [row.split()[-1] for row in output.split('\n') if '[ + ]' in row]
|
||||||
|
|
||||||
|
|
||||||
def service_running(service_name):
|
def service_running(service_name):
|
||||||
"""Determine whether a system service is running"""
|
"""Determine whether a system service is running"""
|
||||||
if init_is_systemd():
|
if init_is_systemd():
|
||||||
@ -140,11 +147,15 @@ def service_running(service_name):
|
|||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
# This works for upstart scripts where the 'service' command
|
||||||
|
# returns a consistent string to represent running 'start/running'
|
||||||
if ("start/running" in output or "is running" in output or
|
if ("start/running" in output or "is running" in output or
|
||||||
"up and running" in output):
|
"up and running" in output):
|
||||||
return True
|
return True
|
||||||
else:
|
# Check System V scripts init script return codes
|
||||||
return False
|
if service_name in systemv_services_running():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def service_available(service_name):
|
def service_available(service_name):
|
||||||
@ -412,7 +423,7 @@ class ChecksumError(ValueError):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def restart_on_change(restart_map, stopstart=False):
|
def restart_on_change(restart_map, stopstart=False, restart_functions=None):
|
||||||
"""Restart services based on configuration files changing
|
"""Restart services based on configuration files changing
|
||||||
|
|
||||||
This function is used a decorator, for example::
|
This function is used a decorator, for example::
|
||||||
@ -433,18 +444,22 @@ def restart_on_change(restart_map, stopstart=False):
|
|||||||
|
|
||||||
@param restart_map: {path_file_name: [service_name, ...]
|
@param restart_map: {path_file_name: [service_name, ...]
|
||||||
@param stopstart: DEFAULT false; whether to stop, start OR restart
|
@param stopstart: DEFAULT false; whether to stop, start OR restart
|
||||||
|
@param restart_functions: nonstandard functions to use to restart services
|
||||||
|
{svc: func, ...}
|
||||||
@returns result from decorated function
|
@returns result from decorated function
|
||||||
"""
|
"""
|
||||||
def wrap(f):
|
def wrap(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapped_f(*args, **kwargs):
|
def wrapped_f(*args, **kwargs):
|
||||||
return restart_on_change_helper(
|
return restart_on_change_helper(
|
||||||
(lambda: f(*args, **kwargs)), restart_map, stopstart)
|
(lambda: f(*args, **kwargs)), restart_map, stopstart,
|
||||||
|
restart_functions)
|
||||||
return wrapped_f
|
return wrapped_f
|
||||||
return wrap
|
return wrap
|
||||||
|
|
||||||
|
|
||||||
def restart_on_change_helper(lambda_f, restart_map, stopstart=False):
|
def restart_on_change_helper(lambda_f, restart_map, stopstart=False,
|
||||||
|
restart_functions=None):
|
||||||
"""Helper function to perform the restart_on_change function.
|
"""Helper function to perform the restart_on_change function.
|
||||||
|
|
||||||
This is provided for decorators to restart services if files described
|
This is provided for decorators to restart services if files described
|
||||||
@ -453,8 +468,12 @@ def restart_on_change_helper(lambda_f, restart_map, stopstart=False):
|
|||||||
@param lambda_f: function to call.
|
@param lambda_f: function to call.
|
||||||
@param restart_map: {file: [service, ...]}
|
@param restart_map: {file: [service, ...]}
|
||||||
@param stopstart: whether to stop, start or restart a service
|
@param stopstart: whether to stop, start or restart a service
|
||||||
|
@param restart_functions: nonstandard functions to use to restart services
|
||||||
|
{svc: func, ...}
|
||||||
@returns result of lambda_f()
|
@returns result of lambda_f()
|
||||||
"""
|
"""
|
||||||
|
if restart_functions is None:
|
||||||
|
restart_functions = {}
|
||||||
checksums = {path: path_hash(path) for path in restart_map}
|
checksums = {path: path_hash(path) for path in restart_map}
|
||||||
r = lambda_f()
|
r = lambda_f()
|
||||||
# create a list of lists of the services to restart
|
# create a list of lists of the services to restart
|
||||||
@ -465,9 +484,12 @@ def restart_on_change_helper(lambda_f, restart_map, stopstart=False):
|
|||||||
services_list = list(OrderedDict.fromkeys(itertools.chain(*restarts)))
|
services_list = list(OrderedDict.fromkeys(itertools.chain(*restarts)))
|
||||||
if services_list:
|
if services_list:
|
||||||
actions = ('stop', 'start') if stopstart else ('restart',)
|
actions = ('stop', 'start') if stopstart else ('restart',)
|
||||||
for action in actions:
|
for service_name in services_list:
|
||||||
for service_name in services_list:
|
if service_name in restart_functions:
|
||||||
service(action, service_name)
|
restart_functions[service_name](service_name)
|
||||||
|
else:
|
||||||
|
for action in actions:
|
||||||
|
service(action, service_name)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# The order of packages is significant, because pip processes them in the order
|
# The order of packages is significant, because pip processes them in the order
|
||||||
# of appearance. Changing the order has an impact on the overall integration
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
# process, which may cause wedges in the gate later.
|
# process, which may cause wedges in the gate later.
|
||||||
|
pbr>=1.8.0,<1.9.0
|
||||||
PyYAML>=3.1.0
|
PyYAML>=3.1.0
|
||||||
simplejson>=2.2.0
|
simplejson>=2.2.0
|
||||||
netifaces>=0.10.4
|
netifaces>=0.10.4
|
||||||
|
@ -601,7 +601,7 @@ class AmuletUtils(object):
|
|||||||
return ('Process name count mismatch. expected, actual: {}, '
|
return ('Process name count mismatch. expected, actual: {}, '
|
||||||
'{}'.format(len(expected), len(actual)))
|
'{}'.format(len(expected), len(actual)))
|
||||||
|
|
||||||
for (e_proc_name, e_pids_length), (a_proc_name, a_pids) in \
|
for (e_proc_name, e_pids), (a_proc_name, a_pids) in \
|
||||||
zip(e_proc_names.items(), a_proc_names.items()):
|
zip(e_proc_names.items(), a_proc_names.items()):
|
||||||
if e_proc_name != a_proc_name:
|
if e_proc_name != a_proc_name:
|
||||||
return ('Process name mismatch. expected, actual: {}, '
|
return ('Process name mismatch. expected, actual: {}, '
|
||||||
@ -610,25 +610,31 @@ class AmuletUtils(object):
|
|||||||
a_pids_length = len(a_pids)
|
a_pids_length = len(a_pids)
|
||||||
fail_msg = ('PID count mismatch. {} ({}) expected, actual: '
|
fail_msg = ('PID count mismatch. {} ({}) expected, actual: '
|
||||||
'{}, {} ({})'.format(e_sentry_name, e_proc_name,
|
'{}, {} ({})'.format(e_sentry_name, e_proc_name,
|
||||||
e_pids_length, a_pids_length,
|
e_pids, a_pids_length,
|
||||||
a_pids))
|
a_pids))
|
||||||
|
|
||||||
# If expected is not bool, ensure PID quantities match
|
# If expected is a list, ensure at least one PID quantity match
|
||||||
if not isinstance(e_pids_length, bool) and \
|
if isinstance(e_pids, list) and \
|
||||||
a_pids_length != e_pids_length:
|
a_pids_length not in e_pids:
|
||||||
|
return fail_msg
|
||||||
|
# If expected is not bool and not list,
|
||||||
|
# ensure PID quantities match
|
||||||
|
elif not isinstance(e_pids, bool) and \
|
||||||
|
not isinstance(e_pids, list) and \
|
||||||
|
a_pids_length != e_pids:
|
||||||
return fail_msg
|
return fail_msg
|
||||||
# If expected is bool True, ensure 1 or more PIDs exist
|
# If expected is bool True, ensure 1 or more PIDs exist
|
||||||
elif isinstance(e_pids_length, bool) and \
|
elif isinstance(e_pids, bool) and \
|
||||||
e_pids_length is True and a_pids_length < 1:
|
e_pids is True and a_pids_length < 1:
|
||||||
return fail_msg
|
return fail_msg
|
||||||
# If expected is bool False, ensure 0 PIDs exist
|
# If expected is bool False, ensure 0 PIDs exist
|
||||||
elif isinstance(e_pids_length, bool) and \
|
elif isinstance(e_pids, bool) and \
|
||||||
e_pids_length is False and a_pids_length != 0:
|
e_pids is False and a_pids_length != 0:
|
||||||
return fail_msg
|
return fail_msg
|
||||||
else:
|
else:
|
||||||
self.log.debug('PID check OK: {} {} {}: '
|
self.log.debug('PID check OK: {} {} {}: '
|
||||||
'{}'.format(e_sentry_name, e_proc_name,
|
'{}'.format(e_sentry_name, e_proc_name,
|
||||||
e_pids_length, a_pids))
|
e_pids, a_pids))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def validate_list_of_identical_dicts(self, list_of_dicts):
|
def validate_list_of_identical_dicts(self, list_of_dicts):
|
||||||
|
@ -79,15 +79,16 @@ class TestClusterHooks(CharmTestCase):
|
|||||||
hooks.hooks.execute(['hooks/cluster-relation-changed'])
|
hooks.hooks.execute(['hooks/cluster-relation-changed'])
|
||||||
ex = [
|
ex = [
|
||||||
call('stop', 'cinder-api'),
|
call('stop', 'cinder-api'),
|
||||||
call('stop', 'cinder-volume'),
|
|
||||||
call('stop', 'cinder-scheduler'),
|
|
||||||
call('stop', 'haproxy'),
|
|
||||||
call('stop', 'apache2'),
|
|
||||||
call('start', 'cinder-api'),
|
call('start', 'cinder-api'),
|
||||||
|
call('stop', 'cinder-volume'),
|
||||||
call('start', 'cinder-volume'),
|
call('start', 'cinder-volume'),
|
||||||
|
call('stop', 'cinder-scheduler'),
|
||||||
call('start', 'cinder-scheduler'),
|
call('start', 'cinder-scheduler'),
|
||||||
|
call('stop', 'haproxy'),
|
||||||
call('start', 'haproxy'),
|
call('start', 'haproxy'),
|
||||||
call('start', 'apache2')]
|
call('stop', 'apache2'),
|
||||||
|
call('start', 'apache2'),
|
||||||
|
]
|
||||||
self.assertEquals(ex, service.call_args_list)
|
self.assertEquals(ex, service.call_args_list)
|
||||||
|
|
||||||
@patch.object(hooks, 'check_db_initialised', lambda *args, **kwargs: None)
|
@patch.object(hooks, 'check_db_initialised', lambda *args, **kwargs: None)
|
||||||
|
Loading…
Reference in New Issue
Block a user