Premier Training & Business Partner Red Hat

Conadd, uno script interattivo per Network Manager[:en]Conadd, an interactive script for Network Manager

EXTRAORDY
Ti piacerebbe diventare anche tu uno di noi e
pubblicare i tuoi articoli nel blog degli RHCE italiani?

Abbiamo già parlato in un primo articolo della gestione di Network Manager tramite nmcli su Red Hat Enterprise Linux e CentOS affrontando gli aspetti basilari della gestione. Per rendere alcune operazioni di routine più veloci e snelle vi proponiamo questo script che automatizza la creazione di connessioni ethernet, bridge e team con Network Manager proponendo all’utente una semplice interfaccia testuale e interattiva che cerca di rendere il controllo dei dati immessi il più possibile error-proof prima di passare i parametri al comando nmcli.

Oltre alle connessioni Ethernet anche le connessioni bridge e team sono finalmente gestite da Network Manager in modo effficiente e snello mentre in passato era necessario agire con dei workaround (vedi ad esempio le connessioni bridge). Questo ci permette di scriptare certe operazioni in modo più agevole e sintatticamente simile all’approccio usato per le connessioni Ethernet.

 

Si consiglia di copiare lo script nella directory /usr/bin. Per l’esecuzione è sufficiente eseguire il comando

/usr/bin/conadd

Alla prima esecuzione ci si presenterà questa schermata con la richiesta di scegliere il tipo di connessione da creare:

conadd01

 

Il seguente screenshot descrive tutti i passi della creazione di una connessione Ethernet statica:

conadd_ethernet

 

Lo screenshot successivo ci mostra invece la configurazione di una connessione team con indirizzo ip dinamico e due slave interface in configurazione activebackup:

conadd_team

 

Infine uno screenshot di una configurazione bridge, sempre con IP dinamico e due bridge slaves.

conadd_bridge

 

Come si può vedere in tutti i casi conadd raccoglie tutte le informazioni necessarie prima di passare i parametri a nmcli e stampa sempre un breve configuration summary prima di procedere. Il funzionamento di conadd è molto simile nmcli quando viene eseguito con il parametro -a[sk] ma con alcune piccole differenze (possibilità di aggiungere gateway, dns) e un maggior controllo sulla validità dell’input dell’utente.

 

Arriviamo ora a passare in rassegna lo script completo per poi focalizzare l’attenzione su alcune delle sezioni più importanti.

#!/bin/bash
 
#*******************************************************#
#                                                       #
#     conadd - Interactive network connections tool     #
#     Release: 0.2.1                                    #
#                                                       #
#*******************************************************#
 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
RELEASE="0.2.1"
 
# Test if the user has root privileges
if [ $UID -ne 0 ]; then
  echo "Error: conadd must be used as root"
  exit 1
fi
 
