diff --git a/management/daemon.py b/management/daemon.py index 0bbb1ad5..8ba11e7e 100755 --- a/management/daemon.py +++ b/management/daemon.py @@ -12,6 +12,7 @@ import os, os.path, re, json, time import multiprocessing.pool, subprocess +import logging from functools import wraps @@ -762,14 +763,21 @@ def log_failed_login(request): # APP if __name__ == '__main__': + logging_level = logging.INFO + if "DEBUG" in os.environ: # Turn on Flask debugging. app.debug = True + logging_level = logging.DEBUG if not app.debug: app.logger.addHandler(utils.create_syslog_handler()) #app.logger.info('API key: ' + auth_service.key) + logging.basicConfig(level=logging_level, format='%(levelname)s:%(module)s.%(funcName)s %(message)s') + logging.info('Logging level set to %s', logging.getLevelName(logging_level)) + # Start the application server. Listens on 127.0.0.1 (IPv4 only). app.run(port=10222) + diff --git a/management/dns_update.py b/management/dns_update.py index 79b9ad8a..e1583528 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -8,6 +8,7 @@ import sys, os, os.path, urllib.parse, datetime, re, hashlib, base64 import ipaddress import rtyaml import dns.resolver +import logging from utils import shell, load_env_vars_from_file, safe_domain_name, sort_domains from ssl_certificates import get_ssl_certificates, check_certificate @@ -117,7 +118,7 @@ def do_dns_update(env, force=False): # Clear unbound's DNS cache so our own DNS resolver is up to date. # (ignore errors with trap=True) - shell('check_call', ["/usr/sbin/unbound-control", "reload"], trap=True) + shell('check_call', ["/usr/sbin/unbound-control", "reload"], trap=True, capture_stdout=False) if len(updated_domains) == 0: # if nothing was updated (except maybe DKIM's files), don't show any output @@ -1101,17 +1102,32 @@ def set_secondary_dns(hostnames, env): if len(hostnames) > 0: # Validate that all hostnames are valid and that all zone-xfer IP addresses are valid. resolver = dns.resolver.get_default_resolver() - resolver.timeout = 5 + resolver.timeout = 6 for item in hostnames: if not item.startswith("xfr:"): # Resolve hostname. try: response = resolver.resolve(item, "A") except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): + logging.debug('Error on resolving ipv4 address, trying ipv6') try: response = resolver.resolve(item, "AAAA") except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): raise ValueError("Could not resolve the IP address of %s." % item) + except (dns.resolver.Timeout): + resolver.timeout = 7 + logging.warning('Timeout on resolving ipv4 address re-trying') + try: + response = resolver.resolve(item, "A") + except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): + logging.debug('Error on resolving ipv4 address, trying ipv6 (2)') + try: + response = resolver.resolve(item, "AAAA") + except (dns.resolver.NoNameservers, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): + raise ValueError("Could not resolve the IP address of %s." % item) + except (dns.resolver.Timeout): + raise ValueError("Could not resolve the IP address of %s due to timeout." % item) + resolver.timeout = 6 else: # Validate IP address. try: diff --git a/management/status_checks.py b/management/status_checks.py index 040695d8..2fdba742 100755 --- a/management/status_checks.py +++ b/management/status_checks.py @@ -56,7 +56,7 @@ def run_checks(rounded_values, env, output, pool, domains_to_check=None): # clear unbound's DNS cache so our DNS checks are up to date # (ignore errors; if unbound isn't running we'd already report # that in run_services checks.) - shell('check_call', ["/usr/sbin/unbound-control", "reload"], trap=True) + shell('check_call', ["/usr/sbin/unbound-control", "reload"], trap=True, capture_stdout=False) run_system_checks(rounded_values, env, output) diff --git a/management/utils.py b/management/utils.py index bc357040..de23361c 100644 --- a/management/utils.py +++ b/management/utils.py @@ -106,7 +106,7 @@ def sort_email_addresses(email_addresses, env): ret.extend(sorted(email_addresses)) # whatever is left return ret -def shell(method, cmd_args, env={}, capture_stderr=False, return_bytes=False, trap=False, input=None): +def shell(method, cmd_args, env={}, capture_stdout=True, capture_stderr=False, return_bytes=False, trap=False, input=None): # A safe way to execute processes. # Some processes like apt-get require being given a sane PATH. import subprocess @@ -116,6 +116,8 @@ def shell(method, cmd_args, env={}, capture_stderr=False, return_bytes=False, tr 'env': env, 'stderr': None if not capture_stderr else subprocess.STDOUT, } + if not capture_stdout: + kwargs['stdout'] = subprocess.DEVNULL if method == "check_output" and input is not None: kwargs['input'] = input