#!/usr/bin/python3
# This script is used to write formatted logs to the host's syslog for
# provisioning actions performed by the Day One Provisioning containers.
# It will subscribe to the redis 'dop-logger' stream on start, and listen for
# published messages and log accordingly.
import sys
import os
import json
import redis
import signal
from remote_dop.target_device import TargetDevice, from_ip, from_mac
from remote_dop.util import normalise_host_addr
from remote_dop.log import Log

# Global handle for the redis connection.
redis_port = 6379
if 'REDIS_PORT' in os.environ:
    redis_port = os.environ['REDIS_PORT']

redis_handle = redis.StrictRedis(host="localhost", port=redis_port, db=0)
redis_channel = "dop"

# handle_message parses the json message from redis and actions it.
def handle_message(msg):
    # Strip any hangover quotes.
    msg = msg.decode("utf-8", "ignore").replace("\'", "")
    print(("processing message: {}\n".format(msg)))

    try:
        msg = json.loads(msg)
    except ValueError:
        print("json error parsing message")
        return

    logger = Log(msg['msg_type'])

    normalised_host_addr = normalise_host_addr(msg.get('host_addr', None))

    # Validate depending on type.
    if msg['msg_type'] == "offer":
        if 'mac_addr' not in msg or not normalised_host_addr:
            return
        else:
            logger.mac = msg['mac_addr']
            logger.host = normalised_host_addr

    elif msg['msg_type'] == "offer_vendor":
        if 'mac_addr' not in msg or 'ident' not in msg:
            return
        else:
            logger.mac = msg['mac_addr']
            logger.vendor = msg['ident']

    elif msg['msg_type'] == "fileserved":
        if 'filename' not in msg or 'method' not in msg:
            return
        else:
            logger.file = msg['filename']
            logger.method = msg['method']

            # Pull mac address from storage.
            td = TargetDevice(redis_handle)
            td = from_ip(td, normalised_host_addr)
            logger.mac = td.mac

    elif msg['msg_type'] == "provision":
        if 'mac_addr' not in msg or 'class_name' not in msg:
            return
        else:
            logger.bundle = msg['class_name']
            logger.mac = msg['mac_addr']

    elif msg['msg_type'] == "post_provision_script_start":
        if 'mac_addr' not in msg or 'script' not in msg or 'script_timeout' not in msg:
            return
        else:
            logger.mac = msg['mac_addr']
            logger.script = msg['script']
            logger.timeout = msg['script_timeout']

    elif msg['msg_type'] == "post_provision_script_complete":
        if 'mac_addr' not in msg or 'script' not in msg or 'exitcode' not in msg:
            return
        else:
            logger.mac = msg['mac_addr']
            logger.script = msg['script']
            logger.exitcode = msg['exitcode']

    elif msg['msg_type'] == "post_provision_script_timeout":
        if 'mac_addr' not in msg or 'script' not in msg:
            return
        else:
            logger.mac = msg['mac_addr']
            logger.script = msg['script']
    else:
        return

    logger.print_log()


def sigterm_handler(signum, frame):
    print("closing redis connection")
    redis_handle.connection_pool.disconnect()
    print("done")
    sys.exit(0)


signal.signal(signal.SIGTERM, sigterm_handler)
signal.signal(signal.SIGINT, sigterm_handler)


def main():
    print("connecting to redis")
    p = redis_handle.pubsub(ignore_subscribe_messages=True)
    p.subscribe(redis_channel)
    print(("subscribed to {}, waiting for messages...".format(redis_channel)))
    for message in p.listen():
        handle_message(message['data'])


if __name__ == "__main__":
    main()
