Files
lxc-manage/lxc_ls.py
2023-11-16 09:50:25 +01:00

162 lines
6.4 KiB
Python

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("<Double-1>", 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("<Button-3>", 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()