#!/usr/bin/python3
#
# MIT License
# Copyright (c) 2019 Dick Visser
#
# https://github.com/dnmvisser/nagios_check_time_by_http_date
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import argparse
import sys
import requests
from datetime import datetime, timezone
import email.utils
import urllib3


def nagios_exit(message, code):
    print(message)
    sys.exit(code)


# start with clean slate
ok_msg = []
warn_msg = []
crit_msg = []
unknown_msg = []

try:
    parser = argparse.ArgumentParser(
        description='Check time offset of the HTTP "Date" response header against the local time'
    )
    parser.add_argument("--url", "-u", help="the URL to check", required=True)
    parser.add_argument(
        "--useragent",
        "-a",
        help="the User-Agent string to use",
        required=False,
        default="check_time_http",
    )
    # https://kantarainitiative.github.io/SAMLprofiles/saml2int.html#_clock_skew
    parser.add_argument(
        "--warn",
        "-w",
        help="Offset to result in warning (seconds, default 180)",
        required=False,
        type=int,
        default=180,
    )
    parser.add_argument(
        "--crit",
        "-c",
        help="Offset to result in critical (seconds, default 300)",
        required=False,
        type=int,
        default=300,
    )
    parser.add_argument(
        "--timeout",
        "-t",
        help="Timeout of the HTTP request (seconds)",
        required=False,
        type=int,
    )
    parser.add_argument(
        "--verbose",
        "-v",
        help="Return verbose output",
        required=False,
        dest="verbose",
        action="store_true",
    )

    verify_parser = parser.add_mutually_exclusive_group(required=False)
    verify_parser.add_argument(
        "--verify",
        dest="verify",
        action="store_true",
        help="Verify SSL certificate (default)",
    )
    verify_parser.add_argument(
        "--no-verify",
        dest="verify",
        action="store_false",
        help="Do not verify SSL certificate",
    )
    parser.set_defaults(verify=True)

    args = parser.parse_args()

    url = args.url
    useragent = args.useragent
    warn = args.warn
    crit = args.crit
    timeout = args.timeout
    verify = args.verify
    verbose = args.verbose

    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    req = requests.head(
        url, timeout=timeout, verify=verify, headers={"User-Agent": useragent}
    )

    # Date with time zone
    utc_now = datetime.now(timezone.utc)

    # this is case insensitive
    if "date" in req.headers:
        http_date = email.utils.parsedate_to_datetime(req.headers["date"])
        offset = int((http_date - utc_now).total_seconds())
        message = "Offset is {0} seconds".format(offset)
        if verbose:
            message += ", URL: {0}".format(url)
            message += ", local date: {0}".format(utc_now)
            message += ", HTTP headers: {0}".format(req.headers)

        if abs(offset) > crit:
            crit_msg.append(message)
        elif abs(offset) > warn:
            warn_msg.append(message)
        else:
            ok_msg.append(message)
    else:
        unknown_msg.append("No Date header detected for {0}".format(url))
except Exception as e:
    unknown_msg.append("{0}.".format(e))

# Exit with accumulated message(s)
if unknown_msg:
    nagios_exit("UNKNOWN: " + " ".join(unknown_msg), 3)
elif crit_msg:
    nagios_exit("CRITICAL: " + " ".join(crit_msg + warn_msg), 2)
elif warn_msg:
    nagios_exit("WARNING: " + " ".join(warn_msg), 1)
else:
    nagios_exit("OK: " + " ".join(ok_msg), 0)
