import urllib import urllib2 import ssl import json from VM import VM from Node import Node from Storage import Storage import time CACHEFILE='/tmp/zabbix_ticket.json' def get_auth(host, username, password): """ Handles ticket and csrf token collection for PVEApi class :param host: ip of pve host with port :param username: zabbix user :param password: zabbix password :return: list with csrf token and auth ticket """ postdata = urllib.urlencode({'username': username, 'password': password}) url = "https://" + host + "/api2/json/access/ticket" req = urllib2.Request(url, postdata) response = urllib2.urlopen(req, context=ssl._create_unverified_context()) response = json.load(response) return response['data']['CSRFPreventionToken'], response['data']['ticket'] class PVEApi(object): """Handle API Connection and authorization""" def __init__(self, host, username, password): """ Creates connection object :param self: :param host: ip of pve host with port :param username: zabbix user :param password: zabbix password :return: """ self.host = host self.url = "https://" + self.host + "/api2/json" self.username = username self.password = password if self.check_cacheexpire(): self.csrftoken = get_auth(self.host, username, password)[0] self.ticket = get_auth(self.host, username, password)[1] self.write_ticketcache() else: self.csrftoken = self.read_ticketcache()['csrf'] self.ticket = self.read_ticketcache()['ticket'] def check_cacheexpire(self): """ Checks if API ticket is expired. Proxmox says ticket is valid for 2 hours. For safety we use 1 hour :return: Boolean value of True if ticket is considered expired. False if opposite. """ try: with open(CACHEFILE, 'r') as f: data = json.load(f) timestamp = data['timestamp'] return True if time.time() - timestamp > 3600 else False except: self.csrftoken = get_auth(self.host, self.username, self.password)[0] self.ticket = get_auth(self.host, self.username, self.password)[1] self.write_ticketcache() def write_ticketcache(self): """ Function writes API login ticket cache to tmp """ data = {} data['csrf'] = self.csrftoken data['ticket'] = self.ticket data['timestamp'] = time.time() with open(CACHEFILE, 'w') as f: json.dump(data, f) def read_ticketcache(self): """ Reads API login ticket cache file :return: returns json parsed dict """ with open(CACHEFILE, 'r') as f: data = json.load(f) return data def get_request(self, url): """ Handles adding auth ticket to API request :param url: url to create request to :return: request to handle with urlopen """ req = urllib2.Request(url) req.add_header('Cookie', 'PVEAuthCookie=' + self.ticket) return req def get_node_list(self): """ Gets Node names from cluster data :return: List of node names """ url = self.url + '/nodes' response = json.load(urllib2.urlopen(self.get_request(url), context=ssl._create_unverified_context())) resources = response['data'] nodes = list() for node in resources: if type(node) is dict: nodeobj = Node(node[u'node'].encode("ascii")) nodes.append(nodeobj) return nodes def get_cluster_vmlist(self, nodelist, detailed=False): """ Creates Virtual Machine List :return: list of VM class objects """ vmlist = list() for node in nodelist: url = self.url + '/nodes/' + node.name + '/qemu' try: response = json.load(urllib2.urlopen(self.get_request(url), context=ssl._create_unverified_context())) except Exception as e: pass resources = response['data'] for machine in resources: name = machine[u'name'] status = machine[u'status'] uptime = machine[u'uptime'] diskread = machine[u'diskread'] diskwrite = machine[u'diskwrite'] memusage = machine[u'mem'] pid = machine[u'pid'] vmid = machine[u'vmid'] netin = machine[u'netin'] netout = machine[u'netout'] cpus = machine[u'cpus'] template = machine[u'template'] disk = machine[u'disk'] cpuusage = machine[u'cpu'] maxdisk = machine[u'maxdisk'] maxmem = machine[u'maxmem'] vm = VM(node, name, status, uptime, diskread, diskwrite, memusage, pid, vmid, netin, netout, cpus, template, disk, cpuusage, maxdisk, maxmem, url) if detailed is True: vm_dattr = self.get_details(url, vmid) for k, v in vm_dattr.items(): vm.__setattr__('det_' + k, v) vmlist.append(vm) return vmlist def get_details(self, url, vmid): """ Gets vm detailed data from PVE API (its slower than just basic data) :param url: url used in vm data get :param vmid: vmid to create new url for detailed data :return: dict of detailed data params """ url = url + '/' + vmid + '/status/current' response = json.load(urllib2.urlopen(self.get_request(url), context=ssl._create_unverified_context())) resources = response['data'] attributedict = dict() for param, paramvalue in resources.items(): attributedict.update({param: paramvalue}) return attributedict def get_cluster_storagelist(self, nodelist): """ Creates Virtual Machine List :return: list of VM class objects """ storagelist = list() for node in nodelist: url = self.url + '/nodes/' + node.name + '/storage' response = json.load(urllib2.urlopen(self.get_request(url), context=ssl._create_unverified_context())) resources = response['data'] for storage in resources: name = storage[u'storage'] total = storage[u'total'] used = storage[u'used'] active = storage[u'active'] enabled = storage[u'enabled'] avail = storage[u'avail'] try: used_fraction = storage[u'used_fraction'] except KeyError: used_fraction = "Error getting value" stor = Storage(node, name, total, used, active, enabled, avail, used_fraction) storagelist.append(stor) return storagelist