abe7ef7e2e
- move single instance services into their own folder - generate Systemd templates for any multi-instance service files in slave.mk - detect single or multi-instance platform in systemd-sonic-generator based on asic.conf platform specific file. - update container hostname after creation instead of during creation (docker_image_ctl) - run Docker containers in a network namespace if specified - add a service to create a simulated multi-ASIC topology on the virtual switch platform Signed-off-by: Lawrence Lee <t-lale@microsoft.com> Signed-off-by: Suvarna Meenakshi <Suvarna.Meenaksh@microsoft.com>
360 lines
13 KiB
Django/Jinja
360 lines
13 KiB
Django/Jinja
#!/bin/bash
|
|
|
|
# single instance containers are still supported (even though it might not look like it)
|
|
# if no instance number is passed to this script, $DEV will simply be unset, resulting in docker
|
|
# commands being sent to the base container name. E.g. `docker start database$DEV` simply starts
|
|
# the container `database` if no instance number is passed since `$DEV` is not defined
|
|
|
|
|
|
{%- if docker_container_name == "database" %}
|
|
link_namespace() {
|
|
# Makes namespace of a docker container available in
|
|
# /var/run/netns so it can be managed with iproute2
|
|
|
|
mkdir -p /var/run/netns
|
|
PID="$(docker inspect -f {{"'{{.State.Pid}}'"}} "{{docker_container_name}}$DEV")"
|
|
|
|
if `ip netns | grep --quiet -w "{{docker_container_name}}$DEV"`; then # namespace exists
|
|
if [ $(readlink -f /var/run/netns/$NET_NS$DEV) = $(readlink -f /proc/$PID/ns/net) ]; then # namespace is correctly linked
|
|
return 0
|
|
else # if it's incorrectly linked remove it
|
|
ip netns delete "{{docker_container_name}}$DEV"
|
|
fi
|
|
fi
|
|
|
|
ln -s /proc/$PID/ns/net /var/run/netns/$NET_NS$DEV
|
|
}
|
|
{%- endif %}
|
|
|
|
function getMountPoint()
|
|
{
|
|
echo $1 | python -c "import sys, json, os; mnts = [x for x in json.load(sys.stdin)[0]['Mounts'] if x['Destination'] == '/usr/share/sonic/hwsku']; print '' if len(mnts) == 0 else os.path.basename(mnts[0]['Source'])" 2>/dev/null
|
|
}
|
|
|
|
function updateHostName()
|
|
{
|
|
HOSTS=/etc/hosts
|
|
HOSTS_TMP=/etc/hosts.tmp
|
|
|
|
EXEC="docker exec -i {{docker_container_name}}$DEV bash -c"
|
|
|
|
NEW_HOSTNAME="$1"
|
|
HOSTNAME=`$EXEC "hostname"`
|
|
if ! [[ $HOSTNAME =~ ^[a-zA-Z0-9.\-]*$ ]]; then
|
|
HOSTNAME=`hostname`
|
|
fi
|
|
|
|
# copy HOSTS to HOSTS_TMP
|
|
$EXEC "cp $HOSTS $HOSTS_TMP"
|
|
# remove entry with hostname
|
|
$EXEC "sed -i \"/$HOSTNAME$/d\" $HOSTS_TMP"
|
|
# add entry with new hostname
|
|
$EXEC "echo -e \"127.0.0.1\t$NEW_HOSTNAME\" >> $HOSTS_TMP"
|
|
|
|
echo "Set hostname in {{docker_container_name}}$DEV container"
|
|
$EXEC "hostname '$NEW_HOSTNAME'"
|
|
$EXEC "cat $HOSTS_TMP > $HOSTS"
|
|
$EXEC "rm -f $HOSTS_TMP"
|
|
}
|
|
|
|
function getBootType()
|
|
{
|
|
# same code snippet in files/scripts/syncd.sh
|
|
case "$(cat /proc/cmdline)" in
|
|
*SONIC_BOOT_TYPE=warm*)
|
|
TYPE='warm'
|
|
;;
|
|
*SONIC_BOOT_TYPE=fastfast*)
|
|
TYPE='fastfast'
|
|
;;
|
|
*SONIC_BOOT_TYPE=fast*|*fast-reboot*)
|
|
TYPE='fast'
|
|
;;
|
|
*)
|
|
TYPE='cold'
|
|
esac
|
|
echo "${TYPE}"
|
|
}
|
|
|
|
function preStartAction()
|
|
{
|
|
{%- if docker_container_name == "database" %}
|
|
WARM_DIR=/host/warmboot
|
|
if [[ ("$BOOT_TYPE" == "warm" || "$BOOT_TYPE" == "fastfast") && -f $WARM_DIR/dump.rdb ]]; then
|
|
# Load redis content from /host/warmboot/dump.rdb
|
|
docker cp $WARM_DIR/dump.rdb database:/var/lib/redis/dump.rdb
|
|
else
|
|
# Create an emtpy file and overwrite any RDB if already there
|
|
echo -n > /tmp/dump.rdb
|
|
docker cp /tmp/dump.rdb database:/var/lib/redis/
|
|
fi
|
|
{%- elif docker_container_name == "snmp" %}
|
|
docker exec -i database redis-cli -n 6 HSET 'DEVICE_METADATA|localhost' chassis_serial_number $(decode-syseeprom -s)
|
|
vrfenabled=`/usr/bin/redis-cli -n 4 hget "MGMT_VRF_CONFIG|vrf_global" mgmtVrfEnabled`
|
|
v1SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestIp`
|
|
v1SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" DestPort`
|
|
v1Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" vrf`
|
|
v1Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v1TrapDest" Community`
|
|
v2SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestIp`
|
|
v2SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" DestPort`
|
|
v2Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" vrf`
|
|
v2Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v2TrapDest" Community`
|
|
v3SnmpTrapIp=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestIp`
|
|
v3SnmpTrapPort=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" DestPort`
|
|
v3Vrf=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" vrf`
|
|
v3Comm=`/usr/bin/redis-cli -n 4 hget "SNMP_TRAP_CONFIG|v3TrapDest" Community`
|
|
|
|
if [ "${v1SnmpTrapIp}" != "" ]
|
|
then
|
|
if [ "${v1Vrf}" != "None" ]
|
|
then
|
|
sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${v1SnmpTrapIp}:${v1SnmpTrapPort}%${v1Vrf} ${v1Comm}/" "/etc/sonic/snmp.yml"
|
|
else
|
|
sed -i "s/v1_trap_dest:.*/v1_trap_dest: ${v1SnmpTrapIp}:${v1SnmpTrapPort} ${v1Comm}/" "/etc/sonic/snmp.yml"
|
|
fi
|
|
else
|
|
sed -i "s/v1_trap_dest:.*/v1_trap_dest: NotConfigured/" "/etc/sonic/snmp.yml"
|
|
fi
|
|
if [ "${v2SnmpTrapIp}" != "" ]
|
|
then
|
|
if [ "${v2Vrf}" != "None" ]
|
|
then
|
|
sed -i "s/v2_trap_dest:.*/v2_trap_dest: ${v2SnmpTrapIp}:${v2SnmpTrapPort}%${v2Vrf} ${v2Comm}/" "/etc/sonic/snmp.yml"
|
|
else
|
|
sed -i "s/v2_trap_dest:.*/v2_trap_dest: ${v2SnmpTrapIp}:${v2SnmpTrapPort} ${v2Comm}/" "/etc/sonic/snmp.yml"
|
|
fi
|
|
else
|
|
sed -i "s/v2_trap_dest:.*/v2_trap_dest: NotConfigured/" "/etc/sonic/snmp.yml"
|
|
fi
|
|
if [ "${v3SnmpTrapIp}" != "" ]
|
|
then
|
|
if [ "${v3Vrf}" != "None" ]
|
|
then
|
|
sed -i "s/v3_trap_dest:.*/v3_trap_dest: ${v3SnmpTrapIp}:${v3SnmpTrapPort}%${v3Vrf} ${v3Comm}/" "/etc/sonic/snmp.yml"
|
|
else
|
|
sed -i "s/v3_trap_dest:.*/v3_trap_dest: ${v3SnmpTrapIp}:${v3SnmpTrapPort} ${v3Comm}/" "/etc/sonic/snmp.yml"
|
|
fi
|
|
else
|
|
sed -i "s/v3_trap_dest:.*/v3_trap_dest: NotConfigured/" "/etc/sonic/snmp.yml"
|
|
fi
|
|
|
|
echo -n "" > /tmp/snmpagentaddr.yml
|
|
keys=`/usr/bin/redis-cli -n 4 keys "SNMP_AGENT_ADDRESS_CONFIG|*"`
|
|
count=1
|
|
for key in $keys;do
|
|
ip=`echo $key|cut -d "|" -f2`
|
|
echo -n "snmp_agent_address_$count: $ip" >> /tmp/snmpagentaddr.yml
|
|
port=`echo $key|cut -d "|" -f3`
|
|
if [ -n "$port" ]; then
|
|
echo -n ":$port" >> /tmp/snmpagentaddr.yml
|
|
fi
|
|
vrf=`echo $key|cut -d "|" -f4`
|
|
if [ -n "$vrf" ]; then
|
|
echo -n "%$vrf" >> /tmp/snmpagentaddr.yml
|
|
fi
|
|
echo "" >> /tmp/snmpagentaddr.yml
|
|
count=$((count+1))
|
|
done
|
|
sed -i '/snmp_agent_address_*/d' /etc/sonic/snmp.yml
|
|
cat /tmp/snmpagentaddr.yml >> /etc/sonic/snmp.yml
|
|
{%- else %}
|
|
: # nothing
|
|
{%- endif %}
|
|
}
|
|
|
|
function postStartAction()
|
|
{
|
|
{%- if docker_container_name == "database" %}
|
|
if [ "$DEV" ]; then
|
|
link_namespace $DEV
|
|
fi
|
|
# Wait until redis starts
|
|
/usr/bin/docker exec database ping_pong_db_insts
|
|
if [[ ("$BOOT_TYPE" == "warm" || "$BOOT_TYPE" == "fastfast") && -f $WARM_DIR/dump.rdb ]]; then
|
|
rm -f $WARM_DIR/dump.rdb
|
|
else
|
|
# If there is a config db dump file, load it
|
|
if [ -r /etc/sonic/config_db.json ]; then
|
|
sonic-cfggen -j /etc/sonic/config_db.json --write-to-db
|
|
fi
|
|
|
|
if [[ "$BOOT_TYPE" == "fast" ]]; then
|
|
# set the key to expire in 3 minutes
|
|
redis-cli -n 6 SET "FAST_REBOOT|system" "1" "EX" "180"
|
|
fi
|
|
|
|
redis-cli -n 4 SET "CONFIG_DB_INITIALIZED" "1"
|
|
fi
|
|
|
|
if [[ -x /usr/bin/db_migrator.py ]]; then
|
|
# Migrate the DB to the latest schema version if needed
|
|
/usr/bin/db_migrator.py -o migrate
|
|
fi
|
|
{%- elif docker_container_name == "swss" %}
|
|
docker exec swss rm -f /ready # remove cruft
|
|
if [[ "$BOOT_TYPE" == "fast" ]] && [[ -d /host/fast-reboot ]]; then
|
|
test -e /host/fast-reboot/fdb.json && docker cp /host/fast-reboot/fdb.json swss:/
|
|
test -e /host/fast-reboot/arp.json && docker cp /host/fast-reboot/arp.json swss:/
|
|
test -e /host/fast-reboot/default_routes.json && docker cp /host/fast-reboot/default_routes.json swss:/
|
|
rm -fr /host/fast-reboot
|
|
fi
|
|
docker exec swss touch /ready # signal swssconfig.sh to go
|
|
{%- elif docker_container_name == "pmon" %}
|
|
|
|
DEVPATH="/usr/share/sonic/device"
|
|
REBOOT="platform_reboot"
|
|
PSENSOR="/usr/local/bin/platform_sensors.py"
|
|
if [ -d ${DEVPATH}/${PLATFORM} ] && [ -f $PSENSOR ]; then
|
|
exist=`docker exec -i pmon ls /usr/bin/platform_sensors.py "$@" 2>/dev/null`
|
|
if [ -z "$exist" ]; then
|
|
docker cp $PSENSOR pmon:/usr/bin/
|
|
fi
|
|
fi
|
|
{%- else %}
|
|
: # nothing
|
|
{%- endif %}
|
|
}
|
|
|
|
start() {
|
|
# Obtain boot type from kernel arguments
|
|
BOOT_TYPE=`getBootType`
|
|
|
|
# Obtain our platform as we will mount directories with these names in each docker
|
|
PLATFORM=`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform`
|
|
|
|
{%- if docker_container_name == "database" %}
|
|
# Don't mount HWSKU in {{docker_container_name}} container.
|
|
HWSKU=""
|
|
{%- else %}
|
|
# Obtain our HWSKU as we will mount directories with these names in each docker
|
|
HWSKU=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["hwsku"]'`
|
|
HOSTNAME=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["hostname"]'`
|
|
{%- endif %}
|
|
if [ -z "$HOSTNAME" ] || ! [[ $HOSTNAME =~ ^[a-zA-Z0-9.\-]*$ ]]; then
|
|
HOSTNAME=`hostname`
|
|
fi
|
|
|
|
DOCKERCHECK=`docker inspect --type container {{docker_container_name}}$DEV 2>/dev/null`
|
|
if [ "$?" -eq "0" ]; then
|
|
{%- if docker_container_name == "database" %}
|
|
DOCKERMOUNT=""
|
|
{%- else %}
|
|
DOCKERMOUNT=`getMountPoint "$DOCKERCHECK"`
|
|
{%- endif %}
|
|
if [ x"$DOCKERMOUNT" == x"$HWSKU" ]; then
|
|
{%- if docker_container_name == "database" %}
|
|
echo "Starting existing {{docker_container_name}}$DEV container"
|
|
{%- else %}
|
|
echo "Starting existing {{docker_container_name}}$DEV container with HWSKU $HWSKU"
|
|
{%- endif %}
|
|
preStartAction
|
|
docker start {{docker_container_name}}$DEV
|
|
postStartAction
|
|
CURRENT_HOSTNAME="$(docker exec {{docker_container_name}}$DEV hostname)"
|
|
if [ x"$HOSTNAME" != x"$CURRENT_HOSTNAME" ]; then
|
|
updateHostName "$HOSTNAME"
|
|
fi
|
|
updateHostName "$HOSTNAME"
|
|
exit $?
|
|
fi
|
|
|
|
# docker created with a different HWSKU, remove and recreate
|
|
echo "Removing obsolete {{docker_container_name}}$DEV container with HWSKU $DOCKERMOUNT"
|
|
docker rm -f {{docker_container_name}}$DEV
|
|
fi
|
|
|
|
{%- if docker_container_name == "database" %}
|
|
echo "Creating new {{docker_container_name}}$DEV container"
|
|
# if database_config exists in old_config, use it; otherwise use the default one in new image
|
|
if [ -f /etc/sonic/old_config/database_config.json ]; then
|
|
echo "Use database_config.json from old system..."
|
|
mv /etc/sonic/old_config/database_config.json /etc/sonic/
|
|
fi
|
|
{%- else %}
|
|
echo "Creating new {{docker_container_name}}$DEV container with HWSKU $HWSKU"
|
|
{%- endif %}
|
|
|
|
if [ -z "$DEV" ]; then
|
|
NET="host"
|
|
else
|
|
{%- if docker_container_name == "database" %}
|
|
NET="bridge"
|
|
{%- else %}
|
|
NET="container:database$DEV"
|
|
{%- endif %}
|
|
fi
|
|
|
|
{%- if sonic_asic_platform == "mellanox" %}
|
|
# TODO: Mellanox will remove the --tmpfs exception after SDK socket path changed in new SDK version
|
|
{%- endif %}
|
|
docker create {{docker_image_run_opt}} \
|
|
--net=$NET \
|
|
{%- if install_debug_image == "y" %}
|
|
-v /src:/src:ro -v /debug:/debug:rw \
|
|
{%- endif %}
|
|
{%- if '--log-driver=json-file' in docker_image_run_opt or '--log-driver' not in docker_image_run_opt %}
|
|
--log-opt max-size=2M --log-opt max-file=5 \
|
|
{%- endif %}
|
|
{%- if sonic_asic_platform == "mellanox" %}
|
|
{%- if docker_container_name == "syncd" %}
|
|
-v /var/log/mellanox/sniffer:/var/log/mellanox/sniffer:rw \
|
|
-v mlnx_sdk_socket:/tmp \
|
|
-v /dev/shm:/dev/shm:rw \
|
|
{%- elif docker_container_name == "pmon" %}
|
|
-v /var/run/hw-management:/var/run/hw-management:rw \
|
|
-v mlnx_sdk_socket:/tmp \
|
|
-v /dev/shm:/dev/shm:rw \
|
|
{%- else %}
|
|
--tmpfs /tmp \
|
|
{%- endif %}
|
|
{%- endif %}
|
|
-v /var/run/redis:/var/run/redis:rw \
|
|
-v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \
|
|
{%- if docker_container_name != "database" %}
|
|
-v /usr/share/sonic/device/$PLATFORM/$HWSKU:/usr/share/sonic/hwsku:ro \
|
|
{%- endif %}
|
|
{%- if sonic_asic_platform != "mellanox" %}
|
|
--tmpfs /tmp \
|
|
{%- endif %}
|
|
--tmpfs /var/tmp \
|
|
--name={{docker_container_name}}$DEV {{docker_image_name}}:latest || {
|
|
echo "Failed to docker run" >&1
|
|
exit 4
|
|
}
|
|
|
|
preStartAction
|
|
docker start {{docker_container_name}}
|
|
postStartAction
|
|
updateHostName "$HOSTNAME"
|
|
}
|
|
|
|
wait() {
|
|
docker wait {{docker_container_name}}$DEV
|
|
}
|
|
|
|
stop() {
|
|
docker stop {{docker_container_name}}$DEV
|
|
{%- if docker_container_name == "database" %}
|
|
ip netns delete "$NET_NS$DEV"
|
|
{%- endif %}
|
|
}
|
|
|
|
OP=$1
|
|
DEV=$2 # namespace/device number to operate on
|
|
NET_NS="asic" #name of the network namespace
|
|
|
|
case "$1" in
|
|
start|wait|stop)
|
|
$1
|
|
;;
|
|
updateHostName)
|
|
cmd=$1
|
|
shift 2
|
|
$cmd $@
|
|
;;
|
|
*)
|
|
echo "Usage: $0 {start namespace(optional)|wait namespace(optional)|stop namespace(optional)|updateHostName namespace(optional) new_hostname}"
|
|
exit 1
|
|
;;
|
|
esac
|