diff --git a/NodeInstance.py b/NodeInstance.py index 1621defd..0892b340 100644 --- a/NodeInstance.py +++ b/NodeInstance.py @@ -24,9 +24,10 @@ import os, sys, socket, time, libvirt, kazoo.client, threading, fencenode, ansii class NodeInstance(): # Initialization function - def __init__(self, name, t_node, s_domain, zk): + def __init__(self, name, t_node, s_domain, zk, config): # Passed-in variables on creation self.zk = zk + self.config = config self.name = name self.state = 'stop' self.t_node = t_node @@ -35,6 +36,7 @@ class NodeInstance(): self.inactive_node_list = [] self.s_domain = s_domain self.domain_list = [] + self.ipmiaddress = '' # Zookeeper handlers for changed states @zk.DataWatch('/nodes/{}/state'.format(self.name)) @@ -193,9 +195,12 @@ class NodeInstance(): # Close the Libvirt connection conn.close() + # Get IPMI address + self.ipmiaddress = fencenode.getIPMIAddress() + # Display node information to the terminal ansiiprint.echo('{}{} keepalive{}'.format(ansiiprint.purple(), self.name, ansiiprint.end()), '', 't') - ansiiprint.echo('{0}CPUs:{1} {2} {0}Free memory:{1} {3} {0}Load:{1} {4}'.format(ansiiprint.bold(), ansiiprint.end(), self.cpucount, self.memfree, self.cpuload), '', 'c') + ansiiprint.echo('{0}CPUs:{1} {2} {0}Free memory:{1} {3} {0}Load:{1} {4} {0}IPMI Address:{1} {5}'.format(ansiiprint.bold(), ansiiprint.end(), self.cpucount, self.memfree, self.cpuload, self.ipmiaddress), '', 'c') ansiiprint.echo('{}Active domains:{} {}'.format(ansiiprint.bold(), ansiiprint.end(), ' '.join(self.domain_list)), '', 'c') # Update our local node lists diff --git a/VMInstance.py b/VMInstance.py index 45cfd3f6..33897ccb 100644 --- a/VMInstance.py +++ b/VMInstance.py @@ -24,10 +24,11 @@ import os, sys, uuid, socket, time, threading, libvirt, kazoo.client, ansiiprint class VMInstance: # Initialization function - def __init__(self, domuuid, zk, thishypervisor): + def __init__(self, domuuid, zk, config, thishypervisor): # Passed-in variables on creation self.domuuid = domuuid self.zk = zk + self.config = config self.thishypervisor = thishypervisor # These will all be set later diff --git a/pvcd.conf b/pvcd.conf new file mode 100644 index 00000000..7566a922 --- /dev/null +++ b/pvcd.conf @@ -0,0 +1,7 @@ +# pvcd configuration file +[test1.i.bonilan.net] +zookeeper = localhost:2181 +keepalive_interval = 5 +ipmi_hostname = test1-lom.i.bonilan.net +ipmi_username = admin +ipmi_password = admin diff --git a/pvcd.py b/pvcd.py index 00152793..f982911e 100755 --- a/pvcd.py +++ b/pvcd.py @@ -23,44 +23,62 @@ import kazoo.client import libvirt import sys +import os import socket import uuid import VMInstance import NodeInstance import time import atexit +import configparser import apscheduler.schedulers.background +import fencenode import ansiiprint -def help(): - print(ansiiprint.bold() + "pvcd - Parallel Virtual Cluster management daemon" + ansiiprint.end()) -# exit(0) +print(ansiiprint.bold() + "pvcd - Parallel Virtual Cluster management daemon" + ansiiprint.end()) -help() +# Get the config file variable from the environment +try: + pvcd_config_file = os.environ['PVC_CONFIG_FILE'] +except: + print('ERROR: The "PVC_CONFIG_FILE" environment variable must be set before starting pvcd.') + exit(1) + +print('Loading configuration from file {}'.format(pvcd_config_file)) + +def readConfig(pvcd_config_file, myhostname): + o_config = configparser.ConfigParser() + o_config.read(pvcd_config_file) + entries = o_config[myhostname] + config = {} + for entry in entries: + config[entry] = entries[entry] + return config + +myhostname = socket.gethostname() +config = readConfig(pvcd_config_file, myhostname) # Connect to local zookeeper -zk = kazoo.client.KazooClient(hosts='127.0.0.1:2181') +zk = kazoo.client.KazooClient(hosts=config['zookeeper']) try: + print('Connecting to Zookeeper instance at {}'.format(config['zookeeper'])) zk.start() except: - print(ansiiprint.red() + "Failed to connect to local Zookeeper instance" + ansiiprint.end()) + print('ERROR: Failed to connect to Zookeeper') exit(1) def zk_listener(state): if state == kazoo.client.KazooState.LOST: cleanup() - exit(2) + exit(1) elif state == kazoo.client.KazooState.SUSPENDED: cleanup() - exit(2) + exit(1) else: pass zk.add_listener(zk_listener) -myhostname = socket.gethostname() -mynodestring = '/nodes/%s' % myhostname - def cleanup(): try: update_timer.shutdown() @@ -80,12 +98,17 @@ else: print("Node is " + ansiiprint.red() + "absent" + ansiiprint.end() + " in Zookeeper; adding new node") keepalive_time = int(time.time()) zk.create('/domains/{}'.format(myhostname), 'hypervisor'.encode('ascii')) + # Basic state information zk.create('/domains/{}/state'.format(myhostname), 'stop'.encode('ascii')) zk.create('/domains/{}/cpucount'.format(myhostname), '0'.encode('ascii')) zk.create('/domains/{}/memfree'.format(myhostname), '0'.encode('ascii')) zk.create('/domains/{}/cpuload'.format(myhostname), '0.0'.encode('ascii')) zk.create('/domains/{}/runningdomains'.format(myhostname), ''.encode('ascii')) + # Keepalives and fencing information zk.create('/domains/{}/keepalive'.format(myhostname), str(keepalive_time).encode('ascii')) + zk.create('/domains/{}/ipmiaddress'.format(myhostname), ''.encode('ascii')) + zk.create('/domains/{}/ipmiusername'.format(myhostname), ''.encode('ascii')) + zk.create('/domains/{}/ipmipassword'.format(myhostname), ''.encode('ascii')) t_node = dict() s_domain = dict() @@ -101,7 +124,7 @@ def updatenodes(new_node_list): if node in t_node: t_node[node].updatenodelist(t_node) else: - t_node[node] = NodeInstance.NodeInstance(node, t_node, s_domain, zk) + t_node[node] = NodeInstance.NodeInstance(node, t_node, s_domain, zk, config) @zk.ChildrenWatch('/domains') def updatedomains(new_domain_list): @@ -110,7 +133,7 @@ def updatedomains(new_domain_list): print(ansiiprint.blue() + 'Domain list: ' + ansiiprint.end() + '{}'.format(' '.join(domain_list))) for domain in domain_list: if not domain in s_domain: - s_domain[domain] = VMInstance.VMInstance(domain, zk, t_node[myhostname]); + s_domain[domain] = VMInstance.VMInstance(domain, zk, config, t_node[myhostname]); for node in node_list: if node in t_node: t_node[node].updatedomainlist(s_domain) @@ -121,7 +144,7 @@ update_zookeeper = this_node.update_zookeeper # Create timer to update this node in Zookeeper update_timer = apscheduler.schedulers.background.BackgroundScheduler() -update_timer.add_job(update_zookeeper, 'interval', seconds=5) +update_timer.add_job(update_zookeeper, 'interval', seconds=config['keepalive_interval']) update_timer.start() # Tick loop