Skip to content
Snippets Groups Projects
test_nginx_vhosts.py 8.13 KiB
Newer Older
Stéphane Diemer's avatar
Stéphane Diemer committed
#!/usr/bin/env python3
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed

"""
Tests that all webserver services (vhosts) are available and reachable.
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
"""

Stéphane Diemer's avatar
Stéphane Diemer committed
import os
import re
import requests
Stéphane Diemer's avatar
Stéphane Diemer committed
import sys
try:
    from requests.packages.urllib3.exceptions import InsecureRequestWarning
    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
except ImportError:
    requests.packages.urllib3.disable_warnings()
Stéphane Diemer's avatar
Stéphane Diemer committed

Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
"""
This script checks for all enabled vhosts in Nginx conf that:
* The response status code is 200, 401 or 403.
* The host is resolved as 127.0.0.1.
* The Wowza response is correct on /streaming/ (only for mediaserver vhosts).
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
"""
Stéphane Diemer's avatar
Stéphane Diemer committed

Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
def test_vhost(
    ports_info=None, domains=None, resolution_ignored=None, celerity_conf=""
):
    tested = 0
    errors = 0
    warnings = 0
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    for port, https in ports_info or [(80, False)]:
        for domain in domains or ["localhost"]:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
            url = "%s://%s:%s" % ("https" if https else "http", domain, port)
            sys.stdout.write('Testing url "%s":\n' % url)
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
            if name.startswith("mediaserver"):
                if not celerity_conf or not re.search(
                    r"http[s]{0,1}://%s" % domain, celerity_conf
                ):
                    sys.stdout.write(
                        '\033[93mWarning:\033[0m Url "%s" not found in celerity conf; it should also be set in the MediaWorker.\n'
                        % url
                    )
                    warnings += 1
            # test domain IP
            ip_error = None
            ip_warning = None
            try:
                ip = socket.gethostbyname(domain)
            except Exception as e:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                ip_error = "domain is not resolved: %s" % e
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                if ip != "127.0.0.1":
                    ip_warning = "domain is resolved with %s instead of 127.0.0.1" % ip
            sys.stdout.write("  IP: ")
            if ip_error:
                if resolution_ignored and domain in resolution_ignored:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    sys.stdout.write("\033[94mIgnored (%s)\033[0m" % ip_error)
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    sys.stdout.write("\033[91mKO (%s)\033[0m" % ip_error)
            elif ip_warning:
                if resolution_ignored and domain in resolution_ignored:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    sys.stdout.write("\033[94mIgnored (%s)\033[0m" % ip_warning)
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    sys.stdout.write("\033[93mWarning (%s)\033[0m" % ip_warning)
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                sys.stdout.write("\033[92mOK (127.0.0.1)\033[0m")
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
            sys.stdout.write(", status: ")
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                req = requests.get(
                    url, verify=False, proxies={"http": "", "https": ""}, timeout=30
                )
                req_time = int(1000 * req.elapsed.total_seconds())
            except Exception as e:
                code = str(e)
                req_time = 0
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
            if (
                domain != "localhost"
                and code not in (200, 401, 403)
                or domain == "localhost"
                and code not in (200, 401, 403, 404)
            ):
                sys.stdout.write("\033[91mKO (%s, %sms)\033[0m" % (code, req_time))
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    sys.stdout.write("\033[93mOK (%s, %sms)\033[0m" % (code, req_time))
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    sys.stdout.write("\033[92mOK (%s, %sms)\033[0m" % (code, req_time))
                if "mediaserver" in name and wowza_dir:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    sys.stdout.write(", streaming: ")
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                        req = requests.get(
                            url + "/streaming/",
                            verify=False,
                            proxies={"http": "", "https": ""},
                            timeout=30,
                        )
                        req_time = int(1000 * req.elapsed.total_seconds())
                    except Exception as e:
                        code = str(e)
                        req_time = 0
                    else:
                        code = req.status_code
                    if code != 200:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                        sys.stdout.write(
                            "\033[91mKO (%s, %sms)\033[0m" % (code, req_time)
                        )
                        req_error = True
                    elif req_time > 10000:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                        sys.stdout.write(
                            "\033[93mOK (%s, %sms)\033[0m" % (code, req_time)
                        )
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                        sys.stdout.write(
                            "\033[92mOK (%s, %sms)\033[0m" % (code, req_time)
                        )
            sys.stdout.write(".\n")

            if ip_warning:
                warnings += 1

            if ip_error or req_error:
                errors += 1
    return tested, warnings, errors


Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
if __name__ == "__main__":
    # check that Nginx dir exists
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    nginx_dir = "/etc/nginx/sites-enabled"
    if not os.path.exists(nginx_dir):
        print('Nginx dir does not exists ("%s").' % nginx_dir)
        sys.exit(2)

    # check that Wowza is installed
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    wowza_dir = "/usr/local/WowzaStreamingEngine"
    if not os.path.exists(wowza_dir):
        print('Info: Wowza is not installed ("%s" does not exist).' % wowza_dir)
        wowza_dir = None
    else:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
        print(
            "Info: Wowza is installed, /streaming/ will be tested on mediaserver vhosts."
        )

    # get envsetup conf
    conf = dict()
    os.chdir(os.path.dirname(__file__))
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    if os.path.isfile("../utils.py"):
        es_utils = imp.load_source("es_utils", "../utils.py")
        conf = es_utils.load_conf()
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    celerity_conf = ""
    if os.path.exists("/etc/celerity/config.py"):
        with open("/etc/celerity/config.py", "r") as fo:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
    resolution_ignored = conf.get("TESTER_VHOST_RESOLUTION_IGNORED", "").split(",")
    tested = 0
    errors = 0
    warnings = 0
    names = os.listdir(nginx_dir)
    names.sort()
    for name in names:
        path = os.path.join(nginx_dir, name)
        level = 0
        domains = list()
        ports_info = list()
        print('Parsing vhost "%s"...' % path)
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
        with open(path, "r") as fo:
            for line in fo:
                line = line.strip()
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                if not line or line.startswith("#"):
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                words = re.sub(r"\s+", " ", line).strip("; ").split(" ")
                if "{" in words or "}" in words:
                    level += words.count("{")
                    level -= words.count("}")
                    if level == 0:
                        # test
                        if ports_info or domains:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                            t, w, e = test_vhost(
                                ports_info, domains, resolution_ignored, celerity_conf
                            )
                            tested += t
                            warnings += w
                            errors += e
                        domains = list()
                        ports_info = list()
                elif level == 1:
                    # server section are level 1
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    if words[0] == "listen":
                        https = "ssl" in words
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                                port = int(port.split(":")[-1])
                            except ValueError:
                                pass
                            else:
                                ports_info.append((port, https))
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                    elif words[0] == "server_name":
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
        print("%s url(s) did not correctly respond." % errors)
        sys.exit(1)
    elif warnings:
        sys.exit(3)
    if not tested:
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
        print("No url found in Nginx sites-enabled dir.")