206 lines
8.1 KiB
Python
206 lines
8.1 KiB
Python
#!/usr/bin/env python3
|
|
import tkinter as tk
|
|
from tkinter import messagebox
|
|
import tkinter.ttk as ttk
|
|
import urllib.request
|
|
import json
|
|
import tempfile
|
|
import subprocess
|
|
import sys
|
|
import os
|
|
import threading
|
|
from urllib.parse import urljoin
|
|
|
|
# Список серверов
|
|
SERVERS = [
|
|
{"name": "Гринатом (МСК)", "url": "http://gren-s-synd01.gk.rosatom.local/admin_helper/"},
|
|
{"name": "Гринатом (НН)", "url": "http://grenn-s-synd01.gk.rosatom.local/admin_helper/"},
|
|
{"name": "ГК Росатом", "url": "http://gkrs-s-synd01.gk.rosatom.local/admin_helper/"},
|
|
]
|
|
|
|
# Имя файла описания (manifest)
|
|
MANIFEST_FILE = "scripts.json"
|
|
|
|
class AdminHelper:
|
|
def __init__(self, root):
|
|
self.root = root
|
|
self.root.title("Admin Helper (Linux)")
|
|
self.root.geometry("500x450")
|
|
|
|
# --- Верхняя панель (Выпадающий список) ---
|
|
self.server_frame = tk.Frame(root, pady=10, bg="#f0f0f0")
|
|
self.server_frame.pack(fill='x')
|
|
tk.Label(self.server_frame, text="Сервер:", bg="#f0f0f0", font=("Arial", 10, "bold")).pack(side='left', padx=5)
|
|
# Создаем выпадающий список
|
|
server_names = [s['name'] for s in SERVERS]
|
|
self.server_combo = ttk.Combobox(
|
|
self.server_frame,
|
|
values=server_names,
|
|
state="readonly", # Запрещаем ручной ввод, можно только выбирать
|
|
width=30
|
|
)
|
|
self.server_combo.pack(side='left', padx=5)
|
|
# Если есть серверы, выбираем первый по умолчанию
|
|
if server_names:
|
|
self.server_combo.current(0)
|
|
# Кнопка "Загрузить" для явного вызова
|
|
self.btn_connect = tk.Button(
|
|
self.server_frame,
|
|
text="Загрузить скрипты",
|
|
command=self.on_server_select
|
|
)
|
|
self.btn_connect.pack(side='left', padx=5)
|
|
self.server_combo.bind("<<ComboboxSelected>>")
|
|
self.active_server_label = tk.Label(root, text="Выберите сервер", fg="blue")
|
|
self.active_server_label.pack(pady=(0, 10))
|
|
|
|
# --- Основная часть (Скролл) ---
|
|
self.main_frame = tk.Frame(root)
|
|
self.main_frame.pack(expand=True, fill='both')
|
|
|
|
self.label_title = tk.Label(
|
|
self.main_frame,
|
|
text="Выберите действие",
|
|
font=("Arial", 14)
|
|
)
|
|
self.label_title.pack(pady=10)
|
|
|
|
self.canvas = tk.Canvas(self.main_frame)
|
|
self.scrollbar = tk.Scrollbar(self.main_frame, orient="vertical", command=self.canvas.yview)
|
|
self.scrollable_frame = tk.Frame(self.canvas)
|
|
|
|
self.scrollable_frame.bind(
|
|
"<Configure>",
|
|
lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
|
|
)
|
|
|
|
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
|
|
self.canvas.configure(yscrollcommand=self.scrollbar.set)
|
|
|
|
self.canvas.pack(side="left", fill="both", expand=True, padx=20)
|
|
self.scrollbar.pack(side="right", fill="y")
|
|
|
|
self.status_label = tk.Label(root, text="Ожидание...", bd=1, relief=tk.SUNKEN, anchor=tk.W)
|
|
self.status_label.pack(side=tk.BOTTOM, fill=tk.X)
|
|
|
|
def on_server_select(self, event=None):
|
|
"""Срабатывает при выборе сервера из списка"""
|
|
selected_name = self.server_combo.get()
|
|
|
|
# Ищем данные сервера в общем списке по имени
|
|
server_info = next((s for s in SERVERS if s['name'] == selected_name), None)
|
|
|
|
if server_info:
|
|
self.connect_to_server(server_info)
|
|
else:
|
|
self.status_label.config(text="Ошибка: сервер не найден")
|
|
|
|
def connect_to_server(self, server_info):
|
|
base_url = server_info['url']
|
|
name = server_info['name']
|
|
self.active_server_label.config(text=f"Активен: {name}")
|
|
|
|
# Очистка
|
|
for widget in self.scrollable_frame.winfo_children():
|
|
widget.destroy()
|
|
|
|
self.status_label.config(text=f"Загрузка {MANIFEST_FILE}...")
|
|
thread = threading.Thread(target=self.load_scripts_from_json, args=(base_url,), daemon=True)
|
|
thread.start()
|
|
|
|
def download_content(self, url):
|
|
"""Универсальный загрузчик (текст или бинарник)"""
|
|
try:
|
|
headers = {'User-Agent': 'Mozilla/5.0'}
|
|
req = urllib.request.Request(url, headers=headers)
|
|
with urllib.request.urlopen(req) as response:
|
|
return response.read()
|
|
except Exception as e:
|
|
print(f"Ошибка загрузки {url}: {e}")
|
|
return None
|
|
|
|
def load_scripts_from_json(self, base_url):
|
|
# 1. Формируем ссылку на JSON-файл
|
|
manifest_url = urljoin(base_url, MANIFEST_FILE)
|
|
json_data = self.download_content(manifest_url)
|
|
|
|
if not json_data:
|
|
self.root.after(0, lambda: self.status_label.config(text="Ошибка: не найден scripts.json"))
|
|
return
|
|
|
|
# 2. Парсим JSON
|
|
try:
|
|
script_list = json.loads(json_data)
|
|
except json.JSONDecodeError:
|
|
self.root.after(0, lambda: self.status_label.config(text="Ошибка: неверный формат JSON"))
|
|
return
|
|
|
|
# 3. Проходим по списку и скачиваем файлы
|
|
count = 0
|
|
for item in script_list:
|
|
name = item.get('name', 'Без имени')
|
|
filename = item.get('file')
|
|
|
|
if not filename:
|
|
continue
|
|
|
|
script_url = urljoin(base_url, filename)
|
|
content = self.download_content(script_url)
|
|
|
|
if content:
|
|
# Определяем тип по расширению
|
|
file_ext = filename.split('.')[-1].lower()
|
|
|
|
# Создаем кнопку
|
|
self.root.after(0, lambda n=name, c=content, f=filename, ext=file_ext: self.create_action_button(n, c, f, ext))
|
|
count += 1
|
|
|
|
if count == 0:
|
|
self.root.after(0, lambda: self.status_label.config(text="Нет доступных скриптов"))
|
|
else:
|
|
self.root.after(0, lambda: self.status_label.config(text=f"Загружено: {count} скриптов"))
|
|
|
|
def create_action_button(self, text, content, filename, ext):
|
|
btn = tk.Button(
|
|
self.scrollable_frame,
|
|
text=text,
|
|
width=40,
|
|
height=2,
|
|
anchor="w"
|
|
)
|
|
btn.config(command=lambda c=content, f=filename, e=ext: self.run_file(c, f, e))
|
|
|
|
btn.pack(pady=2, fill='x')
|
|
|
|
def run_file(self, content, filename, ext):
|
|
try:
|
|
# Создаем временный файл
|
|
with tempfile.NamedTemporaryFile(mode='wb', suffix=f'.{ext}', delete=False) as tmp_file:
|
|
tmp_file.write(content)
|
|
tmp_path = tmp_file.name
|
|
|
|
# Логика запуска для Linux
|
|
if ext == 'bin':
|
|
# 1. Делаем файл исполняемым (chmod +x)
|
|
os.chmod(tmp_path, 0o755)
|
|
# 2. Запускаем напрямую
|
|
subprocess.Popen([tmp_path])
|
|
|
|
elif ext == 'sh':
|
|
os.chmod(tmp_path, 0o755)
|
|
subprocess.Popen(['fly-term', '--hide-menubar', '--hide-tabbar', '-e', tmp_path])
|
|
|
|
else:
|
|
messagebox.showwarning("Внимание", f"Неизвестный тип файла: {ext}")
|
|
|
|
# ИЗМЕНЕНИЕ: Убрали всплывающее окно, просто пишем в статус-бар
|
|
self.status_label.config(text=f"Запущен: {filename}")
|
|
|
|
except Exception as e:
|
|
messagebox.showerror("Ошибка", f"Не удалось запустить: {e}")
|
|
|
|
if __name__ == "__main__":
|
|
root = tk.Tk()
|
|
app = AdminHelper(root)
|
|
root.mainloop()
|