Переглянути джерело

[MySQL] Check if MySQL supports timezone conversion on startup

FreddleSpl0it 3 місяців тому
батько
коміт
767d746419

+ 17 - 9
data/Dockerfiles/bootstrap/modules/BootstrapBase.py

@@ -273,33 +273,39 @@ 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():
-      path.unlink()
+      if path.name not in exclude:
+        path.unlink()
     elif path.is_dir():
       if recursive:
         shutil.rmtree(path)
@@ -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

+ 40 - 0
data/Dockerfiles/bootstrap/modules/BootstrapMysql.py

@@ -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}")