|
|
@@ -0,0 +1,84 @@
|
|
|
+import os
|
|
|
+import sys
|
|
|
+import subprocess
|
|
|
+import yaml
|
|
|
+import shutil
|
|
|
+
|
|
|
+# Constants
|
|
|
+SCRIPTS_DIR = "/scripts"
|
|
|
+DEFAULTS_DIR = "/app/defaults"
|
|
|
+CONFIG_PATH = os.path.join(SCRIPTS_DIR, "config.yaml")
|
|
|
+CRONTAB_PATH = "/app/generated_crontab"
|
|
|
+
|
|
|
+def initialize_volume_if_empty():
|
|
|
+ """Copies default files to /scripts if config.yaml is missing."""
|
|
|
+ if not os.path.exists(CONFIG_PATH):
|
|
|
+ print("---------------------------------")
|
|
|
+ print("No config found in volume. Initializing with defaults...")
|
|
|
+
|
|
|
+ # Ensure directory exists
|
|
|
+ os.makedirs(SCRIPTS_DIR, exist_ok=True)
|
|
|
+
|
|
|
+ # Copy all files from defaults to scripts
|
|
|
+ if os.path.exists(DEFAULTS_DIR):
|
|
|
+ for filename in os.listdir(DEFAULTS_DIR):
|
|
|
+ src = os.path.join(DEFAULTS_DIR, filename)
|
|
|
+ dst = os.path.join(SCRIPTS_DIR, filename)
|
|
|
+ if os.path.isfile(src):
|
|
|
+ shutil.copy2(src, dst)
|
|
|
+ print(f" -> Created: {filename}")
|
|
|
+ print("Initialization complete.")
|
|
|
+ print("---------------------------------")
|
|
|
+ else:
|
|
|
+ print(f"Found existing config at {CONFIG_PATH}. Using it.")
|
|
|
+
|
|
|
+def install_dependencies(deps):
|
|
|
+ if not deps:
|
|
|
+ return
|
|
|
+ print(f"Installing {len(deps)} dependencies...")
|
|
|
+ subprocess.check_call([sys.executable, "-m", "pip", "install", "--no-cache-dir"] + deps)
|
|
|
+
|
|
|
+def generate_crontab(jobs):
|
|
|
+ print(f"Scheduling {len(jobs)} jobs...")
|
|
|
+ lines = []
|
|
|
+ for job in jobs:
|
|
|
+ schedule = job['schedule']
|
|
|
+ script = job['script']
|
|
|
+ # Use -u for unbuffered output
|
|
|
+ command = f"python3 -u {SCRIPTS_DIR}/{script}"
|
|
|
+ lines.append(f"{schedule} {command}")
|
|
|
+ print(f" -> Loaded: {script} [{schedule}]")
|
|
|
+
|
|
|
+ with open(CRONTAB_PATH, "w") as f:
|
|
|
+ f.write("\n".join(lines) + "\n")
|
|
|
+
|
|
|
+def main():
|
|
|
+ # 1. Initialize Volume (The new feature)
|
|
|
+ initialize_volume_if_empty()
|
|
|
+
|
|
|
+ # 2. Read Config
|
|
|
+ if not os.path.exists(CONFIG_PATH):
|
|
|
+ print(f"Error: {CONFIG_PATH} still not found after initialization.")
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ with open(CONFIG_PATH, "r") as f:
|
|
|
+ config = yaml.safe_load(f)
|
|
|
+
|
|
|
+ # 3. Setup Environment
|
|
|
+ install_dependencies(config.get("dependencies", []))
|
|
|
+ generate_crontab(config.get("jobs", []))
|
|
|
+
|
|
|
+ # 4. Start Supercronic
|
|
|
+ print("Starting Scheduler...")
|
|
|
+ print("--------------------------------------------")
|
|
|
+ sys.stdout.flush()
|
|
|
+
|
|
|
+ # Wir starten Supercronic und leiten stderr (wo Logs sind) an stdout weiter
|
|
|
+ # und pipen das Ganze in unseren log_formatter.py
|
|
|
+ cmd = f"supercronic {CRONTAB_PATH} 2>&1 | python3 -u /app/log_formatter.py"
|
|
|
+
|
|
|
+ # shell=True ist hier notwendig für die Pipe "|"
|
|
|
+ subprocess.call(cmd, shell=True)
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ main()
|