Move functions into separate method

Moving all bash functions into a separate file. This avoids that the
main script gets executed when testing function, as now just this
new function file get be sourced.

Change-Id: Ia9219080790d92f671618ba4aef90e2b6bab78b3
This commit is contained in:
Andreas Scheuring 2017-02-28 20:19:35 +01:00
parent a6bee99ff0
commit dad341f2ff
4 changed files with 215 additions and 185 deletions

View File

@ -196,6 +196,8 @@ Add DPM-Guest Tools
cp nova-dpm/dpm_guest_tools/usr/lib/systemd/system/autoconfigure_networking.service /usr/lib/systemd/system/autoconfigure_networking.service
cp nova-dpm/dpm_guest_tools/usr/bin/dpm_guest_image_tools_common /usr/bin/
cp nova-dpm/dpm_guest_tools/usr/bin/setmac.sh /usr/bin/setmac.sh
cp nova-dpm/dpm_guest_tools/etc/udev/rules.d/80-setmac.rules /etc/udev/rules.d/80-setmac.rules

View File

@ -23,10 +23,14 @@
# Exit on error
set -e
source $(dirname "$0")/dpm_guest_image_tools_common
LOG_PREFIX=$(basename "$0")
REGEX_DEV_NO="[0-9A-Fa-f]{4}"
REGEX_MAC="[0-9A-Fa-f]{12}"
# This script usually gets called by systemd. Systemd takes care of writing
# stdout and stderr into the journal. Using "echo" here ensures, that
# all the messages show up under the corresponding systemd unit and not as
# separate entity.
LOG_TARGET="stdout"
# Regex to match
# <devno>,<port>;
@ -34,46 +38,7 @@ REGEX_MAC="[0-9A-Fa-f]{12}"
REGEX="($REGEX_DEV_NO),([0-1])(,$REGEX_MAC)?;"
#CMDLINE="some stuff 0001,1,000000000011;0004,;0007,0; more stuff"
CMDLINE=$(cat /proc/cmdline)
function log {
# $1 = message to log
# This script usually gets called by systemd. Systemd takes care of writing
# stdout and stderr into the journal. Using "echo" here ensures, that
# all the messages show up under the corresponding systemd unit.
echo "$LOG_PREFIX: $1"
}
function get_device_bus_id {
# $1 = the device number
# returns the corresponding device_bus_id
echo "0.0.$1"
}
function device_exists {
# $1 = the device bus id
local dev_bus_id="$1"
# Check if device is already configured
path="/sys/bus/ccwgroup/devices/$dev_bus_id"
if ! [ -d "$path" ]; then
return 1
fi
}
function configure_device {
# $1 = the device bus id
# $2 = the port no
local dev_bus_id="$1"
local port_no="$2"
# TODO(andreas_s): Do not depend on znetconf
# Errors of the following command are written to stderr, and therefore
# show up in the systemd units journal
znetconf -a $dev_bus_id -o portno=$port_no,layer2=1
return "$?"
}
CMDLINE=$(get_cmdline)
log "Start"

View File

