@@ -0,0 +1,135 @@
#!/usr/bin/env python3
import os
import time
import logging
import difflib
from flask import Flask , request , jsonify , abort
from flask_sslify import SSLify
from datetime import datetime , timezone , timedelta
from croniter import croniter
import psutil
app = Flask ( __name__ )
sslify = SSLify ( app )
# Konfiguracja tokenu autoryzacyjnego (przyjmujemy pre-shared secret)
API_TOKEN = os . environ . get ( " HOSTS_DAEMON_API_TOKEN " , " changeme " )
# Konfiguracja logowania – logi zapisywane do pliku /opt/hosts_daemon/logs/daemon.log
LOG_DIR = " /opt/hosts_daemon/logs "
os . makedirs ( LOG_DIR , exist_ok = True )
LOG_FILE = os . path . join ( LOG_DIR , " daemon.log " )
logging . basicConfig (
level = logging . INFO ,
format = " %(asctime)s [ %(levelname)s ] %(message)s " ,
handlers = [
logging . FileHandler ( LOG_FILE ) ,
logging . StreamHandler ( )
]
)
logger = logging . getLogger ( " hosts_daemon " )
# Globalne metryki
metrics = {
" total_requests " : 0 ,
" total_time " : 0.0 ,
" endpoints " : { } ,
" hosts_get " : 0 ,
" hosts_post " : 0 ,
}
# Funkcja sprawdzająca autoryzację
def require_auth ( ) :
token = request . headers . get ( " Authorization " )
if token != API_TOKEN :
abort ( 401 , description = " Unauthorized " )
# Logowanie i zbieranie metryk – logujemy czas rozpoczęcia, adres IP, endpoint i metodę
@app.before_request
def before_request_logging ( ) :
request . start_time = time . time ( )
client_ip = request . remote_addr
endpoint = request . path
logger . info ( f " Request from { client_ip } to { endpoint } [ { request . method } ], Auth: { request . headers . get ( ' Authorization ' ) } " )
metrics [ " total_requests " ] + = 1
if endpoint not in metrics [ " endpoints " ] :
metrics [ " endpoints " ] [ endpoint ] = { " count " : 0 , " total_time " : 0.0 }
metrics [ " endpoints " ] [ endpoint ] [ " count " ] + = 1
@app.after_request
def after_request_logging ( response ) :
elapsed = time . time ( ) - request . start_time
metrics [ " total_time " ] + = elapsed
endpoint = request . path
if endpoint in metrics [ " endpoints " ] :
metrics [ " endpoints " ] [ endpoint ] [ " total_time " ] + = elapsed
logger . info ( f " Completed { endpoint } in { elapsed : .3f } sec with status { response . status_code } " )
return response
# Endpoint GET /hosts – pobiera zawartość /etc/hosts
@app.route ( ' /hosts ' , methods = [ ' GET ' ] )
def get_hosts ( ) :
require_auth ( )
metrics [ " hosts_get " ] + = 1
try :
with open ( ' /etc/hosts ' , ' r ' ) as f :
content = f . read ( )
logger . info ( f " /hosts GET successful from { request . remote_addr } " )
return jsonify ( { " hosts " : content } )
except Exception as e :
logger . error ( f " /hosts GET error: { str ( e ) } " )
return jsonify ( { " error " : str ( e ) } ) , 500
# Endpoint POST /hosts – aktualizuje plik /etc/hosts
@app.route ( ' /hosts ' , methods = [ ' POST ' ] )
def update_hosts ( ) :
require_auth ( )
metrics [ " hosts_post " ] + = 1
data = request . get_json ( )
if not data or " hosts " not in data :
logger . warning ( f " /hosts POST: missing ' hosts ' key from { request . remote_addr } " )
return jsonify ( { " error " : " Invalid request, missing ' hosts ' key " } ) , 400
new_content = data [ " hosts " ]
try :
with open ( ' /etc/hosts ' , ' w ' ) as f :
f . write ( new_content )
logger . info ( f " /hosts POST updated by { request . remote_addr } " )
return jsonify ( { " message " : " File updated successfully " } )
except Exception as e :
logger . error ( f " /hosts POST error: { str ( e ) } " )
return jsonify ( { " error " : str ( e ) } ) , 500
# Endpoint /health – zwraca status usługi
@app.route ( ' /health ' , methods = [ ' GET ' ] )
def health ( ) :
require_auth ( )
uptime = time . time ( ) - psutil . boot_time ( )
now = datetime . now ( timezone . utc ) . isoformat ( )
logger . info ( f " /health check from { request . remote_addr } " )
return jsonify ( { " status " : " ok " , " time " : now , " uptime " : uptime } )
# Endpoint /metrics – zwraca metryki
@app.route ( ' /metrics ' , methods = [ ' GET ' ] )
def metrics_endpoint ( ) :
require_auth ( )
avg_time = metrics [ " total_time " ] / metrics [ " total_requests " ] if metrics [ " total_requests " ] > 0 else 0.0
ep_data = { }
for ep , data in metrics [ " endpoints " ] . items ( ) :
ep_avg = data [ " total_time " ] / data [ " count " ] if data [ " count " ] > 0 else 0.0
ep_data [ ep ] = { " count " : data [ " count " ] , " avg_time " : ep_avg }
response_data = {
" total_requests " : metrics [ " total_requests " ] ,
" avg_response_time " : avg_time ,
" endpoints " : ep_data ,
" hosts_get " : metrics . get ( " hosts_get " , 0 ) ,
" hosts_post " : metrics . get ( " hosts_post " , 0 )
}
logger . info ( f " /metrics accessed by { request . remote_addr } " )
return jsonify ( response_data )
if __name__ == ' __main__ ' :
app . run (
host = ' 0.0.0.0 ' ,
port = 8000 ,
ssl_context = ( ' /opt/hosts_daemon/ssl/hosts_daemon.crt ' , ' /opt/hosts_daemon/ssl/hosts_daemon.key ' )
)