Skip to content

Commit

Permalink
[dhcp_server] Add dhcpservd to dhcp_server container (#16560)
Browse files Browse the repository at this point in the history
Why I did it
Part implementation of dhcp_server. HLD: sonic-net/SONiC#1282.
Add dhcpservd to dhcp_server container.

How I did it
Add installing required pkg (psutil) in Dockerfile.
Add copying required file to container in Dockerfile (kea-dhcp related and dhcpservd related)
Add critical_process and supervisor config.
Add support for generating kea config (only in dhcpservd.py) and updating lease table (in dhcpservd.py and lease_update.sh)

How to verify it
Build image with setting INCLUDE_DHCP_SERVER to y and enabled dhcp_server feature after installed image, container start as expected.
Enter container and found that all processes defined in supervisor configuration running as expected.
Kill processes defined in critical_processes, container exist.
  • Loading branch information
yaqiangz authored Oct 20, 2023
1 parent 1dd0bec commit 73dd38a
Show file tree
Hide file tree
Showing 33 changed files with 2,139 additions and 5 deletions.
21 changes: 19 additions & 2 deletions dockers/docker-dhcp-server/Dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM docker-config-engine-bullseye-{{DOCKER_USERNAME}}:{{DOCKER_USERTAG}}

ARG docker_container_name
ARG image_version
RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf

## Make apt-get non-interactive
ENV DEBIAN_FRONTEND=noninteractive
Expand All @@ -13,6 +14,7 @@ ENV IMAGE_VERSION=$image_version
RUN apt-get update && \
apt-get install -f -y \
tcpdump \
python3-dev \
# For kea build environment
automake \
libtool \
Expand Down Expand Up @@ -47,7 +49,9 @@ RUN echo "/usr/local/lib/kea/hooks" > /etc/ld.so.conf.d/kea.conf && \
RUN cd /usr/local/sbin && rm -f kea-admin kea-ctrl-agent kea-dhcp-ddns kea-dhcp6 keactrl
# Remove hook lib we don't need
RUN cd /usr/local/lib/kea/hooks && rm -f libdhcp_bootp.so libdhcp_flex_option.so libdhcp_stat_cmds.so
# RUN pip3 install psutil
RUN pip3 install psutil
# TODO issue on remote rsyslog server in non-host container
RUN rm -f /etc/supervisor/conf.d/containercfgd.conf

{% if docker_dhcp_server_debs.strip() -%}
# Copy locally-built Debian package dependencies
Expand All @@ -57,23 +61,36 @@ RUN cd /usr/local/lib/kea/hooks && rm -f libdhcp_bootp.so libdhcp_flex_option.so
{{ install_debian_packages(docker_dhcp_server_debs.split(' ')) }}
{%- endif %}

{% if docker_dhcp_server_whls.strip() %}
# Copy locally-built Python wheel dependencies
{{ copy_files("python-wheels/", docker_dhcp_server_whls.split(' '), "/python-wheels/") }}

# Install locally-built Python wheel dependencies
{{ install_python_wheels(docker_dhcp_server_whls.split(' ')) }}
{% endif %}

# Remove build stuff we don't need
RUN apt-get remove -y devscripts \
automake \
libtool \
pkg-config \
build-essential \
python3-dev \
ccache

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

COPY ["docker_init.sh", "/usr/bin/"]
COPY ["docker_init.sh", "start.sh", "/usr/bin/"]
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]
COPY ["files/supervisor-proc-exit-listener", "/usr/bin"]
COPY ["port-name-alias-map.txt.j2", "rsyslog/rsyslog.conf.j2", "kea-dhcp4.conf.j2", "/usr/share/sonic/templates/"]
COPY ["critical_processes", "/etc/supervisor/"]
COPY ["lease_update.sh", "/etc/kea/"]
COPY ["kea-dhcp4-init.conf", "/etc/kea/kea-dhcp4.conf"]
COPY ["cli", "/cli/"]
COPY ["rsyslog/default.conf", "/etc/rsyslog.d"]

ENTRYPOINT ["/usr/bin/docker_init.sh"]
1 change: 1 addition & 0 deletions dockers/docker-dhcp-server/critical_processes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
group:dhcp-server-ipv4
16 changes: 16 additions & 0 deletions dockers/docker-dhcp-server/docker_init.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
#!/usr/bin/env bash


# Generate supervisord config file
mkdir -p /etc/supervisor/conf.d/
# Generate kea folder
mkdir -p /etc/kea/
udp_server_ip=$(ip -j -4 addr list lo scope host | jq -r -M '.[0].addr_info[0].local')
hostname=$(hostname)
# Generate the following files from templates:
# port-to-alias name map
sonic-cfggen -d -t /usr/share/sonic/templates/rsyslog.conf.j2 \
-a "{\"udp_server_ip\": \"$udp_server_ip\", \"hostname\": \"$hostname\"}" \
> /etc/rsyslog.conf
sonic-cfggen -d -t /usr/share/sonic/templates/port-name-alias-map.txt.j2,/tmp/port-name-alias-map.txt

