blob: b5c5668faca0c41772d25cd8a7ffc235326cd86a [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 Hart07f56a02015-08-06 14:17:18 +010025import sys
26import os
Matt Hartfc646822015-02-27 14:51:16 +000027from lavapdu.dbhandler import DBHandler
Matt Harte7bddc02015-07-08 18:05:08 +010028from lavapdu.shared import drivername_from_hostname
Matt Hartd4a09982015-07-17 16:13:11 +010029log = logging.getLogger(__name__)
Matt Hart1499bd42013-08-20 11:35:46 +010030
Matt Hartfe042212015-07-09 14:13:29 +010031
Matt Hart1499bd42013-08-20 11:35:46 +010032class ListenerServer(object):
Matt Hart1499bd42013-08-20 11:35:46 +010033
Matt Harte7bddc02015-07-08 18:05:08 +010034 def __init__(self, config):
35 self.config = config
36 settings = config["daemon"]
Matt Hart132d43c2015-02-25 18:19:53 +000037 listen_host = settings["hostname"]
38 listen_port = settings["port"]
Matt Hartd4a09982015-07-17 16:13:11 +010039 log.debug("ListenerServer __init__")
Matt Hart07f56a02015-08-06 14:17:18 +010040 if "purge" in config:
41 self.server.dbh.purge()
42 sys.exit(os.EX_OK)
Matt Hartd4a09982015-07-17 16:13:11 +010043 log.info("listening on %s:%s", listen_host, listen_port)
Matt Hart132d43c2015-02-25 18:19:53 +000044
45 self.server = TCPServer((listen_host, listen_port), TCPRequestHandler)
46 self.server.settings = settings
Matt Harte7bddc02015-07-08 18:05:08 +010047 self.server.config = config
Matt Hartd4a09982015-07-17 16:13:11 +010048 self.server.dbh = DBHandler(settings)
Matt Hart1306d822013-08-09 12:08:22 +010049
Matt Hart07f56a02015-08-06 14:17:18 +010050
Matt Hart1306d822013-08-09 12:08:22 +010051 def start(self):
Matt Hartd4a09982015-07-17 16:13:11 +010052 log.info("Starting the ListenerServer")
Matt Hart1306d822013-08-09 12:08:22 +010053 self.server.serve_forever()
54
Matt Hart1499bd42013-08-20 11:35:46 +010055
Matt Hart1306d822013-08-09 12:08:22 +010056class TCPRequestHandler(SocketServer.BaseRequestHandler):
Matt Hartfe042212015-07-09 14:13:29 +010057 # "One instance per connection. Override handle(self) to customize
58 # action."
Matt Hart1306d822013-08-09 12:08:22 +010059 def insert_request(self, data):
60 array = data.split(" ")
Matt Hart76fb2542014-06-01 14:24:56 +010061 delay = 10
62 custom_delay = False
63 now = int(time.time())
Matt Hart132d43c2015-02-25 18:19:53 +000064 if (len(array) < 3) or (len(array) > 4):
Matt Hartd4a09982015-07-17 16:13:11 +010065 log.info("Wrong data size")
matthew.hart@linaro.org1d632392013-08-27 14:40:11 +010066 raise Exception("Unexpected data")
Matt Hart76fb2542014-06-01 14:24:56 +010067 if len(array) == 4:
68 delay = int(array[3])
69 custom_delay = True
Matt Hart1306d822013-08-09 12:08:22 +010070 hostname = array[0]
71 port = int(array[1])
72 request = array[2]
Matt Hartd4a09982015-07-17 16:13:11 +010073 # this will throw if the pdu is not found
Matt Harte7bddc02015-07-08 18:05:08 +010074 drivername_from_hostname(hostname, self.server.config["pdus"])
Matt Hartd4a09982015-07-17 16:13:11 +010075 dbh = self.server.dbh
Matt Hartfc646822015-02-27 14:51:16 +000076 if not (request in ["reboot", "on", "off"]):
Matt Hartd4a09982015-07-17 16:13:11 +010077 log.info("Unknown request: %s", request)
Matt Hart76584172015-03-02 10:25:51 +000078 raise Exception("Unknown request: %s", request)
Matt Hart76fb2542014-06-01 14:24:56 +010079 if request == "reboot":
Matt Hartd4a09982015-07-17 16:13:11 +010080 log.debug("reboot requested, submitting off/on")
81 dbh.insert_request(hostname, port, "off", now)
82 dbh.insert_request(hostname, port, "on", now + delay)
Matt Hart76fb2542014-06-01 14:24:56 +010083 else:
84 if custom_delay:
Matt Hartd4a09982015-07-17 16:13:11 +010085 log.debug("using delay as requested")
86 dbh.insert_request(hostname, port, request, now + delay)
Matt Hart76fb2542014-06-01 14:24:56 +010087 else:
Matt Hartd4a09982015-07-17 16:13:11 +010088 dbh.insert_request(hostname, port, request, now)
Matt Hart1306d822013-08-09 12:08:22 +010089
90 def handle(self):
Matt Hart76584172015-03-02 10:25:51 +000091 request_ip = self.client_address[0]
Matt Hart40d6c312013-08-20 14:47:31 +010092 try:
93 data = self.request.recv(4096).strip()
matthew.hart@linaro.org6e15b5e2013-08-28 19:48:51 +010094 socket.setdefaulttimeout(2)
matthew.hart@linaro.org00612962014-02-13 15:49:27 +000095 try:
Matt Hart76584172015-03-02 10:25:51 +000096 request_host = socket.gethostbyaddr(request_ip)[0]
Matt Hartfe042212015-07-09 14:13:29 +010097 except socket.herror:
Matt Hart76584172015-03-02 10:25:51 +000098 request_host = request_ip
Matt Hartd4a09982015-07-17 16:13:11 +010099 log.info("Received a request from %s: '%s'",
100 request_host,
101 data)
Matt Hart40d6c312013-08-20 14:47:31 +0100102 self.insert_request(data)
103 self.request.sendall("ack\n")
Matt Hartfe042212015-07-09 14:13:29 +0100104 except Exception as global_error: # pylint: disable=broad-except
Matt Hartd4a09982015-07-17 16:13:11 +0100105 log.debug(global_error.__class__)
106 log.debug(global_error.message)
Matt Hartfe042212015-07-09 14:13:29 +0100107 self.request.sendall(global_error.message)
Matt Hart1306d822013-08-09 12:08:22 +0100108 self.request.close()
109
Matt Hart76584172015-03-02 10:25:51 +0000110
Matt Hart1306d822013-08-09 12:08:22 +0100111class TCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
112 allow_reuse_address = True
113 daemon_threads = True