if [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
  echo "conadd - Interactive network connections management tool."
  echo "This script helps the user to add new IPv4 ethernet connections using Network Manager interactively."
  echo "It is similar to "nmcli -a con add" but brings some different feature like ip address format check" 
  echo "Usage: $(basename $0)"
  exit 0
elif [ "$1" == "-v" ] || [ "$1" == "--version" ]; then
  echo "conadd - Interactive network connections management tool."
  echo "Version $RELEASE"
  exit 0
fi
 
 
#*****************************************************************************#
 
# Functions definition
 
connTypeDef () {
  CONN_TYPE=
  TYPE_LIST="ethernet bridge team"
  while [ -z "$CONN_TYPE" ]; do
    echo -n "Connection type: (available types: "
    echo -n $TYPE_LIST
    echo ")"
    echo -n "> "
    read CONN_TYPE
 
    # Check if $CONN_TYPE is zero lenght
    if [ -z "$CONN_TYPE" ]; then
      echo "Must specify a connection type"
      echo
    else
      # Check if the interface exists
      for type_chk in $TYPE_LIST; do
        if [ "$CONN_TYPE" == "$type_chk" ]; then
          TYPE_OK=1
        fi
      done
 
      if [ "$TYPE_OK" != "1" ]; then
        echo "The type specified does not exist"
        echo "Choose a type among this list: $TYPE_LIST"
        CONN_TYPE=
      fi
    fi
  done
}
 
connDef () {
  CONN_NAME=
  while [ -z "$CONN_NAME" ]; do
    echo "Connection name:"
    echo -n "> "
    read CONN_NAME
 
    # Check if $CONN_NAME is zero lenght
    if [ -z "$CONN_NAME" ]; then
      echo "Connection name cannot be blank"
      echo
    else
    # Check if the connection name already exists
    CONN_LIST=$(nmcli con | sed '1d' | awk '{print $1}')
    for conn_chk in $CONN_LIST; do
      if [ "$conn_chk" == "$CONN_NAME" ]; then
        echo "Connection name already exists"
        echo
        CONN_NAME=
      fi
    done
    fi
  done
}
 
# Hardware interface (not used with bond, team, bridge)
hwIfaceDef () {
  IFACE=
  IF_OK=0
  IFACE_LIST=$(nmcli dev | sed '1d' | awk '{print $1}')
  while [ -z "$IFACE" ]; do
    echo -n "Network interface name: (available interfaces: "
    echo -n $IFACE_LIST
    echo ")"
    echo -n "> "
    read IFACE
 
    # Check if $IFACE is zero lenght
    if [ -z "$IFACE" ]; then
      echo "Network interface name cannot be blank"
      echo
    else
      # Check if the interface exists
      for ifname_chk in $IFACE_LIST; do
        if [ "$IFACE" == "$ifname_chk" ]; then
          IF_OK=1
        fi
      done
 
      if [ $IF_OK -ne 1 ]; then
        echo "Network interface does not exist"
        echo "Choose and interface among this list: $IFACE_LIST"
        IFACE=
      fi
    fi
  done
}
 
# Bonded interface (used with bonded connecions like team and bridge)
bdIfaceDef () {
  IFACE=
  IF_OK=0
  while [ -z "$IFACE" ]; do
    echo "Network interface name: "
    echo -n "> "
    read IFACE
 
    # Check if $IFACE is zero lenght
    if [ -z "$IFACE" ]; then
      echo "Network interface name cannot be blank"
      echo
    else
      # Check if the interface name equals to the connection name
      # This means that $CONN_NAME must be set before invoking this function
      if [ "$IFACE" == "$CONN_NAME" ]; then
        IF_OK=1
      fi
 
      if [ $IF_OK -ne 1 ]; then
        echo "The interface name should have the value $CONN_NAME"
        IFACE=
      fi
    fi
  done
}
 
 
# Slave interfaces for bridge and team connections
slIfaceDef () {
  echo "Please enter the number of slave interfaces"
  echo -n ">  "
  read SLAVE
  for NUM in $(seq 0 $(($SLAVE-1))); do
    eval echo IFACE_$NUM= &> /dev/null
    varRef=IFACE_$NUM
    IF_OK=0
    IFACE_LIST=$(nmcli dev | sed '1d' | awk '{print $1}')
    while [ -z "${!varRef}" ]; do
      echo -n "Slave interface $NUM name: (available interfaces: "
      echo -n $IFACE_LIST
      echo ")"
      echo -n "> "
      read IFACE_$NUM
 
      # Check if $IFACE_$NUM is zero lenght
      if [ -z "${varRef}" ]; then
        echo "Network interface name cannot be blank"
        echo
      else
        # Check if the interface exists
        for ifname_chk in $IFACE_LIST; do
          if [ "${!varRef}" == "$ifname_chk" ]; then
            IF_OK=1
          fi
        done
 
        if [ $IF_OK -ne 1 ]; then
          echo "Network interface does not exist"
          eval echo IFACE_$NUM= &> /dev/null
        fi
      fi
    done
 
    # Slave port name input. 
    eval echo SLNAME_$NUM= &> /dev/null
    portRef=SLNAME_$NUM		
    while [ -z "${!portRef}" ]; do
      echo "Slave port name: "
      echo -n "> "
      read SLNAME_$NUM
      if [ -z "${!portRef}" ]; then		# Check if SLNAME_$NUM is blank
        echo "Slave port name cannot be blank"
      fi
    done
  done
}
 
teamConfig () {
  RUNNER=
  RUN_OK=0
  RUNNER_LIST="roundrobin activebackup loadbalance"
  while [ -z "$RUNNER" ]; do
    echo "Team connection runner: (available runners: $RUNNER_LIST)"
    echo "Just press enter to leave "roundrobin" as the default runner"
    echo -n "> "
    read RUNNER
    if [ -z "$RUNNER" ]; then
      echo "Assuming roundrobin as default"
      RUNNER="roundrobin"
    else
      for runnerChk in $RUNNER_LIST; do
        if [ "$RUNNER" == "$runnerChk" ]; then
          RUN_OK=1
        fi
      done
      if [ $RUN_OK != 1 ]; then
        echo "Unsupported runner config"
        RUNNER=
      fi
    fi
 
  done
  case $RUNNER in
    activebackup) RUNNER_STR="{"runner": {"name": "activebackup"}}";;
    roundrobin) RUNNER_STR="{"runner": {"name": "roundrobin"}}";;
    loadbalance) RUNNER_STR="{"runner": {"name": "loadbalance"}}";;
  esac    
}
 
