Getting latest code into git for Steve
Change-Id: Ie7c63c227cc4805b2d13a327964edfb5896777a8
diff --git a/.gitignore b/.gitignore
index 6501940..362c6b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+dist/
*.pyc
.idea/
*.egg-info/
diff --git a/etc/lavapdu.conf b/etc/lavapdu.conf
deleted file mode 100644
index fba2a26..0000000
--- a/etc/lavapdu.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "hostname": "0.0.0.0",
- "port": 16421,
- "dbhost": "127.0.0.1",
- "dbuser": "pdudaemon",
- "dbpass": "pdudaemon",
- "dbname": "lavapdu"
-}
\ No newline at end of file
diff --git a/etc/lavapdu/lavapdu.conf b/etc/lavapdu/lavapdu.conf
new file mode 100644
index 0000000..acded88
--- /dev/null
+++ b/etc/lavapdu/lavapdu.conf
@@ -0,0 +1,25 @@
+{
+ "daemon": {
+ "hostname": "0.0.0.0",
+ "port": 16421,
+ "dbhost": "127.0.0.1",
+ "dbuser": "pdudaemon",
+ "dbpass": "pdudaemon",
+ "dbname": "lavapdu"
+ },
+ "pdus": {
+ "pdu14": {
+ "driver": "apc9218"
+ },
+ "pdu15": {
+ "driver": "apc9218"
+ },
+ "localhost": {
+ "driver": "apc9218"
+ },
+ "pdu04": {
+ "driver": "blah",
+ "snmp": "this"
+ }
+ }
+}
\ No newline at end of file
diff --git a/lavapdu-listen b/lavapdu-listen
index c1e7852..c6a22f0 100755
--- a/lavapdu-listen
+++ b/lavapdu-listen
@@ -48,23 +48,17 @@
"""
Read settings from config file, to listen to all hosts, hostname should be 0.0.0.0
"""
- settings = {"port": 16421, "hostname": "0.0.0.0", "dbuser": "pdudaemon",
- "dbpass": "pdudaemon", "dbname": "pdu_queue", "dbhost": "127.0.0.1"}
+ settings = {}
+ print("Reading settings from %s" % conffile)
with open(filename) as stream:
jobdata = stream.read()
- json_default = json.loads(jobdata)
- if "port" in json_default:
- settings['port'] = json_default['port']
- if "hostname" in json_default:
- settings['hostname'] = json_default['hostname']
- if "dbuser" in json_default:
- settings['dbuser'] = json_default['dbuser']
- if "dbpass" in json_default:
- settings['dbpass'] = json_default['dbpass']
- if "dbname" in json_default:
- settings['dbname'] = json_default['dbname']
- if "dbhost" in json_default:
- settings['dbhost'] = json_default['dbhost']
+ json_data = json.loads(jobdata)
+ settings['port'] = json_data["daemon"]['port']
+ settings['hostname'] = json_data["daemon"]['hostname']
+ settings['dbuser'] = json_data["daemon"]['dbuser']
+ settings['dbpass'] = json_data["daemon"]['dbpass']
+ settings['dbname'] = json_data["daemon"]['dbname']
+ settings['dbhost'] = json_data["daemon"]['dbhost']
return settings
if __name__ == '__main__':
@@ -72,7 +66,7 @@
# not necessarily per-instance, so use the command line and a default conf file.
pidfile = "/var/run/lavapdu-listen.pid"
logfile = "/var/log/lavapdu-listener.log"
- conffile = "/etc/lavapdu.conf"
+ conffile = "/etc/lavapdu/lavapdu.conf"
settings = readSettings(conffile)
usage = "Usage: %prog [--logfile] --[loglevel]"
description = "LAVA PDU request listener server, host and port are handled in %s" % conffile
@@ -114,12 +108,7 @@
stderr=watched_file_handler.stream,
stdout=watched_file_handler.stream)
starter = {"logging_level": level,
- "hostname": settings['hostname'],
- "port": settings['port'],
- "dbhost": settings["dbhost"],
- "dbuser": settings["dbuser"],
- "dbpass": settings["dbpass"],
- "dbname": settings["dbname"]}
+ "settings": settings}
with context:
logging.info("Running LAVA PDU Listener %s %s %d."
% (logfile, settings['hostname'], settings['port']))
diff --git a/lavapdu-runner b/lavapdu-runner
index 9ad9d62..dadf9f3 100755
--- a/lavapdu-runner
+++ b/lavapdu-runner
@@ -48,27 +48,29 @@
"""
Read settings from config file, to listen to all hosts, hostname should be 0.0.0.0
"""
- settings = {"dbuser": "pdudaemon", "dbpass": "pdudaemon", "dbname": "pdu_queue", "dbhost": "127.0.0.1"}
+ pdus = {}
+ settings = {}
+ print("Reading settings from %s" % conffile)
with open(filename) as stream:
jobdata = stream.read()
- json_default = json.loads(jobdata)
- if "dbuser" in json_default:
- settings['dbuser'] = json_default['dbuser']
- if "dbpass" in json_default:
- settings['dbpass'] = json_default['dbpass']
- if "dbname" in json_default:
- settings['dbname'] = json_default['dbname']
- if "dbhost" in json_default:
- settings['dbhost'] = json_default['dbhost']
- return settings
+ json_data = json.loads(jobdata)
+ settings['port'] = json_data["daemon"]['port']
+ settings['hostname'] = json_data["daemon"]['hostname']
+ settings['dbuser'] = json_data["daemon"]['dbuser']
+ settings['dbpass'] = json_data["daemon"]['dbpass']
+ settings['dbname'] = json_data["daemon"]['dbname']
+ settings['dbhost'] = json_data["daemon"]['dbhost']
+ pdus = json_data["pdus"]
+ return (settings, pdus)
+
if __name__ == '__main__':
# instance settings come from django - the coordinator doesn't use django and is
# not necessarily per-instance, so use the command line and a default conf file.
pidfile = "/var/run/lavapdu-runner.pid"
logfile = "/var/log/lavapdu-runner.log"
- conffile = "/etc/lavapdu.conf"
- settings = readSettings(conffile)
+ conffile = "/etc/lavapdu/lavapdu.conf"
+ settings, pdus = readSettings(conffile)
usage = "Usage: %prog [--logfile] --[loglevel]"
description = "LAVA PDU request listener server, host and port are handled in %s" % conffile
parser = optparse.OptionParser(usage=usage, description=description)
@@ -109,10 +111,8 @@
stderr=watched_file_handler.stream,
stdout=watched_file_handler.stream)
starter = {"logging_level": level,
- "dbhost": settings["dbhost"],
- "dbuser": settings["dbuser"],
- "dbpass": settings["dbpass"],
- "dbname": settings["dbname"]}
+ "settings": settings,
+ "pdus": pdus}
with context:
logging.info("Running LAVA PDU Runner %s dbhost: %s"
% (logfile, settings["dbhost"]))
diff --git a/lavapdu/drivers/__init__.py b/lavapdu/drivers/__init__.py
index e69de29..2524629 100644
--- a/lavapdu/drivers/__init__.py
+++ b/lavapdu/drivers/__init__.py
@@ -0,0 +1,23 @@
+#! /usr/bin/python
+
+# Copyright 2013 Linaro Limited
+# Author Matt Hart <matthew.hart@linaro.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+#from apc9218 import apc9218
+#from apc7952 import apc7952
+#from apc8959 import apc8959
diff --git a/lavapdu/drivers/apc7952.py b/lavapdu/drivers/apc7952.py
index 447bac1..2e4abfb 100644
--- a/lavapdu/drivers/apc7952.py
+++ b/lavapdu/drivers/apc7952.py
@@ -19,9 +19,10 @@
# MA 02110-1301, USA.
import logging
-from driver import PDUDriver
+from apcbase import APCBase
-class apc7952(PDUDriver):
+
+class APC7952(APCBase):
def _pdu_logout(self):
self._back_to_main()
@@ -30,6 +31,7 @@
def _back_to_main(self):
logging.debug("Returning to main menu")
+ self.connection.send("\r")
self.connection.expect('>')
for i in range(1, 20):
self.connection.send("\x1B")
@@ -89,7 +91,4 @@
self.connection.expect("Enter 'YES' to continue or <ENTER> to cancel :")
self.connection.send("YES\r")
self.connection.expect("Press <ENTER> to continue...")
- self.connection.send("\r")
-
- class Meta():
- handled_firmware = ["v3.7.3"]
\ No newline at end of file
+ self.connection.send("\r")
\ No newline at end of file
diff --git a/lavapdu/drivers/apc8959.py b/lavapdu/drivers/apc8959.py
index a3f1e29..f5f64c7 100644
--- a/lavapdu/drivers/apc8959.py
+++ b/lavapdu/drivers/apc8959.py
@@ -19,10 +19,10 @@
# MA 02110-1301, USA.
import logging
-from driver import PDUDriver
+from apcbase import APCBase
-class apc8959(PDUDriver):
+class APC8959(APCBase):
pdu_commands = {"off": "olOff", "on": "olOn"}
def _pdu_logout(self):
@@ -41,7 +41,4 @@
self._pdu_get_to_prompt()
self.connection.sendline(self.pdu_commands[command] + (" %i" % port_number))
self.connection.expect("E000: Success")
- logging.debug("done")
-
- class Meta():
- handled_firmware = ["v5.1.9"]
\ No newline at end of file
+ logging.debug("done")
\ No newline at end of file
diff --git a/lavapdu/drivers/apc9218.py b/lavapdu/drivers/apc9218.py
index a81f6d7..1dae89a 100644
--- a/lavapdu/drivers/apc9218.py
+++ b/lavapdu/drivers/apc9218.py
@@ -19,10 +19,9 @@
# MA 02110-1301, USA.
import logging
-from apc7952 import apc7952
+from apc7952 import APC7952
-class apc9218(apc7952):
- handled_firmware = ["v3.0.3","v3.0.1"]
+class APC9218(APC7952):
def _port_interaction(self, command, port_number):
print("Attempting command: %s port: %i" % (command, port_number))
@@ -56,7 +55,4 @@
self.connection.expect("Immediate Off")
self._do_it()
else:
- logging.debug("Unknown command!")
-
- class Meta():
- handled_firmware = ["v3.0.3","v3.0.1"]
\ No newline at end of file
+ logging.debug("Unknown command!")
\ No newline at end of file
diff --git a/lavapdu/drivers/apcbase.py b/lavapdu/drivers/apcbase.py
new file mode 100644
index 0000000..d3dca6f
--- /dev/null
+++ b/lavapdu/drivers/apcbase.py
@@ -0,0 +1,62 @@
+#! /usr/bin/python
+
+# Copyright 2013 Linaro Limited
+# Author Matt Hart <matthew.hart@linaro.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+import logging
+import pexpect
+from driver import PDUDriver
+import sys
+
+class APCBase(PDUDriver):
+ connection = None
+
+ def __init__(self, pdu_hostname, pdu_telnetport=23):
+ self.exec_string = "/usr/bin/telnet %s %d" % (pdu_hostname, pdu_telnetport)
+ self.get_connection()
+ super(APCBase, self).__init__(pdu_hostname)
+
+ #def port_on(self, port_number):
+ # self.port_interaction("on", port_number)
+
+ #def port_off(self, port_number):
+ # self.port_interaction("off", port_number)
+
+ def port_interaction(self, command, port_number):
+ logging.debug("Running port_interaction from APCBase")
+ self._port_interaction(command, port_number)
+ self._cleanup()
+
+ def get_connection(self):
+ logging.debug("Connecting to APC PDU with: %s" % self.exec_string)
+ self.connection = pexpect.spawn(self.exec_string, logfile=sys.stdout)
+ self._pdu_login("apc","apc")
+
+ def _cleanup(self):
+ self._pdu_logout()
+ logging.debug("Closing connection: %s" % self.connection)
+ self.connection.close(True)
+ del(self)
+
+ def _pdu_login(self, username, password):
+ logging.debug("attempting login with username %s, password %s" % (username, password))
+ self.connection.send("\r")
+ self.connection.expect("User Name :")
+ self.connection.send("%s\r" % username)
+ self.connection.expect("Password :")
+ self.connection.send("%s\r" % password)
diff --git a/lavapdu/drivers/driver.py b/lavapdu/drivers/driver.py
index 7be55e9..7325473 100644
--- a/lavapdu/drivers/driver.py
+++ b/lavapdu/drivers/driver.py
@@ -18,29 +18,36 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
+import time
import logging
-
-class NoDriverException(Exception):
- pass
-
-
class PDUDriver(object):
connection = None
- firmware_dict = {}
+ hostname = ""
- def __init__(self, connection):
- self.connection = connection
+ def __init__(self, pdu_hostname):
+ self.hostname = pdu_hostname
+ #super(PDUDriver,self).__init__(pdu_hostname)
- # return the driver that provides the firmware version
- def _port_interaction(self, command, port_number):
- pass
+ def handle(self, request, port_number, delay=0):
+ logging.debug("Driving PDU: %s PORT: %s REQUEST: %s (delay %s)" %(self.hostname,port_number,request,delay))
+ if request == "reboot":
+ self.port_off(port_number)
+ time.sleep(delay)
+ self.port_on(port_number)
+ elif request == "on":
+ self.port_on(port_number)
+ elif request == "off":
+ self.port_off(port_number)
+ else:
+ logging.debug("Unknown request to handle - oops")
+ raise
- def _pdu_logout(self):
- pass
+ #def _port_interaction(self, command, port_number):
+ # super(PDUDriver, self).port_interaction(command,port_number)
def port_on(self, port_number):
- self._port_interaction("on", port_number)
+ self.port_interaction("on", port_number)
def port_off(self, port_number):
- self._port_interaction("off", port_number)
\ No newline at end of file
+ self.port_interaction("off", port_number)
\ No newline at end of file
diff --git a/lavapdu/engine.py b/lavapdu/engine.py
index 7bcbfa7..47c04f7 100644
--- a/lavapdu/engine.py
+++ b/lavapdu/engine.py
@@ -31,80 +31,8 @@
driver = None
firmware_dict = {}
- def __init__(self, pdu_hostname, pdu_telnetport=23):
- self.exec_string = "/usr/bin/telnet %s %d" % (pdu_hostname, pdu_telnetport)
- logging.debug("Created new PDUEngine: %s" % self.exec_string)
- required_version = self._pdu_login("apc", "apc")
- logging.debug("Got firmware version: %s" % required_version)
- driver_list = self.load_all_modules_from_dir("drivers")
- for driver in driver_list:
- handled = []
- exec("handled = %s.Meta.handled_firmware" % driver)
- for firmware_value in handled:
- self.firmware_dict[firmware_value] = driver
-
- logging.debug("Firmware versions supported: %s" % self.firmware_dict)
- if self.firmware_dict[required_version]:
- driver = self.firmware_dict[required_version]
- logging.debug("Using driver %s for version: %s" % (driver, required_version))
- exec("self.driver = %s(self.connection)" % driver)
- else:
- self.driver = None
-
- def load_all_modules_from_dir(self, dirname):
- module_list = []
- for importer, package_name, _ in pkgutil.iter_modules([dirname]):
- full_package_name = '%s.%s' % (dirname, package_name)
- if full_package_name not in sys.modules and (not full_package_name == "%s.driver" % dirname):
- import_string = "global %s\nfrom %s import %s" % (package_name,full_package_name,package_name)
- exec (import_string)
- logging.debug(import_string)
- if (not full_package_name == "%s.driver" % dirname):
- module_list.append(package_name)
- return module_list
-
- def pduconnect(self):
- self.connection = self.get_connection(self.exec_string)
-
- def pduclose(self):
- logging.debug("Closing connection: %s" % self.connection)
- self.connection.close(True)
-
- def pdureconnect(self):
- self.pduclose()
- self.pduconnect()
-
- def get_connection(self, exec_string):
- connection = pexpect.spawn(exec_string)
- #connection.logfile = sys.stdout
- return connection
-
- def is_busy(self):
- if os.path.exists("/proc/%i" % self.connection.pid):
- return True
- return False
-
- def close(self):
- self.driver._pdu_logout()
- self.firmware_dict = {}
- del(self)
-
- def _pdu_login(self, username, password):
- logging.debug("attempting login with username %s, password %s" % (username, password))
- self.pduconnect()
- self.connection.send("\r")
- self.connection.expect("User Name :")
- self.connection.send("apc\r")
- self.connection.expect("Password :")
- self.connection.send("apc\r")
- output = self.connection.read(250)
- #print "OUTPUT: %s" % output
- a = output.split("AOS")[1].split()[0]
- #print "A: %s" % a
- b = a.strip()
- #print "B: %s" % b
- version = b
- return version.strip()
+ def __init__(self, pdu_hostname):
+ pass
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
diff --git a/lavapdu/pdurunner.py b/lavapdu/pdurunner.py
index 8a83f12..d31b8fd 100644
--- a/lavapdu/pdurunner.py
+++ b/lavapdu/pdurunner.py
@@ -20,9 +20,8 @@
import logging
import time
-from engine import PDUEngine
from dbhandler import DBHandler
-
+import traceback
class PDURunner():
@@ -31,6 +30,7 @@
logging.getLogger().setLevel(config["logging_level"])
logging.getLogger().name = "PDURunner"
self.config = config
+ self.pdus = config["pdus"]
def get_one(self, db):
job = db.get_next_job()
@@ -38,51 +38,53 @@
job_id, hostname, port, request = job
logging.debug(job)
logging.info("Processing queue item: (%s %s) on hostname: %s" % (request, port, hostname))
- #logging.debug(id, hostname, request, port)
res = self.do_job(hostname, port, request)
db.delete_row(job_id)
else:
logging.debug("Found nothing to do in database")
- def do_job(self, hostname, port, request):
+ def driver_from_hostname(self, hostname):
+ logging.debug("Trying to find a driver for %s" % hostname)
+ logging.debug(self.pdus)
+ driver = self.pdus[hostname]["driver"]
+ logging.debug("Driver: %s" % driver)
+ module = __import__("drivers.%s" % driver.lower(), fromlist=[driver])
+ class_ = getattr(module, driver)
+ return class_(hostname)
+
+ def do_job(self, hostname, port, request, delay=0):
retries = 10
while retries > 0:
try:
- pe = PDUEngine(hostname, 23)
- if request == "on":
- pe.driver.port_on(port)
- return true
- elif request == "off":
- pe.driver.port_off(port)
- return true
- else:
- logging.debug("Unknown request type: %s" % request)
- return false
- pe.pduclose()
- del(pe)
- retries = 0
+ driver = self.driver_from_hostname(hostname)
+ return driver.handle(request, port, delay)
except Exception as e:
+ driver.cleanup()
+ logging.warn(traceback.format_exc())
logging.warn("Failed to execute job: %s %s %s (attempts left %i) error was %s" %
(hostname, port, request, retries, e.message))
- #logging.warn(e)
time.sleep(5)
retries -= 1
- return false
+ return False
def run_me(self):
logging.info("Starting up the PDURunner")
while 1:
- db = DBHandler(self.config)
+ db = DBHandler(self.config["settings"])
self.get_one(db)
db.close()
del(db)
time.sleep(2)
if __name__ == "__main__":
- starter = {"dbhost": "127.0.0.1",
+ starter = { "settings": {"dbhost": "127.0.0.1",
"dbuser": "pdudaemon",
"dbpass": "pdudaemon",
- "dbname": "lavapdu",
+ "dbname": "lavapdu"},
+ "pdus": { "pdu14": { "driver": "APC9218" },"pdu15": {"driver": "APC8959"} },
"logging_level": logging.DEBUG}
p = PDURunner(starter)
- p.run_me()
+ p.do_job("pdu15",18,"off",10)
+ p.do_job("pdu15",18,"reboot",10)
+ p.do_job("pdu15",18,"on",10)
+ #p.run_me()
diff --git a/lavapdu/socketserver.py b/lavapdu/socketserver.py
index 62551bc..2ba149c 100644
--- a/lavapdu/socketserver.py
+++ b/lavapdu/socketserver.py
@@ -28,12 +28,12 @@
class ListenerServer(object):
def __init__(self, config):
- self.server = TCPServer((config["hostname"], config["port"]), TCPRequestHandler)
+ self.server = TCPServer((config["settings"]["hostname"], config["settings"]["port"]), TCPRequestHandler)
logging.getLogger().name = "ListenerServer"
logging.getLogger().setLevel(config["logging_level"])
- logging.info("listening on %s:%s" % (config["hostname"], config["port"]))
- self.server.config = config
- self.db = DBHandler(config)
+ logging.info("listening on %s:%s" % (config["settings"]["hostname"], config["settings"]["port"]))
+ self.server.settings = config["settings"]
+ self.db = DBHandler(self.server.settings)
self.create_db()
self.db.close()
del(self.db)
@@ -86,9 +86,9 @@
self.queue_request(hostname,port,request,now)
def queue_request(self, hostname, port, request, exectime):
- db = DBHandler(self.server.config)
+ db = DBHandler(self.server.settings)
sql = "insert into pdu_queue (hostname,port,request,exectime)" \
- "values ('%s',%i,'%s')" % (hostname,port,request,exectime)
+ "values ('%s',%i,'%s',%i)" % (hostname,port,request,exectime)
db.do_sql(sql)
db.close()
del(db)
@@ -109,7 +109,8 @@
self.insert_request(data)
self.request.sendall("ack\n")
except Exception as e:
- logging.debug(e)
+ logging.debug(e.__class__)
+ logging.debug(e.message)
self.request.sendall("nack\n")
self.request.close()
diff --git a/setup.py b/setup.py
index 577345f..a74ae5f 100644
--- a/setup.py
+++ b/setup.py
@@ -23,7 +23,7 @@
setup(
name='lavapdu',
- version="0.0.3",
+ version="0.0.4",
author="Matthew Hart",
author_email="matthew.hart@linaro.org",
license="GPL2+",