Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug/unit test runtime #655

Merged
merged 4 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ build/

# Ignore generated files from unit tests
testing/unit_test/temp/
testing/unit/conn/output/
testing/unit/dns/output/
testing/unit/nmap/output/
testing/unit/ntp/output/
Expand Down
71 changes: 71 additions & 0 deletions modules/test/base/bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/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.

# Define the local mount point to store local files to
export OUTPUT_DIR="/runtime/output"

# Directory where all binaries will be loaded
export BIN_DIR="/testrun/bin"

# Default interface should be veth0 for all containers
export IFACE=veth0

# Create a local user that matches the same as the host
# to be used for correct file ownership for various logs
# HOST_USER mapped in via docker container environemnt variables
useradd $HOST_USER

# Set permissions on the output files
chown -R $HOST_USER $OUTPUT_DIR

# Enable IPv6 for all containers
sysctl net.ipv6.conf.all.disable_ipv6=0
sysctl -p

# Read in the config file
CONF_FILE="/testrun/conf/module_config.json"
CONF=`cat $CONF_FILE`

if [[ -z $CONF ]]
then
echo "No config file present at $CONF_FILE. Exiting startup."
exit 1
fi

# Extract the necessary config parameters
export MODULE_NAME=$(echo "$CONF" | jq -r '.config.meta.name')
export NETWORK_REQUIRED=$(echo "$CONF" | jq -r '.config.network')
export GRPC=$(echo "$CONF" | jq -r '.config.grpc')

# Validate the module name is present
if [[ -z "$MODULE_NAME" || "$MODULE_NAME" == "null" ]]
then
echo "No module name present in $CONF_FILE. Exiting startup."
exit 1
fi

# Setup the PYTHONPATH so all imports work as expected
echo "Setting up PYTHONPATH..."
export PYTHONPATH=$($BIN_DIR/setup_python_path)
echo "PYTHONPATH: $PYTHONPATH"

echo "Configuring binary files..."
$BIN_DIR/setup_binaries $BIN_DIR

# Build all gRPC files from the proto for use in
# gRPC clients for communications to network modules
echo "Building gRPC files from available proto files..."
$BIN_DIR/setup_grpc_clients
13 changes: 12 additions & 1 deletion modules/test/base/bin/start
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.

/testrun/bin/start_module
# Allow one argument which is the unit test file to run
# instead of running the test module
UNIT_TEST_FILE=$1

source /testrun/bin/setup

# Conditionally run start_module based on RUN
if [[ -z "$UNIT_TEST_FILE" ]];then
/testrun/bin/start_module
else
python3 $UNIT_TEST_FILE
fi
146 changes: 45 additions & 101 deletions modules/test/base/bin/start_module
Original file line number Diff line number Diff line change
@@ -1,102 +1,46 @@
#!/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.

# Define the local mount point to store local files to
OUTPUT_DIR="/runtime/output"

# Directory where all binaries will be loaded
BIN_DIR="/testrun/bin"

# Default interface should be veth0 for all containers
IFACE=veth0

# Create a local user that matches the same as the host
# to be used for correct file ownership for various logs
# HOST_USER mapped in via docker container environemnt variables
useradd $HOST_USER

# Set permissions on the output files
chown -R $HOST_USER $OUTPUT_DIR

# Enable IPv6 for all containers
sysctl net.ipv6.conf.all.disable_ipv6=0
sysctl -p

# Read in the config file
CONF_FILE="/testrun/conf/module_config.json"
CONF=`cat $CONF_FILE`

if [[ -z $CONF ]]
then
echo "No config file present at $CONF_FILE. Exiting startup."
exit 1
fi

# Extract the necessary config parameters
MODULE_NAME=$(echo "$CONF" | jq -r '.config.meta.name')
NETWORK_REQUIRED=$(echo "$CONF" | jq -r '.config.network')
GRPC=$(echo "$CONF" | jq -r '.config.grpc')

# Validate the module name is present
if [[ -z "$MODULE_NAME" || "$MODULE_NAME" == "null" ]]
then
echo "No module name present in $CONF_FILE. Exiting startup."
exit 1
fi

