Automatic setting the value of attribute "parents" of Host (with livestatus, wato-api und vsphere-plugin)

Automatic setting the value of attribute “parents” of Host (with livestatus, wato-api und vsphere-plugin)

Hello folks,

I wanted to have an automatic function to set the curent parents value of vmware machines in the wato host configuration. Therfore I made a script to do it, that is periodically executed via crond of the cmk site user. Details below, have fun with it.

Regards
Stefan

#!/usr/bin/env python
# -*- coding: utf-8 -*-

__doc__ = u"""
Environment: python 2.7

Need to make it run with python 3!

Target: 
Set the value for attribute parents of each host,
that is hosted on a esx server (vmware).

Prerequisites:
Working piggyback function - > https://checkmk.de/cms_monitoring_vmware.html
HTTPS connection to Check_MK site
SSL certificates of of the ca embedded system wide, i.e. under ubuntu:
https://askubuntu.com/questions/645818/how-to-install-certificates-for-command-line

Simple description of the script:
Get all Hosts via check_MK Livestatus, then fetch status detail of monitoring
service ESX Hostsystem. Finally set via Check_MK wato API the host attribute parent,
that is different to the existing value.

Get it wun periodically via crond of check_mk site user, example for executing it each hour:
0 */1 * * *  python /omd/sites/sitename/customScripts/LQgetHost-APIsetParent2.py 2>1&
"""

import json
import os
import requests
import socket
import time

__author__ = "Stefan Senftleben"
__version__ = "1.0.1"
__credits__ = ["Tribe29, code samples from check_mk website theme livestatus"]
__email__ = "stefan.senftleben@posteo.de"
__status__ = "Production"



class Livestatus:

    def __init__(self):
        self.address = "%s/tmp/run/live" % os.getenv("OMD_ROOT")
        """
        for local/remote sites: TCP address/port for Livestatus socket
        self.address = ("localhost", 6557)
        """
        self.family = socket.AF_INET if type(self.address) == tuple else socket.AF_UNIX
        self.sock = socket.socket(self.family, socket.SOCK_STREAM)

    def getdata(self, *largs):
        requestdata = largs[0]
        """Connect to livestatus unix socket and request data. """
        self.sock.connect(self.address)
        self.sock.sendall('{}'.format(requestdata))
        self.sock.shutdown(socket.SHUT_WR)
        self.chunks = []
        while len(self.chunks) == 0 or self.chunks[-1] != "":
            self.chunks.append(self.sock.recv(4096))
        self.sock.close()
        self.reply = "".join(self.chunks)
        return self.reply
        


