447 lines
14 KiB
Bash
Executable File
447 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..."
|
|
if
|
|
[[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.subtype | tr [:upper:] [:lower:])" == *"dualtor"* ]] ||
|
|
[[ "$(sonic-cfggen -d -v DEVICE_METADATA.localhost.type | tr [:upper:] [:lower:])" == *"leafrouter"* ]];
|
|
then
|
|
#Keep device isolated with traffic-shift-away option on LeafRouter and Dualtor
|
|
config load_minigraph -y -n -t
|
|
else
|
|
config load_minigraph -y -n
|
|
fi
|
|
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
|