Initial
This commit is contained in:
BIN
__pycache__/create.cpython-311.pyc
Normal file
BIN
__pycache__/create.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/json.cpython-311.pyc
Normal file
BIN
__pycache__/json.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/lxc_ls.cpython-311.pyc
Normal file
BIN
__pycache__/lxc_ls.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/lxc_ls1.cpython-311.pyc
Normal file
BIN
__pycache__/lxc_ls1.cpython-311.pyc
Normal file
Binary file not shown.
128
create.py
Normal file
128
create.py
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, messagebox
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
class LxcLauncherGUI:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.root.title("LXC Launcher")
|
||||||
|
|
||||||
|
# Neue Variable für den Hostnamen
|
||||||
|
self.host_name_var = tk.StringVar()
|
||||||
|
|
||||||
|
# Neue Variable für die Anzahl der zu erstellenden Hosts
|
||||||
|
self.num_hosts_var = tk.StringVar()
|
||||||
|
self.num_hosts_var.set("1") # Standardwert auf 1 setzen
|
||||||
|
|
||||||
|
self.create_widgets()
|
||||||
|
|
||||||
|
def create_widgets(self):
|
||||||
|
# Label
|
||||||
|
label = ttk.Label(self.root, text="Wähle ein LXC-Image:")
|
||||||
|
label.grid(row=0, column=0, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Auswahlmenü
|
||||||
|
images = self.get_lxc_images()
|
||||||
|
self.selected_image = tk.StringVar()
|
||||||
|
image_menu = ttk.Combobox(self.root, textvariable=self.selected_image, values=images)
|
||||||
|
image_menu.grid(row=0, column=1, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Eingabefeld für den Hostnamen
|
||||||
|
host_label = ttk.Label(self.root, text="Host-Name:")
|
||||||
|
host_label.grid(row=1, column=0, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
host_entry = ttk.Entry(self.root, textvariable=self.host_name_var)
|
||||||
|
host_entry.grid(row=1, column=1, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Eingabefeld für die Anzahl der zu erstellenden Hosts
|
||||||
|
num_hosts_label = ttk.Label(self.root, text="Anzahl der Hosts:")
|
||||||
|
num_hosts_label.grid(row=2, column=0, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
num_hosts_entry = ttk.Entry(self.root, textvariable=self.num_hosts_var)
|
||||||
|
num_hosts_entry.grid(row=2, column=1, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Checkbox für Nesting
|
||||||
|
self.nesting_checkbox_var = tk.BooleanVar()
|
||||||
|
nesting_checkbox = ttk.Checkbutton(self.root, text="Nesting", variable=self.nesting_checkbox_var)
|
||||||
|
nesting_checkbox.grid(row=3, column=0, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Checkbox für Protection
|
||||||
|
self.protection_checkbox_var = tk.BooleanVar()
|
||||||
|
protection_checkbox = ttk.Checkbutton(self.root, text="Protection", variable=self.protection_checkbox_var)
|
||||||
|
protection_checkbox.grid(row=3, column=1, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Button zum Starten
|
||||||
|
launch_button = ttk.Button(self.root, text="Starten", command=self.launch_lxc)
|
||||||
|
launch_button.grid(row=4, column=0, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Button für Weitere Hosts
|
||||||
|
hosts_button = ttk.Button(self.root, text="Weitere Hosts", command=self.show_hosts)
|
||||||
|
hosts_button.grid(row=4, column=1, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Button zum Beenden
|
||||||
|
exit_button = ttk.Button(self.root, text="Beenden", command=self.root.destroy)
|
||||||
|
exit_button.grid(row=5, column=0, columnspan=4, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
# Label für das Ergebnis
|
||||||
|
self.result_label = ttk.Label(self.root, text="")
|
||||||
|
self.result_label.grid(row=6, column=0, columnspan=4, padx=10, pady=10, sticky="w")
|
||||||
|
|
||||||
|
def show_error_message(self, message):
|
||||||
|
messagebox.showerror("Fehler", message)
|
||||||
|
|
||||||
|
def show_info_message(self, message):
|
||||||
|
messagebox.showinfo("OK", message)
|
||||||
|
|
||||||
|
def get_lxc_images(self):
|
||||||
|
command = "lxc image list images: | awk -F'|' '{ print $2}' | sed '/^[[:space:]]*$/d' | awk -F'/' '{ print $1\"/\"$2 }' | sort | uniq | grep -vE 'more|ALIAS' | grep -iE 'Debian|CentOS|Ubuntu'"
|
||||||
|
process = Popen(command, shell=True, stdout=PIPE, stderr=PIPE)
|
||||||
|
output, error = process.communicate()
|
||||||
|
images = [line.strip() for line in output.decode("utf-8").split('\n') if line.strip()]
|
||||||
|
return images
|
||||||
|
|
||||||
|
def launch_lxc(self):
|
||||||
|
selected_image = self.selected_image.get()
|
||||||
|
host_name_prefix = self.host_name_var.get()
|
||||||
|
|
||||||
|
if selected_image and host_name_prefix:
|
||||||
|
num_hosts = self.num_hosts_var.get()
|
||||||
|
if not num_hosts.isdigit() or int(num_hosts) <= 0:
|
||||||
|
self.show_error_message("Bitte geben Sie eine gültige positive Ganzzahl für die Anzahl der Hosts ein.")
|
||||||
|
return
|
||||||
|
|
||||||
|
created_hosts = [] # Eine Liste, um die erstellten Hostnamen zu speichern
|
||||||
|
|
||||||
|
for i in range(1, int(num_hosts) + 1):
|
||||||
|
# Erstellen des Hostnamens mit Ordnungszahl
|
||||||
|
host_name = f"{host_name_prefix}{i}"
|
||||||
|
|
||||||
|
nesting_option = "true" if self.nesting_checkbox_var.get() else "false"
|
||||||
|
protection_option = "true" if self.protection_checkbox_var.get() else "false"
|
||||||
|
launch_command = f"lxc launch images:{selected_image} {host_name} -c security.nesting={nesting_option} -c security.protection.delete={protection_option}"
|
||||||
|
|
||||||
|
process = Popen(launch_command, shell=True, stdout=PIPE, stderr=PIPE)
|
||||||
|
output, error = process.communicate()
|
||||||
|
|
||||||
|
if error:
|
||||||
|
self.show_error_message(f"Fehler beim Starten des Containers {host_name}:\n{error.decode('utf-8')}")
|
||||||
|
else:
|
||||||
|
created_hosts.append(host_name)
|
||||||
|
|
||||||
|
if created_hosts:
|
||||||
|
self.show_info_message(f"Container erfolgreich eingerichtet:\n{', '.join(created_hosts)}")
|
||||||
|
|
||||||
|
def show_hosts(self):
|
||||||
|
# Hier kannst du die Logik für die Anzeige weiterer Hosts implementieren
|
||||||
|
# Zum Beispiel ein Popup-Fenster oder eine separate Seite im GUI
|
||||||
|
|
||||||
|
# Reset der Auswahl
|
||||||
|
self.selected_image.set("") # Zurücksetzen des Auswahlmenüs
|
||||||
|
self.host_name_var.set("") # Zurücksetzen des Hostnamen-Eingabefelds
|
||||||
|
self.num_hosts_var.set("") # Zurücksetzen des Felds für die Anzahl der Hosts
|
||||||
|
self.nesting_checkbox_var.set(False) # Zurücksetzen der Nesting-Checkbox
|
||||||
|
self.protection_checkbox_var.set(False) # Zurücksetzen der Protection-Checkbox
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = tk.Tk()
|
||||||
|
app = LxcLauncherGUI(root)
|
||||||
|
root.mainloop()
|
||||||
69
gui.py
Normal file
69
gui.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
from lxc_ls import LXCInfoGUI
|
||||||
|
from create import LxcLauncherGUI
|
||||||
|
|
||||||
|
class MyGUI:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.root.title("Zwei Ansichten")
|
||||||
|
self.root.geometry("800x400") # Setze die Fenstergröße auf 800x400
|
||||||
|
|
||||||
|
menubar = tk.Menu(self.root)
|
||||||
|
self.root.config(menu=menubar)
|
||||||
|
|
||||||
|
menu1 = tk.Menu(menubar, tearoff=0)
|
||||||
|
menu1.add_command(label="lxc list", command=self.lxc_list)
|
||||||
|
menu1.add_command(label="lxc create", command=self.lxc_create)
|
||||||
|
menubar.add_cascade(label="LXC Manage", menu=menu1)
|
||||||
|
|
||||||
|
menu2 = tk.Menu(menubar, tearoff=0)
|
||||||
|
menu2.add_command(label="Menüpunkt 2.1", command=self.menu_item2_1)
|
||||||
|
menu2.add_command(label="Menüpunkt 2.2", command=self.menu_item2_2)
|
||||||
|
menubar.add_cascade(label="Menü 2", menu=menu2)
|
||||||
|
|
||||||
|
menu3 = tk.Menu(menubar, tearoff=0)
|
||||||
|
menu3.add_command(label="Menüpunkt 3.1", command=self.menu_item3_1)
|
||||||
|
menu3.add_command(label="Menüpunkt 3.2", command=self.menu_item3_2)
|
||||||
|
menubar.add_cascade(label="Menü 3", menu=menu3)
|
||||||
|
|
||||||
|
self.frame1 = ttk.Frame(self.root, style='Green.TFrame')
|
||||||
|
self.frame1.place(relx=0, rely=0, relwidth=1, relheight=0.4)
|
||||||
|
|
||||||
|
frame2 = ttk.Frame(self.root, style='Yellow.TFrame')
|
||||||
|
frame2.place(relx=0, rely=0.4, relwidth=1, relheight=0.6)
|
||||||
|
|
||||||
|
ttk.Separator(self.root, orient='horizontal').place(relx=0, rely=0.4, relwidth=1)
|
||||||
|
|
||||||
|
self.root.style = ttk.Style()
|
||||||
|
self.root.style.configure('Green.TFrame', background='#aaffaa')
|
||||||
|
self.root.style.configure('Yellow.TFrame', background='#ffffaa')
|
||||||
|
|
||||||
|
def lxc_list(self):
|
||||||
|
for widget in self.frame1.winfo_children():
|
||||||
|
widget.destroy()
|
||||||
|
lxc_info_app = LXCInfoGUI(self.frame1)
|
||||||
|
|
||||||
|
def lxc_create(self):
|
||||||
|
# Hier wird das LXC-Erstellungsfenster geöffnet
|
||||||
|
create_window = tk.Toplevel(self.root)
|
||||||
|
create_window.title("LXC Launcher")
|
||||||
|
create_app = LxcLauncherGUI(create_window)
|
||||||
|
|
||||||
|
def menu_item2_1(self):
|
||||||
|
print("Menüpunkt 2.1 wurde ausgewählt.")
|
||||||
|
|
||||||
|
def menu_item2_2(self):
|
||||||
|
print("Menüpunkt 2.2 wurde ausgewählt.")
|
||||||
|
|
||||||
|
def menu_item3_1(self):
|
||||||
|
print("Menüpunkt 3.1 wurde ausgewählt.")
|
||||||
|
|
||||||
|
def menu_item3_2(self):
|
||||||
|
print("Menüpunkt 3.2 wurde ausgewählt.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = tk.Tk()
|
||||||
|
app = MyGUI(root)
|
||||||
|
root.mainloop()
|
||||||
161
lxc_ls.py
Normal file
161
lxc_ls.py
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
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()
|
||||||
Reference in New Issue
Block a user