11from datetime import datetime
22import docker
3+ import logging
34import os
45import threading
56import time
67
8+ ACCESS_LOG_FILE = "/config/log/nginx/access.log"
9+ LOG_FILE = "/config/log/ondemand/ondemand.log"
10+ STOP_THRESHOLD = int (os .environ .get ("SWAG_ONDEMAND_STOP_THRESHOLD" , "1800" ))
11+
712last_accessed_urls = set ()
813last_accessed_urls_lock = threading .Lock ()
914ondemand_containers = {}
1015ondemand_containers_lock = threading .Lock ()
11- stop_threshold = int (os .environ .get ("SWAG_ONDEMAND_STOP_THRESHOLD" , "1800" ))
1216
1317class ContainerThread (threading .Thread ):
14- def process_containers (self , docker_client ):
18+ def __init__ (self ):
19+ super ().__init__ ()
20+ self .docker_client = docker .from_env ()
21+ self .daemon = True
22+
23+ def process_containers (self ):
1524 global ondemand_containers
16- containers = docker_client .containers .list (all = True , filters = { "label" : ["swag_ondemand=enable" ] })
25+ containers = self . docker_client .containers .list (all = True , filters = { "label" : ["swag_ondemand=enable" ] })
1726 container_names = {container .name for container in containers }
1827
1928 for container_name in list (ondemand_containers .keys ()):
2029 if container_name in container_names :
2130 continue
2231 ondemand_containers .pop (container_name )
23- print (f"{ datetime . now () } - Stopped monitoring { container_name } " )
32+ logging . info (f"Stopped monitoring { container_name } " )
2433
2534 for container in containers :
2635 container_urls = container .labels .get ("swag_ondemand_urls" , f"https://{ container .name } .,http://{ container .name } ." )
2736 if container .name not in ondemand_containers .keys ():
2837 last_accessed = datetime .now ()
29- print (f"{ datetime . now () } - Started monitoring { container .name } " )
38+ logging . info (f"Started monitoring { container .name } " )
3039 else :
3140 last_accessed = ondemand_containers [container .name ]["last_accessed" ]
3241 ondemand_containers [container .name ] = { "status" : container .status , "urls" : container_urls , "last_accessed" : last_accessed }
3342
34- def stop_containers (self , docker_client ):
43+ def stop_containers (self ):
3544 global ondemand_containers
3645
3746 for container_name in ondemand_containers .keys ():
3847 if ondemand_containers [container_name ]["status" ] != "running" :
3948 continue
4049 inactive_seconds = (datetime .now () - ondemand_containers [container_name ]["last_accessed" ]).total_seconds ()
41- if inactive_seconds < stop_threshold :
50+ if inactive_seconds < STOP_THRESHOLD :
4251 continue
43- docker_client .containers .get (container_name ).stop ()
44- print (f"{ datetime . now () } - Stopped { container_name } after { stop_threshold } s of inactivity" )
52+ self . docker_client .containers .get (container_name ).stop ()
53+ logging . info (f"Stopped { container_name } after { STOP_THRESHOLD } s of inactivity" )
4554
46- def start_containers (self , docker_client ):
55+ def start_containers (self ):
4756 global ondemand_containers
48- last_accessed_urls_lock .acquire ()
49- last_accessed_urls_combined = "," .join (last_accessed_urls )
50- last_accessed_urls .clear ()
51- last_accessed_urls_lock .release ()
57+ with last_accessed_urls_lock :
58+ last_accessed_urls_combined = "," .join (last_accessed_urls )
59+ last_accessed_urls .clear ()
5260
5361 for container_name in ondemand_containers .keys ():
5462 accessed = False
@@ -59,21 +67,25 @@ def start_containers(self, docker_client):
5967 accessed = True
6068 if not accessed or ondemand_containers [container_name ]["status" ] == "running" :
6169 continue
62- docker_client .containers .get (container_name ).start ()
63- print (f"{ datetime . now () } - Started { container_name } " )
70+ self . docker_client .containers .get (container_name ).start ()
71+ logging . info (f"Started { container_name } " )
6472 ondemand_containers [container_name ]["status" ] = "running"
6573
6674 def run (self ):
6775 while True :
68- docker_client = docker .from_env ()
69- with ondemand_containers_lock :
70- self .process_containers (docker_client )
71- self .start_containers (docker_client )
72- self .stop_containers (docker_client )
73- time .sleep (5 )
76+ try :
77+ with ondemand_containers_lock :
78+ self .process_containers ()
79+ self .start_containers ()
80+ self .stop_containers ()
81+ time .sleep (2 )
82+ except Exception as e :
83+ logging .exception (e )
7484
7585class LogReaderThread (threading .Thread ):
76- logname = "/config/log/nginx/access.log"
86+ def __init__ (self ):
87+ super ().__init__ ()
88+ self .daemon = True
7789
7890 def tail (self , f ):
7991 f .seek (0 ,2 )
@@ -82,24 +94,44 @@ def tail(self, f):
8294 while True :
8395 line = f .readline ()
8496 if not line :
85- time .sleep (1 )
86- if os .stat (self . logname ).st_ino != inode :
97+ time .sleep (0. 1 )
98+ if os .stat (ACCESS_LOG_FILE ).st_ino != inode :
8799 f .close ()
88- f = open (self . logname , 'r' )
100+ f = open (ACCESS_LOG_FILE , 'r' )
89101 inode = os .fstat (f .fileno ()).st_ino
90102 continue
91103 yield line
92104
93105 def run (self ):
94- logfile = open ( self . logname , "r" )
95- for line in self . tail ( logfile ) :
96- for part in line . split ( ):
97- if not part . startswith ( "http" ):
106+ while True :
107+ try :
108+ if not os . path . exists ( ACCESS_LOG_FILE ):
109+ time . sleep ( 1 )
98110 continue
99- with last_accessed_urls_lock :
100- last_accessed_urls .add (part )
101- print (f"{ datetime .now ()} - Accessed { part } " )
102- break
103111
104- ContainerThread ().start ()
105- LogReaderThread ().start ()
112+ logfile = open (ACCESS_LOG_FILE , "r" )
113+ for line in self .tail (logfile ):
114+ for part in line .split ():
115+ if not part .startswith ("http" ):
116+ continue
117+ with last_accessed_urls_lock :
118+ last_accessed_urls .add (part )
119+ break
120+ except Exception as e :
121+ logging .exception (e )
122+ time .sleep (1 )
123+
124+ if __name__ == "__main__" :
125+ os .makedirs (os .path .dirname (LOG_FILE ), exist_ok = True )
126+ logging .basicConfig (filename = LOG_FILE ,
127+ filemode = 'a' ,
128+ format = '%(asctime)s - %(threadName)s - %(levelname)s - %(message)s' ,
129+ datefmt = '%Y-%m-%d %H:%M:%S' ,
130+ level = logging .INFO )
131+ logging .info ("Starting swag-ondemand..." )
132+
133+ ContainerThread ().start ()
134+ LogReaderThread ().start ()
135+
136+ while True :
137+ time .sleep (1 )
0 commit comments