#!/usr/bin/python3
#
# Contributed by Nagy Zsombor.
# Support for GLUE 2.0r1 by Gabor Roczei.
# Released under the Apache License with permission from Gabor Roczei.
# See also http://bugzilla.nordugrid.org/show_bug.cgi?id=1983.
#
# TODO: If this is still needed, move code into functions and fix pylint issues.
# pylint: disable=all

import getopt
import signal
import socket
import sys
import traceback
import http.client
import urllib.parse
try:
    import xml.etree.ElementTree as ET
except ImportError:
    import elementtree.ElementTree as ET # pylint: disable=import-error

glue_schemas = [
    'http://schemas.ogf.org/glue/2008/05/spec_2.0_d41_r01',
    'http://schemas.ogf.org/glue/2009/03/spec_2.0_r1',
]

timeout = 10

def handler(signum, frame): # pylint: disable=unused-argument
    print("ARCSERVICE UNKNOWN: Check timed out after %s seconds" % timeout)
    sys.exit(3)

signal.signal(signal.SIGALRM, handler)
signal.alarm(timeout)

def usage():
    print("""Usage: check_arcservice -u <URL> -k <key_file> -c <cert_file> -t <timeout> --debug

    -u <URL>        the URL of the service to check (mandatory)
    -t <timeout>    after this amount of seconds the check will return UNKNOWN (default: 10)
    -k <key_file>   path of the key file (default: /etc/grid-security/hostkey.pem)
    -c <cert_file>  path of the cert file (default: /etc/grid-security/hostcert.pem)
    --debug         print some debugging information
    """)
    sys.exit(3)

try:
    options, args = getopt.getopt(sys.argv[1:],"u:k:c:t:",["debug"])
except getopt.GetoptError:
    usage()

key_file = '/etc/grid-security/hostkey.pem'
cert_file = '/etc/grid-security/hostcert.pem'
url = ''
debug = False

for name, value in options:
    if name in ['-k']:
        key_file = value
    if name in ['-c']:
        cert_file = value
    if name in ['-u']:
        url = value
    if name in ['--debug']:
        debug = True
    if name in ['-t']:
        timeout = int(value)
        signal.alarm(timeout)

if not key_file or not cert_file or not url:
    usage()

try:
    parsed = urllib.parse.urlparse(url)
    https = (parsed[0] == 'https')
    hostport = parsed[1]
    path = parsed[2]
except (ValueError, KeyError):
    print("ARCSERVICE UNKNOWN: Error parsing URL %s" % url)


get_resource_property_document_request = '''<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:wsrf-rp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsa="http://www.w3.org/2005/08/addressing">
    <SOAP-ENV:Header>
        <wsa:Action>http://docs.oasis-open.org/wsrf/rpw-2/GetResourcePropertyDocument/GetResourcePropertyDocumentRequest</wsa:Action>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
        <wsrf-rp:GetResourcePropertyDocument/>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>'''

if https:
    import ssl
    ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    ssl_context.load_cert_chain(certfile = cert_file, keyfile = key_file)
    connection = http.client.HTTPSConnection(host=hostport, context=ssl_context)
else:
    connection = http.client.HTTPConnection(host=hostport)
try:
    connection.request('POST', path, get_resource_property_document_request)
except (socket.error, http.client.HTTPException) as exn:
    print("ARCSERVICE CRITICAL: Connecting to %s failed: %s" % (url, exn))
    if debug:
        traceback.print_exc()
    sys.exit(2)
response = connection.getresponse()
if response.status == 200:
    data = response.read()
    try:
        et = ET.fromstring(data)
        health_state = None
        for glue_schema in glue_schemas:
            health_state = et.findtext(".//{%s}HealthState" % glue_schema)
            if health_state:
                break

        if health_state is None:
            print("ARCSERVICE UNKNOWN: Service's health state is unknown")
            if debug:
                print(data)
            sys.exit(3)

        if health_state == 'ok':
            print("ARCSERVICE OK: Service's health state is %s" % health_state)
            if debug:
                print(data)
            sys.exit(0)
        else:
            print("ARCSERVICE CRITICAL: Service's health state is %s"
                  % health_state)
            if debug:
                print(data)
            sys.exit(2)
    except ET.ParseError as exn:
        print("ARCSERVICE UNKNOWN: Unable to parse respone (%s)" % exn)
        if debug:
            print(data)
        sys.exit(3)
else:
    print("ARCSERVICE CRITICAL: Invalid response from server (%s, %s)" \
          % (response.status, response.reason))
    if debug:
        print(response.read())
    sys.exit(2)
