#!/usr/bin/python
# ----------------------------------------------------------------------------
# process_status -- collect process status info
#
# January 2022, Anand Kumar, Akshatha
#
# Copyright (c) 2022 by cisco Systems, Inc.
# All rights reserved.
# ----------------------------------------------------------------------------

import sys
import optparse
import commands
import re
import os
platform_prefix = "/opt/cisco/calvados/bin/vrfch.sh CTRL_VRF"
import json
from datetime import datetime
threshold_value = 98
import signal

SUCCESS = "success"
FAILURE = "failure"
FAILURE_STR = FAILURE+"$"

def handler(signum, frame):
    print(FAILURE_STR)
    sys.exit(0)

def skip_line(line):
    list_data = ["-------", "========", "JID", "unlimited", "PID"]

    for li in list_data:
        if li in line :
            return True
    return False

def parse_admin_process_list(output, metric, vm_type):
    rval = 0
    node_name = "0_RP0"
    n_val = ""

    list_op = output.split("\n")
    for i in range(len(list_op)):
        if skip_line(list_op[i]):
            continue
        li_op = list_op[i].split()
        if len(li_op) == 0:
            continue

        if "K" in li_op[8]:
            n_val = li_op[7] + "K"
        elif "M" in li_op[8]:
            n_val = li_op[7] + "M"
        m_val = li_op[10] + "B"
        rval = get_rvalue(n_val, m_val)
        pid = li_op[0]
        process_name = li_op[9]
        if (rval > 0):
            metric['process_resource_metric']['metric_info'][pid] = {}
            metric['process_resource_metric']['metric_info'][pid]['process_name'] = process_name
            metric['process_resource_metric']['metric_info'][pid]['node_name'] = node_name
            metric['process_resource_metric']['metric_info'][pid]['vm_type'] = vm_type
            metric['process_resource_metric']['metric_info'][pid]['rval'] = rval

def is_xr_process(process_name, node_name):

    cmd = 'sysmgr_show "-o" "-p" "%s" "-n" "all"' %process_name
    status, output = commands.getstatusoutput(cmd)
    if not status:
        if "No such process" in output:
            return False, ""
        val = re.search("PID: \d+", output)
        if val:
            pid = val.group(0).split(":")[-1].strip()
            return True, pid
    return False, ""

def get_rvalue(v1, v2):
    rval = 0
    global threshold_value

    if "M" in v1 and "M" in v2:
        v1 = int(v1.replace("M", ""))
        v2 = float(v2.replace("M", ""))
        if int(v1) > 0 and int(v2) > 0:
            val = float((v1 * 100) / v2)
            if val >= threshold_value:
                rval = val
    elif "K" in v1 and "M" in v2:
        v1 = int(v1.replace("K", ""))
        v2 = float(v2.replace("M", ""))
        if int(v1) > 0 and int(v2) > 0:
            val = float(((v1/1024.0) * 100) / v2)
            if val >= threshold_value:
                rval = val
    elif "K" in v1 and "K" in v2:
        v1 = int(v1.replace("K", ""))
        v2 = float(v2.replace("K", ""))
        if int(v1) > 0 and int(v2) > 0:
            val = float((v1 * 100) /  v2)
            if val >= threshold_value:
                rval = val
    elif "K" in v1 and "B" in v2:
        v1 = int(v1.replace("K", ""))
        v2 = float(v2.replace("B", ""))
        if int(v1) > 0 and int(v2) > 0:
            val = float((v1 * 1024 * 100) /  v2)
            if val >= threshold_value:
                rval = val
    elif "M" in v1 and "B" in v2:
        v1 = int(v1.replace("M", ""))
        v2 = float(v2.replace("B", ""))
        if int(v1) > 0 and int(v2) > 0:
            val = float((v1 * 1024 * 1024 * 100) /  v2)
            if val >= threshold_value:
                rval = val
    return rval

def parse_xr_process_list(output, metric, vm_type):
    rval = 0

    op_li = output.split("\n")
    for i in range(len(op_li)):
        try:
            if skip_line(op_li[i]):
                continue
            if "node:" in op_li[i]:
                node_name = ((op_li[i].split(":")[-1]).strip()).split("node")[-1]
                continue
            op_list = op_li[i].split()
            if op_list:
                process_name = op_list[8]
                pid = op_list[0]
                rval = get_rvalue(op_list[4], op_list[5])
                if (rval > 0) :
                    metric['process_resource_metric']['metric_info'][pid] = {}
                    metric['process_resource_metric']['metric_info'][pid]['process_name'] = process_name
                    metric['process_resource_metric']['metric_info'][pid]['node_name'] = node_name
                    metric['process_resource_metric']['metric_info'][pid]['vm_type'] = vm_type
                    metric['process_resource_metric']['metric_info'][pid]['rval'] = rval
        except:
            pass
 
def extract_process_res_data(data):
    data = data.split("},")
    str = ""

    for i in range(len(data)):
        val = data[i].replace("{", "").replace('"', "").replace("}", "").replace("'", "").split(":")
        pname = val[2].split(",")[0]
        vm_type = val[3].split(",")[0]
        rlimit = val[4].split(",")[0]
        nname = val[-1]
        str += pname + ":" + nname + ":" + rlimit + ":" + vm_type + ":" + "\n"
    return (str)

def func_process_resource():
    metric_name = "process-resource"
    health_state = ""
    health_msg = ""
    output = ""
    metric = {}
    metric_info = "{}"  
    metric['process_resource_metric'] = {}
    metric['process_resource_metric']['metric_info'] = {}

    vm_list = ["xr", "admin"]
    for vm in vm_list:
        if vm == "xr":
            cmd = 'sh_proc_memory_sort "sh_proc_mem_cli   -d -l all"'
        else:
            cmd = "/pkg/bin/install_exec_sysadmin \"source /opt/cisco/calvados/bin/install-functions.sh ;\
                  %s  /opt/cisco/calvados/bin/install-functions.py admin_process_memory \"" %(platform_prefix)
        status, output = commands.getstatusoutput(cmd)
        if status:
            print(FAILURE_STR)
            sys.exit(0)
        if vm == "xr":
            parse_xr_process_list(output, metric, vm)
        else:
            parse_admin_process_list(output, metric, vm)

    if metric['process_resource_metric']['metric_info']:
        health_state = 'Warning'
        health_msg = 'Process found with greater rlimit value'
    else:
        health_state = 'Normal'
        health_msg = 'No Process found with greater rlimit value'
    last_update = datetime.now().strftime('%-d %b %H:%M:%S.%f')
    if(metric['process_resource_metric']['metric_info']):
        metric_info = extract_process_res_data(str(metric['process_resource_metric']['metric_info']))

    output = SUCCESS+"$"+metric_name+"$"+health_state+"$"+health_msg+"$"+last_update+"$"+metric_info+"$"
    print(output)

if __name__ == '__main__':
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(7)
    func_process_resource()

