#!/usr/bin/env python3

import sys
import traceback
import os, re
import logging, logging.handlers
import json
import os.path
import argparse
from utils import utils

import validate
import generateConfig
import pdb
import subprocess

class CLOUD_CONFIG(object):
    """
    Prepare the quired iso to support qcow2 and vmdk based installation.

    """
    LOG_FILE = "./sweInstall.log"

    PID_FILENAME = "./sweInstall.pid"

    def __init__(self):
        sys.excepthook = self.catchall
        self._logger = logging.getLogger(__name__)
        self._setup_logging()
        self._pidfile = CLOUD_CONFIG.PID_FILENAME
        self.data = {}
        self.emsData = {}
        self.oamData = {}
        self.tsbcConfigData = {}

    def run(self):
        """
        Parse the arguments and run the command
        """
        mutexed = utils.mutex(self._pidfile)
        if mutexed:
            self._logger.warning('Another instance of CLOUD_CONFIG Install is running... ')
            #sys.exit(1)

        utils.logStart(self._logger, 'Executing Command : ' + ' '.join(sys.argv))

        # setup CLI parser
        usage = """\tcreateConfigDrive.py -h  | --help |
\t\t\t     --cli |
\t\t\t     --file [FILE] [ --tsbcConfig [TSBCCONFIG] ] |
\t\t\t     --clean"""
        parser = argparse.ArgumentParser(description='CLOUD_CONFIG Qcow2 and VMDK installation preparation.', usage=usage)

        # Add more options if you like
        parser.add_argument("--cli", action='store_true', help="Interactive way to enter sbx install configuration")
        parser.add_argument("--file", type=str, nargs='?', help="Name of json config file")
        parser.add_argument("--tsbcConfig", type=str, nargs='?', help="Name of tsbc json config file")
        parser.add_argument('--clean', action='store_true', help="Clean the output directory with the old files. ")
        args = parser.parse_args()
        if args.tsbcConfig and not args.file:
            self._logger.info("tsbc json config file should always be supplied with sbx json config file.")
            parser.print_help()
            sys.exit(1)
        if not (args.clean or args.cli) and (args.file is None):
            parser.print_help()
            sys.exit(1)
        if (args.file and (args.cli or args.clean)) or (args.cli and (args.clean)):
            self._logger.info("--cli and --file and --clean are mutually exclusive")
            parser.print_help()
            sys.exit(1)
        # Check for required installed packages
        if not utils.cmd_exists("genisoimage"):
            self._logger.error(
                'genisoimage command does not exists. Please install genisoimage to run this script.')
            sys.exit(1)
        if args.clean:
            os.system('rm -rf output/* tmp_conf')
            self._logger.info("Cleaned output Dir....")
            sys.exit(0)
        if args.file is not None:
            print("Using config file : " + args.file)
            loadData = utils.loadConfigData(args.file, self._logger)
            if not loadData:
                self._logger.critical(str(args.file) + ' not found exiting')
                utils.evacuate(CLOUD_CONFIG.PID_FILENAME,1)
            self.data=loadData["sbxConf"]
            self.emsData=loadData["emsConf"]
            self.oamData=loadData["oamConf"]
            self.extraData=loadData.get("extraConf", {})
            self.data["installType"] = int(self.data["installType"])
            self.data["timezone"] = int(self.data["timezone"])
            self.data["tipc"] = int(self.data["tipc"])
            self.data["role"] = int(self.data["role"])
            self.data = json.dumps(self.data)
            self.emsData = json.dumps(self.emsData)
            self.oamData = json.dumps(self.oamData)
            self.extraData = json.dumps(self.extraData)
            if utils.is_json(self.data):
                self.data = json.loads(self.data)
                self.emsData = json.loads(self.emsData)
                self.oamData = json.loads(self.oamData)
                self.extraData = json.loads(self.extraData)
                if self.emsData["emsName"] == "":
                    self.emsData={}
                if self.oamData["oamIp1"] == "":
                    self.oamData={}
                if self.extraData == {}:
                    self.extraData["haFaultDetectionMode"] = "normal"
                dir_path = os.path.dirname(os.path.realpath(__file__))
                conf_dir_path=dir_path + "/conf"
                USER_DATA_FILE = conf_dir_path + "/user-data"
                sshKeyProvided = subprocess.check_output("grep 'ssh-rsa ' " + USER_DATA_FILE + " | wc -l | tr -d '\n'", shell=True).decode('utf-8')
                if sshKeyProvided == "2":
                    self.data["sshKeyReq"] = 0
                    self._logger.info("SSH Public Key provided for 'admin' and 'linuxadmin' user.")
                    # self.data["sshKeyReq"] will be 1 when --cli is used, 
                    # for SSH Public Key for 'admin' and 'linuxadmin' users
                else:
                    self.data["sshKeyReq"] = 2

                if not validate.validateConfig(self.data, self.emsData, self.oamData, self._logger):
                    print("sbx validation is failed")
                    sys.exit(1)

                name_std=generateConfig.genJsonConfig(self.emsData,"CLEAR")
                self._logger.info("Cleared old JSON files : " + name_std )
                if self.oamData and validate.validateOamConfig(self.oamData, self._logger):
                    name_std = generateConfig.genJsonConfig(self.oamData,"OAM")
                    self._logger.info("Created OAM config JSON file : " + name_std + " under output dir")

                # Extra config that are not part of sbx.conf but need to be in userData.json should be populated here
                # All the config passed here will go in extraConfig.json and then merged into final userData.json
                if self.extraData:
                    if self.data["haMode"] == "Nto1" and validate.validateExtraConfig(self.extraData, self._logger):
                        name = generateConfig.genJsonConfig(self.extraData, "EXTRA_CONFIG")
                        self._logger.info("Creating Extra config JSON file : " + name + " under output dir")

            else:
                self._logger.error('Config file %s is not a proper json file' % args.file)
                sys.exit(1)

            if args.tsbcConfig is not None:
                self._logger.info("TSBC configuration has been provided by the user. File : %s" %(args.tsbcConfig))
                # Get the Json content of the file.
                self.tsbcConfigData = utils.loadConfigData(args.tsbcConfig, self._logger)
                if not self.tsbcConfigData:
                    self._logger.critical(str(args.tsbcConfig) + ' file missing or wrongly formatted.')
                    utils.evacuate(CLOUD_CONFIG.PID_FILENAME,1)
                # Validate TSBC configurations.
                if not validate.validateTsbcConfig(self.tsbcConfigData, self.data, self._logger):
                    self._logger.error("Error encountered in validating the Transcode config.")
                    sys.exit(1)
                else:
                    name_std = generateConfig.genJsonConfig(self.tsbcConfigData,"TSBC")
                    self._logger.info("Created Transcode config JSON file : " + name_std + " under output dir")

            if self.data["haMode"] == "1to1" or (self.data["haMode"] == "Nto1" and self.data["role"] == 1):
                if self.emsData and validate.validateEmsConfig(self.emsData, self._logger):
                    self.emsData["vnfcId"]=self.data["ceName"] + "-" +  self.emsData["clusterId"] + "-1"
                    name_std = generateConfig.genJsonConfig(self.emsData,"EMS")
                    self._logger.info("Created EMS config JSON file : " + name_std + " under output dir")
                name = generateConfig.genConfig(self.data,"ACTIVE")
                self._logger.info("Created the active server config drive name : " + name + " under output dir")
            if self.data["installType"] == 2 or (self.data["haMode"] == "Nto1" and self.data["role"] == 2):
                if self.emsData and (self.data["haMode"] == "1to1" or validate.validateEmsConfig(self.emsData,self._logger)):
                    if (self.data["haMode"] == "Nto1" and role == 2):
                        self.emsData["vnfcId"]=self.data["ceName"] + "-" +  self.emsData["clusterId"] + "-1"
                    else:
                        self.emsData["vnfcId"]=self.data["peerCeName"] + "-" +  self.emsData["clusterId"] + "-2"
                    name_std = generateConfig.genJsonConfig(self.emsData,"EMS")
                    self._logger.info("Created EMS config JSON file : " + name_std + " under output dir")
                name_std = generateConfig.genConfig(self.data, "STANDBY")
                self._logger.info("Created the standby server config drive name : " + name_std + " under output dir")

        elif args.cli:
            self.take_input()

    def take_input(self):
        ProductType = utils.prompt(type=int, message = "Enter the Product Type [1 - SBC , 2 - OAM]" , 
                errormessage = "Invalid Value Please re-enter.", isvalid = lambda v: int(v) == 1 or int(v) == 2 )
        if ProductType == 1:
            sbcHaType = utils.prompt(type=int, message = "Enter the SBC HA Mode Type [1 - 1:1 , 2 - N:1]" ,
                    errormessage = "Invalid Type Please re-enter.", isvalid = lambda v: int(v) == 1 or int(v) == 2 )
            if sbcHaType == 1:
                self.data["haMode"]="1to1"
                self.data["installType"] = utils.prompt(type=int, message = "Enter the SBC Install Type [1- Standalone, 2- HA]" ,
                        errormessage = "Invalid Type Please re-enter.",
                        isvalid = lambda v: int(v) == 1 or int(v) == 2)
            else:
                self.data["haMode"]="Nto1"
        else:
            self.data["haMode"]="Nto1"

        if self.data["haMode"] == "Nto1":
            self.data["installType"] = 1
            roleStatus = utils.prompt(type=int, message = "Enter the SBC CE Role [1- Active, 2- Standby]" ,
                  errormessage = "Invalid Type Please re-enter.",
                  isvalid = lambda v: int(v) == 1 or int(v) == 2)
    
        self.data["systemName"] = utils.prompt(type=str, message = "Enter the System Name",
                                 errormessage = "Invalid SystemName. Please re-enter.",
                                 isvalid = lambda v: validate.validateName(v, 26, self._logger))
        self.data["ceName"] = utils.prompt(type=str, message = "Enter the Ce Name",
                             errormessage = "Invalid CeName. Please re-enter.",
                             isvalid = lambda v: validate.validateName(v, 63, self._logger))
        self.data["mgtIpType"] = utils.prompt(type=int, message = "Enter the Type of mgt IP[1- V4, 2- V6, 3- V4+v6]",
                             errormessage = "Invalid type. Please re-enter.",
                             isvalid = lambda v: int(v) == 1 or int(v) == 2 or int(v) == 3)
        if self.data["mgtIpType"] == 1 or self.data["mgtIpType"] == 3:
            self.data["mgtIp"] = utils.prompt(type=str, message = "Enter the V4 mgt IP of the Active server",
                                 errormessage = "Invalid V4 mgt IP. Please re-enter.",
                                 isvalid = lambda v: validate.validateIP(v,"mgtv4"))
            self.data["mgtPrefix"] = utils.prompt(type=str, message = "Enter the V4 mgt Prefix for Active server",
                                 errormessage = "Invalid V4 mgt Prefix. Please re-enter.",
                                 isvalid = lambda v: validate.validatePrefix(v, "V4"))
            self.data["mgtGw"] = utils.prompt(type=str, message = "Enter the V4 mgt GW for the Active server",
                                 errormessage = "Invalid V4 mgt GW. Please re-enter.",
                                 isvalid = lambda v: (validate.validateIP(v,"mgtv4") and validate.validateGW(v,self.data["mgtIp"] + '/' + self.data["mgtPrefix"])))
        if self.data["mgtIpType"] == 2 or self.data["mgtIpType"] ==3:
            self.data["mgtIpV6"] = utils.prompt(type=str, message="Enter the V6 mgt IP of the Active server",
                                              errormessage="Invalid V6 mgt IP. Please re-enter.",
                                              isvalid=lambda v: validate.validateIP(v, "mgtv6"))
            self.data["mgtPrefixV6"] = utils.prompt(type=str, message="Enter the V6 mgt Prefix for Active server",
                                                  errormessage="Invalid V6 mgt Prefix. Please re-enter.",
                                                  isvalid=lambda v: validate.validatePrefix(v, "V6"))
            self.data["mgtGwV6"] = utils.prompt(type=str, message="Enter the V6 mgt GW for the Active server",
                                              errormessage="Invalid V6 mgt GW. Please re-enter.",
                                              isvalid=lambda v: (validate.validateIP(v, "mgtv6") and validate.validateGW(v, self.data["mgtIpV6"] + '/' + self.data["mgtPrefixV6"])))
        if ProductType == 1:
            self.data["isMgt1Conf"] = utils.prompt(type=int, message = "Do you want to configure second management port (mgt1) [1- Yes, 2-No ]",
                    errormessage = "Invalid option, please try-again", isvalid = lambda v: int(v) == 1 or int(v) == 2)
        else:
            self.data["isMgt1Conf"] = 2
        if self.data["isMgt1Conf"] == 1:
            self.data["mgt1IpType"] = utils.prompt(type=int, message = "Enter the Type of mgt1 IP[1- V4, 2- V6, 3- V4+v6]",
                                 errormessage = "Invalid type. Please re-enter.",
                                 isvalid = lambda v: int(v) == 1 or int(v) == 2 or int(v) == 3)
            if self.data["mgt1IpType"] == 1 or self.data["mgt1IpType"] == 3:
                self.data["mgt1Ip"] = utils.prompt(type=str, message = "Enter the V4 mgt1 IP of the Active server",
                                     errormessage = "Invalid V4 mgt1 IP. Please re-enter.",
                                     isvalid = lambda v: validate.validateIP(v,"mgtv4"))
                self.data["mgt1Prefix"] = utils.prompt(type=str, message = "Enter the V4 mgt1 Prefix for Active server",
                                     errormessage = "Invalid V4 mgt1 Prefix. Please re-enter.",
                                     isvalid = lambda v: validate.validatePrefix(v, "V4"))
                self.data["mgt1Gw"] = utils.prompt(type=str, message = "Enter the V4 mgt1 GW for the Active server",
                                     errormessage = "Invalid V4 mgt1 GW. Please re-enter.",
                                     isvalid = lambda v:(validate.validateIP(v,"mgtv4") and validate.validateGW(v,self.data["mgt1Ip"] +
                                             '/' + self.data["mgt1Prefix"])))
            if self.data["mgt1IpType"] == 2 or self.data["mgt1IpType"] ==3:
                self.data["mgt1IpV6"] = utils.prompt(type=str, message="Enter the V6 mgt1 IP of the Active server",
                                                  errormessage="Invalid V6 mgt1 IP. Please re-enter.", isvalid=lambda v:
                                                  validate.validateIP(v, "mgtv6"))
                self.data["mgt1PrefixV6"] = utils.prompt(type=str, message="Enter the V6 mgt1 Prefix for Active server",
                                                      errormessage="Invalid V6 mgt1 Prefix. Please re-enter.",
                                                      isvalid=lambda v: validate.validatePrefix(v, "V6"))
                self.data["mgt1GwV6"] = utils.prompt(type=str, message="Enter the V6 mgt1 GW for the Active server",
                                                  errormessage="Invalid V6 mgt1 GW. Please re-enter.",
                                                  isvalid=lambda v: (validate.validateIP(v, "mgtv6") and validate.validateGW(v, self.data["mgt1IpV6"] + '/' + self.data["mgt1PrefixV6"])))
        if self.data["installType"] == 2:
            self.data["peerCeName"] = utils.prompt(type=str, message = "Enter the Peer Ce Name",
                                     errormessage = "Invalid Peer Ce Name. Please re-enter.",
                                     isvalid = lambda v: validate.validateName(v, 63, self._logger))
            self.data["peerMgtIpType"] = utils.prompt(type=int, message="Enter the Type of Peer mgt IP[1-V4, 2-V6, 3-V4+V6]",
                                      errormessage="Invalid type. Please re-enter.",
                                      isvalid=lambda v: int(v) == 1 or int(v) == 2 or int(v) == 3)
            if self.data["peerMgtIpType"] == 1 or self.data["peerMgtIpType"] == 3:
                self.data["peerMgtIp"] = utils.prompt(type=str, message = "Enter the V4 mgt IP of the Standby server",
                                 errormessage = "Invalid peer V4 mgt IP. Please re-enter.",
                                 isvalid = lambda v: validate.validateIP(v,"mgtv4"))
                self.data["peerMgtPrefix"] = utils.prompt(type=str, message = "Enter the V4 mgt Prefix for Standby server",
                                 errormessage = "Invalid peer V4 mgt prefix. Please re-enter.",
                                 isvalid = lambda v: validate.validatePrefix(v, "V4"))
                self.data["peerMgtGw"] = utils.prompt(type=str, message = "Enter the V4 mgt GW for the Standby server",
                                 errormessage = "Invalid peer V4 mgt GW. Please re-enter.",
                                 isvalid = lambda v: (validate.validateIP(v,"mgtv4") and validate.validateGW(v,self.data["peerMgtIp"] + '/' + self.data["peerMgtPrefix"])))
            if self.data["peerMgtIpType"] == 2 or self.data["peerMgtIpType"] == 3:
                self.data["peerMgtIpV6"] = utils.prompt(type=str, message="Enter the V6 mgt IP of the Standby server",
                                                      errormessage="Invalid peer V6 mgt IP. Please re-enter.",
                                                      isvalid=lambda v: validate.validateIP(v, "mgtv6"))
                self.data["peerMgtPrefixV6"] = utils.prompt(type=str, message="Enter the V6 mgt Prefix for Standby server",
                                                          errormessage="Invalid peer V6 mgt prefix. Please re-enter.",
                                                          isvalid=lambda v: validate.validatePrefix(v, "V6"))
                self.data["peerMgtGwV6"] = utils.prompt(type=str, message="Enter the V6 mgt GW for the Standby server",
                                                      errormessage="Invalid peer V6 mgt GW. Please re-enter.",
                                                      isvalid=lambda v: (validate.validateIP(v, "mgtv6") and validate.validateGW(v, self.data["peerMgtIpV6"] + '/' + self.data["peerMgtPrefixV6"])))
            if self.data["isMgt1Conf"] == 1:
                self.data["peerMgt1IpType"] = utils.prompt(type=int, message="Enter the Type of Peer mgt1 IP[1-V4, 2-V6, 3-V4+V6]",
                        errormessage="Invalid type. Please re-enter.", 
                        isvalid=lambda v: int(v) == 1 or int(v) == 2 or int(v) == 3)
                if self.data["peerMgt1IpType"] == 1 or self.data["peerMgt1IpType"] == 3:
                    self.data["peerMgt1Ip"] = utils.prompt(type=str, message = "Enter the V4 mgt1 IP of the Standby server",
                            errormessage = "Invalid peer V4 mgt1 IP. Please re-enter.", 
                            isvalid = lambda v: validate.validateIP(v,"mgtv4"))
                    self.data["peerMgt1Prefix"] = utils.prompt(type=str, message = "Enter the V4 mgt1 Prefix for Standby server", 
                            errormessage = "Invalid peer V4 mgt1 prefix. Please re-enter.", 
                            isvalid = lambda v: validate.validatePrefix(v, "V4"))
                    self.data["peerMgt1Gw"] = utils.prompt(type=str, message = "Enter the V4 mgt1 GW for the Standby server", 
                            errormessage = "Invalid peer V4 mgt1 GW. Please re-enter.", 
                            isvalid = lambda v: (validate.validateIP(v,"mgtv4") and validate.validateGW(v,self.data["peerMgt1Ip"] + '/' + self.data["peerMgt1Prefix"])))
                if self.data["peerMgt1IpType"] == 2 or self.data["peerMgt1IpType"] == 3:
                    self.data["peerMgt1IpV6"] = utils.prompt(type=str, message="Enter the V6 mgt1 IP of the Standby server",
                            errormessage="Invalid peer V6 mgt1 IP. Please re-enter.",
                            isvalid=lambda v: validate.validateIP(v, "mgtv6"))
                    self.data["peerMgt1PrefixV6"] = utils.prompt(type=str, message="Enter the V6 mgt1 Prefix for Standby server",
                            errormessage="Invalid peer V6 mgt1 prefix. Please re-enter.",
                            isvalid=lambda v: validate.validatePrefix(v, "V6"))
                    self.data["peerMgt1GwV6"] = utils.prompt(type=str, message="Enter the V6 mgt1 GW for the Standby server",
                            errormessage="Invalid peer V6 mgt1 GW. Please re-enter.",
                            isvalid=lambda v:(validate.validateIP(v,"mgtv6") and validate.validateGW(v, self.data["peerMgt1IpV6"] + '/' +                                                           self.data["peerMgt1PrefixV6"])))
            self.data["haIp"] = utils.prompt(type=str, message = "Enter the ha IP for Active server[V4]",
			                                errormessage = "Invalid ha IP(V4). Please re-enter.",
			                                isvalid = lambda v: validate.validateIP(v,"ha"))
            self.data["haPrefix"] = utils.prompt(type=str, message="Enter the ha Prefix for Active server",
                                            errormessage="Invalid ha IP(V4). Please re-enter.",
                                            isvalid=lambda v: validate.validatePrefix(v, "V4"))
            self.data["peerHaIp"] = utils.prompt(type=str, message = "Enter the ha IP for Standby server[V4]",
                             errormessage = "Invalid peer ha IP(V4), should be in same subnet as used in active. Please re-enter.",
                             isvalid = lambda v: validate.validateIP(v,"ha") and validate.validateGW(v,self.data["haIp"] + '/' + self.data["haPrefix"] ))
            self.data["haMode"]="1to1"
            self.data["rgIp"]=self.data["peerHaIp"]

        else:
            if self.data["haMode"] == "Nto1":
                role = "Active" if roleStatus == 1  else "Standby"
                self.data["haIp"] = utils.prompt(type=str, message = "Enter the ha IP for " + role + " server[V4]",
                        errormessage = "Invalid ha IP(V4). Please re-enter.",
                        isvalid = lambda v: validate.validateIP(v,"ha"))
                self.data["haPrefix"] = utils.prompt(type=str, message="Enter the ha Prefix for " + role + " server",
                                                errormessage="Invalid ha IP(V4). Please re-enter.",
                                                isvalid=lambda v: validate.validatePrefix(v, "V4"))
                self.data["rgIp"] = utils.prompt(type=str, message = "Enter the V4 RG IP address one of the members of SBC Redundancy Group(RG). (Note - Provide 169.254.88.1 for the first node of RG)",
                        errormessage = "Invalid ha IP(V4). Please re-enter.",
                        isvalid = lambda v: validate.validateIP(v,"ha"))

                faultDetectionMode = utils.prompt(type=int, message="Enter HA fault detection mode[1- Normal, 2- Sensitive]",
                                      errormessage="Invalid type. Please re-enter.",
                                      isvalid=lambda v: int(v) == 1 or int(v) == 2)
                self.extraData = {}
                if faultDetectionMode == 2:
                    self.extraData["haFaultDetectionMode"] = "sensitive"
                else:
                    self.extraData["haFaultDetectionMode"] = "normal"
            else:
                self.data["haMode"]="1to1"
                check = utils.prompt(type=int, message = "Do you want to configure HA IP or set default ip (169.254.99.1) [1-Configure, 2-Set Default ]",
                        errormessage = "Invalid option, please try-again", isvalid = lambda v: int(v) == 1 or int(v) == 2)
                if check == 1:
                    self.data["haIp"] = utils.prompt(type=str, message = "Enter the HA IP for Active server[V4]",
                            errormessage = "Invalid HA IP(V4). Please re-enter.", isvalid = lambda v: validate.validateIP(v,"ha"))
                else:
                    self.data["haIp"] = "169.254.99.1"
                self.data["rgIp"]=self.data["haIp"]
            self.data["peerCeName"] = "none"
        self.data["ntpIp"] = utils.prompt(type=str, message = "Enter the ntp IP for the server",
                             errormessage = "Invalid ntp IP . Please re-enter.",
                             isvalid = lambda v: validate.validateIP(v,"ntp"))
        self.data["timezone"] = utils.prompt(type=int, message = "Enter the Timezone ID [Check README for the ID(1-595)]",
                             errormessage = "Invalid timezone. Please re-enter.",
                             isvalid = lambda v: int(v) > 0 and int(v) < 596)
        self.data["sbctype"] = utils.prompt(type=str, message = "Enter the SBC Type[isbc,ssbc,msbc,mrfp,slb]",
                             errormessage = "Invalid SBC Type. Please re-enter.",
                             isvalid = lambda v: validate.validateSbcType(v))
        if ProductType == 2:
            self.data["personality"] = 4 #For OAM, personality parameter has to be 4
        else:
            self.data["personality"] = 1

        if self.data["haMode"] == "1to1":
            self.data["tipc"] = utils.prompt(type=int, message = "Enter the TIPC id for the system",
                    errormessage = "Invalid TIPC id. Please re-enter.",
                    isvalid = lambda v: int(v) > 1025 and int(v) < 4095)
        self.data["sshKeyReq"] = utils.prompt(type=int, message = "Do you want SSH Public Key based authentication for 'admin' and 'linuxadmin' user [1- Yes, 2-No ]",
                errormessage = "Invalid Value Please re-enter.",
                isvalid = lambda v: int(v) == 1 or int(v) == 2)
        if self.data["sshKeyReq"] == 1:
            self.data["adminSshKey"] = utils.prompt(type=str, message = "Enter SSH Public Key for 'admin' user",
                    errormessage = "Invalid SSH Public Key. Please re-enter.",
                    isvalid = lambda v: v[0:8] == "ssh-rsa ")
            self.data["linuxadminSshKey"] = utils.prompt(type=str, message = "Enter SSH Public Key for 'linuxadmin' user",
                    errormessage = "Invalid SSH Public Key. Please re-enter.",
                    isvalid = lambda v: v[0:8] == "ssh-rsa ")
        emsSettings = utils.prompt(type=int, message = "Do you want to enter EMS settings [1- Yes, 2-No ]",  
                errormessage = "Invalid Value Please re-enter.",
                isvalid = lambda v: int(v) == 1 or int(v) == 2)
        if emsSettings == 1:
            self.emsData["emsName"] = utils.prompt(type=str, message = "Enter EMS User Name",
                    errormessage = "Invalid EMS Name. Please re-enter.",
                    isvalid = lambda v: validate.validateName(v, 26, self._logger))
            self.emsData["emsPass"] = utils.promptPassword(type=str, message = "Enter EMS Password =",
                    errormessage = "EMS Password does not match. Please re-enter.",
                    isvalid = lambda v: validate.validatePassword(v, 26, self._logger))
            self.emsData["emsIp1"] = utils.prompt(type=str, message = "Enter EMS IP 1",
                    errormessage = "Invalid ems IP. Please re-enter.",
                    isvalid = lambda v: validate.validateIP(v,"ems"))
            choice = utils.prompt(type=int, message = "Do you want to enter 2nd EMS IP[1- Yes, 2-No ]",  
                errormessage = "Invalid Value Please re-enter.",
                isvalid = lambda v: int(v) == 1 or int(v) == 2)
            if choice == 1:
                self.emsData["emsIp2"] = utils.prompt(type=str, message = "Enter EMS IP 2",
                        errormessage = "Invalid ems IP. Please re-enter.",
                        isvalid = lambda v: validate.validateIP(v,"ems"))
            else:
                self.emsData["emsIp2"]=""
            self.emsData["clusterId"] = utils.prompt(type=str, message = "Cluster/VNF ID value from EMS Cluster Mgmt.",
                    errormessage = "Invalid Cluster ID. Please re-enter.",
                    isvalid = lambda v: validate.validateId(v, 63, self._logger))
            locVar = utils.prompt(type=int, message = "Download Configuration from EMS [1- True, 2-False ]",  
                errormessage = "Invalid Value Please re-enter.",
                isvalid = lambda v: int(v) == 1 or int(v) == 2)
            if locVar == 1:
                self.emsData["downloadEmsConfig"]="True"
            else:
                self.emsData["downloadEmsConfig"]="False"

        #Enter EMA config
        enableEmaREST = utils.prompt(type=int, message = "Enable or Disable EMA REST module? [1- enable, 2- disable]" ,
                  errormessage = "Invalid Type Please re-enter.",
                  isvalid = lambda v: int(v) == 1 or int(v) == 2)
        if (enableEmaREST == 1):
            self.data["enableREST"]="enabled"
        else:
            self.data["enableREST"]="disabled"

        enableEmaCore = utils.prompt(type=int, message = "Enable or Disable EMA Core module? [1- enable, 2- disable]" ,
                  errormessage = "Invalid Type Please re-enter.",
                  isvalid = lambda v: int(v) == 1 or int(v) == 2)
        if (enableEmaCore == 1):
            self.data["enableCoreEMA"]="enabled"
        else:
            self.data["enableCoreEMA"]="disabled"

        enableEmaTS = utils.prompt(type=int, message = "Enable or Disable EMA Troubleshooting module? [1- enable, 2- disable]" ,
                  errormessage = "Invalid Type Please re-enter.",
                  isvalid = lambda v: int(v) == 1 or int(v) == 2)
        if (enableEmaTS == 1):
            self.data["enableTS"]="enabled"
        else:
            self.data["enableTS"]="disabled"
        #EMA config ends

        if ProductType == 1:
            oamSettings = utils.prompt(type=int, message = "Do you want to enter OAM settings [1- Yes, 2-No ]",  
                    errormessage = "Invalid Type Please re-enter.",
                    isvalid = lambda v: int(v) == 1 or int(v) == 2)
            if oamSettings == 1:
                self.oamData["oamIp1"] = utils.prompt(type=str, message = "Enter OAM IP 1",
                        errormessage = "Invalid oam IP(V4). Please re-enter.",
                        isvalid = lambda v: validate.validateIP(v,"ha"))

                self.oamData["oamIp2"] = utils.prompt(type=str, message = "Enter OAM IP 2",
                        errormessage = "Invalid oam IP(V4). Please re-enter.",
                        isvalid = lambda v: validate.validateIP(v,"ha"))
    
            # Enter TSBC Config
            tsbcSettings = utils.prompt(type=int, message = "Do you want to enter TSBC settings [1- Yes, 2-No ]",  errormessage = "Invalid Type. Please re-enter.", isvalid = lambda v: int(v) == 1 or int(v) == 2)
            if tsbcSettings == 1:
                self.tsbcConfigData = {"TranscodeConfig":{}}
                useGpu = utils.prompt(type=int, message = "Use GPU for transcoding [1 - Yes, 2 - No]", errormessage = "Invalid Option. Please re-enter.", isvalid = lambda v: int(v) == 1 or int(v) == 2)
                if useGpu == 1:
                    self.tsbcConfigData["TranscodeConfig"]["gpu"] = "true"
    
                    listOfAllowedCodecs = ['G729', 'G722', 'EVRCB', 'AMRWB', 'EVRC', 
                            'AMR', 'G723', 'G726', 'G7221', 'ILBC', 'OPUS', 
                            'SILK_8', 'SILK_16', 'EVS', 'T38', 'G711', 'G7112G711']
    
                    self.tsbcConfigData["TranscodeConfig"]["callmix"] = {}
                    sumOfCodecPercentage = 0
                    for codec in listOfAllowedCodecs:
                        self.tsbcConfigData["TranscodeConfig"]["callmix"][codec] = utils.prompt(type=float, message = "Enter " + codec + " Percentage", errormessage = "Invalid Value. Please enter a value 0<=x<=100.", isvalid = lambda v: float(v) <=100 and float(v) >=0)
                        sumOfCodecPercentage += self.tsbcConfigData["TranscodeConfig"]["callmix"][codec]
                        if sumOfCodecPercentage == 100:
                            self._logger.info("Sum of Codec Percentage sums up to 100. Continuing further.")
                            break
                        elif sumOfCodecPercentage > 100:
                            self._logger.error("Sum of Codec Percentge cannot be greater than 100%.")
                            sys.exit(1)
    
                    if self.data["sbctype"] == "isbc":
                        enterTonePercentage = utils.prompt(type=int, message = "Do you want to enter Tone Percentage [1- Yes, 2-No ]",  errormessage = "Invalid Type.  Please re-enter.", isvalid = lambda v: int(v) == 1 or int(v) == 2)
                        if enterTonePercentage == 1:
                            self.tsbcConfigData["TranscodeConfig"]["tone"] = utils.prompt(type=int, message = "Enter Tone Percentage", errormessage = "Invalid Value. Please enter a value 0<=x<=100.", isvalid = lambda v: int(v) <=100 and int(v) >=0)
                        else:
                            self.tsbcConfigData["TranscodeConfig"]["tone"] = 0
                    else:
                        self.tsbcConfigData["TranscodeConfig"]["tone"] = 0
    
                    if not validate.validateTsbcConfig(self.tsbcConfigData, self.data, self._logger):
                        self._logger.error("Error encountered in validating the Transcode config.")
                        sys.exit(1)
                else:
                    self.tsbcConfigData["TranscodeConfig"]["gpu"] = "false"
            # TSBC Config ends
        if not validate.validateAllIps(self.data,self.emsData,self.oamData, self._logger):
            sys.exit(1)
        #default Oam Config for OAM config drive
        if ProductType == 2:
            oamSettings = 1
            if roleStatus ==1:
                self.oamData["oamIp1"] = self.data["haIp"]
                self.oamData["oamIp2"] = self.data["rgIp"]
            else:
                self.oamData["oamIp1"] = self.data["rgIp"]
                self.oamData["oamIp2"] = self.data["haIp"]

        name=generateConfig.genJsonConfig(self.emsData,"CLEAR")
        self._logger.info("Cleared old JSON files : " + name )

        # Extra config that are not part of sbx.conf but need to be in userData.json should be populated here
        # All the config passed here will go in extraConfig.json and then merged into final userData.json
        if self.data["haMode"] == "Nto1":
            name = generateConfig.genJsonConfig(self.extraData, "EXTRA_CONFIG")
            self._logger.info("Creating Extra config JSON file : " + name + " under output dir")

        if oamSettings == 1:
            name = generateConfig.genJsonConfig(self.oamData,"OAM")
            self._logger.info("Created OAM config JSON file : " + name + " under output dir")
        if ProductType == 1:
            if tsbcSettings == 1:
                name_std = generateConfig.genJsonConfig(self.tsbcConfigData,"TSBC")
                self._logger.info("Created Transcode config JSON file : " + name_std + " under output dir")
        if self.data["haMode"] == "1to1" or (self.data["haMode"] == "Nto1" and roleStatus == 1):
            if emsSettings == 1:
                self.emsData["vnfcId"]=self.data["ceName"] + "-" +  self.emsData["clusterId"] + "-1"
                name = generateConfig.genJsonConfig(self.emsData,"EMS")
                self._logger.info("Created EMS config JSON file : " + name + " under output dir")
            name = generateConfig.genConfig(self.data, "ACTIVE")
            self._logger.info("Created the active server config drive name : " + name + " under output dir")
        if self.data["installType"] == 2 or (self.data["haMode"] == "Nto1" and roleStatus == 2):
            if emsSettings == 1:
                #ProductType =1 for SBC and 2 for OAM, in OAM VNFC id should tag with -2
                if (self.data["haMode"] == "Nto1" and roleStatus == 2):
                    if (ProductType == 1):
                        self.emsData["vnfcId"]=self.data["ceName"] + "-" +  self.emsData["clusterId"] + "-1"
                    else:
                        self.emsData["vnfcId"]=self.data["ceName"] + "-" +  self.emsData["clusterId"] + "-2"
                else:
                    self.emsData["vnfcId"]=self.data["peerCeName"] + "-" +  self.emsData["clusterId"] + "-2"
                name = generateConfig.genJsonConfig(self.emsData,"EMS")
                self._logger.info("Created EMS config JSON file : " + name + " under output dir")
            name_std = generateConfig.genConfig(self.data, "STANDBY")
            self._logger.info("Created the standby server config drive name : " + name_std + " under output dir")


    def catchall(self,type, value, tb):
        """
        Param:  Standard Python inputs to exception handler.
        Desc: Routine to supplant the normal exception processing so that we can log
        fatal exceptions not caught by the code.
        Return: None.
        """
        utils.killPid(self._pidfile)
        self._logger.critical('Uncaught exception: {0}'.format(str(value)))
        self._logger.critical('Type: {0}'.format(str(type)))
        self._logger.critical('Traceback: {0}'.format(traceback.format_tb(tb)))

    def _setup_logging(self):
        """
        Setup the logger
        """
        # create log directory if not exist
        if not os.path.exists(os.path.dirname(CLOUD_CONFIG.LOG_FILE)):
            try:
                os.makedirs(os.path.dirname(CLOUD_CONFIG.LOG_FILE))
            except OSError as exc:  # Guard against race condition
                print("ERROR: Failed to create directory: %s" % str(exc))
                exit(1)
        log_args = {'class': self.__class__}
        # logging.basicConfig()

        self._logger.setLevel(logging.INFO)
        handler = logging.handlers.RotatingFileHandler(CLOUD_CONFIG.LOG_FILE, mode='w', maxBytes=1000000, backupCount=10,
                                                       encoding=None, delay=0)
        formatter = '%(asctime)s %(levelname)-8s %(class)s [%(filename)s:%(lineno)s - %(funcName)10s()] %(message)s'
        file_formatter = logging.Formatter(formatter)

        handler.setFormatter(file_formatter)
        self._logger.addHandler(handler)

        self._logger = logging.LoggerAdapter(self._logger, log_args)

if __name__ == '__main__':
    logging.basicConfig()
    CLOUD_CONFIG().run()
    utils.evacuate(CLOUD_CONFIG.PID_FILENAME, 0)
