Why I did it Support for SONIC chassis isolation using TSA and un-isolation using TSB from supervisor module Work item tracking Microsoft ADO (number only): 17826134 How I did it When TSA is run on the supervisor, it triggers TSA on each of the linecards using the secure rexec infrastructure introduced in sonic-net/sonic-utilities#2701. User password is requested to allow secure login to linecards through ssh, before execution of TSA/TSB on the linecards TSA of the chassis withdraws routes from all the external BGP neighbors on each linecard, in order to isolate the entire chassis. No route withdrawal is done from the internal BGP sessions between the linecards to prevent transient drops during internal route deletion. With these changes, complete isolation of a single linecard using TSA will not be possible (a separate CLI/script option will be introduced at a later time to achieve this) Changes also include no-stats option with TSC for quick retrieval of the current system isolation state This PR also reverts changes in #11403 How to verify it These changes have a dependency on sonic-net/sonic-utilities#2701 for testing Run TSA from supervisor module and ensure transition to Maintenance mode on each linecard Verify that all routes are withdrawn from eBGP neighbors on all linecards Run TSB from supervisor module and ensure transition to Normal mode on each linecard Verify that all routes are re-advertised from eBGP neighbors on all linecards Run TSC no-stats from supervisor and verify that just the system maintenance state is returned from all linecards
439 lines
14 KiB
Bash
Executable File
439 lines
14 KiB
Bash
Executable File
#!/bin/bash
|
|
###########################################################################
|
|
# Copyright 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. #
|
|
# and/or its subsidiaries. #
|
|
# #
|
|
# 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. #
|
|
# #
|
|
###########################################################################
|
|
# SONiC Configuration Setup #
|
|
# #
|
|
# This script is used to initialize configuration used #
|
|
# by SONiC SWSS. It also performs configuration #
|
|
# migration. #
|
|
# #
|
|
###########################################################################
|
|
|
|
# Initialize constants
|
|
UPDATEGRAPH_CONF=/etc/sonic/updategraph.conf
|
|
INIT_CFG_JSON=/etc/sonic/init_cfg.json
|
|
CONFIG_DB_JSON=/etc/sonic/config_db.json
|
|
CONFIG_DB_PATH=/etc/sonic/
|
|
CONFIG_DB_PREFIX=config_db
|
|
CONFIG_DB_SUFFIX=.json
|
|
MINGRAPH_FILE=/etc/sonic/minigraph.xml
|
|
TMP_ZTP_CONFIG_DB_JSON=/tmp/ztp_config_db.json
|
|
FACTORY_DEFAULT_HOOKS=/etc/config-setup/factory-default-hooks.d
|
|
CONFIG_PRE_MIGRATION_HOOKS=/etc/config-setup/config-migration-pre-hooks.d
|
|
CONFIG_POST_MIGRATION_HOOKS=/etc/config-setup/config-migration-post-hooks.d
|
|
CONFIG_SETUP_VAR_DIR=/var/lib/config-setup
|
|
CONFIG_SETUP_PRE_MIGRATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_pre_migration
|
|
CONFIG_SETUP_POST_MIGRATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_post_migration
|
|
CONFIG_SETUP_INITIALIZATION_FLAG=${CONFIG_SETUP_VAR_DIR}/pending_initialization
|
|
|
|
TACACS_JSON_BACKUP=tacacs.json
|
|
|
|
# Command usage and help
|
|
usage()
|
|
{
|
|
cat << EOF
|
|
Usage: config-setup < backup | boot | factory >
|
|
|
|
backup - Take a backup copy of SONiC configuration.
|
|
boot - Initialize/migrate SONiC configuration during system boot.
|
|
factory - Create factory default SONiC configuration and save it to
|
|
to ${CONFIG_DB_JSON}.
|
|
EOF
|
|
}
|
|
|
|
# run given script
|
|
run_hook() {
|
|
local script="$1"
|
|
local exit_status=0
|
|
|
|
if [ -f $script ]; then
|
|
# Check hook for syntactical correctness before executing it
|
|
/bin/bash -n $script
|
|
exit_status=$?
|
|
if [ "$exit_status" -eq 0 ]; then
|
|
. $script
|
|
fi
|
|
exit_status=$?
|
|
fi
|
|
|
|
if [ -n "$exit_status" ] && [ "$exit_status" -ne 0 ]; then
|
|
echo "$script returned non-zero exit status $exit_status"
|
|
fi
|
|
|
|
return $exit_status
|
|
}
|
|
|
|
# run scripts in given directory
|
|
run_hookdir() {
|
|
local dir="$1"
|
|
local progress_file="$2"
|
|
local exit_status=0
|
|
|
|
if [ -d "$dir" ]; then
|
|
if [ -n $progress_file ]; then
|
|
[ ! -d $(dirname $progress_file) ] && mkdir -p $(dirname $progress_file)
|
|
[ ! -e $progress_file ] && run-parts --list $dir > $progress_file
|
|
SCRIPT_LIST=$(cat $progress_file)
|
|
else
|
|
SCRIPT_LIST=$(run-parts --list $dir)
|
|
fi
|
|
|
|
for script in $SCRIPT_LIST; do
|
|
run_hook $script
|
|
exit_status=$((exit_status|$?))
|
|
script_name=$(basename $script)
|
|
sed -i "/$script_name/d" $progress_file
|
|
done
|
|
[ -n $progress_file ] && [ "$(cat ${progress_file})" = "" ] && rm -f ${progress_file}
|
|
fi
|
|
|
|
return $exit_status
|
|
}
|
|
|
|
# Reload minigraph.xml file on disk
|
|
reload_minigraph()
|
|
{
|
|
echo "Reloading minigraph..."
|
|
config load_minigraph -y -n
|
|
config save -y
|
|
}
|
|
|
|
# Apply tacacs config
|
|
apply_tacacs()
|
|
{
|
|
if [ -r /etc/sonic/old_config/${TACACS_JSON_BACKUP} ]; then
|
|
sonic-cfggen -j /etc/sonic/old_config/${TACACS_JSON_BACKUP} --write-to-db
|
|
echo "Applied tacacs json to restore tacacs credentials"
|
|
config save -y
|
|
else
|
|
echo "Missing tacacs json to restore tacacs credentials"
|
|
fi
|
|
}
|
|
|
|
# Reload existing config db file on disk
|
|
# Usage: reload_configdb <config_file>
|
|
reload_configdb()
|
|
{
|
|
CONFIG_FILE=${1}
|
|
|
|
echo "Reloading existing config db..."
|
|
config reload ${CONFIG_FILE} -y -n
|
|
}
|
|
|
|
# Restore SONiC configuration from a backup copy
|
|
copy_config_files_and_directories()
|
|
{
|
|
for file_dir in $@; do
|
|
if [ -f /etc/sonic/old_config/${file_dir} ] || [ -d /etc/sonic/old_config/${file_dir} ]; then
|
|
echo "Copying SONiC configuration ${file_dir} ..."
|
|
cp -ar /etc/sonic/old_config/${file_dir} /etc/sonic/
|
|
else
|
|
echo "Missing SONiC configuration ${file_dir} ..."
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Check if SONiC switch has booted after a warm reboot request
|
|
check_system_warm_boot()
|
|
{
|
|
SYSTEM_WARM_START=`sonic-db-cli STATE_DB hget "WARM_RESTART_ENABLE_TABLE|system" enable`
|
|
# SYSTEM_WARM_START could be empty, always make WARM_BOOT meaningful.
|
|
if [[ x"$SYSTEM_WARM_START" == x"true" ]]; then
|
|
WARM_BOOT="true"
|
|
else
|
|
WARM_BOOT="false"
|
|
fi
|
|
}
|
|
|
|
# Check if updategraph service is administratively enabled
|
|
updategraph_is_enabled()
|
|
{
|
|
rv=1
|
|
if [ -e ${UPDATEGRAPH_CONF} ]; then
|
|
updategraph_mode=$(grep enabled ${UPDATEGRAPH_CONF} | head -n 1 | cut -f2 -d=)
|
|
[ "${updategraph_mode}" = "true" ] && rv=0
|
|
fi
|
|
return $rv
|
|
}
|
|
|
|
# Disable updategraph admininistratively
|
|
disable_updategraph()
|
|
{
|
|
sed -i "/enabled=/d" ${UPDATEGRAPH_CONF}
|
|
echo "enabled=false" >> ${UPDATEGRAPH_CONF}
|
|
}
|
|
|
|
# Check if Zero Touch Provisioning is available and is administratively enabled
|
|
ztp_is_enabled()
|
|
{
|
|
rv=1
|
|
if [ -e /usr/bin/ztp ]; then
|
|
status=$(ztp status -c)
|
|
[ "$status" != "0:DISABLED" ] && [ "$status" != "" ] && rv=0
|
|
fi
|
|
return $rv
|
|
}
|
|
|
|
# Generate requested SONiC configuration and save it as destination file
|
|
# Usage: generate_config < factory | ztp > <destination_file>
|
|
#
|
|
# factory - Create factory default configuration
|
|
# ztp - Create Zero Touch Provisioning Configuration
|
|
# used for provisioning data discovery.
|
|
#
|
|
generate_config()
|
|
{
|
|
# Collect all information needed to generate configuration
|
|
PLATFORM=${PLATFORM:-`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform`}
|
|
PRESET=(`head -n 1 /usr/share/sonic/device/$PLATFORM/default_sku`)
|
|
HW_KEY=${PRESET[0]}
|
|
DEFAULT_PRESET=${PRESET[1]}
|
|
|
|
# Parse arguments passed
|
|
CONFIG_TYPE=$1
|
|
DEST_FILE=$2
|
|
|
|
if [ "$1" = "ztp" ]; then
|
|
/usr/lib/ztp/ztp-profile.sh create ${DEST_FILE}
|
|
elif [ "$1" = "factory" ]; then
|
|
rv=1
|
|
|
|
# Execute config initialization hooks
|
|
run_hookdir ${FACTORY_DEFAULT_HOOKS} ${CONFIG_SETUP_INITIALIZATION_FLAG}
|
|
|
|
# Use preset defined in default_sku
|
|
if [ ! -e ${DEST_FILE} ]; then
|
|
sonic-cfggen -H -k ${HW_KEY} --preset ${DEFAULT_PRESET} > ${DEST_FILE}
|
|
rv=$?
|
|
if [ $rv -ne 0 ]; then
|
|
return $rv
|
|
fi
|
|
fi
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Create SONiC configuration for first time bootup
|
|
# - If ZTP is enabled, ZTP configuraion is created
|
|
# - If ZTP is disabled and updategraph is disabled, factory default configuration
|
|
# is created
|
|
# - If updategraph is enabled and ZTP is disabled, updategraph initializes
|
|
# configuration
|
|
do_config_initialization()
|
|
{
|
|
if ! updategraph_is_enabled ; then
|
|
if ! ztp_is_enabled ; then
|
|
echo "No configuration detected, generating factory default configuration..."
|
|
generate_config factory ${CONFIG_DB_JSON}
|
|
reload_configdb ${CONFIG_DB_JSON}
|
|
fi
|
|
fi
|
|
|
|
if ztp_is_enabled ; then
|
|
echo "No configuration detected, initiating zero touch provisioning..."
|
|
generate_config ztp ${TMP_ZTP_CONFIG_DB_JSON}
|
|
reload_configdb ${TMP_ZTP_CONFIG_DB_JSON}
|
|
rm -f ${TMP_ZTP_CONFIG_DB_JSON}
|
|
fi
|
|
|
|
rm -f /tmp/pending_config_initialization
|
|
}
|
|
|
|
# Restore config-setup post migration hooks from a backup copy
|
|
copy_post_migration_hooks()
|
|
{
|
|
BACKUP_DIR=/etc/sonic/old_config/config-migration-post-hooks.d
|
|
if [ -d ${BACKUP_DIR} ]; then
|
|
[ -d ${CONFIG_POST_MIGRATION_HOOKS} ] || mkdir -p ${CONFIG_POST_MIGRATION_HOOKS}
|
|
for hook in $(ls -1 ${BACKUP_DIR}) ; do
|
|
if [ ! -e ${CONFIG_POST_MIGRATION_HOOKS}/$hook ]; then
|
|
cp -ar ${BACKUP_DIR}/$hook ${CONFIG_POST_MIGRATION_HOOKS}
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Get the list of config db for both
|
|
# single and multi-npu platforms
|
|
get_config_db_file_list()
|
|
{
|
|
config_db_file_list=${CONFIG_DB_PREFIX}${CONFIG_DB_SUFFIX}
|
|
asic_num=0
|
|
while [[ ($asic_num -lt $NUM_ASIC) && ($NUM_ASIC -gt 1) ]]; do
|
|
config_db_file_list+=' '${CONFIG_DB_PREFIX}$asic_num${CONFIG_DB_SUFFIX}
|
|
((asic_num = asic_num + 1))
|
|
done
|
|
|
|
echo $config_db_file_list
|
|
}
|
|
|
|
# Check if all needed config db are present for both
|
|
# single and multi-npu platforms
|
|
check_all_config_db_present()
|
|
{
|
|
if [[ ! -r ${CONFIG_DB_JSON} ]]; then
|
|
return 1
|
|
fi
|
|
asic_num=0
|
|
while [[ ($asic_num -lt $NUM_ASIC) && ($NUM_ASIC -gt 1) ]]; do
|
|
if [[ ! -r ${CONFIG_DB_PATH}${CONFIG_DB_PREFIX}$asic_num${CONFIG_DB_SUFFIX} ]]; then
|
|
return 1
|
|
fi
|
|
((asic_num = asic_num + 1))
|
|
done
|
|
|
|
return 0
|
|
}
|
|
|
|
# Perform configuration migration from backup copy.
|
|
# - This step is performed when a new image is installed and SONiC switch boots into it
|
|
do_config_migration()
|
|
{
|
|
# Identify list of files to migrate
|
|
copy_list="minigraph.xml snmp.yml acl.json port_config.json frr telemetry"
|
|
|
|
# Migrate all configuration files from old to new
|
|
copy_config_files_and_directories $copy_list
|
|
|
|
# Migrate all config_db from old to new
|
|
copy_config_files_and_directories $(get_config_db_file_list)
|
|
|
|
# Migrate post-migration hooks
|
|
copy_post_migration_hooks
|
|
|
|
# Execute custom hooks if present
|
|
run_hookdir ${CONFIG_POST_MIGRATION_HOOKS} ${CONFIG_SETUP_POST_MIGRATION_FLAG}
|
|
|
|
if [ x"${WARM_BOOT}" == x"true" ]; then
|
|
echo "Warm reboot detected..."
|
|
disable_updategraph
|
|
rm -f /tmp/pending_config_migration
|
|
exit 0
|
|
elif check_all_config_db_present; then
|
|
echo "Use config_db.json from old system..."
|
|
reload_configdb
|
|
# Disable updategraph
|
|
disable_updategraph
|
|
elif [ -r ${MINGRAPH_FILE} ]; then
|
|
echo "Use minigraph.xml from old system..."
|
|
reload_minigraph
|
|
# Disable updategraph
|
|
disable_updategraph
|
|
else
|
|
echo "Didn't found neither config_db.json nor minigraph.xml ..."
|
|
fi
|
|
|
|
rm -f /tmp/pending_config_migration
|
|
}
|
|
|
|
# Take a backup of current SONiC configuration
|
|
do_config_backup()
|
|
{
|
|
echo "Taking backup of current configuration"
|
|
rm -rf /host/old_config
|
|
cp -ar /etc/sonic /host/old_config
|
|
[ -d ${CONFIG_POST_MIGRATION_HOOKS} ] && cp -arL ${CONFIG_POST_MIGRATION_HOOKS} /host/old_config
|
|
|
|
# Execute custom hooks if present
|
|
run_hookdir ${CONFIG_PRE_MIGRATION_HOOKS} ${CONFIG_SETUP_PRE_MIGRATION_FLAG}
|
|
}
|
|
|
|
# Process switch bootup event
|
|
# - Check if it is warm boot and take no further action
|
|
# - Perform configuration migration if requested
|
|
# - Perform configuration initialization if requested
|
|
# - If no saved SONiC configuration is found and ZTP is enabled,
|
|
# start ZTP
|
|
boot_config()
|
|
{
|
|
check_system_warm_boot
|
|
if [ -e /tmp/pending_config_migration ] || [ -e ${CONFIG_SETUP_POST_MIGRATION_FLAG} ]; then
|
|
do_config_migration
|
|
fi
|
|
|
|
# For multi-npu platfrom we don't support config initialization. Assumption
|
|
# is there should be existing minigraph or config_db from previous image
|
|
# file system to trigger. pending_config_initialization will remain set
|
|
# for multi-npu platforms if we reach this case.
|
|
if [[ ($NUM_ASIC -gt 1) ]]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ -e /tmp/pending_config_initialization ] || [ -e ${CONFIG_SETUP_INITIALIZATION_FLAG} ]; then
|
|
do_config_initialization
|
|
fi
|
|
|
|
# If no startup configuration is found, create a configuration to be used
|
|
if [ ! -e ${CONFIG_DB_JSON} ]; then
|
|
do_config_initialization
|
|
# force ZTP to restart
|
|
if ztp_is_enabled ; then
|
|
ztp_status=$(ztp status -c)
|
|
if [ "$ztp_status" = "5:SUCCESS" ] || \
|
|
[ "$ztp_status" = "6:FAILED" ]; then
|
|
# Clear completed ztp information, before starting a new one
|
|
ztp erase -y
|
|
else
|
|
touch /tmp/pending_ztp_restart
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# read SONiC immutable variables
|
|
[ -f /etc/sonic/sonic-environment ] && . /etc/sonic/sonic-environment
|
|
|
|
### Execution starts here ###
|
|
PLATFORM=${PLATFORM:-`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform`}
|
|
# Parse the device specific asic conf file, if it exists
|
|
ASIC_CONF=/usr/share/sonic/device/$PLATFORM/asic.conf
|
|
if [[ -f "$ASIC_CONF" ]]; then
|
|
source $ASIC_CONF
|
|
fi
|
|
|
|
|
|
CMD=$1
|
|
# Default command is boot
|
|
if [ "$CMD" = "" ] || [ "$CMD" = "help" ] || \
|
|
[ "$CMD" = "-h" ] || [ "$CMD" = "--help" ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
# Process switch bootup event
|
|
if [ "$CMD" = "boot" ]; then
|
|
boot_config
|
|
fi
|
|
|
|
# Process factory default configuration creation request
|
|
if [ "$CMD" = "factory" ]; then
|
|
generate_config factory ${CONFIG_DB_JSON}
|
|
fi
|
|
|
|
# Take a backup of current configuration
|
|
if [ "$CMD" = "backup" ]; then
|
|
do_config_backup
|
|
fi
|
|
|
|
# Apply tacacs from old configuration
|
|
if [ "$CMD" = "apply_tacacs" ]; then
|
|
apply_tacacs
|
|
fi
|
|
|
|
exit 0
|