5eee070465
This change is a result of "make sync" for neutron-api charm.
Test changes also applied: removing an "charmhelpers/tests" sync
due to recent charm changes (see commit 8937059
for details) and
keystone auth_uri/auth_url removed from test since it has to been
checked later by functional tests.
Change-Id: I108497e50f28fc2a84e035f520fea4452edd91db
101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
# Copyright 2016 Canonical Limited.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import re
|
|
import subprocess
|
|
|
|
import six
|
|
|
|
from charmhelpers.core.hookenv import (
|
|
log,
|
|
INFO,
|
|
ERROR,
|
|
)
|
|
|
|
from charmhelpers.contrib.hardening.audits import BaseAudit
|
|
|
|
|
|
class DisabledModuleAudit(BaseAudit):
|
|
"""Audits Apache2 modules.
|
|
|
|
Determines if the apache2 modules are enabled. If the modules are enabled
|
|
then they are removed in the ensure_compliance.
|
|
"""
|
|
def __init__(self, modules):
|
|
if modules is None:
|
|
self.modules = []
|
|
elif isinstance(modules, six.string_types):
|
|
self.modules = [modules]
|
|
else:
|
|
self.modules = modules
|
|
|
|
def ensure_compliance(self):
|
|
"""Ensures that the modules are not loaded."""
|
|
if not self.modules:
|
|
return
|
|
|
|
try:
|
|
loaded_modules = self._get_loaded_modules()
|
|
non_compliant_modules = []
|
|
for module in self.modules:
|
|
if module in loaded_modules:
|
|
log("Module '%s' is enabled but should not be." %
|
|
(module), level=INFO)
|
|
non_compliant_modules.append(module)
|
|
|
|
if len(non_compliant_modules) == 0:
|
|
return
|
|
|
|
for module in non_compliant_modules:
|
|
self._disable_module(module)
|
|
self._restart_apache()
|
|
except subprocess.CalledProcessError as e:
|
|
log('Error occurred auditing apache module compliance. '
|
|
'This may have been already reported. '
|
|
'Output is: %s' % e.output, level=ERROR)
|
|
|
|
@staticmethod
|
|
def _get_loaded_modules():
|
|
"""Returns the modules which are enabled in Apache."""
|
|
output = subprocess.check_output(['apache2ctl', '-M'])
|
|
if six.PY3:
|
|
output = output.decode('utf-8')
|
|
modules = []
|
|
for line in output.splitlines():
|
|
# Each line of the enabled module output looks like:
|
|
# module_name (static|shared)
|
|
# Plus a header line at the top of the output which is stripped
|
|
# out by the regex.
|
|
matcher = re.search(r'^ (\S*)_module (\S*)', line)
|
|
if matcher:
|
|
modules.append(matcher.group(1))
|
|
return modules
|
|
|
|
@staticmethod
|
|
def _disable_module(module):
|
|
"""Disables the specified module in Apache."""
|
|
try:
|
|
subprocess.check_call(['a2dismod', module])
|
|
except subprocess.CalledProcessError as e:
|
|
# Note: catch error here to allow the attempt of disabling
|
|
# multiple modules in one go rather than failing after the
|
|
# first module fails.
|
|
log('Error occurred disabling module %s. '
|
|
'Output is: %s' % (module, e.output), level=ERROR)
|
|
|
|
@staticmethod
|
|
def _restart_apache():
|
|
"""Restarts the apache process"""
|
|
subprocess.check_output(['service', 'apache2', 'restart'])
|