Merge branch 'kubernetes:master' into no-kubernetes-skip-downloads

pull/21139/head
Divy Singhvi 2025-11-09 17:01:09 +05:30 committed by GitHub
commit 9d0cf672d7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 2066 additions and 18 deletions

View File

@ -902,6 +902,7 @@ generate-licenses:
gomodtidy: ## run go mod tidy everywhere needed
go mod tidy
cd hack && go mod tidy
cd hack/prow/minitest && env -u GOTOOLCHAIN go mod tidy
.PHONY: help
@ -1126,3 +1127,9 @@ get-dependency-version:
.PHONY: _update-all
_update-all:
@(cd hack && go run update/update_all/update_all.go)
# targets for tests on prow
include ./hack/prow/prow.mk

4
go.mod
View File

@ -62,7 +62,7 @@ require (
github.com/spf13/viper v1.20.1
github.com/zchee/go-vmnet v0.0.0-20161021174912-97ebf9174097
go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/sdk v1.37.0
go.opentelemetry.io/otel/sdk v1.38.0
go.opentelemetry.io/otel/trace v1.38.0
golang.org/x/build v0.0.0-20190927031335-2835ba2e683f
golang.org/x/crypto v0.41.0
@ -233,7 +233,7 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/net v0.43.0 // indirect

8
go.sum
View File

@ -711,10 +711,10 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1x
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=

View File

@ -19,7 +19,7 @@ require (
github.com/spf13/viper v1.20.1
go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/metric v1.38.0
go.opentelemetry.io/otel/sdk/metric v1.36.0
go.opentelemetry.io/otel/sdk/metric v1.38.0
golang.org/x/mod v0.27.0
golang.org/x/oauth2 v0.30.0
gonum.org/v1/plot v0.16.0
@ -208,7 +208,7 @@ require (
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect

View File

@ -515,10 +515,10 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1x
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=

212
hack/prow/common.sh Executable file
View File

@ -0,0 +1,212 @@
#!/bin/bash
# Copyright 2025 The Kubernetes Authors All rights reserved.
#
# 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.
# The script expects the following env variables:
# OS: The operating system
# ARCH: The architecture
# DRIVER: the driver to use for the test
# CONTAINER_RUNTIME: the container runtime to use for the test
# EXTRA_START_ARGS: additional flags to pass into minikube start
# EXTRA_TEST_ARGS: additional flags to pass into go test
# JOB_NAME: the name of the logfile and check name to update on github
# PULL_NUMBER: the PR number, if applicable
function print_test_info() {
echo ">> Starting at $(date)"
echo ""
echo "user: $(whoami)"
echo "arch: ${OS_ARCH}"
echo "pr: ${PULL_NUMBER}"
echo "driver: ${DRIVER}"
echo "runtime: ${CONTAINER_RUNTIME}"
echo "job: ${JOB_NAME}"
echo "test home: ${TEST_HOME}"
echo "kernel: $(uname -v)"
echo "uptime: $(uptime)"
# Setting KUBECONFIG prevents the version check from erroring out due to permission issues
echo "kubectl: $(env KUBECONFIG=${TEST_HOME} kubectl version --client)"
echo "docker: $(docker version --format '{{ .Client.Version }}')"
echo "podman: $(sudo podman version --format '{{.Version}}' || true)"
echo "go: $(go version || true)"
case "${DRIVER}" in
kvm2)
echo "virsh: $(virsh --version)"
;;
virtualbox)
echo "vbox: $(vboxmanage --version)"
;;
vfkit)
echo "vfkit: $(vfkit --version)"
;;
krunkit)
echo "krunkit: $(krunkit --version)"
;;
esac
echo ""
}
function install_dependencies() {
# We need pstree for the restart cronjobs
if [ "$(uname)" != "Darwin" ]; then
sudo apt-get -y install lsof psmisc dnsutils
else
brew install pstree coreutils pidof
ln -s /usr/local/bin/gtimeout /usr/local/bin/timeout || true
fi
# install golang if not present
sudo hack/prow/installer/check_install_golang.sh /usr/local 1.24.5 || true
# install gotestsum if not present
GOROOT="/usr/local/go" hack/prow/installer/check_install_gotestsum.sh || true
# install gopogh
hack/prow/installer/check_install_gopogh.sh || true
# install jq
if ! type "jq" >/dev/null; then
echo ">> Installing jq"
if [ "${ARCH}" == "arm64" && "${OS}" == "linux" ]; then
sudo apt-get install jq -y
elif [ "${ARCH}" == "arm64" ]; then
echo "Unable to install 'jq' automatically for arm64 on Darwin, please install 'jq' manually."
exit 5
elif [ "${OS}" != "darwin" ]; then
curl -LO https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 && sudo install jq-linux64 /usr/local/bin/jq
else
curl -LO https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 && sudo install jq-osx-amd64 /usr/local/bin/jq
fi
fi
}
function docker_setup() {
# clean all docker artifacts up
docker system prune -a --volumes -f || true
docker system df || true
docker rm -f -v $(docker ps -aq) >/dev/null 2>&1 || true
# read only token, never expires
#todo: do we need this token
# docker login -u minikubebot -p "$DOCKERHUB_READONLY_TOKEN"
}
function gvisor_image_build() {
# Build the gvisor image so that we can integration test changes to pkg/gvisor
chmod +x testdata/gvisor-addon
# skipping gvisor mac because ofg https://github.com/kubernetes/minikube/issues/5137
if [ "$(uname)" != "Darwin" ]; then
# Should match GVISOR_IMAGE_VERSION in Makefile
docker build -t gcr.io/k8s-minikube/gvisor-addon:2 -f testdata/gvisor-addon-Dockerfile ./testdata
fi
}
function run_gopogh() {
# todo: currently we do not save to gopogh db
echo "Not saving to DB"
gopogh -in "${JSON_OUT}" -out_html "${HTML_OUT}" -out_summary "${SUMMARY_OUT}" -name "${JOB_NAME}" -pr "${PULL_NUMBER}" -repo github.com/kubernetes/minikube/ -details "${COMMIT}:$(date +%Y-%m-%d)"
}
# this is where the script starts
readonly OS_ARCH="${OS}-${ARCH}"
readonly TEST_ROOT="${HOME}/minikube-integration"
readonly TEST_HOME="${TEST_ROOT}/${MINIKUBE_LOCATION}-$$"
export GOPATH="$HOME/go"
export KUBECONFIG="${TEST_HOME}/kubeconfig"
export PATH=$PATH:"/usr/local/bin/:/usr/local/go/bin/:$GOPATH/bin"
export MINIKUBE_SUPPRESS_DOCKER_PERFORMANCE=true
readonly TIMEOUT=120m
cp -r test/integration/testdata .
# Add the out/ directory to the PATH, for using new drivers.
export PATH="$(pwd)/out/":$PATH
mkdir -p "${TEST_ROOT}"
mkdir -p "${TEST_HOME}"
export MINIKUBE_HOME="${TEST_HOME}/.minikube"
export MINIKUBE_BIN="out/minikube-${OS_ARCH}"
export E2E_BIN="out/e2e-${OS_ARCH}"
install_dependencies
docker_setup
if [ "$CONTAINER_RUNTIME" == "containerd" ]; then
cp out/gvisor-addon testdata/
gvisor_image_build
fi
print_test_info
readonly TEST_OUT="${TEST_HOME}/testout.txt"
readonly JSON_OUT="${TEST_HOME}/test.json"
readonly JUNIT_OUT="${TEST_HOME}/junit-unit.xml"
readonly HTML_OUT="${TEST_HOME}/test.html"
readonly SUMMARY_OUT="${TEST_HOME}/test_summary.json"
touch "${TEST_OUT}"
touch "${JSON_OUT}"
touch "${JUNIT_OUT}"
touch "${HTML_OUT}"
touch "${SUMMARY_OUT}"
e2e_start_time="$(date -u +%s)"
echo ""
echo ">> Starting ${E2E_BIN} at $(date)"
set -x
EXTRA_START_ARGS="${EXTRA_START_ARGS} --container-runtime=${CONTAINER_RUNTIME}"
echo $PATH
gotestsum --jsonfile "${JSON_OUT}" --junitfile="${JUNIT_OUT}" -f standard-verbose --raw-command -- \
go tool test2json -t \
${E2E_BIN} \
-minikube-start-args="--driver=${DRIVER} ${EXTRA_START_ARGS}" \
-test.timeout=${TIMEOUT} -test.v \
${EXTRA_TEST_ARGS} \
-binary="${MINIKUBE_BIN}" 2>&1 |
tee "${TEST_OUT}"
result=${PIPESTATUS[0]} # capture the exit code of the first cmd in pipe.
set +x
echo ">> ${E2E_BIN} exited with ${result} at $(date)"
echo ""
# calculate the time took to finish running e2e binary test.
e2e_end_time="$(date -u +%s)"
elapsed=$(($e2e_end_time - $e2e_start_time))
min=$(($elapsed / 60))
sec=$(tail -c 3 <<<$((${elapsed}00 / 60)))
elapsed=$min.$sec
#todo: currently we skip gopogh upload , we shall add it back
run_gopogh
# according to prow's requirement, upload the test report to $ARTIFACTS
cp ${TEST_OUT} .
cp ${JSON_OUT} .
cp ${JUNIT_OUT} .
cp ${HTML_OUT} .
cp ${SUMMARY_OUT} .
if [[ $result -eq 0 ]]; then
echo "minikube: SUCCESS"
else
echo "minikube: FAIL"
fi
exit "$result"

