Skip to content

Commit 4d7421d

Browse files
ausphamgshemesh2
authored andcommitted
feat: enable-debug option (sonic-net#18009)
Description of PR Summary: This PR adds remote debugging functionality using https://github.com/microsoft/debugpy support with vs-code for sonic-mgmt container. This will need the follow PR to be mereged as well: feat: add debugpy dependency sonic-buildimage#22341 In summary, one can setup a remote debug container when provide option --enable-debug. For example: ./setup-containers.sh sonic-mgmt-user_master --enable-debug Which will automatically scan for available ports and establish a tunnel between docker and host for debugpy purpose. The user then can execute normal run_test command with --enable-debug added to the end to connect with their vscode client. For example: ./run_tests.sh -n vms-kvm-t0 -d vlab-01 -c bgp/test_bgp_fact.py -f vtestbed.yaml -i ../ansible/veos_vtb --enable-debug Fixes # (issue) 32317137 Approach What is the motivation for this PR? To provide a native-like debug experience, improve our development efficiency. How did you do it? Described above How did you verify/test it? Verified on dev server Signed-off-by: Austin Pham <[email protected]> Signed-off-by: Guy Shemesh <[email protected]>
1 parent f10800b commit 4d7421d

2 files changed

Lines changed: 83 additions & 6 deletions

File tree

setup-container.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ FORCE_REMOVAL="${NO_PARAM}"
4949
VERBOSE_LEVEL="${VERBOSE_MIN}"
5050
SILENT_HOOK="&> /dev/null"
5151

52+
# Sonic-mgmt remote debug feature
53+
DEBUG_PORT_START_RANGE=50000
54+
DEBUG_PORT_END_RANGE=60000
55+
DEFAULT_LOCK_FOLDER="/tmp/sonic-mgmt-locks/"
56+
5257
#
5358
# Functions -----------------------------------------------------------------------------------------------------------
5459
#
@@ -110,13 +115,15 @@ function show_help_and_exit() {
110115
echo " -v explain what is being done"
111116
echo " -x show execution details"
112117
echo " -h display this help and exit"
118+
echo " --enable-debug enable debug mode"
113119
echo
114120
echo "Examples:"
115121
echo " ./${SCRIPT_NAME} -n sonic-mgmt-${USER}_master"
116122
echo " ./${SCRIPT_NAME} -n sonic-mgmt-${USER}_master -i sonicdev-microsoft.azurecr.io:443/docker-sonic-mgmt:latest"
117123
echo " ./${SCRIPT_NAME} -n sonic-mgmt-${USER}_master -d /var/src"
118124
echo " ./${SCRIPT_NAME} -n sonic-mgmt-${USER}_master -m /my/working/dir"
119125
echo " ./${SCRIPT_NAME} -n sonic-mgmt-${USER}_master -p 192.0.2.1:8080:80/tcp"
126+
echo " ./${SCRIPT_NAME} -n sonic-mgmt-${USER}_master --enable-debug"
120127
echo " ./${SCRIPT_NAME} -h"
121128
echo
122129
exit ${1}
@@ -133,6 +140,16 @@ function show_local_container_login() {
133140
echo "EXEC: docker exec --user ${USER} -ti ${CONTAINER_NAME} bash"
134141
echo "SSH: ssh -i ~/.ssh/id_rsa_docker_sonic_mgmt ${USER}@${CONTAINER_IPV4}"
135142
echo "******************************************************************************"
143+
144+
if [[ -n ${SELECTED_DEBUG_PORT} ]]; then
145+
echo
146+
echo "*********************************[IMPORTANT]*********************************"
147+
echo "DEBUG PORT: $SELECTED_DEBUG_PORT"
148+
echo "Please use the above debug port in your vscode extensions"
149+
echo "When running the test, add --enable-debug to the end of your ./run_tests.sh to use"
150+
echo "You can check which port was assigned to you again by running 'docker ps' and search for your container"
151+
echo "*********************************[IMPORTANT]*********************************"
152+
fi
136153
}
137154

138155
function pull_sonic_mgmt_docker_image() {
@@ -259,6 +276,10 @@ RUN if ! pip3 list | grep -c pytest >/dev/null && \
259276
/bin/bash -c '${HOME}/env-python3/bin/pip install $(/var/AzDevOps/env-python3/bin/pip freeze | grep -vE "distro|PyGObject|python-apt|unattended-upgrades|dbus-python")'; \
260277
fi
261278
279+
# Remote debug port setup
280+
{% if SONIC_MGMT_DEBUG_PORT %}
281+
ENV SONIC_MGMT_DEBUG_PORT={{ SONIC_MGMT_DEBUG_PORT }}
282+
{% endif %}
262283
EOF
263284

264285
log_info "prepare an environment file: ${TMP_DIR}/data.env"
@@ -272,6 +293,7 @@ GROUP_NAME=${USER}
272293
USER_NAME=${USER}
273294
USER_PASS=${USER_PASS}
274295
ROOT_PASS=${ROOT_PASS}
296+
SONIC_MGMT_DEBUG_PORT=${SELECTED_DEBUG_PORT}
275297
EOF
276298

277299
log_info "generate a Dockerfile: ${TMP_DIR}/Dockerfile"
@@ -387,6 +409,29 @@ function parse_arguments() {
387409
fi
388410
}
389411

412+
function find_debug_port() {
413+
mkdir -p "$DEFAULT_LOCK_FOLDER"
414+
for port in $(seq $DEBUG_PORT_START_RANGE $DEBUG_PORT_END_RANGE); do
415+
if ! ss -tuln | grep -q ":$port\b" && mkdir $DEFAULT_LOCK_FOLDER/$port.lock 2>/dev/null; then
416+
trap "rm -rf $DEFAULT_LOCK_FOLDER/$port.lock" EXIT # Remove the port.lock file when done
417+
SELECTED_DEBUG_PORT=$port
418+
return 0
419+
fi
420+
done
421+
return 1
422+
}
423+
424+
425+
ARGS=()
426+
for arg in "$@"; do
427+
if [[ "$arg" == "--enable-debug" ]]; then
428+
ENABLE_DEBUG=1
429+
else
430+
ARGS+=("$arg")
431+
fi
432+
done
433+
434+
set -- "${ARGS[@]}"
390435
#
391436
# Script --------------------------------------------------------------------------------------------------------------
392437
#
@@ -431,6 +476,17 @@ while getopts "n:i:d:m:p:fvxh" opt; do
431476
esac
432477
done
433478

479+
if [[ "$ENABLE_DEBUG" -eq 1 ]]; then
480+
find_debug_port
481+
if [[ -n "$SELECTED_DEBUG_PORT" ]]; then
482+
PUBLISH_PORTS+=" -p \"$SELECTED_DEBUG_PORT:$SELECTED_DEBUG_PORT\""
483+
else
484+
echo "FAILURE: Cannot find an eligible debug port within the range [$DEBUG_PORT_START_RANGE, $DEBUG_PORT_END_RANGE]"
485+
echo "Please re-run without --enable-debug option."
486+
exit 1
487+
fi
488+
fi
489+
434490
parse_arguments
435491

436492
if [[ "$(id -u)" = "${ROOT_UID}" ]]; then

tests/run_tests.sh

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ function validate_parameters()
9696
function setup_environment()
9797
{
9898
SCRIPT=$0
99+
PYTEST_EXEC="python3 -m pytest"
99100
FULL_PATH=$(realpath ${SCRIPT})
100101
SCRIPT_PATH=$(dirname ${FULL_PATH})
101102
BASE_PATH=$(dirname ${SCRIPT_PATH})
@@ -301,22 +302,22 @@ function pre_post_extra_params()
301302
function prepare_dut()
302303
{
303304
echo "=== Preparing DUT for subsequent tests ==="
304-
echo Running: python3 -m pytest ${PYTEST_UTIL_OPTS} ${PRET_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m pretest
305-
python3 -m pytest ${PYTEST_UTIL_OPTS} ${PRET_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m pretest
305+
echo Running: ${PYTEST_EXEC} ${PYTEST_UTIL_OPTS} ${PRET_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m pretest
306+
${PYTEST_EXEC} ${PYTEST_UTIL_OPTS} ${PRET_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m pretest
306307
}
307308

308309
function cleanup_dut()
309310
{
310311
echo "=== Cleaning up DUT after tests ==="
311-
echo Running: python3 -m pytest ${PYTEST_UTIL_OPTS} ${POST_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m posttest
312-
python3 -m pytest ${PYTEST_UTIL_OPTS} ${POST_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m posttest
312+
echo Running: ${PYTEST_EXEC} ${PYTEST_UTIL_OPTS} ${POST_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m posttest
313+
${PYTEST_EXEC} ${PYTEST_UTIL_OPTS} ${POST_LOGGING_OPTIONS} ${UTIL_TOPOLOGY_OPTIONS} $(pre_post_extra_params) -m posttest
313314
}
314315

315316
function run_group_tests()
316317
{
317318
echo "=== Running tests in groups ==="
318-
echo Running: python3 -m pytest ${TEST_CASES} ${PYTEST_COMMON_OPTS} ${TEST_LOGGING_OPTIONS} ${TEST_TOPOLOGY_OPTIONS} ${EXTRA_PARAMETERS}
319-
python3 -m pytest ${TEST_CASES} ${PYTEST_COMMON_OPTS} ${TEST_LOGGING_OPTIONS} ${TEST_TOPOLOGY_OPTIONS} ${EXTRA_PARAMETERS} --cache-clear
319+
echo Running: ${PYTEST_EXEC} ${TEST_CASES} ${PYTEST_COMMON_OPTS} ${TEST_LOGGING_OPTIONS} ${TEST_TOPOLOGY_OPTIONS} ${EXTRA_PARAMETERS}
320+
${PYTEST_EXEC} ${TEST_CASES} ${PYTEST_COMMON_OPTS} ${TEST_LOGGING_OPTIONS} ${TEST_TOPOLOGY_OPTIONS} ${EXTRA_PARAMETERS} --cache-clear
320321
}
321322

322323
function run_individual_tests()
@@ -383,6 +384,26 @@ function run_bsl_tests()
383384

384385
setup_environment
385386

387+
for arg in "$@"; do
388+
if [[ "$arg" == "--enable-debug" ]]; then
389+
if [[ -z $SONIC_MGMT_DEBUG_PORT ]]; then
390+
echo "*********************************[WARNING]*********************************"
391+
echo "This container was not setup with --enable-debug option. Please re-setup this container with --enable-debug option"
392+
echo "Please re-run without '--enable-debug' option to continue."
393+
echo "*********************************[WARNING]*********************************"
394+
exit 1
395+
fi
396+
397+
if [[ "$arg" != "${@: -1}" ]]; then
398+
echo "Please put '--enable-debug' as the last option of your './run_tests.sh' command to avoid conflicts with pytest and run_tests options"
399+
echo "Example: ./run_tests.sh ... --enable-debug"
400+
exit 1
401+
fi
402+
403+
PYTEST_EXEC="python3 -m debugpy --listen 0.0.0.0:$SONIC_MGMT_DEBUG_PORT --wait-for-client -m pytest"
404+
set -- "${@/$arg/}" # remove this option so getopts can process the rest
405+
fi
406+
done
386407

387408
while getopts "h?a:b:Bc:C:d:e:Ef:F:H:i:I:k:l:m:n:oOp:q:rs:S:t:ux" opt; do
388409
case ${opt} in

0 commit comments

Comments
 (0)