from bundlewrap.metadata import atomic

defaults = {
    'apt': {
        'repos': {
            'nginx': {
                'items': {
                    'deb http://nginx.org/packages/{os} {os_release} nginx',
                },
            },
        },
        'packages': {
            'nginx': {},
        },
    },
    'backups': {
        'paths': {
            '/var/www',
        },
    },
    'icinga2_api': {
        'nginx': {
            'services': {
                'NGINX PROCESS': {
                    'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_systemd_unit nginx',
                },
                'NGINX STATUS': {
                    'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_nginx_status',
                },
            },
        },
    },
    'nginx': {
        'worker_connections': 768,
    },
    'pacman': {
        'packages': {
            'nginx': {},
        },
    },
}

if node.has_bundle('telegraf'):
    defaults['telegraf'] = {
        'input_plugins': {
            'builtin': {
                'nginx': [{
                    'urls': ['http://localhost:22999/server_status'],
                }],
            },
        },
    }


@metadata_reactor.provides(
    'nginx/worker_processes',
)
def worker_processes(metadata):
    return {
        'nginx': {
            'worker_processes': metadata.get('vm/cpu', 2),
        },
    }


@metadata_reactor.provides(
    'letsencrypt/domains',
    'letsencrypt/reload_after',
    'nginx/vhosts',
)
def letsencrypt(metadata):
    if not node.has_bundle('letsencrypt'):
        raise DoNotRunAgain

    domains = {}
    vhosts = {}

    for vhost, config in metadata.get('nginx/vhosts', {}).items():
        if config.get('ssl', 'letsencrypt') == 'letsencrypt':
            domain = config.get('domain', vhost)
            domains[domain] = config.get('domain_aliases', set())
            vhosts[vhost] = {
                'ssl': 'letsencrypt',
                'force_domain': True,
            }

    return {
        'letsencrypt': {
            'domains': domains,
            'reload_after': {
                'nginx',
            },
        },
        'nginx': {
            'vhosts': vhosts,
        },
    }


@metadata_reactor.provides(
    'nginx/vhosts',
)
def index_files(metadata):
    vhosts = {}

    for vhost, config in metadata.get('nginx/vhosts', {}).items():
        if 'index' in config:
            continue

        vhosts[vhost] = {
            'index': [
                'index.html',
                'index.htm',
            ],
        }

        if config.get('php', False):
            # If we're using PHP, make sure index.php is tried first
            vhosts[vhost]['index'].insert(0, 'index.php')


    return {
        'nginx': {
            'vhosts': vhosts,
        },
    }


@metadata_reactor.provides(
    'icinga2_api/nginx/services',
)
def monitoring(metadata):
    services = {}

    for vname, vconfig in metadata.get('nginx/vhosts', {}).items():
        domain = vconfig.get('domain', vname)

        if vconfig['ssl']:
            scheme = 'https'
        else:
            scheme = 'http'

        if 'website_check_path' in vconfig and 'website_check_string' in vconfig:
            services['NGINX VHOST {} CONTENT'.format(vname)] = {
                'check_command': 'check_http_wget',
                'vars.http_wget_contains': vconfig['website_check_string'],
                'vars.http_wget_url': '{}://{}{}'.format(scheme, domain, vconfig['website_check_path']),
                'vars.notification.sms': True,
            }

        if vconfig.get('check_ssl', vconfig['ssl']):
            services['NGINX VHOST {} CERTIFICATE: {}'.format(vname, vconfig['ssl'])] = {
                'check_command': 'check_https_cert_at_url',
                'vars.domain': domain,
                'vars.notification.mail': True,
            }

    max_connections = metadata.get('nginx/worker_connections') * metadata.get('nginx/worker_processes')
    connections_warn = int(max_connections * 0.8)
    connections_crit = int(max_connections * 0.9)

    services['NGINX STATUS'] = {
        'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_nginx_status --warn={},-1,-1 --critical={},-1,-1 -H 127.0.0.1:22999'.format(connections_warn, connections_crit),
    }

    return {
        'icinga2_api': {
            'nginx': {
                'services': services,
            },
        },
    }


@metadata_reactor.provides(
    'firewall/port_rules',
    'firewall/port_rules',
)
def firewall(metadata):
    return {
        'firewall': {
            'port_rules': {
                '80/tcp': atomic(metadata.get('nginx/restrict-to', {'*'})),
                '443/tcp': atomic(metadata.get('nginx/restrict-to', {'*'})),
            },
        },
    }


@metadata_reactor.provides(
    'telegraf/input_plugins/tail',
)
def telegraf_anon_timing(metadata):
    result = {}

    for vname, vconfig in metadata.get('nginx/vhosts', {}).items():
        if not vconfig.get('timing_log', True):
            continue

        result[f'nginx-{vname}'] = {
            'files': [f'/var/log/nginx-timing/{vname}.log'],
            'from_beginning': False,
            'grok_patterns': ['%{LOGPATTERN}'],
            'grok_custom_patterns': 'LOGPATTERN \[%{HTTPDATE:ts:ts-httpd}\] %{NUMBER:request_time:float} (?:%{NUMBER:upstream_response_time:float}|-) "%{WORD:verb:tag} %{NOTSPACE:request} HTTP/%{NUMBER:http_version:float}" %{NUMBER:resp_code:tag}',
            'data_format': 'grok',
            'name_override': 'nginx_timing',
        }

    return {
        'telegraf': {
            'input_plugins': {
                'tail': result,
            },
        },
    }

