Vorweg einmal kurz in einen Blick in eine typische Netzwerk-Konfigurationsdatei unter Linux:
network:
version: 2
renderer: NetworkManager
ethernets:
eno1:
dhcp4: false
addresses:
- 192.168.111.112/27
nameservers:
addresses:
- 192.168.111.1
routes:
- to: default
via: 192.168.111.1
Und mal dieselbe Netzwerk Konfiguration mal anders:
auto eno1
iface eno1 inet static
address 192.168.111.112/27
nameserver 192.168.111.1
gateway 192.168.111.1
Diese beiden Konfiguration tun im Endeffekt dasselbe. Das Problem: Die erste ist für netplan, die zweite für Ifupdown2. Allein aus Gründen der Effizienz kommt da die Frage auf: Warum nicht einfach ifupdown2 verwenden? Tja, wenn es so einfach wäre….
Die beiden haben andere Anwendungsgebiete. Während ifupdown2 bei Bare-Metal-Systemen allmählich zum Standard wird, ist Netplan bei Cloud Projekten und vor allem bei Kubernetes-Clustern im Einsatz. Da ein Docker-Container eh immer mit einer .yaml-Datei in ein K8s-Cluster eingebunden wird, bot sich da an, auch die Netzwerk-Konfiguration gleich mit in den .yaml-Datei zu schreiben. So entstand Netplan.
Jetzt möchte ich aber eine Proxmox Umgebung (meist auf Bare-Metal) in ein bestehendes Cluster einbetten, das Cluster verfügt aber über mehrere Netze und diese sind auch in einer Netplan-Datei verankert. Da dieses Netzwerk sich aber über mehrere Netzwerke erstreckt, ist die Datei dann nicht mehr ganz so simpel wie das oben genannte Beispiel, sondern sieht dann eher so aus:
network:
version: 2
renderer: networkd
ethernets:
eno1:
dhcp4: no
dhcp6: no
bridges:
br1:
dhcp4: no
dhcp6: no
interfaces: [ eno1 ]
addresses: [ 10.17.132.22/25 ]
routes:
- to: default
via: 10.17.132.1
nameservers:
addresses:
- "10.17.132.1"
br1001:
dhcp4: no
dhcp6: no
interfaces: [ vlan1001 ]
br1002:
dhcp4: no
dhcp6: no
interfaces: [ vlan1002 ]
br1003:
dhcp4: no
dhcp6: no
interfaces: [ vlan1003 ]
br1004:
dhcp4: no
dhcp6: no
interfaces: [ vlan1004 ]
br1101:
dhcp4: no
dhcp6: no
interfaces: [ vlan1101 ]
br1102:
dhcp4: no
dhcp6: no
interfaces: [ vlan102 ]
link-local: [ ipv6 ]
accept-ra: false
br1201:
dhcp4: no
dhcp6: no
interfaces: [ vlan81 ]
vlans:
vlan1001:
id: 1001
link: eno1
dhcp4: no
dhcp6: no
vlan1002:
id: 1002
link: eno1
dhcp4: no
dhcp6: no
vlan1003:
id: 1003
link: eno1
dhcp4: no
dhcp6: no
vlan1004:
id: 1004
link: eno1
dhcp4: no
dhcp6: no
vlan1101:
id: 1101
link: eno1
dhcp4: no
dhcp6: no
vlan102:
id: 102
link: eno1
dhcp4: no
dhcp6: no
link-local: [ ipv6, ipv4 ]
accept-ra: true
vlan1201:
id: 81
link: eno1
dhcp4: no
dhcp6: no
Das wird mal ein wenig komplexer. Und bevor ich jetzt alles aus dieser Datei in eine ifupdown2 übertrage, mache ich das ganze doch besser via Script, weil vertippen tue ich mich zwischenzeitlich vermutlich eh.
Nun kommt die erste Hürde: bash (die Kommando Zeile von Linux) kann eine .yaml-Datei nicht einfach so parsen, um dies zu tun, braucht man eine python3-Erweiterung namens ’niet‘. Aber nachdem dies geklärt ist, könnte ich mich jetzt hinsetzen und das Script selber runterschreiben, oder ich könnte ein KI-Modul zum Skripten in mein LocalAi laden und das Modul das Script für mich schreiben lassen. Nach dem Testen mehrerer Module ist dies das Beste, was ich bekommen habe:
To create an ifupdown2 configuration file using the niet Python library, you first need to install the niet library. If you haven’t already, you can install it using pip:
pip install niet
Next, you need to write a script that uses niet to generate the ifupdown2 configuration file. ifupdown2 uses a different configuration format, so you’ll need to convert your netplan configuration to ifupdown2 syntax.
Here’s a bash script that performs this conversion:
#!/bin/bash
# Function to convert netplan to ifupdown2
convert_netplan_to_ifupdown2() {
local netplan_file="$1"
local ifupdown2_file="$2"
# Read netplan file
local netplan
netplan=$(cat "$netplan_file")
# Extract interfaces and their configurations
local interfaces=$(echo "$netplan" | jq -r '.network.ethernets + .network.bridges + .network.vlans | .[] | .id')
# Create ifupdown2 configuration
local ifupdown2_content=""
for interface in $interfaces; do
local interface_config=$(echo "$netplan" | jq -r --arg interface "$interface" '.network | select (.ethernets[$interface] or .bridges[$interface] or .vlans[$interface]) | .ethernets[$interface] or .bridges[$interface] or .vlans[$interface]')
local address=$(echo "$interface_config" | jq -r '.addresses[0]')
local gateway=$(echo "$interface_config" | jq -r '.routes[] | select(.to == "default") | .via')
local nameservers=$(echo "$interface_config" | jq -r '.nameservers.addresses[0]')
# Convert to ifupdown2 syntax
local ifupdown2_entry="auto $interface"
ifupdown2_entry+="\niface $interface inet static"
ifupdown2_entry+="\n address $address"
ifupdown2_entry+="\n gateway $gateway"
ifupdown2_entry+="\n dns-nameservers $nameservers"
# Add to ifupdown2 content
ifupdown2_content+="$ifupdown2_entry\n"
done
# Write ifupdown2 configuration to file
echo "$ifupdown2_content" > "$ifupdown2_file"
}
# Main script execution
if [ -n "$1" ] && [ -n "$2" ]; then
convert_netplan_to_ifupdown2 "$1" "$2"
echo "ifupdown2 configuration created at $2"
else
echo "Usage: $0 <netplan_file> <ifupdown2_file>"
exit 1
fi
Explanation:
Function convert_netplan_to_ifupdown2: Reads the netplan configuration file. Extracts the list of interfaces. Converts each interface's configuration to ifupdown2 syntax. Writes the ifupdown2 configuration to the specified output file. Main Script Execution: Checks if the script is called with the correct number of arguments. Calls the function with the provided input and output file paths.
Usage:
Save the script to a file, for example, convert_netplan.sh, give it execution permissions, and run it:
chmod +x convert_netplan.sh ./convert_netplan.sh input_netplan.yaml output_ifupdown2.conf
This will generate an ifupdown2 configuration file from your netplan configuration. Adjust the script as needed to handle more specific configurations or to convert additional types of network configurations.
Das sieht auch alles ganz lustig aus, bis man sich die Befehle mal näher ansieht: Das Script nutzt nicht „niet“, obwohl es den Installationsvorgang noch beschreibt und einen dazu auffordert, die python Bibliothek zu installieren. Es nutzt „jq“, was, wenn man es sich genau anschaut, dafür gebaut ist, eine .json-Datei zu parsen. Nun, eine .yaml und und ein .json Datei sind schon ähnlich, aber leider nicht dasselbe. Sprich, das funktioniert nicht.
Den nächsten Fehler, den das Script begeht, ist die gesamte .yaml-Datei erstmal mit cat zu parsen und in der der Variable netplan zu speichern, um mit dieser weiter zu arbeiten. Was so auch nicht funktioniert, da Formatierungen aufgehoben werden, welche in einer .yaml-Datei allerdings essentiell sind. Also, ja, ich kann die Datei zu einer Variable innerhalb des Scriptes machen. Aber die Datei an sich sollte nicht mit bash-Boardmitteln geparst werden, wenn dies ginge, bräuchte ich auch die python3-Bibliothek nicht!!
Vorweg könnte man mit echo noch die Frage nach der Datei ausgeben. Entweder in demselben Verzeichnis oder mit absolutem Pfad, dann müssen sich Script und Datei nicht in demselben Ordner befinden.
Das, was danach gemacht werden sollte, ist die Bezeichnung des oder der Standard-Ethernetports herauszufinden:
PS3='Bitte nennen Sie die Bezeichnung für ihre Netzwerkkarte: '
options=("eth" "enp0s1 (o.ä)" "eno" "Quit")
select opt in "${options[@]}"
do
case $opt in
"eth")
eName="eth"
echo "Die Bezeichnung für ihre Netzwerkkarte beginnt mit eth"
break
;;
"enp0s1 (o.ä)")
eName="enp"
echo "Die Bezeichnung für ihre Netzwerkkarte beginnt mit enp"
break
;;
"eno")
eName="eno"
echo "Die Bezeichnung für ihre Netzwerkkarte beginnt mit eno"
break
;;
"Quit")
exit 1
break
;;
*) echo "ungültige Option, bitte nochmal";;
esac
done
eth, eno und enp werden genommen. swp ist noch nicht integriert, kann man aber als Option schnell intergrieren.
Anschließend werden die Interfaces, Bridges und VLANs gesammelt:
(Hier das Beispiel für Bridges:)
nrOfBridges=`niet ".network.bridges" $netplan | grep br* | wc -l`
declare -a bridges=()
for (( c = 1; c <= $nrOfBridges; c++ ))
do
bridges+=(`niet ".network.bridges" $netplan | grep br* | sed -n "$c"p`)
done
Man sollte hier dabei daran denken, dass das die erste Variable in einem Array mit [0] adressiert wird, d.h. das die erste Bridge also bridges[0] ist.
Als nächstes zieht man sich die relevanten Informationen aus den Unterpunkten der .yaml-Datei
(Wieder anhand der Bridges:)
for (( i = 1; i <= 1; i++ ))
do
j=$i-1
bridgeWrong=${bridges[$j]}
bridgeNow=(`echo "$bridgeWrong" | tr -d :`)
interface=(`niet ".network.bridges."$bridgeNow".interfaces" $netplan`)
dhcpV4=(`niet ".network.bridges."$bridgeNow".dhcp4" $netplan`)
dhcpV6=(`niet ".network.bridges."$bridgeNow".dhcp6" $netplan`)
ipV4=(`niet ".network.bridges."$bridgeNow".addresses" $netplan | cut -d'/' -f1`)
ipV4Netmask=(`niet ".network.bridges."$bridgeNow".addresses" $netplan | cut -d'/' -f2-`)
defaultRoute=("`niet ".network.bridges."$bridgeNow".routes" $netplan`")
dRoute1=(`echo "$defaultRoute" | tr -d ' ' | tr -d "'" | cut -d',' -f1 | cut -d':' -f2-`)
dRoute2=(`echo "$defaultRoute" | tr -d ' ' | tr -d "'" | cut -d',' -f2- | cut -d':' -f2- | cut -d'}' -f1`)
nameserver=(`niet ".network.bridges."$bridgeNow".nameservers.addresses" $netplan`)
linkLocal=(`niet ".network.bridges."$bridgeNow"" $netplan | niet "link-local"`)
acceptRA=(`niet ".network.bridges."$bridgeNow"" $netplan | niet "accept-ra"`)
done
Was man nun mit den relevanten Informationen macht, muss man schauen. Muss das in ifupdown2 eigentlich noch deklariert werden, oder kann das ignoriert werden.
Sollten die Infos allerdings benötigt werden, direkt schreiben. Da hilft das Ki- generierte Script oben dann wieder.
Aber als Fazit muss ich sagen:
Habe ich dieses Problem häufig (also mindestens im zweistelligen Bereich) würde sich ein Script mit Sicherheit lohnen. Ansonsten würde ich das nach wie vor per Hand machen. Sollten die KI Modelle allerdings irgendwann besser werden, könnte man auch darüber nachdenken, das übernehmen zu lassen.
Neueste Kommentare