summaryrefslogtreecommitdiff
path: root/lavaproxy
diff options
context:
space:
mode:
authorMatt Hart <matthew.hart@linaro.org>2014-04-18 17:43:41 +0100
committerMatt Hart <matthew.hart@linaro.org>2014-04-18 17:43:41 +0100
commitffb5edd271230606407c5ebe4c708cd637ea7436 (patch)
tree4183ac39b7e348a660fcae2ce7e134e1a3889f03 /lavaproxy
parentbc8b057384ebc289f6f708818c78690b4c4d36d4 (diff)
Renamed folder and cut down socketserver.py to remove the lavapdu specific stuff
Diffstat (limited to 'lavaproxy')
-rw-r--r--lavaproxy/__init__.py22
-rw-r--r--lavaproxy/apcdrivers.py168
-rw-r--r--lavaproxy/driver.py27
-rw-r--r--lavaproxy/engine.py111
-rw-r--r--lavaproxy/pdurunner.py85
-rw-r--r--lavaproxy/proxyexample.py98
-rw-r--r--lavaproxy/socketserver.py80
7 files changed, 591 insertions, 0 deletions
diff --git a/lavaproxy/__init__.py b/lavaproxy/__init__.py
new file mode 100644
index 0000000..9b73b54
--- /dev/null
+++ b/lavaproxy/__init__.py
@@ -0,0 +1,22 @@
+#! /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 pdurunner
+import socketserver
diff --git a/lavaproxy/apcdrivers.py b/lavaproxy/apcdrivers.py
new file mode 100644
index 0000000..0dad9b6
--- /dev/null
+++ b/lavaproxy/apcdrivers.py
@@ -0,0 +1,168 @@
+#! /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
+
+from driver import PDUDriver
+
+
+class apc7952(PDUDriver):
+ 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.expect('>')
+ for i in range(1, 20):
+ #print("Sending escape character")
+ self.connection.send("\x1B")
+ self.connection.send("\r")
+ res = self.connection.expect(["4- Logout", "> "])
+ if res == 0:
+ logging.debug("Back at main menu")
+ break
+ #self.connection.send("\r")
+ #self.connection.expect("4- Logout")
+ #self.connection.expect("> ")
+
+ 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 <ENTER> 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")
+ res = self.connection.expect(["3- Outlet Control/Configuration", "2- Outlet Control", "2- Outlet Management", "------- Device Manager"])
+ logging.debug("Matched pattern %s", res)
+ if res == 0:
+ self.connection.send("3\r")
+ self._enter_outlet(port_number)
+ elif res == 1:
+ self.connection.send("2\r")
+ self._enter_outlet(port_number)
+ elif res == 2:
+ self.connection.send("2\r")
+ elif res == 3:
+ logging.debug("Matched ------- 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 <ENTER> 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"])
+ if res == 0:
+ logging.debug("Already at the right port")
+ else:
+ self.connection.send("%s\r" % port_number)
+ self.connection.send("1\r")
+ self.connection.expect("3- Immediate Reboot")
+ self.connection.expect("> ")
+ if command == "reboot":
+ self.connection.send("3\r")
+ self.connection.expect("Immediate Reboot")
+ self._do_it()
+ elif command == "delayed":
+ self.connection.send("6\r")
+ self.connection.expect("Delayed Reboot")
+ self._do_it()
+ elif 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 <ENTER> to cancel :")
+ self.connection.send("YES\r")
+ self.connection.expect("Press <ENTER> to continue...")
+ self.connection.send("\r")
+
+ def port_delayed(self, port_number):
+ self._port_interaction("delayed", 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)
+
+ def port_reboot(self, port_number):
+ self._port_interaction("reboot", port_number)
+
+
+class apc8959(PDUDriver):
+ connection = None
+ pdu_commands = {"off": "olOff", "on": "olOn", "reboot": "olReboot", "delayed": "olDlyReboot"}
+
+ 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")
+ logging.debug("done")
+
+ def port_delayed(self, port_number):
+ self._port_interaction("delayed", 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)
+
+ def port_reboot(self, port_number):
+ self._port_interaction("reboot", port_number)
diff --git a/lavaproxy/driver.py b/lavaproxy/driver.py
new file mode 100644
index 0000000..bd36c18
--- /dev/null
+++ b/lavaproxy/driver.py
@@ -0,0 +1,27 @@
+#! /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.
+
+
+class PDUDriver():
+ connection = None
+ pdu_commands = {"off": "olOff", "on": "olOn", "reboot": "olReboot", "delayed": "olDlyReboot"}
+
+ def __init__(self, connection):
+ self.connection = connection
diff --git a/lavaproxy/engine.py b/lavaproxy/engine.py
new file mode 100644
index 0000000..beb954f
--- /dev/null
+++ b/lavaproxy/engine.py
@@ -0,0 +1,111 @@
+#! /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 pexpect
+import os
+import logging
+import sys
+
+from apcdrivers import apc8959
+from apcdrivers import apc7952
+
+
+class PDUEngine():
+ connection = None
+ prompt = 0
+ driver = None
+
+ 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)
+ #self.connection.logfile_read = sys.stdout
+ prompt = self._pdu_login("apc", "apc")
+ if prompt == 0:
+ logging.debug("Found a v5 prompt")
+ self.driver = apc8959(self.connection)
+ elif prompt == 1:
+ logging.debug("Found a v3 prompt")
+ self.driver = apc7952(self.connection)
+ else:
+ logging.debug("Unknown prompt!")
+
+ def pduconnect(self):
+ self.connection = self.get_connection(self.exec_string)
+
+ def pduclose(self):
+ 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.connection.close(True)
+
+ 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")
+ return self.connection.expect(["apc>", ">"])
+
+
+if __name__ == "__main__":
+ #pe1 = PDUEngine("pdu15")
+ #pe1.driver.port_off(22)
+ #pe1.driver.port_on(22)
+ #pe1.close()
+ #pe2 = PDUEngine("pdu14")
+ #pe2.driver.port_off(6)
+ #pe2.driver.port_on(6)
+ #pe2.close()
+ #pe3 = PDUEngine("pdu01")
+ #pe3.driver.port_reboot(1)
+ #pe3.driver.port_off(1)
+ #pe3.driver.port_on(1)
+ #pe3.close()
+ logging.basicConfig(level=logging.DEBUG)
+ logging.getLogger().setLevel(logging.DEBUG)
+ pe4 = PDUEngine("192.168.1.153")
+ pe4.driver.port_reboot(1)
+ pe4.driver.port_reboot(2)
+ pe4.driver.port_reboot(3)
+ pe4.driver.port_reboot(4)
+ pe4.driver.port_reboot(5)
+ pe4.driver.port_reboot(6)
+ pe4.driver.port_reboot(7)
+ pe4.driver.port_reboot(8)
+ #pe4.driver.port_off(8)
+ #pe4.driver.port_on(8)
+ pe4.close()
diff --git a/lavaproxy/pdurunner.py b/lavaproxy/pdurunner.py
new file mode 100644
index 0000000..cc2b19d
--- /dev/null
+++ b/lavaproxy/pdurunner.py
@@ -0,0 +1,85 @@
+#! /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 time
+from engine import PDUEngine
+from socketserver import DBHandler
+
+
+class PDURunner():
+
+ def __init__(self, config):
+ logging.basicConfig(level=config["logging_level"])
+ logging.getLogger().setLevel(config["logging_level"])
+ logging.getLogger().name = "PDURunner"
+ self.config = config
+
+ def get_one(self, db):
+ job = db.get_next_job()
+ if job:
+ job_id, hostname, port, request = 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):
+ retries = 5
+ while retries > 0:
+ try:
+ pe = PDUEngine(hostname, 23)
+ if request == "reboot":
+ pe.driver.port_reboot(port)
+ elif request == "on":
+ pe.driver.port_on(port)
+ elif request == "off":
+ pe.driver.port_off(port)
+ elif request == "delayed":
+ pe.driver.port_delayed(port)
+ else:
+ logging.debug("Unknown request type: %s" % request)
+ pe.pduclose()
+ retries = 0
+ except:
+ logging.warn("Failed to execute job: %s %s %s (attempts left %i)" % (hostname, port, request, retries))
+ #logging.warn(e)
+ time.sleep(5)
+ retries -= 1
+
+ def run_me(self):
+ logging.info("Starting up the PDURunner")
+ while 1:
+ db = DBHandler(self.config)
+ self.get_one(db)
+ db.close()
+ del(db)
+ time.sleep(2)
+
+if __name__ == "__main__":
+ starter = {"dbhost": "127.0.0.1",
+ "dbuser": "pdudaemon",
+ "dbpass": "pdudaemon",
+ "dbname": "lavapdu",
+ "logging_level": logging.DEBUG}
+ p = PDURunner(starter)
+ p.run_me()
diff --git a/lavaproxy/proxyexample.py b/lavaproxy/proxyexample.py
new file mode 100644
index 0000000..e11a4a0
--- /dev/null
+++ b/lavaproxy/proxyexample.py
@@ -0,0 +1,98 @@
+__author__ = 'matt'
+
+#!/usr/bin/python
+# This is a simple port-forward / proxy, written using only the default python
+# library. If you want to make a suggestion or fix something you can contact-me
+# at voorloop_at_gmail.com
+# Distributed over IDC(I Don't Care) license
+import socket
+import select
+import time
+import sys
+
+# Changing the buffer_size and delay, you can improve the speed and bandwidth.
+# But when buffer get to high or delay go too down, you can broke things
+buffer_size = 4096
+delay = 0.0001
+forward_to = ('smtp.zaz.ufsk.br', 25)
+
+class Forward:
+ def __init__(self):
+ self.forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ def start(self, host, port):
+ try:
+ self.forward.connect((host, port))
+ return self.forward
+ except Exception, e:
+ print e
+ return False
+
+class TheServer:
+ input_list = []
+ channel = {}
+
+ def __init__(self, host, port):
+ self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.server.bind((host, port))
+ self.server.listen(200)
+
+ def main_loop(self):
+ self.input_list.append(self.server)
+ while 1:
+ time.sleep(delay)
+ ss = select.select
+ inputready, outputready, exceptready = ss(self.input_list, [], [])
+ for self.s in inputready:
+ if self.s == self.server:
+ self.on_accept()
+ break
+
+ self.data = self.s.recv(buffer_size)
+ if len(self.data) == 0:
+ self.on_close()
+ else:
+ self.on_recv()
+
+ def on_accept(self):
+ forward = Forward().start(forward_to[0], forward_to[1])
+ clientsock, clientaddr = self.server.accept()
+ if forward:
+ print clientaddr, "has connected"
+ self.input_list.append(clientsock)
+ self.input_list.append(forward)
+ self.channel[clientsock] = forward
+ self.channel[forward] = clientsock
+ else:
+ print "Can't establish connection with remote server.",
+ print "Closing connection with client side", clientaddr
+ clientsock.close()
+
+ def on_close(self):
+ print self.s.getpeername(), "has disconnected"
+ #remove objects from input_list
+ self.input_list.remove(self.s)
+ self.input_list.remove(self.channel[self.s])
+ out = self.channel[self.s]
+ # close the connection with client
+ self.channel[out].close() # equivalent to do self.s.close()
+ # close the connection with remote server
+ self.channel[self.s].close()
+ # delete both objects from channel dict
+ del self.channel[out]
+ del self.channel[self.s]
+
+ def on_recv(self):
+ data = self.data
+ # here we can parse and/or modify the data before send forward
+ print data
+ self.channel[self.s].send(data)
+
+if __name__ == '__main__':
+ server = TheServer('', 9090)
+ try:
+ server.main_loop()
+ except KeyboardInterrupt:
+ print "Ctrl C - Stopping server"
+ sys.exit(1) \ No newline at end of file
diff --git a/lavaproxy/socketserver.py b/lavaproxy/socketserver.py
new file mode 100644
index 0000000..a678207
--- /dev/null
+++ b/lavaproxy/socketserver.py
@@ -0,0 +1,80 @@
+#! /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 SocketServer
+import logging
+import socket
+
+class ListenerServer(object):
+ servers = []
+
+ def __init__(self, config):
+ logging.getLogger().name = "ManagementServer"
+ logging.getLogger().setLevel(config["logging_level"])
+ self.management_server = TCPServer((config["hostname"], config["mgmt-port"]), TCPRequestHandler)
+# for portnum in range(config["port-start"], config["port-end"]):
+# self.servers.append(TCPServer((config["hostname"], portnum), TCPRequestHandler))
+# logging.info("listening on %s:%s" % (config["hostname"], portnum))
+
+ def start(self):
+ logging.info("Starting the Management Server")
+ self.management_server.serve_forever()
+ # for server in self.servers:
+ # server.serve_forever()
+
+
+class TCPRequestHandler(SocketServer.BaseRequestHandler):
+ #"One instance per connection. Override handle(self) to customize action."
+ def handle(self):
+ logging.getLogger().name = "TCPRequestHandler"
+ ip = self.client_address[0]
+ logging.debug(self.client_address)
+ try:
+ data = self.request.recv(4096).strip()
+ socket.setdefaulttimeout(2)
+ try:
+ request_host = socket.gethostbyaddr(ip)[0]
+ except socket.herror as e:
+ logging.debug("Unable to resolve: %s error: %s" % (ip, e))
+ request_host = ip
+ logging.info("Received a request from %s: '%s'" % (request_host, data))
+ self.request.sendall("ack\n")
+ except Exception as e:
+ logging.debug(e)
+ 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__")
+ starter = {"hostname": "0.0.0.0",
+ "port-start": 40001,
+ "port-end": 41000,
+ "mgmt-port": 40000,
+ "logging_level": logging.DEBUG}
+ ss = ListenerServer(starter)
+ ss.start()