# Setup the PYTHONPATH so all imports work as expected
echo "Setting up PYTHONPATH..."
export PYTHONPATH=$($BIN_DIR/setup_python_path)
echo "PYTHONPATH: $PYTHONPATH"

# Build all gRPC files from the proto for use in
# gRPC clients for communications to network modules
echo "Building gRPC files from available proto files..."
$BIN_DIR/setup_grpc_clients

echo "Configuring binary files..."
$BIN_DIR/setup_binaries $BIN_DIR

echo "Starting module $MODULE_NAME..."

# Only start network services if the test container needs
# a network connection to run its tests
if [ $NETWORK_REQUIRED == "true" ];then
# Wait for interface to become ready
$BIN_DIR/wait_for_interface $IFACE

# Start network capture
$BIN_DIR/capture $MODULE_NAME $IFACE
fi

# Start the grpc server
if [[ ! -z $GRPC && ! $GRPC == "null" ]]
then
GRPC_PORT=$(echo "$GRPC" | jq -r '.port')
if [[ ! -z $GRPC_PORT && ! $GRPC_PORT == "null" ]]
then
echo "gRPC port resolved from config: $GRPC_PORT"
$BIN_DIR/start_grpc "-p $GRPC_PORT"
else
$BIN_DIR/start_grpc
fi
fi

# Small pause to let all core services stabalize
sleep 3

# Start the test module
#!/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.

echo "Starting module $MODULE_NAME..."

# Only start network services if the test container needs
# a network connection to run its tests
if [ $NETWORK_REQUIRED == "true" ];then
# Wait for interface to become ready
$BIN_DIR/wait_for_interface $IFACE

# Start network capture
$BIN_DIR/capture $MODULE_NAME $IFACE
fi

# Start the grpc server
if [[ ! -z $GRPC && ! $GRPC == "null" ]]
then
GRPC_PORT=$(echo "$GRPC" | jq -r '.port')
if [[ ! -z $GRPC_PORT && ! $GRPC_PORT == "null" ]]
then
echo "gRPC port resolved from config: $GRPC_PORT"
$BIN_DIR/start_grpc "-p $GRPC_PORT"
else
$BIN_DIR/start_grpc
fi
fi

# Small pause to let all core services stabalize
sleep 3

# Start the test module
$BIN_DIR/start_test_module $MODULE_NAME $IFACE
6 changes: 0 additions & 6 deletions modules/test/baseline/baseline.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,5 @@ COPY $MODULE_DIR/conf /testrun/conf
# Copy over all binary files
COPY $MODULE_DIR/bin /testrun/bin

