Skip to content

Commit

Permalink
[docker-teamd]: Manage teamd and teamsyncd processes with supervisor (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jleveque authored Nov 13, 2017
1 parent 3e03df7 commit a6edef2
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 64 deletions.
7 changes: 3 additions & 4 deletions dockers/docker-teamd/Dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ RUN dpkg -i \
debs/{{ deb }}{{' '}}
{%- endfor %}

COPY ["start.sh", "teamd.sh", "/usr/bin/"]
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]
COPY ["teamd.j2", "/usr/share/sonic/templates/"]
COPY ["docker-teamd-init.sh", "docker-teamd-start.sh", "teamd.sh", "/usr/bin/"]
COPY ["docker-teamd.supervisord.conf.j2", "teamd.j2", "/usr/share/sonic/templates/"]

RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y
RUN rm -rf /debs

ENTRYPOINT ["/usr/bin/supervisord"]
ENTRYPOINT ["/usr/bin/docker-teamd-init.sh"]
43 changes: 43 additions & 0 deletions dockers/docker-teamd/docker-teamd-init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash

TEAMD_CONF_PATH="/etc/teamd"

rm -rf $TEAMD_CONF_PATH
mkdir -p $TEAMD_CONF_PATH

SONIC_ASIC_TYPE=$(sonic-cfggen -y /etc/sonic/sonic_version.yml -v asic_type)
MAC_ADDRESS=$(ip link show eth0 | grep ether | awk '{print $2}')

# Align last byte
if [ "$SONIC_ASIC_TYPE" == "mellanox" -o "$SONIC_ASIC_TYPE" == "centec" ]; then
last_byte=$(python -c "print '$MAC_ADDRESS'[-2:]")
aligned_last_byte=$(python -c "print format(int(int('$last_byte', 16) & 0b11000000), '02x')") # put mask and take away the 0x prefix
MAC_ADDRESS=$(python -c "print '$MAC_ADDRESS'[:-2] + '$aligned_last_byte'") # put aligned byte into the end of MAC
fi

for pc in `sonic-cfggen -d -v "PORTCHANNEL.keys() | join(' ') if PORTCHANNEL"`; do
sonic-cfggen -d -a '{"pc":"'$pc'","hwaddr":"'$MAC_ADDRESS'"}' -t /usr/share/sonic/templates/teamd.j2 > $TEAMD_CONF_PATH/$pc.conf
# bring down all member ports before starting teamd
for member in $(sonic-cfggen -d -v "PORTCHANNEL['$pc']['members'] | join(' ')" ); do
if [ -L /sys/class/net/$member ]; then
ip link set $member down
fi
done
done

# Create a Python dictionary where the key is the Jinja2 variable name
# "lags" and the value is a list of dctionaries containing the name of
# the LAG and the path of the LAG config file. Then output this in
# JSON format, as we will pass it to sonic-cfggen as additional data
# below for generating the supervisord config file.
# Example output: {"lags": [{"name": "PortChannel1", "file": "/etc/teamd/PortChannel1.conf"}, {"name": "PortChannel2", "file": "/etc/teamd/PortChannel2.conf"}]}
LAG_INFO_DICT=$(python -c "import json,os,sys; lags_dict = {}; lags_dict['lags'] = [{'name': os.path.basename(file).split('.')[0], 'file': os.path.join('${TEAMD_CONF_PATH}', file)} for file in sorted(os.listdir('${TEAMD_CONF_PATH}'))]; sys.stdout.write(json.dumps(lags_dict))")

# Generate supervisord config file
mkdir -p /etc/supervisor/conf.d/
sonic-cfggen -d -a "${LAG_INFO_DICT}" -t /usr/share/sonic/templates/docker-teamd.supervisord.conf.j2 > /etc/supervisor/conf.d/docker-teamd.supervisord.conf

# The Docker container should start this script as PID 1, so now that we
# have generated the proper supervisord configuration, we exec supervisord
# so that it runs as PID 1 for the duration of the container's lifetime
exec /usr/bin/supervisord
9 changes: 9 additions & 0 deletions dockers/docker-teamd/docker-teamd-start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

rm -f /var/run/rsyslogd.pid

