Skip to content

Commit

Permalink
Add netplan config parding sh utility for ubuntu static ip
Browse files Browse the repository at this point in the history
Signed-off-by: yaacov <[email protected]>
  • Loading branch information
yaacov committed Sep 10, 2024
1 parent fa43dc5 commit c36f80e
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 6 deletions.
1 change: 1 addition & 0 deletions virt-v2v/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ go_library(
"scripts/rhel/firstboot/README.md",
"scripts/rhel/run/README.md",
"scripts/rhel/run/network_config_util.sh",
"scripts/rhel/run/netplan_config_util.sh",
"scripts/rhel/run/network_config_util_test",
],
importpath = "github.com/konveyor/forklift-controller/virt-v2v",
Expand Down
95 changes: 95 additions & 0 deletions virt-v2v/scripts/rhel/run/netplan_config_util.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/bash

# Function to extract the interface name and all valid IPv4 addresses from a block of text
parse_interface_block() {
block="$1"

# Regular expression for matching IPv4 and IPv6 addresses
ip_regex="([0-9]{1,3}\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?"

# Extract the interface name (first word before ":") and take only the first match
interface_name=$(echo "$block" | grep -Eo '^[^:]+' | head -n 1)

# Find and capture all IP addresses matching the regex in the block
ip_addresses=$(echo "$block" | grep -Eo "$ip_regex" | tr '\n' ' ')

# Return the interface name and concatenated IP addresses
echo "${interface_name}: ${ip_addresses}"
}

# Function to parse the netplan file
parse_netplan_file() {
netplan_file="$1"

# Initialize variables
found_ethernets=0
interface_indent=""
current_block=""
interfaces_list=""

# Read the file line by line
while IFS= read -r line; do
# Check if the current line contains "ethernets:"
if [ "$found_ethernets" -eq 0 ] && echo "$line" | grep -q '^[[:space:]]*ethernets:'; then
found_ethernets=1
continue
fi

# Once "ethernets:" is found, determine the indentation of the interface block
if [ "$found_ethernets" -eq 1 ] && [ -n "$line" ]; then
interface_indent=$(echo "$line" | sed -e 's/^\([[:space:]]*\).*/\1/' | wc -c)
found_ethernets=2
fi

# If we are inside the "ethernets" section, capture each interface block
if [ "$found_ethernets" -eq 2 ]; then
current_indent=$(echo "$line" | sed -e 's/^\([[:space:]]*\).*/\1/' | wc -c)

# If a new interface is found (same indentation as the interface level)
if [ "$current_indent" -eq "$interface_indent" ]; then
# Parse the previous block and add it to the list
if [ -n "$current_block" ]; then
interfaces_list="$interfaces_list$(parse_interface_block "$current_block") \n"
fi

# Start a new interface block
current_block="$line"
else
current_block="$current_block\n$line"
fi

# Stop capturing when encountering a line with less indentation than "interface_indent"
if [ "$current_indent" -lt "$interface_indent" ] && [ -n "$line" ]; then
found_ethernets=0
fi
fi
done < "$netplan_file"

# Parse and add the last interface block
if [ -n "$current_block" ]; then
interfaces_list="$interfaces_list$(parse_interface_block "$current_block") \n"
fi

# Output the parsed interfaces with their IP addresses
printf "$interfaces_list"
}