ip4AddrDef () {
  IP_ADDR=
  while [ -z "$IP_ADDR" ]; do
    echo "IPv4 address + Network prefix (leave blank for dhcp):"
    echo -n "> "
    read IP_ADDR
 
    # Check if ip address has a valid format
    if [ -n "$IP_ADDR" ]; then
      echo "$IP_ADDR" | grep '[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*/[0-9]*' &> /dev/null
      if [ $? -ne 0 ]; then
        echo "Invalid IPv4 address. Format: xxx.xxx.xxx.xxx/yy"
        echo
        IP_ADDR=
      fi
    else
      IP_ADDR="__dhcp__"
    fi
  done
 
  # If static ip address is set, collects default gateway and dns address
  if [ "$IP_ADDR" != "__dhcp__" ]; then
 
   # Default Gateway
   GW_ADDR=
    while [ -z "$GW_ADDR" ]; do
      echo "Default gateway address (leave blank for none):"
      echo -n "> "
      read GW_ADDR
 
      # Check if ip address has a valid format
      if [ -n "$GW_ADDR" ]; then
        echo "$GW_ADDR" | grep '[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*' &> /dev/null
        if [ $? -ne 0 ]; then
          echo "Invalid gateway address. Format: xxx.xxx.xxx.xxx"
          echo
          GW_ADDR=
        fi
      else
        GW_ADDR="__blank__"
      fi
    done
 
    # Dns address
    DNS_ADDR=
    while [ -z "$DNS_ADDR" ]; do
      echo "Primary DNS address (leave blank for none):"
      echo -n "> "
      read DNS_ADDR
 
      # Check if ip address has a valid format
      if [ -n "$DNS_ADDR" ]; then
        echo "$DNS_ADDR" | grep '[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*' &> /dev/null
        if [ $? -ne 0 ]; then
          echo "Invalid DNS address. Format: xxx.xxx.xxx.xxx"
          echo
          DNS_ADDR=
        fi
      else
        DNS_ADDR="__blank__"
      fi
    done
  fi
}
 
autoConnDef () {
  echo "Autoconnect (Y|N):"
  echo -n "> "
  read AUTO
  case $AUTO in
    y|Y|yes) AUTO=yes;;
    n|N|no) AUTO=no;;
    *) echo "Ambiguous choice, assuming autoconnect=no"
      AUTO=no
      ;;
  esac
}
 
#*****************************************************************************#
 
# Welcome section
# Clear the screen
clear
 
echo
echo "+-------------------------------------------------------+"
echo "|                                                       |"
echo "|     conadd - Interactive network connection tool      |"
echo "|                                                       |"
echo "+-------------------------------------------------------+"
echo
 
 
#*****************************************************************************#
 