3
hack/prow/docker.json Normal file
View File

@ -0,0 +1,3 @@
{
"Image": "debian"
}

View File

@ -0,0 +1,31 @@
#!/bin/bash
# Copyright 2016 The Kubernetes Authors All rights reserved.
#
# 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.
set -eux -o pipefail
ARCH=${ARCH:=amd64}
echo "Installing latest docker"
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
rm get-docker.sh
sudo usermod -aG docker minitest || true
echo "Installing latest kubectl"
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl"
sudo install ./kubectl /usr/local/bin/kubectl

View File

@ -0,0 +1,101 @@
#!/bin/bash
# Copyright 2025 The Kubernetes Authors All rights reserved.
#
# 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.
# This script requires two parameters:
# $1. INSTALL_PATH: The path to install the golang binary
# $2. GO_VERSION: The version of golang to install
set -eux -o pipefail
if (($# < 2)); then
echo "ERROR: given ! ($#) parameters but expected 2."
echo "USAGE: ./check_install_golang.sh INSTALL_PATH GO_VERSION"
exit 1
fi
VERSION_TO_INSTALL=${2}
INSTALL_PATH=${1}
function current_arch() {
case $(arch) in
"x86_64" | "i386")
echo "amd64"
;;
"aarch64" | "arm64")
echo "arm64"
;;
*)
echo "unexpected arch: $(arch). use amd64" 1>&2
echo "amd64"
;;
esac
}
ARCH=${ARCH:=$(current_arch)}
# installs or updates golang if right version doesn't exists
function check_and_install_golang() {
if ! go version &>/dev/null; then
echo "WARNING: No golang installation found in your environment."
install_golang "$VERSION_TO_INSTALL" "$INSTALL_PATH"
return
fi
sudo chown -R $USER:$USER "$INSTALL_PATH"/go
# golang has been installed and check its version
if [[ $(go version | cut -d' ' -f 3) =~ go(([0-9]+)\.([0-9]+).([0-9]+)*) ]]; then
HOST_VERSION=${BASH_REMATCH[1]}
if [ $HOST_VERSION == $VERSION_TO_INSTALL ]; then
echo "go version on the host looks good : $HOST_VERSION"
else
echo "WARNING: expected go version to be $VERSION_TO_INSTALL but got $HOST_VERSION"
install_golang "$VERSION_TO_INSTALL" "$INSTALL_PATH"
fi
else
echo "ERROR: Failed to parse golang version: $(go version)"
return
fi
}
# install_golang takes two parameters version and path to install.
function install_golang() {
local -r GO_VER="$1"
local -r GO_DIR="$2/go"
echo "Installing golang version: $GO_VER in $GO_DIR"
INSTALLOS=linux
if [[ "$OSTYPE" == "darwin"* ]]; then
INSTALLOS=darwin
fi
local -r GO_TGZ="go${GO_VER}.${INSTALLOS}-${ARCH}.tar.gz"
pushd /tmp
# using sudo because previously installed versions might have been installed by a different user.
sudo rm -rf "$GO_TGZ"
curl -qL -O "https://storage.googleapis.com/golang/$GO_TGZ"
sudo rm -rf "$GO_DIR"
sudo mkdir -p "$GO_DIR"
sudo tar -C "$GO_DIR" --strip-components=1 -xzf "$GO_TGZ"
popd >/dev/null
echo "installed in $GO_DIR: $($GO_DIR/bin/go version)"
}
check_and_install_golang

View File

@ -0,0 +1,21 @@
#!/bin/bash
# Copyright 2025 The Kubernetes Authors All rights reserved.
#
# 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.
# this script requires golang to be installed
set -eux -o pipefail
go install github.com/medyagh/gopogh/cmd/gopogh@v0.29.0

View File

@ -0,0 +1,24 @@
#!/bin/bash
# Copyright 2021 The Kubernetes Authors All rights reserved.
#
# 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.
set -eux -o pipefail
function install_gotestsum() {
rm -f $(which gotestsum)
sudo env "GOBIN=$GOROOT/bin" "PATH=$PATH" go install gotest.tools/gotestsum@v1.12.3
}
echo "Installing gotestsum"
which gotestsum || install_gotestsum

View File

@ -0,0 +1,43 @@
#!/bin/bash
# Copyright 2025 The Kubernetes Authors All rights reserved.
#
# 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.
set -e
set -x
OS="linux"
ARCH="amd64"
DRIVER="kvm2"
CONTAINER_RUNTIME="docker"
# in prow, if you want libvirtd to be run, you have to start a privileged container as root
EXTRA_START_ARGS=""
EXTRA_TEST_ARGS=""
JOB_NAME="KVM_Linux"
COMMIT=$(git rev-parse HEAD)
MINIKUBE_LOCATION=$COMMIT
echo "running test in $(pwd)"
set +e
sleep 5 # wait for libvirtd to be running
echo "=========libvirtd status=========="
sudo systemctl status libvirtd
echo "=========Check virtualization support=========="
grep -E -q 'vmx|svm' /proc/cpuinfo && echo yes || echo no
echo "=========virt-host-validate=========="
virt-host-validate
set -e
source ./hack/prow/common.sh

