diff --git a/dockers/docker-router-advertiser/Dockerfile.j2 b/dockers/docker-router-advertiser/Dockerfile.j2 index 7f57ade4fad..1d5a9acc43e 100644 --- a/dockers/docker-router-advertiser/Dockerfile.j2 +++ b/dockers/docker-router-advertiser/Dockerfile.j2 @@ -25,7 +25,7 @@ RUN apt-get clean -y && \ rm -rf /debs COPY ["docker-init.sh", "/usr/bin/"] -COPY ["radvd.conf.j2", "wait_for_intf.sh.j2", "docker-router-advertiser.supervisord.conf.j2", "/usr/share/sonic/templates/"] +COPY ["radvd.conf.j2", "wait_for_link.sh.j2", "docker-router-advertiser.supervisord.conf.j2", "/usr/share/sonic/templates/"] COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] COPY ["critical_processes", "/etc/supervisor"] diff --git a/dockers/docker-router-advertiser/docker-init.sh b/dockers/docker-router-advertiser/docker-init.sh index a38988186a9..a3f373f438a 100755 --- a/dockers/docker-router-advertiser/docker-init.sh +++ b/dockers/docker-router-advertiser/docker-init.sh @@ -8,10 +8,10 @@ CFGGEN_PARAMS=" \ -d \ -t /usr/share/sonic/templates/docker-router-advertiser.supervisord.conf.j2,/etc/supervisor/conf.d/supervisord.conf \ -t /usr/share/sonic/templates/radvd.conf.j2,/etc/radvd.conf \ - -t /usr/share/sonic/templates/wait_for_intf.sh.j2,/usr/bin/wait_for_intf.sh \ + -t /usr/share/sonic/templates/wait_for_link.sh.j2,/usr/bin/wait_for_link.sh \ " sonic-cfggen $CFGGEN_PARAMS -chmod +x /usr/bin/wait_for_intf.sh +chmod +x /usr/bin/wait_for_link.sh exec /usr/bin/supervisord diff --git a/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf.j2 b/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf.j2 index 146e7c1b67d..9bfc8d9220a 100644 --- a/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf.j2 +++ b/dockers/docker-router-advertiser/docker-router-advertiser.supervisord.conf.j2 @@ -26,20 +26,21 @@ stdout_logfile=syslog stderr_logfile=syslog dependent_startup=true -{# Router advertiser should only run on ToR (T0) devices #} -{% if DEVICE_METADATA.localhost.type == "ToRRouter" %} - - {% if VLAN_INTERFACE %} - {% for (name, prefix) in VLAN_INTERFACE|pfx_filter %} +{# Router advertiser should only run on ToR (T0) devices which have #} +{# at least one VLAN interface which has an IPv6 address asigned #} +{%- set vlan_v6 = namespace(count=0) -%} +{%- if DEVICE_METADATA.localhost.type == "ToRRouter" -%} + {%- if VLAN_INTERFACE -%} + {%- for (name, prefix) in VLAN_INTERFACE|pfx_filter -%} {# If this VLAN has an IPv6 address... #} - {% if prefix | ipv6 %} - {% set ipv6_found = true %} - {% endif %} - {% endfor %} - {% endif %} + {%- if prefix | ipv6 -%} + {%- set vlan_v6.count = vlan_v6.count + 1 -%} + {%- endif -%} + {%- endfor -%} + {%- endif -%} +{%- endif -%} - {# Enusre at least one ipv6 vlan interface #} - {% if ipv6_found == true %} +{%- if vlan_v6.count > 0 %} [program:wait_for_link] command=/usr/bin/wait_for_link.sh priority=3 @@ -60,6 +61,4 @@ stdout_logfile=syslog stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=wait_for_link:exited - {% endif %} - -{% endif %} +{% endif -%} diff --git a/dockers/docker-router-advertiser/wait_for_intf.sh.j2 b/dockers/docker-router-advertiser/wait_for_link.sh.j2 similarity index 100% rename from dockers/docker-router-advertiser/wait_for_intf.sh.j2 rename to dockers/docker-router-advertiser/wait_for_link.sh.j2 diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index b22f7ac03a1..9fb517cb09a 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -196,6 +196,12 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/sonic-ztp_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f {% endif %} +{% if include_host_service == "y" %} +# Install SONiC Host Service (and its dependencies via 'apt-get -y install -f') +sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/sonic-host-service_*.deb || \ + sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f +{% endif %} + # SONiC utilities installs bash-completion as a dependency. However, it is disabled by default # in bash.bashrc, so we copy a version of the file with it enabled here. sudo cp -f $IMAGE_CONFIGS/bash/bash.bashrc $FILESYSTEM_ROOT/etc/ diff --git a/rules/config b/rules/config index 1691fd12988..8cffedc4e96 100644 --- a/rules/config +++ b/rules/config @@ -125,6 +125,10 @@ INCLUDE_SFLOW = y # INCLUDE_MGMT_FRAMEWORK - build docker-sonic-mgmt-framework for CLI and REST server support INCLUDE_MGMT_FRAMEWORK = y +# INCLUDE_HOST_SERVICE - build sonic-host-services for mgmt-framework and/or +# telemetry containers to access host functionality +INCLUDE_HOST_SERVICE = n + # INCLUDE_RESTAPI - build docker-sonic-restapi for configuring the switch using REST APIs INCLUDE_RESTAPI = n diff --git a/rules/docker-sonic-mgmt-framework.mk b/rules/docker-sonic-mgmt-framework.mk index 997881ca46f..65bac8bd9dd 100644 --- a/rules/docker-sonic-mgmt-framework.mk +++ b/rules/docker-sonic-mgmt-framework.mk @@ -28,6 +28,7 @@ $(DOCKER_MGMT_FRAMEWORK)_CONTAINER_NAME = mgmt-framework $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += --privileged -t $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /etc:/host_etc:ro +$(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += -v /var/run/dbus:/var/run/dbus:rw $(DOCKER_MGMT_FRAMEWORK)_RUN_OPT += --mount type=bind,source="/var/platform/",target="/mnt/platform/" $(DOCKER_MGMT_FRAMEWORK)_BASE_IMAGE_FILES += sonic-cli:/usr/bin/sonic-cli diff --git a/rules/docker-telemetry.mk b/rules/docker-telemetry.mk index b44f7dc6022..c42e15e2443 100644 --- a/rules/docker-telemetry.mk +++ b/rules/docker-telemetry.mk @@ -26,6 +26,7 @@ endif $(DOCKER_TELEMETRY)_CONTAINER_NAME = telemetry $(DOCKER_TELEMETRY)_RUN_OPT += --privileged -t $(DOCKER_TELEMETRY)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_TELEMETRY)_RUN_OPT += -v /var/run/dbus:/var/run/dbus:rw $(DOCKER_TELEMETRY)_RUN_OPT += --mount type=bind,source="/var/platform/",target="/mnt/platform/" $(DOCKER_TELEMETRY)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) diff --git a/rules/sonic-host-service.dep b/rules/sonic-host-service.dep new file mode 100644 index 00000000000..9e5d823caea --- /dev/null +++ b/rules/sonic-host-service.dep @@ -0,0 +1,11 @@ + +SPATH := $($(SONIC_HOST_SERVICE)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/sonic-host-service.mk rules/sonic-host-service.dep +SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files)) + +$(SONIC_HOST_SERVICE)_CACHE_MODE := GIT_CONTENT_SHA +$(SONIC_HOST_SERVICE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(SONIC_HOST_SERVICE)_DEP_FILES := $(DEP_FILES) +$(SONIC_HOST_SERVICE)_SMDEP_FILES := $(SMDEP_FILES) +$(SONIC_HOST_SERVICE)_SMDEP_PATHS := $(SPATH) + diff --git a/rules/sonic-host-service.mk b/rules/sonic-host-service.mk new file mode 100644 index 00000000000..ad786f1a9d1 --- /dev/null +++ b/rules/sonic-host-service.mk @@ -0,0 +1,9 @@ +# SONiC host service package + +ifeq ($(INCLUDE_HOST_SERVICE), y) + +SONIC_HOST_SERVICE = sonic-host-service_1.0.0_all.deb +$(SONIC_HOST_SERVICE)_SRC_PATH = $(SRC_PATH)/sonic-host-service +SONIC_MAKE_DEBS += $(SONIC_HOST_SERVICE) + +endif diff --git a/slave.mk b/slave.mk index 63779c22d63..36849686647 100644 --- a/slave.mk +++ b/slave.mk @@ -224,6 +224,7 @@ $(info "VS_PREPARE_MEM" : "$(VS_PREPARE_MEM)") $(info "INCLUDE_MGMT_FRAMEWORK" : "$(INCLUDE_MGMT_FRAMEWORK)") $(info "INCLUDE_ICCPD" : "$(INCLUDE_ICCPD)") $(info "INCLUDE_SYSTEM_TELEMETRY" : "$(INCLUDE_SYSTEM_TELEMETRY)") +$(info "INCLUDE_HOST_SERVICE" : "$(INCLUDE_HOST_SERVICE)") $(info "INCLUDE_RESTAPI" : "$(INCLUDE_RESTAPI)") $(info "INCLUDE_SFLOW" : "$(INCLUDE_SFLOW)") $(info "INCLUDE_NAT" : "$(INCLUDE_NAT)") @@ -794,7 +795,8 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ $(PYTHON_SWSSCOMMON)) \ $$(addprefix $(TARGET_PATH)/,$$($$*_DOCKERS)) \ $$(addprefix $(FILES_PATH)/,$$($$*_FILES)) \ - $(if $(findstring y,$(ENABLE_ZTP)),$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$(SONIC_ZTP))) \ + $(if $(findstring y,$(ENABLE_ZTP)),$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$(SONIC_ZTP))) \ + $(if $(findstring y,$(INCLUDE_HOST_SERVICE)),$(addprefix $(IMAGE_DISTRO_DEBS_PATH)/,$(SONIC_HOST_SERVICE))) \ $(addprefix $(PYTHON_DEBS_PATH)/,$(SONIC_UTILS)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PY_COMMON_PY2)) \ $(addprefix $(PYTHON_WHEELS_PATH)/,$(SONIC_PY_COMMON_PY3)) \ @@ -821,6 +823,7 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ export enable_ztp="$(ENABLE_ZTP)" export include_system_telemetry="$(INCLUDE_SYSTEM_TELEMETRY)" export include_restapi="$(INCLUDE_RESTAPI)" + export include_host_service="$(INCLUDE_HOST_SERVICE)" export include_nat="$(INCLUDE_NAT)" export include_sflow="$(INCLUDE_SFLOW)" export include_mgmt_framework="$(INCLUDE_MGMT_FRAMEWORK)" diff --git a/src/sonic-host-service/Makefile b/src/sonic-host-service/Makefile new file mode 100644 index 00000000000..53eaa4cd510 --- /dev/null +++ b/src/sonic-host-service/Makefile @@ -0,0 +1,41 @@ +################################################################################ +# # +# Copyright 2020 Dell Inc. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# # +################################################################################ + +TOPDIR := $(abspath .) +MAIN_TARGET = sonic-host-service_1.0.0_all.deb +INSTALL := /usr/bin/install + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + dpkg-buildpackage -us -uc -b + mv ../$(MAIN_TARGET) $(DEST)/ + +SOURCES := $(wildcard '*.*') $(wildcard 'host_modules/*.py') +install: $(SOURCES) + # Scripts for host service + $(INSTALL) -d $(DESTDIR)/usr/lib/sonic_host_service/host_modules + $(INSTALL) -D $(TOPDIR)/sonic_host_server.py $(DESTDIR)/usr/lib/sonic_host_service + $(INSTALL) -D $(TOPDIR)/host_modules/*.py $(DESTDIR)/usr/lib/sonic_host_service/host_modules + + # D-Bus permissions configuration + $(INSTALL) -d $(DESTDIR)/etc/dbus-1/system.d + $(INSTALL) -D $(TOPDIR)/org.sonic.hostservice.conf $(DESTDIR)/etc/dbus-1/system.d + + # systemd unit + $(INSTALL) -d $(DESTDIR)/lib/systemd/system + $(INSTALL) -D $(TOPDIR)/sonic-hostservice.service $(DESTDIR)/lib/systemd/system + diff --git a/src/sonic-host-service/debian/.gitignore b/src/sonic-host-service/debian/.gitignore new file mode 100644 index 00000000000..9a07690ac27 --- /dev/null +++ b/src/sonic-host-service/debian/.gitignore @@ -0,0 +1,4 @@ +.debhelper +sonic-host-service.* +sonic-host-service/ +files diff --git a/src/sonic-host-service/debian/changelog b/src/sonic-host-service/debian/changelog new file mode 100644 index 00000000000..5c512fe009e --- /dev/null +++ b/src/sonic-host-service/debian/changelog @@ -0,0 +1,5 @@ +sonic-host-service (1.0.0) UNRELEASED; urgency=low + + * Initial release. + + -- Nirenjan Krishnan Mon, 22 Jun 2020 00:00:00 +0000 diff --git a/src/sonic-host-service/debian/compat b/src/sonic-host-service/debian/compat new file mode 100644 index 00000000000..ec635144f60 --- /dev/null +++ b/src/sonic-host-service/debian/compat @@ -0,0 +1 @@ +9 diff --git a/src/sonic-host-service/debian/control b/src/sonic-host-service/debian/control new file mode 100644 index 00000000000..57d126af60d --- /dev/null +++ b/src/sonic-host-service/debian/control @@ -0,0 +1,15 @@ +Source: sonic-host-service +Maintainer: Nirenjan Krishnan +Build-Depends: debhelper (>= 8.0.0), + dh-systemd +Vcs-Git: https://github.com/Azure/sonic-buildimage +Homepage: https://github.com/Azure/SONiC/ +Standards-Version: 3.9.3 +Section: net + +Package: sonic-host-service +Priority: extra +Architecture: all +Depends: python3-systemd, python3-dbus, python3-gi, ${misc:Depends} +Description: SONiC Host Service + diff --git a/src/sonic-host-service/debian/rules b/src/sonic-host-service/debian/rules new file mode 100755 index 00000000000..eaed7a19038 --- /dev/null +++ b/src/sonic-host-service/debian/rules @@ -0,0 +1,9 @@ +#!/usr/bin/make -f +%: + dh $@ --with systemd --parallel + +override_dh_auto_clean: +override_dh_auto_test: +override_dh_auto_build: +override_dh_auto_install: + make install DESTDIR=debian/sonic-host-service diff --git a/src/sonic-host-service/host_modules/host_service.py b/src/sonic-host-service/host_modules/host_service.py new file mode 100644 index 00000000000..48f55ae0623 --- /dev/null +++ b/src/sonic-host-service/host_modules/host_service.py @@ -0,0 +1,34 @@ +"""Base class for host modules""" + +import dbus.service +import dbus + +BUS_NAME_BASE = 'org.SONiC.HostService' +BUS_PATH = '/org/SONiC/HostService' + +def bus_name(mod_name): + """Return the bus name for the service""" + return BUS_NAME_BASE + '.' + mod_name + +def bus_path(mod_name): + """Return the bus path for the service""" + return BUS_PATH + '/' + mod_name + +method = dbus.service.method + +class HostService(dbus.service.Object): + """Service class for top level DBus endpoint""" + def __init__(self, mod_name): + self.bus = dbus.SystemBus() + self.bus_name = dbus.service.BusName(BUS_NAME_BASE, self.bus) + super(HostService, self).__init__(self.bus_name, BUS_PATH) + +class HostModule(dbus.service.Object): + """Base class for all host modules""" + def __init__(self, mod_name): + self.bus = dbus.SystemBus() + self.bus_name = dbus.service.BusName(bus_name(mod_name), self.bus) + super(HostModule, self).__init__(self.bus_name, bus_path(mod_name)) + +def register(): + return HostService, "host_service" diff --git a/src/sonic-host-service/org.sonic.hostservice.conf b/src/sonic-host-service/org.sonic.hostservice.conf new file mode 100644 index 00000000000..08599007d9b --- /dev/null +++ b/src/sonic-host-service/org.sonic.hostservice.conf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/src/sonic-host-service/sonic-hostservice.service b/src/sonic-host-service/sonic-hostservice.service new file mode 100644 index 00000000000..7717022285b --- /dev/null +++ b/src/sonic-host-service/sonic-hostservice.service @@ -0,0 +1,15 @@ +[Unit] +Description=SONiC Host Service + +[Service] +Type=dbus +BusName=org.SONiC.HostService + +ExecStart=/usr/bin/python3 -u /usr/lib/sonic_host_service/sonic_host_server.py + +Restart=on-failure +RestartSec=10 +TimeoutStopSec=3 + +[Install] +WantedBy=multi-user.target diff --git a/src/sonic-host-service/sonic_host_server.py b/src/sonic-host-service/sonic_host_server.py new file mode 100755 index 00000000000..9232209f7dc --- /dev/null +++ b/src/sonic-host-service/sonic_host_server.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +"""Host Service to handle docker-to-host communication""" + +import os +import os.path +import glob +import importlib +import sys + +import dbus +import dbus.service +import dbus.mainloop.glib + +from gi.repository import GObject + +def register_modules(): + """Register all host modules""" + mod_path = os.path.join(os.path.dirname(__file__), 'host_modules') + sys.path.append(mod_path) + for mod_file in glob.glob(os.path.join(mod_path, '*.py')): + if os.path.isfile(mod_file) and not mod_file.endswith('__init__.py'): + mod_name = os.path.basename(mod_file)[:-3] + module = importlib.import_module(mod_name) + + register_cb = getattr(module, 'register', None) + if not register_cb: + raise Exception('Missing register function for ' + mod_name) + + register_dbus(register_cb) + +def register_dbus(register_cb): + """Register DBus handlers for individual modules""" + handler_class, mod_name = register_cb() + handlers[mod_name] = handler_class(mod_name) + +# Create a main loop reactor +GObject.threads_init() +dbus.mainloop.glib.threads_init() +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) +loop = GObject.MainLoop() +handlers = {} + +class SignalManager(object): + ''' This is used to manage signals received (e.g. SIGINT). + When stopping a process (systemctl stop [service]), systemd sends + a SIGTERM signal. + ''' + shutdown = False + def __init__(self): + ''' Install signal handlers. + + SIGTERM is invoked when systemd wants to stop the daemon. + For example, "systemctl stop mydaemon.service" + or, "systemctl restart mydaemon.service" + + ''' + import signal + signal.signal(signal.SIGTERM, self.sigterm_hdlr) + + def sigterm_hdlr(self, _signum, _frame): + self.shutdown = True + loop.quit() + +sigmgr = SignalManager() +register_modules() + +# Only run if we actually have some handlers +if handlers: + import systemd.daemon + systemd.daemon.notify("READY=1") + + while not sigmgr.shutdown: + loop.run() + if sigmgr.shutdown: + break + + systemd.daemon.notify("STOPPING=1") +else: + print("No handlers to register, quitting...") diff --git a/src/sonic-utilities b/src/sonic-utilities index d5fdd74d3d5..17fb3781b2c 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit d5fdd74d3d548b608aae849aecf4094ef27adaf0 +Subproject commit 17fb3781b2cb7dfb845faa9f16bc17ccd0069649