1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2025-12-24 07:11:32 +00:00

[MySQL] Check if MySQL supports timezone conversion on startup

This commit is contained in:
FreddleSpl0it
2025-05-22 12:59:37 +02:00
parent 9174a05af3
commit 767d746419
2 changed files with 57 additions and 9 deletions

View File

@@ -273,32 +273,38 @@ class BootstrapBase:
shutil.copy2(src_path, dst_path)
def remove(self, path, recursive=False, wipe_contents=False):
def remove(self, path, recursive=False, wipe_contents=False, exclude=None):
"""
Removes a file or directory.
Removes a file or directory with optional exclusion logic.
Args:
path (str or Path): The file or directory path to remove.
recursive (bool): If True, directories will be removed recursively.
wipe_contents (bool): If True and path is a directory, only its contents are removed, not the dir itself.
exclude (list[str], optional): List of filenames to exclude from deletion.
Raises:
FileNotFoundError: If the path does not exist.
ValueError: If a directory is passed without recursive or wipe_contents.
"""
path = Path(path)
exclude = set(exclude or [])
if not path.exists():
raise FileNotFoundError(f"Cannot remove: {path} does not exist")
if wipe_contents and path.is_dir():
for child in path.iterdir():
if child.name in exclude:
continue
if child.is_dir():
shutil.rmtree(child)
else:
child.unlink()
elif path.is_file():
if path.name not in exclude:
path.unlink()
elif path.is_dir():
if recursive:
@@ -664,21 +670,22 @@ class BootstrapBase:
allowed_chars = string.ascii_letters + string.digits + "_-"
return ''.join(secrets.choice(allowed_chars) for _ in range(length))
def run_command(self, command, check=True, shell=False):
def run_command(self, command, check=True, shell=False, input_stream=None):
"""
Executes an OS command and optionally checks for errors.
Supports piping via input_stream.
Args:
command (str or list): The command to execute. Can be a string (if shell=True)
or a list of command arguments.
check (bool): If True, raises CalledProcessError on failure.
shell (bool): If True, runs the command in a shell.
command (str or list): The command to execute.
check (bool): Raise CalledProcessError on failure if True.
shell (bool): Run in a shell if True.
input_stream: A pipe source to use as stdin (e.g. another process's stdout).
Returns:
subprocess.CompletedProcess: The result of the command execution.
Logs:
Prints the command being run and any error output.
Prints command output and errors.
"""
try:
@@ -686,6 +693,7 @@ class BootstrapBase:
command,
shell=shell,
check=check,
stdin=input_stream,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True

View File

@@ -20,6 +20,8 @@ class Bootstrap(BootstrapBase):
print("Running mysql_upgrade...")
self.upgrade_mysql(dbuser, dbpass, socket)
print("Checking timezone support with CONVERT_TZ...")
self.check_and_import_timezone_support(dbuser, dbpass, socket)
print("Shutting down temporary mysqld...")
self.close_mysql()
@@ -119,3 +121,41 @@ class Bootstrap(BootstrapBase):
else:
print("mysql_upgrade failed after all retries.")
return False
def check_and_import_timezone_support(self, dbuser, dbpass, socket):
"""
Checks if MySQL supports timezone conversion (CONVERT_TZ).
If not, it imports timezone info using mysql_tzinfo_to_sql piped into mariadb.
"""
try:
cursor = self.mysql_conn.cursor()
cursor.execute("SELECT CONVERT_TZ('2019-11-02 23:33:00','Europe/Berlin','UTC')")
result = cursor.fetchone()
cursor.close()
if not result or result[0] is None:
print("Timezone conversion failed or returned NULL. Importing timezone info...")
# Use mysql_tzinfo_to_sql piped into mariadb
tz_dump = subprocess.Popen(
["mysql_tzinfo_to_sql", "/usr/share/zoneinfo"],
stdout=subprocess.PIPE
)
self.run_command([
"mariadb",
"--socket", socket,
"-u", dbuser,
f"-p{dbpass}",
"mysql"
], input_stream=tz_dump.stdout)
tz_dump.stdout.close()
tz_dump.wait()
print("Timezone info successfully imported.")
else:
print(f"Timezone support is working. Sample result: {result[0]}")
except Exception as e:
print(f"Failed to verify or import timezone info: {e}")