manager.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import os
  2. import sys
  3. import subprocess
  4. import yaml
  5. import shutil
  6. # Constants
  7. SCRIPTS_DIR = "/scripts"
  8. DEFAULTS_DIR = "/app/defaults"
  9. CONFIG_PATH = os.path.join(SCRIPTS_DIR, "config.yaml")
  10. CRONTAB_PATH = "/app/generated_crontab"
  11. def initialize_volume_if_empty():
  12. """Copies default files to /scripts if config.yaml is missing."""
  13. if not os.path.exists(CONFIG_PATH):
  14. print("---------------------------------")
  15. print("No config found in volume. Initializing with defaults...")
  16. # Ensure directory exists
  17. os.makedirs(SCRIPTS_DIR, exist_ok=True)
  18. # Copy all files from defaults to scripts
  19. if os.path.exists(DEFAULTS_DIR):
  20. for filename in os.listdir(DEFAULTS_DIR):
  21. src = os.path.join(DEFAULTS_DIR, filename)
  22. dst = os.path.join(SCRIPTS_DIR, filename)
  23. if os.path.isfile(src):
  24. shutil.copy2(src, dst)
  25. print(f" -> Created: {filename}")
  26. print("Initialization complete.")
  27. print("---------------------------------")
  28. else:
  29. print(f"Found existing config at {CONFIG_PATH}. Using it.")
  30. def install_dependencies(deps):
  31. if not deps:
  32. return
  33. print(f"Installing {len(deps)} dependencies...")
  34. subprocess.check_call([sys.executable, "-m", "pip", "install", "--no-cache-dir"] + deps)
  35. def generate_crontab(jobs):
  36. print(f"Scheduling {len(jobs)} jobs...")
  37. lines = []
  38. for job in jobs:
  39. schedule = job['schedule']
  40. script = job['script']
  41. # Use -u for unbuffered output
  42. command = f"python3 -u {SCRIPTS_DIR}/{script}"
  43. lines.append(f"{schedule} {command}")
  44. print(f" -> Loaded: {script} [{schedule}]")
  45. with open(CRONTAB_PATH, "w") as f:
  46. f.write("\n".join(lines) + "\n")
  47. def main():
  48. # 1. Initialize Volume (The new feature)
  49. initialize_volume_if_empty()
  50. # 2. Read Config
  51. if not os.path.exists(CONFIG_PATH):
  52. print(f"Error: {CONFIG_PATH} still not found after initialization.")
  53. sys.exit(1)
  54. with open(CONFIG_PATH, "r") as f:
  55. config = yaml.safe_load(f)
  56. # 3. Setup Environment
  57. install_dependencies(config.get("dependencies", []))
  58. generate_crontab(config.get("jobs", []))
  59. # 4. Start Supercronic
  60. print("Starting Scheduler...")
  61. print("--------------------------------------------")
  62. sys.stdout.flush()
  63. # Wir starten Supercronic und leiten stderr (wo Logs sind) an stdout weiter
  64. # und pipen das Ganze in unseren log_formatter.py
  65. cmd = f"supercronic {CRONTAB_PATH} 2>&1 | python3 -u /app/log_formatter.py"
  66. # shell=True ist hier notwendig für die Pipe "|"
  67. subprocess.call(cmd, shell=True)
  68. if __name__ == "__main__":
  69. main()