View File

@ -0,0 +1,39 @@
#!/bin/bash
# Copyright 2025 The Kubernetes Authors All rights reserved.
#
# 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.
set -e
set -x
OS="linux"
ARCH="amd64"
DRIVER="kvm2"
CONTAINER_RUNTIME="docker"
# in prow, if you want libvirtd to be run, you have to start a privileged container as root
EXTRA_START_ARGS=""
EXTRA_TEST_ARGS=""
JOB_NAME="KVM_Linux"
# install docker if not present
ARCH="$ARCH" hack/prow/installer/check_install_docker.sh || true
sudo adduser $(whoami) docker || true
sudo apt-get update
sudo apt-get -y install qemu-system qemu-kvm libvirt-clients libvirt-daemon-system ebtables iptables dnsmasq
sudo adduser $(whoami) libvirt || true
# start libvirtd
sudo systemctl start libvirtd

9
hack/prow/kvm.json Normal file
View File

@ -0,0 +1,9 @@
{
"GCPZone": "us-central1-b",
"InstanceImage": "ubuntu-os-cloud/ubuntu-2404-lts-amd64",
"InstanceType": "n2-standard-8",
"DiskGiB": 300,
"BoskosAcquireTimeoutSeconds": 180,
"BoskosHeartbeatIntervalSeconds": 10,
"BoskosLocation": "http://boskos.test-pods.svc.cluster.local"
}

View File

@ -0,0 +1,55 @@
#!/bin/bash
# Copyright 2025 The Kubernetes Authors All rights reserved.
#
# 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.
# This script requires 3 parameter:
# $1. GO_VERSION: The version of golang to install
# $2. OS: The operating system
# $3. ARCH: The architecture
set -eux -o pipefail
GO_VERSION=$1
OS=$2
ARCH=$3
readonly OS_ARCH="${OS}-${ARCH}"
echo "running build in $(pwd), current pr number: ${PULL_NUMBER:-none}"
# hack/prow/installer/check_install_golang.sh /usr/local $GO_VERSION
# declare -rx GOPATH="$HOME/go"
declare -rx BUILD_IN_DOCKER=y
make -j 16 \
out/minikube-${OS_ARCH} \
out/e2e-${OS_ARCH} \
out/gvisor-addon \
&& failed=$? || failed=$?
export MINIKUBE_BIN="out/minikube-${OS_ARCH}"
export E2E_BIN="out/e2e-${OS_ARCH}"
chmod +x "${MINIKUBE_BIN}" "${E2E_BIN}"
BUILT_VERSION=$("out/minikube-$(go env GOOS)-$(go env GOARCH)" version)
echo ${BUILT_VERSION}
COMMIT=$(echo ${BUILT_VERSION} | grep 'commit:' | awk '{print $2}')
if (echo ${COMMIT} | grep -q dirty); then
echo "'minikube version' reports dirty commit: ${COMMIT}"
exit 1
fi
if [[ "${failed}" -ne 0 ]]; then
echo "build failed"
exit "${failed}"
fi

View File

@ -0,0 +1,28 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package deployer
type MiniTestBoskosConfig struct {
GCPZone string
InstanceImage string
InstanceType string
DiskGiB int
// Boskos flags correspond to https://github.com/kubernetes-sigs/kubetest2/blob/71238a9645df6fbd7eaac9a36f635c22f1566168/kubetest2-gce/deployer/deployer.go
BoskosAcquireTimeoutSeconds int
BoskosHeartbeatIntervalSeconds int
BoskosLocation string
}

View File