@ -0,0 +1,205 @@
#! /bin/bash
# Copyright 2017 IBM Corp. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Allow caller to define a different folder for the root directory
ROOT_DIR=${ROOT_DIR:-}
# Allow caller to define a different LOG prefix
LOG_PREFIX=${LOG_PREFIX:-"DPM-guest-image-tools"}
# Allow caller to define a different LOG target
LOG_TARGET=${LOG_TARGET:-"syslog"}
# Matches MAC in format: xxxxxxxxxxxx
REGEX_MAC="[0-9A-Fa-f]{12}"
REGEX_DEV_NO="[0-9A-Fa-f]{4}"
REGEX_EXTRACT_DEVNO="qeth/0\.0\.($REGEX_DEV_NO)/net"
REGEX_EXTRACT_IFNAME="/net/(.{1,15})"
function log {
# $1 = message to log
local log_msg="$LOG_PREFIX: $1"
if [[ $LOG_TARGET == "syslog" ]]; then
logger $log_msg
elif [[ $LOG_TARGET == "stdout" ]]; then
echo $log_msg
else
# Logging disabled
:
fi
}
function extract_devno {
# Extracts the device number out of a device path
# $1 = the device path, e.g. "/devices/qeth/0.0.0001/net/enc1"
# Returns: device number, e.g. "0001"
local dev_path="$1"
if [[ $dev_path =~ $REGEX_EXTRACT_DEVNO ]]; then
echo "${BASH_REMATCH[1]}"
else
log "Could not extract devno from '$dev_path'. Skipping!"
exit 1
fi
}
function extract_interface_name {
# Extracts the interface name out of a device path
# $1 = the device path, e.g. "/devices/qeth/0.0.0001/net/enc1"
# Returns: interface name, e.g. "enc1"
local dev_path="$1"
if [[ $dev_path =~ $REGEX_EXTRACT_IFNAME ]]; then
echo "${BASH_REMATCH[1]}"
else
log "Could not find interface for device number '$devno' in path 'dev_path'. Skipping!"
exit 1
fi
}
function extract_mac {
# Get the mac address to a given device number from the cmdline
# $1 = the device number, e.g. "0001"
# $2 = the cmdline, e.g. "0001,0,aabbccddeeff;"
# Returns: The MAC address in format xx:xx:xx:xx:xx:xx
local devno="$1"
local cmdline="$2"
# Regex matches: <devno>,<port>,<mac>;
regex=${devno}",[0-1],("${REGEX_MAC}");"
if [[ $cmdline =~ $regex ]]; then
local mac_tmp="${BASH_REMATCH[1]}"
# Insert ':' into MAC again
echo ${mac_tmp:0:2}:${mac_tmp:2:2}:${mac_tmp:4:2}:${mac_tmp:6:2}:${mac_tmp:8:2}:${mac_tmp:10:2}
else
log "No MAC for devno '$devno' found in cmdline '$cmdline'. Exit."
exit 1
fi
}
function is_locally_administered_mac {
# Verifies if a MAC is a locally administered unicast MAC
# $1 = MAC, e.g. "00:11:22:33:44:55"
# Returns <nothing>
# rc 0 = True, rc 1 = False
local mac="$1"
# Only Unicast MACs that have the "locally administered" bit set are allowed
# by OSA. The "locally administered" bit is the "second least significant"
# bit of the most significant MAC byte. In addition only unicast addresses
# are allowed. The unicast bit is the least significant bit of the most
# significant byte.
# Example: AA:BB:CC:DD:EE:FF
# Most significant Byte: ^^
# In Binary: 1010 1010
# Second least significant bit: ^ = locally administered = 1
# Least significant bit: ^ = unicast = 0
# Therefore the only MACs are allowed, that have the 10 as those 2 bits.
# This results in the following possible MACs (where X can be any hex char):
# X2:XX:XX:XX:XX:XX
# X6:XX:XX:XX:XX:XX
# XA:XX:XX:XX:XX:XX
# XE:XX:XX:XX:XX:XX
local regex="^[0-9A-Fa-f][26AaEe]"
if [[ $mac =~ $regex ]]; then
return 0
else
return 1
fi
}
function get_ip_cmd {
# Determines the path of the ip cmd
# Returns: Path to ip cmd
# When this script is called from a udev rule, it is not able to find
# the ip command. Also the 'which' command is not working. As different
# distros install it to different locations, we need to try out which
# path is working.
local paths=("/usr/sbin/ip" "/sbin/ip")
for path in "${paths[@]}"; do
local full_path=$ROOT_DIR$path
if [[ -x $full_path ]]; then
echo "$full_path"
return 0
fi
done
log "'ip' command not found. Exiting."
exit 1
}
function set_mac {
# This function sets the given MAC on the given interface
# $1 = Interface name to set the mac on, e.g. "enc1"
# $2 = The mac address, e.g. "00:11:22:33:44:55"
local if_name="$1"
local mac="$2"
if ! is_locally_administered_mac "$mac" ; then
log "MAC $mac is not a locally administered MAC. Aborting!"
exit 1
fi
local ip_cmd=$(get_ip_cmd)
local cmd="$ip_cmd link set $if_name address $mac 2>&1 > /dev/null"
stderr=$(eval "$cmd")
local rc=$?
if [[ $rc != 0 ]]; then
log "Operation '$cmd' failed with exit rc '$rc': $stderr. Aborting!"
exit 1
fi
log "Successfully set MAC of interface '$if_name' to '$mac'"
}
function get_device_bus_id {
# $1 = the device number
# returns the corresponding device_bus_id
echo "0.0.$1"
}
function device_exists {
# $1 = the device bus id
local dev_bus_id="$1"
# Check if device is already configured
path="/sys/bus/ccwgroup/devices/$dev_bus_id"
if ! [ -d "$path" ]; then
return 1
fi
}
function configure_device {
# $1 = the device bus id
# $2 = the port no
local dev_bus_id="$1"
local port_no="$2"
# TODO(andreas_s): Do not depend on znetconf
# Errors of the following command are written to stderr, and therefore
# show up in the systemd units journal
znetconf -a $dev_bus_id -o portno=$port_no,layer2=1
return "$?"
}
function get_cmdline {
#Example: "some stuff nics=0001,0,aabbccddeeff;abcd,1,001122334455;"
echo $(cat /proc/cmdline)
}

View File