# Begin data collection
 
# Connection type
connTypeDef
echo
 
case $CONN_TYPE in
  ethernet)
    # Connection name
    connDef
    echo
    # Network interface name
    hwIfaceDef
    echo
    # Static ip address
    ip4AddrDef
    echo
    # Auto Connect
    autoConnDef
    echo
    ;;
 
  bridge)
    # Connection name
    connDef
    echo
    # Bonded network interface
    bdIfaceDef
    echo
    # Slave interfaces
    slIfaceDef
    echo
    # Static ip address
    ip4AddrDef
    # Auto Connect
    autoConnDef
    echo
    ;;
 
  team)
    # Connection name
    connDef
    echo
    # Bonded network interface
    bdIfaceDef
    echo
    # Slave interfaces
    slIfaceDef
    echo
    # Team config
    teamConfig
    echo
    # Static ip address
    ip4AddrDef
    # Auto Connect
    autoConnDef
    echo
    ;;
esac
 
# Static ip address
echo
echo +----------------------------------------------------+
echo "  Configuration Summary:"
echo
echo -n "  Connection type: "
echo "$CONN_TYPE"
echo -n "  Interface name: "
echo "$IFACE"
echo -n "  Connection name: "
echo "$CONN_NAME"
if [ "$CONN_TYPE" == "bridge" ] || [ "$CONN_TYPE" == "team" ]; then	# Slave interface are only showed on bridge and team connections
  echo -n "  Slave interfaces: "
  for NUM in $(seq 0 $(($SLAVE-1))); do
    inetRef=IFACE_$NUM
    portRef=SLNAME_$NUM
    echo -n "${!inetRef} (${!portRef})  "
  done
  echo
fi
 
if [ "$CONN_TYPE" == "team" ]; then
  echo -n "  Team config: "
  echo $RUNNER_STR
fi
 
echo -n "  Ip address: "
if [ "$IP_ADDR" != "__dhcp__" ]; then
  echo "$IP_ADDR"
  echo -n "  Default gateway: "
  if [ "$GW_ADDR" != "__blank__" ]; then
    echo "$GW_ADDR"
  else
    echo "none"
  fi
  echo -n "  Primary DNS: "
  if [ "$DNS_ADDR" != "__blank__" ]; then
    echo "$DNS_ADDR"
  else
    echo "none"
  fi
else
  echo "DHCP"
fi
echo -n "  Autoconnect: "
echo "$AUTO"
echo +----------------------------------------------------+
echo
 
# End data collection
 
#*****************************************************************************#
 
# Begin connection configuration section
 