supervisorctl start rsyslogd

supervisorctl start teamd:*

supervisorctl start teamsyncd
52 changes: 52 additions & 0 deletions dockers/docker-teamd/docker-teamd.supervisord.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[supervisord]
logfile_maxbytes=1MB
logfile_backups=2
nodaemon=true

[program:docker-teamd-start.sh]
command=/usr/bin/docker-teamd-start.sh
priority=1
autostart=true
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[program:rsyslogd]
command=/usr/sbin/rsyslogd -n
priority=2
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

{# If there are LAGs... #}
{% if lags -%}
[group:teamd]
programs=
{%- set add_preceding_comma = { 'flag': False } -%}
{%- for lag in lags -%}
{%- if add_preceding_comma.flag %},{% endif -%}
{%- set _dummy = add_preceding_comma.update({'flag': True}) -%}
teamd-{{ lag['name'] }}
{%- endfor %}

{# Create a program entry for each teamd instance #}
{% for lag in lags %}

[program:teamd-{{ lag['name'] }}]
command=/usr/bin/teamd.sh {{ lag['file'] }}
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
{% endfor %}

[program:teamsyncd]
command=/usr/bin/teamsyncd
priority=4
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
{% endif %}
35 changes: 0 additions & 35 deletions dockers/docker-teamd/start.sh

This file was deleted.

27 changes: 7 additions & 20 deletions dockers/docker-teamd/teamd.sh
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
#!/usr/bin/env bash

TEAMD_CONF_PATH=/etc/teamd

function start_app {
rm -f /var/run/teamd/*
if [ "$(ls -A $TEAMD_CONF_PATH)" ]; then
for f in $TEAMD_CONF_PATH/*; do
teamd -f $f -d
done
fi
teamsyncd &
}
TEAMD_CONF_FILE=$1

function clean_up {
if [ "$(ls -A $TEAMD_CONF_PATH)" ]; then
for f in $TEAMD_CONF_PATH/*; do
teamd -f $f -k
done
fi
pkill -9 teamsyncd
exit
teamd -f $TEAMD_CONF_FILE -k
exit $?
}

trap clean_up SIGTERM SIGKILL

start_app
read
teamd -f $TEAMD_CONF_FILE &
TEAMD_PID=$!
wait $TEAMD_PID
exit $?
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[program:teamd]
command=/usr/bin/teamd.sh
[group:isc-dhcp-relay]
programs=isc-dhcp-relay-Vlan1000

[program:isc-dhcp-relay-Vlan1000]
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -i Vlan1000 -i PortChannel02 -i PortChannel03 -i PortChannel04 -i PortChannel01 192.0.0.1 192.0.0.2
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog


Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
[supervisord]
logfile_maxbytes=1MB
logfile_backups=2
nodaemon=true

[program:docker-teamd-start.sh]
command=/usr/bin/docker-teamd-start.sh
priority=1
autostart=true
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[program:rsyslogd]
command=/usr/sbin/rsyslogd -n
priority=2
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[group:teamd]
programs=teamd-PortChannel01,teamd-PortChannel02,teamd-PortChannel03,teamd-PortChannel04

[program:teamd-PortChannel01]
command=/usr/bin/teamd.sh /sonic/src/sonic-config-engine/tests/sample_output/t0_sample_output/PortChannel01.conf
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[program:teamd-PortChannel02]
command=/usr/bin/teamd.sh /sonic/src/sonic-config-engine/tests/sample_output/t0_sample_output/PortChannel02.conf
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[program:teamd-PortChannel03]
command=/usr/bin/teamd.sh /sonic/src/sonic-config-engine/tests/sample_output/t0_sample_output/PortChannel03.conf
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[program:teamd-PortChannel04]
command=/usr/bin/teamd.sh /sonic/src/sonic-config-engine/tests/sample_output/t0_sample_output/PortChannel04.conf
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

[program:teamsyncd]
command=/usr/bin/teamsyncd
priority=4
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog

28 changes: 28 additions & 0 deletions src/sonic-config-engine/tests/sample_output/wait_for_intf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

function wait_until_iface_exists
{
IFACE=$1

echo "Waiting for interface ${IFACE}..."

# Wait for the interface to come up (i.e., 'ip link show' returns 0)
until ip link show $IFACE > /dev/null 2>&1; do
sleep 1
done

echo "Interface ${IFACE} is created"
}


# Wait for all interfaces to come up before starting the DHCP relay
wait_until_iface_exists Vlan1000
wait_until_iface_exists PortChannel04
wait_until_iface_exists PortChannel02
wait_until_iface_exists PortChannel03
wait_until_iface_exists PortChannel03
wait_until_iface_exists PortChannel01
wait_until_iface_exists PortChannel02
wait_until_iface_exists PortChannel04
wait_until_iface_exists PortChannel01

30 changes: 27 additions & 3 deletions src/sonic-config-engine/tests/test_j2files.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ def test_alias_map(self):
data = json.loads(output)
self.assertEqual(data["Ethernet4"], "fortyGigE0/4")

def test_dhcp_relay(self):
# Test generation of wait_for_intf.sh
template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', 'wait_for_intf.sh.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + template_path + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'wait_for_intf.sh'), self.output_file))

# Test generation of docker-dhcp-relay.supervisord.conf
template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-dhcp-relay', 'docker-dhcp-relay.supervisord.conf.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + template_path + ' > ' + self.output_file
self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'docker-dhcp-relay.supervisord.conf'), self.output_file))

def test_lldp(self):
lldpd_conf_template = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-lldp-sv2', 'lldpd.conf.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + lldpd_conf_template + ' > ' + self.output_file
Expand All @@ -49,7 +62,7 @@ def test_render_teamd(self, pc, minigraph, sample_output):

# Test T0 minigraph
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -v "PORTCHANNEL.keys() | join(\' \') if PORTCHANNEL"'
output = self.run_script(argument) # Mock the output via config.sh in docker-teamd
output = self.run_script(argument) # Mock the output via docker-teamd-init.sh in docker-teamd
pc_list = output.split()

for i in range(1, 5):
Expand All @@ -58,16 +71,27 @@ def test_render_teamd(self, pc, minigraph, sample_output):
sample_output = os.path.join(self.test_dir, 'sample_output', 't0_sample_output', pc_name + '.conf')
test_render_teamd(self, pc_name, self.t0_minigraph, sample_output)

# Test port channel test minigraph
# Test port channel test minigraph (for testing proper 'min_ports' attribute generation)
argument = '-m ' + self.pc_minigraph + ' -p ' + self.t0_port_config + ' -v "PORTCHANNEL.keys() | join(\' \') if PORTCHANNEL"'
output = self.run_script(argument) # Mock the output via config.sh in docker-teamd
output = self.run_script(argument) # Mock the output via docker-teamd-init.sh in docker-teamd
pc_list = output.split()

pc_name = 'PortChannel01'
self.assertTrue(pc_name in pc_list)
sample_output = os.path.join(self.test_dir, 'sample_output', 'pc_sample_output', pc_name + '.conf')
test_render_teamd(self, pc_name, self.pc_minigraph, sample_output)

# Test generation of docker-teamd.supervisord.conf
template_path = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-teamd', 'docker-teamd.supervisord.conf.j2')
teamd_conf_dir = os.path.join(self.test_dir, 'sample_output', 't0_sample_output')

lags_dict = {}
lags_dict['lags'] = [{'name': os.path.basename(file).split('.')[0], 'file': os.path.join(teamd_conf_dir, file)} for file in sorted(os.listdir(teamd_conf_dir))]
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -a \'' + json.dumps(lags_dict) + '\' -t ' + template_path + ' > ' + self.output_file

self.run_script(argument)
self.assertTrue(filecmp.cmp(os.path.join(self.test_dir, 'sample_output', 'docker-teamd.supervisord.conf'), self.output_file))

def test_ipinip(self):
ipinip_file = os.path.join(self.test_dir, '..', '..', '..', 'dockers', 'docker-orchagent', 'ipinip.json.j2')
argument = '-m ' + self.t0_minigraph + ' -p ' + self.t0_port_config + ' -t ' + ipinip_file + ' > ' + self.output_file
Expand Down

0 comments on commit a6edef2

Please sign in to comment.