class Watoapi:

    def __init__(self):
        """
        class to some functions of the check_mk wato api.
        self.params defines class variables. Edit to your needs -> username, password
		Define in WATO an web api automation user:
		https://checkmk.de/cms_wato_user.html#automation
        """
        self.preparams = [                 
                 ('_username', 'username'),
                 ('_secret', 'password'),
                 ]
        self.sitename = '{}'.format(os.getenv("OMD_SITE"))
        self.fqdn = '{}'.format(socket.getfqdn())
        self.url = 'https://{}/{}/check_mk/webapi.py'.format(self.fqdn, self.sitename)
        """When connecting to a self signed https website, set here the system wide
        ca certificates location. """
        self.capath = '/etc/ssl/certs/ca-certificates.crt'


    def getdata(self, *largs):
        """
        Building some python dictionarys in form of the needed json request.
        Parsing it to json format and do a request to the wato api.
        """
        valuehostname = largs[0]
        valueget = largs[1]
        self.preparams.append(('output_format', 'json'))
        self.preparams.append(('request_format', 'python'))
        self.preparams.append(('action', 'get_host'))
        self.params = tuple(self.preparams)
        self.data = {}
        self.dicthostname = {}
        self.dicthostname["hostname"] = '{}'.format(valuehostname)
        self.dataset = {}
        self.dataset.update(self.dicthostname)
        self.data['request'] = json.dumps(self.dataset)
        self.response = requests.post(self.url, params=self.params, data=self.data, verify=self.capath)
        self.loaded_jsondata = (json.loads(self.response.text))
        # print(self.loaded_jsondata)
        if valueget in self.loaded_jsondata['result']['attributes']:
            self.watovalue = self.loaded_jsondata['result']['attributes'][valueget]
        if valueget in self.loaded_jsondata['result']:
           self.watovalue = self.loaded_jsondata['result'][valueget]
        return self.watovalue

    def changedata(self, *largs):
        """Method to change values of a host parameter"""
        valuehostname = largs[0]
        valueesxhost = largs[1]
        self.preparams.append(('action', 'edit_host'))
        self.params = tuple(self.preparams)
        self.data = {}
        self.dicthostname = {}
        self.dictesxhost = {}
        self.dictattrib = {}
        self.dicthostname["hostname"] = '{}'.format(valuehostname)
        self.dictesxhost["parents"] = ['{}'.format(valueesxhost)]
        self.dictattrib["attributes"] = self.dictesxhost
        self.dataset = {}
        self.dataset.update(self.dictattrib)
        self.dataset.update(self.dicthostname)
        self.data['request'] = json.dumps(self.dataset)
        self.response = requests.post(self.url, params=self.params, data=self.data, verify=self.capath)
        self.loaded_jsondata = (json.loads(self.response.text))
        # print(self.loaded_jsondata)


    def activatechanges(self, *largs):
        """Method to activate changes in wato"""
        valuesitename = largs[0]
        valueforeign = largs[1]
        valuecomment = largs[2]
        self.preparams.append(('action', 'activate_changes'))
        self.params = tuple(self.preparams)
        self.data = {}
        self.dictsitename = {}
        self.dictforeignchanges = {}
        self.dictcomment = {}
        self.dictsitename["sites"] = ['{}'.format(valuesitename)]
        self.dictforeignchanges["allow_foreign_changes"] = '{}'.format(valueforeign)
        self.dictcomment["comment"] = '{}'.format(valuecomment)
        self.dataset = {}
        self.dataset.update(self.dictsitename)
        self.dataset.update(self.dictforeignchanges)
        self.dataset.update(self.dictcomment)
        self.data['request'] = json.dumps(self.dataset)
        self.response = requests.post(self.url, params=self.params, data=self.data, verify=self.capath)
        self.loaded_jsondata = (json.loads(self.response.text))
        print(self.loaded_jsondata)


    def __exit__(self):
        return


def main():
    hostrequest = "GET hosts\nColumns: host_name\nOutputFormat: json\n"
    cmklivestatus = Livestatus()
    reply = cmklivestatus.getdata(hostrequest)
    # print(json.loads(reply))
    for element in json.loads(reply):
             hostname = "".join(element)
             wato = Watoapi()
             watovalue = wato.getdata("{}".format(hostname), 'path')
             servicerequest = "GET services\nColumns: host_name description plugin_output\nFilter: host_name = {}\nFilter: description = ESX Hostsystem\nOutputFormat: json\n".format(hostname)
             # print('{}'.format(servicerequest))
             cmklivestatus = Livestatus()
             reply2 = cmklivestatus.getdata(servicerequest)
             if len(reply2) == 3:
                 print(' - Host {} seems to be no virtual machine on ESX.'.format(hostname))
             else:
                 for item in json.loads(reply2):
                     esxhost = ''
                     esxhost = "".join(item).split()[-1]
                     if esxhost != '':
                         if esxhost not in ''.join(wato.getdata(hostname, 'parents')):
                             print(' + Host {} is running on {}.'.format(hostname, esxhost))
                             wato.changedata(hostname, esxhost)
                         else:
                             print('= Host {}. The value of the attribut {} equals to the existing one.'.format(hostname, 'parents'))

    # activate changes
    wato = Watoapi()
    wato.activatechanges('{}'.format(os.getenv("OMD_SITE")), 1, 'Change by a custom script -> crontab -l')


if __name__ == '__main__':
    main()

Hi @stefan.senftleben,

Thank you for your contribution. Have you asked before writing I could have told you that there is already an example at check_mk_extensions/vm_parent.py at master · HeinleinSupport/check_mk_extensions · GitHub :wink:

That would have been to easy! :rofl:

2 Likes

I heard about this script before but the Github link returns “404” !?

Since last year the repo has been reorganized.

The script for checkmk 2.0 can be found here: https://github.com/HeinleinSupport/check_mk_extensions/blob/cmk2.0/helper/bin/vm_parent.py

The script for checkmk 1.6 can be found here: https://github.com/HeinleinSupport/check_mk_extensions/blob/cmk1.6/helper/vm_parent.py

Both need the checkmk API wrapper for Python which is also available in that repo.