echo -n "Are you sure you want to proceed? ([Y]es|[N]o) "
read CHOICE
case $CHOICE in
  y|Y) echo "Invoking Network Manager to configure the connection..."
 
    # Ethernet connections
    if [ "$CONN_TYPE" == "ethernet" ]; then 
      if [ "$IP_ADDR" == "__dhcp__" ]; then
         nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} &> /dev/null
         if [ $? -ne 0 ]; then
           echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO}". Error $?"
           exit 1
         fi
       else
         if [ "GW_ADDR" == "__blank__" ]; then
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN-NAME} ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR}". Error $?"
             exit 1
           fi
         else
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} gw4 ${GW_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} gw4 ${GW_ADDR}". Error $?"
             exit 1
           fi
         fi
 
         if [ "$DNS_ADDR" != "__blank__" ]; then
           nmcli con mod "${CONN_NAME}" ipv4.dns ${DNS_ADDR}
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command nmcli con mod. Error $?"
             exit 1
           fi
         fi
       fi
 
     # Bridge connections
     elif [ "$CONN_TYPE" == "bridge" ]; then
       if [ "$IP_ADDR" == "__dhcp__" ]; then
         nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} &> /dev/null
         if [ $? -ne 0 ]; then
           echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO}". Error $?"
           exit 1
         fi
       else
         if [ "GW_ADDR" == "__blank__" ]; then
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN-NAME} ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR}". Error $?"
             exit 1
           fi
         else
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} gw4 ${GW_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} gw4 ${GW_ADDR}". Error $?"
             exit 1
           fi
         fi
 
         if [ "$DNS_ADDR" != "__blank__" ]; then
           nmcli con mod "${CONN_NAME}" ipv4.dns ${DNS_ADDR}
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command nmcli con mod. Error $?"
             exit 1
           fi
         fi
       fi
 
       # Bridge slaves
       for NUM in $(seq 0 $(($SLAVE-1))); do
         inetRef=IFACE_$NUM
         portRef=SLNAME_$NUM
         nmcli con add type ${CONN_TYPE}-slave con-name ${!portRef} ifname ${!inetRef} master ${CONN_NAME} &> /dev/null
         if [ $? -ne 0 ]; then
           echo "FATAL: error during the execution of command "nmcli con add type ${CONN_TYPE}-slave con-name ${!portRef} ifname ${!inetRef} master ${CONN_NAME}". Error $?"
 	 fi
       done
 
     # Team connections
     elif [ "$CONN_TYPE" == "team" ]; then
       if [ "$IP_ADDR" == "__dhcp__" ]; then
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} config "${RUNNER_STR}" &> /dev/null
         if [ $? -ne 0 ]; then
           echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO} config ${RUNNER_STR}". Error $?"
           exit 1
         fi
       else
         if [ "GW_ADDR" == "__blank__" ]; then
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} config "${RUNNER_STR}" ip4 ${IP_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN-NAME} ifname ${IFACE} autoconnect ${AUTO} config ${RUNNER_STR} ip4 ${IP_ADDR}". Error $?"
             exit 1
           fi
         else
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} config "${RUNNER_STR}" ip4 ${IP_ADDR} gw4 ${GW_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO} config ${RUNNER_STR} ip4 ${IP_ADDR} gw4 ${GW_ADDR}". Error $?"
             exit 1
           fi
         fi
 
         if [ "$DNS_ADDR" != "__blank__" ]; then
           nmcli con mod "${CONN_NAME}" ipv4.dns ${DNS_ADDR}
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command nmcli con mod. Error $?"
             exit 1
           fi
         fi
       fi
 
       # Team Slaves 
       for NUM in $(seq 0 $(($SLAVE-1))); do
         inetRef=IFACE_$NUM
         portRef=SLNAME_$NUM
         nmcli con add type ${CONN_TYPE}-slave con-name ${!portRef} ifname ${!inetRef} master ${CONN_NAME} &> /dev/null
         if [ $? -ne 0 ]; then
           echo "FATAL: error during the execution of command "nmcli con add type ${CONN_TYPE}-slave con-name ${!portRef} ifname ${!inetRef} master ${CONN_NAME}". Error $?"
         fi
       done
     fi
 
     echo
     CONN_UUID=$(nmcli conn | grep "${CONN_NAME}" | awk '{print $2}')
     echo "Network Manager has successfully added the new connection "$CONN_NAME" with UUID ${CONN_UUID}."
     echo -n "Activate the connection? "
     read CONN_UP
     case $CONN_UP in
       y|Y|yes) nmcli con up "${CONN_NAME}" &> /dev/null
         if [ $? -ne 0 ]; then
           echo "FATAL: cannot bring the connection $CONN_NAME up"
           exit 1
         else
           echo "Successfully activated the connection $CONN_NAME. Goodbye"
         fi
         ;;
       *) echo "Goodbye.";;
     esac
     ;;
  n|N) echo "You choosed not to update your network config. Goodbye."
     exit 0
     ;;
  *) echo "Wrong selection. Exiting."
     exit 1
     ;;
esac
 
exit 0

La prima parte dello script, che è anche la più corposa, definisce alcune funzioni che verranno invocate successivamente.
La funzione connTypeDef () permette all’utente di scegliere il tipo di connessione. Attualmente ne sono disponibili solo tre tipi (definiti nella variabile “TYPE_LIST”) ma seguendo l’approccio utilizzato è facile estendere le funzionalità ad altre tipologie. Viene effettuato un controllo in modo da impedire l’immissione di stringhe vuote o di tipi di connessioni non valide.

