diff --git a/dockers/docker-database/Dockerfile.j2 b/dockers/docker-database/Dockerfile.j2 index f5a8ec083675..205020082352 100644 --- a/dockers/docker-database/Dockerfile.j2 +++ b/dockers/docker-database/Dockerfile.j2 @@ -44,5 +44,6 @@ COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] COPY ["files/sysctl-net.conf", "/etc/sysctl.d/"] COPY ["files/update_chassisdb_config", "/usr/local/bin/"] COPY ["flush_unused_database", "/usr/local/bin/"] +COPY ["http-server", "/usr/local/bin/"] ENTRYPOINT ["/usr/local/bin/docker-database-init.sh"] diff --git a/dockers/docker-database/http-server b/dockers/docker-database/http-server new file mode 100755 index 000000000000..5464b95caac4 --- /dev/null +++ b/dockers/docker-database/http-server @@ -0,0 +1,119 @@ +#!/usr/bin/python3 +# +########################################################################### +# http-server +# +# Python HTTP Server service. +# This service runs based on the configuration provided in +# device//chassisdb.conf +# +# Configuration parameters provided by chassisdb.conf are as follows: +# +# start_http_server: if "yes" or "1", http-server will be started on this +# node +# chassis_db_address : IP address for http-server. This is the same IP used +# for the chassis db server +# http_server_port : Port to bind to, default: 8000 +# http_server_dir : HTTP server home directory path, default: /var/www/ +# +########################################################################### +# Copyright (c) 2021-2022 Cisco Systems, Inc. and its affiliates. +# All rights reserved. +# +# 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. +# +########################################################################### + +# Example of config: +''' +start_http_server=yes +chassis_db_address=127.0.0.10 +http_server_port=8000 +http_server_dir=/var/www/tftp/ +''' + +import argparse +import http.server +import os +import socketserver +import subprocess +import syslog + +from pathlib import Path + +HTTP_DEFAULT_BIND_PORT = "8000" +HTTP_DEFAULT_DIR_PATH = '/var/www' +http_dir = None + +class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler): + def __init__(self, *args, **kwargs): + super().__init__(*args, directory=http_dir, **kwargs) + +class HttpServer(): + ''' HTTP server class implementation ''' + + def __init__(self, args, **kw): + self.http_config = {} + self.start_http_server = None + + if args.config_file: + # Use config file provided from command line + platform_conf = args.config_file + else: + platform_conf=os.path.join('/usr/share/sonic/platform', 'chassisdb.conf') + + syslog.syslog(syslog.LOG_INFO,'HTTP Server config file:{}'.format(platform_conf)) + if os.path.isfile(platform_conf): + with open(platform_conf) as f: + for line in f.readlines(): + (key, _, value) = line.strip().replace('"','').partition("=") + self.http_config[key] = value + else: + syslog.syslog(syslog.LOG_INFO, 'HTTP server config file {} not present - exiting...'.format(platform_conf)) + exit(0) + + self.http_server_ip = self.http_config.get('chassis_db_address') + if self.http_server_ip: + global http_dir + self.start_http_server = self.http_config.get('start_http_server') + http_dir = self.http_config.get('http_server_dir', HTTP_DEFAULT_DIR_PATH) + + # Get Server port from config + self.http_server_port = int(self.http_config.get('http_server_port', HTTP_DEFAULT_BIND_PORT)) + + # Create HTTP home dir path if not present + path = Path(http_dir) + path.mkdir(parents=True, exist_ok=True) + + def run(self): + ''' start the http-server if start_http_server is set in config file ''' + + if self.start_http_server == 'yes' or self.start_http_server == '1': + # Start the http-server, generally on the Supervisor card. + syslog.syslog(syslog.LOG_INFO, 'start_http_server is set, starting http-server') + if self.http_config: + with socketserver.TCPServer((self.http_server_ip, self.http_server_port), HTTPRequestHandler) as httpd: + syslog.syslog(syslog.LOG_INFO, 'HTTP Server Port:{} home:{}'.format(self.http_server_port, http_dir)) + httpd.serve_forever() + else: + syslog.syslog(syslog.LOG_INFO, 'start_http_server is not set, exiting...') + +def main(): + parser = argparse.ArgumentParser(description='Python3 HTTP Server') + parser.add_argument('--config-file', help='HTTP Server config yaml file', default=None) + args = parser.parse_args() + + HttpServer(args).run() + +if __name__ == '__main__': + main() diff --git a/dockers/docker-database/supervisord.conf.j2 b/dockers/docker-database/supervisord.conf.j2 index c73c6e783e81..852d20ac1344 100644 --- a/dockers/docker-database/supervisord.conf.j2 +++ b/dockers/docker-database/supervisord.conf.j2 @@ -56,3 +56,23 @@ stdout_logfile=syslog stderr_logfile=syslog dependent_startup=true dependent_startup_wait_for=rsyslogd:running + +{% if INSTANCES %} +{% for redis_inst, redis_items in INSTANCES.items() %} +{%- if redis_inst == 'redis_chassis' %} +[program: http-server] +; http-server should run only on database-chassis which hosts redis_chassis server. +; Using 2 sec sleep in command to give the process enough run time to reach +; RUNNING state when the process needs to exit with status 0 when start_http_server +; config is not set. +command=/bin/bash -c "sleep 2 && python3 /usr/local/bin/http-server" +priority=3 +autostart=true +autorestart=unexpected +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running +{%- endif %} +{%- endfor %} +{% endif %} diff --git a/rules/docker-database.mk b/rules/docker-database.mk index a10609933c35..92190619cbdd 100644 --- a/rules/docker-database.mk +++ b/rules/docker-database.mk @@ -28,6 +28,7 @@ $(DOCKER_DATABASE)_CONTAINER_NAME = database $(DOCKER_DATABASE)_RUN_OPT += --privileged -t $(DOCKER_DATABASE)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro $(DOCKER_DATABASE)_RUN_OPT += -v /etc/timezone:/etc/timezone:ro +$(DOCKER_DATABASE)_RUN_OPT += -v /var/www/:/var/www/:ro $(DOCKER_DATABASE)_BASE_IMAGE_FILES += redis-cli:/usr/bin/redis-cli $(DOCKER_DATABASE)_FILES += $(SYSCTL_NET_CONFIG) $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT)