mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git
synced 2024-11-29 23:41:28 +00:00
195 lines
5.3 KiB
Python
195 lines
5.3 KiB
Python
"""Actions to manage the system."""
|
|
|
|
import os
|
|
import subprocess
|
|
import pytz
|
|
from typing import Optional, List
|
|
from pydantic import BaseModel
|
|
|
|
from selfprivacy_api.jobs import Job, JobStatus, Jobs
|
|
from selfprivacy_api.jobs.upgrade_system import rebuild_system_task
|
|
|
|
from selfprivacy_api.utils import WriteUserData, ReadUserData
|
|
from selfprivacy_api.utils import UserDataFiles
|
|
|
|
from selfprivacy_api.graphql.queries.providers import DnsProvider
|
|
|
|
|
|
def get_timezone() -> str:
|
|
"""Get the timezone of the server"""
|
|
with ReadUserData() as user_data:
|
|
if "timezone" in user_data:
|
|
return user_data["timezone"]
|
|
return "Etc/UTC"
|
|
|
|
|
|
class InvalidTimezone(Exception):
|
|
"""Invalid timezone"""
|
|
|
|
pass
|
|
|
|
|
|
def change_timezone(timezone: str) -> None:
|
|
"""Change the timezone of the server"""
|
|
if timezone not in pytz.all_timezones:
|
|
raise InvalidTimezone(f"Invalid timezone: {timezone}")
|
|
with WriteUserData() as user_data:
|
|
user_data["timezone"] = timezone
|
|
|
|
|
|
class UserDataAutoUpgradeSettings(BaseModel):
|
|
"""Settings for auto-upgrading user data"""
|
|
|
|
enable: bool = True
|
|
allowReboot: bool = False
|
|
|
|
|
|
def set_dns_provider(provider: DnsProvider, token: str):
|
|
with WriteUserData() as user_data:
|
|
if "dns" not in user_data.keys():
|
|
user_data["dns"] = {}
|
|
user_data["dns"]["provider"] = provider.value
|
|
|
|
with WriteUserData(file_type=UserDataFiles.SECRETS) as secrets:
|
|
if "dns" not in secrets.keys():
|
|
secrets["dns"] = {}
|
|
secrets["dns"]["apiKey"] = token
|
|
|
|
|
|
def get_auto_upgrade_settings() -> UserDataAutoUpgradeSettings:
|
|
"""Get the auto-upgrade settings"""
|
|
with ReadUserData() as user_data:
|
|
if "autoUpgrade" in user_data:
|
|
return UserDataAutoUpgradeSettings(**user_data["autoUpgrade"])
|
|
return UserDataAutoUpgradeSettings()
|
|
|
|
|
|
def set_auto_upgrade_settings(
|
|
enable: Optional[bool] = None, allowReboot: Optional[bool] = None
|
|
) -> None:
|
|
"""Set the auto-upgrade settings"""
|
|
with WriteUserData() as user_data:
|
|
if "autoUpgrade" not in user_data:
|
|
user_data["autoUpgrade"] = {}
|
|
if enable is not None:
|
|
user_data["autoUpgrade"]["enable"] = enable
|
|
if allowReboot is not None:
|
|
user_data["autoUpgrade"]["allowReboot"] = allowReboot
|
|
|
|
|
|
class ShellException(Exception):
|
|
"""Something went wrong when calling another process"""
|
|
|
|
pass
|
|
|
|
|
|
def run_blocking(cmd: List[str], new_session: bool = False) -> str:
|
|
"""Run a process, block until done, return output, complain if failed"""
|
|
process_handle = subprocess.Popen(
|
|
cmd,
|
|
shell=False,
|
|
start_new_session=new_session,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
stdout_raw, stderr_raw = process_handle.communicate()
|
|
stdout = stdout_raw.decode("utf-8")
|
|
if stderr_raw is not None:
|
|
stderr = stderr_raw.decode("utf-8")
|
|
else:
|
|
stderr = ""
|
|
output = stdout + "\n" + stderr
|
|
if process_handle.returncode != 0:
|
|
raise ShellException(
|
|
f"Shell command failed, command array: {cmd}, output: {output}"
|
|
)
|
|
return stdout
|
|
|
|
|
|
def add_rebuild_job() -> Job:
|
|
return Jobs.add(
|
|
type_id="system.nixos.rebuild",
|
|
name="Rebuild system",
|
|
description="Applying the new system configuration by building the new NixOS generation.",
|
|
status=JobStatus.CREATED,
|
|
)
|
|
|
|
|
|
def rebuild_system() -> Job:
|
|
"""Rebuild the system"""
|
|
job = add_rebuild_job()
|
|
rebuild_system_task(job)
|
|
return job
|
|
|
|
|
|
def rollback_system() -> int:
|
|
"""Rollback the system"""
|
|
run_blocking(["systemctl", "start", "sp-nixos-rollback.service"], new_session=True)
|
|
return 0
|
|
|
|
|
|
def upgrade_system() -> Job:
|
|
"""Upgrade the system"""
|
|
job = Jobs.add(
|
|
type_id="system.nixos.upgrade",
|
|
name="Upgrade system",
|
|
description="Upgrading the system to the latest version.",
|
|
status=JobStatus.CREATED,
|
|
)
|
|
rebuild_system_task(job, upgrade=True)
|
|
return job
|
|
|
|
|
|
def reboot_system() -> None:
|
|
"""Reboot the system"""
|
|
run_blocking(["reboot"], new_session=True)
|
|
|
|
|
|
def get_system_version() -> str:
|
|
"""Get system version"""
|
|
return subprocess.check_output(["uname", "-a"]).decode("utf-8").strip()
|
|
|
|
|
|
def get_python_version() -> str:
|
|
"""Get Python version"""
|
|
return subprocess.check_output(["python", "-V"]).decode("utf-8").strip()
|
|
|
|
|
|
class SystemActionResult(BaseModel):
|
|
"""System action result"""
|
|
|
|
status: int
|
|
message: str
|
|
data: str
|
|
|
|
|
|
def pull_repository_changes() -> SystemActionResult:
|
|
"""Pull repository changes"""
|
|
git_pull_command = ["git", "pull"]
|
|
|
|
current_working_directory = os.getcwd()
|
|
os.chdir("/etc/nixos")
|
|
|
|
git_pull_process_descriptor = subprocess.Popen(
|
|
git_pull_command,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
shell=False,
|
|
)
|
|
|
|
data = git_pull_process_descriptor.communicate()[0].decode("utf-8")
|
|
|
|
os.chdir(current_working_directory)
|
|
|
|
if git_pull_process_descriptor.returncode == 0:
|
|
return SystemActionResult(
|
|
status=0,
|
|
message="Pulled repository changes",
|
|
data=data,
|
|
)
|
|
return SystemActionResult(
|
|
status=git_pull_process_descriptor.returncode,
|
|
message="Failed to pull repository changes",
|
|
data=data,
|
|
)
|