blob: 2ba149c94d3363a846600918da6cb5abe88153cc [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
Matt Hart1306d822013-08-09 12:08:22 +010022import logging
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010023import socket
Matt Hart76fb2542014-06-01 14:24:56 +010024import time
25from dbhandler import DBHandler
Matt Hart1499bd42013-08-20 11:35:46 +010026
27
28class ListenerServer(object):
Matt Hart1499bd42013-08-20 11:35:46 +010029
30 def __init__(self, config):
Matt Hart2af71142014-07-22 10:40:41 +010031 self.server = TCPServer((config["settings"]["hostname"], config["settings"]["port"]), TCPRequestHandler)
Matt Hart40d6c312013-08-20 14:47:31 +010032 logging.getLogger().name = "ListenerServer"
Matt Hart7d670612013-08-20 16:47:52 +010033 logging.getLogger().setLevel(config["logging_level"])
Matt Hart2af71142014-07-22 10:40:41 +010034 logging.info("listening on %s:%s" % (config["settings"]["hostname"], config["settings"]["port"]))
35 self.server.settings = config["settings"]
36 self.db = DBHandler(self.server.settings)
Matt Hart1306d822013-08-09 12:08:22 +010037 self.create_db()
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010038 self.db.close()
39 del(self.db)
Matt Hart1306d822013-08-09 12:08:22 +010040
41 def create_db(self):
Matt Hart76fb2542014-06-01 14:24:56 +010042 sql = "create table if not exists pdu_queue (id serial, hostname text, port int, request text, exectime int)"
Matt Hart1499bd42013-08-20 11:35:46 +010043 self.db.do_sql(sql)
Matt Hart76fb2542014-06-01 14:24:56 +010044 sql = "select column_name from information_schema.columns where table_name='pdu_queue'" \
45 "and column_name='exectime'"
46 res = self.db.do_sql_with_fetch(sql)
47 if not res:
48 logging.info("Old db schema discovered, upgrading")
49 sql = "alter table pdu_queue add column exectime int default 1"
50 self.db.do_sql(sql)
Matt Hart1306d822013-08-09 12:08:22 +010051
52 def start(self):
Matt Hart1499bd42013-08-20 11:35:46 +010053 logging.info("Starting the ListenerServer")
Matt Hart1306d822013-08-09 12:08:22 +010054 self.server.serve_forever()
55
Matt Hart1499bd42013-08-20 11:35:46 +010056
Matt Hart1306d822013-08-09 12:08:22 +010057class TCPRequestHandler(SocketServer.BaseRequestHandler):
Matt Hart1499bd42013-08-20 11:35:46 +010058 #"One instance per connection. Override handle(self) to customize action."
Matt Hart1306d822013-08-09 12:08:22 +010059 def insert_request(self, data):
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010060 logging.getLogger().name = "TCPRequestHandler"
Matt Hart1306d822013-08-09 12:08:22 +010061 array = data.split(" ")
Matt Hart76fb2542014-06-01 14:24:56 +010062 delay = 10
63 custom_delay = False
64 now = int(time.time())
65 if len(array) < 3:
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010066 logging.info("Wrong data size")
67 raise Exception("Unexpected data")
Matt Hart76fb2542014-06-01 14:24:56 +010068 if len(array) == 4:
69 delay = int(array[3])
70 custom_delay = True
Matt Hart1306d822013-08-09 12:08:22 +010071 hostname = array[0]
72 port = int(array[1])
73 request = array[2]
Matt Hart76fb2542014-06-01 14:24:56 +010074 if not (request in ["reboot","on","off"]):
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010075 logging.info("Unknown request: %s" % request)
76 raise Exception("Unknown request: %s" % request)
Matt Hart76fb2542014-06-01 14:24:56 +010077 if request == "reboot":
78 logging.debug("reboot requested, submitting off/on")
79 self.queue_request(hostname,port,"off",now)
80 self.queue_request(hostname,port,"on",now+delay)
81 else:
82 if custom_delay:
83 logging.debug("using delay as requested")
84 self.queue_request(hostname,port,request,now+delay)
85 else:
86 self.queue_request(hostname,port,request,now)
87
88 def queue_request(self, hostname, port, request, exectime):
Matt Hart2af71142014-07-22 10:40:41 +010089 db = DBHandler(self.server.settings)
Matt Hart76fb2542014-06-01 14:24:56 +010090 sql = "insert into pdu_queue (hostname,port,request,exectime)" \
Matt Hart2af71142014-07-22 10:40:41 +010091 "values ('%s',%i,'%s',%i)" % (hostname,port,request,exectime)
Matt Hart1499bd42013-08-20 11:35:46 +010092 db.do_sql(sql)
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010093 db.close()
94 del(db)
Matt Hart1306d822013-08-09 12:08:22 +010095
Matt Hart76fb2542014-06-01 14:24:56 +010096
Matt Hart1306d822013-08-09 12:08:22 +010097 def handle(self):
Matt Hart40d6c312013-08-20 14:47:31 +010098 logging.getLogger().name = "TCPRequestHandler"
matthew.hart@linaro.org00612962014-02-13 15:49:27 +000099 ip = self.client_address[0]
Matt Hart40d6c312013-08-20 14:47:31 +0100100 try:
101 data = self.request.recv(4096).strip()
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100102 socket.setdefaulttimeout(2)
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000103 try:
104 request_host = socket.gethostbyaddr(ip)[0]
105 except socket.herror as e:
Matt Hart76fb2542014-06-01 14:24:56 +0100106 logging.debug("Unable to resolve: %s error: %s" % (ip,e))
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000107 request_host = ip
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100108 logging.info("Received a request from %s: '%s'" % (request_host, data))
Matt Hart40d6c312013-08-20 14:47:31 +0100109 self.insert_request(data)
110 self.request.sendall("ack\n")
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100111 except Exception as e:
Matt Hart2af71142014-07-22 10:40:41 +0100112 logging.debug(e.__class__)
113 logging.debug(e.message)
Matt Hart40d6c312013-08-20 14:47:31 +0100114 self.request.sendall("nack\n")
Matt Hart1306d822013-08-09 12:08:22 +0100115 self.request.close()
116
117class TCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
118 allow_reuse_address = True
119 daemon_threads = True
120 pass
121
122if __name__ == "__main__":
Matt Hart1499bd42013-08-20 11:35:46 +0100123 logging.basicConfig(level=logging.DEBUG)
Matt Hart63ed9112013-08-20 13:31:50 +0100124 logging.getLogger().setLevel(logging.DEBUG)
Matt Hart1499bd42013-08-20 11:35:46 +0100125 logging.debug("Executing from __main__")
126 starter = {"hostname": "0.0.0.0",
Matt Hart76fb2542014-06-01 14:24:56 +0100127 "port":16421,
128 "dbhost":"127.0.0.1",
129 "dbuser":"pdudaemon",
130 "dbpass":"pdudaemon",
131 "dbname":"lavapdu",
Matt Hart96ca8662013-08-21 13:37:35 +0100132 "logging_level": logging.DEBUG}
Matt Hart1499bd42013-08-20 11:35:46 +0100133 ss = ListenerServer(starter)
Matt Hart76fb2542014-06-01 14:24:56 +0100134 ss.start()