import tkinter as tk from tkinter import ttk, messagebox import subprocess import json class LXCInfoGUI: def __init__(self, parent): self.parent = parent self.column_width = 120 columns = ('Host Name', 'Pool', 'IP Address', 'Nesting / Protect', 'OS', 'Status') self.tree = ttk.Treeview(self.parent, columns=columns, show='headings') for col in columns: self.tree.heading(col, text=col, command=lambda c=col: self.column_sort(c, False)) self.tree.column(col, width=self.column_width, anchor='w') self.tree.pack(padx=10, pady=10) self.tree.bind("", self.on_tree_double_click) self.refresh_button = ttk.Button(self.parent, text='Aktualisieren', command=self.refresh_info) self.refresh_button.pack(pady=10) self.parent.after(10000, self.auto_refresh_info) self.refresh_info() self.context_menu = tk.Menu(self.parent, tearoff=0) self.configure_context_menu() self.tree.bind("", self.show_context_menu) def configure_context_menu(self): menu_items = [ ("Start", self.start_container), ("Stoppen", self.stop_container), ("Löschen", self.delete_container), None, # Separator ("ProtecNO", self.set_protection_no), ("ProtectYES", self.set_protection_yes) ] for item in menu_items: if item: label, command = item self.context_menu.add_command(label=label, command=command) else: self.context_menu.add_separator() def show_context_menu(self, event): self.context_menu.post(event.x_root, event.y_root) def run_command(self, command): try: result = subprocess.run(command, stdout=subprocess.PIPE, text=True, shell=True, check=True) return result.stdout.strip() except subprocess.CalledProcessError as e: print(f"Fehler beim Ausführen des Befehls: {e}") return "" def get_lxc_info(self): command_output = self.run_command( "lxc list -f json | jq -cr '(.[] | [.name, .expanded_devices.root.pool, " "(.state.network.eth0.addresses // [] | map(select(.family == \"inet\").address) | join(\", \")), " "(.config.\"security.nesting\" // false), (.config.\"security.protection.delete\" // false), " ".config.\"image.os\", .config.\"image.release\", .state.status])'" ) try: lxc_info = [json.loads(line) for line in command_output.splitlines()] lxc_info.sort(key=lambda x: x[7] != 'Stopped') return lxc_info except json.JSONDecodeError as e: print(f"Fehler beim Dekodieren von JSON: {e}") return [] def refresh_info(self): for item in self.tree.get_children(): self.tree.delete(item) lxc_info = self.get_lxc_info() self.tree.tag_configure('oddrow', background='#f0f0f0') self.tree.tag_configure('evenrow', background='white') for i, container_info in enumerate(lxc_info): container_name, pool, ip_address, nesting, protection, os, release, status = container_info tags = ('oddrow', 'evenrow')[i % 2] self.tree.insert('', 'end', values=(container_name, pool, ip_address, f"{nesting}/{protection}", f"{os} {release}", status), tags=tags) def auto_refresh_info(self): self.refresh_info() self.parent.after(10000, self.auto_refresh_info) def on_tree_double_click(self, event): item = self.tree.selection()[0] container_name = self.tree.item(item, 'values')[0] status = self.tree.item(item, 'values')[5] if status == 'Running': response = messagebox.askyesno("Container stoppen", f"Soll der Container '{container_name}' gestoppt werden?") if response: self.run_command(f"lxc stop {container_name}") elif status == 'Stopped': response = messagebox.askyesno("Container starten", f"Soll der Container '{container_name}' gestartet werden?") if response: self.run_command(f"lxc start {container_name}") def start_container(self): item = self.tree.selection()[0] container_name = self.tree.item(item, 'values')[0] response = messagebox.askyesno("Container starten", f"Soll der Container '{container_name}' gestartet werden?") if response: self.run_command(f"lxc start {container_name}") def stop_container(self): item = self.tree.selection()[0] container_name = self.tree.item(item, 'values')[0] response = messagebox.askyesno("Container stoppen", f"Soll der Container '{container_name}' gestoppt werden?") if response: self.run_command(f"lxc stop {container_name}") def delete_container(self): item = self.tree.selection()[0] container_name = self.tree.item(item, 'values')[0] status = self.tree.item(item, 'values')[5] if status == 'Running': response = messagebox.askyesno("Container löschen", f"Der Container '{container_name}' ist noch aktiv. Möchten Sie ihn trotzdem löschen?") if response: self.run_command(f"lxc stop {container_name}") self.run_command(f"lxc delete {container_name}") else: response = messagebox.askyesno("Container löschen", f"Soll der Container '{container_name}' gelöscht werden?") if response: self.run_command(f"lxc delete {container_name}") def set_protection_no(self): self.set_protection(False) def set_protection_yes(self): self.set_protection(True) def set_protection(self, enable_protection): item = self.tree.selection()[0] container_name = self.tree.item(item, 'values')[0] protection_setting = "true" if enable_protection else "false" self.run_command(f"lxc config set {container_name} security.protection.delete={protection_setting}") def column_sort(self, col, reverse): l = [(self.tree.set(k, col), k) for k in self.tree.get_children('')] l.sort(reverse=reverse) for index, (val, k) in enumerate(l): self.tree.move(k, '', index) if __name__ == "__main__": root = tk.Tk() app = LXCInfoGUI(root) root.mainloop()