lavapdu-0.0.5/0000755000175000017500000000000012545042476013061 5ustar neilneil00000000000000lavapdu-0.0.5/setup.cfg0000644000175000017500000000007312545042476014702 0ustar neilneil00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 lavapdu-0.0.5/PKG-INFO0000644000175000017500000000033612545042476014160 0ustar neilneil00000000000000Metadata-Version: 1.0 Name: lavapdu Version: 0.0.5 Summary: LAVA PDU Deamon for APC PDU's Home-page: UNKNOWN Author: Matthew Hart Author-email: matthew.hart@linaro.org License: GPL2+ Description: UNKNOWN Platform: UNKNOWN lavapdu-0.0.5/etc/0000755000175000017500000000000012545042476013634 5ustar neilneil00000000000000lavapdu-0.0.5/etc/lavapdu-listen.init0000644000175000017500000000707512455032104017445 0ustar neilneil00000000000000#!/bin/sh ### BEGIN INIT INFO # Provides: lavapdu-listen # Required-Start: $remote_fs $network postgresql # Required-Stop: $remote_fs $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: LAVA PDU Listener # Description: TCP Listening daemon to accept PDU requests ### END INIT INFO # Author: Matthew Hart LOGFILE="--logfile /var/log/lavapdu-listener.log" LOGLEVEL="--loglevel=INFO" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="lavapdu-listen" # short description NAME=lavapdu-listen # short server's name (truncated for 15 chars) DAEMON=/usr/sbin/lavapdu-listen # server's location DAEMON_ARGS="$LOGLEVEL" # Arguments to run the daemon with PIDFILE=/var/run/$DESC.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x $DAEMON ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables #. /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS \ || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac lavapdu-0.0.5/etc/lavapdu-runner.service0000644000175000017500000000032412545042174020153 0ustar neilneil00000000000000[Unit] Description=Runner daemon to process PDU requests After=postgresql.service [Service] ExecStart=/usr/sbin/lavapdu-runner Type=forking PIDFile=/var/run/lavapdu-runner.pid [Install] WantedBy=network.target lavapdu-0.0.5/etc/lavapdu-listen.service0000644000175000017500000000033212545042251020133 0ustar neilneil00000000000000[Unit] Description=TCP Listening daemon to accept PDU requests After=postgresql.service [Service] ExecStart=/usr/sbin/lavapdu-listen Type=forking PIDFile=/var/run/lavapdu-listen.pid [Install] WantedBy=network.target lavapdu-0.0.5/etc/lavapdu-runner.init0000644000175000017500000000706312455032104017455 0ustar neilneil00000000000000#!/bin/sh ### BEGIN INIT INFO # Provides: lavapdu-runner # Required-Start: $remote_fs $network postgresql # Required-Stop: $remote_fs $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: LAVA PDU Runner # Description: Runner daemon to process PDU requests ### END INIT INFO # Author: Matthew Hart LOGFILE="--logfile /var/log/lavapdu-runner.log" LOGLEVEL="--loglevel=INFO" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="lavapdu-runner" # short description NAME=lavapdu-runner # short server's name (truncated for 15 chars) DAEMON=/usr/sbin/lavapdu-runner # server's location DAEMON_ARGS="$LOGLEVEL" # Arguments to run the daemon with PIDFILE=/var/run/$DESC.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x $DAEMON ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables #. /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.0-6) to ensure that this file is present. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS \ || return 2 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac lavapdu-0.0.5/etc/lavapdu/0000755000175000017500000000000012545042476015270 5ustar neilneil00000000000000lavapdu-0.0.5/etc/lavapdu/lavapdu.conf0000644000175000017500000000131312475036233017565 0ustar neilneil00000000000000{ "daemon": { "hostname": "0.0.0.0", "port": 16421, "dbhost": "127.0.0.1", "dbuser": "pdudaemon", "dbpass": "pdudaemon", "dbname": "lavapdu", "retries": 5, "logging_level": "INFO" }, "pdus": { "192.168.10.2": { "driver": "apc9210" }, "192.168.10.3": { "driver": "apc7952", "telnetport": 5023 }, "192.168.10.4": { "driver": "apc7952" }, "192.168.10.5": { "driver": "apc8959", "this": "that", "something": "else" }, "192.168.25.52": { "driver": "apc7952" } } } lavapdu-0.0.5/etc/lavapdulogrotate0000644000175000017500000000036412264737663017146 0ustar neilneil00000000000000/var/log/lavapdu-listener.log { weekly rotate 12 compress delaycompress missingok notifempty create 644 root root } /var/log/lavapdu-runner.log { weekly rotate 12 compress delaycompress missingok notifempty create 644 root root }lavapdu-0.0.5/setup.py0000644000175000017500000000320412545042400014555 0ustar neilneil00000000000000#! /usr/bin/env python # # Copyright (C) 2013 Linaro Limited # # Author: Matthew Hart # # This file is part of PDUDAEMON. # # PDUDAEMON 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. # # PDUDAEMON 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, see . from setuptools import setup, find_packages setup( name='lavapdu', version="0.0.5", author="Matthew Hart", author_email="matthew.hart@linaro.org", license="GPL2+", description="LAVA PDU Deamon for APC PDU's", packages=find_packages(), install_requires=[ "daemon", "lockfile", "pexpect", "psycopg2" ], data_files=[ ("/etc/init.d/", ["etc/lavapdu-runner.init"]), ("/etc/init.d/", ["etc/lavapdu-listen.init"]), ("/usr/share/lavapdu/", [ "etc/lavapdu-listen.service", "etc/lavapdu-runner.service" ]), ("/etc/lavapdu/", ["etc/lavapdu/lavapdu.conf"]), ("/etc/logrotate.d/", ["etc/lavapdulogrotate"]), ], scripts=[ 'lavapdu-runner', 'lavapdu-listen', 'pduclient' ], zip_safe=False, include_package_data=True) lavapdu-0.0.5/pduclient0000755000175000017500000000570512474655603015010 0ustar neilneil00000000000000#!/usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 socket import optparse if __name__ == '__main__': usage = "Usage: %prog --daemon deamonhostname --hostname pduhostname --port pduportnum --command pducommand" description = "LAVA PDU daemon client" commands = ["reboot", "on", "off"] parser = optparse.OptionParser(usage=usage, description=description) parser.add_option("--daemon", dest="pdudaemonhostname", action="store", type="string", help="LAVAPDU Daemon hostname (ex: localhost)") parser.add_option("--hostname", dest="pduhostname", action="store", type="string", help="PDU Hostname (ex: pdu05)") parser.add_option("--port", dest="pduportnum", action="store", type="string", help="PDU Portnumber (ex: 04)") parser.add_option("--command", dest="pducommand", action="store", type="string", help="PDU command (ex: reboot|on|off)") parser.add_option("--delay", dest="pdudelay", action="store", type="int", help="Delay before command runs, or between off/on when rebooting (ex: 5)") (options, args) = parser.parse_args() if (not (options.pdudaemonhostname) or not(options.pduhostname) or not (options.pduportnum) or not (options.pducommand)): print("Missing option, try -h for help") exit(1) if not (options.pducommand in commands): print("Unknown pdu command: %s" % options.pducommand) exit(1) if options.pdudelay: string = ("%s %s %s %s" % (options.pduhostname, options.pduportnum, options.pducommand, options.pdudelay)) else: string = ("%s %s %s" % (options.pduhostname, options.pduportnum, options.pducommand)) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #sock.setblocking(0) # optional non-blocking reply = "" try: sock.connect((options.pdudaemonhostname, 16421)) sock.send(string) reply = sock.recv(16384).strip() # limit reply to 16K sock.close() except Exception: print ("Error sending command, wrong daemon hostname?") exit(1) if reply == "ack": print("Command sent successfully.") exit(0) else: print("Unknown error sending command! %s replied: %s" % (options.pdudaemonhostname, reply)) exit(127) lavapdu-0.0.5/MANIFEST.in0000644000175000017500000000030412545042465014612 0ustar neilneil00000000000000include etc/lavapdu/lavapdu.conf include etc/lavapdu-runner.init include etc/lavapdu-listen.init include etc/lavapdu-runner.service include etc/lavapdu-listen.service include etc/lavapdulogrotate lavapdu-0.0.5/lavapdu.egg-info/0000755000175000017500000000000012545042476016207 5ustar neilneil00000000000000lavapdu-0.0.5/lavapdu.egg-info/not-zip-safe0000644000175000017500000000000112277434153020434 0ustar neilneil00000000000000 lavapdu-0.0.5/lavapdu.egg-info/PKG-INFO0000644000175000017500000000033612545042476017306 0ustar neilneil00000000000000Metadata-Version: 1.0 Name: lavapdu Version: 0.0.5 Summary: LAVA PDU Deamon for APC PDU's Home-page: UNKNOWN Author: Matthew Hart Author-email: matthew.hart@linaro.org License: GPL2+ Description: UNKNOWN Platform: UNKNOWN lavapdu-0.0.5/lavapdu.egg-info/SOURCES.txt0000644000175000017500000000127112545042476020074 0ustar neilneil00000000000000MANIFEST.in lavapdu-listen lavapdu-runner pduclient setup.py etc/lavapdu-listen.init etc/lavapdu-listen.service etc/lavapdu-runner.init etc/lavapdu-runner.service etc/lavapdulogrotate etc/lavapdu/lavapdu.conf lavapdu/__init__.py lavapdu/dbhandler.py lavapdu/pdurunner.py lavapdu/socketserver.py lavapdu.egg-info/PKG-INFO lavapdu.egg-info/SOURCES.txt lavapdu.egg-info/dependency_links.txt lavapdu.egg-info/not-zip-safe lavapdu.egg-info/requires.txt lavapdu.egg-info/top_level.txt lavapdu/drivers/__init__.py lavapdu/drivers/apc7952.py lavapdu/drivers/apc8959.py lavapdu/drivers/apc9210.py lavapdu/drivers/apc9218.py lavapdu/drivers/apcbase.py lavapdu/drivers/driver.py lavapdu/drivers/strategies.pylavapdu-0.0.5/lavapdu.egg-info/top_level.txt0000644000175000017500000000001012545042476020730 0ustar neilneil00000000000000lavapdu lavapdu-0.0.5/lavapdu.egg-info/dependency_links.txt0000644000175000017500000000000112545042476022255 0ustar neilneil00000000000000 lavapdu-0.0.5/lavapdu.egg-info/requires.txt0000644000175000017500000000004112545042476020602 0ustar neilneil00000000000000daemon lockfile pexpect psycopg2 lavapdu-0.0.5/lavapdu-listen0000755000175000017500000001041412545030607015730 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 json import os import sys import optparse from logging.handlers import WatchedFileHandler import daemon try: import daemon.pidlockfile as pidlockfile except ImportError: from lockfile import pidlockfile from lavapdu.socketserver import ListenerServer def getDaemonLogger(filePath, log_format=None, loglevel=logging.INFO): logger = logging.getLogger() logger.setLevel(loglevel) try: watchedHandler = WatchedFileHandler(filePath) except Exception as e: return e watchedHandler.setFormatter(logging.Formatter(log_format or '%(asctime)s %(msg)s')) logger.addHandler(watchedHandler) return logger, watchedHandler def readSettings(filename): """ Read settings from config file, to listen to all hosts, hostname should be 0.0.0.0 """ #settings = {} print("Reading settings from %s" % conffile) with open(filename) as stream: jobdata = stream.read() json_data = json.loads(jobdata) return json_data 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-listen.pid" logfile = "/var/log/lavapdu-listener.log" 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 parser = optparse.OptionParser(usage=usage, description=description) parser.add_option("--logfile", dest="logfile", action="store", type="string", help="log file [%s]" % logfile) parser.add_option("--loglevel", dest="loglevel", action="store", type="string", help="logging level [INFO]") (options, args) = parser.parse_args() if options.logfile: if os.path.exists(os.path.dirname(options.logfile)): logfile = options.logfile else: print "No such directory for specified logfile '%s'" % logfile open(logfile, 'w').close() level = logging.DEBUG settings = settings["daemon"] if settings["logging_level"] == "DEBUG": level = logging.DEBUG if settings["logging_level"] == "WARNING": level = logging.WARNING if settings["logging_level"] == "ERROR": level = logging.ERROR if settings["logging_level"] == "INFO": level = logging.INFO client_logger, watched_file_handler = getDaemonLogger(logfile, loglevel=level, log_format='%(asctime)s:%(levelname)s:%(name)s:%(message)s') if isinstance(client_logger, Exception): print("Fatal error creating client_logger: " + str(client_logger)) sys.exit(os.EX_OSERR) # noinspection PyArgumentList lockfile = pidlockfile.PIDLockFile(pidfile) if lockfile.is_locked(): logging.error("PIDFile %s already locked" % pidfile) sys.exit(os.EX_OSERR) context = daemon.DaemonContext( detach_process=True, working_directory=os.getcwd(), pidfile=lockfile, files_preserve=[watched_file_handler.stream], stderr=watched_file_handler.stream, stdout=watched_file_handler.stream) with context: logging.info("Running LAVA PDU Listener %s %s %d." % (logfile, settings['hostname'], settings['port'])) ListenerServer(settings).start() lavapdu-0.0.5/lavapdu-runner0000755000175000017500000001046412545030354015747 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 json import os import sys import optparse from logging.handlers import WatchedFileHandler import daemon try: import daemon.pidlockfile as pidlockfile except ImportError: from lockfile import pidlockfile from lavapdu.pdurunner import PDURunner def getDaemonLogger(filePath, log_format=None, loglevel=logging.INFO): logger = logging.getLogger() logger.setLevel(loglevel) try: watchedHandler = WatchedFileHandler(filePath) except Exception as e: return e watchedHandler.setFormatter(logging.Formatter(log_format or '%(asctime)s %(msg)s')) logger.addHandler(watchedHandler) return logger, watchedHandler def readSettings(filename): """ Read settings from config file, to listen to all hosts, hostname should be 0.0.0.0 """ pdus = {} settings = {} print("Reading settings from %s" % conffile) with open(filename) as stream: jobdata = stream.read() json_data = json.loads(jobdata) return json_data 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/lavapdu.conf" settings = 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) parser.add_option("--logfile", dest="logfile", action="store", type="string", help="log file [%s]" % logfile) parser.add_option("--loglevel", dest="loglevel", action="store", type="string", help="logging level [INFO]") (options, args) = parser.parse_args() if options.logfile: if os.path.exists(os.path.dirname(options.logfile)): logfile = options.logfile else: print "No such directory for specified logfile '%s'" % logfile open(logfile, 'w').close() level = logging.DEBUG daemon_settings = settings["daemon"] if daemon_settings["logging_level"] == "DEBUG": level = logging.DEBUG if daemon_settings["logging_level"] == "WARNING": level = logging.WARNING if daemon_settings["logging_level"] == "ERROR": level = logging.ERROR if daemon_settings["logging_level"] == "INFO": level = logging.INFO client_logger, watched_file_handler = getDaemonLogger(logfile, loglevel=level, log_format='%(asctime)s:%(levelname)s:%(name)s:%(message)s') if isinstance(client_logger, Exception): print("Fatal error creating client_logger: " + str(client_logger)) sys.exit(os.EX_OSERR) # noinspection PyArgumentList lockfile = pidlockfile.PIDLockFile(pidfile) if lockfile.is_locked(): logging.error("PIDFile %s already locked" % pidfile) sys.exit(os.EX_OSERR) context = daemon.DaemonContext( detach_process=True, working_directory=os.getcwd(), pidfile=lockfile, files_preserve=[watched_file_handler.stream], stderr=watched_file_handler.stream, stdout=watched_file_handler.stream) with context: logging.info("Running LAVA PDU Runner %s dbhost: %s" % (logfile, settings["daemon"]["dbhost"])) p = PDURunner(settings) p.run_me() lavapdu-0.0.5/lavapdu/0000755000175000017500000000000012545042476014515 5ustar neilneil00000000000000lavapdu-0.0.5/lavapdu/dbhandler.py0000644000175000017500000000551512474655603017023 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 psycopg2 import time class DBHandler(object): def __init__(self, config): logging.debug("Creating new DBHandler: %s" % config["dbhost"]) logging.getLogger().name = "DBHandler" self.conn = psycopg2.connect(database=config["dbname"], user=config["dbuser"], password=config["dbpass"], host=config["dbhost"]) self.cursor = self.conn.cursor() def do_sql(self, sql): logging.debug("executing sql: %s" % sql) self.cursor.execute(sql) self.conn.commit() def do_sql_with_fetch(self, sql): logging.debug("executing sql: %s" % sql) self.cursor.execute(sql) row = self.cursor.fetchone() self.conn.commit() return row def create_db(self): logging.info("Creating db table if it doesn't exist") sql = "create table if not exists pdu_queue (id serial, hostname " \ "text, port int, request text, exectime int)" self.cursor.execute(sql) self.conn.commit() sql = "select column_name from information_schema.columns where " \ "table_name='pdu_queue' and column_name='exectime'" self.cursor.execute(sql) res = self.cursor.fetchone() if not res: logging.info("Old db schema discovered, upgrading") sql = "alter table pdu_queue add column exectime int default 1" self.cursor.execute(sql) self.conn.commit() def delete_row(self, row_id): logging.debug("deleting row %i" % row_id) self.do_sql("delete from pdu_queue where id=%i" % row_id) def get_res(self, sql): return self.cursor.execute(sql) def get_next_job(self): now = int(time.time()) row = self.do_sql_with_fetch("select id,hostname,port,request from pdu_queue where (exectime < %i or exectime is null) order by id asc limit 1" % now) return row def close(self): logging.debug("Closing DBHandler") self.cursor.close() self.conn.close()lavapdu-0.0.5/lavapdu/drivers/0000755000175000017500000000000012545042476016173 5ustar neilneil00000000000000lavapdu-0.0.5/lavapdu/drivers/apc9218.py0000644000175000017500000000465412475036233017641 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 from lavapdu.drivers.apc7952 import APC7952 class APC9218(APC7952): @classmethod def accepts(cls, drivername): if drivername == "apc9218": return True return False def _port_interaction(self, command, port_number): ### make sure in main menu here self._back_to_main() self.connection.send("\r") self.connection.expect("1- Device Manager") self.connection.expect("> ") logging.debug("Entering Device Manager") self.connection.send("1\r") self.connection.expect("------- Device Manager") logging.debug("Got to Device Manager") self._enter_outlet(port_number, False) res = self.connection.expect(["1- Control Outlet", "1- Outlet Control/Configuration"]) self.connection.expect("> ") self.connection.send("1\r") res = self.connection.expect(["> ", "Press to continue..."]) if res == 1: logging.debug("Stupid paging thingmy detected, pressing enter") self.connection.send("\r") self.connection.send("\r") res = self.connection.expect(["Control Outlet %s" % port_number, "Control Outlet"]) self.connection.expect("3- Immediate Reboot") self.connection.expect("> ") if command == "on": self.connection.send("1\r") self.connection.expect("Immediate On") self._do_it() elif command == "off": self.connection.send("2\r") self.connection.expect("Immediate Off") self._do_it() else: logging.debug("Unknown command!")lavapdu-0.0.5/lavapdu/drivers/apc9210.py0000644000175000017500000000423612474655603017634 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 from lavapdu.drivers.apc7952 import APC7952 class APC9210(APC7952): @classmethod def accepts(cls, drivername): if drivername == "apc9210": return True return False def _port_interaction(self, command, port_number): print("Attempting command: %s port: %i" % (command, port_number)) ### make sure in main menu here self._back_to_main() self.connection.send("\r") self.connection.expect("1- Outlet Manager") self.connection.expect("> ") logging.debug("Entering Outlet Manager") self.connection.send("1\r") self.connection.expect("------- Outlet Manager") logging.debug("Got to Device Manager") self._enter_outlet(port_number, False) self.connection.expect(["1- Control of Outlet", "1- Outlet Control/Configuration"]) self.connection.expect("> ") self.connection.send("1\r") self.connection.expect("Turn Outlet On") self.connection.expect("> ") if command == "on": self.connection.send("1\r") self.connection.expect("Turn Outlet On") self._do_it() elif command == "off": self.connection.send("2\r") self.connection.expect("Turn Outlet Off") self._do_it() else: logging.debug("Unknown command!")lavapdu-0.0.5/lavapdu/drivers/strategies.py0000644000175000017500000000174412474655603020730 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 lavapdu.drivers.apc7952 import APC7952 from lavapdu.drivers.apc9218 import APC9218 from lavapdu.drivers.apc8959 import APC8959 from lavapdu.drivers.apc9210 import APC9210lavapdu-0.0.5/lavapdu/drivers/__init__.py0000644000175000017500000000146312474655603020313 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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.lavapdu-0.0.5/lavapdu/drivers/driver.py0000644000175000017500000000536712474655603020056 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 class PDUDriver(object): connection = None hostname = "" def __init__(self): super(PDUDriver, self).__init__() @classmethod def select(cls, drivername): logging.debug("adding PDUDriver subclasses: %s" % cls.__subclasses__()) candidates = cls.__subclasses__() # pylint: disable=no-member for subc in cls.__subclasses__(): logging.debug("adding %s subclasses: %s" % (subc,subc.__subclasses__())) candidates = candidates + (subc.__subclasses__()) for subsubc in subc.__subclasses__(): logging.debug("adding %s subclasses: %s" % (subsubc,subsubc.__subclasses__())) candidates = candidates + (subsubc.__subclasses__()) logging.debug(candidates) willing = [c for c in candidates if c.accepts(drivername)] if len(willing) == 0: raise NotImplementedError( "No driver accepted the request " "'%s' with the specified job parameters. %s" % (drivername, cls) ) logging.debug("%s accepted the request" % willing[0]) return willing[0] def handle(self, request, port_number, delay=0): logging.debug("Driving PDU hostname: %s PORT: %s REQUEST: %s (delay %s)" %(self.hostname,port_number,request,delay)) if request == "on": self.port_on(port_number) elif request == "off": self.port_off(port_number) else: logging.debug("Unknown request to handle - oops") raise NotImplementedError( "Driver doesn't know how to %s " % (request) ) self._cleanup() #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) def port_off(self, port_number): self.port_interaction("off", port_number)lavapdu-0.0.5/lavapdu/drivers/apcbase.py0000644000175000017500000000500512474655603020146 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 lavapdu.drivers.driver import PDUDriver import sys class APCBase(PDUDriver): connection = None def __init__(self, hostname, settings): self.hostname = hostname logging.debug(settings) self.settings = settings telnetport = 23 if "telnetport" in settings: telnetport = settings["telnetport"] self.exec_string = "/usr/bin/telnet %s %d" % (hostname, telnetport) self.get_connection() super(APCBase, self).__init__() @classmethod def accepts(cls, drivername): return False 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) if logging.getLogger().getEffectiveLevel() == logging.DEBUG: self.connection = pexpect.spawn(self.exec_string, logfile=sys.stdout) else: self.connection = pexpect.spawn(self.exec_string) self._pdu_login("apc","apc") def _cleanup(self): self._pdu_logout() def _bombout(self): logging.debug("Bombing out of driver: %s" % self.connection) self.connection.close(force=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) lavapdu-0.0.5/lavapdu/drivers/apc7952.py0000644000175000017500000000721112474655603017643 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 from lavapdu.drivers.apcbase import APCBase class APC7952(APCBase): @classmethod def accepts(cls, drivername): if drivername == "apc7952": return True return False def _pdu_logout(self): self._back_to_main() logging.debug("Logging out") self.connection.send("4\r") 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") self.connection.send("\r") res = self.connection.expect(["4- Logout", "> "]) if res == 0: logging.debug("Back at main menu") break def _enter_outlet(self, outlet, enter_needed=True): outlet = "%s" % outlet logging.debug("Attempting to enter outlet %s", outlet) if (enter_needed): self.connection.expect("Press to continue...") logging.debug("Sending enter") self.connection.send("\r") self.connection.expect("> ") logging.debug("Sending outlet number") self.connection.send(outlet) self.connection.send("\r") logging.debug("Finished entering outlet") def _port_interaction(self, command, port_number): print("Attempting command: %s port: %i" % (command, port_number)) ### make sure in main menu here self._back_to_main() self.connection.send("\r") self.connection.expect("1- Device Manager") self.connection.expect("> ") logging.debug("Entering Device Manager") self.connection.send("1\r") self.connection.expect("------- Device Manager") self.connection.send("2\r") res = self.connection.expect("1- Outlet Control/Configuration") self.connection.expect("> ") self.connection.send("1\r") self._enter_outlet(port_number, False) self.connection.expect("> ") self.connection.send("1\r") res = self.connection.expect(["> ", "Press to continue..."]) if res == 1: logging.debug("Stupid paging thingmy detected, pressing enter") self.connection.send("\r") self.connection.send("\r") if command == "on": self.connection.send("1\r") self.connection.expect("Immediate On") self._do_it() elif command == "off": self.connection.send("2\r") self.connection.expect("Immediate Off") self._do_it() else: logging.debug("Unknown command!") def _do_it(self): self.connection.expect("Enter 'YES' to continue or to cancel :") self.connection.send("YES\r") self.connection.expect("Press to continue...") self.connection.send("\r")lavapdu-0.0.5/lavapdu/drivers/apc8959.py0000644000175000017500000000346612474655603017663 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 from lavapdu.drivers.apcbase import APCBase class APC8959(APCBase): pdu_commands = {"off": "olOff", "on": "olOn"} # def __init__(self, hostname): # super(APC8959, self).__init__(hostname) @classmethod def accepts(cls, drivername): if drivername == "apc8959": return True return False def _pdu_logout(self): logging.debug("logging out") self.connection.send("\r") self.connection.send("exit") self.connection.send("\r") logging.debug("done") def _pdu_get_to_prompt(self): self.connection.send("\r") self.connection.expect('apc>') def _port_interaction(self, command, port_number): logging.debug("Attempting %s on port %i" % (command, port_number)) self._pdu_get_to_prompt() self.connection.sendline(self.pdu_commands[command] + (" %i" % port_number)) self.connection.expect("E000: Success") self._pdu_get_to_prompt() logging.debug("done")lavapdu-0.0.5/lavapdu/socketserver.py0000644000175000017500000001130112475036233017576 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 SocketServer import logging import socket import time import json from lavapdu.dbhandler import DBHandler class ListenerServer(object): def __init__(self, settings): listen_host = settings["hostname"] listen_port = settings["port"] logging.getLogger().name = "ListenerServer" logging.getLogger().setLevel(settings["logging_level"]) logging.debug("ListenerServer __init__") logging.info("listening on %s:%s", listen_host, listen_port) self.server = TCPServer((listen_host, listen_port), TCPRequestHandler) self.server.settings = settings dbh = DBHandler(settings) dbh.create_db() dbh.close() del dbh def start(self): logging.info("Starting the ListenerServer") self.server.serve_forever() class TCPRequestHandler(SocketServer.BaseRequestHandler): #"One instance per connection. Override handle(self) to customize action." def insert_request(self, data): logging.getLogger().name = "TCPRequestHandler" logging.getLogger().setLevel(self.server.settings["logging_level"]) array = data.split(" ") delay = 10 custom_delay = False now = int(time.time()) if (len(array) < 3) or (len(array) > 4): logging.info("Wrong data size") raise Exception("Unexpected data") if len(array) == 4: delay = int(array[3]) custom_delay = True hostname = array[0] port = int(array[1]) request = array[2] if not (request in ["reboot", "on", "off"]): logging.info("Unknown request: %s", request) raise Exception("Unknown request: %s", request) if request == "reboot": logging.debug("reboot requested, submitting off/on") self.queue_request(hostname, port, "off", now) self.queue_request(hostname, port, "on", now+delay) else: if custom_delay: logging.debug("using delay as requested") self.queue_request(hostname, port, request, now+delay) else: self.queue_request(hostname, port, request, now) def queue_request(self, hostname, port, request, exectime): dbhandler = DBHandler(self.server.settings) sql = "insert into pdu_queue (hostname,port,request,exectime) " \ "values ('%s',%i,'%s',%i)" % (hostname, port, request, exectime) dbhandler.do_sql(sql) dbhandler.close() del dbhandler def handle(self): logging.getLogger().name = "TCPRequestHandler" request_ip = self.client_address[0] try: data = self.request.recv(4096).strip() socket.setdefaulttimeout(2) try: request_host = socket.gethostbyaddr(request_ip)[0] except socket.herror as e: #pylint: disable=invalid-name #logging.debug("Unable to resolve: %s error: %s" % (ip,e)) request_host = request_ip logging.info("Received a request from %s: '%s'", request_host, data) self.insert_request(data) self.request.sendall("ack\n") except Exception as e: #pylint: disable=invalid-name logging.debug(e.__class__) logging.debug(e.message) self.request.sendall("nack\n") self.request.close() class TCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): allow_reuse_address = True daemon_threads = True #pass if __name__ == "__main__": logging.basicConfig(level=logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG) logging.debug("Executing from __main__") filename = "/etc/lavapdu/lavapdu.conf" print("Reading settings from %s" % filename) with open(filename) as stream: jobdata = stream.read() json_data = json.loads(jobdata) ss = ListenerServer(json_data["daemon"]) ss.start() lavapdu-0.0.5/lavapdu/__init__.py0000644000175000017500000000146412474655603016636 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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. lavapdu-0.0.5/lavapdu/pdurunner.py0000644000175000017500000000706512474655603017124 0ustar neilneil00000000000000#! /usr/bin/python # Copyright 2013 Linaro Limited # Author Matt Hart # # 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 time import json import traceback from lavapdu.dbhandler import DBHandler from lavapdu.drivers.driver import PDUDriver import lavapdu.drivers.strategies class PDURunner(object): def __init__(self, config): self.pdus = config["pdus"] self.settings = config["daemon"] logging.basicConfig(level=self.settings["logging_level"]) logging.getLogger().setLevel(self.settings["logging_level"]) logging.getLogger().name = "PDURunner" def get_one(self, db): job = db.get_next_job() if job: job_id, hostname, port, request = job logging.debug(job) logging.info("Processing queue item: (%s %s) on hostname: %s" % (request, port, hostname)) res = self.do_job(hostname, port, request) db.delete_row(job_id) else: logging.debug("Found nothing to do in database") def driver_from_hostname(self, hostname): logging.debug("Trying to find a driver for hostname %s" % hostname) logging.debug(self.pdus) if hostname in self.pdus: drivername = (self.pdus[hostname]["driver"]) else: raise NotImplementedError("No configuration available for hostname %s\n" "Is there a section in the lavapdu.conf?" % hostname) logging.debug("Config file wants driver: %s" % drivername) driver = PDUDriver.select(drivername)(hostname, self.pdus[hostname]) return driver def do_job(self, hostname, port, request, delay=0): retries = self.settings["retries"] driver = False while retries > 0: try: driver = self.driver_from_hostname(hostname) return driver.handle(request, port, delay) except Exception as e: 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)) if driver: #driver._cleanup() driver._bombout() time.sleep(5) retries -= 1 return False def run_me(self): logging.info("Starting up the PDURunner") while 1: db = DBHandler(self.settings) self.get_one(db) db.close() del(db) time.sleep(2) if __name__ == "__main__": settings = {} filename = "/etc/lavapdu/lavapdu.conf" print("Reading settings from %s" % filename) with open(filename) as stream: jobdata = stream.read() json_data = json.loads(jobdata) p = PDURunner(json_data) #p.do_job("192.168.10.5",18,"reboot",2) p.run_me()