Anpassungen hinzufügen von ssh-key und anpassung der out.csv
This commit is contained in:
@@ -37,6 +37,7 @@ Führen Sie `setup_host.py` aus. Das Skript akzeptiert verschiedene Argumente, u
|
|||||||
* `-b`, `--basename`: Der Basisname für die Container, falls die Vorlage `{basename}` enthält. (Standard: `vm`)
|
* `-b`, `--basename`: Der Basisname für die Container, falls die Vorlage `{basename}` enthält. (Standard: `vm`)
|
||||||
* `--no-port-forward`: Deaktiviert die SSH-Port-Weiterleitung.
|
* `--no-port-forward`: Deaktiviert die SSH-Port-Weiterleitung.
|
||||||
* `--port-start`: Der Start-Port für die SSH-Weiterleitung, falls diese aktiv ist. (Standard: `2201`)
|
* `--port-start`: Der Start-Port für die SSH-Weiterleitung, falls diese aktiv ist. (Standard: `2201`)
|
||||||
|
* `--ssh-pub-key-file`: Pfad zu einem öffentlichen SSH-Schlüssel, der für den Benutzer `jonnybravo` hinterlegt werden soll. (Standard: `~/.ssh/id_rsa.pub`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ def main():
|
|||||||
parser.add_argument("password", help="Das gewünschte root-Passwort.")
|
parser.add_argument("password", help="Das gewünschte root-Passwort.")
|
||||||
parser.add_argument("hostname", help="Der Hostname für diesen Container.")
|
parser.add_argument("hostname", help="Der Hostname für diesen Container.")
|
||||||
parser.add_argument("distro", help="Die Distribution des Containers (z.B. 'arch', 'ubuntu').")
|
parser.add_argument("distro", help="Die Distribution des Containers (z.B. 'arch', 'ubuntu').")
|
||||||
|
parser.add_argument("ssh_key", nargs='?', default="", help="Der öffentliche SSH-Schlüssel für den Benutzer 'jonnybravo'.")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
root_password = args.password
|
root_password = args.password
|
||||||
@@ -132,7 +133,18 @@ def main():
|
|||||||
wheel_group_equivalent = "wheel" if distro in ["arch", "fedora"] else "sudo"
|
wheel_group_equivalent = "wheel" if distro in ["arch", "fedora"] else "sudo"
|
||||||
run_command(f"useradd -m -G {config['user_groups']} -s /bin/bash jonnybravo", "Benutzer 'jonnybravo' hinzufügen")
|
run_command(f"useradd -m -G {config['user_groups']} -s /bin/bash jonnybravo", "Benutzer 'jonnybravo' hinzufügen")
|
||||||
run_command("passwd jonnybravo", "Passwort für jonnybravo setzen", input_str=password_input)
|
run_command("passwd jonnybravo", "Passwort für jonnybravo setzen", input_str=password_input)
|
||||||
|
|
||||||
|
# SSH-Schlüssel für jonnybravo einrichten
|
||||||
|
if args.ssh_key:
|
||||||
|
print("--- Richte SSH-Schlüssel für Benutzer 'jonnybravo' ein ---")
|
||||||
|
ssh_dir = "/home/jonnybravo/.ssh"
|
||||||
|
authorized_keys_file = os.path.join(ssh_dir, "authorized_keys")
|
||||||
|
run_command(f"mkdir -p {ssh_dir}", f"Erstelle Verzeichnis {ssh_dir}")
|
||||||
|
run_command(f"echo '{args.ssh_key}' > {authorized_keys_file}", f"Schreibe Schlüssel nach {authorized_keys_file}")
|
||||||
|
run_command(f"chown -R jonnybravo:jonnybravo {ssh_dir}", f"Setze Eigentümer für {ssh_dir}")
|
||||||
|
run_command(f"chmod 700 {ssh_dir}", f"Setze Berechtigungen für {ssh_dir}")
|
||||||
|
run_command(f"chmod 600 {authorized_keys_file}", f"Setze Berechtigungen für {authorized_keys_file}")
|
||||||
|
|
||||||
if wheel_group_equivalent == "wheel":
|
if wheel_group_equivalent == "wheel":
|
||||||
run_command("echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/wheel_nopasswd", "Passwortloses sudo für Gruppe 'wheel' aktivieren")
|
run_command("echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/wheel_nopasswd", "Passwortloses sudo für Gruppe 'wheel' aktivieren")
|
||||||
else: # sudo group
|
else: # sudo group
|
||||||
|
|||||||
162
setup_host.py
162
setup_host.py
@@ -1,12 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
# geschrieben vmit der Hilfe von Gemini2.5-pro
|
||||||
import subprocess
|
import subprocess
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
|
import pylxd
|
||||||
|
|
||||||
|
|
||||||
def run_command(command_str, description, ignore_errors=False):
|
def run_command(command_str, description, ignore_errors=False):
|
||||||
@@ -75,6 +76,9 @@ def get_container_ip(container_name):
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
os.environ['PYLXD_WARNINGS'] = 'none'
|
||||||
|
host_folder = "/home/jonnybravo/lxc_folder"
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="Erstellt und konfiguriert mehrere LXD-Container.")
|
description="Erstellt und konfiguriert mehrere LXD-Container.")
|
||||||
parser.add_argument("-c", "--count", type=int, default=1,
|
parser.add_argument("-c", "--count", type=int, default=1,
|
||||||
@@ -91,6 +95,8 @@ def main():
|
|||||||
help="Zu verwendendes Image (z.B. images:archlinux, ubuntu:22.04).")
|
help="Zu verwendendes Image (z.B. images:archlinux, ubuntu:22.04).")
|
||||||
parser.add_argument("--no-port-forward", action="store_true",
|
parser.add_argument("--no-port-forward", action="store_true",
|
||||||
help="Überspringt die Einrichtung der SSH-Port-Weiterleitung.")
|
help="Überspringt die Einrichtung der SSH-Port-Weiterleitung.")
|
||||||
|
parser.add_argument("--ssh-pub-key-file", default="~/.ssh/ansible-test.pub",
|
||||||
|
help="Pfad zur öffentlichen SSH-Schlüsseldatei, die für den Benutzer 'jonnybravo' autorisiert werden soll.")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.count > 1 and '{i}' not in args.hostname_template:
|
if args.count > 1 and '{i}' not in args.hostname_template:
|
||||||
@@ -99,15 +105,139 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
run_command("command -v lxc >/dev/null", "Prüfe, ob LXD installiert ist")
|
run_command("command -v lxc >/dev/null", "Prüfe, ob LXD installiert ist")
|
||||||
print("LXD ist verfügbar. WICHTIG: Es wird davon ausgegangen, dass 'lxd init' bereits ausgeführt wurde.")
|
|
||||||
|
|
||||||
|
client = pylxd.Client(project='default')
|
||||||
|
|
||||||
|
# Überprüfe, ob das Profil 'myprofile' existiert, und erstelle es, falls nicht
|
||||||
|
try:
|
||||||
|
client.profiles.get("myprofile")
|
||||||
|
print("\n--- Profil 'myprofile' existiert bereits. Aktualisiere es. ---")
|
||||||
|
profile = client.profiles.get("myprofile")
|
||||||
|
profile.config = {"security.nesting": "true",
|
||||||
|
"security.privileged": "true"}
|
||||||
|
profile.devices = {
|
||||||
|
"root": {
|
||||||
|
"path": "/",
|
||||||
|
"pool": "default",
|
||||||
|
"type": "disk",
|
||||||
|
},
|
||||||
|
"eth0": {
|
||||||
|
"name": "eth0",
|
||||||
|
"network": "lxdbr0",
|
||||||
|
"type": "nic",
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"path": "/public",
|
||||||
|
"source": host_folder,
|
||||||
|
"type": "disk",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profile.save()
|
||||||
|
except pylxd.exceptions.NotFound:
|
||||||
|
print("\n--- Profil 'myprofile' nicht gefunden. Erstelle es. ---")
|
||||||
|
profile_config = {"security.nesting": "true",
|
||||||
|
"security.privileged": "true"}
|
||||||
|
profile_devices = {
|
||||||
|
"root": {
|
||||||
|
"path": "/",
|
||||||
|
"pool": "default",
|
||||||
|
"type": "disk",
|
||||||
|
},
|
||||||
|
"eth0": {
|
||||||
|
"name": "eth0",
|
||||||
|
"network": "lxdbr0",
|
||||||
|
"type": "nic",
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"path": "/public",
|
||||||
|
"source": host_folder,
|
||||||
|
"type": "disk",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.profiles.create("myprofile", profile_config, profile_devices)
|
||||||
|
|
||||||
|
# Erstelle den Ordner auf dem Host, falls er nicht existiert
|
||||||
|
if not os.path.exists(host_folder):
|
||||||
|
print(f"--- Erstelle Host-Ordner: {host_folder} ---")
|
||||||
|
os.makedirs(host_folder)
|
||||||
|
else:
|
||||||
|
print(f"--- Host-Ordner {host_folder} existiert bereits. ---")
|
||||||
|
|
||||||
|
# Konfiguriere lxdbr0, falls nicht bereits geschehen
|
||||||
|
try:
|
||||||
|
run_command("lxc network show lxdbr0",
|
||||||
|
"Prüfe, ob lxdbr0 existiert", ignore_errors=True)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print("\n--- lxdbr0 nicht gefunden. Konfiguriere es. ---")
|
||||||
|
run_command("lxc network set lxdbr0 ipv4.address 10.0.4.1/24",
|
||||||
|
"Setze IPv4-Adresse für lxdbr0")
|
||||||
|
run_command("lxc network set lxdbr0 ipv4.nat true",
|
||||||
|
"Aktiviere IPv4-NAT für lxdbr0")
|
||||||
|
run_command("lxc network set lxdbr0 ipv6.address none",
|
||||||
|
"Deaktiviere IPv6 für lxdbr0")
|
||||||
|
else:
|
||||||
|
print("\n--- lxdbr0 existiert bereits. ---")
|
||||||
|
|
||||||
|
# Lese den öffentlichen SSH-Schlüssel
|
||||||
|
ssh_key_path = os.path.expanduser(args.ssh_pub_key_file)
|
||||||
|
ssh_key_content = ""
|
||||||
|
if os.path.exists(ssh_key_path):
|
||||||
|
with open(ssh_key_path, 'r') as f:
|
||||||
|
ssh_key_content = f.read().strip()
|
||||||
|
print(f"--- SSH-Schlüssel von {ssh_key_path} geladen. ---")
|
||||||
|
else:
|
||||||
|
print(f"--- WARNUNG: SSH-Schlüsseldatei nicht gefunden unter {
|
||||||
|
ssh_key_path}. Der Schlüssel wird nicht kopiert. ---")
|
||||||
|
|
||||||
|
# Importiere pylxd und initialisiere den Client
|
||||||
|
# client = pylxd.Client() # Dies sollte bereits oben geschehen sein
|
||||||
|
|
||||||
|
# Initialisiere LXD, falls nicht bereits geschehen
|
||||||
|
# try:
|
||||||
|
# client.api.get('/')
|
||||||
|
# print("\n--- LXD ist bereits initialisiert. ---")
|
||||||
|
# except pylxd.exceptions.ClientConnectionFailed:
|
||||||
|
# print("\n--- LXD ist nicht initialisiert. Initialisiere es. ---")
|
||||||
|
# run_command("lxd init --auto", "Initialisiere LXD")
|
||||||
|
|
||||||
|
# Erstelle den 'out'-Ordner, falls er nicht existiert
|
||||||
if not os.path.exists("out"):
|
if not os.path.exists("out"):
|
||||||
os.makedirs("out")
|
os.makedirs("out")
|
||||||
|
|
||||||
|
# Bereinige die CSV-Datei von alten Einträgen
|
||||||
|
csv_path = "out/clients.csv"
|
||||||
|
if os.path.exists(csv_path):
|
||||||
|
print(f"\n--- Bereinige {csv_path} von alten Einträgen ---")
|
||||||
|
try:
|
||||||
|
result = run_command("lxc list --format json",
|
||||||
|
"Frage alle Container ab", ignore_errors=True)
|
||||||
|
if result and result.returncode == 0:
|
||||||
|
existing_containers = {c['name']
|
||||||
|
for c in json.loads(result.stdout)}
|
||||||
|
valid_clients = []
|
||||||
|
with open(csv_path, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
if lines:
|
||||||
|
header = lines[0]
|
||||||
|
valid_clients.append(header)
|
||||||
|
for line in lines[1:]:
|
||||||
|
try:
|
||||||
|
name = line.strip().split(',')[0]
|
||||||
|
if name in existing_containers:
|
||||||
|
valid_clients.append(line)
|
||||||
|
except IndexError:
|
||||||
|
pass # Ignoriere leere oder fehlerhafte Zeilen
|
||||||
|
|
||||||
|
with open(csv_path, 'w') as f:
|
||||||
|
f.writelines(valid_clients)
|
||||||
|
print(f"--- {csv_path} erfolgreich bereinigt. ---")
|
||||||
|
except (json.JSONDecodeError, FileNotFoundError):
|
||||||
|
print(f"--- WARNUNG: Konnte {csv_path} nicht bereinigen. ---")
|
||||||
|
|
||||||
|
# Stelle sicher, dass die CSV-Datei existiert und einen Header hat
|
||||||
|
if not os.path.exists(csv_path) or os.path.getsize(csv_path) == 0:
|
||||||
with open(csv_path, "w") as f:
|
with open(csv_path, "w") as f:
|
||||||
f.write("name,ip\n")
|
f.write("name,ip\n")
|
||||||
elif not os.path.isdir("out"):
|
|
||||||
# os.remove("out")
|
|
||||||
os.makedirs("out")
|
|
||||||
|
|
||||||
clients = []
|
clients = []
|
||||||
|
|
||||||
@@ -117,10 +247,17 @@ def main():
|
|||||||
|
|
||||||
print(f"{'=' * 20} ERSTELLE CONTAINER: {vm_name} {'=' * 20}")
|
print(f"{'=' * 20} ERSTELLE CONTAINER: {vm_name} {'=' * 20}")
|
||||||
|
|
||||||
run_command(f"lxc delete {vm_name} --force",
|
try:
|
||||||
f"{vm_name} vorsorglich löschen", ignore_errors=True)
|
client.containers.get(vm_name)
|
||||||
|
print(
|
||||||
|
f"--- HINWEIS: Container '{vm_name}' existiert bereits und wird übersprungen. ---")
|
||||||
|
continue
|
||||||
|
except pylxd.exceptions.NotFound:
|
||||||
|
pass
|
||||||
|
|
||||||
run_command(f"lxc launch {args.image} {
|
run_command(f"lxc launch {args.image} {
|
||||||
vm_name}", f"Starte {vm_name} von Image")
|
vm_name} -p myprofile", f"Starte {vm_name} von Image mit myprofile")
|
||||||
|
|
||||||
wait_for_network(vm_name)
|
wait_for_network(vm_name)
|
||||||
|
|
||||||
distro_id_command = "lxc exec {} -- cat /etc/os-release | grep '^ID=' | cut -d'=' -f2"
|
distro_id_command = "lxc exec {} -- cat /etc/os-release | grep '^ID=' | cut -d'=' -f2"
|
||||||
@@ -130,11 +267,11 @@ def main():
|
|||||||
|
|
||||||
install_cmd = ""
|
install_cmd = ""
|
||||||
if distro_id == "arch":
|
if distro_id == "arch":
|
||||||
install_cmd = "pacman -Sy --noconfirm python"
|
install_cmd = "pacman -Sy --noconfirm python vim "
|
||||||
elif distro_id in ["ubuntu", "debian"]:
|
elif distro_id in ["ubuntu", "debian"]:
|
||||||
install_cmd = "sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get update && apt-get install -y python3'"
|
install_cmd = "sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get update && apt-get install -y python3 vim'"
|
||||||
elif distro_id == "fedora":
|
elif distro_id == "fedora":
|
||||||
install_cmd = "dnf install -y python3"
|
install_cmd = "dnf install -y python3 vim"
|
||||||
else:
|
else:
|
||||||
print(f"FEHLER: Nicht unterstützte Distribution: {
|
print(f"FEHLER: Nicht unterstützte Distribution: {
|
||||||
distro_id}", file=sys.stderr)
|
distro_id}", file=sys.stderr)
|
||||||
@@ -146,7 +283,7 @@ def main():
|
|||||||
run_command(f"lxc file push setup_container.py {
|
run_command(f"lxc file push setup_container.py {
|
||||||
vm_name}/root/", f"Kopiere Setup-Skript nach {vm_name}")
|
vm_name}/root/", f"Kopiere Setup-Skript nach {vm_name}")
|
||||||
run_command(f"lxc exec {vm_name} -- python3 /root/setup_container.py '{
|
run_command(f"lxc exec {vm_name} -- python3 /root/setup_container.py '{
|
||||||
args.root_password}' '{vm_name}' '{distro_id}'", f"Führe Konfiguration in {vm_name} aus")
|
args.root_password}' '{vm_name}' '{distro_id}' '{ssh_key_content}'", f"Führe Konfiguration in {vm_name} aus")
|
||||||
|
|
||||||
ssh_info = ""
|
ssh_info = ""
|
||||||
if not args.no_port_forward:
|
if not args.no_port_forward:
|
||||||
@@ -171,7 +308,6 @@ def main():
|
|||||||
if clients:
|
if clients:
|
||||||
csv_path = "out/clients.csv"
|
csv_path = "out/clients.csv"
|
||||||
with open(csv_path, "a") as f:
|
with open(csv_path, "a") as f:
|
||||||
# f.write("name,ip\n")
|
|
||||||
for client in clients:
|
for client in clients:
|
||||||
f.write(f"{client['name']},{client['ip']}\n")
|
f.write(f"{client['name']},{client['ip']}\n")
|
||||||
print(f"\nAlle Container wurden erstellt und in {
|
print(f"\nAlle Container wurden erstellt und in {
|
||||||
|
|||||||
Reference in New Issue
Block a user