Controller/tsgrain_controller/systimecfg.py

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