From 8779d8617abb03bd38b700b10927b4651e602a7f Mon Sep 17 00:00:00 2001 From: Paulo Gomes Date: Thu, 27 Jun 2024 17:05:38 +0100 Subject: [PATCH] tests: Add tests to confirm iptables wrapper works Pull some of the upstream tests for iptables-wrapper and use them during CI to reduce the likelihood of regression with iptables-wrapper on this image. Signed-off-by: Paulo Gomes --- .github/workflows/ci-on-pr.yaml | 4 +- Dockerfile | 2 +- Makefile | 6 +- scripts/hyperkube | 2 +- tests/Dockerfile | 6 ++ tests/run-wrapper-tests.sh | 130 ++++++++++++++++++++++++++++++++ tests/test.sh | 85 +++++++++++++++++++++ 7 files changed, 230 insertions(+), 5 deletions(-) create mode 100644 tests/Dockerfile create mode 100755 tests/run-wrapper-tests.sh create mode 100755 tests/test.sh diff --git a/.github/workflows/ci-on-pr.yaml b/.github/workflows/ci-on-pr.yaml index cdfaffa..f02f83a 100644 --- a/.github/workflows/ci-on-pr.yaml +++ b/.github/workflows/ci-on-pr.yaml @@ -5,8 +5,6 @@ on: branches: - master push: - branches: - - master jobs: test-prepare-binaries: @@ -49,3 +47,5 @@ jobs: labels: "${{ steps.meta.outputs.labels }}" build-args: | ARCH="${{ matrix.arch }}" + + - run: make test diff --git a/Dockerfile b/Dockerfile index 993736a..81f6ff3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -79,7 +79,7 @@ RUN echo CACHEBUST>/dev/null \ # iptables-wrapper-installer.sh uses `iptables-nft --version` to check whether iptables-nft exists, iptables-nft returns # the error "protocol not supported" when being invoked in an emulated enviroment whose arch (for example, arm64) -# is differnt from the host (amd64). So we do the check ourselves before running iptables-wrapper-installer.sh. +# is different from the host (amd64). So we do the check ourselves before running iptables-wrapper-installer.sh. RUN which iptables-legacy && which iptables-nft RUN /usr/sbin/iptables-wrapper-installer.sh --no-sanity-check diff --git a/Makefile b/Makefile index 1de3c7f..259fefd 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ ARCH ?=amd64 ALL_ARCH = amd64 arm64 -IMAGE ?= docker.io/oats87/hyperkube-base +IMAGE ?= docker.io/rancher/hyperkube-base TAG ?= v0.0.1 BASEIMAGE ?= ubuntu:22.04 @@ -35,6 +35,10 @@ build: clean scripts/iptables-wrapper-installer.sh push: build docker push $(IMAGE):$(TAG)-$(ARCH) +test: clean scripts/iptables-wrapper-installer.sh + IMAGE=test-hyperkube-base DEBUG=true \ + ./tests/run-wrapper-tests.sh bci + .PHONY: all build push clean all-build all-push-images all-push .DEFAULT_GOAL := build diff --git a/scripts/hyperkube b/scripts/hyperkube index 3726e09..641d730 100755 --- a/scripts/hyperkube +++ b/scripts/hyperkube @@ -72,4 +72,4 @@ function main() { exec "${command}" "${@}" } -main "${@}" \ No newline at end of file +main "${@}" diff --git a/tests/Dockerfile b/tests/Dockerfile new file mode 100644 index 0000000..322bf31 --- /dev/null +++ b/tests/Dockerfile @@ -0,0 +1,6 @@ +ARG IMAGE +FROM ${IMAGE} + +COPY tests/test.sh / + +ENTRYPOINT [] diff --git a/tests/run-wrapper-tests.sh b/tests/run-wrapper-tests.sh new file mode 100755 index 0000000..08bb3df --- /dev/null +++ b/tests/run-wrapper-tests.sh @@ -0,0 +1,130 @@ +#!/bin/bash +# +# Copyright 2020 The Kubernetes Authors. +# +# 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. + +# Adapted from: https://github.com/kubernetes-sigs/iptables-wrappers/blob/master/test/run-test.sh + +set -o errexit +set -o nounset +set -o pipefail + +if [[ -n "${DEBUG:-}" ]]; then + set -x + dash_x="-x" +fi + +build_arg="" +build_fail=0 +nft_fail=0 + +while [[ $# -gt 1 ]]; do + case "$1" in + --build-arg=*) + build_arg="${1#--build_arg=}" + ;; + --build-arg) + shift + build_arg="$1" + ;; + --build-fail) + build_fail=1 + ;; + --nft-fail) + nft_fail=1 + ;; + *) + echo "Unrecognized flag '$1'" 1>&2 + exit 1 + ;; + esac + shift +done + +if podman -h &> /dev/null; then + docker_binary=podman +elif docker -h &> /dev/null; then + if docker version &> /dev/null; then + docker_binary=docker + else + docker_binary="sudo docker" + # Get the password prompting out of the way now + sudo docker version > /dev/null + fi +else + echo "Could not find podman or docker" 1>&2 + exit 1 +fi + +function docker() { + if [[ -n "${DEBUG:-}" ]]; then + command ${docker_binary} "$@" + else + if [[ "$1" == "build" ]]; then + echo " docker $*" + fi + # Redirect stdout to /dev/null and indent stderr + command ${docker_binary} "$@" 2>&1 > /dev/null | \ + sed -e '/debconf: delaying package configuration/ d' \ + -e 's/^/ /' + fi +} + +function build() { + shift + + if ! docker buildx build -t test-hyperkube-base . --load; then + FAIL "building base image failed" + fi + if ! docker buildx build --build-arg IMAGE=test-hyperkube-base -q -t iptables-wrapper-test -f tests/Dockerfile "$@" . --load; then + FAIL "building test image failed" + fi + +} + +function PASS() { + printf "\033[1;92mPASS: $@\033[0m\n\n" + exit 0 +} + +function FAIL() { + echo "update-alternatives configuration:" + docker run iptables-wrapper-test update-alternatives --query iptables + + printf "\033[1;31mFAIL: $@\033[0m\n" 1>&2 + + exit 1 +} + +if ! build iptables-wrapper-test ${build_arg}; then + if [[ "${build_fail}" = 1 ]]; then + PASS "build failed as expected" + fi + FAIL "build failed unexpectedly" +fi + +if ! docker run --privileged -e iptables_binary=/usr/sbin/iptables iptables-wrapper-test /bin/sh ${dash_x:-} /test.sh legacy; then + FAIL "failed legacy iptables / new rules test" +fi +if ! docker run --privileged -e iptables_binary=/usr/sbin/iptables iptables-wrapper-test /bin/sh ${dash_x:-} /test.sh nft; then + FAIL "failed nft iptables / new rules test" +fi +if ! docker run --privileged -e iptables_binary=/usr/sbin/ip6tables iptables-wrapper-test /bin/sh ${dash_x:-} /test.sh legacy; then + FAIL "failed legacy ip6tables / new rules test" +fi +if ! docker run --privileged -e iptables_binary=/usr/sbin/ip6tables iptables-wrapper-test /bin/sh ${dash_x:-} /test.sh nft; then + FAIL "failed nft ip6tables / new rules test" +fi + +PASS "success" diff --git a/tests/test.sh b/tests/test.sh new file mode 100755 index 0000000..6ab86e6 --- /dev/null +++ b/tests/test.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# +# Copyright 2020 The Kubernetes Authors. +# +# 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. + +# Adapted from: https://github.com/kubernetes-sigs/iptables-wrappers/blob/master/test/test.sh + +set -eu + +mode=$1 +iptables_binary=${iptables_binary:-/usr/sbin/iptables} + +case "${mode}" in + legacy) + wrongmode=nft + ;; + nft) + wrongmode=legacy + ;; + *) + echo "ERROR: bad mode '${mode}'" 1>&2 + exit 1 + ;; +esac + +sbin="/usr/sbin" +if [ ! -d /usr/sbin -a -e "${iptables_binary}" ]; then + echo "ERROR: ${iptables_binary} not found" 1>&2 + exit 1 +fi + +ensure_iptables_undecided() { + iptables=$(realpath "${iptables_binary}") + if [ "${iptables}" != "${sbin}/iptables-wrapper" ]; then + echo "iptables link was resolved prematurely! (${iptables})" 1>&2 + exit 1 + fi +} + +ensure_iptables_resolved() { + expected=$1 + iptables=$(realpath "${iptables_binary}") + if [ "${iptables}" = "${sbin}/iptables-wrapper" ]; then + echo "iptables link is not yet resolved!" 1>&2 + exit 1 + fi + version=$(iptables -V | sed -e 's/.*(\(.*\)).*/\1/') + case "${version}/${expected}" in + legacy/legacy|nf_tables/nft) + return + ;; + *) + echo "iptables link resolved incorrectly (expected ${expected}, got ${version})" 1>&2 + exit 1 + ;; + esac +} + +ensure_iptables_undecided + +# Initialize the chosen iptables mode with just a hint chain +iptables-${mode} -t mangle -N KUBE-IPTABLES-HINT + +# Put some junk in the other iptables system +iptables-${wrongmode} -t filter -N BAD-1 +iptables-${wrongmode} -t filter -A BAD-1 -j ACCEPT +iptables-${wrongmode} -t filter -N BAD-2 +iptables-${wrongmode} -t filter -A BAD-2 -j DROP + +ensure_iptables_undecided + +iptables -L > /dev/null + +ensure_iptables_resolved ${mode}