diff --git a/modules/network/dhcp-1/bin/radvd-service b/modules/network/dhcp-1/bin/radvd-service new file mode 100644 index 000000000..1cfe499cb --- /dev/null +++ b/modules/network/dhcp-1/bin/radvd-service @@ -0,0 +1,55 @@ +#!/bin/bash + +# Copyright 2023 Google LLC +# +# 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 +# +# https://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. + +RA_PID_FILE=/var/run/radvd/radvd.pid +RA_LOG_FILE=/runtime/network/dhcp1-radvd.log + +stop_radvd(){ + # Directly kill by PID file reference + if [ -f "$RA_PID_FILE" ]; then + kill -9 $(cat $RA_PID_FILE) || true + rm -f $RA_PID_FILE + fi +} + +start_radvd(){ + /usr/sbin/radvd -m logfile -l $RA_LOG_FILE -p $RA_PID_FILE +} + +case "$1" in + start) + start_radvd + ;; + stop) + stop_radvd + ;; + restart) + stop_radvd + sleep 1 + start_radvd + ;; + status) + if [ -f "$RA_PID_FILE" ]; then + echo "radvd service is running." + else + echo "radvd service is not running." + fi + ;; + *) + echo "Usage: $0 {start|stop|status|restart}" + exit 1 + ;; +esac \ No newline at end of file diff --git a/modules/network/dhcp-1/bin/start_network_service b/modules/network/dhcp-1/bin/start_network_service index 9f4a3dc51..82b4c6e33 100644 --- a/modules/network/dhcp-1/bin/start_network_service +++ b/modules/network/dhcp-1/bin/start_network_service @@ -29,63 +29,23 @@ sysctl -p # Create leases file if needed touch /var/lib/dhcp/dhcpd.leases -#Create directory for radvd +# Create directory for radvd mkdir /var/run/radvd -#Create and set permissions on the log files +# Create and set permissions on the log files touch $DHCP_LOG_FILE touch $RA_LOG_FILE chown $HOST_USER $DHCP_LOG_FILE chown $HOST_USER $RA_LOG_FILE -#Move the config files to the correct location +# Move the config files to the correct location +cp /testrun/conf/isc-dhcp-server /etc/default/ cp /testrun/conf/dhcpd.conf /etc/dhcp/dhcpd.conf cp /testrun/conf/radvd.conf /etc/radvd.conf -# Restart dhcp server when config changes -while true; do +# Move the radvd-sevice file to the correct location +cp /testrun/bin/radvd-service /usr/local/bin/ - new_checksum=$(md5sum $CONFIG_FILE) - - if [ "$checksum" == "$new_checksum" ]; then - sleep 2 - continue - fi - - echo Config changed. Restarting dhcp server at $(date).. - - if [ -f $DHCP_PID_FILE ]; then - kill -9 $(cat $DHCP_PID_FILE) || true - rm -f $DHCP_PID_FILE - fi - - if [ -f $RA_PID_FILE ]; then - kill -9 $(cat $RA_PID_FILE) || true - rm -f $RA_PID_FILE - fi - - checksum=$new_checksum - - echo Starting isc-dhcp-server at $(date) - - radvd -m logfile -l $RA_LOG_FILE -p $RA_PID_FILE - dhcpd -d &> $DHCP_LOG_FILE & - - while [ ! -f $DHCP_PID_FILE ]; do - echo Waiting for $DHCP_PID_FILE... - sleep 2 - done - - echo $DHCP_PID_FILE now available - - while [ ! -f $RA_PID_FILE ]; do - echo Waiting for $RA_PID_FILE... - sleep 2 - done - - echo $RA_PID_FILE now available - - echo Server now stable - -done \ No newline at end of file +# Start the DHCP Server +python3 -u /testrun/python/src/grpc_server/dhcp_server.py \ No newline at end of file diff --git a/modules/network/dhcp-1/conf/isc-dhcp-server b/modules/network/dhcp-1/conf/isc-dhcp-server new file mode 100644 index 000000000..44db95cd9 --- /dev/null +++ b/modules/network/dhcp-1/conf/isc-dhcp-server @@ -0,0 +1,4 @@ +# On what interfaces should the DHCP server (dhcpd) serve DHCP requests? +# Separate multiple interfaces with spaces, e.g. "eth0 eth1". +INTERFACESv4="veth0" +#INTERFACESv6="veth0" diff --git a/modules/network/dhcp-1/dhcp-1.Dockerfile b/modules/network/dhcp-1/dhcp-1.Dockerfile index b47378045..6b941d878 100644 --- a/modules/network/dhcp-1/dhcp-1.Dockerfile +++ b/modules/network/dhcp-1/dhcp-1.Dockerfile @@ -25,7 +25,7 @@ RUN apt-get install -y wget RUN wget http://standards-oui.ieee.org/oui.txt -P /usr/local/etc/ # Install dhcp server -RUN apt-get install -y isc-dhcp-server radvd +RUN apt-get install -y isc-dhcp-server radvd systemd # Copy over all configuration files COPY $MODULE_DIR/conf /testrun/conf diff --git a/modules/network/dhcp-1/python/src/grpc_server/dhcp_server.py b/modules/network/dhcp-1/python/src/grpc_server/dhcp_server.py new file mode 100644 index 000000000..2f67b0c2d --- /dev/null +++ b/modules/network/dhcp-1/python/src/grpc_server/dhcp_server.py @@ -0,0 +1,130 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://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. +"""Contains all the necessary classes to maintain the +DHCP server""" +import time +from common import logger +from common import util +from dhcp_config import DHCPConfig +from radvd_server import RADVDServer + +CONFIG_FILE = '/etc/dhcp/dhcpd.conf' +LOG_NAME = 'dhcp_server' +LOGGER = None + + +class DHCPServer: + """Represents the DHCP Server""" + + def __init__(self): + global LOGGER + LOGGER = logger.get_logger(LOG_NAME, 'dhcp-1') + self.dhcp_config = DHCPConfig() + self.radvd = RADVDServer() + self.dhcp_config.resolve_config() + + def restart(self): + LOGGER.info("Restarting DHCP Server") + isc_started = util.run_command("service isc-dhcp-server restart", False) + radvd_started = self.radvd.restart() + started = isc_started and radvd_started + LOGGER.info("DHCP Restarted: " + str(started)) + return started + + def start(self): + LOGGER.info("Starting DHCP Server") + isc_started = util.run_command("service isc-dhcp-server start", False) + radvd_started = self.radvd.start() + started = isc_started and radvd_started + LOGGER.info("DHCP Started: " + str(started)) + return started + + def stop(self): + LOGGER.info("Stopping DHCP Server") + isc_stopped = util.run_command("service isc-dhcp-server stop", False) + radvd_stopped = self.radvd.stop() + stopped = isc_stopped and radvd_stopped + LOGGER.info("DHCP Stopped: " + str(stopped)) + return stopped + + def is_running(self): + LOGGER.info("Checking DHCP Status") + response = util.run_command("service isc-dhcp-server status") + isc_running = response[0] == 'Status of ISC DHCPv4 server: dhcpd is running.' + radvd_running = self.radvd.is_running() + running = isc_running and radvd_running + LOGGER.info("DHCP Status: " + str(running)) + return running + + def boot(self): + LOGGER.info("Booting DHCP Server") + isc_booted = False + radvd_booted = False + if self.is_running(): + LOGGER.info("Stopping isc-dhcp-server") + stopped = self.stop() + LOGGER.info("isc-dhcp-server stopped: " + str(stopped)) + + if self.radvd.is_running(): + LOGGER.info("Stopping RADVD") + stopped = self.radvd.stop() + LOGGER.info("radvd stopped: " + str(stopped)) + + LOGGER.info("Starting isc-dhcp-server") + if self.start(): + isc_booted = False + # Scan for 5 seconds if not yet ready + for i in range(5): + time.sleep(1) + isc_booted = self.is_running() + if isc_booted: + break; + LOGGER.info("isc-dhcp-server started: " + str(isc_booted)) + + LOGGER.info("Starting RADVD") + if self.radvd.start(): + radvd_booted = False + # Scan for 5 seconds if not yet ready + for i in range(5): + time.sleep(1) + radvd_booted = self.radvd.is_running() + if radvd_booted: + break; + LOGGER.info("RADVD started: " + str(radvd_booted)) + + + + return isc_booted and radvd_booted + +def run(): + dhcp_server = DHCPServer() + booted = dhcp_server.boot() + + if not booted: + LOGGER.error('DHCP Server Failed to boot. Exiting') + sys.exit(1) + + config = str(dhcp_server.dhcp_config) + while True: + dhcp_server.dhcp_config.resolve_config() + new_config = str(dhcp_server.dhcp_config) + if config != new_config: + LOGGER.info("DHCP Config Changed") + config = new_config + success = dhcp_server.restart() + success = dhcp_server.radvd.restart() + time.sleep(1) + +if __name__ == '__main__': + run() diff --git a/modules/network/dhcp-1/python/src/grpc_server/network_service.py b/modules/network/dhcp-1/python/src/grpc_server/network_service.py index bf2b98803..a693ac3a1 100644 --- a/modules/network/dhcp-1/python/src/grpc_server/network_service.py +++ b/modules/network/dhcp-1/python/src/grpc_server/network_service.py @@ -15,6 +15,7 @@ import proto.grpc_pb2_grpc as pb2_grpc import proto.grpc_pb2 as pb2 +from dhcp_server import DHCPServer from dhcp_config import DHCPConfig from dhcp_leases import DHCPLeases @@ -28,6 +29,7 @@ class NetworkService(pb2_grpc.NetworkModule): """gRPC endpoints for the DHCP Server""" def __init__(self): + self._dhcp_server = DHCPServer() self._dhcp_config = None self.dhcp_leases = DHCPLeases() global LOGGER @@ -39,6 +41,42 @@ def _get_dhcp_config(self): self._dhcp_config.resolve_config() return self._dhcp_config + def RestartDHCPServer(self, request, context): # pylint: disable=W0613 + LOGGER.info('Restarting DHCP server') + try: + started = self._dhcp_server.restart() + LOGGER.info('DHCP server restarted: ' + (str(started))) + return pb2.Response(code=200, message='{}') + except Exception as e: # pylint: disable=W0718 + fail_message = 'Failed to restart DHCP server: ' + str(e) + LOGGER.error(fail_message) + LOGGER.error(traceback.format_exc()) + return pb2.Response(code=500, message=fail_message) + + def StartDHCPServer(self, request, context): # pylint: disable=W0613 + LOGGER.info('Starting DHCP server') + try: + started = self._dhcp_server.start() + LOGGER.info('DHCP server started: ' + (str(started))) + return pb2.Response(code=200, message='{}') + except Exception as e: # pylint: disable=W0718 + fail_message = 'Failed to start DHCP server: ' + str(e) + LOGGER.error(fail_message) + LOGGER.error(traceback.format_exc()) + return pb2.Response(code=500, message=fail_message) + + def StopDHCPServer(self, request, context): # pylint: disable=W0613 + LOGGER.info('Stopping DHCP server') + try: + stopped = self._dhcp_server.stop() + LOGGER.info('DHCP server stopped: ' + (str(stopped))) + return pb2.Response(code=200, message='{}') + except Exception as e: # pylint: disable=W0718 + fail_message = 'Failed to stop DHCP server: ' + str(e) + LOGGER.error(fail_message) + LOGGER.error(traceback.format_exc()) + return pb2.Response(code=500, message=fail_message) + def AddReservedLease(self, request, context): # pylint: disable=W0613 LOGGER.info('Add reserved lease called') try: @@ -151,7 +189,6 @@ def GetStatus(self, request, context): # pylint: disable=W0613 """ Return the current status of the network module """ - # ToDo: Figure out how to resolve the current DHCP status - dhcp_status = True + dhcp_status = self._dhcp_server.is_running() message = str({'dhcpStatus': dhcp_status}) - return pb2.Response(code=200, message=message) + return pb2.Response(code=200, message=message) \ No newline at end of file diff --git a/modules/network/dhcp-1/python/src/grpc_server/proto/grpc.proto b/modules/network/dhcp-1/python/src/grpc_server/proto/grpc.proto index d9f56213e..e6abda674 100644 --- a/modules/network/dhcp-1/python/src/grpc_server/proto/grpc.proto +++ b/modules/network/dhcp-1/python/src/grpc_server/proto/grpc.proto @@ -2,6 +2,12 @@ syntax = "proto3"; service NetworkModule { + rpc RestartDHCPServer(RestartDHCPServerRequest) returns (Response) {}; + + rpc StartDHCPServer(StartDHCPServerRequest) returns (Response) {}; + + rpc StopDHCPServer(StopDHCPServerRequest) returns (Response) {}; + rpc AddReservedLease(AddReservedLeaseRequest) returns (Response) {}; rpc DeleteReservedLease(DeleteReservedLeaseRequest) returns (Response) {}; @@ -29,6 +35,12 @@ message DeleteReservedLeaseRequest { string hw_addr = 1; } +message RestartDHCPServerRequest {} + +message StartDHCPServerRequest {} + +message StopDHCPServerRequest {} + message DisableFailoverRequest {} message EnableFailoverRequest {} @@ -53,7 +65,7 @@ message Response { } message DHCPRange { - int32 code = 1; + int32 code = 1; string start = 2; string end = 3; -} +} \ No newline at end of file diff --git a/modules/network/dhcp-1/python/src/grpc_server/radvd_server.py b/modules/network/dhcp-1/python/src/grpc_server/radvd_server.py new file mode 100644 index 000000000..48e063e61 --- /dev/null +++ b/modules/network/dhcp-1/python/src/grpc_server/radvd_server.py @@ -0,0 +1,55 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://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. +"""Contains all the necessary classes to maintain the +DHCP server""" +import time +from common import logger +from common import util +from dhcp_config import DHCPConfig + +CONFIG_FILE = '/etc/dhcp/dhcpd.conf' +LOG_NAME = 'radvd' +LOGGER = None + + +class RADVDServer: + """Represents the RADVD Server""" + + def __init__(self): + global LOGGER + LOGGER = logger.get_logger(LOG_NAME, 'dhcp-1') + + def restart(self): + LOGGER.info("Restarting RADVD Server") + response = util.run_command("radvd-service restart", False) + LOGGER.info("RADVD Restarted: " + str(response)) + return response + + def start(self): + LOGGER.info("Starting RADVD Server") + response = util.run_command("radvd-service start", False) + LOGGER.info("RADVD Started: " + str(response)) + return response + + def stop(self): + LOGGER.info("Stopping RADVD Server") + response = util.run_command("radvd-service stop", False) + LOGGER.info("RADVD Stopped: " + str(response)) + return response + + def is_running(self): + LOGGER.info("Checking RADVD Status") + response = util.run_command("radvd-service status") + LOGGER.info("RADVD Status: " + str(response)) + return response[0] == 'radvd service is running.' diff --git a/modules/network/dhcp-2/bin/radvd-service b/modules/network/dhcp-2/bin/radvd-service new file mode 100644 index 000000000..912c64ee3 --- /dev/null +++ b/modules/network/dhcp-2/bin/radvd-service @@ -0,0 +1,55 @@ +#!/bin/bash + +# Copyright 2023 Google LLC +# +# 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 +# +# https://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. + +RA_PID_FILE=/var/run/radvd/radvd.pid +RA_LOG_FILE=/runtime/network/dhcp2-radvd.log + +stop_radvd(){ + # Directly kill by PID file reference + if [ -f "$RA_PID_FILE" ]; then + kill -9 $(cat $RA_PID_FILE) || true + rm -f $RA_PID_FILE + fi +} + +start_radvd(){ + /usr/sbin/radvd -m logfile -l $RA_LOG_FILE -p $RA_PID_FILE +} + +case "$1" in + start) + start_radvd + ;; + stop) + stop_radvd + ;; + restart) + stop_radvd + sleep 1 + start_radvd + ;; + status) + if [ -f "$RA_PID_FILE" ]; then + echo "radvd service is running." + else + echo "radvd service is not running." + fi + ;; + *) + echo "Usage: $0 {start|stop|status|restart}" + exit 1 + ;; +esac \ No newline at end of file diff --git a/modules/network/dhcp-2/bin/start_network_service b/modules/network/dhcp-2/bin/start_network_service index 723689278..ed7d3125e 100644 --- a/modules/network/dhcp-2/bin/start_network_service +++ b/modules/network/dhcp-2/bin/start_network_service @@ -29,63 +29,23 @@ sysctl -p # Create leases file if needed touch /var/lib/dhcp/dhcpd.leases -#Create directory for radvd +# Create directory for radvd mkdir /var/run/radvd -#Create and set permissions on the log files +# Create and set permissions on the log files touch $DHCP_LOG_FILE touch $RA_LOG_FILE chown $HOST_USER $DHCP_LOG_FILE chown $HOST_USER $RA_LOG_FILE -#Move the config files to the correct location +# Move the config files to the correct location +cp /testrun/conf/isc-dhcp-server /etc/default/ cp /testrun/conf/dhcpd.conf /etc/dhcp/dhcpd.conf cp /testrun/conf/radvd.conf /etc/radvd.conf -# Restart dhcp server when config changes -while true; do +# Move the radvd-sevice file to the correct location +cp /testrun/bin/radvd-service /usr/local/bin/ - new_checksum=$(md5sum $CONFIG_FILE) - - if [ "$checksum" == "$new_checksum" ]; then - sleep 2 - continue - fi - - echo Config changed. Restarting dhcp server at $(date).. - - if [ -f $DHCP_PID_FILE ]; then - kill -9 $(cat $DHCP_PID_FILE) || true - rm -f $DHCP_PID_FILE - fi - - if [ -f $RA_PID_FILE ]; then - kill -9 $(cat $RA_PID_FILE) || true - rm -f $RA_PID_FILE - fi - - checksum=$new_checksum - - echo Starting isc-dhcp-server at $(date) - - radvd -m logfile -l $RA_LOG_FILE -p $RA_PID_FILE - dhcpd -d &> $DHCP_LOG_FILE & - - while [ ! -f $DHCP_PID_FILE ]; do - echo Waiting for $DHCP_PID_FILE... - sleep 2 - done - - echo $DHCP_PID_FILE now available - - while [ ! -f $RA_PID_FILE ]; do - echo Waiting for $RA_PID_FILE... - sleep 2 - done - - echo $RA_PID_FILE now available - - echo Server now stable - -done \ No newline at end of file +# Start the DHCP Server +python3 -u /testrun/python/src/grpc_server/dhcp_server.py \ No newline at end of file diff --git a/modules/network/dhcp-2/conf/isc-dhcp-server b/modules/network/dhcp-2/conf/isc-dhcp-server new file mode 100644 index 000000000..44db95cd9 --- /dev/null +++ b/modules/network/dhcp-2/conf/isc-dhcp-server @@ -0,0 +1,4 @@ +# On what interfaces should the DHCP server (dhcpd) serve DHCP requests? +# Separate multiple interfaces with spaces, e.g. "eth0 eth1". +INTERFACESv4="veth0" +#INTERFACESv6="veth0" diff --git a/modules/network/dhcp-2/dhcp-2.Dockerfile b/modules/network/dhcp-2/dhcp-2.Dockerfile index df77cb811..153aa50e7 100644 --- a/modules/network/dhcp-2/dhcp-2.Dockerfile +++ b/modules/network/dhcp-2/dhcp-2.Dockerfile @@ -18,8 +18,14 @@ FROM test-run/base:latest ARG MODULE_NAME=dhcp-2 ARG MODULE_DIR=modules/network/$MODULE_NAME +# Install all necessary packages +RUN apt-get install -y wget + +#Update the oui.txt file from ieee +RUN wget http://standards-oui.ieee.org/oui.txt -P /usr/local/etc/ + # Install dhcp server -RUN apt-get install -y isc-dhcp-server radvd +RUN apt-get install -y isc-dhcp-server radvd systemd # Copy over all configuration files COPY $MODULE_DIR/conf /testrun/conf @@ -28,5 +34,4 @@ COPY $MODULE_DIR/conf /testrun/conf COPY $MODULE_DIR/bin /testrun/bin # Copy over all python files -COPY $MODULE_DIR/python /testrun/python - +COPY $MODULE_DIR/python /testrun/python \ No newline at end of file diff --git a/modules/network/dhcp-2/python/src/grpc_server/dhcp_config.py b/modules/network/dhcp-2/python/src/grpc_server/dhcp_config.py index 444faa87c..33cb5938c 100644 --- a/modules/network/dhcp-2/python/src/grpc_server/dhcp_config.py +++ b/modules/network/dhcp-2/python/src/grpc_server/dhcp_config.py @@ -33,7 +33,7 @@ def __init__(self): self._peer = None self._reserved_hosts = [] global LOGGER - LOGGER = logger.get_logger(LOG_NAME, 'dhcp-1') + LOGGER = logger.get_logger(LOG_NAME, 'dhcp-2') def add_reserved_host(self, hostname, hw_addr, ip_addr): host = DHCPReservedHost(hostname=hostname, @@ -490,4 +490,4 @@ def resolve_host(self, reserved_host): self.hw_addr = part.strip().split(HARDWARE_KEY)[1].strip().split(';')[0] elif FIXED_ADDRESS_KEY in part: self.fixed_addr = part.strip().split( - FIXED_ADDRESS_KEY)[1].strip().split(';')[0] + FIXED_ADDRESS_KEY)[1].strip().split(';')[0] \ No newline at end of file diff --git a/modules/network/dhcp-2/python/src/grpc_server/dhcp_server.py b/modules/network/dhcp-2/python/src/grpc_server/dhcp_server.py new file mode 100644 index 000000000..1431d6ddd --- /dev/null +++ b/modules/network/dhcp-2/python/src/grpc_server/dhcp_server.py @@ -0,0 +1,130 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://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. +"""Contains all the necessary classes to maintain the +DHCP server""" +import time +from common import logger +from common import util +from dhcp_config import DHCPConfig +from radvd_server import RADVDServer + +CONFIG_FILE = '/etc/dhcp/dhcpd.conf' +LOG_NAME = 'dhcp_server' +LOGGER = None + + +class DHCPServer: + """Represents the DHCP Server""" + + def __init__(self): + global LOGGER + LOGGER = logger.get_logger(LOG_NAME, 'dhcp-2') + self.dhcp_config = DHCPConfig() + self.radvd = RADVDServer() + self.dhcp_config.resolve_config() + + def restart(self): + LOGGER.info("Restarting DHCP Server") + isc_started = util.run_command("service isc-dhcp-server restart", False) + radvd_started = self.radvd.restart() + started = isc_started and radvd_started + LOGGER.info("DHCP Restarted: " + str(started)) + return started + + def start(self): + LOGGER.info("Starting DHCP Server") + isc_started = util.run_command("service isc-dhcp-server start", False) + radvd_started = self.radvd.start() + started = isc_started and radvd_started + LOGGER.info("DHCP Started: " + str(started)) + return started + + def stop(self): + LOGGER.info("Stopping DHCP Server") + isc_stopped = util.run_command("service isc-dhcp-server stop", False) + radvd_stopped = self.radvd.stop() + stopped = isc_stopped and radvd_stopped + LOGGER.info("DHCP Stopped: " + str(stopped)) + return stopped + + def is_running(self): + LOGGER.info("Checking DHCP Status") + response = util.run_command("service isc-dhcp-server status") + isc_running = response[0] == 'Status of ISC DHCPv4 server: dhcpd is running.' + radvd_running = self.radvd.is_running() + running = isc_running and radvd_running + LOGGER.info("DHCP Status: " + str(running)) + return running + + def boot(self): + LOGGER.info("Booting DHCP Server") + isc_booted = False + radvd_booted = False + if self.is_running(): + LOGGER.info("Stopping isc-dhcp-server") + stopped = self.stop() + LOGGER.info("isc-dhcp-server stopped: " + str(stopped)) + + if self.radvd.is_running(): + LOGGER.info("Stopping RADVD") + stopped = self.radvd.stop() + LOGGER.info("radvd stopped: " + str(stopped)) + + LOGGER.info("Starting isc-dhcp-server") + if self.start(): + isc_booted = False + # Scan for 5 seconds if not yet ready + for i in range(5): + time.sleep(1) + isc_booted = self.is_running() + if isc_booted: + break; + LOGGER.info("isc-dhcp-server started: " + str(isc_booted)) + + LOGGER.info("Starting RADVD") + if self.radvd.start(): + radvd_booted = False + # Scan for 5 seconds if not yet ready + for i in range(5): + time.sleep(1) + radvd_booted = self.radvd.is_running() + if radvd_booted: + break; + LOGGER.info("RADVD started: " + str(radvd_booted)) + + + + return isc_booted and radvd_booted + +def run(): + dhcp_server = DHCPServer() + booted = dhcp_server.boot() + + if not booted: + LOGGER.error('DHCP Server Failed to boot. Exiting') + sys.exit(1) + + config = str(dhcp_server.dhcp_config) + while True: + dhcp_server.dhcp_config.resolve_config() + new_config = str(dhcp_server.dhcp_config) + if config != new_config: + LOGGER.info("DHCP Config Changed") + config = new_config + success = dhcp_server.restart() + success = dhcp_server.radvd.restart() + time.sleep(1) + +if __name__ == '__main__': + run() diff --git a/modules/network/dhcp-2/python/src/grpc_server/network_service.py b/modules/network/dhcp-2/python/src/grpc_server/network_service.py index 053d26d6b..5af9e6c44 100644 --- a/modules/network/dhcp-2/python/src/grpc_server/network_service.py +++ b/modules/network/dhcp-2/python/src/grpc_server/network_service.py @@ -15,6 +15,7 @@ import proto.grpc_pb2_grpc as pb2_grpc import proto.grpc_pb2 as pb2 +from dhcp_server import DHCPServer from dhcp_config import DHCPConfig from dhcp_leases import DHCPLeases @@ -28,6 +29,7 @@ class NetworkService(pb2_grpc.NetworkModule): """gRPC endpoints for the DHCP Server""" def __init__(self): + self._dhcp_server = DHCPServer() self._dhcp_config = None self.dhcp_leases = DHCPLeases() global LOGGER @@ -39,6 +41,42 @@ def _get_dhcp_config(self): self._dhcp_config.resolve_config() return self._dhcp_config + def RestartDHCPServer(self, request, context): # pylint: disable=W0613 + LOGGER.info('Restarting DHCP server') + try: + started = self._dhcp_server.restart() + LOGGER.info('DHCP server restarted: ' + (str(started))) + return pb2.Response(code=200, message='{}') + except Exception as e: # pylint: disable=W0718 + fail_message = 'Failed to restart DHCP server: ' + str(e) + LOGGER.error(fail_message) + LOGGER.error(traceback.format_exc()) + return pb2.Response(code=500, message=fail_message) + + def StartDHCPServer(self, request, context): # pylint: disable=W0613 + LOGGER.info('Starting DHCP server') + try: + started = self._dhcp_server.start() + LOGGER.info('DHCP server started: ' + (str(started))) + return pb2.Response(code=200, message='{}') + except Exception as e: # pylint: disable=W0718 + fail_message = 'Failed to start DHCP server: ' + str(e) + LOGGER.error(fail_message) + LOGGER.error(traceback.format_exc()) + return pb2.Response(code=500, message=fail_message) + + def StopDHCPServer(self, request, context): # pylint: disable=W0613 + LOGGER.info('Stopping DHCP server') + try: + stopped = self._dhcp_server.stop() + LOGGER.info('DHCP server stopped: ' + (str(stopped))) + return pb2.Response(code=200, message='{}') + except Exception as e: # pylint: disable=W0718 + fail_message = 'Failed to stop DHCP server: ' + str(e) + LOGGER.error(fail_message) + LOGGER.error(traceback.format_exc()) + return pb2.Response(code=500, message=fail_message) + def AddReservedLease(self, request, context): # pylint: disable=W0613 LOGGER.info('Add reserved lease called') try: @@ -151,7 +189,6 @@ def GetStatus(self, request, context): # pylint: disable=W0613 """ Return the current status of the network module """ - # ToDo: Figure out how to resolve the current DHCP status - dhcp_status = True + dhcp_status = self._dhcp_server.is_running() message = str({'dhcpStatus': dhcp_status}) - return pb2.Response(code=200, message=message) + return pb2.Response(code=200, message=message) \ No newline at end of file diff --git a/modules/network/dhcp-2/python/src/grpc_server/proto/grpc.proto b/modules/network/dhcp-2/python/src/grpc_server/proto/grpc.proto index b6a11a75b..e6abda674 100644 --- a/modules/network/dhcp-2/python/src/grpc_server/proto/grpc.proto +++ b/modules/network/dhcp-2/python/src/grpc_server/proto/grpc.proto @@ -2,6 +2,12 @@ syntax = "proto3"; service NetworkModule { + rpc RestartDHCPServer(RestartDHCPServerRequest) returns (Response) {}; + + rpc StartDHCPServer(StartDHCPServerRequest) returns (Response) {}; + + rpc StopDHCPServer(StopDHCPServerRequest) returns (Response) {}; + rpc AddReservedLease(AddReservedLeaseRequest) returns (Response) {}; rpc DeleteReservedLease(DeleteReservedLeaseRequest) returns (Response) {}; @@ -29,6 +35,12 @@ message DeleteReservedLeaseRequest { string hw_addr = 1; } +message RestartDHCPServerRequest {} + +message StartDHCPServerRequest {} + +message StopDHCPServerRequest {} + message DisableFailoverRequest {} message EnableFailoverRequest {} @@ -56,4 +68,4 @@ message DHCPRange { int32 code = 1; string start = 2; string end = 3; -} +} \ No newline at end of file diff --git a/modules/network/dhcp-2/python/src/grpc_server/radvd_server.py b/modules/network/dhcp-2/python/src/grpc_server/radvd_server.py new file mode 100644 index 000000000..0c6ef90d6 --- /dev/null +++ b/modules/network/dhcp-2/python/src/grpc_server/radvd_server.py @@ -0,0 +1,55 @@ +# Copyright 2023 Google LLC +# +# 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 +# +# https://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. +"""Contains all the necessary classes to maintain the +DHCP server""" +import time +from common import logger +from common import util +from dhcp_config import DHCPConfig + +CONFIG_FILE = '/etc/dhcp/dhcpd.conf' +LOG_NAME = 'radvd' +LOGGER = None + + +class RADVDServer: + """Represents the RADVD Server""" + + def __init__(self): + global LOGGER + LOGGER = logger.get_logger(LOG_NAME, 'dhcp-2') + + def restart(self): + LOGGER.info("Restarting RADVD Server") + response = util.run_command("radvd-service restart", False) + LOGGER.info("RADVD Restarted: " + str(response)) + return response + + def start(self): + LOGGER.info("Starting RADVD Server") + response = util.run_command("radvd-service start", False) + LOGGER.info("RADVD Started: " + str(response)) + return response + + def stop(self): + LOGGER.info("Stopping RADVD Server") + response = util.run_command("radvd-service stop", False) + LOGGER.info("RADVD Stopped: " + str(response)) + return response + + def is_running(self): + LOGGER.info("Checking RADVD Status") + response = util.run_command("radvd-service status") + LOGGER.info("RADVD Status: " + str(response)) + return response[0] == 'radvd service is running.'