mirror of
https://github.com/frappe/bench.git
synced 2024-09-27 22:39:03 +00:00
bbf0169994
Changes * Added sugared option class that allows setting options only if another is set * setup nginx command allows to set logging level & log_format options
303 lines
8.3 KiB
Python
303 lines
8.3 KiB
Python
# imports - standard imports
|
|
import hashlib
|
|
import os
|
|
import random
|
|
import string
|
|
|
|
# imports - third party imports
|
|
import click
|
|
|
|
# imports - module imports
|
|
import bench
|
|
import bench.config
|
|
from bench.bench import Bench
|
|
from bench.utils import get_bench_name
|
|
|
|
|
|
def make_nginx_conf(bench_path, yes=False, logging=None, log_format=None):
|
|
conf_path = os.path.join(bench_path, "config", "nginx.conf")
|
|
|
|
if not yes and os.path.exists(conf_path):
|
|
if not click.confirm(
|
|
"nginx.conf already exists and this will overwrite it. Do you want to continue?"
|
|
):
|
|
return
|
|
|
|
template = bench.config.env().get_template("nginx.conf")
|
|
bench_path = os.path.abspath(bench_path)
|
|
sites_path = os.path.join(bench_path, "sites")
|
|
|
|
config = Bench(bench_path).conf
|
|
sites = prepare_sites(config, bench_path)
|
|
bench_name = get_bench_name(bench_path)
|
|
|
|
allow_rate_limiting = config.get("allow_rate_limiting", False)
|
|
|
|
template_vars = {
|
|
"sites_path": sites_path,
|
|
"http_timeout": config.get("http_timeout"),
|
|
"sites": sites,
|
|
"webserver_port": config.get("webserver_port"),
|
|
"socketio_port": config.get("socketio_port"),
|
|
"bench_name": bench_name,
|
|
"error_pages": get_error_pages(),
|
|
"allow_rate_limiting": allow_rate_limiting,
|
|
# for nginx map variable
|
|
"random_string": "".join(random.choice(string.ascii_lowercase) for i in range(7)),
|
|
}
|
|
|
|
if logging and logging != "none":
|
|
_log_format = ""
|
|
if log_format and log_format != "none":
|
|
_log_format = log_format
|
|
template_vars["logging"] = {"level": logging, "log_format": _log_format}
|
|
|
|
if allow_rate_limiting:
|
|
template_vars.update(
|
|
{
|
|
"bench_name_hash": hashlib.sha256(bench_name).hexdigest()[:16],
|
|
"limit_conn_shared_memory": get_limit_conn_shared_memory(),
|
|
}
|
|
)
|
|
|
|
nginx_conf = template.render(**template_vars)
|
|
|
|
with open(conf_path, "w") as f:
|
|
f.write(nginx_conf)
|
|
|
|
|
|
def make_bench_manager_nginx_conf(bench_path, yes=False, port=23624, domain=None):
|
|
from bench.config.site_config import get_site_config
|
|
|
|
template = bench.config.env().get_template("bench_manager_nginx.conf")
|
|
bench_path = os.path.abspath(bench_path)
|
|
sites_path = os.path.join(bench_path, "sites")
|
|
|
|
config = Bench(bench_path).conf
|
|
site_config = get_site_config(domain, bench_path=bench_path)
|
|
bench_name = get_bench_name(bench_path)
|
|
|
|
template_vars = {
|
|
"port": port,
|
|
"domain": domain,
|
|
"bench_manager_site_name": "bench-manager.local",
|
|
"sites_path": sites_path,
|
|
"http_timeout": config.get("http_timeout"),
|
|
"webserver_port": config.get("webserver_port"),
|
|
"socketio_port": config.get("socketio_port"),
|
|
"bench_name": bench_name,
|
|
"error_pages": get_error_pages(),
|
|
"ssl_certificate": site_config.get("ssl_certificate"),
|
|
"ssl_certificate_key": site_config.get("ssl_certificate_key"),
|
|
}
|
|
|
|
bench_manager_nginx_conf = template.render(**template_vars)
|
|
|
|
conf_path = os.path.join(bench_path, "config", "nginx.conf")
|
|
|
|
if not yes and os.path.exists(conf_path):
|
|
click.confirm(
|
|
"nginx.conf already exists and bench-manager configuration will be appended to it. Do you want to continue?",
|
|
abort=True,
|
|
)
|
|
|
|
with open(conf_path, "a") as myfile:
|
|
myfile.write(bench_manager_nginx_conf)
|
|
|
|
|
|
def prepare_sites(config, bench_path):
|
|
sites = {
|
|
"that_use_port": [],
|
|
"that_use_dns": [],
|
|
"that_use_ssl": [],
|
|
"that_use_wildcard_ssl": [],
|
|
}
|
|
|
|
domain_map = {}
|
|
ports_in_use = {}
|
|
|
|
dns_multitenant = config.get("dns_multitenant")
|
|
|
|
shared_port_exception_found = False
|
|
sites_configs = get_sites_with_config(bench_path=bench_path)
|
|
|
|
# preload all preset site ports to avoid conflicts
|
|
|
|
if not dns_multitenant:
|
|
for site in sites_configs:
|
|
if site.get("port"):
|
|
if not site["port"] in ports_in_use:
|
|
ports_in_use[site["port"]] = []
|
|
ports_in_use[site["port"]].append(site["name"])
|
|
|
|
for site in sites_configs:
|
|
if dns_multitenant:
|
|
domain = site.get("domain")
|
|
|
|
if domain:
|
|
# when site's folder name is different than domain name
|
|
domain_map[domain] = site["name"]
|
|
|
|
site_name = domain or site["name"]
|
|
|
|
if site.get("wildcard"):
|
|
sites["that_use_wildcard_ssl"].append(site_name)
|
|
|
|
if not sites.get("wildcard_ssl_certificate"):
|
|
sites["wildcard_ssl_certificate"] = site["ssl_certificate"]
|
|
sites["wildcard_ssl_certificate_key"] = site["ssl_certificate_key"]
|
|
|
|
elif site.get("ssl_certificate") and site.get("ssl_certificate_key"):
|
|
sites["that_use_ssl"].append(site)
|
|
|
|
else:
|
|
sites["that_use_dns"].append(site_name)
|
|
|
|
else:
|
|
if not site.get("port"):
|
|
site["port"] = 80
|
|
if site["port"] in ports_in_use:
|
|
site["port"] = 8001
|
|
while site["port"] in ports_in_use:
|
|
site["port"] += 1
|
|
|
|
if site["port"] in ports_in_use and not site["name"] in ports_in_use[site["port"]]:
|
|
shared_port_exception_found = True
|
|
ports_in_use[site["port"]].append(site["name"])
|
|
else:
|
|
ports_in_use[site["port"]] = []
|
|
ports_in_use[site["port"]].append(site["name"])
|
|
|
|
sites["that_use_port"].append(site)
|
|
|
|
if not dns_multitenant and shared_port_exception_found:
|
|
message = "Port conflicts found:"
|
|
port_conflict_index = 0
|
|
for port_number in ports_in_use:
|
|
if len(ports_in_use[port_number]) > 1:
|
|
port_conflict_index += 1
|
|
message += f"\n{port_conflict_index} - Port {port_number} is shared among sites:"
|
|
for site_name in ports_in_use[port_number]:
|
|
message += f" {site_name}"
|
|
raise Exception(message)
|
|
|
|
if not dns_multitenant:
|
|
message = "Port configuration list:"
|
|
for site in sites_configs:
|
|
message += f"\n\nSite {site['name']} assigned port: {site['port']}"
|
|
|
|
print(message)
|
|
|
|
sites["domain_map"] = domain_map
|
|
|
|
return sites
|
|
|
|
|
|
def get_sites_with_config(bench_path):
|
|
from bench.bench import Bench
|
|
from bench.config.site_config import get_site_config
|
|
|
|
bench = Bench(bench_path)
|
|
sites = bench.sites
|
|
conf = bench.conf
|
|
dns_multitenant = conf.get("dns_multitenant")
|
|
|
|
ret = []
|
|
for site in sites:
|
|
try:
|
|
site_config = get_site_config(site, bench_path=bench_path)
|
|
except Exception as e:
|
|
strict_nginx = conf.get("strict_nginx")
|
|
if strict_nginx:
|
|
print(
|
|
f"\n\nERROR: The site config for the site {site} is broken.",
|
|
"If you want this command to pass, instead of just throwing an error,",
|
|
"You may remove the 'strict_nginx' flag from common_site_config.json or set it to 0",
|
|
"\n\n",
|
|
)
|
|
raise e
|
|
else:
|
|
print(
|
|
f"\n\nWARNING: The site config for the site {site} is broken.",
|
|
"If you want this command to fail, instead of just showing a warning,",
|
|
"You may add the 'strict_nginx' flag to common_site_config.json and set it to 1",
|
|
"\n\n",
|
|
)
|
|
continue
|
|
|
|
ret.append(
|
|
{
|
|
"name": site,
|
|
"port": site_config.get("nginx_port"),
|
|
"ssl_certificate": site_config.get("ssl_certificate"),
|
|
"ssl_certificate_key": site_config.get("ssl_certificate_key"),
|
|
}
|
|
)
|
|
|
|
if dns_multitenant and site_config.get("domains"):
|
|
for domain in site_config.get("domains"):
|
|
# domain can be a string or a dict with 'domain', 'ssl_certificate', 'ssl_certificate_key'
|
|
if isinstance(domain, str):
|
|
domain = {"domain": domain}
|
|
|
|
domain["name"] = site
|
|
ret.append(domain)
|
|
|
|
use_wildcard_certificate(bench_path, ret)
|
|
|
|
return ret
|
|
|
|
|
|
def use_wildcard_certificate(bench_path, ret):
|
|
"""
|
|
stored in common_site_config.json as:
|
|
"wildcard": {
|
|
"domain": "*.erpnext.com",
|
|
"ssl_certificate": "/path/to/erpnext.com.cert",
|
|
"ssl_certificate_key": "/path/to/erpnext.com.key"
|
|
}
|
|
"""
|
|
from bench.bench import Bench
|
|
|
|
config = Bench(bench_path).conf
|
|
wildcard = config.get("wildcard")
|
|
|
|
if not wildcard:
|
|
return
|
|
|
|
domain = wildcard["domain"]
|
|
ssl_certificate = wildcard["ssl_certificate"]
|
|
ssl_certificate_key = wildcard["ssl_certificate_key"]
|
|
|
|
# If domain is set as "*" all domains will be included
|
|
if domain.startswith("*"):
|
|
domain = domain[1:]
|
|
else:
|
|
domain = "." + domain
|
|
|
|
for site in ret:
|
|
if site.get("ssl_certificate"):
|
|
continue
|
|
|
|
if (site.get("domain") or site["name"]).endswith(domain):
|
|
# example: ends with .erpnext.com
|
|
site["ssl_certificate"] = ssl_certificate
|
|
site["ssl_certificate_key"] = ssl_certificate_key
|
|
site["wildcard"] = 1
|
|
|
|
|
|
def get_error_pages():
|
|
bench_app_path = os.path.abspath(bench.__path__[0])
|
|
templates = os.path.join(bench_app_path, "config", "templates")
|
|
|
|
return {502: os.path.join(templates, "502.html")}
|
|
|
|
|
|
def get_limit_conn_shared_memory():
|
|
"""Allocate 2 percent of total virtual memory as shared memory for nginx limit_conn_zone"""
|
|
total_vm = (os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES")) / (
|
|
1024 * 1024
|
|
) # in MB
|
|
|
|
return int(0.02 * total_vm)
|