connTypeDef () {
  CONN_TYPE=
  TYPE_LIST="ethernet bridge team"
  while [ -z "$CONN_TYPE" ]; do
    echo -n "Connection type: (available types: "
    echo -n $TYPE_LIST
    echo ")"
    echo -n "> "
    read CONN_TYPE
 
    # Check if $CONN_TYPE is zero lenght
    if [ -z "$CONN_TYPE" ]; then
      echo "Must specify a connection type"
      echo
    else
      # Check if the interface exists
      for type_chk in $TYPE_LIST; do
        if [ "$CONN_TYPE" == "$type_chk" ]; then
          TYPE_OK=1
        fi
      done
 
      if [ "$TYPE_OK" != "1" ]; then
        echo "The type specified does not exist"
        echo "Choose a type among this list: $TYPE_LIST"
        CONN_TYPE=
      fi
    fi
  done
}

La funzione hwIfaceDef () invece viene utilizzata solo dalle connessioni Ethernet e restituisce un elenco dei device disponibili sulla macchina. Anche qui avviene il solito controllo su stringhe vuote e/o input non validi.

hwIfaceDef () {
  IFACE=
  IF_OK=0
  IFACE_LIST=$(nmcli dev | sed '1d' | awk '{print $1}')
  while [ -z "$IFACE" ]; do
    echo -n "Network interface name: (available interfaces: "
    echo -n $IFACE_LIST
    echo ")"
    echo -n "> "
    read IFACE
 
    # Check if $IFACE is zero lenght
    if [ -z "$IFACE" ]; then
      echo "Network interface name cannot be blank"
      echo
    else
      # Check if the interface exists
      for ifname_chk in $IFACE_LIST; do
        if [ "$IFACE" == "$ifname_chk" ]; then
          IF_OK=1
        fi
      done
 
      if [ $IF_OK -ne 1 ]; then
        echo "Network interface does not exist"
        echo "Choose and interface among this list: $IFACE_LIST"
        IFACE=
      fi
    fi
  done
}

Un’altra funzione importante è ip4AddrDef () che permette all’utente di impostare un indirizzo IPv4 statico (o un dhcp), default gateway e un eventuale DNS primario. In questa funzione, tramite l’uso di semplici regular expression, vengono verificati i formati gli indirizzi IP immessi in modo da non incappare successivamente in un errore generato da nmcli.

ip4AddrDef () {
  IP_ADDR=
  while [ -z "$IP_ADDR" ]; do
    echo "IPv4 address + Network prefix (leave blank for dhcp):"
    echo -n "> "
    read IP_ADDR
 
    # Check if ip address has a valid format
    if [ -n "$IP_ADDR" ]; then
      echo "$IP_ADDR" | grep '[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*/[0-9]*' &> /dev/null
      if [ $? -ne 0 ]; then
        echo "Invalid IPv4 address. Format: xxx.xxx.xxx.xxx/yy"
        echo
        IP_ADDR=
      fi
    else
      IP_ADDR="__dhcp__"
    fi
  done
 
  # If static ip address is set, collects default gateway and dns address
  if [ "$IP_ADDR" != "__dhcp__" ]; then
 
   # Default Gateway
   GW_ADDR=
    while [ -z "$GW_ADDR" ]; do
      echo "Default gateway address (leave blank for none):"
      echo -n "> "
      read GW_ADDR
 
      # Check if ip address has a valid format
      if [ -n "$GW_ADDR" ]; then
        echo "$GW_ADDR" | grep '[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*' &> /dev/null
        if [ $? -ne 0 ]; then
          echo "Invalid gateway address. Format: xxx.xxx.xxx.xxx"
          echo
          GW_ADDR=
        fi
      else
        GW_ADDR="__blank__"
      fi
    done
 
    # Dns address
    DNS_ADDR=
    while [ -z "$DNS_ADDR" ]; do
      echo "Primary DNS address (leave blank for none):"
      echo -n "> "
      read DNS_ADDR
 
      # Check if ip address has a valid format
      if [ -n "$DNS_ADDR" ]; then
        echo "$DNS_ADDR" | grep '[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]*' &> /dev/null
        if [ $? -ne 0 ]; then
          echo "Invalid DNS address. Format: xxx.xxx.xxx.xxx"
          echo
          DNS_ADDR=
        fi
      else
        DNS_ADDR="__blank__"
      fi
    done
  fi
}