@ -0,0 +1,273 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package deployer
import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/google/uuid"
"k8s.io/klog/v2"
"sigs.k8s.io/boskos/client"
"sigs.k8s.io/kubetest2/pkg/boskos"
)
const (
// gceProjectResourceType is called "gce" project in Boskos,
// while it is called "gcp" project in this CLI.
gceProjectResourceType = "gce-project"
runDirSSHKeys = "gce-ssh-keys"
remoteUserName = "minitest"
)
type MiniTestBosKosDeployer struct {
ctx context.Context
config *MiniTestBoskosConfig
isUp bool
id string
gcpProject string
remoteUserName string
networkName string
firewallRuleName string
instanceName string
sshAddr string
boskosClient *client.Client
// this channel serves as a signal channel for the hearbeat goroutine
// so that it can be explicitly closed
boskosHeartbeatClose chan struct{}
}
func NewMiniTestBosKosDeployerFromConfigFile(path string) MiniTestDeployer {
config := MiniTestBoskosConfig{}
data, err := os.ReadFile(path)
if err != nil {
klog.Fatalf("failed to read config file %s: %v", path, err)
}
if err := json.Unmarshal(data, &config); err != nil {
klog.Fatalf("failed to parse config file %s: %v", path, err)
}
return NewMiniTestBosKosDeployer(&config)
}
func NewMiniTestBosKosDeployer(config *MiniTestBoskosConfig) MiniTestDeployer {
boskosClient, err := boskos.NewClient(config.BoskosLocation)
if err != nil {
klog.Fatalf("failed to make boskos client: %v", err)
}
id := uuid.New().String()[:8]
return &MiniTestBosKosDeployer{
ctx: context.TODO(),
config: config,
boskosClient: boskosClient,
boskosHeartbeatClose: make(chan struct{}),
remoteUserName: remoteUserName,
id: id,
networkName: "minitest-network-" + id,
firewallRuleName: "minitest-firewall-" + id,
instanceName: "minitest-vm-" + id,
}
}
func (m *MiniTestBosKosDeployer) Up() error {
if err := m.requestGCPProject(); err != nil {
klog.Errorf("Failed to request gcp project from boskos: %v", err)
return err
}
if err := m.gcpVMSetUp(); err != nil {
klog.Errorf("Failed to start a vm in gcp: %v", err)
return err
}
if err := m.gcpSSHSetUp(); err != nil {
klog.Errorf("Failed to set up ssh: %v", err)
return err
}
if err := sshConnectionCheck(m.ctx, m.remoteUserName, m.sshAddr, nil); err != nil {
klog.Errorf("Failed to conntect via ssh: %v", err)
return err
}
klog.Infof("Successfully started vm in gcp: %s", m.instanceName)
m.isUp = true
return nil
}
func (m *MiniTestBosKosDeployer) Down() error {
//todo: clean up the VM?
klog.Info("Releasing bosko project")
if m.boskosClient == nil {
return fmt.Errorf("m.boskosClient not set")
}
err := boskos.Release(
m.boskosClient,
[]string{m.gcpProject},
m.boskosHeartbeatClose,
)
if err != nil {
return fmt.Errorf("down failed to release boskos project: %v", err)
}
m.isUp = false
return nil
}
func (m *MiniTestBosKosDeployer) IsUp() (bool, error) {
return m.isUp, nil
}
func (m *MiniTestBosKosDeployer) Execute(args ...string) error {
return executeSSHCommand(m.ctx, m.remoteUserName, m.sshAddr, nil, args...)
}
func (m *MiniTestBosKosDeployer) SyncToRemote(src string, dst string, excludedPattern []string) error {
excludedArgs := make([]string, 0, len(excludedPattern)*2)
for _, pattern := range excludedPattern {
excludedArgs = append(excludedArgs, "--exclude", pattern)
}
dstRemote := fmt.Sprintf("%s@%s:%s", m.remoteUserName, m.sshAddr, dst)
return executeRsyncSSHCommand(m.ctx, nil, src, dstRemote, excludedArgs)
}
func (m *MiniTestBosKosDeployer) SyncToHost(src string, dst string, excludedPattern []string) error {
excludedArgs := make([]string, 0, len(excludedPattern)*2)
for _, pattern := range excludedPattern {
excludedArgs = append(excludedArgs, "--exclude", pattern)
}
srcRemote := fmt.Sprintf("%s@%s:%s", m.remoteUserName, m.sshAddr, src)
return executeRsyncSSHCommand(m.ctx, nil, srcRemote, dst, excludedArgs)
}
func (m *MiniTestBosKosDeployer) requestGCPProject() error {
resource, err := boskos.Acquire(
m.boskosClient,
gceProjectResourceType,
time.Duration(m.config.BoskosAcquireTimeoutSeconds)*time.Second,
time.Duration(m.config.BoskosHeartbeatIntervalSeconds)*time.Second,
m.boskosHeartbeatClose,
)
if err != nil {
return fmt.Errorf("failed to get project from boskos: %v", err)
}
if resource.Name == "" {
return fmt.Errorf("boskos returned an empty resource name, resource: %v", resource)
}
klog.Infof("Got project %q from boskos", resource.Name)
m.gcpProject = resource.Name
return nil
}
func (m *MiniTestBosKosDeployer) gcpVMSetUp() error {
// ensure gcp zone is set to start a vm
if m.config.GCPZone == "" {
return fmt.Errorf("GCPZone is not set")
}
// execute gcloud commands to set environment up a vm
if err := m.executeLocalGloudCommand("services", "enable", "compute.googleapis.com"); err != nil {
klog.Warningf("failed to enable service: %v", err)
}
if err := m.executeLocalGloudCommand("compute", "networks", "create", m.networkName); err != nil {
klog.Warningf("failed to set up network: %v", err)
}
if err := m.executeLocalGloudCommand("compute", "firewall-rules", "create", m.firewallRuleName, "--network="+m.networkName, "--allow=tcp:22"); err != nil {
klog.Warningf("failed to set up firewalls: %v", err)
}
// create the vm
description := fmt.Sprintf("%s instance (login ID: %q)", m.instanceName, m.remoteUserName)
instImgPair := strings.SplitN(m.config.InstanceImage, "/", 2)
if err := m.executeLocalGloudCommand("compute", "instances", "create",
"--enable-nested-virtualization",
"--zone="+m.config.GCPZone,
"--description="+description,
"--network="+m.networkName,
"--image-project="+instImgPair[0],
"--image-family="+instImgPair[1],
"--machine-type="+m.config.InstanceType,
fmt.Sprintf("--boot-disk-size=%dGiB", m.config.DiskGiB),
"--boot-disk-type=pd-ssd",
"--metadata=block-project-ssh-keys=TRUE",
m.instanceName,
); err != nil {
klog.Errorf("failed to start a gcp vm: %v", err)
return err
}
return nil
}
func (m *MiniTestBosKosDeployer) gcpSSHSetUp() error {
home, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to find home dir: %v", err)
}
gcePubPath := filepath.Join(home, ".ssh/google_compute_engine.pub")
gcePubContent, err := os.ReadFile(gcePubPath)
if err != nil {
return fmt.Errorf("failed to read GCE public key: %v", err)
}
sshKeysContent := []byte(m.remoteUserName + ":" + string(gcePubContent))
runDir, err := os.MkdirTemp("", "rundir")
if err != nil {
return fmt.Errorf("failed to create temp dir: %v", err)
}
sshKeysPath := filepath.Join(runDir, runDirSSHKeys)
_ = os.RemoveAll(sshKeysPath)
if err = os.WriteFile(sshKeysPath, sshKeysContent, 0400); err != nil {
return fmt.Errorf("failed to create new public key file: %v", err)
}
// set up ssh login with pub key
if err := m.executeLocalGloudCommand("compute", "instances", "add-metadata", m.instanceName, "--zone="+m.config.GCPZone, "--metadata-from-file=ssh-keys="+sshKeysPath); err != nil {
klog.Warningf("failed to add metadata: %v", err)
// continue anyway
}
// update the local ssh config
if err := m.executeLocalGloudCommand("compute", "config-ssh"); err != nil {
klog.Warningf("failed to compute ssh: %v", err)
// continue anyway
}
// set sshAddr field
if m.instanceName == "" || m.config.GCPZone == "" || m.gcpProject == "" {
return fmt.Errorf("gcp project configuration incorrect: %s.%s.%s", m.instanceName, m.config.GCPZone, m.gcpProject)
}
m.sshAddr = fmt.Sprintf("%s.%s.%s", m.instanceName, m.config.GCPZone, m.gcpProject)
return nil
}
func (m *MiniTestBosKosDeployer) executeLocalGloudCommand(args ...string) error {
if err := executeLocalCommand(m.ctx, "gcloud", append([]string{"--project=" + m.gcpProject}, args...)...); err != nil {
return fmt.Errorf("failed to run %v: %v", args, err)
}
return nil
}

View File

@ -0,0 +1,32 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package deployer
type MiniTestDeployer interface {
// Up should provision the environment for testing
Up() error
// Down should tear down the environment if any
Down() error
// IsUp should return true if a test cluster is successfully provisioned
IsUp() (bool, error)
// Execute execute a command in the deployed environment
Execute(args ...string) error
// SyncToRemote sync file or folder from src on host to dst on deployed environment
SyncToRemote(src string, dst string, excludedPattern []string) error
// SyncToRemote sync file or folder from src on remote to host
SyncToHost(src string, dst string, excludedPattern []string) error
}

View File

@ -0,0 +1,21 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package deployer
type MiniTestDockerConfig struct {
Image string
}

View File

