aklyuk / zabbix-emc-unity

Python script for monitoring EMC Unity strages
23 stars 22 forks source link

Processing with zabbix_sender ok but sending to Server Zabbix ko #22

Open Neo914 opened 4 months ago

Neo914 commented 4 months ago

Hello I have a problem of the same type I have a Zabbix server proxy and a Zabbix main server, the latter monitoring the Zabbix proxy. From the Zabbix proxy I have the Python script that is run to explore my Dell Unity and upload all the discovery elements in my Zabbix but I have a problem to remount the elements in Zabbix HMI.

root@deb:/usr/lib/zabbix/externalscripts# python3 unity_get_state.py --api_ip ... --api_port 443 --api_user ** --api_password * --storage_name DellEMC_unity --discovery 1 root@deb:/usr/lib/zabbix/externalscripts# python3 unity_get_state.py --api_ip ...* --api_port 443 --api_user --api_password ***** --storage_name DellEMC_unity --status 1 root@deb:/usr/lib/zabbix/externalscripts#

in the log unity_state.log I don't have an error

2024-07-09 11:41:07,751 - unity_logger - INFO - Connection established 2024-07-09 11:41:12,247 - unity_logger - INFO - Logout successful 2024-07-09 11:41:35,916 - unity_logger - INFO - Connection established 2024-07-09 11:41:40,324 - unity_logger - INFO - Logout successful 2024-07-09 11:41:50,849 - unity_logger - INFO - Connection established 2024-07-09 11:41:55,705 - unity_logger - INFO - Logout successful

on the other hand when I do the tests manually

root@deb:/usr/bin# zabbix_sender -z server_zabbix -p 10051 -s "DellEMC_unity" -k "health.disk.[{#ID}] " -o 4 -vv zabbix_sender [4022880]: DEBUG: In connect_to_server() [server_zabbix]:10051 [timeout:60, connection timeout:3] zabbix_sender [4022880]: DEBUG: In is_ip4() ip:'...**' zabbix_sender [4022880]: DEBUG: End of is_ip4():SUCCEED zabbix_sender [4022880]: DEBUG: answer [{"response":"success","info":"processed: 0; failed: 1; total: 1; seconds spent: 0.000019"}] Response from "server_zabbix:10051": "processed: 0; failed: 1; total: 1; seconds spent: 0.000019" sent: 1; skipped: 0; total: 1 root@deb:/usr/bin#

Can you help me figure out what's wrong?

Neo914 commented 4 months ago

For information I use the EMC Unity REST-API v3 template

zabbix_export: version: '6.0' date: '2024-07-09T13:02:02Z' groups:


and the script unity_get_state.py

!/usr/bin/python3

-- coding: utf-8 --

import os import time import argparse import sys import json import subprocess import logging import logging.handlers import requests import urllib3

urllib3.disable_warnings()

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

Create log-object

LOG_FILENAME = "/tmp/unity_state.log" unity_logger = logging.getLogger("unity_logger") unity_logger.setLevel(logging.INFO)

Set handler

unity_handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=1024*1024, backupCount=5) unity_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

Set formatter for handler

unity_handler.setFormatter(unity_formatter)

Add handler to log-object

unity_logger.addHandler(unity_handler)

def api_connect(api_user, api_password, api_ip, api_port): api_login_url = "https://{0}:{1}/api/types/loginSessionInfo".format(api_ip, api_port) session_unity = requests.Session() session_unity.auth = (api_user, api_password) session_unity.headers = {'X-EMC-REST-CLIENT': 'true', 'Content-type': 'application/json', 'Accept': 'application/json'}

    try:
            login = session_unity.get(api_login_url, verify=False)
    except Exception as oops:
            unity_logger.error("Connection Error Occurs: {0}".format(oops))
            sys.exit("50")

    if login.status_code != 200:
            unity_logger.error("Connection Return Code = {0}".format(login.status_code))
            sys.exit("60")
    elif login.text.find("isPasswordChangeRequired") >= 0: # If i can find string "isPasswordChangeRequired" therefore login is successful
            unity_logger.info("Connection established")
            return session_unity
    else:
            unity_logger.error("Login Something went wrong")
            sys.exit("70")

def api_logout(api_ip, session_unity): api_logout_url = "https://{0}/api/types/loginSessionInfo/action/logout".format(api_ip) session_unity.headers = {'Content-type': 'application/json', 'Accept': 'application/json'}

    try:
            logout = session_unity.post(api_logout_url, verify=False)
    except Exception as oops:
            unity_logger.error("Logout Error Occurs: {0}".format(oops))
            sys.exit("150")

    if logout.status_code != 200:
            unity_logger.error("Logout status = {0}".format(logout.status_code))
            sys.exit("160")
    elif logout.text.find("Logout successful") >= 0:
            unity_logger.info("Logout successful")
    else:
            unity_logger.error("Logout Something went wrong")
            sys.exit("170")

def convert_to_zabbix_json(data): output = json.dumps({"data": data}, indent = None, separators = (',',': ')) return output

