[containercfgd] Add containercfgd and syslog rate limit configuration support (#12489)
* [containercfgd] Add containercfgd and syslog rate limit configuration support * Fix build issue * Fix checker issue * Fix review comment * Fix review comment * Update containercfgd.py
This commit is contained in:
parent
ffad305fd3
commit
3b3837a636
@ -81,7 +81,7 @@ RUN pip3 install supervisor==4.2.1
|
|||||||
# Add support for supervisord to handle startup dependencies
|
# Add support for supervisord to handle startup dependencies
|
||||||
RUN pip3 install supervisord-dependent-startup==1.4.0
|
RUN pip3 install supervisord-dependent-startup==1.4.0
|
||||||
|
|
||||||
RUN mkdir -p /etc/supervisor /var/log/supervisor
|
RUN mkdir -p /var/log/supervisor /etc/supervisor/conf.d
|
||||||
|
|
||||||
RUN apt-get -y purge \
|
RUN apt-get -y purge \
|
||||||
exim4 \
|
exim4 \
|
||||||
@ -104,10 +104,10 @@ RUN apt-get clean -y && \
|
|||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* ~/.cache
|
rm -rf /var/lib/apt/lists/* /tmp/* ~/.cache
|
||||||
|
|
||||||
COPY ["etc/rsyslog.conf", "/etc/rsyslog.conf"]
|
|
||||||
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
||||||
COPY ["root/.vimrc", "/root/.vimrc"]
|
COPY ["root/.vimrc", "/root/.vimrc"]
|
||||||
|
|
||||||
RUN ln /usr/bin/vim.tiny /usr/bin/vim
|
RUN ln /usr/bin/vim.tiny /usr/bin/vim
|
||||||
|
|
||||||
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
||||||
|
COPY ["etc/supervisor/containercfgd.conf", "/etc/supervisor/conf.d/"]
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
[program:containercfgd]
|
||||||
|
command=python3 /usr/local/bin/containercfgd
|
||||||
|
priority=99
|
||||||
|
autostart=false
|
||||||
|
autorestart=unexpected
|
||||||
|
stdout_logfile=syslog
|
||||||
|
stderr_logfile=syslog
|
||||||
|
dependent_startup=true
|
||||||
|
dependent_startup_wait_for=rsyslogd:running
|
@ -94,7 +94,7 @@ RUN pip3 install supervisor==4.2.1
|
|||||||
# Add support for supervisord to handle startup dependencies
|
# Add support for supervisord to handle startup dependencies
|
||||||
RUN pip3 install supervisord-dependent-startup==1.4.0
|
RUN pip3 install supervisord-dependent-startup==1.4.0
|
||||||
|
|
||||||
RUN mkdir -p /etc/supervisor /var/log/supervisor
|
RUN mkdir -p /var/log/supervisor /etc/supervisor/conf.d
|
||||||
|
|
||||||
RUN apt-get -y purge \
|
RUN apt-get -y purge \
|
||||||
exim4 \
|
exim4 \
|
||||||
@ -117,10 +117,10 @@ RUN apt-get clean -y && \
|
|||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/* ~/.cache/
|
rm -rf /var/lib/apt/lists/* /tmp/* ~/.cache/
|
||||||
|
|
||||||
COPY ["etc/rsyslog.conf", "/etc/rsyslog.conf"]
|
|
||||||
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
||||||
COPY ["root/.vimrc", "/root/.vimrc"]
|
COPY ["root/.vimrc", "/root/.vimrc"]
|
||||||
|
|
||||||
RUN ln /usr/bin/vim.tiny /usr/bin/vim
|
RUN ln /usr/bin/vim.tiny /usr/bin/vim
|
||||||
|
|
||||||
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
||||||
|
COPY ["etc/supervisor/containercfgd.conf", "/etc/supervisor/conf.d/"]
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
[program:containercfgd]
|
||||||
|
command=python3 /usr/local/bin/containercfgd
|
||||||
|
priority=99
|
||||||
|
autostart=false
|
||||||
|
autorestart=unexpected
|
||||||
|
stdout_logfile=syslog
|
||||||
|
stderr_logfile=syslog
|
||||||
|
dependent_startup=true
|
||||||
|
dependent_startup_wait_for=rsyslogd:running
|
@ -90,7 +90,7 @@ RUN pip install supervisor>=3.4.0
|
|||||||
# Add support for supervisord to handle startup dependencies
|
# Add support for supervisord to handle startup dependencies
|
||||||
RUN pip install supervisord-dependent-startup==1.4.0
|
RUN pip install supervisord-dependent-startup==1.4.0
|
||||||
|
|
||||||
RUN mkdir -p /etc/supervisor /var/log/supervisor
|
RUN mkdir -p /var/log/supervisor /etc/supervisor/conf.d
|
||||||
|
|
||||||
RUN apt-get -y purge \
|
RUN apt-get -y purge \
|
||||||
exim4 \
|
exim4 \
|
||||||
@ -113,10 +113,10 @@ RUN apt-get clean -y && \
|
|||||||
apt-get autoremove -y && \
|
apt-get autoremove -y && \
|
||||||
rm -rf /var/lib/apt/lists/* /tmp/*
|
rm -rf /var/lib/apt/lists/* /tmp/*
|
||||||
|
|
||||||
COPY ["etc/rsyslog.conf", "/etc/rsyslog.conf"]
|
|
||||||
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
||||||
COPY ["root/.vimrc", "/root/.vimrc"]
|
COPY ["root/.vimrc", "/root/.vimrc"]
|
||||||
|
|
||||||
RUN ln /usr/bin/vim.tiny /usr/bin/vim
|
RUN ln /usr/bin/vim.tiny /usr/bin/vim
|
||||||
|
|
||||||
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
||||||
|
COPY ["etc/supervisor/containercfgd.conf", "/etc/supervisor/conf.d/"]
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
[program:containercfgd]
|
||||||
|
command=python /usr/local/bin/containercfgd
|
||||||
|
priority=99
|
||||||
|
autostart=false
|
||||||
|
autorestart=unexpected
|
||||||
|
stdout_logfile=syslog
|
||||||
|
stderr_logfile=syslog
|
||||||
|
dependent_startup=true
|
||||||
|
dependent_startup_wait_for=rsyslogd:running
|
@ -49,7 +49,6 @@ RUN apt-get -y install \
|
|||||||
rsyslog \
|
rsyslog \
|
||||||
less
|
less
|
||||||
|
|
||||||
COPY ["etc/rsyslog.conf", "/etc/rsyslog.conf"]
|
|
||||||
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
COPY ["etc/rsyslog.d/*", "/etc/rsyslog.d/"]
|
||||||
COPY ["root/.vimrc", "/root/.vimrc"]
|
COPY ["root/.vimrc", "/root/.vimrc"]
|
||||||
|
|
||||||
@ -64,10 +63,11 @@ RUN pip install wheel
|
|||||||
# Install supervisor
|
# Install supervisor
|
||||||
RUN pip install supervisor>=3.4.0
|
RUN pip install supervisor>=3.4.0
|
||||||
|
|
||||||
RUN mkdir -p /etc/supervisor
|
RUN mkdir -p /etc/supervisor/conf.d
|
||||||
RUN mkdir -p /var/log/supervisor
|
RUN mkdir -p /var/log/supervisor
|
||||||
|
|
||||||
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
COPY ["etc/supervisor/supervisord.conf", "/etc/supervisor/"]
|
||||||
|
COPY ["etc/supervisor/containercfgd.conf", "/etc/supervisor/conf.d/"]
|
||||||
|
|
||||||
RUN apt-get -y purge \
|
RUN apt-get -y purge \
|
||||||
exim4 \
|
exim4 \
|
||||||
|
9
dockers/docker-base/etc/supervisor/containercfgd.conf
Normal file
9
dockers/docker-base/etc/supervisor/containercfgd.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[program:containercfgd]
|
||||||
|
command=python /usr/local/bin/containercfgd
|
||||||
|
priority=99
|
||||||
|
autostart=false
|
||||||
|
autorestart=unexpected
|
||||||
|
stdout_logfile=syslog
|
||||||
|
stderr_logfile=syslog
|
||||||
|
dependent_startup=true
|
||||||
|
dependent_startup_wait_for=rsyslogd:running
|
@ -3,6 +3,15 @@ logfile_maxbytes=1MB
|
|||||||
logfile_backups=2
|
logfile_backups=2
|
||||||
nodaemon=true
|
nodaemon=true
|
||||||
|
|
||||||
|
[eventlistener:dependent-startup]
|
||||||
|
command=python3 -m supervisord_dependent_startup
|
||||||
|
autostart=true
|
||||||
|
autorestart=unexpected
|
||||||
|
startretries=0
|
||||||
|
exitcodes=0,3
|
||||||
|
events=PROCESS_STATE
|
||||||
|
buffer_size=1024
|
||||||
|
|
||||||
[eventlistener:supervisor-proc-exit-listener]
|
[eventlistener:supervisor-proc-exit-listener]
|
||||||
command=/usr/bin/supervisor-proc-exit-listener --container-name database
|
command=/usr/bin/supervisor-proc-exit-listener --container-name database
|
||||||
events=PROCESS_STATE_EXITED,PROCESS_STATE_RUNNING
|
events=PROCESS_STATE_EXITED,PROCESS_STATE_RUNNING
|
||||||
@ -13,14 +22,15 @@ buffer_size=1024
|
|||||||
[program:rsyslogd]
|
[program:rsyslogd]
|
||||||
command=/usr/sbin/rsyslogd -n -iNONE
|
command=/usr/sbin/rsyslogd -n -iNONE
|
||||||
priority=1
|
priority=1
|
||||||
autostart=true
|
autostart=false
|
||||||
autorestart=false
|
autorestart=false
|
||||||
stdout_logfile=syslog
|
stdout_logfile=syslog
|
||||||
stderr_logfile=syslog
|
stderr_logfile=syslog
|
||||||
|
dependent_startup=true
|
||||||
|
|
||||||
{% if INSTANCES %}
|
{% if INSTANCES %}
|
||||||
{% for redis_inst, redis_items in INSTANCES.items() %}
|
{% for redis_inst, redis_items in INSTANCES.items() %}
|
||||||
[program: {{ redis_inst }}]
|
[program:{{ redis_inst }}]
|
||||||
{% if redis_items['hostname'] != '127.0.0.1' and redis_inst != 'redis_chassis' %}
|
{% if redis_items['hostname'] != '127.0.0.1' and redis_inst != 'redis_chassis' %}
|
||||||
{%- set LOOPBACK_IP = '127.0.0.1' -%}
|
{%- set LOOPBACK_IP = '127.0.0.1' -%}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
@ -28,17 +38,21 @@ stderr_logfile=syslog
|
|||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
command=/bin/bash -c "{ [[ -s /var/lib/{{ redis_inst }}/dump.rdb ]] || rm -f /var/lib/{{ redis_inst }}/dump.rdb; } && mkdir -p /var/lib/{{ redis_inst }} && exec /usr/bin/redis-server /etc/redis/redis.conf --bind {{ LOOPBACK_IP }} {{ redis_items['hostname'] }} --port {{ redis_items['port'] }} --unixsocket {{ redis_items['unix_socket_path'] }} --pidfile /var/run/redis/{{ redis_inst }}.pid --dir /var/lib/{{ redis_inst }}"
|
command=/bin/bash -c "{ [[ -s /var/lib/{{ redis_inst }}/dump.rdb ]] || rm -f /var/lib/{{ redis_inst }}/dump.rdb; } && mkdir -p /var/lib/{{ redis_inst }} && exec /usr/bin/redis-server /etc/redis/redis.conf --bind {{ LOOPBACK_IP }} {{ redis_items['hostname'] }} --port {{ redis_items['port'] }} --unixsocket {{ redis_items['unix_socket_path'] }} --pidfile /var/run/redis/{{ redis_inst }}.pid --dir /var/lib/{{ redis_inst }}"
|
||||||
priority=2
|
priority=2
|
||||||
autostart=true
|
autostart=false
|
||||||
autorestart=false
|
autorestart=false
|
||||||
stdout_logfile=syslog
|
stdout_logfile=syslog
|
||||||
stderr_logfile=syslog
|
stderr_logfile=syslog
|
||||||
|
dependent_startup=true
|
||||||
|
dependent_startup_wait_for=rsyslogd:running
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
[program:flushdb]
|
[program:flushdb]
|
||||||
command=/bin/bash -c "sleep 300 && /usr/local/bin/flush_unused_database"
|
command=/bin/bash -c "sleep 300 && /usr/local/bin/flush_unused_database"
|
||||||
priority=3
|
priority=3
|
||||||
autostart=true
|
autostart=false
|
||||||
autorestart=false
|
autorestart=false
|
||||||
stdout_logfile=syslog
|
stdout_logfile=syslog
|
||||||
stderr_logfile=syslog
|
stderr_logfile=syslog
|
||||||
|
dependent_startup=true
|
||||||
|
dependent_startup_wait_for=rsyslogd:running
|
||||||
|
@ -34,16 +34,23 @@ function updateSyslogConf()
|
|||||||
# Also update the container name
|
# Also update the container name
|
||||||
if [[ ($NUM_ASIC -gt 1) ]]; then
|
if [[ ($NUM_ASIC -gt 1) ]]; then
|
||||||
TARGET_IP=$(docker network inspect bridge --format={{ "'{{(index .IPAM.Config 0).Gateway}}'" }})
|
TARGET_IP=$(docker network inspect bridge --format={{ "'{{(index .IPAM.Config 0).Gateway}}'" }})
|
||||||
CONTAINER_NAME="$DOCKERNAME"
|
else
|
||||||
TMP_FILE="/tmp/rsyslog.$CONTAINER_NAME.conf"
|
if [ "$CONTAINER_EXISTS" = "yes" ]; then
|
||||||
{%- if docker_container_name == "database" %}
|
# database configuration has been synced to /etc/rsyslog.conf
|
||||||
python -c "import jinja2, os; paths=['/usr/share/sonic/templates']; loader = jinja2.FileSystemLoader(paths); env = jinja2.Environment(loader=loader, trim_blocks=True); template_file='/usr/share/sonic/templates/rsyslog-container.conf.j2'; template = env.get_template(os.path.basename(template_file)); data=template.render({\"target_ip\":\"$TARGET_IP\",\"container_name\":\"$CONTAINER_NAME\"}); print(data)" > $TMP_FILE
|
# no need generate it to save boot time
|
||||||
{%- else %}
|
return
|
||||||
sonic-cfggen -t /usr/share/sonic/templates/rsyslog-container.conf.j2 -a "{\"target_ip\": \"$TARGET_IP\", \"container_name\": \"$CONTAINER_NAME\" }" > $TMP_FILE
|
fi
|
||||||
{%- endif %}
|
TARGET_IP="127.0.0.1"
|
||||||
docker cp $TMP_FILE ${DOCKERNAME}:/etc/rsyslog.conf
|
|
||||||
rm -rf $TMP_FILE
|
|
||||||
fi
|
fi
|
||||||
|
CONTAINER_NAME="$DOCKERNAME"
|
||||||
|
TMP_FILE="/tmp/rsyslog.$CONTAINER_NAME.conf"
|
||||||
|
{%- if docker_container_name == "database" %}
|
||||||
|
python -c "import jinja2, os; paths=['/usr/share/sonic/templates']; loader = jinja2.FileSystemLoader(paths); env = jinja2.Environment(loader=loader, trim_blocks=True); template_file='/usr/share/sonic/templates/rsyslog-container.conf.j2'; template = env.get_template(os.path.basename(template_file)); data=template.render({\"target_ip\":\"$TARGET_IP\",\"container_name\":\"$CONTAINER_NAME\"}); print(data)" > $TMP_FILE
|
||||||
|
{%- else %}
|
||||||
|
sonic-cfggen -d -t /usr/share/sonic/templates/rsyslog-container.conf.j2 -a "{\"target_ip\": \"$TARGET_IP\", \"container_name\": \"$CONTAINER_NAME\" }" > $TMP_FILE
|
||||||
|
{%- endif %}
|
||||||
|
docker cp $TMP_FILE ${DOCKERNAME}:/etc/rsyslog.conf
|
||||||
|
rm -rf $TMP_FILE
|
||||||
}
|
}
|
||||||
function ebtables_config()
|
function ebtables_config()
|
||||||
{
|
{
|
||||||
@ -342,6 +349,7 @@ start() {
|
|||||||
DOCKERMOUNT=`getMountPoint "$DOCKERCHECK"`
|
DOCKERMOUNT=`getMountPoint "$DOCKERCHECK"`
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
if [ x"$DOCKERMOUNT" == x"$MOUNTPATH" ]; then
|
if [ x"$DOCKERMOUNT" == x"$MOUNTPATH" ]; then
|
||||||
|
CONTAINER_EXISTS="yes"
|
||||||
preStartAction
|
preStartAction
|
||||||
{%- if docker_container_name == "database" %}
|
{%- if docker_container_name == "database" %}
|
||||||
echo "Starting existing ${DOCKERNAME} container"
|
echo "Starting existing ${DOCKERNAME} container"
|
||||||
@ -536,6 +544,7 @@ start() {
|
|||||||
{%- endif %}
|
{%- endif %}
|
||||||
$REDIS_MNT \
|
$REDIS_MNT \
|
||||||
-v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \
|
-v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \
|
||||||
|
-v /usr/share/sonic/templates/rsyslog-container.conf.j2:/usr/share/sonic/templates/rsyslog-container.conf.j2:ro \
|
||||||
{%- if sonic_asic_platform != "mellanox" %}
|
{%- if sonic_asic_platform != "mellanox" %}
|
||||||
{%- if mount_default_tmpfs|default("n") == "y" %}
|
{%- if mount_default_tmpfs|default("n") == "y" %}
|
||||||
--tmpfs /tmp \
|
--tmpfs /tmp \
|
||||||
@ -547,6 +556,7 @@ start() {
|
|||||||
--env "NAMESPACE_ID"="$DEV" \
|
--env "NAMESPACE_ID"="$DEV" \
|
||||||
--env "NAMESPACE_PREFIX"="$NAMESPACE_PREFIX" \
|
--env "NAMESPACE_PREFIX"="$NAMESPACE_PREFIX" \
|
||||||
--env "NAMESPACE_COUNT"=$NUM_ASIC \
|
--env "NAMESPACE_COUNT"=$NUM_ASIC \
|
||||||
|
--env "CONTAINER_NAME"=$DOCKERNAME \
|
||||||
--name=$DOCKERNAME \
|
--name=$DOCKERNAME \
|
||||||
{%- if docker_container_name == "gbsyncd" %}
|
{%- if docker_container_name == "gbsyncd" %}
|
||||||
-v /var/run/docker-syncd$DEV:/var/run/sswsyncd \
|
-v /var/run/docker-syncd$DEV:/var/run/sswsyncd \
|
||||||
@ -617,6 +627,7 @@ fi
|
|||||||
{%- endif %}
|
{%- endif %}
|
||||||
NAMESPACE_PREFIX="asic"
|
NAMESPACE_PREFIX="asic"
|
||||||
DOCKERNAME=$DOCKERNAME$DEV
|
DOCKERNAME=$DOCKERNAME$DEV
|
||||||
|
CONTAINER_EXISTS="no"
|
||||||
if [ "$DEV" ]; then
|
if [ "$DEV" ]; then
|
||||||
NET_NS="$NAMESPACE_PREFIX$DEV" #name of the network namespace
|
NET_NS="$NAMESPACE_PREFIX$DEV" #name of the network namespace
|
||||||
|
|
||||||
@ -639,4 +650,4 @@ case "$1" in
|
|||||||
echo "Usage: $0 {start namespace(optional)|wait namespace(optional)|stop namespace(optional)}"
|
echo "Usage: $0 {start namespace(optional)|wait namespace(optional)|stop namespace(optional)}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
@ -14,8 +14,24 @@ $ModLoad imuxsock # provides support for local system logging
|
|||||||
#
|
#
|
||||||
# Set a rate limit on messages from the container
|
# Set a rate limit on messages from the container
|
||||||
#
|
#
|
||||||
$SystemLogRateLimitInterval 300
|
|
||||||
$SystemLogRateLimitBurst 20000
|
{% if SYSLOG_CONFIG_FEATURE is defined %}
|
||||||
|
{% if container_name in SYSLOG_CONFIG_FEATURE %}
|
||||||
|
{% if 'rate_limit_interval' in SYSLOG_CONFIG_FEATURE[container_name]%}
|
||||||
|
{% set rate_limit_interval = SYSLOG_CONFIG_FEATURE[container_name]['rate_limit_interval'] %}
|
||||||
|
{% endif %}
|
||||||
|
{% if 'rate_limit_burst' in SYSLOG_CONFIG_FEATURE[container_name]%}
|
||||||
|
{% set rate_limit_burst = SYSLOG_CONFIG_FEATURE[container_name]['rate_limit_burst'] %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if rate_limit_interval is defined %}
|
||||||
|
$SystemLogRateLimitInterval {{ rate_limit_interval }}
|
||||||
|
{% endif %}
|
||||||
|
{% if rate_limit_burst is defined %}
|
||||||
|
$SystemLogRateLimitBurst {{ rate_limit_burst }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
#$ModLoad imklog # provides kernel logging support
|
#$ModLoad imklog # provides kernel logging support
|
||||||
#$ModLoad immark # provides --MARK-- message capability
|
#$ModLoad immark # provides --MARK-- message capability
|
||||||
@ -73,4 +89,4 @@ $RepeatedMsgReduction on
|
|||||||
|
|
||||||
###############
|
###############
|
||||||
#### RULES ####
|
#### RULES ####
|
||||||
###############
|
###############
|
@ -11,8 +11,9 @@ $(DOCKER_CONFIG_ENGINE_BULLSEYE)_DEPENDS += $(LIBSWSSCOMMON) \
|
|||||||
$(SONIC_DB_CLI) \
|
$(SONIC_DB_CLI) \
|
||||||
$(SONIC_EVENTD)
|
$(SONIC_EVENTD)
|
||||||
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_PYTHON_WHEELS += $(SONIC_PY_COMMON_PY3) \
|
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_PYTHON_WHEELS += $(SONIC_PY_COMMON_PY3) \
|
||||||
$(SONIC_YANG_MGMT_PY3) \
|
$(SONIC_YANG_MGMT_PY3) \
|
||||||
$(SONIC_YANG_MODELS_PY3)
|
$(SONIC_YANG_MODELS_PY3) \
|
||||||
|
$(SONIC_CONTAINERCFGD)
|
||||||
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_PYTHON_WHEELS += $(SONIC_CONFIG_ENGINE_PY3)
|
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_PYTHON_WHEELS += $(SONIC_CONFIG_ENGINE_PY3)
|
||||||
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_LOAD_DOCKERS += $(DOCKER_BASE_BULLSEYE)
|
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_LOAD_DOCKERS += $(DOCKER_BASE_BULLSEYE)
|
||||||
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_FILES += $(SWSS_VARS_TEMPLATE)
|
$(DOCKER_CONFIG_ENGINE_BULLSEYE)_FILES += $(SWSS_VARS_TEMPLATE)
|
||||||
|
@ -11,7 +11,8 @@ $(DOCKER_CONFIG_ENGINE_BUSTER)_DEPENDS += $(LIBSWSSCOMMON) \
|
|||||||
$(SONIC_DB_CLI)
|
$(SONIC_DB_CLI)
|
||||||
$(DOCKER_CONFIG_ENGINE_BUSTER)_PYTHON_WHEELS += $(SONIC_PY_COMMON_PY3) \
|
$(DOCKER_CONFIG_ENGINE_BUSTER)_PYTHON_WHEELS += $(SONIC_PY_COMMON_PY3) \
|
||||||
$(SONIC_YANG_MGMT_PY3) \
|
$(SONIC_YANG_MGMT_PY3) \
|
||||||
$(SONIC_YANG_MODELS_PY3)
|
$(SONIC_YANG_MODELS_PY3) \
|
||||||
|
$(SONIC_CONTAINERCFGD)
|
||||||
$(DOCKER_CONFIG_ENGINE_BUSTER)_PYTHON_WHEELS += $(SONIC_CONFIG_ENGINE_PY3)
|
$(DOCKER_CONFIG_ENGINE_BUSTER)_PYTHON_WHEELS += $(SONIC_CONFIG_ENGINE_PY3)
|
||||||
$(DOCKER_CONFIG_ENGINE_BUSTER)_LOAD_DOCKERS += $(DOCKER_BASE_BUSTER)
|
$(DOCKER_CONFIG_ENGINE_BUSTER)_LOAD_DOCKERS += $(DOCKER_BASE_BUSTER)
|
||||||
$(DOCKER_CONFIG_ENGINE_BUSTER)_FILES += $(SWSS_VARS_TEMPLATE)
|
$(DOCKER_CONFIG_ENGINE_BUSTER)_FILES += $(SWSS_VARS_TEMPLATE)
|
||||||
|
10
rules/sonic-containercfgd.dep
Normal file
10
rules/sonic-containercfgd.dep
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
SPATH := $($(SONIC_CONTAINERCFGD)_SRC_PATH)
|
||||||
|
DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/sonic-containercfgd.mk rules/sonic-containercfgd.dep
|
||||||
|
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
|
||||||
|
SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files))
|
||||||
|
|
||||||
|
$(SONIC_CONTAINERCFGD)_CACHE_MODE := GIT_CONTENT_SHA
|
||||||
|
$(SONIC_CONTAINERCFGD)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
|
||||||
|
$(SONIC_CONTAINERCFGD)_DEP_FILES := $(DEP_FILES)
|
||||||
|
$(SONIC_CONTAINERCFGD)_SMDEP_FILES := $(SMDEP_FILES)
|
||||||
|
$(SONIC_CONTAINERCFGD)_SMDEP_PATHS := $(SPATH)
|
8
rules/sonic-containercfgd.mk
Normal file
8
rules/sonic-containercfgd.mk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# sonic-bgpcfgd package
|
||||||
|
|
||||||
|
SONIC_CONTAINERCFGD = sonic_containercfgd-1.0-py3-none-any.whl
|
||||||
|
$(SONIC_CONTAINERCFGD)_SRC_PATH = $(SRC_PATH)/sonic-containercfgd
|
||||||
|
$(SONIC_CONTAINERCFGD)_DEPENDS += $(SONIC_PY_COMMON_PY3)
|
||||||
|
$(SONIC_CONTAINERCFGD)_DEBS_DEPENDS = $(LIBSWSSCOMMON) $(PYTHON3_SWSSCOMMON)
|
||||||
|
$(SONIC_CONTAINERCFGD)_PYTHON_VERSION = 3
|
||||||
|
SONIC_PYTHON_WHEELS += $(SONIC_CONTAINERCFGD)
|
13
src/sonic-containercfgd/.gitignore
vendored
Normal file
13
src/sonic-containercfgd/.gitignore
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Compiled Python files
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Generated by packaging
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Unit test coverage
|
||||||
|
.coverage
|
||||||
|
coverage.xml
|
||||||
|
htmlcov/
|
0
src/sonic-containercfgd/containercfgd/__init__.py
Normal file
0
src/sonic-containercfgd/containercfgd/__init__.py
Normal file
198
src/sonic-containercfgd/containercfgd/containercfgd.py
Normal file
198
src/sonic-containercfgd/containercfgd/containercfgd.py
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from sonic_py_common import daemon_base, logger
|
||||||
|
from swsscommon.swsscommon import ConfigDBConnector, RestartWaiter
|
||||||
|
|
||||||
|
SYSLOG_IDENTIFIER = "containercfgd"
|
||||||
|
logger = logger.Logger(SYSLOG_IDENTIFIER)
|
||||||
|
|
||||||
|
# Table names
|
||||||
|
FEATURE_TABLE = 'FEATURE'
|
||||||
|
SYSLOG_CONFIG_FEATURE_TABLE = 'SYSLOG_CONFIG_FEATURE'
|
||||||
|
|
||||||
|
# Table field names
|
||||||
|
SYSLOG_RATE_LIMIT_INTERVAL = 'rate_limit_interval'
|
||||||
|
SYSLOG_RATE_LIMIT_BURST = 'rate_limit_burst'
|
||||||
|
|
||||||
|
# Container name
|
||||||
|
container_name = None
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(command):
|
||||||
|
"""
|
||||||
|
Utility function to run an shell command and return the output.
|
||||||
|
:param command: Shell command string.
|
||||||
|
:return: Output of the shell command.
|
||||||
|
"""
|
||||||
|
return subprocess.check_output(command, text=True, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerConfigDaemon(daemon_base.DaemonBase):
|
||||||
|
handlers = {}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(ContainerConfigDaemon, self).__init__(SYSLOG_IDENTIFIER)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Register config handlers and listen to CONFIG DB changes
|
||||||
|
"""
|
||||||
|
config_db = ConfigDBConnector()
|
||||||
|
config_db.connect(wait_for_init=True, retry_on=True)
|
||||||
|
self.log_notice(f'Connected to CONFIG DB')
|
||||||
|
for table_name, handler in self.handlers.items():
|
||||||
|
config_db.subscribe(table_name, handler.handle_config)
|
||||||
|
config_db.listen(init_data_handler=self.init_data_handler)
|
||||||
|
|
||||||
|
def init_data_handler(self, init_data):
|
||||||
|
"""Handle initial data in CONFIG DB
|
||||||
|
|
||||||
|
Args:
|
||||||
|
init_data (dict): Initial data when first time connecting to CONFIG DB. {<table_name>: {<field_name>: <field_value>}}
|
||||||
|
"""
|
||||||
|
for handler in self.handlers.values():
|
||||||
|
handler.handle_init_data(init_data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register_handler(cls, table_name, object_type):
|
||||||
|
"""Register CONFIG DB handler
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_name (str): CONFIG DB table name
|
||||||
|
object_type (class): Class of CONFIG DB handler
|
||||||
|
"""
|
||||||
|
cls.handlers[table_name] = object_type()
|
||||||
|
|
||||||
|
def signal_handler(self, sig, frame):
|
||||||
|
if sig == signal.SIGHUP:
|
||||||
|
self.log_info("ContainerCfgd: Caught SIGHUP - ignoring...")
|
||||||
|
elif sig == signal.SIGINT:
|
||||||
|
self.log_info("ContainerCfgd: Caught SIGINT - exiting...")
|
||||||
|
sys.exit(128 + sig)
|
||||||
|
elif sig == signal.SIGTERM:
|
||||||
|
self.log_info("ContainerCfgd: Caught SIGTERM - exiting...")
|
||||||
|
sys.exit(128 + sig)
|
||||||
|
else:
|
||||||
|
self.log_warning("ContainerCfgd: Caught unhandled signal '{}'".format(sig))
|
||||||
|
|
||||||
|
|
||||||
|
def config_handler(table_name):
|
||||||
|
"""Decorator to register CONFIG DB handler
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table_name (str): CONFIG DB table name
|
||||||
|
"""
|
||||||
|
def wrapper(object_type):
|
||||||
|
ContainerConfigDaemon.register_handler(table_name, object_type)
|
||||||
|
return object_type
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@config_handler(SYSLOG_CONFIG_FEATURE_TABLE)
|
||||||
|
class SyslogHandler:
|
||||||
|
# syslog conf file path in docker
|
||||||
|
SYSLOG_CONF_PATH = '/etc/rsyslog.conf'
|
||||||
|
# temporary syslog conf file path in docker
|
||||||
|
TMP_SYSLOG_CONF_PATH = '/tmp/rsyslog.conf'
|
||||||
|
|
||||||
|
# Regular expressions to extract value from rsyslog.conf
|
||||||
|
INTERVAL_PATTERN = '.*SystemLogRateLimitInterval\s+(\d+).*'
|
||||||
|
BURST_PATTERN = '.*SystemLogRateLimitBurst\s+(\d+).*'
|
||||||
|
TARGET_IP_PATTERN = '.*target="(.*?)".*'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.current_interval, self.current_burst, self.target_ip = self.parse_syslog_conf()
|
||||||
|
|
||||||
|
def handle_config(self, table, key, data):
|
||||||
|
"""Handle CONFIG DB change. Callback by ConfigDBConnector.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
table (str): CONFIG DB table name
|
||||||
|
key (str): Key of the changed entry
|
||||||
|
data (dict): Data of the entry: {<field_name>: <field_value>}
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if key != container_name:
|
||||||
|
return
|
||||||
|
self.update_syslog_config(data)
|
||||||
|
except Exception as e:
|
||||||
|
logger.log_error('Failed to config syslog for container {} with data {} - {}'.format(key, data, e))
|
||||||
|
|
||||||
|
def handle_init_data(self, init_data):
|
||||||
|
"""Handle initial data in CONFIG DB. Callback by ConfigDBConnector.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
init_data (dict): Initial data when first time connecting to CONFIG DB. {<table_name>: {<field_name>: <field_value>}}
|
||||||
|
"""
|
||||||
|
if SYSLOG_CONFIG_FEATURE_TABLE in init_data:
|
||||||
|
if container_name in init_data[SYSLOG_CONFIG_FEATURE_TABLE]:
|
||||||
|
self.update_syslog_config(init_data[SYSLOG_CONFIG_FEATURE_TABLE][container_name])
|
||||||
|
|
||||||
|
def update_syslog_config(self, data):
|
||||||
|
"""Parse existing syslog conf and apply new syslog conf.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (dict): Data of the entry: {<field_name>: <field_value>}
|
||||||
|
"""
|
||||||
|
new_interval = '0' if not data else data.get(SYSLOG_RATE_LIMIT_INTERVAL, '0')
|
||||||
|
new_burst = '0' if not data else data.get(SYSLOG_RATE_LIMIT_BURST, '0')
|
||||||
|
|
||||||
|
if new_interval == self.current_interval and new_burst == self.current_burst:
|
||||||
|
logger.log_notice('Syslog rate limit configuration does not change, ignore it')
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.log_notice(f'Configure syslog rate limit interval={new_interval}, burst={new_burst}')
|
||||||
|
|
||||||
|
if os.path.exists(self.TMP_SYSLOG_CONF_PATH):
|
||||||
|
os.remove(self.TMP_SYSLOG_CONF_PATH)
|
||||||
|
with open(self.TMP_SYSLOG_CONF_PATH, 'w+') as f:
|
||||||
|
json_args = f'{{"target_ip": "127.0.0.1", "{self.target_ip}": "{container_name}" }}'
|
||||||
|
output = run_command(['sonic-cfggen', '-d', '-t', '/usr/share/sonic/templates/rsyslog-container.conf.j2', '-a', json_args])
|
||||||
|
f.write(output)
|
||||||
|
run_command(['cp', self.TMP_SYSLOG_CONF_PATH, self.SYSLOG_CONF_PATH])
|
||||||
|
run_command(['supervisorctl', 'restart', 'rsyslogd'])
|
||||||
|
self.current_interval = new_interval
|
||||||
|
self.current_burst = new_burst
|
||||||
|
|
||||||
|
def parse_syslog_conf(self):
|
||||||
|
"""Passe existing syslog conf and extract config values
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: interval,burst,target_ip
|
||||||
|
"""
|
||||||
|
interval = '0'
|
||||||
|
burst = '0'
|
||||||
|
target_ip = None
|
||||||
|
|
||||||
|
with open(self.SYSLOG_CONF_PATH, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
pattern = re.compile(self.INTERVAL_PATTERN)
|
||||||
|
for match in pattern.finditer(content):
|
||||||
|
interval = match.group(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
pattern = re.compile(self.BURST_PATTERN)
|
||||||
|
for match in pattern.finditer(content):
|
||||||
|
burst = match.group(1)
|
||||||
|
break
|
||||||
|
|
||||||
|
pattern = re.compile(self.TARGET_IP_PATTERN)
|
||||||
|
for match in pattern.finditer(content):
|
||||||
|
target_ip = match.group(1)
|
||||||
|
break
|
||||||
|
return interval, burst, target_ip
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
RestartWaiter.waitAdvancedBootDone()
|
||||||
|
global container_name
|
||||||
|
container_name = os.environ['CONTAINER_NAME']
|
||||||
|
daemon = ContainerConfigDaemon()
|
||||||
|
daemon.run()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
2
src/sonic-containercfgd/pytest.ini
Normal file
2
src/sonic-containercfgd/pytest.ini
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[pytest]
|
||||||
|
addopts = --cov=containercfgd --cov-report html --cov-report term --cov-report xml
|
2
src/sonic-containercfgd/setup.cfg
Normal file
2
src/sonic-containercfgd/setup.cfg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[aliases]
|
||||||
|
test=pytest
|
48
src/sonic-containercfgd/setup.py
Normal file
48
src/sonic-containercfgd/setup.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
'sonic_py_common',
|
||||||
|
]
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='sonic-containercfgd',
|
||||||
|
version='1.0',
|
||||||
|
description='SONiC container config daemon package',
|
||||||
|
license='Apache 2.0',
|
||||||
|
author='SONiC Team',
|
||||||
|
author_email='linuxnetdev@microsoft.com',
|
||||||
|
url='https://github.com/Azure/sonic-buildimage',
|
||||||
|
maintainer='Junchao Chen',
|
||||||
|
maintainer_email='junchaow@nvidia.com',
|
||||||
|
install_requires=dependencies,
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'containercfgd = containercfgd.containercfgd:main',
|
||||||
|
]
|
||||||
|
},
|
||||||
|
packages=[
|
||||||
|
'containercfgd',
|
||||||
|
'tests'
|
||||||
|
],
|
||||||
|
setup_requires=[
|
||||||
|
'pytest-runner'
|
||||||
|
],
|
||||||
|
tests_require=[
|
||||||
|
'pytest',
|
||||||
|
'mock>=2.0.0'
|
||||||
|
],
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 4 - Beta',
|
||||||
|
'Environment :: No Input/Output (Daemon)',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Intended Audience :: Information Technology',
|
||||||
|
'Intended Audience :: System Administrators',
|
||||||
|
'License :: OSI Approved :: Apache Software License',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Operating System :: POSIX :: Linux',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Topic :: System :: Hardware',
|
||||||
|
],
|
||||||
|
keywords='SONiC sonic container config daemon',
|
||||||
|
test_suite='setup.get_test_suite'
|
||||||
|
)
|
7
src/sonic-containercfgd/tests/conftest.py
Normal file
7
src/sonic-containercfgd/tests/conftest.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def init_env():
|
||||||
|
# Just make sure there is an environment variable CONTAINER_NAME
|
||||||
|
# The value of this environment variable is not important
|
||||||
|
os.environ["CONTAINER_NAME"] = "some_container"
|
29
src/sonic-containercfgd/tests/mock_rsyslog.conf
Normal file
29
src/sonic-containercfgd/tests/mock_rsyslog.conf
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
$ModLoad imuxsock # provides support for local system logging
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set a rate limit on messages from the container
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
$SystemLogRateLimitInterval 50
|
||||||
|
$SystemLogRateLimitBurst 10002
|
||||||
|
|
||||||
|
#$ModLoad imklog # provides kernel logging support
|
||||||
|
#$ModLoad immark # provides --MARK-- message capability
|
||||||
|
|
||||||
|
# provides UDP syslog reception
|
||||||
|
#$ModLoad imudp
|
||||||
|
#$UDPServerRun 514
|
||||||
|
|
||||||
|
# provides TCP syslog reception
|
||||||
|
#$ModLoad imtcp
|
||||||
|
#$InputTCPServerRun 514
|
||||||
|
|
||||||
|
|
||||||
|
###########################
|
||||||
|
#### GLOBAL DIRECTIVES ####
|
||||||
|
###########################
|
||||||
|
|
||||||
|
# Set remote syslog server
|
||||||
|
template (name="ForwardFormatInContainer" type="string" string="<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% pmon#%syslogtag%%msg:::sp-if-no-1st-sp%%msg%")
|
||||||
|
*.* action(type="omfwd" target="127.0.0.1" port="514" protocol="udp" Template="ForwardFormatInContainer")
|
54
src/sonic-containercfgd/tests/test_config_daemon.py
Normal file
54
src/sonic-containercfgd/tests/test_config_daemon.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
test_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
modules_path = os.path.dirname(test_path)
|
||||||
|
sys.path.insert(0, modules_path)
|
||||||
|
|
||||||
|
from containercfgd import containercfgd
|
||||||
|
|
||||||
|
|
||||||
|
@containercfgd.config_handler('MockTable')
|
||||||
|
class MockHandler:
|
||||||
|
def handle_init_data(self, init_data):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def handle_config(self, table, key, data):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_handler_register():
|
||||||
|
assert 'MockTable' in containercfgd.ContainerConfigDaemon.handlers
|
||||||
|
assert isinstance(containercfgd.ContainerConfigDaemon.handlers['MockTable'], MockHandler)
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_data_handler():
|
||||||
|
mock_handler_cls = mock.MagicMock()
|
||||||
|
mock_handler_instance = mock.MagicMock()
|
||||||
|
mock_handler_instance.handle_init_data = mock.MagicMock()
|
||||||
|
mock_handler_cls.return_value = mock_handler_instance
|
||||||
|
|
||||||
|
containercfgd.ContainerConfigDaemon.register_handler('LoadMock', mock_handler_cls)
|
||||||
|
daemon = containercfgd.ContainerConfigDaemon()
|
||||||
|
daemon.init_data_handler({})
|
||||||
|
mock_handler_instance.handle_init_data.assert_called_once()
|
||||||
|
containercfgd.ContainerConfigDaemon.handlers.pop('LoadMock')
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch('containercfgd.containercfgd.ConfigDBConnector')
|
||||||
|
def test_run(mock_connector):
|
||||||
|
mock_db = mock.MagicMock()
|
||||||
|
mock_db.connect = mock.MagicMock()
|
||||||
|
mock_db.subscribe = mock.MagicMock()
|
||||||
|
mock_db.listen = mock.MagicMock()
|
||||||
|
mock_connector.return_value = mock_db
|
||||||
|
|
||||||
|
daemon = containercfgd.ContainerConfigDaemon()
|
||||||
|
daemon.run()
|
||||||
|
mock_db.connect.assert_called_once()
|
||||||
|
expected = []
|
||||||
|
for table_name, handler in containercfgd.ContainerConfigDaemon.handlers.items():
|
||||||
|
expected.append(mock.call(table_name, handler.handle_config))
|
||||||
|
mock_db.subscribe.assert_has_calls(expected, any_order=True)
|
||||||
|
mock_db.listen.assert_called_once()
|
81
src/sonic-containercfgd/tests/test_syslog_config.py
Normal file
81
src/sonic-containercfgd/tests/test_syslog_config.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
test_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
modules_path = os.path.dirname(test_path)
|
||||||
|
sys.path.insert(0, modules_path)
|
||||||
|
|
||||||
|
from containercfgd import containercfgd
|
||||||
|
|
||||||
|
containercfgd.container_name = 'swss'
|
||||||
|
|
||||||
|
|
||||||
|
def test_handle_config():
|
||||||
|
handler = containercfgd.SyslogHandler()
|
||||||
|
handler.update_syslog_config = mock.MagicMock()
|
||||||
|
|
||||||
|
handler.handle_config(containercfgd.SYSLOG_CONFIG_FEATURE_TABLE,
|
||||||
|
'bgp',
|
||||||
|
None)
|
||||||
|
handler.update_syslog_config.assert_not_called()
|
||||||
|
|
||||||
|
handler.handle_config(containercfgd.SYSLOG_CONFIG_FEATURE_TABLE,
|
||||||
|
'swss',
|
||||||
|
None)
|
||||||
|
handler.update_syslog_config.assert_called_once()
|
||||||
|
|
||||||
|
handler.update_syslog_config.side_effect = Exception('')
|
||||||
|
handler.handle_config(containercfgd.SYSLOG_CONFIG_FEATURE_TABLE,
|
||||||
|
'swss',
|
||||||
|
None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_handle_init_data():
|
||||||
|
handler = containercfgd.SyslogHandler()
|
||||||
|
handler.update_syslog_config = mock.MagicMock()
|
||||||
|
|
||||||
|
init_data = {}
|
||||||
|
handler.handle_init_data(init_data)
|
||||||
|
handler.update_syslog_config.assert_not_called()
|
||||||
|
|
||||||
|
init_data = {containercfgd.SYSLOG_CONFIG_FEATURE_TABLE: {}}
|
||||||
|
handler.handle_init_data(init_data)
|
||||||
|
handler.update_syslog_config.assert_not_called()
|
||||||
|
|
||||||
|
init_data = {containercfgd.SYSLOG_CONFIG_FEATURE_TABLE: {'swss': {}}}
|
||||||
|
handler.handle_init_data(init_data)
|
||||||
|
handler.update_syslog_config.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch('containercfgd.containercfgd.run_command')
|
||||||
|
@mock.patch('containercfgd.containercfgd.SyslogHandler.parse_syslog_conf', mock.MagicMock(return_value=('100', '200', '127.0.0.1')))
|
||||||
|
def test_update_syslog_config(mock_run_cmd):
|
||||||
|
mock_run_cmd.return_value = ""
|
||||||
|
handler = containercfgd.SyslogHandler()
|
||||||
|
|
||||||
|
data = {containercfgd.SYSLOG_RATE_LIMIT_INTERVAL: '100',
|
||||||
|
containercfgd.SYSLOG_RATE_LIMIT_BURST: '200'}
|
||||||
|
handler.update_syslog_config(data)
|
||||||
|
mock_run_cmd.assert_not_called()
|
||||||
|
|
||||||
|
data = {containercfgd.SYSLOG_RATE_LIMIT_INTERVAL: '200',
|
||||||
|
containercfgd.SYSLOG_RATE_LIMIT_BURST: '200'}
|
||||||
|
|
||||||
|
handler.update_syslog_config(data)
|
||||||
|
mock_run_cmd.assert_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_syslog_conf():
|
||||||
|
handler = containercfgd.SyslogHandler()
|
||||||
|
handler.SYSLOG_CONF_PATH = os.path.join(test_path, 'mock_rsyslog.conf')
|
||||||
|
interval, burst, target_ip = handler.parse_syslog_conf()
|
||||||
|
assert interval == '50'
|
||||||
|
assert burst == '10002'
|
||||||
|
assert target_ip == '127.0.0.1'
|
||||||
|
|
||||||
|
handler.SYSLOG_CONF_PATH = os.path.join(test_path, 'mock_empty_rsyslog.conf')
|
||||||
|
interval, burst, target_ip = handler.parse_syslog_conf()
|
||||||
|
assert interval == '0'
|
||||||
|
assert burst == '0'
|
||||||
|
assert target_ip is None
|
Loading…
Reference in New Issue
Block a user