Nella sezione successiva tramite un semplice costrutto case vengono invocate le varie funzioni tramite in base al tipo di connessione che si è scelto.

case $CONN_TYPE in
  ethernet)
    # Connection name
    connDef
    echo
    # Network interface name
    hwIfaceDef
    echo
    # Static ip address
    ip4AddrDef
    echo
    # Auto Connect
    autoConnDef
    echo
    ;;
 
  bridge)
    # Connection name
    connDef
    echo
    # Bonded network interface
    bdIfaceDef
    echo
    # Slave interfaces
    slIfaceDef
    echo
    # Static ip address
    ip4AddrDef
    # Auto Connect
    autoConnDef
    echo
    ;;
 
  team)
    # Connection name
    connDef
    echo
    # Bonded network interface
    bdIfaceDef
    echo
    # Slave interfaces
    slIfaceDef
    echo
    # Team config
    teamConfig
    echo
    # Static ip address
    ip4AddrDef
    # Auto Connect
    autoConnDef
    echo
    ;;
esac

Dopo un breve configuration summary si entra nel vivo della configurazione vera e propria. Nella terza sezione viene finalmente invocato nmcli con i parametri variabilizzati. Ad esempio, ecco la parte relativa alla configurazione delle connessioni Ethernet. Come si può vedere viene immediatamente effettuato un controllo sull’indirizzo ip dinamico. Se l’utente ha optato per una connessione dhcp nmcli verrà eseguito con un set di parametri minimale, ovvero tipo connessione ($CONN_TYPE), nome connessione ($CONN_NAME), nome device ($IFACE) e autoconnect ($AUTO). Se sono stati definiti indirizzo IP statico e default gateway invece nmcli verrà eseguito con i parametri corretti. Il tutto viene gestito tramite un cotrutto if/else/fi.

if [ "$CONN_TYPE" == "ethernet" ]; then 
      if [ "$IP_ADDR" == "__dhcp__" ]; then
         nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} &> /dev/null
         if [ $? -ne 0 ]; then
           echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO}". Error $?"
           exit 1
         fi
       else
         if [ "GW_ADDR" == "__blank__" ]; then
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN-NAME} ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR}". Error $?"
             exit 1
           fi
         else
           nmcli con add type ${CONN_TYPE} con-name "${CONN_NAME}" ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} gw4 ${GW_ADDR} &> /dev/null
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command "nmcli con add type $CONN_TYPE con-name ${CONN_NAME} ifname ${IFACE} autoconnect ${AUTO} ip4 ${IP_ADDR} gw4 ${GW_ADDR}". Error $?"
             exit 1
           fi
         fi
 
         if [ "$DNS_ADDR" != "__blank__" ]; then
           nmcli con mod "${CONN_NAME}" ipv4.dns ${DNS_ADDR}
           if [ $? -ne 0 ]; then
             echo "FATAL: error during the execution of command nmcli con mod. Error $?"
             exit 1
           fi
         fi
       fi

 

Se lo ritenete valido e utile per il vostro lavoro vi invitiamo a utilizzare questo script e ad apportarvi le vostre customizzazioni.
Nel prossimo articolo continueremo con la seconda parte della configurazione della rete su RHEL7/CentOS7 con nmcli. Verranno coperte, oltre alle connessioni team e bridge di cui abbiamo parlato pocanzi, anche le connessioni IPv6. Nel frattempo vi invitiamo a rileggere il precedente post disponibile a questo link.
Buona lettura!

Info about author

EXTRAORDY