# Make the script that waits for all interfaces to come up executable
chmod +x /etc/kea/lease_update.sh /usr/bin/start.sh
# The docker container should start this script as PID 1, so now that supervisord is
# properly configured, we exec /usr/local/bin/supervisord so that it runs as PID 1 for the
# duration of the container's lifetime
Expand Down
40 changes: 40 additions & 0 deletions dockers/docker-dhcp-server/kea-dhcp4-init.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"Dhcp4": {
"hooks-libraries": [
{
"library": "/usr/local/lib/kea/hooks/libdhcp_run_script.so",
"parameters": {
"name": "/etc/kea/lease_update.sh",
"sync": false
}
}
],
"interfaces-config": {
"interfaces": ["eth0"]
},
"control-socket": {
"socket-type": "unix",
"socket-name": "/run/kea/kea4-ctrl-socket"
},
"lease-database": {
"type": "memfile",
"persist": true,
"name": "/tmp/kea-lease.csv",
"lfc-interval": 3600
},
"subnet4": [],
"loggers": [
{
"name": "kea-dhcp4",
"output_options": [
{
"output": "/tmp/kea-dhcp.log",
"pattern": "%-5p %m\n"
}
],
"severity": "INFO",
"debuglevel": 0
}
]
}
}
87 changes: 87 additions & 0 deletions dockers/docker-dhcp-server/kea-dhcp4.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{%- set default_lease_time = 900 -%}
{
"Dhcp4": {
"hooks-libraries": [
{
"library": "/usr/local/lib/kea/hooks/libdhcp_run_script.so",
"parameters": {
"name": "{{ lease_update_script_path }}",
"sync": false
}
}
],
"interfaces-config": {
"interfaces": [
"eth0"
]
},
"control-socket": {
"socket-type": "unix",
"socket-name": "/run/kea/kea4-ctrl-socket"
},
"lease-database": {
"type": "memfile",
"persist": true,
"name": "{{ lease_path }}",
"lfc-interval": 3600
},
"subnet4": [
{%- set add_subnet_preceding_comma = { 'flag': False } %}
{%- for subnet_info in subnets %}
{%- if add_subnet_preceding_comma.flag -%},{%- endif -%}
{%- set _dummy = add_subnet_preceding_comma.update({'flag': True}) %}
{
"subnet": "{{ subnet_info["subnet"] }}",
"pools": [
{%- set add_pool_preceding_comma = { 'flag': False } %}
{%- for pool in subnet_info["pools"] %}
{%- if add_pool_preceding_comma.flag -%},{%- endif -%}
{%- set _dummy = add_pool_preceding_comma.update({'flag': True}) %}
{
"pool": "{{ pool["range"] }}",
"client-class": "{{ pool["client_class"] }}"
}
{%- endfor%}
],
"option-data": [
{
"name": "routers",
"data": "{{ subnet_info["gateway"] if "gateway" in subnet_info else subnet_info["server_id"] }}"
},
{
"name": "dhcp-server-identifier",
"data": "{{ subnet_info["server_id"] }}"
}
],
"valid-lifetime": {{ subnet_info["lease_time"] if "lease_time" in subnet_info else default_lease_time }},
"reservations": []
}
{%- endfor %}
],
"loggers": [
{
"name": "kea-dhcp4",
"output_options": [
{
"output": "/var/log/kea-dhcp.log",
"pattern": "%-5p %m\n"
}
],
"severity": "INFO",
"debuglevel": 0
}
]{%- if client_classes -%},
"client-classes": [
{%- set add_preceding_comma = { 'flag': False } %}
{%- for class in client_classes %}
{%- if add_preceding_comma.flag -%},{%- endif -%}
{%- set _dummy = add_preceding_comma.update({'flag': True}) %}
{
"name": "{{ class["name"] }}",
"test": "{{ class["condition"] }}"
}
{%- endfor %}
]
{%- endif %}
}
}
12 changes: 12 additions & 0 deletions dockers/docker-dhcp-server/lease_update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
# This script would run once kea-dhcp4 lease change (defined in kea-dhcp4.conf),
# it is to find running process dhcpservd.py, and send SIGUSR1 signal to this
# process to inform it to update lease table in state_db (defined in dhcpservd.py)