def send_data_to_zabbix(zabbix_data, storage_name): sender_command = "/usr/bin/zabbix_sender" config_path = "/etc/zabbix/zabbix_agentd.conf" time_of_create_file = int(time.time()) tempfile = "/tmp/{0}{1}.tmp".format(storage_name, time_of_create_file)

    with open(temp_file, "w") as f:
            f.write("")
            f.write("\n".join(zabbix_data))

    send_code = subprocess.call([sender_command, "-vv", "-c", config_path, "-s", storage_name, "-T", "-i", temp_file], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    os.remove(temp_file)
    return send_code

def discovering_resources(api_user, api_password, api_ip, api_port, storage_name, list_resources): api_session = api_connect(api_user, api_password, api_ip, api_port)

    xer = []
    try:
            for resource in list_resources:
                    resource_url = "https://{0}:{1}/api/types/{2}/instances?fields=name".format(api_ip, api_port, resource)
                    resource_info = api_session.get(resource_url, verify=False)
                    resource_info = json.loads(resource_info.content.decode('utf8'))

                    discovered_resource = []
                    for one_object in resource_info['entries']:
                            if ['lun', 'pool'].count(resource) == 1:
                                    one_object_list = {}
                                    one_object_list["{#ID}"] = one_object['content']['id']
                                    one_object_list["{#NAME}"] = one_object['content']['name'].replace(' ', '_')
                                    discovered_resource.append(one_object_list)
                            else:
                                    one_object_list = {}
                                    one_object_list["{#ID}"] = one_object['content']['id']
                                    discovered_resource.append(one_object_list)
                    converted_resource = convert_to_zabbix_json(discovered_resource)
                    timestampnow = int(time.time())
                    xer.append("%s %s %s %s" % (storage_name, resource, timestampnow, converted_resource))
    except Exception as oops:
            unity_logger.error("Error occurs in discovering")
            sys.exit("1000")

    api_session_logout = api_logout(api_ip, api_session)
    return send_data_to_zabbix(xer, storage_name)

def get_status_resources(api_user, api_password, api_ip, api_port, storage_name, list_resources): api_session = api_connect(api_user, api_password, api_ip, api_port)

    state_resources = [] # This list will persist state of resources (pool, lun, fcPort, battery, diks, ...) on zabbix format
    try:
            for resource in list_resources:
                    # Create different URI for different resources
                    if ['pool'].count(resource) == 1:
                            resource_url = "https://{0}:{1}/api/types/{2}/instances?fields=name,health,sizeTotal,sizeUsed,sizeSubscribed".format(api_ip, api_port, resource)
                    elif ['lun'].count(resource) == 1:
                            resource_url = "https://{0}:{1}/api/types/{2}/instances?fields=name,health,sizeTotal,sizeAllocated".format(api_ip, api_port, resource)
                    else:
                            resource_url = "https://{0}:{1}/api/types/{2}/instances?fields=name,health,needsReplacement".format(api_ip, api_port, resource)

                    # Get info about one resource
                    resource_info = api_session.get(resource_url, verify=False)
                    resource_info = json.loads(resource_info.content.decode('utf8'))
                    timestampnow = int(time.time())

                    if ['ethernetPort', 'fcPort', 'sasPort'].count(resource) == 1:
                            for one_object in resource_info['entries']:
                                    key_health = "health.{0}.[{1}]".format(resource, one_object['content']['id'].replace(' ', '_'))
                                    key_status = "link.{0}.[{1}]".format(resource, one_object['content']['id'].replace(' ', '_'))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_health, timestampnow, one_object['content']['health']['value']))

                                    # Get state of interfaces from description
                                    descriptionIds = str(one_object['content']['health']['descriptionIds'][0]) # Convert description to string
                                    if descriptionIds.find("LINK_UP") >= 0: # From description i can known, link is up or link is down
                                            link_status = 10
                                    elif descriptionIds.find("LINK_DOWN") >=0:
                                            link_status = 11

                                    state_resources.append("%s %s %s %s" % (storage_name, key_status, timestampnow, link_status))

                    elif ['lun'].count(resource) == 1:
                            for one_object in resource_info['entries']:
                                    key_health = "health.{0}.[{1}]".format(resource, one_object['content']['name'].replace(' ', '_')) # Use lun name instead lun id on zabbix key
                                    key_sizeTotal = "sizeTotal.{0}.[{1}]".format(resource, one_object['content']['name'].replace(' ', '_'))
                                    key_sizeAllocated = "sizeAllocated.{0}.[{1}]".format(resource, one_object['content']['name'].replace(' ', '_'))

                                    state_resources.append("%s %s %s %s" % (storage_name, key_health, timestampnow, one_object['content']['health']['value']))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_sizeTotal, timestampnow, one_object['content']['sizeTotal']))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_sizeAllocated, timestampnow, one_object['content']['sizeAllocated']))
                    elif ['pool'].count(resource) == 1:
                            for one_object in resource_info['entries']:
                                    key_health = "health.{0}.[{1}]".format(resource, one_object['content']['name'].replace(' ', '_')) # Use pull name instead lun id on zabbix key
                                    key_sizeUsedBytes = "sizeUsedBytes.{0}.[{1}]".format(resource, one_object['content']['name'].replace(' ', '_'))
                                    key_sizeTotalBytes = "sizeTotalBytes.{0}.[{1}]".format(resource, one_object['content']['name'].replace(' ', '_'))
                                    key_sizeSubscribedBytes = "sizeSubscribedBytes.{0}.[{1}]".format(resource, one_object['content']['name'].replace(' ', '_'))

                                    state_resources.append("%s %s %s %s" % (storage_name, key_health, timestampnow, one_object['content']['health']['value']))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_sizeUsedBytes, timestampnow, one_object['content']['sizeUsed']))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_sizeTotalBytes, timestampnow, one_object['content']['sizeTotal']))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_sizeSubscribedBytes, timestampnow, one_object['content']['sizeSubscribed']))
                    else:
                            for one_object in resource_info['entries']:
                                    # Get state of resources from description
                                    descriptionIds = str(one_object['content']['health']['descriptionIds'][0]) # Convert description to string
                                    if descriptionIds.find("ALRT_COMPONENT_OK") >= 0:
                                            running_status = 8
                                    elif descriptionIds.find("ALRT_DISK_SLOT_EMPTY") >= 0:
                                            running_status = 6
                                    else:
                                            running_status = 5

                                    key_health = "health.{0}.[{1}]".format(resource, one_object['content']['id'].replace(' ', '_'))
                                    key_status = "running.{0}.[{1}]".format(resource, one_object['content']['id'].replace(' ', '_'))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_health, timestampnow, one_object['content']['health']['value']))
                                    state_resources.append("%s %s %s %s" % (storage_name, key_status, timestampnow, running_status))
    except Exception as oops:
            unity_logger.error("Error occured in get state")
            sys.exit("1000")

    api_session_logout = api_logout(api_ip, api_session)
    return send_data_to_zabbix(state_resources, storage_name)

