blob: 4f103bfcae8ad9220f33bfd9aad8d9964ba2d9e5 [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
Matt Hart132d43c2015-02-25 18:19:53 +000025import json
Matt Hart76fb2542014-06-01 14:24:56 +010026from dbhandler import DBHandler
Matt Hart1499bd42013-08-20 11:35:46 +010027
Matt Hart1499bd42013-08-20 11:35:46 +010028class ListenerServer(object):
Matt Hart1499bd42013-08-20 11:35:46 +010029
Matt Hart132d43c2015-02-25 18:19:53 +000030 def __init__(self, settings):
31 listen_host = settings["hostname"]
32 listen_port = settings["port"]
33
Matt Hart40d6c312013-08-20 14:47:31 +010034 logging.getLogger().name = "ListenerServer"
Matt Hart132d43c2015-02-25 18:19:53 +000035 logging.getLogger().setLevel(settings["logging_level"])
36 logging.debug("ListenerServer __init__")
37 logging.info("listening on %s:%s" % (listen_host, listen_port))
38
39 self.server = TCPServer((listen_host, listen_port), TCPRequestHandler)
40 self.server.settings = settings
41 self.db = DBHandler(settings)
Matt Hart1306d822013-08-09 12:08:22 +010042 self.create_db()
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010043 self.db.close()
44 del(self.db)
Matt Hart1306d822013-08-09 12:08:22 +010045
46 def create_db(self):
Matt Hart76fb2542014-06-01 14:24:56 +010047 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 +010048 self.db.do_sql(sql)
Matt Hart76fb2542014-06-01 14:24:56 +010049 sql = "select column_name from information_schema.columns where table_name='pdu_queue'" \
50 "and column_name='exectime'"
51 res = self.db.do_sql_with_fetch(sql)
52 if not res:
53 logging.info("Old db schema discovered, upgrading")
54 sql = "alter table pdu_queue add column exectime int default 1"
55 self.db.do_sql(sql)
Matt Hart1306d822013-08-09 12:08:22 +010056
57 def start(self):
Matt Hart1499bd42013-08-20 11:35:46 +010058 logging.info("Starting the ListenerServer")
Matt Hart1306d822013-08-09 12:08:22 +010059 self.server.serve_forever()
60
Matt Hart1499bd42013-08-20 11:35:46 +010061
Matt Hart1306d822013-08-09 12:08:22 +010062class TCPRequestHandler(SocketServer.BaseRequestHandler):
Matt Hart1499bd42013-08-20 11:35:46 +010063 #"One instance per connection. Override handle(self) to customize action."
Matt Hart1306d822013-08-09 12:08:22 +010064 def insert_request(self, data):
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010065 logging.getLogger().name = "TCPRequestHandler"
Matt Hart132d43c2015-02-25 18:19:53 +000066 logging.getLogger().setLevel(self.server.settings["logging_level"])
Matt Hart1306d822013-08-09 12:08:22 +010067 array = data.split(" ")
Matt Hart76fb2542014-06-01 14:24:56 +010068 delay = 10
69 custom_delay = False
70 now = int(time.time())
Matt Hart132d43c2015-02-25 18:19:53 +000071 if (len(array) < 3) or (len(array) > 4):
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010072 logging.info("Wrong data size")
73 raise Exception("Unexpected data")
Matt Hart76fb2542014-06-01 14:24:56 +010074 if len(array) == 4:
75 delay = int(array[3])
76 custom_delay = True
Matt Hart1306d822013-08-09 12:08:22 +010077 hostname = array[0]
78 port = int(array[1])
79 request = array[2]
Matt Hart76fb2542014-06-01 14:24:56 +010080 if not (request in ["reboot","on","off"]):
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010081 logging.info("Unknown request: %s" % request)
82 raise Exception("Unknown request: %s" % request)
Matt Hart76fb2542014-06-01 14:24:56 +010083 if request == "reboot":
84 logging.debug("reboot requested, submitting off/on")
85 self.queue_request(hostname,port,"off",now)
86 self.queue_request(hostname,port,"on",now+delay)
87 else:
88 if custom_delay:
89 logging.debug("using delay as requested")
90 self.queue_request(hostname,port,request,now+delay)
91 else:
92 self.queue_request(hostname,port,request,now)
93
94 def queue_request(self, hostname, port, request, exectime):
Matt Hart2af71142014-07-22 10:40:41 +010095 db = DBHandler(self.server.settings)
Matt Hart132d43c2015-02-25 18:19:53 +000096 sql = "insert into pdu_queue (hostname,port,request,exectime) " \
Matt Hart2af71142014-07-22 10:40:41 +010097 "values ('%s',%i,'%s',%i)" % (hostname,port,request,exectime)
Matt Hart1499bd42013-08-20 11:35:46 +010098 db.do_sql(sql)
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010099 db.close()
100 del(db)
Matt Hart1306d822013-08-09 12:08:22 +0100101
Matt Hart76fb2542014-06-01 14:24:56 +0100102
Matt Hart1306d822013-08-09 12:08:22 +0100103 def handle(self):
Matt Hart40d6c312013-08-20 14:47:31 +0100104 logging.getLogger().name = "TCPRequestHandler"
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000105 ip = self.client_address[0]
Matt Hart40d6c312013-08-20 14:47:31 +0100106 try:
107 data = self.request.recv(4096).strip()
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100108 socket.setdefaulttimeout(2)
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000109 try:
110 request_host = socket.gethostbyaddr(ip)[0]
111 except socket.herror as e:
Matt Hart132d43c2015-02-25 18:19:53 +0000112 #logging.debug("Unable to resolve: %s error: %s" % (ip,e))
matthew.hart@linaro.org00612962014-02-13 15:49:27 +0000113 request_host = ip
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100114 logging.info("Received a request from %s: '%s'" % (request_host, data))
Matt Hart40d6c312013-08-20 14:47:31 +0100115 self.insert_request(data)
116 self.request.sendall("ack\n")
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +0100117 except Exception as e:
Matt Hart2af71142014-07-22 10:40:41 +0100118 logging.debug(e.__class__)
119 logging.debug(e.message)
Matt Hart40d6c312013-08-20 14:47:31 +0100120 self.request.sendall("nack\n")
Matt Hart1306d822013-08-09 12:08:22 +0100121 self.request.close()
122
123class TCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
124 allow_reuse_address = True
125 daemon_threads = True
126 pass
127
128if __name__ == "__main__":
Matt Hart1499bd42013-08-20 11:35:46 +0100129 logging.basicConfig(level=logging.DEBUG)
Matt Hart63ed9112013-08-20 13:31:50 +0100130 logging.getLogger().setLevel(logging.DEBUG)
Matt Hart1499bd42013-08-20 11:35:46 +0100131 logging.debug("Executing from __main__")
Matt Hart132d43c2015-02-25 18:19:53 +0000132 settings = {}
133 filename = "/etc/lavapdu/lavapdu.conf"
134 print("Reading settings from %s" % filename)
135 with open(filename) as stream:
136 jobdata = stream.read()
137 json_data = json.loads(jobdata)
138
139 #starter = {"daemon": {"dbhost":"127.0.0.1",
140 # "dbuser":"pdudaemon",
141 # "dbpass":"pdudaemon",
142 # "dbname":"lavapdu",
143 # "logging_level": logging.DEBUG,
144 # "hostname": "0.0.0.0", "port": 16421}}
145 #ss = ListenerServer(starter)
Matt Hart21dc0372015-02-25 21:15:21 +0000146 ss = ListenerServer(json_data["daemon"])
147 ss.start()