@ -23,152 +23,10 @@
# Exit on error
set -e
source $(dirname "$0")/dpm_guest_image_tools_common
# Matches MAC in format: xxxxxxxxxxxx
REGEX_MAC="[0-9A-Fa-f]{12}"
REGEX_EXTRACT_DEVNO="qeth/0\.0\.([0-9A-Fa-f]{4})/net"
REGEX_EXTRACT_IFNAME="/net/(.{1,15})"
LOG_PREFIX=$(basename "$0")
function log {
# $1 = message to log
# Logging to syslog
logger "$LOG_PREFIX: $1"
}
function extract_devno {
# Extracts the device number out of a device path
# $1 = the device path, e.g. "/devices/qeth/0.0.0001/net/enc1"
# Returns: device number, e.g. "0001"
local dev_path="$1"
if [[ $dev_path =~ $REGEX_EXTRACT_DEVNO ]]; then
echo "${BASH_REMATCH[1]}"
else
log "Could not extract devno from '$dev_path'. Skipping!"
exit 1
fi
}
function extract_interface_name {
# Extracts the interface name out of a device path
# $1 = the device path, e.g. "/devices/qeth/0.0.0001/net/enc1"
# Returns: interface name, e.g. "enc1"
local dev_path="$1"
if [[ $dev_path =~ $REGEX_EXTRACT_IFNAME ]]; then
echo "${BASH_REMATCH[1]}"
else
log "Could not find interface for device number '$devno' in path 'dev_path'. Skipping!"
exit 1
fi
}
function extract_mac {
# Get the mac address to a given device number from the cmdline
# $1 = the device number, e.g. "0001"
# $2 = the cmdline, e.g. "0001,0,aabbccddeeff;"
# Returns: The MAC address in format xx:xx:xx:xx:xx:xx
local devno="$1"
local cmdline="$2"
# Regex matches: <devno>,<port>,<mac>;
regex=${devno}",[0-1],("${REGEX_MAC}");"
if [[ $cmdline =~ $regex ]]; then
local mac_tmp="${BASH_REMATCH[1]}"
# Insert ':' into MAC again
echo ${mac_tmp:0:2}:${mac_tmp:2:2}:${mac_tmp:4:2}:${mac_tmp:6:2}:${mac_tmp:8:2}:${mac_tmp:10:2}
else
log "No MAC for devno '$devno' found in cmdline '$cmdline'. Exit."
exit 1
fi
}
function is_locally_administered_mac {
# Verifies if a MAC is a locally administered unicast MAC
# $1 = MAC, e.g. "00:11:22:33:44:55"
# Returns <nothing>
# rc 0 = True, rc 1 = False
local mac="$1"
# Only Unicast MACs that have the "locally administered" bit set are allowed
# by OSA. The "locally administered" bit is the "second least significant"
# bit of the most significant MAC byte. In addition only unicast addresses
# are allowed. The unicast bit is the least significant bit of the most
# significant byte.
# Example: AA:BB:CC:DD:EE:FF
# Most significant Byte: ^^
# In Binary: 1010 1010
# Second least significant bit: ^ = locally administered = 1
# Least significant bit: ^ = unicast = 0
# Therefore the only MACs are allowed, that have the 10 as those 2 bits.
# This results in the following possible MACs (where X can be any hex char):
# X2:XX:XX:XX:XX:XX
# X6:XX:XX:XX:XX:XX
# XA:XX:XX:XX:XX:XX
# XE:XX:XX:XX:XX:XX
local regex="^[0-9A-Fa-f][26AaEe]"
if [[ $mac =~ $regex ]]; then
return 0
else
return 1
fi
}
function get_ip_cmd {
# Determines the path of the ip cmd
# Returns: Path to ip cmd
# When this script is called from a udev rule, it is not able to find
# the ip command. Also the 'which' command is not working. As different
# distros install it to different locations, we need to try out which
# path is working.
local paths=("/usr/sbin/ip" "/sbin/ip")
for path in "${paths[@]}"; do
if [[ -x $path ]]; then
echo "$path"
return 0
fi
done
log "'ip' command not found. Exiting."
exit 1
}
function set_mac {
# This function sets the given MAC on the given interface
# $1 = Interface name to set the mac on, e.g. "enc1"
# $2 = The mac address, e.g. "00:11:22:33:44:55"
local if_name="$1"
local mac="$2"
if ! is_locally_administered_mac "$mac" ; then
log "MAC $mac is not a locally administered MAC. Aborting!"
exit 1
fi
local ip_cmd=$(get_ip_cmd)
local cmd="$ip_cmd link set $if_name address $mac 2>&1 > /dev/null"
stderr=$(eval "$cmd")
local rc=$?
if [[ $rc != 0 ]]; then
log "Operation '$cmd' failed with exit rc '$rc': $stderr. Aborting!"
exit 1
fi
log "Successfully set MAC of interface '$if_name' to '$mac'"
}
function get_cmdline {
#Example: "some stuff nics=0001,0,aabbccddeeff;abcd,1,001122334455;"
echo $(cat /proc/cmdline)
}
# e.g. /devices/qeth/0.0.0001/net/enc1
DEV_PATH="$1"
CMDLINE=$(get_cmdline)