#!/usr/bin/python3
import json
import re
import subprocess
from subprocess import Popen, PIPE
from jdsu.mts.ScpiAccess import ScpiAccess, EsrError
import time
import datetime
import logging
import os
from os import path
import sys
from collections import defaultdict
from collections import OrderedDict
from decimal import Decimal

#############################################################
def log_ztp_update_info(ztp_info, upd_time):
    upg_logfile_path = "/var/log/user.log"
    upg_logfile = open(upg_logfile_path, "a")
    upd_time_info = "\n"+"OTU ZTP Get Declarative Configuration Info ----  " + upd_time + "\n"
    upg_logfile.writelines([upd_time_info])
    upg_logfile.writelines(ztp_info)
    upg_logfile.writelines("\n")
    upg_logfile.close()
    return True

##############################################################
def get_otu_device_profile():
    grc = 0
    otu_device = []
    try:
        #
        #  Get OTU Name
        #  "OTU:NAME?"
        d_name = otu_p.SendAndReadCommand("OTU:NAME?")
        #
        #  Get OTU Configuration Summary
        #  "OTU:API:CONF:SUMARY?
        dev_otu_sum = ((otu_p.SendAndReadCommand("OTU:API:CONF:SUMARY?")).split(","))
        #
        #  Build JSON compatible OTU Device profile
        otu_device = \
            OrderedDict([("name" , d_name), \
                         ("serial_number", dev_otu_sum[0].replace("\"",'')), \
                         ("type", dev_otu_sum[1].replace("\"",'')), \
                         ("module_type", dev_otu_sum[2].replace("\"",'')), \
                         ("port_count", int(dev_otu_sum[3])), \
                         ("date", int(dev_otu_sum[4])), \
                         ("software_version", dev_otu_sum[5].replace("\"",'')), \
                         ("licences", dev_otu_sum[6].replace("\"",''))])    
    except Exception as error_e:
        grc += 1
    return (otu_device)
 
##############################################################
def get_ipv6_management():
    grc = 0
    otu_ipv6 = []
    try:
        #
        #  Get IPv6 Configuration
        d_ipv6 = ((otu_p.SendAndReadCommand("otu:api:conf:eth:ipv6?")).split(","))
        #  Build JSON compatible OTU Device profile
        ipv6_active = "ON"
        if d_ipv6[0] == ipv6_active:
            v6state = True
        else:
            v6state = False
        st_dhcp = (d_ipv6[1].lower() == "true")
        #
        #  Build IPv6 profile
        otu_ipv6 = \
            OrderedDict([("active" , v6state), \
                         ("dhcp" , st_dhcp), \
                         ("ip", d_ipv6[2].replace("\"",'')), \
                         ("gateway", d_ipv6[3].replace("\"",'')), \
                         ("site", d_ipv6[4].replace("\"",'')), \
                         ("linkip", d_ipv6[6].replace("\"",'')), \
                         ("dns", d_ipv6[5].replace("\"",''))])
    except Exception as error_e:
        grc += 16

    return (otu_ipv6)

##############################################################
def get_ipv4_management():
    grc = 0
    otu_ipv4 = []
    try:
        #
        #  Get IPv4 Configuration
        d_ipv4 = ((otu_p.SendAndReadCommand("otu:api:conf:eth:ipv4?")).split(","))
        #
        #  Build IPv4 profile
        st_dhcp = (d_ipv4[0].lower() == "true")
        otu_ipv4 = \
            OrderedDict([("dhcp" , st_dhcp), \
                         ("ip", d_ipv4[1].replace("\"",'')), \
                         ("subnet_mask", d_ipv4[2].replace("\"",'')), \
                         ("gateway", d_ipv4[5].replace("\"",'')), \
                         ("domain", d_ipv4[4].replace("\"",'')), \
                         ("dns", d_ipv4[3].replace("\"",''))])
    except Exception as error_e:
        grc += 8

    return (otu_ipv4)

#############################################################
def get_traphosts():
    MAX_NUMBER_OF_HOSTS = 5
    #
    #  Get SNMP TrapHost info
    hstnum = 1
    sman_hosts = []
    while (hstnum <= MAX_NUMBER_OF_HOSTS): 
        th_request = "OTU:API:CONF:SNMP:CONF? "+str(hstnum)
        traphost = ((otu_p.SendAndReadCommand(th_request)).split(","))
        if (traphost[3] == None) or (int(traphost[3]) == 0): break
        #  Build JSON compatible OTU Device profile
        host = \
           OrderedDict([("id", int(traphost[0])), \
                        ("ip", traphost[1].replace("\"",'')), \
                        ("community", traphost[2].replace("\"",'')), \
                        ("port", int(traphost[3]))])
        host_x = ((((json.dumps(host,sort_keys=False, indent=0))\
                                .replace(",\n",', ')).replace("{\n",'{')).replace("\n}",'}'))
        #sman_hosts.append(host_x)
        sman_hosts.append(host)
        hstnum += 1
    return (sman_hosts)

