7bf0537c9e
sonic-cfggen is now using Unix Domain Socket for Redis DB. The socket is created using root account. Subsequently, services that are started as admin fails to start. This PR creates redis group and add admin user to redis group. It also grants read/write access on redis.sock for redis group members. signed-off-by: Tamer Ahmed <tamer.ahmed@microsoft.com>
377 lines
14 KiB
Django/Jinja
377 lines
14 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")"
|
|
|
|
PIDS=`ip netns pids "$NET_NS" 2>/dev/null`
|
|
if [ "$?" -eq "0" ]; then # namespace exists
|
|
if `echo $PIDS | grep --quiet -w $PID`; then # namespace is correctly linked
|
|
return 0
|
|
else # if it's incorrectly linked remove it
|
|
ip netns delete $NET_NS
|
|
fi
|
|
fi
|
|
|
|
ln -s /proc/$PID/ns/net /var/run/netns/$NET_NS
|
|
}
|
|
{%- endif %}
|
|
|
|
function updateSyslogConf()
|
|
{
|
|
# On multiNPU platforms, change the syslog target ip to docker0 ip to allow logs from containers
|
|
# running on the namespace to reach the rsyslog service running on the host
|
|
# Also update the container name
|
|
if [[ ($NUM_ASIC -gt 1) ]]; then
|
|
TARGET_IP=$(docker network inspect bridge --format={{ "'{{(index .IPAM.Config 0).Gateway}}'" }})
|
|
CONTAINER_NAME="{{docker_container_name}}$DEV"
|
|
TMP_FILE="/tmp/rsyslog.$CONTAINER_NAME.conf"
|
|
|
|
sonic-cfggen -t /usr/share/sonic/templates/rsyslog-container.conf.j2 -a "{\"target_ip\": \"$TARGET_IP\", \"container_name\": \"$CONTAINER_NAME\" }" > $TMP_FILE
|
|
docker cp $TMP_FILE {{docker_container_name}}$DEV:/etc/rsyslog.conf
|
|
rm -rf $TMP_FILE
|
|
fi
|
|
}
|
|
|
|
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 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$DEV:/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$DEV:/var/lib/redis/
|
|
fi
|
|
{%- elif docker_container_name == "snmp" %}
|
|
$SONIC_DB_CLI STATE_DB HSET 'DEVICE_METADATA|localhost' chassis_serial_number $(decode-syseeprom -s)
|
|
{%- else %}
|
|
: # nothing
|
|
{%- endif %}
|
|
updateSyslogConf
|
|
}
|
|
|
|
function postStartAction()
|
|
{
|
|
{%- if docker_container_name == "database" %}
|
|
if [ "$DEV" ]; then
|
|
docker exec -i database$DEV sysctl --system -e
|
|
link_namespace $DEV
|
|
fi
|
|
|
|
# Wait until supervisord and redis starts. This change is needed
|
|
# because now database_config.json is jinja2 templated based
|
|
# and by the time file gets generated if we do redis ping
|
|
# then we catch python exception of file not valid
|
|
# that comes to syslog which is unwanted so wait till database
|
|
# config is ready and then ping
|
|
until [[ ($(docker exec -i database$DEV pgrep -x -c supervisord) -gt 0) && ($($SONIC_DB_CLI PING | grep -c PONG) -gt 0) ]]; do
|
|
sleep 1;
|
|
done
|
|
|
|
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.json dump file, load it.
|
|
if [ -r /etc/sonic/config_db$DEV.json ]; then
|
|
if [ -r /etc/sonic/init_cfg.json ]; then
|
|
$SONIC_CFGGEN -j /etc/sonic/init_cfg.json -j /etc/sonic/config_db$DEV.json --write-to-db
|
|
else
|
|
$SONIC_CFGGEN -j /etc/sonic/config_db$DEV.json --write-to-db
|
|
fi
|
|
fi
|
|
|
|
if [[ "$BOOT_TYPE" == "fast" ]]; then
|
|
# set the key to expire in 3 minutes
|
|
$SONIC_DB_CLI STATE_DB SET "FAST_REBOOT|system" "1" "EX" "180"
|
|
fi
|
|
|
|
$SONIC_DB_CLI CONFIG_DB SET "CONFIG_DB_INITIALIZED" "1"
|
|
fi
|
|
|
|
if [[ -x /usr/bin/db_migrator.py ]]; then
|
|
# Migrate the DB to the latest schema version if needed
|
|
if [ -z "$DEV" ]; then
|
|
/usr/bin/db_migrator.py -o migrate
|
|
fi
|
|
fi
|
|
# Add redis UDS to the redis group and give read/write access to the group
|
|
REDIS_SOCK="/var/run/redis${DEV}/redis.sock"
|
|
chgrp -f redis $REDIS_SOCK && chmod -f 0760 $REDIS_SOCK
|
|
{%- elif docker_container_name == "swss" %}
|
|
docker exec swss$DEV 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$DEV:/
|
|
test -e /host/fast-reboot/arp.json && docker cp /host/fast-reboot/arp.json swss$DEV:/
|
|
test -e /host/fast-reboot/default_routes.json && docker cp /host/fast-reboot/default_routes.json swss$DEV:/
|
|
rm -fr /host/fast-reboot
|
|
fi
|
|
docker exec swss$DEV 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`
|
|
|
|
# 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
|
|
|
|
{%- 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"]'`
|
|
{%- endif %}
|
|
|
|
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
|
|
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 [ -z "$DEV" ]; then
|
|
# if database_global exists in old_config, use it; otherwise use the default one in new image
|
|
if [ -f /etc/sonic/old_config/database_global.json ]; then
|
|
echo "Use database_global.json from old system..."
|
|
mv /etc/sonic/old_config/database_global.json /etc/sonic/
|
|
fi
|
|
fi
|
|
# 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$DEV.json ]; then
|
|
echo "Use database_config.json from old system..."
|
|
mv /etc/sonic/old_config/database_config$DEV.json /etc/sonic/
|
|
fi
|
|
{%- else %}
|
|
echo "Creating new {{docker_container_name}}$DEV container with HWSKU $HWSKU"
|
|
{%- endif %}
|
|
|
|
# In Multi ASIC platforms the global database config file database_global.json will exist.
|
|
# Parse the file and get the include path for the database_config.json files used in
|
|
# various namesapces. The database_config paths are relative to the DIR of SONIC_DB_GLOBAL_JSON.
|
|
SONIC_DB_GLOBAL_JSON="/var/run/redis/sonic-db/database_global.json"
|
|
if [ -f "$SONIC_DB_GLOBAL_JSON" ]; then
|
|
# TODO Create a separate python script with the below logic and invoke it here.
|
|
redis_dir_list=`/usr/bin/python -c "import sys; import os; import json; f=open(sys.argv[1]); \
|
|
global_db_dir = os.path.dirname(sys.argv[1]); data=json.load(f); \
|
|
print(\" \".join([os.path.normpath(global_db_dir+'/'+elem['include']).partition('sonic-db')[0]\
|
|
for elem in data['INCLUDES'] if 'namespace' in elem])); f.close()" $SONIC_DB_GLOBAL_JSON`
|
|
fi
|
|
|
|
if [ -z "$DEV" ]; then
|
|
NET="host"
|
|
|
|
# For Multi-ASIC platform we have to mount the redis paths for database instances running in different
|
|
# namespaces, into the single instance dockers like snmp, pmon on linux host. These global dockers
|
|
# will need to get/set tables from databases in different namespaces.
|
|
# /var/run/redis0 ---> mounted as --> /var/run/redis0
|
|
# /var/run/redis1 ---> mounted as --> /var/run/redis1 .. etc
|
|
# The below logic extracts the base DIR's where database_config.json's for various namespaces exist.
|
|
# redis_dir_list is a string of form "/var/run/redis0/ /var/run/redis1/ /var/run/redis2/"
|
|
|
|
{%- if docker_container_name != "database" %}
|
|
if [ -n "$redis_dir_list" ]; then
|
|
for redis_dir in $redis_dir_list
|
|
do
|
|
REDIS_MNT=$REDIS_MNT" -v $redis_dir:$redis_dir:rw "
|
|
done
|
|
fi
|
|
{%- endif %}
|
|
else
|
|
# This part of code is applicable for Multi-ASIC platforms. Here we mount the namespace specific
|
|
# redis directory into the docker running in that namespace. Below eg: is for namespace "asic1"
|
|
# /var/run/redis1 ---> mounted as --> /var/run/redis1
|
|
# redis_dir_list is a string of form "/var/run/redis0/ /var/run/redis1/ /var/run/redis2/"
|
|
if [ -n "$redis_dir_list" ]; then
|
|
id=`expr $DEV + 1`
|
|
redis_dir=`echo $redis_dir_list | cut -d " " -f $id`
|
|
REDIS_MNT=" -v $redis_dir:$redis_dir:rw "
|
|
fi
|
|
|
|
{%- if docker_container_name == "database" %}
|
|
NET="bridge"
|
|
{%- else %}
|
|
NET="container:database$DEV"
|
|
{%- endif %}
|
|
fi
|
|
{%- if docker_container_name == "bgp" %}
|
|
if [ "$DEV" ]; then
|
|
if [ ! -d "/etc/sonic/frr/$DEV" ]; then
|
|
mkdir /etc/sonic/frr/$DEV
|
|
cp -r /etc/sonic/frr/*.conf /etc/sonic/frr/$DEV
|
|
fi
|
|
fi
|
|
{%- endif %}
|
|
{%- 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 \
|
|
--uts=host \{# W/A: this should be set per-docker, for those dockers which really need host's UTS namespace #}
|
|
{%- 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:/var/run/sx_sdk \
|
|
-v mlnx_sdk_ready:/tmp \
|
|
-v /dev/shm:/dev/shm:rw \
|
|
-e SX_API_SOCKET_FILE=/var/run/sx_sdk/sx_api.sock \
|
|
{%- elif docker_container_name == "pmon" %}
|
|
-v /var/run/hw-management:/var/run/hw-management:rw \
|
|
-v mlnx_sdk_socket:/var/run/sx_sdk \
|
|
-v mlnx_sdk_ready:/tmp \
|
|
-e SX_API_SOCKET_FILE=/var/run/sx_sdk/sx_api.sock \
|
|
-v /dev/shm:/dev/shm:rw \
|
|
{%- else %}
|
|
--tmpfs /tmp \
|
|
{%- endif %}
|
|
{%- endif %}
|
|
{%- if sonic_asic_platform == "broadcom" %}
|
|
{%- if docker_container_name == "syncd" %}
|
|
-v /var/run/docker-syncd$DEV:/var/run/sswsyncd \
|
|
{%- endif %}
|
|
{%- endif %}
|
|
{%- if docker_container_name == "bgp" %}
|
|
-v /etc/sonic/frr/$DEV:/etc/frr:rw \
|
|
{%- endif %}
|
|
-v /var/run/redis$DEV:/var/run/redis:rw \
|
|
$REDIS_MNT \
|
|
-v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \
|
|
{%- if docker_container_name != "database" %}
|
|
-v /usr/share/sonic/device/$PLATFORM/$HWSKU/$DEV:/usr/share/sonic/hwsku:ro \
|
|
{%- endif %}
|
|
{%- if sonic_asic_platform != "mellanox" %}
|
|
--tmpfs /tmp \
|
|
{%- endif %}
|
|
--tmpfs /var/tmp \
|
|
--env "NAMESPACE_ID"="$DEV" \
|
|
--env "NAMESPACE_PREFIX"="$NAMESPACE_PREFIX" \
|
|
--env "NAMESPACE_COUNT"=$NUM_ASIC \
|
|
--name={{docker_container_name}}$DEV {{docker_image_name}}:latest || {
|
|
echo "Failed to docker run" >&1
|
|
exit 4
|
|
}
|
|
|
|
preStartAction
|
|
docker start {{docker_container_name}}$DEV
|
|
postStartAction
|
|
}
|
|
|
|
wait() {
|
|
docker wait {{docker_container_name}}$DEV
|
|
}
|
|
|
|
stop() {
|
|
docker stop {{docker_container_name}}$DEV
|
|
{%- if docker_container_name == "database" %}
|
|
if [ "$DEV" ]; then
|
|
ip netns delete "$NET_NS"
|
|
fi
|
|
{%- endif %}
|
|
}
|
|
|
|
OP=$1
|
|
DEV=$2 # namespace/device number to operate on
|
|
NAMESPACE_PREFIX="asic"
|
|
if [ "$DEV" ]; then
|
|
NET_NS="$NAMESPACE_PREFIX$DEV" #name of the network namespace
|
|
|
|
SONIC_CFGGEN="sonic-cfggen -n $NET_NS"
|
|
SONIC_DB_CLI="sonic-db-cli -n $NET_NS"
|
|
else
|
|
NET_NS=""
|
|
SONIC_CFGGEN="sonic-cfggen"
|
|
SONIC_DB_CLI="sonic-db-cli"
|
|
fi
|
|
|
|
case "$1" in
|
|
start|wait|stop)
|
|
$1
|
|
;;
|
|
*)
|
|
echo "Usage: $0 {start namespace(optional)|wait namespace(optional)|stop namespace(optional)}"
|
|
exit 1
|
|
;;
|
|
esac
|