# Remove incorrect line endings
RUN dos2unix /testrun/bin/*

# Make sure all the bin files are executable
RUN chmod u+x /testrun/bin/*

# Copy over all python files
COPY $MODULE_DIR/python /testrun/python
6 changes: 0 additions & 6 deletions modules/test/conn/conn.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,5 @@ COPY $MODULE_DIR/conf /testrun/conf
# Copy over all binary files
COPY $MODULE_DIR/bin /testrun/bin

# Remove incorrect line endings
RUN dos2unix /testrun/bin/*

# Make sure all the bin files are executable
RUN chmod u+x /testrun/bin/*

# Copy over all python files
COPY $MODULE_DIR/python /testrun/python
35 changes: 22 additions & 13 deletions modules/test/conn/python/src/connection_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,23 @@
class ConnectionModule(TestModule):
"""Connection Test module"""

def __init__(self, module, log_dir=None, conf_file=None, results_dir=None):
def __init__(self,
module,
log_dir=None,
conf_file=None,
results_dir=None,
startup_capture_file=STARTUP_CAPTURE_FILE,
monitor_capture_file=MONITOR_CAPTURE_FILE):

super().__init__(module_name=module,
log_name=LOG_NAME,
log_dir=log_dir,
conf_file=conf_file,
results_dir=results_dir)
global LOGGER
LOGGER = self._get_logger()
self.startup_capture_file = startup_capture_file
self.monitor_capture_file = monitor_capture_file
self._port_stats = PortStatsUtil(logger=LOGGER)
self.dhcp1_client = DHCPClient1()
self.dhcp2_client = DHCPClient2()
Expand Down Expand Up @@ -106,7 +115,8 @@ def _connection_switch_arp_inspection(self):
no_arp = True

# Read all the pcap files
packets = rdpcap(STARTUP_CAPTURE_FILE) + rdpcap(MONITOR_CAPTURE_FILE)
packets = rdpcap(self.startup_capture_file) + rdpcap(
self.monitor_capture_file)
for packet in packets:

# We are not interested in packets unless they are ARP packets
Expand All @@ -123,12 +133,8 @@ def _connection_switch_arp_inspection(self):

# Check MAC address matches IP address
if (arp_packet.hwsrc == self._device_mac
and (arp_packet.psrc not in (
self._device_ipv4_addr,
'0.0.0.0'
)) and not arp_packet.psrc.startswith(
'169.254'
)):
and (arp_packet.psrc not in (self._device_ipv4_addr, '0.0.0.0'))
and not arp_packet.psrc.startswith('169.254')):
LOGGER.info(f'Bad ARP packet detected for MAC: {self._device_mac}')
LOGGER.info(f'''ARP packet from IP {arp_packet.psrc}
does not match {self._device_ipv4_addr}''')
Expand All @@ -145,7 +151,8 @@ def _connection_switch_dhcp_snooping(self):
disallowed_dhcp_types = [2, 4, 5, 6, 9, 10, 12, 13, 15, 17]

# Read all the pcap files
packets = rdpcap(STARTUP_CAPTURE_FILE) + rdpcap(MONITOR_CAPTURE_FILE)
packets = rdpcap(self.startup_capture_file) + rdpcap(
self.monitor_capture_file)
for packet in packets:

# We are not interested in packets unless they are DHCP packets
Expand Down Expand Up @@ -225,7 +232,8 @@ def _connection_single_ip(self):
return result, 'No MAC address found.'

# Read all the pcap files containing DHCP packet information
packets = rdpcap(STARTUP_CAPTURE_FILE) + rdpcap(MONITOR_CAPTURE_FILE)
packets = rdpcap(self.startup_capture_file) + rdpcap(
self.monitor_capture_file)

# Extract MAC addresses from DHCP packets
mac_addresses = set()
Expand Down Expand Up @@ -399,8 +407,9 @@ def _connection_ipv6_slaac(self):
return result

def _has_slaac_addres(self):
packet_capture = (rdpcap(STARTUP_CAPTURE_FILE) +
rdpcap(MONITOR_CAPTURE_FILE) + rdpcap(DHCP_CAPTURE_FILE))
packet_capture = (rdpcap(self.startup_capture_file) +
rdpcap(self.monitor_capture_file) +
rdpcap(DHCP_CAPTURE_FILE))
sends_ipv6 = False
for packet_number, packet in enumerate(packet_capture, start=1):
if IPv6 in packet and packet.src == self._device_mac:
Expand Down Expand Up @@ -437,7 +446,7 @@ def _ping(self, host, ipv6=False):
cmd += ' -6 ' if ipv6 else ''
cmd += str(host)
#cmd = 'ping -c 1 ' + str(host)
success = util.run_command(cmd, output=False) # pylint: disable=E1120
success = util.run_command(cmd, output=False) # pylint: disable=E1120
return success

def restore_failover_dhcp_server(self, subnet):
Expand Down
6 changes: 0 additions & 6 deletions modules/test/dns/dns.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,5 @@ COPY $MODULE_DIR/conf /testrun/conf
# Copy over all binary files
COPY $MODULE_DIR/bin /testrun/bin

# Remove incorrect line endings
RUN dos2unix /testrun/bin/*

# Make sure all the bin files are executable
RUN chmod u+x /testrun/bin/*

# Copy over all python files
COPY $MODULE_DIR/python /testrun/python
6 changes: 0 additions & 6 deletions modules/test/ntp/ntp.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,5 @@ COPY $MODULE_DIR/conf /testrun/conf
# Copy over all binary files
COPY $MODULE_DIR/bin /testrun/bin

# Remove incorrect line endings
RUN dos2unix /testrun/bin/*

# Make sure all the bin files are executable
RUN chmod u+x /testrun/bin/*

# Copy over all python files
COPY $MODULE_DIR/python /testrun/python
Loading