90 lines
2.9 KiB
Python
90 lines
2.9 KiB
Python
# coding=utf-8
|
|
import re
|
|
import shlex
|
|
import subprocess
|
|
from datetime import datetime
|
|
|
|
_TZ_REGEX = r'''^([A-z0-9]+\/)?([A-z0-9]+)([+-]\d+)?$'''
|
|
|
|
|
|
class ErrorInvalidTimezone(Exception):
|
|
pass
|
|
|
|
|
|
class ErrorInvalidCmdTemplate(Exception):
|
|
pass
|
|
|
|
|
|
class ErrorTimeConfig(Exception):
|
|
pass
|
|
|
|
|
|
def get_system_timezone(cmd: str = "cat /etc/timezone") -> str:
|
|
"""
|
|
Rufe die Systemzeitzone mit dem entsprechenden Befehl ab.
|
|
|
|
:return: Systemzeitzone im Unix-Format (z.B. Europe/Berlin)
|
|
:raise ErrorTimeConfig: wenn der Befehl einen Fehler zurückgibt
|
|
:raise ErrorInvalidTimezone: wenn die ermittelte Zeitzone ein ungültiges Format hat
|
|
|
|
"""
|
|
tz = _run_cmd(cmd).strip()
|
|
|
|
if not re.match(_TZ_REGEX, tz):
|
|
raise ErrorInvalidTimezone(f'Got timezone {tz} with invalid format')
|
|
|
|
return tz
|
|
|
|
|
|
def set_system_datetime(date_time: datetime,
|
|
cmd_tmpl: str = "date -s '%Y-%m-%d %H:%M:%S'"):
|
|
"""
|
|
Ändere die Systemzeit mit dem entsprechenden Befehl.
|
|
Die Anwendung muss hierfür als Root laufen.
|
|
|
|
:param cmd_tmpl: Befehlsvorlage (verwende Python-strftime()-Platzhalter für
|
|
Datum und Uhrzeit)
|
|
:param date_time: Einzustellendes Datum und Uhrzeit
|
|
:raise ErrorTimeConfig: wenn der Konfigurationsbefehl einen Fehler zurückgibt
|
|
"""
|
|
cmd_str = date_time.strftime(cmd_tmpl)
|
|
_run_cmd(cmd_str)
|
|
|
|
|
|
def set_system_timezone(tz: str,
|
|
cmd_tmpl: str = "timedatectl set-timezone '{TZ}'"):
|
|
"""
|
|
Ändere die Systemzeitzone mit dem entsprechenden Befehl.
|
|
Die Anwendung muss hierfür als Root laufen.
|
|
|
|
:param tz: Zeitzone im Unix-Format (z.B. Europe/Berlin)
|
|
:param cmd_tmpl: Befehlsvorlage (verwende ``{TZ}`` als Platzhalter für die Zeitzone).
|
|
:raise ErrorInvalidCmdTemplate: wenn die Befehlsvorlage keinen Platzhalter enthält
|
|
:raise ErrorInvalidTimezone: wenn die eingegebene Zeitzone ein ungültiges Format hat
|
|
:raise ErrorTimeConfig: wenn der Konfigurationsbefehl einen Fehler zurückgibt
|
|
"""
|
|
if '{TZ}' not in cmd_tmpl:
|
|
raise ErrorInvalidCmdTemplate(
|
|
'Command template %s is missing {TZ} placeholder')
|
|
|
|
if not re.match(_TZ_REGEX, tz):
|
|
raise ErrorInvalidTimezone(f'Timezone {tz} has invalid format')
|
|
|
|
cmd_str = cmd_tmpl.replace('{TZ}', tz)
|
|
_run_cmd(cmd_str)
|
|
|
|
|
|
def _run_cmd(cmd_str: str) -> str:
|
|
cmd_parts = shlex.split(cmd_str)
|
|
|
|
try:
|
|
completed = subprocess.run(cmd_parts,
|
|
check=True,
|
|
universal_newlines=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
return completed.stdout
|
|
except subprocess.CalledProcessError as e:
|
|
raise ErrorTimeConfig(
|
|
f'Error configuring system time. Ran cmd {e.cmd}. \
|
|
Output "{e.stdout}{e.stderr}". Exit code {e.returncode}.') from e
|