server steering implementation
This commit is contained in:
+163
-16
@@ -26,8 +26,10 @@ from bson.objectid import ObjectId
|
|||||||
import user as user_store
|
import user as user_store
|
||||||
import buchungen
|
import buchungen
|
||||||
import server_steering as steering
|
import server_steering as steering
|
||||||
from modules.emailservice.email import send_register_token
|
from modules.emailservice.email import send_register_token, send_accreditation_email
|
||||||
import secrets
|
import secrets
|
||||||
|
import requests
|
||||||
|
from server_steering import Instance
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = "ASDfhbsdfseiufhgildsrfrjg874368546987s6e8468f4!?FAUS/&s"
|
app.secret_key = "ASDfhbsdfseiufhgildsrfrjg874368546987s6e8468f4!?FAUS/&s"
|
||||||
@@ -3607,26 +3609,171 @@ def logout():
|
|||||||
flash('Logged out successfully', 'info')
|
flash('Logged out successfully', 'info')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
@app.route('/booking_payment_async', methods=['POST'])
|
def generate_secure_password(length=14):
|
||||||
def booking_payment_async():
|
alphabet = string.ascii_letters + string.digits
|
||||||
# ... Speichere Daten in DB ...
|
return ''.join(secrets.choice(alphabet) for _ in range(length))
|
||||||
# ... Starte das manage-tenants.sh Skript ASYNCHRON (z.B. Celery) ...
|
|
||||||
return jsonify({"success": True, "tenant_slug": request.form['tenant_slug']}), 200
|
|
||||||
|
|
||||||
|
def _utc_now_iso():
|
||||||
|
return datetime.now(timezone.utc).isoformat()
|
||||||
|
|
||||||
|
def run_tenant_provisioning_async(app, user_id, tenant_slug, school_name, user_email, prov_id):
|
||||||
|
with app.app_context():
|
||||||
|
# Helper to update provisioning status in 'instance_requests' collection
|
||||||
|
def _update_prov_status(status, extra_fields=None):
|
||||||
|
req_client, req_col = _get_collection("instance_requests")
|
||||||
|
try:
|
||||||
|
update_data = {
|
||||||
|
"provision_status": status,
|
||||||
|
"updated_at": _utc_now_iso()
|
||||||
|
}
|
||||||
|
if extra_fields:
|
||||||
|
update_data.update(extra_fields)
|
||||||
|
|
||||||
|
req_col.update_one(
|
||||||
|
{"_id": ObjectId(prov_id)},
|
||||||
|
{"$set": update_data}
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
req_client.close()
|
||||||
|
|
||||||
|
# Set status to processing
|
||||||
|
_update_prov_status("in_progress")
|
||||||
|
|
||||||
|
# 1. Determine next available port dynamically
|
||||||
|
existing_tenants = Instance.list()
|
||||||
|
used_ports = [t['port'] for t in existing_tenants if 'port' in t]
|
||||||
|
next_port = max(used_ports) + 1 if used_ports else 10002
|
||||||
|
|
||||||
|
admin_password = generate_secure_password()
|
||||||
|
|
||||||
|
# 2. Execute script to create tenant
|
||||||
|
success = Instance.new(tenant_slug, next_port, admin_password)
|
||||||
|
if not success:
|
||||||
|
_update_prov_status("failed", {"last_error": "Tenant shell creation failed"})
|
||||||
|
return
|
||||||
|
|
||||||
|
# Enable default modules
|
||||||
|
Instance.edit(tenant_slug, "starter")
|
||||||
|
|
||||||
|
# 3. Create instance document & link to user
|
||||||
|
instance_doc = {
|
||||||
|
"owner_id": user_id,
|
||||||
|
"school_name": school_name,
|
||||||
|
"subdomain": tenant_slug,
|
||||||
|
"domain": f"{tenant_slug}.invario-software.de",
|
||||||
|
"https_port": next_port,
|
||||||
|
"status": "ready",
|
||||||
|
"nginx_status": "active",
|
||||||
|
"admin_username": "admin",
|
||||||
|
"admin_password": admin_password
|
||||||
|
}
|
||||||
|
|
||||||
|
inst_client, inst_col = _get_collection("instances")
|
||||||
|
try:
|
||||||
|
inst_result = inst_col.insert_one(instance_doc)
|
||||||
|
created_inst_id = str(inst_result.inserted_id)
|
||||||
|
finally:
|
||||||
|
inst_client.close()
|
||||||
|
|
||||||
|
# 4. Mark request as completed in instance_requests
|
||||||
|
_update_prov_status("completed", {
|
||||||
|
"instance_id": created_inst_id,
|
||||||
|
"domain": instance_doc["domain"]
|
||||||
|
})
|
||||||
|
|
||||||
|
# 5. Send Email with documents and access credentials
|
||||||
|
send_accreditation_email(
|
||||||
|
recipient=user_email,
|
||||||
|
domain=instance_doc["domain"],
|
||||||
|
username="admin",
|
||||||
|
password=admin_password,
|
||||||
|
invoice_pdf_path=f"/var/invoices/{tenant_slug}_invoice.pdf",
|
||||||
|
contract_pdf_path=f"/var/contracts/{tenant_slug}_contract.pdf"
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route('/booking_payment_async', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def booking_payment_async():
|
||||||
|
user_id = session.get("user_id")
|
||||||
|
user_email = session.get("email")
|
||||||
|
tenant_slug = _slugify_subdomain(request.form.get('tenant_slug'))
|
||||||
|
school_name = request.form.get('school_name', tenant_slug)
|
||||||
|
|
||||||
|
# Insert request record into instance_requests
|
||||||
|
req_client, req_col = _get_collection("instance_requests")
|
||||||
|
try:
|
||||||
|
prov_doc = {
|
||||||
|
"user_id": user_id,
|
||||||
|
"tenant_slug": tenant_slug,
|
||||||
|
"school_name": school_name,
|
||||||
|
"provision_status": "pending",
|
||||||
|
"created_at": _utc_now_iso(),
|
||||||
|
"updated_at": _utc_now_iso()
|
||||||
|
}
|
||||||
|
prov_id = str(req_col.insert_one(prov_doc).inserted_id)
|
||||||
|
finally:
|
||||||
|
req_client.close()
|
||||||
|
|
||||||
|
# Start async worker passing prov_id
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=run_tenant_provisioning_async,
|
||||||
|
args=(app._get_current_object(), user_id, tenant_slug, school_name, user_email, prov_id)
|
||||||
|
)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"tenant_slug": tenant_slug,
|
||||||
|
"request_id": prov_id
|
||||||
|
}), 200
|
||||||
|
|
||||||
@app.route('/instance_request/status')
|
@app.route('/instance_request/status')
|
||||||
def tenant_status():
|
def tenant_status():
|
||||||
slug = request.args.get('slug')
|
slug = request.args.get('slug')
|
||||||
# Prüfe in der Datenbank, ob das Skript für diesen Slug schon fertig ist
|
req_id = request.args.get('request_id')
|
||||||
if ist_fertig(slug):
|
|
||||||
return jsonify({
|
req_client, req_col = _get_collection("instance_requests")
|
||||||
"status": "ready",
|
try:
|
||||||
"url": f"https://{slug}.invario-software.de",
|
query = {}
|
||||||
"username": "admin",
|
if req_id:
|
||||||
"password": generiertes_passwort
|
query["_id"] = ObjectId(req_id)
|
||||||
})
|
elif slug:
|
||||||
else:
|
query["tenant_slug"] = slug
|
||||||
return jsonify({"status": "pending"})
|
else:
|
||||||
|
return jsonify({"status": "error", "message": "Missing slug or request_id"}), 400
|
||||||
|
|
||||||
|
prov_req = req_col.find_one(query)
|
||||||
|
finally:
|
||||||
|
req_client.close()
|
||||||
|
|
||||||
|
if not prov_req or prov_req.get("provision_status") != "completed":
|
||||||
|
return jsonify({"status": "pending"}), 200
|
||||||
|
|
||||||
|
# Retrieve created instance details for health check
|
||||||
|
inst_client, inst_col = _get_collection("instances")
|
||||||
|
try:
|
||||||
|
instance = inst_col.find_one({"subdomain": prov_req.get("tenant_slug")})
|
||||||
|
finally:
|
||||||
|
inst_client.close()
|
||||||
|
|
||||||
|
if not instance:
|
||||||
|
return jsonify({"status": "pending"}), 200
|
||||||
|
|
||||||
|
# Perform health check ping
|
||||||
|
target_url = f"https://{instance['domain']}/health"
|
||||||
|
try:
|
||||||
|
response = requests.get(target_url, timeout=3)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return jsonify({
|
||||||
|
"status": "ready",
|
||||||
|
"url": f"https://{instance['domain']}",
|
||||||
|
"username": instance.get("admin_username", "admin"),
|
||||||
|
"password": instance.get("admin_password")
|
||||||
|
}), 200
|
||||||
|
except requests.RequestException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return jsonify({"status": "pending"}), 200
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app.run(host="0.0.0.0", port=4999, debug=False)
|
app.run(host="0.0.0.0", port=4999, debug=False)
|
||||||
|
|||||||
@@ -166,4 +166,42 @@ def send_password_reset_token(email: str, token: str) -> bool:
|
|||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return send(email, subject, text_body=text_note, html_body=html_note)
|
return send(email, subject, text_body=text_note, html_body=html_note)
|
||||||
|
|
||||||
|
def send_accreditation_email(recipient: str, domain: str, username: str, password: str, invoice_pdf_path: str, contract_pdf_path: str) -> bool:
|
||||||
|
"""Sends an accreditation email with login credentials and attached documents."""
|
||||||
|
|
||||||
|
subject = "Ihre Zugangsdaten und Unterlagen für Invario"
|
||||||
|
|
||||||
|
text_note = (
|
||||||
|
f"Sehr geehrte/r {username},\n\n"
|
||||||
|
"Vielen Dank für Ihre Akkreditierung bei Invario. "
|
||||||
|
"Im Anhang finden Sie Ihre Rechnung und den Vertrag.\n\n"
|
||||||
|
f"Ihre Zugangsdaten:\n"
|
||||||
|
f"Domain: {domain}\n"
|
||||||
|
f"Benutzername: {username}\n"
|
||||||
|
f"Passwort: {password}\n\n"
|
||||||
|
"Bitte bewahren Sie diese Informationen sicher auf."
|
||||||
|
)
|
||||||
|
|
||||||
|
html_note = f"""
|
||||||
|
<div style="font-family: Arial, Helvetica, sans-serif; color: #333333;">
|
||||||
|
<h2 style="color: #2c3e50; margin-top: 0;">Willkommen bei Invario!</h2>
|
||||||
|
<p style="font-size: 15px; line-height: 1.6;">
|
||||||
|
Vielen Dank für Ihre Akkreditierung. Im Anhang finden Sie Ihre Rechnung und den Vertrag.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 style="color: #2c3e50;">Ihre Zugangsdaten:</h3>
|
||||||
|
<ul style="font-size: 15px; line-height: 1.6;">
|
||||||
|
<li><strong>Domain:</strong> {domain}</li>
|
||||||
|
<li><strong>Benutzername:</strong> {username}</li>
|
||||||
|
<li><strong>Passwort:</strong> {password}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p style="font-size: 13px; color: #64748b; line-height: 1.5;">
|
||||||
|
Bitte bewahren Sie diese Informationen sicher auf.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
|
||||||
|
return send(recipient, subject, text_body=text_note, html_body=html_note)
|
||||||
+79
-227
@@ -16,21 +16,6 @@ def _get_users_collection():
|
|||||||
db = client[MONGO_DB_NAME]
|
db = client[MONGO_DB_NAME]
|
||||||
return client, db["packages"]
|
return client, db["packages"]
|
||||||
|
|
||||||
|
|
||||||
def add_dns(name: str, port: int) -> bool:
|
|
||||||
"""
|
|
||||||
Adds the subdomain to the DNS Routes
|
|
||||||
|
|
||||||
Input:
|
|
||||||
- name (Name of the subdomain) -> String
|
|
||||||
- port (Port number for the subdomain) -> int
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- bool (True if adding of the Subdomain is active)
|
|
||||||
"""
|
|
||||||
# This is a placeholder function, as the actual implementation would depend on the DNS provider and how the DNS records are managed.
|
|
||||||
return False
|
|
||||||
|
|
||||||
def clear_special(var_:str) -> str:
|
def clear_special(var_:str) -> str:
|
||||||
"""
|
"""
|
||||||
Clears the variable of any special carakters
|
Clears the variable of any special carakters
|
||||||
@@ -59,7 +44,7 @@ def clear_special(var_:str) -> str:
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def execute_script(wd_: str, file_: str, com_: str, com2_: str="None", com3_: str="None"):
|
def execute_script(wd_: str, file_: str, com_: str, com2_: str="None", com3_: str="None", com4_: str="None") -> str:
|
||||||
"""
|
"""
|
||||||
executes a script with the option of to extra inputs
|
executes a script with the option of to extra inputs
|
||||||
|
|
||||||
@@ -69,7 +54,7 @@ def execute_script(wd_: str, file_: str, com_: str, com2_: str="None", com3_: st
|
|||||||
- com_ = first option -> String
|
- com_ = first option -> String
|
||||||
- com2_ = second option (Optional if needet)-> String
|
- com2_ = second option (Optional if needet)-> String
|
||||||
- com3_ = third option (Optional if needet)-> String
|
- com3_ = third option (Optional if needet)-> String
|
||||||
|
- com4_ = fourth option (Optional if needet)-> String
|
||||||
Output:
|
Output:
|
||||||
- ether False if failed -> bool
|
- ether False if failed -> bool
|
||||||
- or result.stdout output of the executed process -> str
|
- or result.stdout output of the executed process -> str
|
||||||
@@ -82,6 +67,8 @@ def execute_script(wd_: str, file_: str, com_: str, com2_: str="None", com3_: st
|
|||||||
cmd = f'bash "{update_path}" {com_} {com2_}'
|
cmd = f'bash "{update_path}" {com_} {com2_}'
|
||||||
elif com3_ != "None":
|
elif com3_ != "None":
|
||||||
cmd = f'bash "{update_path}" {com_} {com2_} {com3_}'
|
cmd = f'bash "{update_path}" {com_} {com2_} {com3_}'
|
||||||
|
elif com4_ != "None":
|
||||||
|
cmd = f'bash "{update_path}" {com_} {com2_} {com3_} {com4_}'
|
||||||
else:
|
else:
|
||||||
cmd = f'bash "{update_path}" {com_}'
|
cmd = f'bash "{update_path}" {com_}'
|
||||||
try:
|
try:
|
||||||
@@ -210,225 +197,90 @@ class versions:
|
|||||||
return int(instance_age) if int(instance_age) is not None and instance_age <= 5 else False
|
return int(instance_age) if int(instance_age) is not None and instance_age <= 5 else False
|
||||||
|
|
||||||
|
|
||||||
class instace:
|
class Instance:
|
||||||
"""
|
@staticmethod
|
||||||
This will give access to anything like:
|
|
||||||
- Instances for Clients
|
|
||||||
- starting
|
|
||||||
- stopping
|
|
||||||
- restarting
|
|
||||||
- list all Clients
|
|
||||||
|
|
||||||
modules:
|
|
||||||
- new(name:str)
|
|
||||||
- remove(name:str)
|
|
||||||
- status(name:str)
|
|
||||||
- restart(name:str)
|
|
||||||
- list()
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__():
|
|
||||||
return list()
|
|
||||||
|
|
||||||
def new_trial(name: str) -> bool:
|
|
||||||
"""
|
|
||||||
Generates a new trial instance with the subdomain [name].invario.eu
|
|
||||||
|
|
||||||
Input:
|
|
||||||
- name -> String
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- bool if the creation of the instance works (True: creation worked; False: didnt work)
|
|
||||||
|
|
||||||
manage-tenant.sh trial <tenant_id> [port] [days]
|
|
||||||
"""
|
|
||||||
port_starter = 10002
|
|
||||||
port = port_starter
|
|
||||||
for i in instace.list():
|
|
||||||
port =+ 1
|
|
||||||
|
|
||||||
if execute_script(_var, _cmd, "trial", clear_special(name), port):
|
|
||||||
add_dns(name, port)
|
|
||||||
return int(port)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def new(name: str) -> int:
|
|
||||||
"""
|
|
||||||
Generates a new instance with the subdomain [name].invario.eu
|
|
||||||
|
|
||||||
Input:
|
|
||||||
- name -> String
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- int (Port number for the subdomain) or False if the creation of the instance didnt work
|
|
||||||
"""
|
|
||||||
port_starter = 10002
|
|
||||||
port = port_starter
|
|
||||||
for i in instace.list():
|
|
||||||
port =+ 1
|
|
||||||
|
|
||||||
if execute_script(_var, _cmd, "add", clear_special(name), port):
|
|
||||||
add_dns(name, port)
|
|
||||||
return int(port)
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def edit(name: str, module:str) -> bool:
|
|
||||||
"""
|
|
||||||
Edits the name of an instance with the subdomain [name].invario.eu to [new_name].invario.eu
|
|
||||||
|
|
||||||
Input:
|
|
||||||
- name -> String
|
|
||||||
- module -> String (Options: "inventarsystem", "buecherei", "terminverwaltung", "emailversand", "starter", "advanced")
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- bool if the edit works (True: edit worked; False: didnt work)
|
|
||||||
"""
|
|
||||||
if module == "inventarsystem":
|
|
||||||
if execute_script(_var, _cmd, "module", clear_special(name), 'library=off inventory=on'):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
elif module == "buecherei":
|
|
||||||
if execute_script(_var, _cmd, "module", clear_special(name), 'library=on inventory=off'):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
elif module == "terminverwaltung":
|
|
||||||
if execute_script(_var, _cmd, "module", clear_special(name), 'library=off inventory=off'): # -> has to be changed when the module is ready
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
elif module == "emailversand":
|
|
||||||
if execute_script(_var, _cmd, "module", clear_special(name), 'library=off inventory=on'):# -> has to be changed when the module is ready
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
elif module == "starter":
|
|
||||||
if execute_script(_var, _cmd, "module", clear_special(name), 'library=on inventory=on'):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
elif module == "advanced":
|
|
||||||
if execute_script(_var, _cmd, "module", clear_special(name), 'library=on inventory=on'):# -> has to be changed when the module is ready
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def remove(name: str) -> bool:
|
|
||||||
"""
|
|
||||||
Removes a instance with the subdomain [name].invario.eu
|
|
||||||
|
|
||||||
Input:
|
|
||||||
- name -> String
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- bool if the removal works (True: removal worked; False: didnt work)
|
|
||||||
"""
|
|
||||||
safe_name = clear_special(name)
|
|
||||||
# try to remove via management script
|
|
||||||
script_ok = execute_script(_var, _cmd, "remove", safe_name)
|
|
||||||
if not script_ok:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# best-effort: remove the associated package entry from the database
|
|
||||||
client = None
|
|
||||||
try:
|
|
||||||
client, packages = _get_users_collection()
|
|
||||||
packages.delete_one({"client_name": name})
|
|
||||||
except Exception:
|
|
||||||
# don't fail the overall removal if DB cleanup fails
|
|
||||||
pass
|
|
||||||
finally:
|
|
||||||
if client:
|
|
||||||
client.close()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def status(name: str) -> bool:
|
|
||||||
"""
|
|
||||||
Returns if a instance with the subdomain [name].invario.eu is up.
|
|
||||||
|
|
||||||
Input:
|
|
||||||
- name -> String
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- bool if the page is online (True: Is working; False: Isnt online)
|
|
||||||
"""
|
|
||||||
name = clear_special(name)
|
|
||||||
request = str(requests.get(f"{name}.invario.eu/test_connection"))
|
|
||||||
if request == '{"message":"Connection successful","status":"success","status_code":200}':
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def restart(name: str) -> bool:
|
|
||||||
"""
|
|
||||||
Restart an instance with the subdomain [name].invario.eu
|
|
||||||
|
|
||||||
Input:
|
|
||||||
- name -> String
|
|
||||||
|
|
||||||
Output:
|
|
||||||
- bool if the restart works (True: restart worked; False: didnt work)
|
|
||||||
"""
|
|
||||||
if execute_script(_var, _cmd, "restart-tenant", clear_special(name)):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def list() -> list:
|
def list() -> list:
|
||||||
"""
|
"""
|
||||||
List off all tenants.
|
Lists all existing tenants along with their mapped ports.
|
||||||
|
Returns: list of dicts -> [{'name': 'school1', 'port': 10002}, ...]
|
||||||
Output:
|
"""
|
||||||
- list with all tenants ("tenant1", "tenant2")
|
|
||||||
"""
|
|
||||||
result = execute_script(_var, _cmd, "list")
|
result = execute_script(_var, _cmd, "list")
|
||||||
if not isinstance(result, str):
|
if not isinstance(result, str):
|
||||||
return []
|
return []
|
||||||
result = result.splitlines()
|
|
||||||
if not result:
|
tenants = []
|
||||||
return []
|
pattern = re.compile(r"^-\s+([^\s]+)\s+\(port\s+(\d+)\)")
|
||||||
return [line.replace("- ", "") for line in result[1:]]
|
for line in result.splitlines():
|
||||||
|
match = pattern.match(line.strip())
|
||||||
|
if match:
|
||||||
|
tenants.append({
|
||||||
|
"name": match.group(1),
|
||||||
|
"port": int(match.group(2))
|
||||||
|
})
|
||||||
|
return tenants
|
||||||
|
|
||||||
def backup(name: str) -> bool:
|
@classmethod
|
||||||
"""
|
def get_next_available_port(cls, start_port=10002) -> int:
|
||||||
Creates a backup of an instance with the subdomain [name].invario.eu
|
tenants = cls.list()
|
||||||
|
if not tenants:
|
||||||
|
return start_port
|
||||||
|
used_ports = [t["port"] for t in tenants]
|
||||||
|
return max(used_ports) + 1
|
||||||
|
|
||||||
Input:
|
@classmethod
|
||||||
- name -> String
|
def new(cls, name: str, port: int = None, password: str = "admin123") -> bool:
|
||||||
|
safe_name = clear_special(name)
|
||||||
|
if port is None:
|
||||||
|
port = cls.get_next_available_port()
|
||||||
|
|
||||||
|
return execute_script(_var, _cmd, "add", safe_name, str(port), password)
|
||||||
|
|
||||||
Output:
|
@staticmethod
|
||||||
- bool if the backup works (True: backup worked; False: didnt work)
|
def edit(name: str, module_preset: str) -> bool:
|
||||||
"""
|
safe_name = clear_special(name)
|
||||||
import subprocess
|
presets = {
|
||||||
try:
|
"inventarsystem": "library=off inventory=on student_cards=off terminplan=off",
|
||||||
subprocess.run(
|
"buecherei": "library=on inventory=off student_cards=off terminplan=off",
|
||||||
[
|
"terminverwaltung": "library=off inventory=off student_cards=off terminplan=on",
|
||||||
"docker",
|
"emailversand": "library=off inventory=on student_cards=off terminplan=off",
|
||||||
"compose",
|
"starter": "library=on inventory=on student_cards=on terminplan=off",
|
||||||
"-f",
|
"advanced": "library=on inventory=on student_cards=on terminplan=on",
|
||||||
"docker-compose-multitenant.yml",
|
}
|
||||||
"exec",
|
|
||||||
"-T",
|
config = presets.get(module_preset)
|
||||||
"mongodb",
|
if not config:
|
||||||
"mongodump",
|
|
||||||
f"--archive=/data/backups/inventar_{name}-$(date +%Y%m%d%H%M%S).gz",
|
|
||||||
"--gzip",
|
|
||||||
"--db",
|
|
||||||
f"inventar_{name}"
|
|
||||||
],
|
|
||||||
check=True
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
return execute_script(_var, _cmd, "module", safe_name, config)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remove(name: str) -> bool:
|
||||||
|
safe_name = clear_special(name)
|
||||||
|
if not execute_script(_var, _cmd, "remove", safe_name):
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
client, packages = _get_users_collection()
|
||||||
|
packages.delete_one({"client_name": safe_name})
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
if 'client' in locals() and client:
|
||||||
|
client.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def status(name: str) -> bool:
|
||||||
|
safe_name = clear_special(name)
|
||||||
|
try:
|
||||||
|
res = requests.get(f"https://{safe_name}.invario-software.de/health", timeout=5)
|
||||||
|
return res.status_code == 200
|
||||||
|
except requests.RequestException:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def restart(name: str) -> bool:
|
||||||
|
return execute_script(_var, _cmd, "restart-tenant", clear_special(name))
|
||||||
|
|
||||||
class ussage:
|
class ussage:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user