#!/usr/bin/env python3
# -*- coding: utf-8; py-indent-offset: 4 -*-
#
# Author:  Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
#          https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.

# https://github.com/Linuxfabrik/monitoring-plugins/blob/main/CONTRIBUTING.md

"""See the check's README for more details.
"""

import argparse  # pylint: disable=C0413
import socket  # pylint: disable=C0413
import sys  # pylint: disable=C0413

import lib.base  # pylint: disable=C0413
from lib.globals import (STATE_CRIT, STATE_OK,  # pylint: disable=C0413
                          STATE_UNKNOWN, STATE_WARN)

__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2023112901'

DESCRIPTION = 'Checks whether a network port is reachable.'

DEFAULT_HOSTNAME = 'localhost'
DEFAULT_PORT = 22
DEFAULT_SEVERITY = 'warn'
DEFAULT_TIMEOUT = 2
DEFAULT_TYPE='tcp'


def parse_args():
    """Parse command line arguments using argparse.
    """
    parser = argparse.ArgumentParser(description=DESCRIPTION)

    parser.add_argument(
        '-V', '--version',
        action='version',
        version='%(prog)s: v{} by {}'.format(__version__, __author__)
    )

    parser.add_argument(
        '-H', '--hostname',
        help='The host or ip address to check. Default: %(default)s',
        dest='HOSTNAME',
        default=DEFAULT_HOSTNAME,
    )

    parser.add_argument(
        '-p', '--port',
        help='The port number. Default: %(default)s',
        dest='PORT',
        type=int,
        default=DEFAULT_PORT,
    )

    parser.add_argument(
        '--portname',
        help='The display name of the port.',
        dest='PORTNAME',
    )

    parser.add_argument(
        '--severity',
        help='Severity for alerting. Default: %(default)s',
        dest='SEVERITY',
        default=DEFAULT_SEVERITY,
        choices=['warn', 'crit'],
    )

    parser.add_argument(
        '-t', '--timeout',
        help='Network timeout. Default: %(default)s',
        dest='TIMEOUT',
        type=float,
        default=DEFAULT_TIMEOUT,
    )

    parser.add_argument(
        '--type',
        help='Connection type. Default: %(default)s',
        dest='TYPE',
        default=DEFAULT_TYPE,
        choices=['tcp', 'tcp6'],
    )

    return parser.parse_args()


def main():
    """The main function. Hier spielt die Musik.
    """

    # parse the command line, exit with UNKNOWN if it fails
    try:
        args = parse_args()
    except SystemExit:
        sys.exit(STATE_UNKNOWN)

    # fetch data
    if args.TYPE == 'tcp':
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    else:
        sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
    sock.settimeout(args.TIMEOUT)

    try:
        # Works fine for tcp connections, but not for udp. The port response for udp is based on
        # the target application and is not standard like tcp.
        if sock.connect_ex((args.HOSTNAME, args.PORT)) == 0:
            state = STATE_OK
        else:
            state = STATE_WARN if args.SEVERITY == 'warn' else STATE_CRIT
        sock.close()
    except:
        lib.base.oao('Cannot initiate a connection to {}:{}/{}.'.format(
            args.HOSTNAME,
            args.PORT,
            args.TYPE,
        ), STATE_UNKNOWN)

    # over and out
    lib.base.oao('{}:{}/{} is {}.'.format(
        args.HOSTNAME,
        args.PORTNAME if args.PORTNAME else args.PORT,
        args.TYPE,
        'reachable' if state == STATE_OK else 'unreachable',
    ), state)


if __name__ == '__main__':
    try:
        main()
    except Exception:   # pylint: disable=W0703
        lib.base.cu()