@ -0,0 +1,314 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package deployer
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"io"
"os"
"strconv"
"github.com/docker/go-connections/nat"
"github.com/google/uuid"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/client"
"github.com/phayes/freeport"
gossh "golang.org/x/crypto/ssh"
"k8s.io/klog/v2"
)
var sshSetupScript = `
#!/bin/bash
USERNAME=%s
apt update
apt install -y openssh-server rsync
service ssh start
useradd -m -s /bin/bash ${USERNAME}
passwd -d ${USERNAME}
USER_HOME=$(eval echo "~${USERNAME}")
mkdir -p $USER_HOME/.ssh
chmod 700 $USER_HOME/.ssh
echo "%s" >> $USER_HOME/.ssh/authorized_keys
chmod 600 $USER_HOME/.ssh/authorized_keys
chown -R $USERNAME:$USERNAME "$USER_HOME/.ssh"
`
type MiniTestDockerDeployer struct {
ctx context.Context
config *MiniTestDockerConfig
isUp bool
dockerClient *client.Client
containerSHA string
sshPrivateKeyFile string
sshPublicKeyFile string
sshPublicKeyContent string
sshPort string
sshTempDir string
remoteUserName string
}
func NewMiniTestDockerDeployerFromConfigFile(path string) MiniTestDeployer {
config := MiniTestDockerConfig{}
data, err := os.ReadFile(path)
if err != nil {
klog.Fatalf("failed to read config file %s: %v", path, err)
}
if err := json.Unmarshal(data, &config); err != nil {
klog.Fatalf("failed to parse config file %s: %v", path, err)
}
return NewMiniTestDockerDeployer(&config)
}
func NewMiniTestDockerDeployer(config *MiniTestDockerConfig) MiniTestDeployer {
return &MiniTestDockerDeployer{
ctx: context.TODO(),
config: config,
isUp: false,
remoteUserName: remoteUserName,
}
}
func (m *MiniTestDockerDeployer) Up() error {
dockerClient, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return fmt.Errorf("failed to create docker api client: %v", err)
}
m.dockerClient = dockerClient
// pull the image
reader, err := dockerClient.ImagePull(m.ctx, m.config.Image, client.ImagePullOptions{})
if err != nil {
return fmt.Errorf("failed to pull image %s: %v", m.config.Image, err)
}
defer reader.Close()
_, err = io.Copy(os.Stdout, reader)
if err != nil {
return fmt.Errorf("failed to read image pull response: %v", err)
}
// find a free port for ssh
port, err := freeport.GetFreePort()
if err != nil {
return fmt.Errorf("failed to get a free port for ssh: %v", err)
}
m.sshPort = strconv.Itoa(port)
klog.Infof("Using port %s for ssh", m.sshPort)
// start the container
id := uuid.New().String()[:8]
//todo: remove hard coded ports
exposedPorts, portBindings, _ := nat.ParsePortSpecs([]string{m.sshPort + ":22"})
response, err := dockerClient.ContainerCreate(
m.ctx,
&container.Config{
Image: m.config.Image,
Tty: true, //-t
OpenStdin: true, // -i
//Entrypoint: []string{"/usr/sbin/init"},
ExposedPorts: exposedPorts,
},
&container.HostConfig{
Privileged: true,
PortBindings: portBindings,
}, nil, nil, "minitest-"+id)
if err != nil {
klog.Errorf("failed to create container from image %s: %v", m.config.Image, err)
return fmt.Errorf("failed to create container from image %s: %v", m.config.Image, err)
}
m.containerSHA = response.ID
err = dockerClient.ContainerStart(m.ctx, m.containerSHA,
client.ContainerStartOptions{})
if err != nil {
klog.Errorf("failed to start container %s: %v", m.containerSHA, err)
return fmt.Errorf("failed to start container %s: %v", m.containerSHA, err)
}
// set up ssh keys
if err := m.sshSetUp(); err != nil {
klog.Errorf("failed to set up ssh: %v", err)
return fmt.Errorf("failed to set up ssh: %v", err)
}
// set up sshd server
err = m.executeDockerShellCommand("root", fmt.Sprintf(sshSetupScript, m.remoteUserName, m.sshPublicKeyContent))
if err != nil {
klog.Errorf("failed to set up sshd server in container %s: %v", m.containerSHA, err)
return fmt.Errorf("failed to set up sshd server in container %s: %v", m.containerSHA, err)
}
// check ssh connectivity
if err := sshConnectionCheck(m.ctx, m.remoteUserName, "localhost", m.sshAdditionalArgs()); err != nil {
klog.Errorf("Failed to conntect via ssh: %v", err)
return fmt.Errorf("Failed to conntect via ssh: %v", err)
}
m.isUp = true
return nil
}
func (m *MiniTestDockerDeployer) Down() error {
os.RemoveAll(m.sshTempDir)
if m.dockerClient == nil {
klog.Errorf("m.dockerClient not set")
return fmt.Errorf("m.dockerClient not set")
}
if err := m.dockerClient.ContainerRemove(m.ctx, m.containerSHA, client.ContainerRemoveOptions{Force: true}); err != nil {
klog.Errorf("failed to remove container %s: %v", m.containerSHA, err)
return fmt.Errorf("failed to remove container %s: %v", m.containerSHA, err)
}
// close the docker client
m.dockerClient.Close()
m.isUp = false
klog.Infof("Successfully removed container %s", m.containerSHA)
return nil
}
func (m *MiniTestDockerDeployer) IsUp() (bool, error) {
return m.isUp, nil
}
func (m *MiniTestDockerDeployer) Execute(args ...string) error {
return executeSSHCommand(m.ctx, m.remoteUserName, "localhost", m.sshAdditionalArgs(), args...)
}
func (m *MiniTestDockerDeployer) SyncToRemote(src string, dst string, excludedPattern []string) error {
excludedArgs := make([]string, 0, len(excludedPattern)*2)
for _, pattern := range excludedPattern {
excludedArgs = append(excludedArgs, "--exclude", pattern)
}
dstRemote := fmt.Sprintf("%s@%s:%s", m.remoteUserName, "localhost", dst)
return executeRsyncSSHCommand(m.ctx, m.sshAdditionalArgs(), src, dstRemote, excludedArgs)
}
func (m *MiniTestDockerDeployer) SyncToHost(src string, dst string, excludedPattern []string) error {
excludedArgs := make([]string, 0, len(excludedPattern)*2)
for _, pattern := range excludedPattern {
excludedArgs = append(excludedArgs, "--exclude", pattern)
}
srcRemote := fmt.Sprintf("%s@%s:%s", m.remoteUserName, "localhost", src)
return executeRsyncSSHCommand(m.ctx, m.sshAdditionalArgs(), srcRemote, dst, excludedArgs)
//return executeScpCommand(m.ctx, m.remoteUserName, "localhost", m.scpAdditionalArgs(), src, dst)
}
func (m *MiniTestDockerDeployer) executeDockerShellCommand(user string, args ...string) error {
execResp, err := m.dockerClient.ContainerExecCreate(m.ctx, m.containerSHA, container.ExecOptions{
Cmd: append([]string{"/bin/bash", "-c"}, args...),
AttachStdout: true,
AttachStderr: true,
Tty: true,
User: user,
})
if err != nil {
return fmt.Errorf("failed to create exec instance: %v", err)
}
attachResp, err := m.dockerClient.ContainerExecAttach(
m.ctx, execResp.ID,
container.ExecAttachOptions{Tty: true})
if err != nil {
return fmt.Errorf("failed to attach to exec instance: %v", err)
}
defer attachResp.Close()
if _, err = io.Copy(os.Stdout, attachResp.Reader); err != nil {
return fmt.Errorf("failed to read exec output: %v", err)
}
return nil
}
func (m *MiniTestDockerDeployer) sshSetUp() error {
// we generate a ssh key pair and add the public key to the container's authorized_keys
sshTempDir, err := os.MkdirTemp("", "minitest-ssh-")
if err != nil {
return fmt.Errorf("failed to create temp dir for ssh keys: %v", err)
}
m.sshTempDir = sshTempDir
klog.Info("Created temp dir for ssh keys: ", sshTempDir)
// create private key file
sshPrivateKeyFile, err := os.CreateTemp(sshTempDir, "id_rsa")
if err != nil {
return fmt.Errorf("failed to create temp file for private key: %v", err)
}
if sshPrivateKeyFile.Chmod(0600) != nil {
return fmt.Errorf("failed to chmod private key file: %v", err)
}
m.sshPrivateKeyFile = sshPrivateKeyFile.Name()
klog.Info("Created temp file for private key: ", m.sshPrivateKeyFile)
// create public key file
sshPublicKeyFile, err := os.CreateTemp(sshTempDir, "id_rsa.pub")
if err != nil {
return fmt.Errorf("failed to create temp file for public key: %v", err)
}
if sshPublicKeyFile.Chmod(0644) != nil {
return fmt.Errorf("failed to chmod public key file: %v", err)
}
m.sshPublicKeyFile = sshPublicKeyFile.Name()
klog.Info("Created temp file for public key: ", m.sshPublicKeyFile)
// generate private key and convert to PEM format
privateKey, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return fmt.Errorf("failed to generate private key: %v", err)
}
privDER := x509.MarshalPKCS1PrivateKey(privateKey)
privBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privDER,
}
if err := pem.Encode(sshPrivateKeyFile, privBlock); err != nil {
sshPrivateKeyFile.Close()
return fmt.Errorf("failed to write private key to file: %v", err)
}
pub, err := gossh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
return fmt.Errorf("failed to generate public key: %v", err)
}
pubBytes := gossh.MarshalAuthorizedKey(pub)
if _, err := sshPublicKeyFile.Write(pubBytes); err != nil {
return fmt.Errorf("failed to write public key to file: %v", err)
}
sshPublicKeyFile.Close()
m.sshPublicKeyContent = string(pubBytes)
klog.Infof("Generated ssh public key:%s ", m.sshPublicKeyContent)
return nil
}
func (m *MiniTestDockerDeployer) sshAdditionalArgs() []string {
return []string{"-i", m.sshPrivateKeyFile, "-p", m.sshPort}
}
func (m *MiniTestDockerDeployer) scpAdditionalArgs() []string {
return []string{"-i", m.sshPrivateKeyFile, "-P", m.sshPort}
}

