Exemple #1
0
def main():
    try:
        if os.geteuid() != 0:
            Logger.error('{} must be run as root.'.format(sys.argv[0]))
            sys.exit(1)

        current_vhost_string = None
        current_vhost_name = None

        force_renew_certs = len(sys.argv) == 2 and sys.argv[1] == force_arg

        with open(CONFIG_FILE_PATH) as f:
            config = util.strip_json_comments(f.read())
            try:
                sites = json.loads(config)
            except Exception as ex:
                raise Exception(
                    'Could not parse configuration file "{}": {}'.format(
                        CONFIG_FILE_PATH, ex))

        apache_vhosts = apache_util.get_apache_vhosts()
        if len(apache_vhosts) == 0:
            Logger.error(
                'Could not find any Apache VHosts on this system, please configure your Apache VHosts before using this script.')
            sys.exit(2)

        for site_index, site in enumerate(sites):
            current_vhost_string = site.get(
                'VHost', 'VHost configuration number {}'.format(
                    site_index + 1))
            current_vhost_name = site.get('ServerName', '')
            process_vhost(
                site,
                current_vhost_string,
                current_vhost_name,
                apache_vhosts,
                force_renew_certs)

        if apache_util.is_apache_running():
            reload_apache()

    except Exception as e:
        log_error(
            'VHost "{}, {}": {} {} {}'.format(
                current_vhost_string,
                current_vhost_name,
                type(e),
                e,
                util.format_traceback()),
            'VHost "{}, {}": {} {}'.format(
                current_vhost_string,
                current_vhost_name,
                type(e),
                e))
        sys.exit(1)
    finally:
        print_error_summary(all_error_messages, all_warning_messages)
        util.close_logger(Logger)
        if all_error_messages:
            sys.exit(1)
def process_vhost(site_configuration, current_vhost_string, current_vhost_name,
                  apache_vhosts, force_renew_certs):
    global error_messages
    global warning_messages

    current_site = site_configuration
    try:
        # Validation
        parsed_site, validation_errors = util.parse_settings(
            current_site, util.APACHE_RENEWAL_SETTINGS)
        # parsed_site either contains correctly parsed site settings with populated defaults or None (and a non-empty validation error list).
        # Even if parsing failed, we want to present the user with a complete error list. So for purposes of further validation
        # we fill current_site at least defined values (e.g. None) using
        # populate_defaults such that validate_site_configuration can is able to
        # do its checks.
        current_site = parsed_site or util.populate_defaults(
            current_site, util.APACHE_RENEWAL_SETTINGS)

        validation_errors.extend(
            validate_site_configuration(current_site, apache_vhosts.keys()))
        if validation_errors:
            message = make_validation_error_message(validation_errors,
                                                    current_vhost_string)
            log_error(message)
            raise Exception(
                'Errors during validation of VHost "{}, {}".'.format(
                    current_vhost_string, current_vhost_name))

        # Processing
        if not apache_util.is_apache_running():
            if (not os.path.isfile(
                    apache_util.get_apache_ssl_cert_path(
                        current_vhost_string,
                        current_vhost_name))) or (not os.path.isfile(
                            apache_util.get_apache_ssl_key_path(
                                current_vhost_string, current_vhost_name))):
                log_warning(
                    'Apache is not running, but certificate/keyfile missing. Attempting to correct. Note: this will not restart apache.'
                )
                pem_cert_key_path = get_cert(current_site)
                install_apache_ssl_cert(pem_cert_key_path, current_site)
                email_results(current_site)
                return True
            else:
                raise Exception(
                    'Apache is not running, skipping certificate update for VHost {} {}.'
                    .format(current_vhost_string, current_vhost_name))

        update_apache_config(current_site)
        if force_renew_certs or is_cert_renewal_needed(current_site):
            pem_cert_key_path = get_cert(current_site)
            install_apache_ssl_cert(pem_cert_key_path, current_site)
    except Exception as e:
        # Log error, but continue processing the next VHost
        log_error(
            'VHost "{}, {}": {} {} {}'.format(current_vhost_string,
                                              current_vhost_name, type(e), e,
                                              util.format_traceback()),
            'VHost "{}, {}": {} {}'.format(current_vhost_string,
                                           current_vhost_name, type(e), e))
        return False
    finally:
        email_results(current_site)
        error_messages = []
        warning_messages = []

    return True
def email_results(site):
    """
    Email error and warning messages for a specific site.

    :param site: The site configuration with E-mail notification settings (if any)
    """
    if not (site and 'EmailNotifications' in site
            and site['EmailNotifications'] is True and
            (error_messages or warning_messages)):
        return

    status = 'SUCCESS'
    if error_messages:
        status = 'ERROR'
    elif warning_messages:
        status = 'WARNINGS'

    message = ''
    log_files = [
        path
        for path in [LOG_FILE_PATH, KTCLIENT_LOG_PATH, CRON_LOG_FILE_PATH]
        if os.path.isfile(path)
    ]
    message += 'Server hostname: {}\r\n'.format(platform.node())
    message += 'Apache VHost: {}\r\n'.format(site['VHost'])
    message += 'Apache VHost ServerName: {}\r\n'.format(site['ServerName']
                                                        or '<None>')
    message += '\r\n'
    if error_messages:
        message += '== Errors ==\r\n{}'.format('\r\n'.join(error_messages))
    if warning_messages:
        message += '\r\n\r\n'
        message += '== Warnings ==\r\n{}'.format('\r\n'.join(warning_messages))
    message += '\r\n\r\nMore information can be found in the attached log file cutouts.'
    message += '\r\nFor full logs, please see the following files:\r\n\t'
    message += '\r\n\t'.join(log_files)

    subject = '{}: {} (VHost {}{})'.format(
        site['EmailSubject'], status, site['VHost'] or '<unknown>',
        ', {}'.format(site['ServerName']) if site['ServerName'] else '')
    server = site['EmailServer']
    try:
        attachments = []
        for log_file in log_files:
            att_name = os.path.basename(log_file)
            att_content = open(log_file).read()
            # Only send the last 200 lines of the log to save traffic
            att_content = '\n'.join(att_content.splitlines()[-200:])
            attachments.append((att_name, att_content))
        util.send_email(server, site['EmailFrom'], site['EmailTo'].split(','),
                        subject, message, attachments)
    except Exception as e:
        log_error(
            'Could not send e-mail summary for VHost "{}, {}": {} {} {}'.
            format(site.get('VHost', '<unknown>'), site.get('ServerName', ''),
                   type(e), e, util.format_traceback()),
            'Could not send e-mail summary for VHost "{}, {}": {} {}'.format(
                site.get('VHost', '<unknown>'), site.get('ServerName', ''),
                type(e), e))
        return False
    return True