#############################################################
def get_snmp_traps_state_info():
    grc = 0
    snmp_state_info = []
    try:
        #
        #  Get SNMP agent state
        #  OTU:API:CONF:SNMP:ENABLE?
        snmp_enable_state = otu_p.SendAndReadCommand("OTU:API:CONF:SNMP:ENABLE?")
        sn_state = (snmp_enable_state.lower() == "true")
        #sys.stdout.write(snmp_state)
        #sys.stdout.write("\n")
        #sys.stdout.flush()
            
        #
        #  Get SNMP Trap IMAlive state/interval
        #  OTU:API:CONF:SNMP:IMAlive?
        iamalive_ind = "disable"
        iamalive_interval = int(otu_p.SendAndReadCommand("OTU:API:CONF:SNMP:IMAlive?"))
        if iamalive_interval > 0: iamalive_ind = "enable"
        #
        #  Build JSON compatible OTU Device profile
        snmp_state_info = \
            OrderedDict([("active" , sn_state), \
                         ("i_am_alive", iamalive_ind), \
                         ("i_am_alive_period_minutes", iamalive_interval), \
                         ("traphosts", get_traphosts())])  
    except Exception as error_e:
        grc += 4

    return (snmp_state_info)

##############################################################
def get_smartotu_credentials():
    grc = 0
    ALIAS_PATH = "/etc/aliases"
    SMT_USER = "smartotu"
    try:
        #
        #  "credentials/cli" will always return
        #  a password of xxxxxxxxxx
        cred_cli = {"password": "xxxxxxxxxx"}
        #
        #  "credntials/smart_otu will return the
        #  smartotu alias configured in the OTU
        smtid = ""
        smt_alias = ""
        if os.path.exists(ALIAS_PATH) and os.path.getsize(ALIAS_PATH) > 0:
            smt_search = open(ALIAS_PATH, "r")
            for line in smt_search:
                if SMT_USER in line:
                    smtid = line.split(":")
                    break
            smt_search.close()
            if smtid != None: smt_alias = smtid[0]
        else:
            grc += 32

    except Exception as error_e:
        grc += 32
    #
    #  Build smartotu alias profile
    cred_smt = OrderedDict([("login", smt_alias), ("password", "xxxxxxxxxx")])
    #
    #  Build JSON compatible credentials tuples
    otu_cred = \
        OrderedDict([("smart_otu", cred_smt), \
                     ("cli", cred_cli)])    
    return (otu_cred)


##############################################################
def get_snmp_agent_configuration():
    grc = 0
    snmp_poll_info = []
    try:
        #
        #  Get SNMP agent state
        #  "otu:api:conf:snmp:agent?"
        snmp_agent_state = str((otu_p.SendAndReadCommand("otu:api:conf:snmp:agent?"))).lower()
        snmp_agnt = (snmp_agent_state == "true")
        #
        #  Get SNMP config run parameters
        #  Pull info from snmpd conf file
        snmp_port = 0
        snmp_comm = ""
        snmp_agent_addr = 0
        community = ""
        #
        #  Search is very context sensitive; searching for line
        #  to match "com2sec readwrite default"
        snmpconf_search = open("/etc/snmp/snmpd.conf", "r")
        for line in snmpconf_search:
            if (line.startswith("com2sec") and ("readwrite" in line) and ("default" in line)):
                snmp_comm = line.split()
                break
        for line in snmpconf_search:
            if line.startswith("agentAddress"):
                snmp_agent_addr = line.split(":")
                break
        snmpconf_search.close()
        #
        #  Get the SNMP community tag
        if snmp_comm != None: community = (snmp_comm[-1]).replace("\n",'')
        #
        #  Get the SNMP port
        if snmp_agent_addr !=None: snmp_port = int(snmp_agent_addr[-1])
        #
        #    
        snmp_poll_info = \
              OrderedDict([("active", snmp_agnt), \
                           ("community", community), \
                           ("port", snmp_port)])
    except Exception as error_e:
        grc += 2

    return (snmp_poll_info)

##############################################################
def handle_ssl_request(ssl_path):
    #
    #  Get ssl file and convert into a JSON ompatible object
    ssl_request = "awk \'NF {sub(/\\r/, \"\"); printf \"%s\\n\",$0;}\' " +ssl_path
    ssl_cmd = subprocess.Popen(ssl_request, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, universal_newlines=True)
    ssl_doc, ssl_err = ssl_cmd.communicate()
    ssl_cmd_rc = ssl_cmd.returncode
    if ssl_cmd_rc != 0:
        ssl_doc = ""
    return (ssl_doc)

