diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 59707e7be6de..665c19210528 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -41,6 +41,9 @@ if [ $(id -u) -eq 0 ]; then _LOG_PROMPT='#' fi +# Used in helpers.network, needed here in teardown +PORT_LOCK_DIR=$BATS_SUITE_TMPDIR/reserved-ports + ############################################################################### # BEGIN tools for fetching & caching test images # @@ -205,6 +208,14 @@ function defer-assertion-failures() { function basic_teardown() { echo "# [teardown]" >&2 + # Free any ports reserved by our test + if [[ -d $PORT_LOCK_DIR ]]; then + mylocks=$(grep -wlr $BATS_SUITE_TEST_NUMBER $PORT_LOCK_DIR || true) + if [[ -n "$mylocks" ]]; then + rm -f $mylocks + fi + fi + immediate-assertion-failures # Unlike normal tests teardown will not exit on first command failure # but rather only uses the return code of the teardown function. diff --git a/test/system/helpers.network.bash b/test/system/helpers.network.bash index 955da500cdf0..792b87164f77 100644 --- a/test/system/helpers.network.bash +++ b/test/system/helpers.network.bash @@ -273,6 +273,36 @@ function ether_get_name() { ### Ports and Ranges ########################################################### +# reserve_port() - create a lock file reserving a port, or return false +function reserve_port() { + local port=$1 + + mkdir -p $PORT_LOCK_DIR + local lockfile=$PORT_LOCK_DIR/$port + local locktmp=$PORT_LOCK_DIR/.$port.$$ + echo $BATS_SUITE_TEST_NUMBER >$locktmp + + if ln $locktmp $lockfile; then + rm -f $locktmp + return + fi + # Port already reserved + rm -f $locktmp + false +} + +# unreserve_port() - free a temporarily-reserved port +function unreserve_port() { + local port=$1 + + local lockfile=$PORT_LOCK_DIR/$port + -e $lockfile || die "Cannot unreserve non-reserved port $port" + assert "$(< $lockfile)" = "$BATS_SUITE_TEST_NUMBER" \ + "Port $port is not reserved by this test" + rm -f $lockfile +} + + # random_free_port() - Get unbound port with pseudorandom number # $1: Optional, dash-separated interval, [5000, 5999] by default # $2: Optional binding address, any IPv4 address by default @@ -284,9 +314,14 @@ function random_free_port() { local port for port in $(shuf -i ${range}); do - if port_is_free $port $address $protocol; then - echo $port - return + # First make sure no other tests are using it + if reserve_port $port; then + if port_is_free $port $address $protocol; then + echo $port + return + fi + + unreserve_port $port fi done @@ -308,8 +343,13 @@ function random_free_port_range() { local lastport= for i in $(seq 1 $((size - 1))); do lastport=$((firstport + i)) + if ! reserve_port $lastport; then + lastport= + break + fi if ! port_is_free $lastport $address $protocol; then echo "# port $lastport is in use; trying another." >&3 + unreserve_port $lastport lastport= break fi @@ -319,6 +359,8 @@ function random_free_port_range() { return fi + unreserve_port $firstport + maxtries=$((maxtries - 1)) done diff --git a/test/system/helpers.t b/test/system/helpers.t index d7677506229b..8c4d892369eb 100755 --- a/test/system/helpers.t +++ b/test/system/helpers.t @@ -22,6 +22,9 @@ rc=0 PODMAN_TMPDIR=$(mktemp -d --tmpdir=${TMPDIR:-/tmp} podman_helper_tests.XXXXXX) trap 'rm -rf $PODMAN_TMPDIR' 0 +# Used by random_free_port. +PORT_LOCK_DIR=$PODMAN_TMPDIR/reserved-ports + ############################################################################### # BEGIN test the parse_table helper