Files
yakpanel-core/script/restart_services.py
2026-04-07 02:04:22 +05:30

817 lines
27 KiB
Python

# coding: utf-8
import json
import os
import socket
import subprocess
import sys
import time
from functools import wraps, partial
from typing import Optional, Dict, Callable
import fcntl
os.chdir("/www/server/panel")
sys.path.insert(0, "class/")
sys.path.insert(0, "class_v2/")
SETUP_PATH = "/www/server"
DATA_PATH = os.path.join(SETUP_PATH, "panel/data")
PLUGINS_PATH = os.path.join(SETUP_PATH, "panel/plugin")
DAEMON_SERVICE = os.path.join(DATA_PATH, "daemon_service.pl")
DAEMON_SERVICE_LOCK = os.path.join(DATA_PATH, "daemon_service_lock.pl")
DAEMON_RESTART_RECORD = os.path.join(DATA_PATH, "daemon_restart_record.pl")
MANUAL_FLAG = os.path.join(SETUP_PATH, "panel/data/mod_push_data", "manual_flag.pl")
def read_file(filename: str):
fp = None
try:
fp = open(filename, "rb")
f_body_bytes: bytes = fp.read()
f_body = f_body_bytes.decode("utf-8", errors='ignore')
fp.close()
return f_body
except Exception:
return False
finally:
if fp and not fp.closed:
fp.close()
def run_command(cmd, timeout=5) -> str:
try:
result = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
timeout=timeout,
check=False
)
output = result.stdout.strip()
return output if output else ""
except subprocess.TimeoutExpired as t:
write_logs(f"Command execution timed out: {cmd}, error: {t}")
return ""
except Exception as e:
write_logs(f"Command execution failed: {cmd}, error: {e}")
return ""
def service_shop_name(services_name: str) -> str:
# 对应商店名字
shop_name = {
"postfix": "mail_sys",
"pgsql": "pgsql_manager",
"pure-ftpd": "pureftpd",
"php-fpm-52": "php-5.2",
"php-fpm-53": "php-5.3",
"php-fpm-54": "php-5.4",
"php-fpm-55": "php-5.5",
"php-fpm-56": "php-5.6",
"php-fpm-70": "php-7.0",
"php-fpm-71": "php-7.1",
"php-fpm-72": "php-7.2",
"php-fpm-73": "php-7.3",
"php-fpm-74": "php-7.4",
"php-fpm-80": "php-8.0",
"php-fpm-81": "php-8.1",
"php-fpm-82": "php-8.2",
"php-fpm-83": "php-8.3",
"php-fpm-84": "php-8.4",
"php-fpm-85": "php-8.5",
}
return shop_name.get(services_name, services_name)
def pretty_title(services_name: str) -> str:
title = {
"apache": "Apache",
"nginx": "Nginx",
"openlitespeed": "OpenLiteSpeed",
"redis": "Redis",
"mysql": "MySQL/MariaDB",
"mongodb": "MongoDB",
"pgsql": "PostgreSQL",
"pure-ftpd": "Pure-FTPd",
"memcached": "Memcached",
"ssh": "SSH",
"postfix": "Postfix",
"pdns": "PowerDNS",
# PHP-FPM
"php-fpm-52": "PHP 5.2 FPM",
"php-fpm-53": "PHP 5.3 FPM",
"php-fpm-54": "PHP 5.4 FPM",
"php-fpm-55": "PHP 5.5 FPM",
"php-fpm-56": "PHP 5.6 FPM",
"php-fpm-70": "PHP 7.0 FPM",
"php-fpm-71": "PHP 7.1 FPM",
"php-fpm-72": "PHP 7.2 FPM",
"php-fpm-73": "PHP 7.3 FPM",
"php-fpm-74": "PHP 7.4 FPM",
"php-fpm-80": "PHP 8.0 FPM",
"php-fpm-81": "PHP 8.1 FPM",
"php-fpm-82": "PHP 8.2 FPM",
"php-fpm-83": "PHP 8.3 FPM",
"php-fpm-84": "PHP 8.4 FPM",
"php-fpm-85": "PHP 8.5 FPM",
# plugins
"btwaf": "YakPanel WAF",
"fail2ban": "Fail2Ban",
}
return title.get(services_name, services_name)
# =======================================================
def ssh_ver() -> str:
version_info = run_command(["ssh", "-V"])
if version_info and "OpenSSH" in version_info:
return version_info.split(",")[0]
return ""
def postfix_ver() -> str:
# mail_version = x.x.x
output = run_command(["/usr/sbin/postconf", "mail_version"])
if output and "=" in output:
return output.split("=")[-1].strip()
return ""
def pgsql_pid() -> str:
pid_str = run_command(["pgrep", "-o", "postgres"])
if pid_str and pid_str.isdigit():
return pid_str
return ""
def pgsql_ver() -> str:
# psql (PostgreSQL) 18.0
output = run_command([f"{SETUP_PATH}/pgsql/bin/psql", "--version"])
if output:
from re import search
match = search(r"(\d+\.\d+(\.\d+)?)", output)
if match:
return match.group(1)
org_file = f"{SETUP_PATH}/pgsql/data/PG_VERSION",
if os.path.exists(str(org_file)):
try:
with open(str(org_file), "r") as f:
version = f.read().strip()
return version
except:
return ""
return ""
def pdns_pid() -> str:
pid_str = run_command(["pgrep", "-x", "pdns_server"])
if pid_str and pid_str.isdigit():
return pid_str
return ""
def pdns_ver() -> str:
# PowerDNS Authoritative Server x.x.x
output = run_command(["pdns_server", "--version"])
if not output:
return ""
from re import search
match = search(r"(\d+\.\d+\.\d+)", output)
if match:
return match.group(1)
if "PowerDNS" in output:
return output.split()[-1]
return ""
def waf_pid() -> str:
pid_str = run_command(["pgrep", "-x", "BT-WAF"])
if pid_str and pid_str.isdigit():
return pid_str
return ""
def pluign_ver(plugin_name: str) -> str:
info = f"{PLUGINS_PATH}/{plugin_name}/info.json"
if not os.path.exists(info):
return ""
try:
with open(info, "r") as f:
json_data = json.load(f)
ret = json_data.get("versions", "")
return ret
except:
pass
return ""
SERVICES_MAP = {
# ========================= core base =============================
"panel": (
"Yak-Panel", f"{SETUP_PATH}/panel/logs/panel.pid", f"{SETUP_PATH}/panel/init.sh",
f"{SETUP_PATH}/nginx/version.pl",
),
"apache": (
"httpd", f"{SETUP_PATH}/apache/logs/httpd.pid", "/etc/init.d/httpd",
f"{SETUP_PATH}/apache/version.pl",
),
"nginx": (
"nginx", f"{SETUP_PATH}/nginx/logs/nginx.pid", "/etc/init.d/nginx",
f"{SETUP_PATH}/nginx/version.pl",
),
"openlitespeed": (
"litespeed", "/tmp/lshttpd/lshttpd.pid", "/usr/local/lsws/bin/lswsctrl",
"/usr/local/lsws/VERSION",
),
"redis": (
"redis-server", f"{SETUP_PATH}/redis/redis.pid", "/etc/init.d/redis",
f"{SETUP_PATH}/redis/version.pl",
),
"mysql": (
"mysqld", "/tmp/mysql.sock", "/etc/init.d/mysqld",
f"{SETUP_PATH}/mysql/version.pl",
),
"mongodb": (
"mongod", f"{SETUP_PATH}/mongodb/log/configsvr.pid", "/etc/init.d/mongodb",
f"{SETUP_PATH}/mongodb/version.pl",
),
"pgsql": (
"postgres", pgsql_pid, "/etc/init.d/pgsql",
pgsql_ver,
),
"pure-ftpd": (
"pure-ftpd", "/var/run/pure-ftpd.pid", "/etc/init.d/pure-ftpd",
f"{SETUP_PATH}/pure-ftpd/version.pl",
),
"memcached": (
"memcached", "/var/run/memcached.pid", "/etc/init.d/memcached",
"/usr/local/memcached/version_check.pl",
),
"ssh": (
"sshd", "/var/run/sshd.pid", "/etc/init.d/ssh",
ssh_ver,
),
"postfix": (
"master", "/var/spool/postfix/pid/master.pid", "/etc/init.d/postfix",
postfix_ver,
),
"pdns": (
# "pdns_server", pdns_pid, "/usr/sbin/pdns_server",
"pdns_server", pdns_pid, "/www/server/panel/class_v2/ssl_dnsV2/aadns.pl",
pdns_ver,
),
# ======================== PHP-FPM ============================
"php-fpm-52": ("php-fpm", f"{SETUP_PATH}/php/52/var/run/php-fpm.pid", "/etc/init.d/php-fpm-52",
f"{SETUP_PATH}/php/52/version.pl"),
"php-fpm-53": ("php-fpm", f"{SETUP_PATH}/php/53/var/run/php-fpm.pid", "/etc/init.d/php-fpm-53",
f"{SETUP_PATH}/php/53/version.pl"),
"php-fpm-54": ("php-fpm", f"{SETUP_PATH}/php/54/var/run/php-fpm.pid", "/etc/init.d/php-fpm-54",
f"{SETUP_PATH}/php/54/version.pl"),
"php-fpm-55": ("php-fpm", f"{SETUP_PATH}/php/55/var/run/php-fpm.pid", "/etc/init.d/php-fpm-55",
f"{SETUP_PATH}/php/55/version.pl"),
"php-fpm-56": ("php-fpm", f"{SETUP_PATH}/php/56/var/run/php-fpm.pid", "/etc/init.d/php-fpm-56",
f"{SETUP_PATH}/php/56/version.pl"),
"php-fpm-70": ("php-fpm", f"{SETUP_PATH}/php/70/var/run/php-fpm.pid", "/etc/init.d/php-fpm-70",
f"{SETUP_PATH}/php/70/version.pl"),
"php-fpm-71": ("php-fpm", f"{SETUP_PATH}/php/71/var/run/php-fpm.pid", "/etc/init.d/php-fpm-71",
f"{SETUP_PATH}/php/71/version.pl"),
"php-fpm-72": ("php-fpm", f"{SETUP_PATH}/php/72/var/run/php-fpm.pid", "/etc/init.d/php-fpm-72",
f"{SETUP_PATH}/php/72/version.pl"),
"php-fpm-73": ("php-fpm", f"{SETUP_PATH}/php/73/var/run/php-fpm.pid", "/etc/init.d/php-fpm-73",
f"{SETUP_PATH}/php/73/version.pl"),
"php-fpm-74": ("php-fpm", f"{SETUP_PATH}/php/74/var/run/php-fpm.pid", "/etc/init.d/php-fpm-74",
f"{SETUP_PATH}/php/74/version.pl"),
"php-fpm-80": ("php-fpm", f"{SETUP_PATH}/php/80/var/run/php-fpm.pid", "/etc/init.d/php-fpm-80",
f"{SETUP_PATH}/php/80/version.pl"),
"php-fpm-81": ("php-fpm", f"{SETUP_PATH}/php/81/var/run/php-fpm.pid", "/etc/init.d/php-fpm-81",
f"{SETUP_PATH}/php/81/version.pl"),
"php-fpm-82": ("php-fpm", f"{SETUP_PATH}/php/82/var/run/php-fpm.pid", "/etc/init.d/php-fpm-82",
f"{SETUP_PATH}/php/82/version.pl"),
"php-fpm-83": ("php-fpm", f"{SETUP_PATH}/php/83/var/run/php-fpm.pid", "/etc/init.d/php-fpm-83",
f"{SETUP_PATH}/php/83/version.pl"),
"php-fpm-84": ("php-fpm", f"{SETUP_PATH}/php/84/var/run/php-fpm.pid", "/etc/init.d/php-fpm-84",
f"{SETUP_PATH}/php/84/version_check.pl"),
"php-fpm-85": ("php-fpm", f"{SETUP_PATH}/php/85/var/run/php-fpm.pid", "/etc/init.d/php-fpm-85",
f"{SETUP_PATH}/php/85/version_check.pl"),
# ======================== plugins ============================
# nginx : btwaf
# apache: btwaf_httpd
"btwaf": (
# "BT-WAF", f"{PLUGINS_PATH}/btwaf/BT-WAF.pid", f"/etc/init.d/btwaf",
"BT-WAF", waf_pid, f"/etc/init.d/btwaf",
partial(pluign_ver, "btwaf"),
),
"fail2ban": (
"fail2ban-server", f"{PLUGINS_PATH}/fail2ban/fail2ban.pid", "/etc/init.d/fail2ban",
partial(pluign_ver, "fail2ban"),
),
}
# 日志
def write_logs(msg: str, logger_name: str = "Service Daemon"):
try:
from public import M
t = time.strftime('%Y-%m-%d %X', time.localtime())
M("logs").add("uid,username,type,log,addtime", (1, "system", logger_name, msg, t))
except:
pass
# 手动干预
def manual_flag(server_name: str = None, open_: str = None) -> Optional[dict]:
if not server_name: # only read
return DaemonManager.manual_safe_read()
# 人为干预
if open_ in ["start", "restart"]: # 激活服务检查
return DaemonManager.active_daemon(server_name)
elif open_ == "stop": # 跳过服务检查
return DaemonManager.skip_daemon(server_name)
return DaemonManager.manual_safe_read()
# 管理服务助手
class ServicesHelper:
def __init__(self, nick_name: str = None):
self.nick_name = nick_name
self._serviced = None
self._pid_source = None
self._bash = None
self._ver_source = None
self._pid_cache = None
self._ver_cache = None
self._install_cache = None
self._info_inited = False
def __check_pid_process(self, pid: int) -> bool:
try:
# 是否活跃
with open(f"/proc/{pid}/stat", "r") as f:
if f.read().split()[2] == "Z":
return False # 僵尸进程
# 进程是否名字匹配
with open(f"/proc/{pid}/comm", "r") as f:
proc_name = f.read().strip()
# 特殊处理 mysql
if self.nick_name != "mysql":
return proc_name == self._serviced or proc_name == self.nick_name
else:
return proc_name in ["mysqld", "mariadbd"]
except (FileNotFoundError, IndexError):
return False
except Exception:
return False
def _init_info(self) -> None:
if self._info_inited:
return
if not self.nick_name or not isinstance(self.nick_name, str):
self._info_inited = True
return
map_info = SERVICES_MAP.get(self.nick_name)
if map_info:
self._serviced, self._pid_source, self._bash, self._ver_source = map_info
self._info_inited = True
@property
def pid(self):
"""返回pid文件路径或pid值"""
if self._pid_cache is None:
self._init_info()
if isinstance(self._pid_source, Callable):
try:
pid_val = self._pid_source()
self._pid_cache = int(pid_val) if pid_val and pid_val.isdigit() else pid_val
except Exception:
self._pid_cache = self._pid_source
else:
self._pid_cache = self._pid_source
return self._pid_cache
@property
def version(self) -> str:
"""返回服务版本号"""
if self._ver_cache is None:
self._init_info()
if isinstance(self._ver_source, Callable):
try:
self._ver_cache = self._ver_source()
except:
self._ver_cache = ""
elif isinstance(self._ver_source, str) and os.path.exists(self._ver_source):
try:
with open(self._ver_source, "r") as f:
self._ver_cache = f.read().strip()
except:
self._ver_cache = ""
else:
self._ver_cache = ""
return str(self._ver_cache).strip()
@property
def is_install(self) -> bool:
"""判断是否安装"""
if self._install_cache is not None:
return self._install_cache
self._init_info()
self._install_cache = False
# waf特殊处理
if self.nick_name == "btwaf":
if os.path.exists(f"{PLUGINS_PATH}/btwaf"):
self._install_cache = True
return self._install_cache
# postfix特殊处理
if self.nick_name == "postfix":
if os.path.exists(f"{PLUGINS_PATH}/mail_sys"):
self._install_cache = True
return self._install_cache
if any([
self._serviced and os.path.exists(f"/etc/init.d/{self._serviced}"),
self.nick_name and os.path.exists(f"/etc/init.d/{self.nick_name}"),
self._bash and os.path.exists(self._bash),
]):
self._install_cache = True
return self._install_cache
@property
def shop_name(self) -> str:
return service_shop_name(self.nick_name)
@property
def pretty_title(self) -> str:
return pretty_title(self.nick_name)
@property
def is_running(self) -> bool:
"""
判断进程是否存活
pid: 进程pid文件 str 或 int
serviced: 进程服务名称
nick_name: 进程别名
"""
if not self.is_install:
return False
if not self.pid:
return False
if isinstance(self.pid, int):
return self.__check_pid_process(self.pid)
if isinstance(self.pid, str):
if not os.path.exists(self.pid):
return False
if self.pid.endswith(".pid"):
try:
with open(self.pid, "r") as f:
temp_pid = int(f.read().strip())
return self.__check_pid_process(temp_pid)
except (ValueError, FileNotFoundError):
return False
except Exception:
return False
elif self.pid.endswith(".sock"):
try:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.settimeout(0.1)
s.connect(self.pid)
return True
except (socket.timeout, ConnectionRefusedError, FileNotFoundError):
return False
except Exception:
return False
# not str and not int
return False
def script(self, act: str, logger_name: str = "Service Daemon") -> None:
if not self.is_install or act not in ["start", "stop", "restart", "status"]:
return
try:
# "try to {act} [{self.nick_name}]..."
self._init_info()
bash_path = self._bash if self._bash else f"/etc/init.d/{self._serviced}"
# if isinstance(self.pid, str) and (
# self.pid.endswith(".sock") or self.pid.endswith(".pid")
# ):
# try:
# os.remove(self.pid)
# except:
# pass
if self.nick_name == "panel":
if not os.path.exists(f"{SETUP_PATH}/panel/init.sh"):
from public import get_url
os.system(f"curl -k {get_url()}/install/update_7.x_en.sh|bash &")
cmd = ["bash", bash_path, act]
elif self.nick_name == "pdns":
cmd = ["systemctl", act, "pdns"]
else:
cmd = [bash_path, act]
subprocess.Popen(
cmd,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
write_logs(f"Service [ {self.nick_name} ] {act}", logger_name)
except Exception as e:
print(str(e))
write_logs(f"Failed to {act} {self.nick_name}, error: {e}", logger_name)
# 守护服务管理
class DaemonManager:
_ensured = False
@classmethod
def __ensure(cls):
if cls._ensured:
return
if not os.path.exists(DAEMON_SERVICE_LOCK):
with open(DAEMON_SERVICE_LOCK, "w") as _:
pass
if not os.path.exists(DAEMON_RESTART_RECORD):
with open(DAEMON_RESTART_RECORD, "w") as fm:
fm.write(json.dumps({}))
os.makedirs(os.path.dirname(MANUAL_FLAG), exist_ok=True)
if not os.path.exists(MANUAL_FLAG):
with open(MANUAL_FLAG, "w") as fm:
fm.write(json.dumps({}))
if not os.path.exists(DAEMON_SERVICE):
with open(DAEMON_SERVICE, "w") as fm:
fm.write(json.dumps([]))
cls._ensured = True
@staticmethod
def read_lock(func):
@wraps(func)
def wrapper(*args, **kwargs):
DaemonManager.__ensure()
with open(DAEMON_SERVICE_LOCK, "r") as lock_file:
fcntl.flock(lock_file, fcntl.LOCK_SH)
try:
return func(*args, **kwargs)
finally:
fcntl.flock(lock_file, fcntl.LOCK_UN)
return wrapper
@staticmethod
def write_lock(func):
@wraps(func)
def wrapper(*args, **kwargs):
DaemonManager.__ensure()
with open(DAEMON_SERVICE_LOCK, "r+") as lock_file:
fcntl.flock(lock_file, fcntl.LOCK_EX)
try:
return func(*args, **kwargs)
finally:
fcntl.flock(lock_file, fcntl.LOCK_UN)
return wrapper
@staticmethod
@write_lock
def operate_daemon(service_name: str, flag: int = 0) -> list:
"""
flag: 0 add, 1 del
"""
with open(DAEMON_SERVICE, "r+") as f:
try:
service = json.load(f)
except json.JSONDecodeError:
service = []
if flag == 0:
service.append(service_name)
elif flag == 1:
service = [x for x in service if x != service_name]
service = list(set(service))
f.seek(0)
# noinspection PyTypeChecker
json.dump(service, f)
f.truncate()
return service
@staticmethod
@write_lock
def operate_manual_flag(service_name: str, flag: int = 0) -> dict:
"""
flag: 0 normal, 1 manual closed
"""
with open(MANUAL_FLAG, "r+") as f:
try:
service = json.load(f)
except json.JSONDecodeError:
service = {}
service[service_name] = flag
f.seek(0)
# noinspection PyTypeChecker
json.dump(service, f)
f.truncate()
return service
@staticmethod
def remove_daemon(service_name: str) -> list:
"""移除守护进程服务"""
return DaemonManager.operate_daemon(service_name, 1)
@staticmethod
def add_daemon(service_name: str) -> list:
"""添加守护进程服务"""
return DaemonManager.operate_daemon(service_name, 0)
@staticmethod
def skip_daemon(service_name: str) -> dict:
"""跳过服务检查"""
return DaemonManager.operate_manual_flag(service_name, 1)
@staticmethod
def active_daemon(service_name: str) -> dict:
"""激活服务检查"""
return DaemonManager.operate_manual_flag(service_name, 0)
@staticmethod
@read_lock
def safe_read():
"""服务守护进程服务列表"""
try:
res = read_file(DAEMON_SERVICE)
return json.loads(res) if res else []
except:
return []
@staticmethod
@read_lock
def manual_safe_read():
"""手动干预服务字典, 0: 需要干预, 1: 被手动关闭的"""
try:
manual = read_file(MANUAL_FLAG)
return json.loads(manual) if manual else {}
except:
return {}
@staticmethod
def update_restart_record(service_name: str, max_count: int) -> bool:
try:
with open(DAEMON_RESTART_RECORD, "r+") as f:
fcntl.flock(f, fcntl.LOCK_EX)
try:
record = json.load(f)
except json.JSONDecodeError:
record = {}
count = record.get(service_name, 0)
if count >= max_count:
return True
record[service_name] = count + 1
f.seek(0)
json.dump(record, f)
f.truncate()
return False
except Exception:
return True
@staticmethod
def safe_read_restart_record() -> Dict[str, int]:
try:
with open(DAEMON_RESTART_RECORD, "r") as f:
fcntl.flock(f, fcntl.LOCK_SH)
record = json.load(f)
except Exception:
record = {}
return record
# 服务守护
class RestartServices:
COUNT = 30
@staticmethod
def __keep_flag_right(manual_info: dict) -> None:
try:
with open(MANUAL_FLAG, "r+") as f:
try:
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
f.seek(0)
# noinspection PyTypeChecker
json.dump(manual_info, f)
f.truncate()
except:
print("Error writing manual flag file")
finally:
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
except Exception as e:
print("Error keep_flag_right:", e)
def _overhead(self, nick_name) -> bool:
return DaemonManager.update_restart_record(
nick_name, self.COUNT
)
@DaemonManager.read_lock
def main(self):
manaul = read_file(MANUAL_FLAG)
services = read_file(DAEMON_SERVICE)
try:
manual_info = json.loads(manaul) if manaul else {}
check_list = json.loads(services) if services else []
check_list = ["panel"] + check_list # panel 强制守护
except Exception:
manual_info = {}
check_list = ["panel"]
record = DaemonManager.safe_read_restart_record()
for service in [
x for x in list(set(check_list)) if record.get(x, 0) < self.COUNT
]:
obj = ServicesHelper(service)
if not obj.is_install:
continue
if not obj.is_running:
if int(manual_info.get(obj.nick_name, 0)) == 1:
# service closed maually, skip
continue
# if obj.nick_name != "panel":
# write_logs(f"Service [ {obj.nick_name} ] is Not Running, Try to start it...")
if not self._overhead(obj.nick_name):
obj.script("restart")
if obj.is_running and manual_info.get(obj.nick_name) == 1:
# service is running, fix the wrong flag
manual_info[obj.nick_name] = 0
# under lock file read lock
self.__keep_flag_right(manual_info)
def first_time_installed(data: dict) -> None:
"""
首次安装服务启动守护进程服务
"""
# todo 虽然支持, 但是守护目前不干预, 前端没开放
exculde = [
"pgsql", "fail2ban", "btwaf", "ssh", "pdns", "php-fpm", "memcached"
]
if not data:
return
try:
for service in SERVICES_MAP.keys(): # support service
if service in exculde:
continue
if "php-fpm" in service:
continue
pl_name = f"{DATA_PATH}/first_installed_flag_{service}.pl"
if data.get(service): # panel installed
setup = data[service].get("setup", False)
if setup is False and os.path.exists(pl_name):
os.remove(pl_name)
elif setup is True and not os.path.exists(pl_name):
DaemonManager.add_daemon(service)
with open(pl_name, "w") as f:
f.write("1")
else:
pass
except:
pass
if __name__ == "__main__":
if len(sys.argv) == 2:
service_name = sys.argv[1]
if service_name in SERVICES_MAP:
helper = ServicesHelper(service_name)
print(f"Attempting to restart service: {service_name}")
helper.script("restart")
print(f"'{service_name}' restart.")
write_logs(f"Service [ {service_name} ] restart ...")
else:
print(f"Error: Service '{service_name}' not found.")
print("Available services are:")
for key in SERVICES_MAP.keys():
print(f" - {key}")
elif len(sys.argv) == 1:
pass
else:
print("Usage: python restart_services.py [service_name]")