View File

@ -0,0 +1,92 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package deployer
import (
"context"
"fmt"
"os"
"os/exec"
"strings"
"time"
"k8s.io/klog/v2"
)
const ssh = "ssh"
const rsync = "rsync"
func executeLocalCommand(ctx context.Context, name string, args ...string) error {
cmd := exec.CommandContext(ctx, name, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
klog.Infof("Executing: %v", cmd.Args)
return cmd.Run()
}
func executeSSHCommand(ctx context.Context, user string, addr string, sshArguments []string, args ...string) error {
allArgs := []string{addr, "-o", "StrictHostKeyChecking=no",
"-o", "User=" + user, "-o", "UserKnownHostsFile=/dev/null"}
allArgs = append(allArgs, sshArguments...)
allArgs = append(allArgs, "--")
allArgs = append(allArgs, args...)
cmd := exec.CommandContext(ctx, "ssh", allArgs...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
klog.Infof("Executing: %v", cmd.Args)
return cmd.Run()
}
func sshConnectionCheck(ctx context.Context, user string, addr string, sshArguments []string) error {
var err error
for i := range 10 {
// cmd cannot be reused after its failure
err = executeSSHCommand(ctx, user, addr, sshArguments, "uname", "-a")
if err == nil {
return nil
}
klog.Infof("[%d/10]ssh command failed with error: %v", i, err)
time.Sleep(10 * time.Second)
}
return fmt.Errorf("failed to connect to vm: %v", err)
}
func executeRsyncSSHCommand(ctx context.Context, sshArguments []string, src string, dst string, rsyncArgs []string) error {
sshArgs := []string{ssh, "-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null"}
sshArgs = append(sshArgs, sshArguments...)
allArgs := []string{"-e", strings.Join(sshArgs, " "), "-avz"}
allArgs = append(allArgs, rsyncArgs...)
allArgs = append(allArgs, src, dst)
cmd := exec.CommandContext(ctx, rsync, allArgs...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
klog.Infof("Executing: %v", cmd.Args)
return cmd.Run()
}
func executeScpCommand(ctx context.Context, user string, addr string, sshArguments []string, src string, dst string) error {
allArgs := []string{"-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null"}
allArgs = append(allArgs, sshArguments...)
allArgs = append(allArgs, fmt.Sprintf("%s@%s:%s", user, addr, src), dst)
cmd := exec.CommandContext(ctx, "scp", allArgs...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
klog.Infof("Executing: %v", cmd.Args)
return cmd.Run()
}

73
hack/prow/minitest/go.mod Normal file
View File

@ -0,0 +1,73 @@
module minitest
go 1.25.0
replace github.com/spf13/cobra => github.com/spf13/cobra v1.9.1
require (
github.com/docker/go-connections v0.6.0
github.com/google/uuid v1.6.0
github.com/moby/moby/api v1.52.0-beta.1
github.com/moby/moby/client v0.1.0-beta.0
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
golang.org/x/crypto v0.41.0
k8s.io/klog/v2 v2.130.1
sigs.k8s.io/boskos v0.0.0-20250918103144-9ad89b7dd38e
sigs.k8s.io/kubetest2 v0.0.0-20250905115125-63caf6a17555
)
require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bombsimon/logrusr/v4 v4.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect
google.golang.org/protobuf v1.36.4 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apimachinery v0.32.2 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/controller-runtime v0.16.5 // indirect
sigs.k8s.io/prow v0.0.0-20240619181241-cfb8754e0459 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

416
hack/prow/minitest/go.sum Normal file
View File

@ -0,0 +1,416 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bombsimon/logrusr/v4 v4.1.0 h1:uZNPbwusB0eUXlO8hIUwStE6Lr5bLN6IgYgG+75kuh4=
github.com/bombsimon/logrusr/v4 v4.1.0/go.mod h1:pjfHC5e59CvjTBIU3V3sGhFWFAnsnhOR03TRc6im0l8=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/moby/api v1.52.0-beta.1 h1:r5U4U72E7xSHh4zX72ndY1mA/FOGiAPiGiz2a8rBW+w=
github.com/moby/moby/api v1.52.0-beta.1/go.mod h1:8sBV0soUREiudtow4vqJGOxa4GyHI5vLQmvgKdHq5Ok=
github.com/moby/moby/client v0.1.0-beta.0 h1:eXzrwi0YkzLvezOBKHafvAWNmH1B9HFh4n13yb2QgFE=
github.com/moby/moby/client v0.1.0-beta.0/go.mod h1:irAv8jRi4yKKBeND96Y+3AM9ers+KaJYk9Vmcm7loxs=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc=
go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/boskos v0.0.0-20250918103144-9ad89b7dd38e h1:OthwV3adPAnbNmaz/vkTHdeF27shWyY+wfd1ItyWLag=
sigs.k8s.io/boskos v0.0.0-20250918103144-9ad89b7dd38e/go.mod h1:v2jnRiOFvt2Ank4LbddEAFjwfj/+bv7uvrOfcNENTM8=
sigs.k8s.io/controller-runtime v0.16.5 h1:yr1cEJbX08xsTW6XEIzT13KHHmIyX8Umvme2cULvFZw=
sigs.k8s.io/controller-runtime v0.16.5/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0=
sigs.k8s.io/kubetest2 v0.0.0-20250905115125-63caf6a17555 h1:WL7/VL7GfsYTe2FUrhB5FE+B3c0rHzhFCUD2l98MHNU=
sigs.k8s.io/kubetest2 v0.0.0-20250905115125-63caf6a17555/go.mod h1:pBd0cFaT0hDqmwQg+TIhyLgPMYaH66QMLcKd09XnKTI=
sigs.k8s.io/prow v0.0.0-20240619181241-cfb8754e0459 h1:t8nFAgqf4A53NMuaML7xbBkaKcQtN3aqPPHDsVLfWWs=
sigs.k8s.io/prow v0.0.0-20240619181241-cfb8754e0459/go.mod h1:B6hUZArrw0kjY/Q4I5qBJd6lQoZP0nloG0ot1cTMhaA=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -0,0 +1,83 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package main
import (
"minitest/deployer"
"minitest/tester"
"flag"
"os"
"k8s.io/klog/v2"
)
var deployers = map[string]func(string) deployer.MiniTestDeployer{
// boskos deployer will require a gcp project and start instances in it to run the test
// the whole gcp project will be cleaned up after tests are done
"boskos": deployer.NewMiniTestBosKosDeployerFromConfigFile,
//docker deployer is for testing minitest. This should never be used for testing minikube
"docker": deployer.NewMiniTestDockerDeployerFromConfigFile,
}
var testers = map[string]tester.MiniTestTester{
"kvm-docker-linux-amd64-integration": &tester.KVMDockerLinuxAmd64IntegrationTester{},
}
func main() {
flagSet := flag.CommandLine
deployerName := flagSet.String("deployer", "boskos", "deployer to use. Options: [boskos, docker]")
config := flagSet.String("config", "", "path to deployer config file")
testerName := flagSet.String("tester", "kvm-docker-linux-amd64-integration", "tester to use. Options: [kvm-docker-linux-amd64-integration]")
klog.InitFlags(flagSet)
flagSet.Parse(os.Args[1:])
dep := getDeployer(*deployerName)(*config)
tester := getTester(*testerName)
if err := dep.Up(); err != nil {
klog.Fatalf("failed to start deployer: %v", err)
}
var testErr error
if testErr = tester.Run(dep); testErr != nil {
klog.Errorf("failed to run tests: %v", testErr)
}
if err := dep.Down(); err != nil {
klog.Fatalf("failed to stop deployer: %v", err)
}
if testErr != nil {
os.Exit(1)
}
}
func getDeployer(name string) func(string) deployer.MiniTestDeployer {
d, ok := deployers[name]
if !ok {
klog.Fatalf("deployer %s not found. Available deployers: %v", name, deployers)
}
return d
}
func getTester(name string) tester.MiniTestTester {
t, ok := testers[name]
if !ok {
klog.Fatalf("tester %s not found. Available testers: %v", name, testers)
}
return t
}

View File

@ -0,0 +1,60 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package tester
import (
"fmt"
"os"
"k8s.io/klog/v2"
)
var _ MiniTestTester = &KVMDockerLinuxAmd64IntegrationTester{}
// this runs the integration tests with kvm2 driver and a docker container runtime.
type KVMDockerLinuxAmd64IntegrationTester struct {
}
// Run implements MiniTestTester.
func (k *KVMDockerLinuxAmd64IntegrationTester) Run(runner MiniTestRunner) error {
if up, err := runner.IsUp(); err != nil || !up {
klog.Errorf("tester: deployed environment is not up: %v", err)
}
if err := runner.SyncToRemote(".", "~/minikube", []string{".cache"}); err != nil {
klog.Errorf("failed to sync file in docker deployer: %v", err)
}
pr := os.Getenv("PULL_NUMBER")
var testErr error
// install docker and libvirtd first then run the test in a new shell
if err := runner.Execute("cd minikube && ./hack/prow/integration_kvm_docker_linux_x86-64_pre.sh"); err != nil {
klog.Errorf("failed to install docker in env: %v", err)
return err
}
if testErr = runner.Execute(fmt.Sprintf("cd minikube && PULL_NUMBER=\"%s\" ./hack/prow/integration_kvm_docker_linux_x86-64.sh", pr)); testErr != nil {
klog.Errorf("failed to execute command in env: %v", testErr)
// don't return here, we still want to collect the test reports
}
// prow requires result file to be copied to $ARTIFACTS. All other files will not be persisted.
if err := copyFileToArtifact(runner); err != nil {
return err
}
return testErr
}

View File

@ -0,0 +1,70 @@
/*
Copyright 2025 The Kubernetes Authors All rights reserved.
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.
*/
package tester
import (
"os"
"k8s.io/klog/v2"
)
type MiniTestRunner interface {
// IsUp should return true if a test cluster is successfully provisioned
IsUp() (bool, error)
// Execute execute a command in the deployed environment
Execute(args ...string) error
// SyncToRemote copy files from src on host to dst on deployed environment
SyncToRemote(src string, dst string, excludedPattern []string) error
// SyncToRemote copy files from src on remote to host
SyncToHost(src string, dst string, excludedPattern []string) error
}
type MiniTestTester interface {
// Run should run the actual tests
Run(MiniTestRunner) error
}
func copyFileToArtifact(runner MiniTestRunner) error {
artifactLocation := os.Getenv("ARTIFACTS")
klog.Infof("copying to %s", artifactLocation)
if err := runner.SyncToHost("~/minikube/testout.txt", artifactLocation, nil); err != nil {
klog.Errorf("failed to sync testout.txt from deployer: %v", err)
return err
}
if err := runner.SyncToHost("~/minikube/test.json", artifactLocation, nil); err != nil {
klog.Errorf("failed to sync test.json in from deployer: %v", err)
return err
}
if err := runner.SyncToHost("~/minikube/junit-unit.xml", artifactLocation, nil); err != nil {
klog.Errorf("failed to sync junit-unit.xml in from deployer: %v", err)
return err
}
if err := runner.SyncToHost("~/minikube/test.html", artifactLocation, nil); err != nil {
klog.Errorf("failed to sync test.html in from deployer: %v", err)
return err
}
if err := runner.SyncToHost("~/minikube/test_summary.json", artifactLocation, nil); err != nil {
klog.Errorf("failed to sync test_summary.json in from deployer: %v", err)
return err
}
return nil
}

12
hack/prow/prow.mk Normal file
View File

@ -0,0 +1,12 @@
.PHONY: integration-prow-kvm-docker-linux-x86-64
integration-prow-kvm-docker-linux-x86-64:
# build first
# container-runtime=docker driver=kvm on linux/amd64
./hack/prow/minikube_cross_build.sh $(GO_VERSION) linux amd64
# set up ssh keys for gcloud cli. These env vars are set by test/infra
mkdir -p -m 0700 ~/.ssh
cp -f "${GCE_SSH_PRIVATE_KEY_FILE}" ~/.ssh/google_compute_engine
cp -f "${GCE_SSH_PUBLIC_KEY_FILE}" ~/.ssh/google_compute_engine.pub
GOTOOLCHAIN=auto go build -C ./hack/prow/minitest -o $(PWD)/out/minitest .
./out/minitest --deployer boskos --tester kvm-docker-linux-amd64-integration --config hack/prow/kvm.json

View File

@ -57,6 +57,11 @@ var (
`github.com/medyagh/gopogh/cmd/gopogh@.*`: `github.com/medyagh/gopogh/cmd/gopogh@{{.StableVersion}}`,
},
},
"hack/prow/installer/check_install_gopogh.sh": {
Replace: map[string]string{
`github.com/medyagh/gopogh/cmd/gopogh@.*`: `github.com/medyagh/gopogh/cmd/gopogh@{{.StableVersion}}`,
},
},
}
)

View File

@ -42,6 +42,11 @@ var (
`gotest.tools/gotestsum@.*`: `gotest.tools/gotestsum@{{.StableVersion}}`,
},
},
"hack/prow/installer/check_install_gotestsum.sh": {
Replace: map[string]string{
`gotest.tools/gotestsum@.*`: `gotest.tools/gotestsum@{{.StableVersion}}`,
},
},
}
)

