PY_PROXY/app.py
Jonatan Rek 610ef79690 Fixes
2025-01-21 15:28:54 +01:00

130 lines
4.9 KiB
Python

import http.server
import http.client
import yaml
import docker
import threading
import time
from datetime import datetime, timezone
from socketserver import ThreadingMixIn
from queue import Queue
import multiprocessing
# Define the target server to proxy requests to
class ProxyHandler(http.server.BaseHTTPRequestHandler):
def __init__(self, configuration, docker_client):
global activity
self.configuration = configuration
self.docker_client = docker_client
def __call__(self, *args, **kwargs):
"""Handle a request."""
super().__init__(*args, **kwargs)
def log_message(self, format, *args):
pass
def do_GET(self):
self.handle_request('GET')
def do_POST(self):
self.handle_request('POST')
def do_PUT(self):
self.handle_request('PUT')
def do_DELETE(self):
self.handle_request('DELETE')
def do_HEAD(self):
self.handle_request('HEAD')
def handle_request(self, method):
#print(self.headers.get('Host').split(":")[0])
proxy_host_configuration = next(filter(lambda host: host['domain'] == self.headers.get('Host').split(":")[0], self.configuration['proxy_hosts']))
starting = False
for container in proxy_host_configuration['containers']:
container_object = self.docker_client.containers.list(all=True, filters = { 'name' : container['container_name'] })[0]
if (container_object.status != 'running'):
print("starting container: {0}".format(container['container_name']))
container_object.start()
starting = True
if (starting == True):
self.send_response(201)
self.send_header('Content-Type', 'text/plain')
self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate')
self.send_header('Pragma', 'no-cache')
self.send_header('Expires', '0')
self.send_header('refresh', proxy_host_configuration['proxy_timeout_seconds'])
self.end_headers()
self.wfile.write(bytes("starting container: {0} waiting for {1}s".format(container['container_name'], proxy_host_configuration['proxy_timeout_seconds']),"utf-8"))
self.wfile.flush()
return
activity[proxy_host_configuration['domain']] = datetime.now(timezone.utc)
# Open a connection to the target server
conn = http.client.HTTPConnection(proxy_host_configuration['proxy_host'], proxy_host_configuration['proxy_port'])
conn.request(method, self.path, headers=self.headers)
response = conn.getresponse()
self.send_response(response.status)
self.send_header('host', proxy_host_configuration['proxy_host'])
for header, value in response.getheaders():
self.send_header(header, value)
self.end_headers()
self.wfile.write(response.read())
conn.close()
class ThreadedHTTPServer(ThreadingMixIn, http.server.HTTPServer):
"""Handle requests in a separate thread."""
class BackgroundTasks(threading.Thread):
def __init__(self, configuration, docker_client):
super(BackgroundTasks, self).__init__()
self.configuration = configuration
self.docker_client = docker_client
def run(self,*args,**kwargs):
global activity
while True:
sleep_time = 900
for apps in self.configuration['proxy_hosts']:
if(sleep_time > apps['proxy_timeout_seconds']):
sleep_time = apps['proxy_timeout_seconds']
for container in apps['containers']:
container_object = self.docker_client.containers.get(container['container_name'])
if (container_object.status == 'running'):
dt = datetime.now(timezone.utc)
if (apps['domain'] in activity):
dt = activity[apps['domain']]
diff_seconds = (datetime.now(timezone.utc) - dt).total_seconds()
if(diff_seconds > apps['proxy_timeout_seconds']):
print("stopping container: {0} ({1}) after {2}s".format(container['container_name'], container_object.id, diff_seconds))
container_object.stop()
time.sleep(sleep_time)
if __name__ == '__main__':
activity = {}
with open('config.yml', 'r') as file:
configuration = yaml.safe_load(file)
docker_client = docker.from_env()
t = BackgroundTasks(configuration, docker_client)
t.start()
# Start the reverse proxy server on port 8888
server_address = ('', configuration['proxy_port'])
proxy_handler = ProxyHandler(configuration, docker_client)
httpd = ThreadedHTTPServer(server_address, proxy_handler)
print('Reverse proxy server running on port {0}...'.format(configuration['proxy_port']))
httpd.serve_forever()