| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  | from flask import Flask, render_template | 
					
						
							|  |  |  | import re | 
					
						
							| 
									
										
										
										
											2024-07-22 18:57:14 -03:00
										 |  |  | import docker | 
					
						
							|  |  |  | import requests | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | app = Flask(__name__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TRAEFIK_API_URL = "https://norman.lan/api/http/routers" | 
					
						
							|  |  |  | REGEX_PATTERNS = [r".*\.gederico\.dynu\.net"] | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  | DEFAULT_GROUP_PRIORITY = 100 | 
					
						
							|  |  |  | DEFAULT_GROUP = 'Applications' | 
					
						
							|  |  |  | DEFAULT_GROUP_ICON = 'fas fa-box' | 
					
						
							|  |  |  | DEFAULT_TITLE = 'Traefik Routers' | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 18:57:14 -03:00
										 |  |  | client = docker.from_env() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  | def get_routers(containers): | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  |     response = requests.get(TRAEFIK_API_URL, verify=False)  # Ignore SSL certificate verification | 
					
						
							|  |  |  |     if response.status_code == 200: | 
					
						
							|  |  |  |         routers = response.json() | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  |         filtered_routers = filter_routers(routers, containers) | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  |         return filtered_routers | 
					
						
							|  |  |  |     return [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  | def filter_routers(routers, containers): | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  |     filtered_routers = [] | 
					
						
							|  |  |  |     for router in routers: | 
					
						
							|  |  |  |         for pattern in REGEX_PATTERNS: | 
					
						
							|  |  |  |             if re.match(pattern, router['rule'].split('`')[1]): | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  |                 if not is_router_hidden(router['name'], containers): | 
					
						
							|  |  |  |                     router['description'] = get_router_description(router['name'], containers) | 
					
						
							|  |  |  |                     router['display_name'] = get_router_display_name(router['name'], containers) | 
					
						
							|  |  |  |                     router['group'] = get_router_group(router['name'], containers) | 
					
						
							|  |  |  |                     filtered_routers.append(router) | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  |                 break | 
					
						
							|  |  |  |     return filtered_routers | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  | def is_router_hidden(router_name, containers): | 
					
						
							|  |  |  |     service_name = router_name.split('@')[0] | 
					
						
							|  |  |  |     for container in containers: | 
					
						
							|  |  |  |         labels = container.attrs.get('Config', {}).get('Labels', {}) | 
					
						
							|  |  |  |         hidden_label = f'traefik-frontend.http.routers.{service_name}.hidden' | 
					
						
							|  |  |  |         if labels.get(hidden_label) == 'true': | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_router_description(router_name, containers): | 
					
						
							|  |  |  |     service_name = router_name.split('@')[0] | 
					
						
							|  |  |  |     for container in containers: | 
					
						
							|  |  |  |         labels = container.attrs.get('Config', {}).get('Labels', {}) | 
					
						
							|  |  |  |         description_label = f'traefik-frontend.http.routers.{service_name}.description' | 
					
						
							|  |  |  |         if description_label in labels: | 
					
						
							|  |  |  |             return labels[description_label] | 
					
						
							| 
									
										
										
										
											2024-07-22 18:25:30 -03:00
										 |  |  |     return 'No description available' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  | def get_router_display_name(router_name, containers): | 
					
						
							|  |  |  |     service_name = router_name.split('@')[0] | 
					
						
							|  |  |  |     for container in containers: | 
					
						
							|  |  |  |         labels = container.attrs.get('Config', {}).get('Labels', {}) | 
					
						
							|  |  |  |         display_name_label = f'traefik-frontend.http.routers.{service_name}.router_name' | 
					
						
							|  |  |  |         if display_name_label in labels: | 
					
						
							|  |  |  |             return labels[display_name_label].upper() | 
					
						
							|  |  |  |     return service_name.upper() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_router_group(router_name, containers): | 
					
						
							|  |  |  |     service_name = router_name.split('@')[0] | 
					
						
							|  |  |  |     for container in containers: | 
					
						
							|  |  |  |         labels = container.attrs.get('Config', {}).get('Labels', {}) | 
					
						
							|  |  |  |         group_label = f'traefik-frontend.http.routers.{service_name}.group' | 
					
						
							|  |  |  |         if group_label in labels: | 
					
						
							|  |  |  |             return labels[group_label] | 
					
						
							|  |  |  |     return DEFAULT_GROUP | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_groups(containers): | 
					
						
							|  |  |  |     groups = { | 
					
						
							|  |  |  |         DEFAULT_GROUP: { | 
					
						
							|  |  |  |             'priority': DEFAULT_GROUP_PRIORITY, | 
					
						
							|  |  |  |             'collapsed': False, | 
					
						
							|  |  |  |             'routers': [], | 
					
						
							|  |  |  |             'icon': DEFAULT_GROUP_ICON | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for container in containers: | 
					
						
							|  |  |  |         labels = container.attrs.get('Config', {}).get('Labels', {}) | 
					
						
							|  |  |  |         for label, value in labels.items(): | 
					
						
							|  |  |  |             if label.startswith('traefik-frontend.groups.'): | 
					
						
							|  |  |  |                 group_name = label.split('.')[2] | 
					
						
							|  |  |  |                 priority_label = f'traefik-frontend.groups.{group_name}.priority' | 
					
						
							|  |  |  |                 collapsed_label = f'traefik-frontend.groups.{group_name}.collapsed' | 
					
						
							|  |  |  |                 icon_label = f'traefik-frontend.groups.{group_name}.icon' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if group_name not in groups: | 
					
						
							|  |  |  |                     groups[group_name] = { | 
					
						
							|  |  |  |                         'priority': DEFAULT_GROUP_PRIORITY, | 
					
						
							|  |  |  |                         'collapsed': False, | 
					
						
							|  |  |  |                         'routers': [], | 
					
						
							|  |  |  |                         'icon': DEFAULT_GROUP_ICON | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if priority_label in labels: | 
					
						
							|  |  |  |                     groups[group_name]['priority'] = int(labels[priority_label]) | 
					
						
							|  |  |  |                 if collapsed_label in labels: | 
					
						
							|  |  |  |                     groups[group_name]['collapsed'] = labels[collapsed_label].lower() == 'true' | 
					
						
							|  |  |  |                 if icon_label in labels: | 
					
						
							|  |  |  |                     groups[group_name]['icon'] = labels[icon_label] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return groups | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_title(containers): | 
					
						
							|  |  |  |     for container in containers: | 
					
						
							|  |  |  |         labels = container.attrs.get('Config', {}).get('Labels', {}) | 
					
						
							|  |  |  |         title_label = 'traefik-frontend.title' | 
					
						
							|  |  |  |         if title_label in labels: | 
					
						
							|  |  |  |             return labels[title_label] | 
					
						
							|  |  |  |     return DEFAULT_TITLE | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | @app.route('/') | 
					
						
							|  |  |  | def index(): | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  |     containers = client.containers.list(all=True)  # Get all containers once | 
					
						
							|  |  |  |     title = get_title(containers) | 
					
						
							|  |  |  |     routers = get_routers(containers) | 
					
						
							|  |  |  |     groups = get_groups(containers) | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  |     for router in routers: | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  |         group_name = router['group'] | 
					
						
							|  |  |  |         if group_name not in groups: | 
					
						
							|  |  |  |             group_name = DEFAULT_GROUP | 
					
						
							|  |  |  |         groups[group_name]['routers'].append(router) | 
					
						
							|  |  |  |     sorted_groups = {k: v for k, v in sorted(groups.items(), key=lambda item: item[1]['priority']) if v['routers']} | 
					
						
							|  |  |  |     return render_template('index.html', title=title, groups=sorted_groups) | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2024-07-23 17:32:12 -03:00
										 |  |  |     app.run(debug=True, host='0.0.0.0') | 
					
						
							| 
									
										
										
										
											2024-07-22 18:14:12 -03:00
										 |  |  | 
 |