##############################################################
def get_security_key_and_certs():
    grc = 0
    keys_certs = []
    #
    #  The following constants contain hard coded
    #  SSL key and SSL certificate paths.
    SSL_KEY_PATH = "/etc/pki/tls/private/smartotu-private.key"
    SSL_CERT_PATH = "/etc/pki/tls/certs/smartotu-certificate.crt"
    SSL_CHAIN_PATH = "/etc/pki/tls/certs/smartotu-certificate-chain.crt"
    #
    #  Get SSL private key and certificate in JSON format
    s_key = handle_ssl_request(SSL_KEY_PATH)
    s_cert = handle_ssl_request(SSL_CERT_PATH)
    s_chain = handle_ssl_request(SSL_CHAIN_PATH)
    keys_certs = OrderedDict([("ssl_private_key", s_key), \
                              ("ssl_cert", s_cert), \
                              ("ssl_cert_chain", s_chain)])
    if (len(s_key) == 0) or (len(s_key) == 0) or (len(s_key) == 0):
        grc += 64    
    return (keys_certs)

##############################################################
def get_otdr_port_config():
    grc = 0
    otdr_ports = []
    MIN_NUMBER_PORTS = 1
    number_of_ports = 1
    #
    #  Get OTU Configuration Summary
    #  "OTU:API:CONF:SUMARY?
    try:
        otu_sum = ((otu_p.SendAndReadCommand("OTU:API:CONF:SUMARY?")).split(","))
        number_of_ports = int(otu_sum[3])
    except Exception:
        pass
    #
    #  Get the list ports with configured links
    #  OTU:LINK:PORTs? xx, zz
    otu_prtlnk_req = "OTU:LINK:PORTS? "\
                     +str(MIN_NUMBER_PORTS)\
                     +","+str(number_of_ports)
    try:
        links = otu_p.SendAndReadCommand(otu_prtlnk_req)
        if len(links) > 0:
            otdr_links = links.split(",")
            for np in otdr_links:
                otdr_req = "OTU:API:PORT:DETAIL? "+str(np)
                otdr_conf = (otu_p.SendAndReadCommand(otdr_req)).split(',')
                sch = (otdr_conf[2].lower() == "true")
                meas_alld = (otdr_conf[3].lower() == "true")
                lwr_thr = (otdr_conf[5].lower() == "true")
                port_link =\
                    OrderedDict([("port", int(otdr_conf[0])), \
                            ("name", otdr_conf[1].replace("\"",'')), \
                            ("scheduled", sch), \
                            ("measurement_allowed", meas_alld), \
                            ("alarm_threshold", int(Decimal(otdr_conf[4]))), \
                            ("lower_threshold", lwr_thr), \
                            ("lower_threshold_db", int(Decimal(otdr_conf[6]))), \
                            ("kml_filepath", otdr_conf[7].replace("\"",''))])
                otdr_link = json.dumps(port_link,sort_keys=False, indent=0)
                otdr_ports.append(port_link)
    except Exception as error_e:
        grc += 128

    return (otdr_ports)


##############################################################
def get_ntp_server_config():
    grc = 0
    MODE_STATIC = "static"
    MODE_DYNAMIC = "dyn"
    ntp_serv_conf = []
    #
    #
    try:
        #  Get NTP Server state
        #  SCPI Command -- otu:api:conf:ntp:enable?
        state_req = "otu:api:conf:ntp:enable ?"
        #print ("\nntp_server state request = ", state_req)
        ntp_state = otu_p.SendAndReadCommand(state_req)
        ntp_act = (ntp_state.lower() == "true")
        #
        #  Get NTP Server Configuration
        #  SCPI Command -- otu:api:conf:ntp:conf ?
        conf_req = "otu:api:conf:ntp:conf ?"
        #print ("\nntp_server config request = ", conf_req)
        ntp_conf = (otu_p.SendAndReadCommand(conf_req)).split(',')
        ntp_dyn = ((ntp_conf[0].lower()) == MODE_DYNAMIC)
        #
        #
        ntp_serv_conf = \
                OrderedDict([("active", ntp_act), \
                             ("dynamic", ntp_dyn), \
                             ("ip", ntp_conf[1].replace("\"",''))])
    except Exception as error_e:
        grc += 32

    return(ntp_serv_conf)

###############################################################
#<><><><><>><><>-------<><><><><><><>-------<><><><><><><>

if __name__ == "__main__":
    #
    #  Open SCPI connections
    otu_p = ScpiAccess("localhost", 1400, 5, "*PASS \"RTU\"\"PASSWORD\"\n")
    #
    #  Global return code
    grc = 0
    otu_base = OrderedDict()    
    #
    #  Get OTU Profile
    otu_base['device'] = get_otu_device_profile()
    otu_base['snmp_polling_agent'] = get_snmp_agent_configuration()
    otu_base['snmp_traps'] = get_snmp_traps_state_info()
    otu_base['ipv4_management'] = get_ipv4_management()
    otu_base['ipv6_management'] = get_ipv6_management()
    otu_base['credentials'] = get_smartotu_credentials()
    otu_base['ntp_server'] = get_ntp_server_config()
    otu_base['https_security'] = get_security_key_and_certs()
    otu_base['otdr_ports'] = get_otdr_port_config()

    sys.stdout.write(json.dumps(otu_base, sort_keys=False, indent=4))
    sys.stdout.write("\n")
    sys.stdout.flush()
    exit (grc)
