templating - road to web ui
This commit is contained in:
parent
1d96620ae6
commit
2db967ad1d
|
@ -3,37 +3,45 @@ import jinja2, glob, os, pathlib, copy, crypt, random, string
|
|||
class Templator :
|
||||
|
||||
def __init__(self, config, input_path, output_path, target_path) :
|
||||
self.__config = config
|
||||
self.__config_global = copy.deepcopy(config)
|
||||
if config["MULTISITE"] == "yes" and config["SERVER_NAME"] != "" :
|
||||
self.__config_sites = {}
|
||||
for server_name in config["SERVER_NAME"].split(" ") :
|
||||
self.__config_sites[server_name] = {}
|
||||
for k, v in config.items() :
|
||||
if k.startswith(server_name + "_") :
|
||||
self.__config_sites[server_name][k.replace(server_name + "_", "", 1)] = v
|
||||
del self.__config_global[k]
|
||||
self.__input_path = input_path
|
||||
self.__output_path = output_path
|
||||
self.__target_path = target_path
|
||||
if not self.__target_path.endswith("/") :
|
||||
self.__target_path += "/"
|
||||
self.__template_env = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath=self.__input_path), trim_blocks=True, lstrip_blocks=True)
|
||||
self.__template_env = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath=self.__input_path), lstrip_blocks=True)
|
||||
|
||||
def render_global(self) :
|
||||
return self.__render("global")
|
||||
|
||||
def render_site(self, server_name=None, first_server=None) :
|
||||
if server_name is None :
|
||||
server_name = self.__config["SERVER_NAME"]
|
||||
server_name = self.__config_global["SERVER_NAME"]
|
||||
if first_server is None :
|
||||
first_server = self.__config["SERVER_NAME"].split(" ")[0]
|
||||
first_server = self.__config_global["SERVER_NAME"].split(" ")[0]
|
||||
return self.__render("site", server_name, first_server)
|
||||
|
||||
def __prepare_config(self, type, server_name=None, first_server=None) :
|
||||
real_config = copy.deepcopy(self.__config)
|
||||
real_config = copy.deepcopy(self.__config_global)
|
||||
if type == "site" and self.__config_global["MULTISITE"] == "yes" :
|
||||
site_config = copy.deepcopy(self.__config_sites[first_server])
|
||||
real_config.update(site_config)
|
||||
if not server_name is None :
|
||||
real_config["SERVER_NAME"] = server_name
|
||||
if not first_server is None :
|
||||
real_config["FIRST_SERVER"] = first_server
|
||||
real_config["NGINX_PREFIX"] = self.__target_path
|
||||
if real_config["MULTISITE"] == "yes" and type == "site" :
|
||||
if self.__config_global["MULTISITE"] == "yes" and type == "site" :
|
||||
real_config["NGINX_PREFIX"] += first_server + "/"
|
||||
real_config["ROOT_FOLDER"] += "/" + first_server
|
||||
for variable, value in self.__config.items() :
|
||||
if variable.startswith(first_server + "_") :
|
||||
real_config[variable.replace(first_server + "_", "", 1)] = value
|
||||
if real_config["ROOT_SITE_SUBFOLDER"] != "" :
|
||||
real_config["ROOT_FOLDER"] += "/" + real_config["ROOT_SITE_SUBFOLDER"]
|
||||
return real_config
|
||||
|
|
|
@ -1 +1 @@
|
|||
./main.py --settings /opt/work/bunkerized-nginx/settings.json --templates /opt/work/bunkerized-nginx/confs2 --output /tmp/debug --variables /tmp/variables.env
|
||||
./main.py --settings /opt/work/bunkerized-nginx/settings.json --templates /opt/work/bunkerized-nginx/confs --output /tmp/debug --variables /tmp/variables.env
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import json, uuid, glob
|
||||
|
||||
class Config :
|
||||
|
||||
def __init__(self) :
|
||||
with open("/opt/settings.json", "r") as f :
|
||||
self.__settings = json.loads(f.read())
|
||||
|
||||
def __env_to_dict(self, filename) :
|
||||
with open(filename, "r") as f :
|
||||
env = f.read()
|
||||
data = {}
|
||||
for line in env.split("\n") :
|
||||
var = line.split("=")[0]
|
||||
val = line.replace(var + "=", "", 1)
|
||||
data[var] = val
|
||||
return data
|
||||
|
||||
def __dict_to_env(self, filename, variables) :
|
||||
env = ""
|
||||
for k, v in variables.items() :
|
||||
env += k + "=" + v + "\n"
|
||||
with open(filename, "w") as f :
|
||||
f.write(env)
|
||||
|
||||
def __gen_conf(self, global_conf, services_conf) :
|
||||
conf = copy.deepcopy(global_conf)
|
||||
for service in services_conf :
|
||||
first_server = service["SERVER_NAME"].split(" ")[0]
|
||||
for k, v in service.items() :
|
||||
conf[first_server + "_" + k] = v
|
||||
env_file = "/tmp/" + str(uuid.uuid4()) + ".env"
|
||||
self.__dict_to_env(env_file, conf)
|
||||
proc = subprocess.run(["/bin/su", "-c", "/opt/gen/main.py --settings /opt/settings.json --templates /opt/confs --output /etc/nginx --variables " + env_file, "nginx"], capture_output=True)
|
||||
stderr = proc.stderr.decode("ascii")
|
||||
if stderr != "" or proc.returncode != 0 :
|
||||
raise Exception("Error from generator (return code = " + str(proc.returncode) + ") : " + stderr)
|
||||
|
||||
def get_settings(self) :
|
||||
return self.__settings
|
||||
|
||||
def get_services(self) :
|
||||
services = []
|
||||
for filename in glob.iglob("/etc/nginx/**/site.env") :
|
||||
env = self.__env_to_dict(filename)
|
||||
services.append(env)
|
||||
return services
|
||||
|
||||
def check_variables(self, variables) :
|
||||
for k, v in variables.items() :
|
||||
check = False
|
||||
for category in self.__settings :
|
||||
for param in self.__settings[category]["params"] :
|
||||
if type != "multiple" :
|
||||
real_params = [param]
|
||||
else :
|
||||
real_params = param
|
||||
for real_param in real_params :
|
||||
if k == real_param["env"] and real_param["context"] == "multisite" and re.search(real_param["regex"], v) :
|
||||
check = True
|
||||
if not check :
|
||||
raise Exception("Variable " + k + " is not valid.")
|
||||
|
||||
def new_service(self, variables) :
|
||||
global_env = self.__env_to_dict("/etc/nginx/global.env")
|
||||
services = self.get_services()
|
||||
for service in services :
|
||||
if service["SERVER_NAME"] == variables["SERVER_NAME"] or service["SERVER_NAME"] in variables["SERVER_NAME"].split(" ") :
|
||||
raise Exception("Service " + service["SERVER_NAME"] + " already exists.")
|
||||
services.append(variables)
|
||||
self.__gen_conf(global_env, services)
|
||||
|
||||
def edit_service(self, old_server_name, variables) :
|
||||
self.delete_service(old_server_name)
|
||||
self.new_service(variables)
|
||||
|
||||
|
||||
def delete_service(self, server_name) :
|
||||
global_env = self.__env_to_dict("/etc/nginx/global.env")
|
||||
services = self.get_services()
|
||||
new_services = []
|
||||
found = False
|
||||
for service in services :
|
||||
if service["SERVER_NAME"].split(" ")[0] == server_name :
|
||||
found = True
|
||||
else :
|
||||
new_services.append(service)
|
||||
if not found :
|
||||
raise Exception("Can't delete missing " + server_name + " configuration.")
|
||||
self.__gen_conf(global_env, new_services)
|
||||
|
17
ui/Docker.py
17
ui/Docker.py
|
@ -17,16 +17,21 @@ class Docker :
|
|||
return self.__client.containers.get(id)
|
||||
|
||||
def reload_instance(self, id) :
|
||||
return self.get_instance(id).kill(signal="SIGHUP")
|
||||
self.get_instance(id).kill(signal="SIGHUP")
|
||||
return "Instance " + id + " has been reloaded."
|
||||
|
||||
def start_instance(self, id) :
|
||||
return self.get_instance(id).start()
|
||||
self.get_instance(id).start()
|
||||
return "Instance " + id + " has been started."
|
||||
|
||||
def stop_instance(self, id) :
|
||||
return self.get_instance(id).stop()
|
||||
self.get_instance(id).stop()
|
||||
return "Instance " + id + " has been stopped."
|
||||
|
||||
def restart_instance(self, id) :
|
||||
return self.get_instance(id).restart()
|
||||
self.get_instance(id).restart()
|
||||
return "Instance " + id + " has been restarted."
|
||||
|
||||
def remove_instance(self, id) :
|
||||
return self.get_instance(id).remove(v=True, force=True)
|
||||
def delete_instance(self, id) :
|
||||
self.get_instance(id).remove(v=True, force=True)
|
||||
return "Instance " + id + " has been deleted."
|
||||
|
|
|
@ -10,14 +10,12 @@ RUN chmod +x /tmp/dependencies.sh && \
|
|||
rm -f /tmp/dependencies.sh
|
||||
|
||||
COPY gen/ /opt/gen
|
||||
#COPY entrypoint/ /opt/entrypoint
|
||||
#COPY confs/global/ /opt/confs/global
|
||||
COPY confs/site/ /opt/confs/site
|
||||
COPY ui/* /opt/entrypoint/
|
||||
COPY ui/ /opt/entrypoint
|
||||
COPY settings.json /opt
|
||||
|
||||
COPY ui/prepare.sh /tmp
|
||||
chmod +x /tmp/prepare && \
|
||||
RUN chmod +x /tmp/prepare.sh && \
|
||||
/tmp/prepare.sh && \
|
||||
rm -f /tmp/prepare.sh
|
||||
|
||||
|
@ -25,4 +23,4 @@ EXPOSE 5000
|
|||
|
||||
WORKDIR /opt/entrypoint
|
||||
ENV FLASK_APP entrypoint.py
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
|
|
|
@ -10,14 +10,12 @@ RUN chmod +x /tmp/dependencies.sh && \
|
|||
rm -f /tmp/dependencies.sh
|
||||
|
||||
COPY gen/ /opt/gen
|
||||
#COPY entrypoint/ /opt/entrypoint
|
||||
#COPY confs/global/ /opt/confs/global
|
||||
COPY confs/site/ /opt/confs/site
|
||||
COPY ui/* /opt/entrypoint/
|
||||
COPY ui/ /opt/entrypoint
|
||||
COPY settings.json /opt
|
||||
|
||||
COPY ui/prepare.sh /tmp
|
||||
chmod +x /tmp/prepare && \
|
||||
RUN chmod +x /tmp/prepare && \
|
||||
/tmp/prepare.sh && \
|
||||
rm -f /tmp/prepare.sh
|
||||
|
||||
|
@ -25,4 +23,4 @@ EXPOSE 5000
|
|||
|
||||
WORKDIR /opt/entrypoint
|
||||
ENV FLASK_APP entrypoint.py
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
|
|
|
@ -16,14 +16,12 @@ RUN chmod +x /tmp/dependencies.sh && \
|
|||
rm -f /tmp/dependencies.sh
|
||||
|
||||
COPY gen/ /opt/gen
|
||||
#COPY entrypoint/ /opt/entrypoint
|
||||
#COPY confs/global/ /opt/confs/global
|
||||
COPY confs/site/ /opt/confs/site
|
||||
COPY ui/* /opt/entrypoint/
|
||||
COPY ui/ /opt/entrypoint
|
||||
COPY settings.json /opt
|
||||
|
||||
COPY ui/prepare.sh /tmp
|
||||
chmod +x /tmp/prepare && \
|
||||
RUN chmod +x /tmp/prepare && \
|
||||
/tmp/prepare.sh && \
|
||||
rm -f /tmp/prepare.sh
|
||||
|
||||
|
@ -31,4 +29,4 @@ EXPOSE 5000
|
|||
|
||||
WORKDIR /opt/entrypoint
|
||||
ENV FLASK_APP entrypoint.py
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
|
|
|
@ -16,14 +16,12 @@ RUN chmod +x /tmp/dependencies.sh && \
|
|||
rm -f /tmp/dependencies.sh
|
||||
|
||||
COPY gen/ /opt/gen
|
||||
#COPY entrypoint/ /opt/entrypoint
|
||||
#COPY confs/global/ /opt/confs/global
|
||||
COPY confs/site/ /opt/confs/site
|
||||
COPY ui/* /opt/entrypoint/
|
||||
COPY ui/ /opt/entrypoint
|
||||
COPY settings.json /opt
|
||||
|
||||
COPY ui/prepare.sh /tmp
|
||||
chmod +x /tmp/prepare && \
|
||||
RUN chmod +x /tmp/prepare && \
|
||||
/tmp/prepare.sh && \
|
||||
rm -f /tmp/prepare.sh
|
||||
|
||||
|
@ -31,4 +29,4 @@ EXPOSE 5000
|
|||
|
||||
WORKDIR /opt/entrypoint
|
||||
ENV FLASK_APP entrypoint.py
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
|
|
|
@ -10,14 +10,12 @@ RUN chmod +x /tmp/dependencies.sh && \
|
|||
rm -f /tmp/dependencies.sh
|
||||
|
||||
COPY gen/ /opt/gen
|
||||
#COPY entrypoint/ /opt/entrypoint
|
||||
#COPY confs/global/ /opt/confs/global
|
||||
COPY confs/site/ /opt/confs/site
|
||||
COPY ui/* /opt/entrypoint/
|
||||
COPY ui/ /opt/entrypoint
|
||||
COPY settings.json /opt
|
||||
|
||||
COPY ui/prepare.sh /tmp
|
||||
chmod +x /tmp/prepare && \
|
||||
RUN chmod +x /tmp/prepare && \
|
||||
/tmp/prepare.sh && \
|
||||
rm -f /tmp/prepare.sh
|
||||
|
||||
|
@ -25,4 +23,4 @@ EXPOSE 5000
|
|||
|
||||
WORKDIR /opt/entrypoint
|
||||
ENV FLASK_APP entrypoint.py
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "flask", "run", "--host=0.0.0.0"]
|
||||
|
|
110
ui/entrypoint.py
110
ui/entrypoint.py
|
@ -3,7 +3,8 @@
|
|||
from flask import Flask, render_template, current_app, request
|
||||
|
||||
from Docker import Docker
|
||||
import Docker, wrappers, utils
|
||||
from Config import Config
|
||||
import utils
|
||||
import os, json, re
|
||||
|
||||
app = Flask(__name__, static_url_path="/", static_folder="static", template_folder="templates")
|
||||
|
@ -11,9 +12,8 @@ ABSOLUTE_URI = ""
|
|||
if "ABSOLUTE_URI" in os.environ :
|
||||
ABSOLUTE_URI = os.environ["ABSOLUTE_URI"]
|
||||
app.config["ABSOLUTE_URI"] = ABSOLUTE_URI
|
||||
with open("/opt/settings.json", "r") as f :
|
||||
app.config["CONFIG"] = json.loads(f.read())
|
||||
app.config["DOCKER"] = Docker()
|
||||
app.config["CONFIG"] = Config()
|
||||
app.jinja_env.globals.update(env_to_summary_class=utils.env_to_summary_class)
|
||||
app.jinja_env.globals.update(form_service_gen=utils.form_service_gen)
|
||||
app.jinja_env.globals.update(form_service_gen_multiple=utils.form_service_gen_multiple)
|
||||
|
@ -24,7 +24,7 @@ app.jinja_env.globals.update(form_service_gen_multiple_values=utils.form_service
|
|||
def home() :
|
||||
try :
|
||||
instances_number = len(app.config["DOCKER"].get_instances())
|
||||
services_number = 0 # TODO
|
||||
services_number = len(app.config["CONFIG"].get_services())
|
||||
return render_template("home.html", title="Home", instances_number=instances_number, services_number=services_number)
|
||||
except Exception as e :
|
||||
return render_template("error.html", title="Error", error=e)
|
||||
|
@ -38,88 +38,70 @@ def instances() :
|
|||
|
||||
# Check operation
|
||||
if not "operation" in request.form or not request.form["operation"] in ["reload", "start", "stop", "restart", "delete"] :
|
||||
return render_template("error.html", title="Error", error="Missing operation parameter on /instances.")
|
||||
raise Exception("Missing operation parameter on /instances.")
|
||||
|
||||
# Check that all fields are present
|
||||
if not "INSTANCE_ID" in request.form :
|
||||
return render_template("error.html", title="Error", error="Missing INSTANCE_ID parameter.")
|
||||
raise Exception("Missing INSTANCE_ID parameter.")
|
||||
|
||||
# Do the operation
|
||||
if request.form["operation"] == "reload" :
|
||||
app.config["DOCKER"].reload(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].reload(request_form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "start" :
|
||||
app.config["DOCKER"].start(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].start(request_form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "stop" :
|
||||
app.config["DOCKER"].stop(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].stop(request_form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "restart" :
|
||||
app.config["DOCKER"].restart(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].restart(request_form["INSTANCE_ID"])
|
||||
elif request.form["operation"] == "delete" :
|
||||
app.config["DOCKER"].remove(request_form["INSTANCE_ID"])
|
||||
operation = app.config["DOCKER"].delete(request_form["INSTANCE_ID"])
|
||||
|
||||
# Display instances
|
||||
instances = app.config["DOCKER"].get_instances()
|
||||
return render_template("instances.html", title="Instances", instances=instances, operation="todo")
|
||||
return render_template("instances.html", title="Instances", instances=instances, operation=operation)
|
||||
|
||||
except Exception as e :
|
||||
return render_template("error.html", title="Error", error=e)
|
||||
return render_template("error.html", title="Error", error=str(e))
|
||||
|
||||
|
||||
@app.route('/services', methods=["GET", "POST"])
|
||||
def services():
|
||||
try :
|
||||
# Manage services
|
||||
operation = ""
|
||||
if request.method == "POST" :
|
||||
|
||||
# Get the client
|
||||
check, client = wrappers.get_client()
|
||||
if not check :
|
||||
return render_template("error.html", title="Error", error=client)
|
||||
# Check operation
|
||||
if not "operation" in request.form or not request.form["operation"] in ["new", "edit", "delete"] :
|
||||
raise Exception("Missing operation parameter on /services.")
|
||||
|
||||
# Manage services
|
||||
operation = ""
|
||||
if request.method == "POST" :
|
||||
# Check variables
|
||||
variables = copy.deepcopy(request.form)
|
||||
if not "OLD_SERVER_NAME" in request.form and request.form["operation"] == "edit" :
|
||||
raise Exception("Missing OLD_SERVER_NAME parameter.")
|
||||
if request.form["operation"] in ["new", "edit"] :
|
||||
del variables["operation"]
|
||||
if request.form["operation"] == "edit" :
|
||||
del variables["OLD_SERVER_NAME"]
|
||||
app.config["CONFIG"].check_variables(variables)
|
||||
|
||||
# Check operation
|
||||
if not "operation" in request.form or not request.form["operation"] in ["new", "edit", "delete"] :
|
||||
return render_template("error.html", title="Error", error="Missing operation parameter on /services.")
|
||||
# Delete
|
||||
elif request.form["operation"] == "delete" :
|
||||
if not "SERVER_NAME" in request.form :
|
||||
raise Exception("Missing SERVER_NAME parameter.")
|
||||
app.config["CONFIG"].check_variables({"SERVER_NAME" : request.form["SERVER_NAME"]})
|
||||
|
||||
# Check that all fields are present and they match the corresponding regex
|
||||
env = {}
|
||||
env["MULTISITE"] = "yes"
|
||||
if request.form["operation"] in ["new", "edit"] :
|
||||
for category in current_app.config["CONFIG"] :
|
||||
for param in current_app.config["CONFIG"][category]["params"] :
|
||||
if param["type"] == "multiple" :
|
||||
for param_user in request.form :
|
||||
if param_user.startswith(param["params"][0]["env"]) :
|
||||
suffix = param_user.replace(param["params"][0]["env"], "")
|
||||
for param_multiple in param["params"] :
|
||||
if not param_multiple["env"] + suffix in request.form :
|
||||
return render_template("error.html", title="Error", error="Missing " + param["env"] + " parameter.")
|
||||
if not re.search(param_multiple["regex"], request.form[param_multiple["env"] + suffix]) :
|
||||
return render_template("error.html", title="Error", error="Parameter " + param["env"] + " doesn't match regex.")
|
||||
env[param_multiple["env"] + suffix] = request.form[param_multiple["env"] + suffix]
|
||||
else :
|
||||
if not param["env"] in request.form :
|
||||
return render_template("error.html", title="Error", error="Missing " + param["env"] + " parameter.")
|
||||
if not re.search(param["regex"], request.form[param["env"]]) :
|
||||
return render_template("error.html", title="Error", error="Parameter " + param["env"] + " doesn't match regex.")
|
||||
env[param["env"]] = request.form[param["env"]]
|
||||
if request.form["operation"] == "edit" :
|
||||
if not "OLD_SERVER_NAME" in request.form :
|
||||
return render_template("error.html", title="Error", error="Missing OLD_SERVER_NAME parameter.")
|
||||
if not re.search("^([a-z\-0-9]+\.?)+$", request.form["OLD_SERVER_NAME"]) :
|
||||
return render_template("error.html", title="Error", error="Parameter OLD_SERVER_NAME doesn't match regex.")
|
||||
elif request.form["operation"] == "delete" :
|
||||
if not "SERVER_NAME" in request.form :
|
||||
return render_template("error.html", title="Error", error="Missing SERVER_NAME parameter.")
|
||||
if not re.search("^([a-z\-0-9]+\.?)+$", request.form["SERVER_NAME"]) :
|
||||
return render_template("error.html", title="Error", error="Parameter SERVER_NAME doesn't match regex.")
|
||||
# Do the operation
|
||||
if request.form["operation"] == "new" :
|
||||
operation = app.config["CONFIG"].new_service(variables)
|
||||
elif request.form["operation"] == "edit" :
|
||||
operation = app.config["CONFIG"].edit_service(request.form["OLD_SERVER_NAME"], variables)
|
||||
elif request.form["operation"] == "delete" :
|
||||
operation = app.config["CONFIG"].delete_service(request.form["SERVER_NAME"])
|
||||
|
||||
# Do the operation
|
||||
check, operation = wrappers.operation_service(client, request.form, env)
|
||||
if not check :
|
||||
render_template("error.html", title="Error", error=operation)
|
||||
# Display services
|
||||
services = app.config["CONFIG"].get_services()
|
||||
return render_template("services.html", title="Services", services=services, operation=operation)
|
||||
|
||||
# Display services
|
||||
check, services = wrappers.get_services()
|
||||
if not check :
|
||||
return render_template("error.html", title="Error", error=services)
|
||||
return render_template("services.html", title="Services", services=services, operation=operation)
|
||||
except Exception as e :
|
||||
return render_template("error.html", title="Error", error=str(e))
|
|
@ -8,7 +8,7 @@
|
|||
<div class="modal-body">
|
||||
<ul class="nav nav-pills mb-3" id="pills-tab-edit" role="tablist">
|
||||
{% set check = {"active": "active", "selected": "true"} %}
|
||||
{% for k, v in config["CONFIG"].items() %}
|
||||
{% for k, v in config["CONFIG"].get_config().items() %}
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {{ check.active }}" id="edit-{{ v["id"] }}-{{ id_server_name }}-tab" data-bs-toggle="pill" href="#edit-{{ v["id"] }}-{{ id_server_name }}" role="tab" aria-controls="edit-{{ v["id"] }}-{{ id_server_name }}" aria-selected="{{ check.selected }}">{{ k }}</a>
|
||||
</li>
|
||||
|
@ -20,7 +20,7 @@
|
|||
<input type="hidden" value="{{ service["SERVER_NAME"] }}" name="OLD_SERVER_NAME">
|
||||
<div class="tab-content" id="edit-content-{{ id_server_name }}">
|
||||
{% set check = {"class": "show active"} %}
|
||||
{% for k, v in config["CONFIG"].items() %}
|
||||
{% for k, v in config["CONFIG"].get_config().items() %}
|
||||
<div class="tab-pane fade {{ check.class }}" id="edit-{{ v["id"] }}-{{ id_server_name }}" role="tabpanel" aria-labelledby="edit-{{ v["id"] }}-{{ id_server_name }}-tab">
|
||||
{% for param in v["params"] %}
|
||||
<div class="row mb-3" id="form-edit-{{ id_server_name }}-{{ param["id"] }}">
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<div class="modal-body">
|
||||
<ul class="nav nav-pills mb-3" id="pills-tab-new" role="tablist">
|
||||
{% set check = {"active": "active", "selected": "true"} %}
|
||||
{% for k, v in config["CONFIG"].items() %}
|
||||
{% for k, v in config["CONFIG"].get_config().items() %}
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {{ check.active }}" id="new-{{ v["id"] }}-tab" data-bs-toggle="pill" href="#new-{{ v["id"] }}" role="tab" aria-controls="new-{{ v["id"] }}" aria-selected="{{ check.selected }}">{{ k }}</a>
|
||||
</li>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<form id="form-new">
|
||||
<div class="tab-content" id="new-content">
|
||||
{% set check = {"class": "show active"} %}
|
||||
{% for k, v in config["CONFIG"].items() %}
|
||||
{% for k, v in config["CONFIG"].get_config().items() %}
|
||||
<div class="tab-pane fade {{ check.class }}" id="new-{{ v["id"] }}" role="tabpanel" aria-labelledby="new-{{ v["id"] }}-tab">
|
||||
{% for param in v["params"] %}
|
||||
<div class="row mb-3" id="form-new-{{ param["id"] }}">
|
||||
|
@ -43,4 +43,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -5,13 +5,6 @@ import datetime, re, json
|
|||
def log(event) :
|
||||
print("[" + str(datetime.datetime.now().replace(microsecond=0)) + "] " + event, flush=True)
|
||||
|
||||
def replace_in_file(file, old_str, new_str) :
|
||||
with open(file) as f :
|
||||
data = f.read()
|
||||
data = data[::-1].replace(old_str[::-1], new_str[::-1], 1)[::-1]
|
||||
with open(file, "w") as f :
|
||||
f.write(data)
|
||||
|
||||
def env_to_summary_class(var, value) :
|
||||
if type(var) is list and type(value) is list :
|
||||
for i in range(0, len(var)) :
|
||||
|
|
168
ui/wrappers.py
168
ui/wrappers.py
|
@ -1,168 +0,0 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import utils
|
||||
import docker, os, stat, sys, subprocess, shutil
|
||||
|
||||
def get_client() :
|
||||
endpoint = "/var/run/docker.sock"
|
||||
if not os.path.exists(endpoint) or not stat.S_ISSOCK(os.stat(endpoint).st_mode) :
|
||||
return False, "Can't connect to /var/run/docker.sock (is it mounted ?)"
|
||||
try :
|
||||
client = docker.DockerClient(base_url='unix:///var/run/docker.sock')
|
||||
except Exception as e :
|
||||
return False, "Can't instantiate DockerClient : " + str(e)
|
||||
return True, client
|
||||
|
||||
def get_containers(client, label) :
|
||||
try :
|
||||
containers = client.containers.list(all=True, filters={"label" : "bunkerized-nginx." + label})
|
||||
except docker.errors.APIError as e :
|
||||
return False, "Docker API error " + str(e)
|
||||
return True, containers
|
||||
|
||||
def get_instances(client) :
|
||||
return get_containers(client, "UI")
|
||||
|
||||
def get_services() :
|
||||
services = []
|
||||
try :
|
||||
for root, dirs, files in os.walk("/etc/nginx") :
|
||||
for file in files :
|
||||
filepath = os.path.join(root, file)
|
||||
if filepath.endswith("/nginx.env") :
|
||||
with open(filepath, "r") as f :
|
||||
service = {}
|
||||
for line in f.readlines() :
|
||||
name = line.split("=")[0]
|
||||
value = line.replace(name + "=", "", 1).strip()
|
||||
service[name] = value
|
||||
services.append(service)
|
||||
except Exception as e :
|
||||
return False, str(e)
|
||||
return True, services
|
||||
|
||||
def reload_instances(client) :
|
||||
check, instances = get_instances(client)
|
||||
if not check :
|
||||
return check, instances
|
||||
i = 0
|
||||
for instance in instances :
|
||||
try :
|
||||
instance.kill(signal="SIGHUP")
|
||||
except docker.errors.APIError as e :
|
||||
return False, str(e)
|
||||
i += 1
|
||||
return True, i
|
||||
|
||||
def new_service(client, env) :
|
||||
proc = subprocess.run(["/bin/su", "-s", "/bin/sh", "-c", "/opt/entrypoint/site-config.sh" + " " + env["SERVER_NAME"], "nginx"], env=env, capture_output=True)
|
||||
if proc.returncode != 0 :
|
||||
return False, "Error code " + str(proc.returncode) + " while generating config."
|
||||
utils.replace_in_file("/etc/nginx/nginx.conf", "}", "include /etc/nginx/" + env["SERVER_NAME"] + "/server.conf;\n}")
|
||||
check, nb = reload_instances(client)
|
||||
if not check :
|
||||
return check, nb
|
||||
return True, "Web service " + env["SERVER_NAME"] + " has been added."
|
||||
|
||||
def edit_service(client, old_server_name, env) :
|
||||
check, delete = delete_service(client, old_server_name)
|
||||
if not check :
|
||||
return check, delete
|
||||
check, new = new_service(client, env)
|
||||
if not check :
|
||||
return check, new
|
||||
return True, "Web service " + old_server_name + " has been edited."
|
||||
|
||||
def delete_service(client, server_name) :
|
||||
if not os.path.isdir("/etc/nginx/" + server_name) :
|
||||
return False, "Config doesn't exist."
|
||||
try :
|
||||
shutil.rmtree("/etc/nginx/" + server_name)
|
||||
except Exception as e :
|
||||
return False, str(e)
|
||||
utils.replace_in_file("/etc/nginx/nginx.conf", "include /etc/nginx/" + server_name + "/server.conf;\n", "")
|
||||
check, nb = reload_instances(client)
|
||||
if not check :
|
||||
return check, nb
|
||||
return True, "Web service " + server_name + " has been deleted."
|
||||
|
||||
def operation_service(client, form, env) :
|
||||
if form["operation"] == "new" :
|
||||
return new_service(client, env)
|
||||
if form["operation"] == "edit" :
|
||||
return edit_service(client, form["OLD_SERVER_NAME"], env)
|
||||
if form["operation"] == "delete" :
|
||||
return delete_service(client, form["SERVER_NAME"])
|
||||
return False, "Wrong operation parameter."
|
||||
|
||||
def get_instance(client, id) :
|
||||
try :
|
||||
instance = client.containers.get(id)
|
||||
if not "bunkerized-nginx.UI" in instance.labels :
|
||||
raise docker.errors.NotFound()
|
||||
except Exception as e :
|
||||
return False, str(e)
|
||||
return True, instance
|
||||
|
||||
def reload_instance(client, id) :
|
||||
check, instance = get_instance(client, id)
|
||||
if not check :
|
||||
return check, instance
|
||||
try :
|
||||
instance.kill(signal="SIGHUP")
|
||||
except docker.errors.APIError as e :
|
||||
return False, str(e)
|
||||
return True, "Instance " + id + " has been reloaded."
|
||||
|
||||
def start_instance(client, id) :
|
||||
check, instance = get_instance(client, id)
|
||||
if not check :
|
||||
return check, instance
|
||||
try :
|
||||
instance.start()
|
||||
except docker.errors.APIError as e :
|
||||
return False, str(e)
|
||||
return True, "Instance " + id + " has been started."
|
||||
|
||||
def stop_instance(client, id) :
|
||||
check, instance = get_instance(client, id)
|
||||
if not check :
|
||||
return check, instance
|
||||
try :
|
||||
instance.stop()
|
||||
except docker.errors.APIError as e :
|
||||
return False, str(e)
|
||||
return True, "Instance " + id + " has been stopped."
|
||||
|
||||
def restart_instance(client, id) :
|
||||
check, instance = get_instance(client, id)
|
||||
if not check :
|
||||
return check, instance
|
||||
try :
|
||||
instance.restart()
|
||||
except docker.errors.APIError as e :
|
||||
return False, str(e)
|
||||
return True, "Instance " + id + " has been restarted."
|
||||
|
||||
def delete_instance(client, id) :
|
||||
check, instance = get_instance(client, id)
|
||||
if not check :
|
||||
return check, instance
|
||||
try :
|
||||
instance.remove(v=True, force=True)
|
||||
except docker.errors.APIError as e :
|
||||
return False, str(e)
|
||||
return True, "Instance " + id + " has been deleted."
|
||||
|
||||
def operation_instance(client, form) :
|
||||
if form["operation"] == "reload" :
|
||||
return reload_instance(client, form["INSTANCE_ID"])
|
||||
if form["operation"] == "start" :
|
||||
return start_instance(client, form["INSTANCE_ID"])
|
||||
if form["operation"] == "stop" :
|
||||
return stop_instance(client, form["INSTANCE_ID"])
|
||||
if form["operation"] == "restart" :
|
||||
return restart_instance(client, form["INSTANCE_ID"])
|
||||
if form["operation"] == "delete" :
|
||||
return delete_instance(client, form["INSTANCE_ID"])
|
||||
return False, "Wrong operation parameter."
|
Loading…
Reference in New Issue