#!/usr/bin/env python3 import os import subprocess import shutil import socket import sys import threading import queue # GUI import tkinter as tk from tkinter import messagebox import tkinter.ttk as ttk # ============================================================================== # НАСТРОЙКИ # ============================================================================== PUPPET_SERVER = "gren-s-synd01.gk.rosatom.local" # ============================================================================== class PuppetProgressBar: def __init__(self, parent, title): self.top = tk.Toplevel(parent) self.top.title(title) self.top.geometry("400x150") self.top.resizable(False, False) # Центрирование окна self.top.update_idletasks() width = self.top.winfo_width() height = self.top.winfo_height() x = (self.top.winfo_screenwidth() // 2) - (width // 2) y = (self.top.winfo_screenheight() // 2) - (height // 2) self.top.geometry(f'+{x}+{y}') self.lbl = tk.Label(self.top, text="Выполняется подключение к Puppet...", font=("Arial", 10)) self.lbl.pack(pady=20) self.progress = ttk.Progressbar(self.top, orient="horizontal", length=300, mode="determinate") self.progress.pack(pady=10) self.queue = queue.Queue() self.line_count = 0 # Флаги для ошибок self.critical_error = False self.error_type = None def start(self, cmd): threading.Thread(target=self._run_thread, args=(cmd,), daemon=True).start() self._update_loop() self.top.wait_window(self.top) def _run_thread(self, cmd): process = None try: process = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1 ) for line in iter(process.stdout.readline, ''): if line: # 1. ПРОВЕРКА НА КРИТИЧЕСКУЮ ОШИБКУ # Ищем ошибку сертификата в текущей строке if "does not match its private key" in line: self.critical_error = True self.error_type = "cert_mismatch" self.queue.put("CRITICAL_ERROR") # Убиваем процесс, так как дальше смысла ждать нет process.terminate() return # Если ошибки нет, двигаем прогресс-бар self.queue.put("STEP") process.wait() self.queue.put("DONE") except Exception as e: print(f"Thread Error: {e}") self.queue.put("ERROR") finally: if process and process.poll() is None: process.kill() def _update_loop(self): try: while True: msg = self.queue.get_nowait() if msg == "STEP": self.line_count += 1 value = self.line_count % 101 self.progress['value'] = value elif msg == "CRITICAL_ERROR": # Если критическая ошибка, сразу закрываем окно self.top.destroy() return elif msg == "DONE": self.progress['value'] = 100 self.lbl.config(text="Готово!") self.top.after(1000, self.top.destroy) return except queue.Empty: pass if self.top.winfo_exists(): self.top.after(50, self._update_loop) def log_message(msg): print(f"[LOG] {msg}") def get_environment(): try: ret_code, output = run_command("lsb_release -a", capture_output=True) detected_version = "Не найдена" for line in output.split('\n'): line = line.strip() if line.startswith("Release:"): detected_version = line.split(":")[1].strip() if detected_version.startswith("1.8"): return "new_base_18" elif detected_version.startswith("1.7"): return "new_base" messagebox.showerror("Ошибка", f"Версия ОС {detected_version} не поддерживается. Нужны 1.7 или 1.8.") sys.exit(1) except Exception as e: messagebox.showerror("Ошибка", f"Ошибка lsb_release: {e}") sys.exit(1) def run_command(cmd, capture_output=False): try: if capture_output: result = subprocess.run( cmd, shell=True, check=True, capture_output=True, text=True ) return 0, result.stdout + result.stderr else: subprocess.run(cmd, shell=True, check=True) return 0, "" except subprocess.CalledProcessError as e: if capture_output: return e.returncode, e.stdout + e.stderr else: raise e def main(): root = tk.Tk() root.withdraw() try: # 1. Проверка домена if not os.path.exists("/etc/krb5.keytab"): messagebox.showerror("Ошибка", "Введите ПК в домен") sys.exit(1) # 2. Окружение и пути environment = get_environment() if environment == "new_base_18": puppet_conf = "/etc/puppet/puppet.conf" ssl_dir = "/var/lib/puppet/ssl" else: puppet_conf = "/etc/puppetlabs/puppet/puppet.conf" ssl_dir = "/etc/puppetlabs/puppet/ssl" # 3. Проверка сертификатов private_keys_dir = os.path.join(ssl_dir, "private_keys") if os.path.exists(private_keys_dir) and os.listdir(private_keys_dir): messagebox.showerror("Ошибка", "АРМ уже подключен к puppet") sys.exit(1) # 4. Остановка log_message("Остановка puppet...") run_command("systemctl stop puppet", capture_output=False) # 5. Запись конфига conf_content = f"""server = {PUPPET_SERVER} runinterval = 60m environment = {environment} """ with open(puppet_conf, "w") as f: f.write(conf_content) # 6. Запуск Puppet с прогрессом pbar = PuppetProgressBar(root, "Подключение к Puppet...") pbar.start("puppet agent -t") # ====================================================================== # ОБРАБОТКА РЕЗУЛЬТАТА (после закрытия окна) # ====================================================================== if pbar.critical_error: # Если была найдена ошибка сертификата messagebox.showerror("Ошибка", "Удалите старый сертификат на сервере управления") log_message("ERROR - need to remove certificate on puppet server") # Очистка SSL папки if os.path.exists(ssl_dir): shutil.rmtree(ssl_dir) sys.exit(1) # ====================================================================== # 7. Финальные шаги (если ошибки не было) log_message("Финальный прогон...") subprocess.run("puppet agent -t > /dev/null 2>&1", shell=True) log_message("Включение puppet...") subprocess.run("systemctl start puppet", shell=True, check=True) subprocess.run("systemctl enable puppet", shell=True, check=True) messagebox.showinfo("Успех", "АРМ успешно подключен к puppet") except Exception as e: messagebox.showerror("Критическая ошибка", f"Ошибка: {e}") sys.exit(1) finally: root.destroy() if __name__ == "__main__": main()