blob: 5a6011c1da72f07bca57a05e82a0ecc75cf2b7f3 [file] [log] [blame]
matthew.hart@linaro.org5e4fce92013-08-22 11:29:21 +01001#! /usr/bin/python
2
3# Copyright 2013 Linaro Limited
4# Author Matt Hart <matthew.hart@linaro.org>
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19# MA 02110-1301, USA.
20
Matt Hart1306d822013-08-09 12:08:22 +010021import SocketServer
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010022import psycopg2
Matt Hart1306d822013-08-09 12:08:22 +010023import logging
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010024import socket
Matt Hart1306d822013-08-09 12:08:22 +010025
Neil Williams16579dc2014-02-13 11:20:04 +000026
Matt Hart1499bd42013-08-20 11:35:46 +010027class DBHandler(object):
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010028 def __init__(self, config):
29 logging.debug("Creating new DBHandler: %s" % config["dbhost"])
Matt Hart40d6c312013-08-20 14:47:31 +010030 logging.getLogger().name = "DBHandler"
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010031 self.conn = psycopg2.connect(database=config["dbname"], user=config["dbuser"],
32 password=config["dbpass"], host=config["dbhost"])
Matt Hart1499bd42013-08-20 11:35:46 +010033 self.cursor = self.conn.cursor()
34
35 def do_sql(self, sql):
36 logging.debug("executing sql: %s" % sql)
37 self.cursor.execute(sql)
38 self.conn.commit()
39
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010040 def do_sql_with_fetch(self, sql):
41 logging.debug("executing sql: %s" % sql)
42 self.cursor.execute(sql)
43 row = self.cursor.fetchone()
44 self.conn.commit()
45 return row
46
47 def delete_row(self, row_id):
48 logging.debug("deleting row %i" % row_id)
49 self.do_sql("delete from pdu_queue where id=%i" % row_id)
50
Matt Hart63ed9112013-08-20 13:31:50 +010051 def get_res(self, sql):
52 return self.cursor.execute(sql)
53
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010054 def get_next_job(self):
55 row = self.do_sql_with_fetch("select * from pdu_queue order by id asc limit 1")
56 return row
Matt Hart63ed9112013-08-20 13:31:50 +010057
Matt Hart1499bd42013-08-20 11:35:46 +010058 def close(self):
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010059 logging.debug("Closing DBHandler")
Matt Hart1499bd42013-08-20 11:35:46 +010060 self.cursor.close()
61 self.conn.close()
62
63
64class ListenerServer(object):
Matt Hart1499bd42013-08-20 11:35:46 +010065
66 def __init__(self, config):
67 self.server = TCPServer((config["hostname"], config["port"]), TCPRequestHandler)
Matt Hart40d6c312013-08-20 14:47:31 +010068 logging.getLogger().name = "ListenerServer"
Matt Hart7d670612013-08-20 16:47:52 +010069 logging.getLogger().setLevel(config["logging_level"])
Matt Hart1499bd42013-08-20 11:35:46 +010070 logging.info("listening on %s:%s" % (config["hostname"], config["port"]))
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010071 self.server.config = config
72 self.db = DBHandler(config)
Matt Hart1306d822013-08-09 12:08:22 +010073 self.create_db()
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010074 self.db.close()
75 del(self.db)
Matt Hart1306d822013-08-09 12:08:22 +010076
77 def create_db(self):
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010078 sql = "create table if not exists pdu_queue (id serial, hostname text, port int, request text)"
Matt Hart1499bd42013-08-20 11:35:46 +010079 self.db.do_sql(sql)
Matt Hart1306d822013-08-09 12:08:22 +010080
81 def start(self):
Matt Hart1499bd42013-08-20 11:35:46 +010082 logging.info("Starting the ListenerServer")
Matt Hart1306d822013-08-09 12:08:22 +010083 self.server.serve_forever()
84
Matt Hart1499bd42013-08-20 11:35:46 +010085
Matt Hart1306d822013-08-09 12:08:22 +010086class TCPRequestHandler(SocketServer.BaseRequestHandler):
Matt Hart1499bd42013-08-20 11:35:46 +010087 #"One instance per connection. Override handle(self) to customize action."
Matt Hart1306d822013-08-09 12:08:22 +010088 def insert_request(self, data):
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010089 logging.getLogger().name = "TCPRequestHandler"
Matt Hart1306d822013-08-09 12:08:22 +010090 array = data.split(" ")
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010091 if len(array) != 3:
92 logging.info("Wrong data size")
93 raise Exception("Unexpected data")
Matt Hart1306d822013-08-09 12:08:22 +010094 hostname = array[0]
95 port = int(array[1])
96 request = array[2]
Neil Williams16579dc2014-02-13 11:20:04 +000097 if not (request in ["reboot", "on", "off", "delayed"]):
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010098 logging.info("Unknown request: %s" % request)
99 raise Exception("Unknown request: %s" % request)
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100100 db = DBHandler(self.server.config)
Neil Williams16579dc2014-02-13 11:20:04 +0000101 sql = "insert into pdu_queue (hostname,port,request) values ('%s',%i,'%s')" % (hostname, port, request)
Matt Hart1499bd42013-08-20 11:35:46 +0100102 db.do_sql(sql)
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100103 db.close()
104 del(db)
Matt Hart1306d822013-08-09 12:08:22 +0100105
106 def handle(self):
Matt Hart40d6c312013-08-20 14:47:31 +0100107 logging.getLogger().name = "TCPRequestHandler"
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000108 ip = self.client_address[0]
Matt Hart40d6c312013-08-20 14:47:31 +0100109 try:
110 data = self.request.recv(4096).strip()
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100111 socket.setdefaulttimeout(2)
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000112 try:
113 request_host = socket.gethostbyaddr(ip)[0]
114 except socket.herror as e:
Neil Williams16579dc2014-02-13 11:20:04 +0000115 logging.debug("Unable to resolve: %s error: %s" % (ip, e))
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000116 request_host = ip
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100117 logging.info("Received a request from %s: '%s'" % (request_host, data))
Matt Hart40d6c312013-08-20 14:47:31 +0100118 self.insert_request(data)
119 self.request.sendall("ack\n")
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100120 except Exception as e:
121 logging.debug(e)
Matt Hart40d6c312013-08-20 14:47:31 +0100122 self.request.sendall("nack\n")
Matt Hart1306d822013-08-09 12:08:22 +0100123 self.request.close()
124
Neil Williams16579dc2014-02-13 11:20:04 +0000125
Matt Hart1306d822013-08-09 12:08:22 +0100126class TCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
127 allow_reuse_address = True
128 daemon_threads = True
129 pass
130
131if __name__ == "__main__":
Matt Hart1499bd42013-08-20 11:35:46 +0100132 logging.basicConfig(level=logging.DEBUG)
Matt Hart63ed9112013-08-20 13:31:50 +0100133 logging.getLogger().setLevel(logging.DEBUG)
Matt Hart1499bd42013-08-20 11:35:46 +0100134 logging.debug("Executing from __main__")
135 starter = {"hostname": "0.0.0.0",
Neil Williams16579dc2014-02-13 11:20:04 +0000136 "port": 16421,
137 "dbhost": "127.0.0.1",
138 "dbuser": "pdudaemon",
139 "dbpass": "pdudaemon",
140 "dbname": "lavapdu",
Matt Hart96ca8662013-08-21 13:37:35 +0100141 "logging_level": logging.DEBUG}
Matt Hart1499bd42013-08-20 11:35:46 +0100142 ss = ListenerServer(starter)
Neil Williams16579dc2014-02-13 11:20:04 +0000143 ss.start()