pid=`ps aux | grep 'dhcpservd' | grep -nv 'grep' | awk '{print $2}'`
if [ -z "$pid" ]; then
logger -p daemon.error Cannot find running dhcpservd.py.
else
# Send SIGUSR1 signal to dhcpservd.py
kill -s 10 ${pid}
fi
5 changes: 5 additions & 0 deletions dockers/docker-dhcp-server/port-name-alias-map.txt.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{# Generate port name-alias map for isc-dhcp-relay to parse. Each line contains one #}
{# name-alias pair of the form "<name> <alias>" #}
{% for port, config in PORT.items() %}
{{- port }} {% if "alias" in config %}{{ config["alias"] }}{% else %}{{ port }}{% endif %} {{- "\n" -}}
{% endfor -%}
27 changes: 27 additions & 0 deletions dockers/docker-dhcp-server/rsyslog/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#
# First some standard log files. Log by facility.
#

# Log all facilities to /var/log/syslog except cron, auth
# and authpriv. They are noisy - log them to their own files
*.*;cron,auth,authpriv.none -/var/log/syslog
auth,authpriv.* /var/log/auth.log
cron.* /var/log/cron.log

#
# Emergencies are sent to everybody logged in.
#
*.emerg :omusrmsg:*

# The named pipe /dev/xconsole is for the `xconsole' utility. To use it,
# you must invoke `xconsole' with the `-file' option:
#
# $ xconsole -file /dev/xconsole [...]
#
# NOTE: adjust the list below, or you'll go crazy if you have a reasonably
# busy site..
#
#daemon.*;mail.*;\
# news.err;\
# *.=debug;*.=info;\
# *.=notice;*.=warn |/dev/xconsole
96 changes: 96 additions & 0 deletions dockers/docker-dhcp-server/rsyslog/rsyslog.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
###############################################################################
# Managed by Ansible
# file: ansible/roles/acs/templates/rsyslog.conf.j2
###############################################################################
#
# /etc/rsyslog.conf Configuration file for rsyslog.
#
# For more information see
# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html


#################
#### MODULES ####
#################

$ModLoad imuxsock # provides support for local system logging

{% set gconf = (SYSLOG_CONFIG | d({})).get('GLOBAL', {}) -%}
{% set rate_limit_interval = gconf.get('rate_limit_interval') %}
{% set rate_limit_burst = gconf.get('rate_limit_burst') %}

{% if rate_limit_interval is not none %}
$SystemLogRateLimitInterval {{ rate_limit_interval }}
{% endif %}
{% if rate_limit_burst is not none %}
$SystemLogRateLimitBurst {{ rate_limit_burst }}
{% endif %}

$ModLoad imklog # provides kernel logging support
#$ModLoad immark # provides --MARK-- message capability

# provides UDP syslog reception
$ModLoad imudp
$UDPServerAddress {{udp_server_ip}} #bind to localhost before udp server run
$UDPServerRun 514

# provides TCP syslog reception
#$ModLoad imtcp
#$InputTCPServerRun 514


###########################
#### GLOBAL DIRECTIVES ####
###########################
{% set format = gconf.get('format', 'standard') -%}
{% set fw_name = gconf.get('welf_firewall_name', hostname) -%}
#
# Use traditional timestamp format.
# To enable high precision timestamps, comment out the following line.
#
#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

# Define a custom template
$template SONiCFileFormat,"%TIMESTAMP%.%timestamp:::date-subseconds% %HOSTNAME% %syslogseverity-text:::uppercase% dhcp_server#%syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n"
$ActionFileDefaultTemplate SONiCFileFormat

template(name="WelfRemoteFormat" type="string" string="%TIMESTAMP% id=firewall time=\"%timereported\
:::date-year%-%timereported:::date-month%-%timereported:::date-day% %timereported:::date-hour%:%timereported:::date-minute%:%timereported\
:::date-second%\" fw=\"{{ fw_name }}\" pri=%syslogpriority% msg=\"%syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\"\n")

#
# Set the default permissions for all log files.
#
$FileOwner root
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022

#
# Where to place spool and state files
#
$WorkDirectory /var/spool/rsyslog

#
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf

#
# Suppress duplicate messages and report "message repeated n times"
#
$RepeatedMsgReduction on

###############
#### RULES ####
###############

#
# Remote syslog logging
#

# The omfwd plug-in provides the core functionality of traditional message
# forwarding via UDP and plain TCP. It is a built-in module that does not need
# to be loaded.
# TODO rsyslog issue in bridge mode container, don't update to remote server for now
19 changes: 19 additions & 0 deletions dockers/docker-dhcp-server/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash

if [ "${RUNTIME_OWNER}" == "" ]; then
RUNTIME_OWNER="kube"
fi

# This script is to basicly check for if this starting-container can be allowed
# to run based on current state, and owner & version of this starting container.
# If allowed, update feature info in state_db and then processes in supervisord.conf
# after this process can start up.
CTR_SCRIPT="/usr/share/sonic/scripts/container_startup.py"
if test -f ${CTR_SCRIPT}
then
${CTR_SCRIPT} -f dhcp_server -o ${RUNTIME_OWNER} -v ${IMAGE_VERSION}
fi

TZ=$(cat /etc/timezone)
rm -rf /etc/localtime
ln -sf /usr/share/zoneinfo/$TZ /etc/localtime
Loading

0 comments on commit 73dd38a

Please sign in to comment.