nginx-amplify-agent/amplify/agent/collectors/nginx/config.py

134 lines
4.7 KiB
Python

# -*- coding: utf-8 -*-
import time
from amplify.agent.collectors.abstract import AbstractCollector
from amplify.agent.common.context import context
from amplify.agent.data.eventd import CRITICAL, INFO, WARNING
__author__ = "Mike Belov"
__copyright__ = "Copyright (C) Nginx, Inc. All rights reserved."
__license__ = ""
__maintainer__ = "Mike Belov"
__email__ = "dedm@nginx.com"
MAX_SIZE_FOR_TEST = 20 * 1024 * 1024 # 20 MB
DEFAULT_PARSE_DELAY = 60.0
class NginxConfigCollector(AbstractCollector):
short_name = 'nginx_config'
def __init__(self, previous=None, **kwargs):
super(NginxConfigCollector, self).__init__(**kwargs)
self.previous = previous or {
'files': {},
'directories': {}
}
self.parse_delay = context.app_config['containers'].get('nginx', {}).get('parse_delay', DEFAULT_PARSE_DELAY)
self.register(
self.parse_config
)
def parse_config(self, no_delay=False):
"""
Parses the NGINX configuration file.
Will not run if:
a) it hasn't been long enough since the last time it parsed (unless `no_delay` is True)
b) the configuration files from the last parse haven't changed
:param no_delay: bool - ignore delay times for this run (useful for testing)
"""
config = self.object.config
# don't parse config if it hasn't been long enough since last parse
if not no_delay and time.time() < config.wait_until:
return
files, directories = config.collect_structure(include_ssl_certs=self.object.upload_ssl)
# only parse config if config files have changed since last collect
if files == self.previous['files']:
return
self.previous['files'] = files
self.previous['directories'] = directories
# parse config tree
start_time = time.time()
try:
config.full_parse(include_ssl_certs=self.object.upload_ssl)
finally:
elapsed_time = time.time() - start_time
delay = 0 if no_delay else max(elapsed_time * 2, self.parse_delay)
config.wait_until = start_time + delay
# Send event for parsing nginx config.
# Use config.parser.filename to account for default value defined in NginxConfigParser.
self.object.eventd.event(
level=INFO,
message='nginx config parsed, read from %s' % config.filename,
)
for error in config.parser_errors:
self.object.eventd.event(level=WARNING, message=error)
# run ssl checks
config.run_ssl_analysis()
# run upload
if self.object.upload_config:
checksum = config.checksum()
self.upload(config, checksum)
# otherwise run test
if self.object.run_config_test and config.total_size() < MAX_SIZE_FOR_TEST:
run_time = config.run_test()
# send event for testing nginx config
if config.test_errors:
self.object.eventd.event(level=WARNING, message='nginx config test failed')
else:
self.object.eventd.event(level=INFO, message='nginx config tested ok')
for error in config.test_errors:
self.object.eventd.event(level=CRITICAL, message=error)
# stop -t if it took too long
if run_time > context.app_config['containers']['nginx']['max_test_duration']:
context.app_config['containers']['nginx']['run_test'] = False
context.app_config.mark_unchangeable('run_test')
self.object.eventd.event(
level=WARNING,
message='%s -t -c %s took %s seconds, disabled until agent restart' % (
config.binary, config.filename, run_time
)
)
self.object.run_config_test = False
def handle_exception(self, method, exception):
super(NginxConfigCollector, self).handle_exception(method, exception)
self.object.eventd.event(
level=INFO,
message='nginx config parser failed, path %s' % self.object.conf_path,
onetime=True
)
def upload(self, config, checksum):
payload = {
'tree': config.tree,
'directory_map': config.directory_map,
'files': config.files,
'directories': config.directories,
'ssl_certificates': config.ssl_certificates,
'access_logs': config.access_logs,
'error_logs': config.error_logs,
'errors': {
'parser': len(config.parser_errors),
'test': len(config.test_errors)
}
}
self.object.configd.config(payload=payload, checksum=checksum)