View File

@ -4,8 +4,10 @@ publish = "site/public/"
command = "pwd && cd themes/docsy && npm install && git submodule update -f --init && cd ../.. && hugo"
[build.environment]
NODE_VERSION = "20.19.5"
HUGO_VERSION = "v0.148.2"
# node Active LTS
NODE_VERSION = "24.11.0"
# https://github.com/gohugoio/hugo/releases
HUGO_VERSION = "0.152.2"
[context.production.environment]
HUGO_ENV = "production"

View File

@ -276,7 +276,6 @@ var Addons = map[string]*Addon{
"0640"),
}, false, "istio", "3rd party (Istio)", "", "https://istio.io/latest/docs/setup/platform-setup/minikube/", nil, nil),
"inspektor-gadget": NewAddon([]*BinAsset{
MustBinAsset(addons.InspektorGadgetAssets, "inspektor-gadget/ig-crd.yaml", vmpath.GuestAddonsDir, "ig-crd.yaml", "0640"),
MustBinAsset(addons.InspektorGadgetAssets, "inspektor-gadget/ig-deployment.yaml.tmpl", vmpath.GuestAddonsDir, "ig-deployment.yaml", "0640"),
}, false, "inspektor-gadget", "3rd party (inspektor-gadget.io)", "https://github.com/orgs/inspektor-gadget/people", "https://minikube.sigs.k8s.io/docs/handbook/addons/inspektor-gadget/",
map[string]string{

View File

@ -20,6 +20,7 @@ package integration
import (
"context"
"encoding/json"
"fmt"
"os/exec"
"runtime"
@ -101,6 +102,23 @@ func TestISOImage(t *testing.T) {
}
})
t.Run("VersionJSON", func(t *testing.T) {
rr, err := Run(t, exec.CommandContext(ctx, Target(), "-p", profile, "ssh", "cat /version.json"))
if err != nil {
t.Fatalf("failed to read /version.json. args %q: %v", rr.Command(), err)
}
var data map[string]string
if err := json.Unmarshal(rr.Stdout.Bytes(), &data); err != nil {
t.Fatalf("failed to parse /version.json as JSON: %v. \nContent: %s", err, rr.Stdout)
}
t.Logf("Successfully parsed /version.json:")
for k, v := range data {
t.Logf(" %s: %s", k, v)
}
})
t.Run("eBPFSupport", func(t *testing.T) {
// Ensure that BTF type information is available (https://github.com/kubernetes/minikube/issues/21788)
btfFile := "/sys/kernel/btf/vmlinux"

View File

@ -545,12 +545,12 @@
"Please re-eval your podman-env, To ensure your environment variables have updated ports:\n\n\t'minikube -p {{.profile_name}} podman-env'\n\n\t": "Veuillez réévaluer votre podman-env, pour vous assurer que vos variables d'environnement ont des ports mis à jour :\n\n\t'minikube -p {{.profile_name}} podman-env'\n\n\t",
"Please run `minikube logs --file=logs.txt` and attach logs.txt to the GitHub issue.": "Veuillez exécuter `minikube logs --file=logs.txt` et attachez logs.txt au problème GitHub.",
"Please see {{.documentation_url}} for more details": "Veuillez consulter {{.documentation_url}} pour plus de détails",
"Please specify the directory to be mounted:\n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "",
"Please specify the directory to be mounted:\n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "Veuillez spécifier le répertoire à monter :\n\tminikube mount \u003crépertoire source\u003e:\u003crépertoire cible\u003e (exemple : \"/host-home:/vm-home\")",
"Please specify the directory to be mounted: \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (example: \"/host-home:/vm-home\")": "Veuillez spécifier le répertoire à monter : \n\tminikube mount \u003csource directory\u003e:\u003ctarget directory\u003e (exemple : \"/host-home:/vm-home\")",
"Please specify the path to copy:\n\tminikube cp \u003csource file path\u003e \u003ctarget file absolute path\u003e (example: \"minikube cp a/b.txt /copied.txt\")": "",
"Please specify the path to copy:\n\tminikube cp \u003csource file path\u003e \u003ctarget file absolute path\u003e (example: \"minikube cp a/b.txt /copied.txt\")": "Veuillez spécifier le chemin à copier :\n\tminikube cp \u003cchemin du fichier source\u003e \u003cchemin absolu du fichier cible\u003e (exemple : \"minikube cp a/b.txt /copied.txt\")",
"Please specify the path to copy: \n\tminikube cp \u003csource file path\u003e \u003ctarget file absolute path\u003e (example: \"minikube cp a/b.txt /copied.txt\")": "Veuillez spécifier le chemin à copier : \n\tminikube cp \u003cchemin du fichier source\u003e \u003cchemin absolu du fichier cible\u003e (exemple : \"minikube cp a/b.txt /copied.txt\")",
"Please try purging minikube using `minikube delete --all --purge`": "Veuillez essayer de purger minikube en utilisant `minikube delete --all --purge`",
"Please visit the following link for documentation around this:\n\thttps://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages\n": "",
"Please visit the following link for documentation around this:\n\thttps://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages\n": "Veuillez consulter le lien suivant pour obtenir de la documentation à ce sujet :\n\thttps://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages\n",
"Please visit the following link for documentation around this: \n\thttps://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages\n": "Veuillez visiter le lien suivant pour la documentation à ce sujet : \n\thttps://help.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with -github-packages#authentiating-to-github-packages\n",
"Populates the specified folder with documentation in markdown about minikube": "Remplit le dossier spécifié avec la documentation en markdown sur minikube",
"PowerShell is running in constrained mode, which is incompatible with Hyper-V scripting.": "PowerShell s'exécute en mode contraint, ce qui est incompatible avec les scripts Hyper-V.",