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