f
This commit is contained in:
@@ -1286,6 +1286,7 @@ def main() -> int:
|
|||||||
str(run_client_script),
|
str(run_client_script),
|
||||||
"--install-service",
|
"--install-service",
|
||||||
"--service-name", "hydrus-client",
|
"--service-name", "hydrus-client",
|
||||||
|
"--service-user", "hydrusnetwork",
|
||||||
"--repo-root", str(target_repo),
|
"--repo-root", str(target_repo),
|
||||||
"--headless",
|
"--headless",
|
||||||
"--pull"
|
"--pull"
|
||||||
|
|||||||
@@ -64,6 +64,22 @@ except Exception:
|
|||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
def _determine_service_user(args) -> Optional[str]:
|
||||||
|
user = getattr(args, "service_user", None)
|
||||||
|
if user:
|
||||||
|
user = user.strip()
|
||||||
|
if not user:
|
||||||
|
user = None
|
||||||
|
if (
|
||||||
|
not user
|
||||||
|
and os.name != "nt"
|
||||||
|
and hasattr(os, "geteuid")
|
||||||
|
and os.geteuid() == 0
|
||||||
|
):
|
||||||
|
user = "hydrusnetwork"
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
def find_git_executable() -> Optional[str]:
|
def find_git_executable() -> Optional[str]:
|
||||||
"""Return the git executable path or None if not found."""
|
"""Return the git executable path or None if not found."""
|
||||||
import shutil as _shutil
|
import shutil as _shutil
|
||||||
@@ -867,6 +883,11 @@ def main(argv: Optional[list[str]] = None) -> int:
|
|||||||
default="hydrus-client",
|
default="hydrus-client",
|
||||||
help="Name for the installed service/scheduled task (default: hydrus-client)",
|
help="Name for the installed service/scheduled task (default: hydrus-client)",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--service-user",
|
||||||
|
default=None,
|
||||||
|
help="When installing a systemd system service as root, run it under this user",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--no-project-venv",
|
"--no-project-venv",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
@@ -1197,6 +1218,7 @@ def main(argv: Optional[list[str]] = None) -> int:
|
|||||||
run_client_script = cand
|
run_client_script = cand
|
||||||
break
|
break
|
||||||
|
|
||||||
|
service_user = _determine_service_user(args)
|
||||||
if run_client_script and run_client_script.exists():
|
if run_client_script and run_client_script.exists():
|
||||||
cmd = [
|
cmd = [
|
||||||
str(venv_py),
|
str(venv_py),
|
||||||
@@ -1207,6 +1229,8 @@ def main(argv: Optional[list[str]] = None) -> int:
|
|||||||
"--detached",
|
"--detached",
|
||||||
"--headless",
|
"--headless",
|
||||||
]
|
]
|
||||||
|
if service_user:
|
||||||
|
cmd.extend(["--service-user", service_user])
|
||||||
logging.info("Installing service via helper: %s", cmd)
|
logging.info("Installing service via helper: %s", cmd)
|
||||||
try:
|
try:
|
||||||
subprocess.run(cmd, cwd=str(dest), check=True)
|
subprocess.run(cmd, cwd=str(dest), check=True)
|
||||||
@@ -1223,6 +1247,7 @@ def main(argv: Optional[list[str]] = None) -> int:
|
|||||||
venv_py,
|
venv_py,
|
||||||
headless=True,
|
headless=True,
|
||||||
detached=True,
|
detached=True,
|
||||||
|
service_user=service_user,
|
||||||
)
|
)
|
||||||
if ok:
|
if ok:
|
||||||
logging.info("Service installed (user-level).")
|
logging.info("Service installed (user-level).")
|
||||||
@@ -1559,6 +1584,7 @@ def main(argv: Optional[list[str]] = None) -> int:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if getattr(args, "install_service", False):
|
if getattr(args, "install_service", False):
|
||||||
|
service_user = _determine_service_user(args)
|
||||||
if run_client_script and run_client_script.exists():
|
if run_client_script and run_client_script.exists():
|
||||||
cmd = [
|
cmd = [
|
||||||
str(venv_py),
|
str(venv_py),
|
||||||
@@ -1569,6 +1595,8 @@ def main(argv: Optional[list[str]] = None) -> int:
|
|||||||
"--detached",
|
"--detached",
|
||||||
"--headless",
|
"--headless",
|
||||||
]
|
]
|
||||||
|
if service_user:
|
||||||
|
cmd.extend(["--service-user", service_user])
|
||||||
logging.info("Installing service via helper: %s", cmd)
|
logging.info("Installing service via helper: %s", cmd)
|
||||||
try:
|
try:
|
||||||
subprocess.run(cmd, cwd=str(dest), check=True)
|
subprocess.run(cmd, cwd=str(dest), check=True)
|
||||||
@@ -1582,7 +1610,8 @@ def main(argv: Optional[list[str]] = None) -> int:
|
|||||||
dest,
|
dest,
|
||||||
venv_py,
|
venv_py,
|
||||||
headless=True,
|
headless=True,
|
||||||
detached=True
|
detached=True,
|
||||||
|
service_user=service_user
|
||||||
)
|
)
|
||||||
if ok:
|
if ok:
|
||||||
logging.info("Service installed (user-level).")
|
logging.info("Service installed (user-level).")
|
||||||
|
|||||||
@@ -262,6 +262,26 @@ def ensure_service_user(username: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def grant_service_user_repo_access(repo_root: Path, username: str) -> bool:
|
||||||
|
try:
|
||||||
|
for dirpath, dirnames, filenames in os.walk(repo_root):
|
||||||
|
shutil.chown(dirpath, user=username, group=username)
|
||||||
|
for name in dirnames + filenames:
|
||||||
|
path = Path(dirpath) / name
|
||||||
|
shutil.chown(path, user=username, group=username)
|
||||||
|
return True
|
||||||
|
except PermissionError as exc:
|
||||||
|
print(
|
||||||
|
f"Failed to grant ownership of '{repo_root}' to '{username}': {exc}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
except Exception as exc:
|
||||||
|
print(
|
||||||
|
f"Error while adjusting permissions for '{username}' in '{repo_root}': {exc}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
# --- Service install/uninstall helpers -----------------------------------
|
# --- Service install/uninstall helpers -----------------------------------
|
||||||
|
|
||||||
|
|
||||||
@@ -552,6 +572,11 @@ def install_service_systemd_system(
|
|||||||
if service_user and not ensure_service_user(service_user):
|
if service_user and not ensure_service_user(service_user):
|
||||||
print(f"Unable to prepare service user '{service_user}' for system service.")
|
print(f"Unable to prepare service user '{service_user}' for system service.")
|
||||||
return False
|
return False
|
||||||
|
if service_user and not grant_service_user_repo_access(repo_root, service_user):
|
||||||
|
print(
|
||||||
|
f"Failed to assign '{service_user}' as the owner of '{repo_root}'."
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
unit_dir = Path("/etc/systemd/system")
|
unit_dir = Path("/etc/systemd/system")
|
||||||
service_file = unit_dir / f"{service_name}.service"
|
service_file = unit_dir / f"{service_name}.service"
|
||||||
@@ -698,6 +723,7 @@ def install_service_auto(
|
|||||||
detached: bool = True,
|
detached: bool = True,
|
||||||
pull: bool = False,
|
pull: bool = False,
|
||||||
workspace_root: Optional[Path] = None,
|
workspace_root: Optional[Path] = None,
|
||||||
|
service_user: Optional[str] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
try:
|
try:
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
@@ -719,7 +745,8 @@ def install_service_auto(
|
|||||||
headless=headless,
|
headless=headless,
|
||||||
detached=detached,
|
detached=detached,
|
||||||
pull=pull,
|
pull=pull,
|
||||||
workspace_root=workspace_root
|
workspace_root=workspace_root,
|
||||||
|
service_user=service_user,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return install_service_cron(
|
return install_service_cron(
|
||||||
@@ -918,6 +945,11 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|||||||
default="hydrus-client",
|
default="hydrus-client",
|
||||||
help="Name of the service / scheduled task to install (default: hydrus-client)",
|
help="Name of the service / scheduled task to install (default: hydrus-client)",
|
||||||
)
|
)
|
||||||
|
p.add_argument(
|
||||||
|
"--service-user",
|
||||||
|
default=None,
|
||||||
|
help="When installing a system-wide unit as root, optionally run it under this user (default: hydrusnetwork)",
|
||||||
|
)
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
"--cwd",
|
"--cwd",
|
||||||
default=None,
|
default=None,
|
||||||
@@ -1144,6 +1176,16 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|||||||
else:
|
else:
|
||||||
use_headless = not first_run
|
use_headless = not first_run
|
||||||
|
|
||||||
|
service_user = args.service_user.strip() if args.service_user else None
|
||||||
|
if (
|
||||||
|
args.install_service
|
||||||
|
and not service_user
|
||||||
|
and os.name != "nt"
|
||||||
|
and hasattr(os, "geteuid")
|
||||||
|
and os.geteuid() == 0
|
||||||
|
):
|
||||||
|
service_user = "hydrusnetwork"
|
||||||
|
|
||||||
if args.install_service:
|
if args.install_service:
|
||||||
ok = install_service_auto(
|
ok = install_service_auto(
|
||||||
args.service_name,
|
args.service_name,
|
||||||
@@ -1152,7 +1194,8 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|||||||
headless=use_headless,
|
headless=use_headless,
|
||||||
detached=True,
|
detached=True,
|
||||||
pull=args.pull,
|
pull=args.pull,
|
||||||
workspace_root=workspace_root
|
workspace_root=workspace_root,
|
||||||
|
service_user=service_user
|
||||||
)
|
)
|
||||||
return 0 if ok else 6
|
return 0 if ok else 6
|
||||||
if args.uninstall_service:
|
if args.uninstall_service:
|
||||||
|
|||||||
Reference in New Issue
Block a user