def main():

Parsing arguments

    unity_parser = argparse.ArgumentParser()
    unity_parser.add_argument('--api_ip', action="store", help="Where to connect", required=True)
    unity_parser.add_argument('--api_port', action="store", required=True)
    unity_parser.add_argument('--api_user', action="store", required=True)
    unity_parser.add_argument('--api_password', action="store", required=True)
    unity_parser.add_argument('--storage_name', action="store", required=True)

    group = unity_parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--discovery', action ='store_true')
    group.add_argument('--status', action='store_true')
    arguments = unity_parser.parse_args()

    list_resources = ['battery','ssd','ethernetPort','fcPort','sasPort','fan','powerSupply','storageProcessor','lun','pool','dae','dpe','ioModule','lcc','memoryModule','ssc','uncommittedPort','disk']
    if arguments.discovery:
            result_discovery = discovering_resources(arguments.api_user, arguments.api_password, arguments.api_ip, arguments.api_port, arguments.storage_name, list_resources)
            print (result_discovery)
    elif arguments.status:
            result_status = get_status_resources(arguments.api_user, arguments.api_password, arguments.api_ip, arguments.api_port, arguments.storage_name, list_resources)
            print (result_status)

if name == "main": main()

Neo914 commented 4 months ago

Hello, I have been able to evolve a little on my work and I complete the information. I manage to recover data of this type:

2024-07-11 09:26:02,489 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=health.memoryModule.[spb_mm_2], timestamp=1720682760, value=5 2024-07-11 09:26:02,496 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,496 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=running.memoryModule.[spb_mm_2], timestamp=1720682760, value=8 2024-07-11 09:26:02,502 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,502 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=health.memoryModule.[spb_mm_3], timestamp=1720682760, value=5 2024-07-11 09:26:02,508 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,508 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=running.memoryModule.[spb_mm_3], timestamp=1720682760, value=8 2024-07-11 09:26:02,513 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,514 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=health.disk.[dae_1_0_disk_0], timestamp=1720682761, value=5 2024-07-11 09:26:02,519 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,519 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=running.disk.[dae_1_0_disk_0], timestamp=1720682761, value=8 2024-07-11 09:26:02,525 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,525 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=health.disk.[dae_1_0_disk_1], timestamp=1720682761, value=5 2024-07-11 09:26:02,530 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,530 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=running.disk.[dae_1_0_disk_1], timestamp=1720682761, value=8 2024-07-11 09:26:02,536 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,537 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=health.disk.[dae_1_0_disk_2], timestamp=1720682761, value=5 2024-07-11 09:26:02,543 - unity_logger - DEBUG - Zabbix sender return code: 2 2024-07-11 09:26:02,543 - unity_logger - DEBUG - Sending to Zabbix: host=DellEMC_unity_rgi1, key=running.disk.[dae_1_0_disk_2], timestamp=1720682761, value=8

But sending to zabbix I don't have to report data because I have a return code:2

Here is an example of a Discovry Rule

image

And Item prototype

image image

Can you please help me to report the data value of each element discovered in Zabbix?

Neo914 commented 4 months ago

Issue Resolved