# Function to parse all YAML files in a directory using parse_netplan_file
parse_netplan_dir() {
dir="$1"
result=""

# Iterate over all YAML files in the directory
for yaml_file in "$dir"/*.yaml; do
if [ -f "$yaml_file" ]; then
# Concatenate the output of parse_netplan_file for each YAML file
result=$(printf "%s\n%s" "$result" "$(parse_netplan_file "$yaml_file")")
fi
done

# Return the concatenated result
echo "$result"
}

# Call the function to parse the netplan files
parse_netplan_dir "$NETPLAN_DIR"
43 changes: 42 additions & 1 deletion virt-v2v/scripts/rhel/run/network_config_util.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#!/bin/bash

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

# Global variables with default values
V2V_MAP_FILE="${V2V_MAP_FILE:-/tmp/macToIP}"
NETWORK_SCRIPTS_DIR="${NETWORK_SCRIPTS_DIR:-/etc/sysconfig/network-scripts}"
NETWORK_CONNECTIONS_DIR="${NETWORK_CONNECTIONS_DIR:-/etc/NetworkManager/system-connections}"
UDEV_RULES_FILE="${UDEV_RULES_FILE:-/etc/udev/rules.d/70-persistent-net.rules}"
NETPLAN_DIR="${NETPLAN_DIR:-/etc/netplan}"

# Source the netplan helper functions
. ${SCRIPT_DIR}/netplan_config_util.sh

# Dump debug strings into a new file descriptor and redirect it to stdout.
exec 3>&1
Expand All @@ -26,7 +32,7 @@ fi

# Clean strigs in case they have quates
remove_quotes() {
echo "$1" | tr -d '"'
echo "$1" | tr -d '"' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
}

# Validate MAC address and IPv4 address and extract them
Expand Down Expand Up @@ -107,6 +113,40 @@ udev_from_nm() {
done < "$V2V_MAP_FILE"
}

# Create udev rules based on the macToIP mapping + output from parse_netplan_file
udev_from_netplan() {
# Check if netplan config directory exists
if [ ! -d "$NETPLAN_DIR" ]; then
log "Warning: Directory $NETPLAN_DIR does not exist."
return 0
fi

# Parse the netplan configuration and store interface to IP mappings
netplan_output=$(parse_netplan_dir "$NETPLAN_DIR")

# Read the mapping file line by line
while IFS= read -r line; do
# Extract S_HW and S_IP from the current line in the mapping file
extract_mac_ip "$line"

# If S_HW and S_IP were not extracted, skip the line
if [ -z "$S_HW" ] || [ -z "$S_IP" ]; then
continue
fi

# Search the parsed netplan output for a matching IP address
interface_name=$(echo "$netplan_output" | grep -w "$S_IP" | cut -d ':' -f 1)

# If no interface is found, skip this entry
if [ -z "$interface_name" ]; then
continue
fi

# Create the udev rule based on the extracted MAC address and interface name
echo "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"$(remove_quotes "$S_HW")\",NAME=\"$(remove_quotes "$interface_name")\""
done < "$V2V_MAP_FILE"
}

# Checks for duplicate hardware addresses
check_dupe_hws() {
input=$(cat)
Expand All @@ -128,6 +168,7 @@ main() {
{
udev_from_ifcfg
udev_from_nm
udev_from_netplan
} | check_dupe_hws > "$UDEV_RULES_FILE" 2>/dev/null
}

Expand Down
58 changes: 53 additions & 5 deletions virt-v2v/scripts/rhel/run/network_config_util_test
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ export V2V_MAP_FILE="$TEST_DIR/macToIP"
export NETWORK_SCRIPTS_DIR="$TEST_DIR/network-scripts"
export NETWORK_CONNECTIONS_DIR="$TEST_DIR/system-connections"
export UDEV_RULES_FILE="$TEST_DIR/70-persistent-net.rules"
export NETPLAN_DIR="$TEST_DIR/netplan"

# Test systems using network-scripts
# ----------------------------------

# Clean up from previous runs
rm -f "$UDEV_RULES_FILE"
rm -rf "$NETWORK_SCRIPTS_DIR" "$NETWORK_CONNECTIONS_DIR"
rm -rf "$NETWORK_SCRIPTS_DIR" "$NETWORK_CONNECTIONS_DIR" "$NETPLAN_DIR"
mkdir -p "$NETWORK_SCRIPTS_DIR"

# Create mock data
Expand Down Expand Up @@ -52,16 +53,13 @@ fi

# Clean up from previous runs
rm -f "$UDEV_RULES_FILE"
rm -rf "$NETWORK_SCRIPTS_DIR" "$NETWORK_CONNECTIONS_DIR"
rm -rf "$NETWORK_SCRIPTS_DIR" "$NETWORK_CONNECTIONS_DIR" "$NETPLAN_DIR"
mkdir -p "$NETWORK_CONNECTIONS_DIR"

# Create mock data
printf "aa:bb:cc:dd:ee:ff:ip:192.168.1.10,things,more\naa:bb:cc:dd:ee:fe:ip:192.168.1.11,hello,world\naa:bb:cc:dd:ee:fd:ip:2001:0db8:85a3:0000:0000:8a2e:0370:7334\n" > "$V2V_MAP_FILE"
printf "[connection]\ninterface-name=eth3\naddress1=192.168.1.11/24\n" > "$NETWORK_CONNECTIONS_DIR/eth1 but with spaces.nmconnection"

# Source the script under test
. ${SCRIPT_DIR}/network_config_util.sh

# Run the script
main

Expand All @@ -83,6 +81,56 @@ if ! echo "$EXPECTED_RULE" | cmp -s - "$UDEV_RULES_FILE"; then
exit 1
fi

# Test systems using netplan YAML
# -------------------------------

NETPLAN_FILE="$NETPLAN_DIR/50-netplan.yaml"

# Clean up from previous runs
rm -f "$UDEV_RULES_FILE"
rm -rf "$NETWORK_SCRIPTS_DIR" "$NETWORK_CONNECTIONS_DIR" "$NETPLAN_DIR"
mkdir -p "$NETPLAN_DIR"

# Create mock data for netplan YAML test
cat <<EOL > "$NETPLAN_FILE"
network:
version: 2
ethernets:
eth0:
dhcp4: true
eth1:
dhcp4: false
addresses:
- 192.168.1.11/24
enp3s0:
addresses:
- 192.168.1.12/24
EOL

# Create mock mapping file
printf "aa:bb:cc:dd:ee:ff:ip:192.168.1.10,things,more\naa:bb:cc:dd:ee:fe:ip:192.168.1.11,hello,world\naa:bb:cc:dd:ee:fd:ip:192.168.1.12,ipv6,support\n" > "$V2V_MAP_FILE"

# Run the script
main

printf "\nTest netplan output:\n"
echo "FILE_START"
cat $UDEV_RULES_FILE
echo "FILE_END"

# Test 1: Verify the udev rules file was created
if [ ! -f "$UDEV_RULES_FILE" ]; then
echo "Test 1 Failed: UDEV_RULES_FILE not created."
exit 1
fi

# Test 3: Verify the content of the udev rules file
EXPECTED_RULE="SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"aa:bb:cc:dd:ee:fe\",NAME=\"eth1\"\nSUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"aa:bb:cc:dd:ee:fd\",NAME=\"enp3s0\""
if ! echo "$EXPECTED_RULE" | cmp -s - "$UDEV_RULES_FILE"; then
echo "Test 2 Failed: The content of $UDEV_RULES_FILE does not match the expected rule."
exit 1
fi

# -----------------------

printf "\nAll tests passed successfully.\n"
Expand Down

0 comments on commit c36f80e

Please sign in to comment.