-
-
Notifications
You must be signed in to change notification settings - Fork 280
Expand file tree
/
Copy pathgenerate_configs.py
More file actions
153 lines (132 loc) · 7 KB
/
generate_configs.py
File metadata and controls
153 lines (132 loc) · 7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import os
import json
import subprocess
from jinja2 import Environment, FileSystemLoader
# --- Configuration ---
TEMPLATE_DIR = '/app/config-generator/templates'
PROXY_OUTPUT_DIR = '/config/nginx/env-proxy-confs'
DEFAULT_CONF_OUTPUT = '/config/nginx/site-confs/default.conf'
HTPASSWD_FILE = '/config/nginx/.htpasswd'
# ---------------------
def process_service_config(service_name, service_config_json, global_auth_provider, auth_exclude_list):
"""Processes a single service configuration, including auth logic."""
service_config = json.loads(service_config_json)
# The default service doesn't have a subdomain name in the traditional sense
if service_name.lower() == 'default':
# We still need a target container name, let the user define it or raise an error
if 'name' not in service_config:
raise ValueError("PROXY_CONFIG_DEFAULT must contain a 'name' key specifying the target container name.")
else:
service_config['name'] = service_name
# --- Authentication Logic ---
auth_provider = 'none' # Default
# 1. Per-service override
if 'auth' in service_config:
auth_provider = service_config['auth']
print(f" - Found per-service auth override: '{auth_provider}'")
# 2. Global provider check
elif global_auth_provider and service_name not in auth_exclude_list:
auth_provider = global_auth_provider
print(f" - Applying global auth provider: '{auth_provider}'")
# 3. Otherwise, no auth
else:
if service_name in auth_exclude_list:
print(f" - Service is in global exclude list. No auth.")
else:
print(f" - No auth provider specified.")
service_config['auth_provider'] = auth_provider
return service_config
def generate_configs():
"""
Generates Nginx config files from PROXY_CONFIG environment variables and a Jinja2 template.
"""
print("--- Starting Nginx Config Generation from Environment Variables ---")
# Ensure output directories exist
os.makedirs(PROXY_OUTPUT_DIR, exist_ok=True)
os.makedirs(os.path.dirname(DEFAULT_CONF_OUTPUT), exist_ok=True)
print(f"Output directories are ready.")
# Get global auth settings from environment variables
global_auth_provider = os.environ.get('PROXY_AUTH_PROVIDER')
auth_exclude_list = os.environ.get('PROXY_AUTH_EXCLUDE', '').split(',')
auth_exclude_list = [name.strip() for name in auth_exclude_list if name.strip()]
# Get basic auth credentials
basic_auth_user = os.environ.get('PROXY_AUTH_BASIC_USER')
basic_auth_pass = os.environ.get('PROXY_AUTH_BASIC_PASS')
basic_auth_configured = False
print(f"Global Auth Provider: {global_auth_provider}")
print(f"Auth Exclude List: {auth_exclude_list}")
# Collect and process service configurations
subdomain_services = []
default_service = None
for key, value in os.environ.items():
if key.startswith('PROXY_CONFIG_'):
service_name = key.replace('PROXY_CONFIG_', '').lower()
print(f" Processing service: {service_name}")
print(value)
try:
service_config = process_service_config(service_name, value, global_auth_provider, auth_exclude_list)
# Handle Basic Auth File Creation
if service_config['auth_provider'] == 'basic' and not basic_auth_configured:
if basic_auth_user and basic_auth_pass:
print(f" - Configuring Basic Auth with user '{basic_auth_user}'.")
try:
os.makedirs(os.path.dirname(HTPASSWD_FILE), exist_ok=True)
command = ['htpasswd', '-bc', HTPASSWD_FILE, basic_auth_user, basic_auth_pass]
subprocess.run(command, check=True, capture_output=True, text=True)
print(f" - Successfully created '{HTPASSWD_FILE}'.")
basic_auth_configured = True
except subprocess.CalledProcessError as e:
print(f" [!!] ERROR: 'htpasswd' command failed: {e.stderr}. Basic auth will not be enabled.")
service_config['auth_provider'] = 'none'
except FileNotFoundError:
print(f" [!!] ERROR: 'htpasswd' command not found. Basic auth will not be enabled.")
service_config['auth_provider'] = 'none'
else:
print(f" [!!] WARNING: 'auth: basic' is set, but PROXY_AUTH_BASIC_USER or PROXY_AUTH_BASIC_PASS is missing. Skipping auth.")
service_config['auth_provider'] = 'none'
if service_name == 'default':
default_service = service_config
else:
subdomain_services.append(service_config)
except (json.JSONDecodeError, ValueError) as e:
print(f" [!!] ERROR: Could not parse or validate config for {service_name}: {e}. Skipping.")
except Exception as e:
print(f" [!!] ERROR: An unexpected error occurred processing {service_name}: {e}. Skipping.")
# Set up Jinja2 environment
try:
env = Environment(loader=FileSystemLoader(TEMPLATE_DIR), trim_blocks=True, lstrip_blocks=True)
proxy_template = env.get_template('proxy.conf.j2')
default_template = env.get_template('default.conf.j2')
print("\nJinja2 templates loaded successfully.")
except Exception as e:
print(f"ERROR: Failed to load Jinja2 templates from '{TEMPLATE_DIR}': {e}. Exiting.")
return
# Generate default site config if specified
if default_service:
print("\n--- Generating Default Site Config ---")
try:
rendered_content = default_template.render(item=default_service)
with open(DEFAULT_CONF_OUTPUT, 'w') as f:
f.write(rendered_content)
print(f" [OK] Generated {os.path.basename(DEFAULT_CONF_OUTPUT)}")
except Exception as e:
print(f" [!!] ERROR: Failed to render or write default config: {e}")
else:
print("\n--- PROXY_CONFIG_DEFAULT not set, default site config will not be generated. ---")
# Generate subdomain proxy configs
print("\n--- Generating Subdomain Proxy Configs ---")
if not subdomain_services:
print("No subdomain services found to configure.")
for service in subdomain_services:
filename = f"{service['name']}.subdomain.conf"
output_path = os.path.join(PROXY_OUTPUT_DIR, filename)
try:
rendered_content = proxy_template.render(item=service)
with open(output_path, 'w') as f:
f.write(rendered_content)
print(f" [OK] Generated {filename}")
except Exception as e:
print(f" [!!] ERROR: Failed to render or write config for {service['name']}: {e}")
print("\n--- Generation Complete ---")
if __name__ == "__main__":
generate_configs()