Merge branch 'master' into ankaggar/instantiate_device_plugin

This commit is contained in:
aggarwal0009 2024-11-06 09:53:16 -08:00 коммит произвёл GitHub
Родитель aaa095ccf2 b7190c88c0
Коммит efcec7d235
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
72 изменённых файлов: 2046 добавлений и 563 удалений

Просмотреть файл

@ -91,7 +91,7 @@ stages:
fi
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"

Просмотреть файл

@ -47,7 +47,7 @@ stages:
pwd
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
@ -117,7 +117,7 @@ stages:
new_count=${NODE_COUNT_UP} # Do not exceed NODE_COUNT_UP
fi
echo "Scaling up nodes to $new_count"
az aks nodepool scale --name nodepool1 --cluster-name ${CLUSTER} --resource-group ${RESOURCE_GROUP} --node-count $new_count
make -C ./hack/aks scale-nodes AZCLI=az GROUP=${RESOURCE_GROUP} CLUSTER=${CLUSTER} NODEPOOL=nodepool1 NODE_COUNT=$new_count
if [ $new_count -eq ${NODE_COUNT_UP} ]; then
echo "Node count reached ${NODE_COUNT_UP}"
break
@ -442,6 +442,7 @@ stages:
- job: scale_down
pool:
name: "$(BUILD_POOL_NAME_DEFAULT)"
timeoutInMinutes: 120
steps:
- task: AzureCLI@2
inputs:
@ -453,8 +454,7 @@ stages:
set -ex
az aks get-credentials --resource-group ${RESOURCE_GROUP} --name ${CLUSTER}
echo "Scaling to 5 nodes"
vmss_name=$(az vmss list -g MC_${RESOURCE_GROUP}_${CLUSTER}_$(LOCATION) --query "[].name" -o tsv)
make -C ./hack/aks scale-vmss AZCLI=az GROUP=${RESOURCE_GROUP} CLUSTER=${CLUSTER} REGION=$(LOCATION) VMSS_NAME=$vmss_name NODE_COUNT=5
make -C ./hack/aks scale-nodes AZCLI=az GROUP=${RESOURCE_GROUP} CLUSTER=${CLUSTER} NODEPOOL=nodepool1 NODE_COUNT=5
kubectl get node
name: "ScaleDown"
displayName: "Scale down to 5 Nodes"

Просмотреть файл

@ -95,7 +95,7 @@ stages:
kubectl get po -owide -A
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"

Просмотреть файл

@ -77,7 +77,7 @@ stages:
scriptType: "bash"
addSpnToEnvironment: true
inlineScript: |
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config-hubble.yaml
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-agent/files

Просмотреть файл

@ -261,6 +261,17 @@ stages:
k8sVersion: ""
dependsOn: "containerize"
# Cilium Nodesubnet E2E tests
- template: singletenancy/cilium-nodesubnet/cilium-nodesubnet-e2e-job-template.yaml
parameters:
name: "cilium_nodesubnet_e2e"
displayName: Cilium NodeSubnet
clusterType: nodesubnet-byocni-nokubeproxy-up
clusterName: "cilndsubnete2e"
vmSize: Standard_B2s
k8sVersion: ""
dependsOn: "containerize"
# Cilium Overlay E2E tests
- template: singletenancy/cilium-overlay/cilium-overlay-e2e-job-template.yaml
parameters:
@ -405,6 +416,7 @@ stages:
- azure_overlay_stateless_e2e
- aks_swift_e2e
- cilium_e2e
- cilium_nodesubnet_e2e
- cilium_overlay_e2e
- cilium_h_overlay_e2e
- aks_ubuntu_22_linux_e2e
@ -425,6 +437,10 @@ stages:
cilium_e2e:
name: cilium_e2e
clusterName: "ciliume2e"
region: $(REGION_AKS_CLUSTER_TEST)
cilium_nodesubnet_e2e:
name: cilium_nodesubnet_e2e
clusterName: "cilndsubnete2e"
region: $(REGION_AKS_CLUSTER_TEST)
cilium_overlay_e2e:
name: cilium_overlay_e2e

Просмотреть файл

@ -34,7 +34,7 @@ steps:
kubectl cluster-info
kubectl get po -owide -A
echo "install Cilium ${CILIUM_DUALSTACK_VERSION}"
export DIR=${CILIUM_DUALSTACK_VERSION%.*}
export DIR=$(echo ${CILIUM_DUALSTACK_VERSION#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config-dualstack.yaml

Просмотреть файл

@ -35,7 +35,7 @@ steps:
kubectl cluster-info
kubectl get po -owide -A
echo "install Cilium ${CILIUM_DUALSTACK_VERSION}"
export DIR=${CILIUM_DUALSTACK_VERSION%.*}
export DIR=$(echo ${CILIUM_DUALSTACK_VERSION#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config-dualstack.yaml

Просмотреть файл

@ -71,9 +71,9 @@ stages:
os: ${{ parameters.os }}
datapath: true
dns: true
cni: cilium
portforward: true
service: true
hostport: true
dependsOn: ${{ parameters.name }}
- job: failedE2ELogs

Просмотреть файл

@ -58,7 +58,7 @@ steps:
kubectl cluster-info
kubectl get po -owide -A
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config.yaml

Просмотреть файл

@ -38,7 +38,7 @@ steps:
make -C ./hack/aks set-kubeconf AZCLI=az CLUSTER=${{ parameters.clusterName }}
ls -lah
export CILIUM_VERSION_TAG=${CILIUM_HUBBLE_VERSION_TAG}
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config-hubble.yaml
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-agent/files

Просмотреть файл

@ -32,7 +32,7 @@ steps:
make -C ./hack/aks set-kubeconf AZCLI=az CLUSTER=${{ parameters.clusterName }}
ls -lah
export CILIUM_VERSION_TAG=${CILIUM_HUBBLE_VERSION_TAG}
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config-hubble.yaml
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-agent/files

Просмотреть файл

@ -54,7 +54,7 @@ steps:
kubectl apply -f test/integration/manifests/cilium/cilium${FILE_PATH}-operator
else
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config.yaml

Просмотреть файл

@ -48,7 +48,7 @@ steps:
kubectl apply -f test/integration/manifests/cilium/cilium${FILE_PATH}-operator
else
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config.yaml

Просмотреть файл

@ -40,7 +40,7 @@ steps:
kubectl cluster-info
kubectl get po -owide -A
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config.yaml

Просмотреть файл

@ -34,7 +34,7 @@ steps:
kubectl cluster-info
kubectl get po -owide -A
echo "install Cilium ${CILIUM_VERSION_TAG}"
export DIR=${CILIUM_VERSION_TAG%.*}
export DIR=$(echo ${CILIUM_VERSION_TAG#v} | cut -d. -f1,2)
echo "installing files from ${DIR}"
echo "deploy Cilium ConfigMap"
kubectl apply -f test/integration/manifests/cilium/v${DIR}/cilium-config/cilium-config.yaml

Просмотреть файл

@ -300,7 +300,7 @@ container-buildah: # util target to build container images using buildah. do not
buildah push $(IMAGE_REGISTRY)/$(IMAGE):$(TAG)
container-docker: # util target to build container images using docker buildx. do not invoke directly.
docker buildx create --use --platform $(PLATFORM)
docker buildx create --use --driver-opt image=mcr.microsoft.com/oss/v2/moby/buildkit:v0.16.0-2 --platform $(PLATFORM)
docker buildx build \
$(BUILDX_ACTION) \
--build-arg ARCH=$(ARCH) \
@ -436,7 +436,8 @@ cni-image: ## build cni container image.
TARGET=$(OS) \
OS=$(OS) \
ARCH=$(ARCH) \
OS_VERSION=$(OS_VERSION)
OS_VERSION=$(OS_VERSION) \
EXTRA_BUILD_ARGS='--build-arg CNI_AI_PATH=$(CNI_AI_PATH) --build-arg CNI_AI_ID=$(CNI_AI_ID)'
cni-image-push: ## push cni container image.
$(MAKE) container-push \

Просмотреть файл

@ -7,7 +7,7 @@ toolchain go1.23.2
require (
github.com/Azure/azure-container-networking v1.5.21
github.com/containernetworking/cni v1.2.3
github.com/containernetworking/plugins v1.5.1
github.com/containernetworking/plugins v1.6.0
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
@ -24,18 +24,18 @@ require (
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.12.3 // indirect
github.com/Microsoft/hcsshim v0.12.7 // indirect
github.com/avast/retry-go/v3 v3.1.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/billgraziano/dpapi v0.5.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/cgroups/v3 v3.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/cgroups/v3 v3.0.3 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/coreos/go-iptables v0.7.0 // indirect
github.com/coreos/go-iptables v0.8.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.4 // indirect
@ -43,7 +43,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
@ -59,28 +59,27 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.18.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.46.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/prometheus/client_golang v1.20.2 // 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/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/grpc v1.62.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

Просмотреть файл

@ -21,8 +21,8 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.12.3 h1:LS9NXqXhMoqNCplK1ApmVSfB4UnVLRDWRapB6EIlxE0=
github.com/Microsoft/hcsshim v0.12.3/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ=
github.com/Microsoft/hcsshim v0.12.7 h1:MP6R1spmjxTE4EU4J3YsrTxn8CjvN9qwjTKJXldFaRg=
github.com/Microsoft/hcsshim v0.12.7/go.mod h1:HPbAuJ9BvQYYZbB4yEQcyGIsTP5L4yHKeO9XO149AEM=
github.com/avast/retry-go/v3 v3.1.1 h1:49Scxf4v8PmiQ/nY0aY3p0hDueqSmc7++cBbtiDGu2g=
github.com/avast/retry-go/v3 v3.1.1/go.mod h1:6cXRK369RpzFL3UQGqIUp9Q7GDrams+KsYWrfNA1/nQ=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -30,20 +30,20 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/billgraziano/dpapi v0.5.0 h1:pcxA17vyjbDqYuxCFZbgL9tYIk2xgbRZjRaIbATwh+8=
github.com/billgraziano/dpapi v0.5.0/go.mod h1:lmEcZjRfLCSbUTsRu8V2ti6Q17MvnKn3N9gQqzDdTh0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0=
github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE=
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
github.com/containernetworking/cni v1.2.3 h1:hhOcjNVUQTnzdRJ6alC5XF+wd9mfGIUaj8FuJbEslXM=
github.com/containernetworking/cni v1.2.3/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
github.com/containernetworking/plugins v1.5.1 h1:T5ji+LPYjjgW0QM+KyrigZbLsZ8jaX+E5J/EcKOE4gQ=
github.com/containernetworking/plugins v1.5.1/go.mod h1:MIQfgMayGuHYs0XdNudf31cLLAC+i242hNm6KuDGqCM=
github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8=
github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/containernetworking/plugins v1.6.0 h1:lrsUrLF7QODLx6gncHOqk/pnCiC7c6bvDAskV4KUifQ=
github.com/containernetworking/plugins v1.6.0/go.mod h1:rYLQWMJz/dYuW1XhHdc9xuzdkgbkWEEjwOhUm84+288=
github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc=
github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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=
@ -63,8 +63,8 @@ github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
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-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
@ -99,10 +99,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -111,15 +109,14 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA=
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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=
@ -132,6 +129,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -159,11 +158,11 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
@ -173,15 +172,15 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
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.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
github.com/prometheus/client_golang v1.20.2/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.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y=
github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@ -203,7 +202,6 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@ -215,9 +213,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
@ -226,7 +223,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -237,45 +233,34 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
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.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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-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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -286,29 +271,26 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -318,10 +300,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
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=

Просмотреть файл

@ -6,7 +6,7 @@ toolchain go1.23.2
require (
github.com/AlekSi/gocov-xml v1.1.0
github.com/axw/gocov v1.1.0
github.com/axw/gocov v1.2.1
github.com/golang/mock v1.6.0
github.com/golangci/golangci-lint v1.61.0
github.com/jstemmer/go-junit-report v1.0.0
@ -120,7 +120,6 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mgechev/revive v1.4.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
@ -172,7 +171,6 @@ require (
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect
github.com/tdakkota/asciicheck v0.2.0 // indirect
github.com/tetafro/godot v1.4.18 // indirect
github.com/timakin/bodyclose v0.0.0-20240125160201-f835fa56326a // indirect

Просмотреть файл

@ -4,48 +4,30 @@
4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU=
github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8=
github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0=
github.com/Abirdcfly/dupword v0.0.14 h1:3U4ulkc8EUo+CaT105/GJ1BQwtgyj6+VaBVbAX11Ba8=
github.com/Abirdcfly/dupword v0.0.14/go.mod h1:VKDAbxdY8YbKUByLGg8EETzYSuC4crm9WwI6Y3S0cLI=
github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY=
github.com/Abirdcfly/dupword v0.1.1/go.mod h1:B49AcJdTYYkpd4HjgAcutNGG9HZ2JWwKunH9Y2BA6sM=
github.com/AlekSi/gocov-xml v1.1.0 h1:iElWGi7s/MuL8/d8WDtI2fOAsN3ap9x8nK5RrAhaDng=
github.com/AlekSi/gocov-xml v1.1.0/go.mod h1:g1dRVOCHjKkMtlPfW6BokJ/qxoeZ1uPNAK7A/ii3CUo=
github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM=
github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns=
github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA=
github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI=
github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ=
github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ=
github.com/Antonboom/nilnil v1.0.0 h1:n+v+B12dsE5tbAqRODXmEKfZv9j2KcTBrp+LkoM4HZk=
github.com/Antonboom/nilnil v1.0.0/go.mod h1:fDJ1FSFoLN6yoG65ANb1WihItf6qt9PJVTn/s2IrcII=
github.com/Antonboom/testifylint v1.3.1 h1:Uam4q1Q+2b6H7gvk9RQFw6jyVDdpzIirFOOrbs14eG4=
github.com/Antonboom/testifylint v1.3.1/go.mod h1:NV0hTlteCkViPW9mSR4wEMfwp+Hs1T3dY60bkvSfhpM=
github.com/Antonboom/testifylint v1.5.0 h1:dlUIsDMtCrZWUnvkaCz3quJCoIjaGi41GzjPBGkkJ8A=
github.com/Antonboom/testifylint v1.5.0/go.mod h1:wqaJbu0Blb5Wag2wv7Z5xt+CIV+eVLxtGZrlK13z3AE=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Crocmagnon/fatcontext v0.2.2 h1:OrFlsDdOj9hW/oBEJBNSuH7QWf+E9WPVHw+x52bXVbk=
github.com/Crocmagnon/fatcontext v0.2.2/go.mod h1:WSn/c/+MMNiD8Pri0ahRj0o9jVpeowzavOQplBJw6u0=
github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA=
github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74=
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 h1:sATXp1x6/axKxz2Gjxv8MALP0bXaNRfQinEwyfMcx8c=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0/go.mod h1:Nl76DrGNJTA1KJ0LePKBw/vznBX1EHbAZX8mwjR82nI=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU=
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA=
github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/go-check-sumtype v0.1.4 h1:WCvlB3l5Vq5dZQTFmodqL2g68uHiSwwlWcT5a2FGK0c=
github.com/alecthomas/go-check-sumtype v0.1.4/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ=
github.com/alecthomas/go-check-sumtype v0.2.0 h1:Bo+e4DFf3rs7ME9w/0SU/g6nmzJaphduP8Cjiz0gbwY=
github.com/alecthomas/go-check-sumtype v0.2.0/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
@ -60,24 +42,19 @@ github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8ger
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI=
github.com/axw/gocov v1.1.0 h1:y5U1krExoJDlb/kNtzxyZQmNRprFOFCutWbNjcQvmVM=
github.com/axw/gocov v1.1.0/go.mod h1:H9G4tivgdN3pYSSVrTFBr6kGDCmAkgbJhtxFzAvgcdw=
github.com/axw/gocov v1.2.1 h1:bqtQDBC2tQWcPzTYIVxK0EDCfNRLwsk4NZ0+GB4hX8Q=
github.com/axw/gocov v1.2.1/go.mod h1:l11/vZBBKfQEE+42jF47myjDrRZHM+hR+XgGjI6FopU=
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/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY=
github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM=
github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
github.com/bombsimon/wsl/v4 v4.2.1 h1:Cxg6u+XDWff75SIFFmNsqnIOgob+Q9hG6y/ioKbRFiM=
github.com/bombsimon/wsl/v4 v4.2.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo=
github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw=
github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo=
github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY=
github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ=
github.com/breml/bidichk v0.3.1 h1:mm0l1NVE6lhaF4GUI8wX6TRV+e9kyHSvtA1wSG3nDqU=
github.com/breml/bidichk v0.3.1/go.mod h1:Qo0jQtZkQYyArvHxFXxNmaioxJRgfnSo6UirDTaAJL4=
github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA=
github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U=
github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk=
github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8=
github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0=
@ -88,24 +65,17 @@ github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyy
github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50=
github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4=
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/ckaznocha/intrange v0.1.2 h1:3Y4JAxcMntgb/wABQ6e8Q8leMd26JbX2790lIss9MTI=
github.com/ckaznocha/intrange v0.1.2/go.mod h1:RWffCw/vKBwHeOEwWdCikAtY0q4gGt8VhJZEEA5n+RE=
github.com/ckaznocha/intrange v0.2.1 h1:M07spnNEQoALOJhwrImSrJLaxwuiQK+hA2DeajBlwYk=
github.com/ckaznocha/intrange v0.2.1/go.mod h1:7NEhVyf8fzZO5Ds7CRaqPEm52Ut83hsTiL5zbER/HYk=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo=
github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
github.com/daixiang0/gci v0.13.4 h1:61UGkmpoAcxHM2hhNkZEf5SzwQtWJXTSws7jaPyqwlw=
github.com/daixiang0/gci v0.13.4/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -130,20 +100,14 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk=
github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw=
github.com/ghostiam/protogetter v0.3.8 h1:LYcXbYvybUyTIxN2Mj9h6rHrDZBDwZloPoKctWrFyJY=
github.com/ghostiam/protogetter v0.3.8/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
github.com/go-critic/go-critic v0.11.4 h1:O7kGOCx0NDIni4czrkRIXTnit0mkyKOCePh3My6OyEU=
github.com/go-critic/go-critic v0.11.4/go.mod h1:2QAdo4iuLik5S9YG0rT4wcZ8QxwHYkrr6/2MWAiv/vc=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
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/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=
@ -165,20 +129,14 @@ github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQi
github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA=
github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4=
github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@ -187,12 +145,8 @@ github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
github.com/golangci/gofmt v0.0.0-20231019111953-be8c47862aaa h1:L0Zq43Px2HrLroRKEgfCsQLMJUkjskJBB1kd1Zjcvvc=
github.com/golangci/gofmt v0.0.0-20231019111953-be8c47862aaa/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM=
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME=
github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE=
github.com/golangci/golangci-lint v1.59.1 h1:CRRLu1JbhK5avLABFJ/OHVSQ0Ie5c4ulsOId1h3TTks=
github.com/golangci/golangci-lint v1.59.1/go.mod h1:jX5Oif4C7P0j9++YB2MMJmoNrb01NJ8ITqKWNLewThg=
github.com/golangci/golangci-lint v1.61.0 h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8=
github.com/golangci/golangci-lint v1.61.0/go.mod h1:e4lztIrJJgLPhWvFPDkhiMwEFRrWlmFbrZea3FsJyN8=
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
@ -216,9 +170,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA=
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s=
github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
@ -248,8 +201,6 @@ github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjz
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48=
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
github.com/jjti/go-spancheck v0.6.1 h1:ZK/wE5Kyi1VX3PJpUO2oEgeoI4FWOUm7Shb2Gbv5obI=
github.com/jjti/go-spancheck v0.6.1/go.mod h1:vF1QkOO159prdo6mHRxak2CpzDpHAfKiPUDP/NeRnX8=
github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk=
github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@ -266,6 +217,8 @@ github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg=
github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -294,8 +247,6 @@ github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE=
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/matoous/godox v0.0.0-20240105082147-c5b5e0e7c0c0 h1:Ny7cm4KSWceJLYyI1sm+aFIVDWSGXLcOJ0O0UaS5wdU=
github.com/matoous/godox v0.0.0-20240105082147-c5b5e0e7c0c0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
@ -306,14 +257,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE=
github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA=
github.com/mgechev/revive v1.4.0 h1:+6LDNE1XKsUCkpuDOMrzjOsXqiQOZ/jPlscLyA6mMXw=
github.com/mgechev/revive v1.4.0/go.mod h1:uzGR6feiCiJi4oND58/KMt/lEnR5vmjzRYPZiR0sQRQ=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@ -325,8 +270,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA=
github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI=
github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=
github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@ -345,12 +288,10 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc=
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
@ -358,38 +299,23 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
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/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
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/polyfloyd/go-errorlint v1.5.2 h1:SJhVik3Umsjh7mte1vE0fVZ5T1gznasQG3PV7U5xFdA=
github.com/polyfloyd/go-errorlint v1.5.2/go.mod h1:sH1QC1pxxi0fFecsVIzBmxtrgd9IF/SkJpA6wqyKAJs=
github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY=
github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
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.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/common v0.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
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/quasilyte/go-ruleguard v0.4.2 h1:htXcXDK6/rO12kiTHKfHuqR4kr3Y4M0J0rOL6CH/BYs=
github.com/quasilyte/go-ruleguard v0.4.2/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI=
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo=
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI=
github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE=
@ -401,21 +327,15 @@ github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:r
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryancurrah/gomodguard v1.3.2 h1:CuG27ulzEB1Gu5Dk5gP8PFxSOZ3ptSdP5iI/3IXxM18=
github.com/ryancurrah/gomodguard v1.3.2/go.mod h1:LqdemiFomEjcxOqirbQCb3JFvSxH2JUYMerTFd3sF2o=
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
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/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
@ -426,12 +346,8 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6Ng
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
github.com/sashamelentyev/usestdlibvars v1.26.0 h1:LONR2hNVKxRmzIrZR0PhSF3mhCAzvnr+DcUiHgREfXE=
github.com/sashamelentyev/usestdlibvars v1.26.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI=
github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9 h1:rnO6Zp1YMQwv8AyxzuwsVohljJgp4L0ZqiCgtACsPsc=
github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9/go.mod h1:dg7lPlu/xK/Ut9SedURCoZbVCR4yC7fM65DtH9/CDHs=
github.com/securego/gosec/v2 v2.21.4 h1:Le8MSj0PDmOnHJgUATjD96PaXRvCpKC+DGJvwyy0Mlk=
github.com/securego/gosec/v2 v2.21.4/go.mod h1:Jtb/MwRQfRxCXyCm1rfM1BEiiiTfUOdyzzAhlr6lUTA=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
@ -442,12 +358,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE=
github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=
github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak=
github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg=
github.com/sivchari/tenv v1.10.0 h1:g/hzMA+dBCKqGXgW8AV/1xIWhAvDrx0zFKNR48NFMg0=
github.com/sivchari/tenv v1.10.0/go.mod h1:tdY24masnVoZFxYrHv/nD6Tc8FbkEtAQEEziXpyMgqY=
github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00=
github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo=
github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM=
github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
@ -456,18 +368,12 @@ github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCp
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
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.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
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/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM=
github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
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/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
@ -491,26 +397,18 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.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/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8=
github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk=
github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM=
github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg=
github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
github.com/tetafro/godot v1.4.16 h1:4ChfhveiNLk4NveAZ9Pu2AN8QZ2nkUGFuadM9lrr5D0=
github.com/tetafro/godot v1.4.16/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
github.com/tetafro/godot v1.4.18 h1:ouX3XGiziKDypbpXqShBfnNLTSjR8r3/HVzrtJ+bHlI=
github.com/tetafro/godot v1.4.18/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M=
github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ=
github.com/timakin/bodyclose v0.0.0-20240125160201-f835fa56326a h1:A6uKudFIfAEpoPdaal3aSqGxBzLyU8TqyXImLwo6dIo=
github.com/timakin/bodyclose v0.0.0-20240125160201-f835fa56326a/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460=
github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4=
github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg=
github.com/tomarrell/wrapcheck/v2 v2.8.3 h1:5ov+Cbhlgi7s/a42BprYoxsr73CbdMUTzE3bRDFASUs=
github.com/tomarrell/wrapcheck/v2 v2.8.3/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4=
github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
@ -519,8 +417,6 @@ github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81v
github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4=
github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ=
github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI=
github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k=
github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM=
github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
@ -546,37 +442,26 @@ go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ=
go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28=
go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs=
go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM=
go-simpler.org/sloglint v0.7.1 h1:qlGLiqHbN5islOxjeLXoPtUdZXb669RW+BDQ+xOSNoU=
go-simpler.org/sloglint v0.7.1/go.mod h1:OlaVDRh/FKKd4X4sIMbsz8st97vomydceL146Fthh/c=
go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY=
go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw=
golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8=
golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/exp/typeparams v0.0.0-20241004190924-225e2abe05e6 h1:+AMOlFY5Pel10HQw2IF09ktVEYXJAIFg39fzZp75OmI=
golang.org/x/exp/typeparams v0.0.0-20241004190924-225e2abe05e6/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -586,13 +471,10 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@ -605,15 +487,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -625,8 +504,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -643,11 +520,9 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/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-20220702020025-31831981b65f/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.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -655,13 +530,10 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -678,14 +550,11 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/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-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
@ -702,33 +571,25 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -747,38 +608,22 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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=
honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A=
k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA=
k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU=
k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI=
k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0=
k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc=
k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40=
k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ=
k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o=
k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis=
k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U=
k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
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-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI=
k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6 h1:MDF6h2H/h4tbzmtIKTuctcwZmY0tY9mD9fNT47QO6HI=
k8s.io/utils v0.0.0-20240921022957-49e7df575cb6/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U=
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ=
mvdan.cc/unparam v0.0.0-20240917084806-57a3b4290ba3 h1:YkmTN1n5U60NM02j7TCSWRlW3fqNiuXe/eVXf0dLFN8=
mvdan.cc/unparam v0.0.0-20240917084806-57a3b4290ba3/go.mod h1:z5yboO1sP1Q9pcfvS597TpfbNXQjphDlkCJHzt13ybc=
sigs.k8s.io/controller-tools v0.13.0 h1:NfrvuZ4bxyolhDBt/rCZhDnx3M2hzlhgo5n3Iv2RykI=
sigs.k8s.io/controller-tools v0.13.0/go.mod h1:5vw3En2NazbejQGCeWKRrE7q4P+CW8/klfVqP8QZkgA=
sigs.k8s.io/controller-tools v0.16.3 h1:z48C5/d4jCVQQvtiSBL5MYyZ3EO2eFIOXrIKMgHVhFY=
sigs.k8s.io/controller-tools v0.16.3/go.mod h1:AEj6k+w1kYpLZv2einOH3mj52ips4W/6FUjnB5tkJGs=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=

Просмотреть файл

@ -12,10 +12,12 @@ FROM --platform=linux/${ARCH} mcr.microsoft.com/cbl-mariner/base/core@sha256:a49
FROM go AS azure-vnet
ARG OS
ARG VERSION
ARG CNI_AI_PATH
ARG CNI_AI_ID
WORKDIR /azure-container-networking
COPY . .
RUN GOOS=$OS CGO_ENABLED=0 go build -a -o /go/bin/azure-vnet -trimpath -ldflags "-X main.version="$VERSION"" -gcflags="-dwarflocationlists=true" cni/network/plugin/main.go
RUN GOOS=$OS CGO_ENABLED=0 go build -a -o /go/bin/azure-vnet-telemetry -trimpath -ldflags "-X main.version="$VERSION"" -gcflags="-dwarflocationlists=true" cni/telemetry/service/telemetrymain.go
RUN GOOS=$OS CGO_ENABLED=0 go build -a -o /go/bin/azure-vnet-telemetry -trimpath -ldflags "-X main.version="$VERSION" -X "$CNI_AI_PATH"="$CNI_AI_ID"" -gcflags="-dwarflocationlists=true" cni/telemetry/service/telemetrymain.go
RUN GOOS=$OS CGO_ENABLED=0 go build -a -o /go/bin/azure-vnet-ipam -trimpath -ldflags "-X main.version="$VERSION"" -gcflags="-dwarflocationlists=true" cni/ipam/plugin/main.go
RUN GOOS=$OS CGO_ENABLED=0 go build -a -o /go/bin/azure-vnet-stateless -trimpath -ldflags "-X main.version="$VERSION"" -gcflags="-dwarflocationlists=true" cni/network/stateless/main.go

Просмотреть файл

@ -31,7 +31,7 @@ type MockIpamInvoker struct {
delegatedVMNIC bool
delegatedVMNICFail bool
ipMap map[string]bool
customReturn map[string]network.InterfaceInfo
add func(opt IPAMAddConfig) (ipamAddResult IPAMAddResult, err error)
}
func NewMockIpamInvoker(ipv6, v4Fail, v6Fail, delegatedVMNIC, delegatedVMNICFail bool) *MockIpamInvoker {
@ -47,8 +47,11 @@ func NewMockIpamInvoker(ipv6, v4Fail, v6Fail, delegatedVMNIC, delegatedVMNICFail
func NewCustomMockIpamInvoker(customReturn map[string]network.InterfaceInfo) *MockIpamInvoker {
return &MockIpamInvoker{
customReturn: customReturn,
add: func(_ IPAMAddConfig) (ipamAddResult IPAMAddResult, err error) {
ipamAddResult = IPAMAddResult{interfaceInfo: make(map[string]network.InterfaceInfo)}
ipamAddResult.interfaceInfo = customReturn
return ipamAddResult, nil
},
ipMap: make(map[string]bool),
}
}
@ -112,9 +115,8 @@ func (invoker *MockIpamInvoker) Add(opt IPAMAddConfig) (ipamAddResult IPAMAddRes
}
}
if invoker.customReturn != nil {
ipamAddResult.interfaceInfo = invoker.customReturn
return ipamAddResult, nil
if invoker.add != nil {
return invoker.add(opt)
}
return ipamAddResult, nil

Просмотреть файл

@ -46,6 +46,7 @@ func setNetworkOptions(cnsNwConfig *cns.GetNetworkContainerResponse, nwInfo *net
}
}
// update epInfo data field, allow host to nc, allow nc to host, and network container id
func setEndpointOptions(cnsNwConfig *cns.GetNetworkContainerResponse, epInfo *network.EndpointInfo, vethName string) {
if cnsNwConfig != nil && cnsNwConfig.MultiTenancyInfo.ID != 0 {
logger.Info("Setting Endpoint Options")

Просмотреть файл

@ -4,10 +4,18 @@
package network
import (
"fmt"
"net"
"regexp"
"testing"
"github.com/Azure/azure-container-networking/cni"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/network"
"github.com/Azure/azure-container-networking/platform"
"github.com/Azure/azure-container-networking/telemetry"
cniSkel "github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -160,3 +168,387 @@ func TestAddSnatForDns(t *testing.T) {
})
}
}
// linux swiftv2 example
func GetTestCNSResponseSecondaryLinux(macAddress string) map[string]network.InterfaceInfo {
parsedMAC, _ := net.ParseMAC(macAddress)
return map[string]network.InterfaceInfo{
string(cns.InfraNIC): {
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("20.241.0.35/16"),
Gateway: net.ParseIP("20.241.0.35"), // actual scenario doesn't have a gateway
},
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/16"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/32"),
Gw: net.ParseIP("169.254.2.1"),
},
},
NICType: cns.InfraNIC,
SkipDefaultRoutes: true,
HostSubnetPrefix: *getCIDRNotationForAddress("10.224.0.0/16"),
},
macAddress: {
MacAddress: parsedMAC,
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("10.241.0.35/32"),
Gateway: net.ParseIP("10.241.0.35"), // actual scenario doesn't have a gateway
},
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/32"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/0"),
Gw: net.ParseIP("169.254.2.1"),
},
},
NICType: cns.NodeNetworkInterfaceFrontendNIC,
SkipDefaultRoutes: false,
},
}
}
// Happy path scenario for add and delete
func TestPluginLinuxAdd(t *testing.T) {
resources := GetTestResources()
mulNwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "mulnet",
MultiTenancy: true,
EnableExactMatchForPodName: true,
Master: "eth0",
}
nwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "net",
MultiTenancy: false,
EnableExactMatchForPodName: true,
// test auto finding master interface
DNS: types.DNS{
Nameservers: []string{
"ns1", "ns2",
},
Domain: "myDomain",
},
}
macAddress := "60:45:bd76:f6:44"
parsedMACAddress, _ := net.ParseMAC(macAddress)
type endpointEntry struct {
epInfo *network.EndpointInfo
epIDRegex string
}
tests := []struct {
name string
plugin *NetPlugin
args *cniSkel.CmdArgs
want []endpointEntry
match func(*network.EndpointInfo, *network.EndpointInfo) bool
}{
{
// in swiftv1 linux multitenancy, we only get 1 response from cns at a time
name: "Add Happy Path Swiftv1 Multitenancy",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
multitenancyClient: NewMockMultitenancy(false, []*cns.GetNetworkContainerResponse{GetTestCNSResponse3()}),
},
args: &cniSkel.CmdArgs{
StdinData: mulNwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NetworkContainerID == ei2.NetworkContainerID
},
want: []endpointEntry{
// should match with GetTestCNSResponse3
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"VlanID": 1, // Vlan ID used here
"localIP": "168.254.0.4/17",
"snatBridgeIP": "168.254.0.1/17",
"vethname": "mulnettest-containereth0",
},
Routes: []network.RouteInfo{
{
Dst: *parseCIDR("192.168.0.4/24"),
Gw: net.ParseIP("192.168.0.1"),
// interface to use is NOT propagated to ep info
},
},
AllowInboundFromHostToNC: true,
EnableSnatOnHost: true,
EnableMultiTenancy: true,
EnableSnatForDns: true,
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
MasterIfName: eth0IfName,
NetworkContainerID: "Swift_74b34111-6e92-49ee-a82a-8881c850ce0e",
NetworkID: "mulnet",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "20.240.0.0/24",
Options: map[string]interface{}{
dockerNetworkOption: map[string]interface{}{
"VlanID": "1", // doesn't seem to be used in linux
"snatBridgeIP": "168.254.0.1/17",
},
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("20.0.0.10"),
Mask: getIPNetWithString("20.0.0.10/24").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
// matches cns ip configuration (20.0.0.1/24 == 20.0.0.0/24)
Prefix: *getIPNetWithString("20.0.0.0/24"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("20.0.0.1"),
},
},
},
epIDRegex: `test-con-eth0`,
},
},
},
{
// Based on a live swiftv2 linux cluster's cns invoker response
name: "Add Happy Path Swiftv2",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
ipamInvoker: &MockIpamInvoker{
add: func(opt IPAMAddConfig) (ipamAddResult IPAMAddResult, err error) {
ipamAddResult = IPAMAddResult{interfaceInfo: make(map[string]network.InterfaceInfo)}
ipamAddResult.interfaceInfo = GetTestCNSResponseSecondaryLinux(macAddress)
opt.options["testflag"] = "copy"
return ipamAddResult, nil
},
ipMap: make(map[string]bool),
},
netClient: &InterfaceGetterMock{
// used in secondary find master interface
interfaces: []net.Interface{
{
Name: "secondary",
HardwareAddr: parsedMACAddress,
},
{
Name: "primary",
HardwareAddr: net.HardwareAddr{},
},
},
// used in primary find master interface
interfaceAddrs: map[string][]net.Addr{
"primary": {
// match with the host subnet prefix to know that this ip belongs to the host
getCIDRNotationForAddress("10.224.0.0/16"),
},
},
},
},
args: &cniSkel.CmdArgs{
StdinData: nwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NICType == ei2.NICType
},
want: []endpointEntry{
// should match infra
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"vethname": "nettest-containereth0",
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/16"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/32"),
Gw: net.ParseIP("169.254.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
SkipDefaultRoutes: true,
MasterIfName: "primary",
NetworkID: "net",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "10.224.0.0/16",
EndpointDNS: network.DNSInfo{
Servers: []string{
"ns1", "ns2",
},
Suffix: "myDomain",
},
Options: map[string]interface{}{
"testflag": "copy",
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("20.241.0.35"),
Mask: getIPNetWithString("20.241.0.35/16").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
// matches cns ip configuration (20.241.0.0/16 == 20.241.0.35/16)
Prefix: *getIPNetWithString("20.241.0.0/16"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("20.241.0.35"),
},
},
},
epIDRegex: `.*`,
},
// should match secondary
{
epInfo: &network.EndpointInfo{
MacAddress: parsedMACAddress,
ContainerID: "test-container",
Data: map[string]interface{}{
"vethname": "nettest-containereth0",
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("169.254.2.1/32"),
Gw: net.ParseIP("10.244.2.1"),
},
{
Dst: *getCIDRNotationForAddress("0.0.0.0/0"),
Gw: net.ParseIP("169.254.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
SkipDefaultRoutes: false,
MasterIfName: "secondary",
NetworkID: "net",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "<nil>",
EndpointDNS: network.DNSInfo{
Servers: []string{
"ns1", "ns2",
},
Suffix: "myDomain",
},
Options: map[string]interface{}{
"testflag": "copy",
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.241.0.35"),
Mask: getIPNetWithString("10.241.0.35/32").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.241.0.35/32"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("10.241.0.35"),
},
},
},
epIDRegex: `.*`,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
err := tt.plugin.Add(tt.args)
require.NoError(t, err)
allEndpoints, _ := tt.plugin.nm.GetAllEndpoints("")
require.Len(t, allEndpoints, len(tt.want))
// compare contents
for _, wantedEndpointEntry := range tt.want {
epID := "none"
for _, endpointInfo := range allEndpoints {
if !tt.match(wantedEndpointEntry.epInfo, endpointInfo) {
continue
}
// save the endpoint id before removing it
epID = endpointInfo.EndpointID
require.Regexp(t, regexp.MustCompile(wantedEndpointEntry.epIDRegex), epID)
// omit endpoint id and ifname fields as they are nondeterministic
endpointInfo.EndpointID = ""
endpointInfo.IfName = ""
require.Equal(t, wantedEndpointEntry.epInfo, endpointInfo)
}
if epID == "none" {
t.Fail()
}
err = tt.plugin.nm.DeleteEndpoint("", epID, nil)
require.NoError(t, err)
}
// confirm separate entities
// that is, if one is modified, the other should not be modified
epInfos := []*network.EndpointInfo{}
for _, val := range allEndpoints {
epInfos = append(epInfos, val)
}
if len(epInfos) > 1 {
epInfo1 := epInfos[0]
epInfo2 := epInfos[1]
epInfo1.Data["dummy"] = "dummy value"
epInfo1.Options["dummy"] = "another dummy value"
require.NotEqual(t, epInfo1.Data, epInfo2.Data)
require.NotEqual(t, epInfo1.Options, epInfo2.Options)
}
// ensure deleted
require.Empty(t, allEndpoints)
})
}
}

Просмотреть файл

@ -688,6 +688,44 @@ func GetTestCNSResponse2() *cns.GetNetworkContainerResponse {
}
}
// For use with GetAllNetworkContainers in linux multitenancy
func GetTestCNSResponse3() *cns.GetNetworkContainerResponse {
return &cns.GetNetworkContainerResponse{
NetworkContainerID: "Swift_74b34111-6e92-49ee-a82a-8881c850ce0e",
IPConfiguration: cns.IPConfiguration{
IPSubnet: cns.IPSubnet{
IPAddress: "20.0.0.10",
PrefixLength: ipPrefixLen,
},
DNSServers: []string{
"168.63.129.16",
},
GatewayIPAddress: "20.0.0.1",
},
Routes: []cns.Route{
// dummy route
{
IPAddress: "192.168.0.4/24",
GatewayIPAddress: "192.168.0.1",
},
},
MultiTenancyInfo: cns.MultiTenancyInfo{
EncapType: cns.Vlan,
ID: multiTenancyVlan1,
},
PrimaryInterfaceIdentifier: "20.240.0.4/24",
LocalIPConfiguration: cns.IPConfiguration{
IPSubnet: cns.IPSubnet{
IPAddress: "168.254.0.4",
PrefixLength: localIPPrefixLen,
},
GatewayIPAddress: "168.254.0.1",
},
AllowHostToNCCommunication: true,
AllowNCToHostCommunication: false,
}
}
// Test Multitenancy Add
func TestPluginMultitenancyAdd(t *testing.T) {
plugin, _ := cni.NewPlugin("test", "0.3.0")

Просмотреть файл

@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"net"
"regexp"
"testing"
"github.com/Azure/azure-container-networking/cni"
@ -14,6 +15,7 @@ import (
"github.com/Azure/azure-container-networking/network"
"github.com/Azure/azure-container-networking/network/hnswrapper"
"github.com/Azure/azure-container-networking/network/policy"
"github.com/Azure/azure-container-networking/platform"
"github.com/Azure/azure-container-networking/telemetry"
hnsv2 "github.com/Microsoft/hcsshim/hcn"
cniSkel "github.com/containernetworking/cni/pkg/skel"
@ -855,3 +857,362 @@ func TestPluginMultitenancyWindowsDelete(t *testing.T) {
})
}
}
// windows swiftv2 example
func GetTestCNSResponseSecondaryWindows(macAddress string) map[string]network.InterfaceInfo {
parsedMAC, _ := net.ParseMAC(macAddress)
return map[string]network.InterfaceInfo{
string(cns.InfraNIC): {
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("10.244.2.107/16"),
Gateway: net.ParseIP("10.244.2.1"),
},
},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("1.1.1.1/24"),
Gw: net.ParseIP("10.244.2.1"),
},
},
SkipDefaultRoutes: true,
NICType: cns.InfraNIC,
HostSubnetPrefix: *getCIDRNotationForAddress("20.224.0.0/16"),
},
macAddress: {
MacAddress: parsedMAC,
IPConfigs: []*network.IPConfig{
{
Address: *getCIDRNotationForAddress("10.241.0.21/16"),
Gateway: net.ParseIP("10.241.0.1"),
},
},
Routes: []network.RouteInfo{
{
// just to ensure we don't overwrite if we had more routes
Dst: *getCIDRNotationForAddress("2.2.2.2/24"),
Gw: net.ParseIP("99.244.2.1"),
},
},
NICType: cns.NodeNetworkInterfaceFrontendNIC,
},
}
}
// Happy path scenario for add and delete
func TestPluginWindowsAdd(t *testing.T) {
resources := GetTestResources()
localNwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "mulnet",
MultiTenancy: true,
EnableExactMatchForPodName: true,
Master: "eth0",
}
nwCfg := cni.NetworkConfig{
CNIVersion: "0.3.0",
Name: "net",
MultiTenancy: false,
EnableExactMatchForPodName: true,
}
macAddress := "60:45:bd:76:f6:44"
parsedMACAddress, _ := net.ParseMAC(macAddress)
type endpointEntry struct {
epInfo *network.EndpointInfo
epIDRegex string
}
tests := []struct {
name string
plugin *NetPlugin
args *cniSkel.CmdArgs
want []endpointEntry
match func(*network.EndpointInfo, *network.EndpointInfo) bool
}{
{
name: "Add Happy Path Dual NIC",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
multitenancyClient: NewMockMultitenancy(false, []*cns.GetNetworkContainerResponse{GetTestCNSResponse1(), GetTestCNSResponse2()}),
},
args: &cniSkel.CmdArgs{
StdinData: localNwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NetworkID == ei2.NetworkID
},
want: []endpointEntry{
// should match with GetTestCNSResponse1
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"cnetAddressSpace": []string(nil),
},
Routes: []network.RouteInfo{},
EnableSnatOnHost: true,
EnableMultiTenancy: true,
EnableSnatForDns: true,
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
MasterIfName: eth0IfName,
NetworkID: "mulnet-vlan1-20-0-0-0_24",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "20.240.0.0/24",
Options: map[string]interface{}{
dockerNetworkOption: map[string]interface{}{
"VlanID": "1",
},
},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("20.0.0.10"),
Mask: getIPNetWithString("20.0.0.10/24").Mask,
},
},
// LocalIPConfiguration doesn't seem used in windows
// Constant, in windows, NAT Info comes from
// options > ipamAddConfig >
// cns invoker may populate network.SNATIPKey with the default response received >
// getNATInfo (with nwCfg) > adds nat info based on condition
// typically adds azure dns (168.63.129.16)
NATInfo: []policy.NATInfo{
{
Destinations: []string{"168.63.129.16"},
},
},
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
// matches cns ip configuration (20.0.0.1/24 == 20.0.0.0/24)
Prefix: *getIPNetWithString("20.0.0.0/24"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("20.0.0.1"),
},
},
},
epIDRegex: `.*`,
},
// should match with GetTestCNSResponse2
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{
"cnetAddressSpace": []string(nil),
},
Routes: []network.RouteInfo{},
EnableSnatOnHost: true,
EnableMultiTenancy: true,
EnableSnatForDns: true,
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
MasterIfName: eth0IfName,
NetworkID: "mulnet-vlan2-10-0-0-0_24",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "10.240.0.0/24",
Options: map[string]interface{}{
dockerNetworkOption: map[string]interface{}{
"VlanID": "2",
},
},
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.0.0.10"),
Mask: getIPNetWithString("10.0.0.10/24").Mask,
},
},
NATInfo: []policy.NATInfo{
{
Destinations: []string{"168.63.129.16"},
},
},
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.0.0.0/24"),
Gateway: net.ParseIP("10.0.0.1"),
},
},
},
epIDRegex: `.*`,
},
},
},
{
// Based on a live swiftv2 windows cluster's (infra + delegated) cns invoker response
name: "Add Happy Path Swiftv2",
plugin: &NetPlugin{
Plugin: resources.Plugin,
nm: network.NewMockNetworkmanager(network.NewMockEndpointClient(nil)),
tb: &telemetry.TelemetryBuffer{},
report: &telemetry.CNIReport{},
ipamInvoker: NewCustomMockIpamInvoker(GetTestCNSResponseSecondaryWindows(macAddress)),
netClient: &InterfaceGetterMock{
// used in secondary find master interface
interfaces: []net.Interface{
{
Name: "secondary",
HardwareAddr: parsedMACAddress,
},
{
Name: "primary",
HardwareAddr: net.HardwareAddr{},
},
},
// used in primary find master interface
interfaceAddrs: map[string][]net.Addr{
"primary": {
// match with the host subnet prefix to know that this ip belongs to the host
getCIDRNotationForAddress("20.224.0.0/16"),
},
},
},
},
args: &cniSkel.CmdArgs{
StdinData: nwCfg.Serialize(),
ContainerID: "test-container",
Netns: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
Args: fmt.Sprintf("K8S_POD_NAME=%v;K8S_POD_NAMESPACE=%v", "test-pod", "test-pod-ns"),
IfName: eth0IfName,
},
match: func(ei1, ei2 *network.EndpointInfo) bool {
return ei1.NICType == ei2.NICType
},
want: []endpointEntry{
// should match infra
{
epInfo: &network.EndpointInfo{
ContainerID: "test-container",
Data: map[string]interface{}{},
Routes: []network.RouteInfo{
{
Dst: *getCIDRNotationForAddress("1.1.1.1/24"),
Gw: net.ParseIP("10.244.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.InfraNIC,
SkipDefaultRoutes: true,
MasterIfName: "primary",
NetworkID: "net",
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "20.224.0.0/16",
Options: map[string]interface{}{},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.244.2.107"),
Mask: getIPNetWithString("10.244.2.107/16").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.244.0.0/16"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("10.244.2.1"),
},
},
},
epIDRegex: `.*`,
},
// should match secondary
{
epInfo: &network.EndpointInfo{
MacAddress: parsedMACAddress,
ContainerID: "test-container",
Data: map[string]interface{}{},
Routes: []network.RouteInfo{
{
// just to ensure we don't overwrite if we had more routes
Dst: *getCIDRNotationForAddress("2.2.2.2/24"),
Gw: net.ParseIP("99.244.2.1"),
},
},
PODName: "test-pod",
PODNameSpace: "test-pod-ns",
NICType: cns.NodeNetworkInterfaceFrontendNIC,
SkipDefaultRoutes: false,
MasterIfName: "secondary",
NetworkID: "azure-" + macAddress,
NetNsPath: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
NetNs: "bc526fae-4ba0-4e80-bc90-ad721e5850bf",
HostSubnetPrefix: "<nil>",
Options: map[string]interface{}{},
// matches with cns ip configuration
IPAddresses: []net.IPNet{
{
IP: net.ParseIP("10.241.0.21"),
Mask: getIPNetWithString("10.241.0.21/16").Mask,
},
},
NATInfo: nil,
// ip config pod ip + mask(s) from cns > interface info > subnet info
Subnets: []network.SubnetInfo{
{
Family: platform.AfINET,
Prefix: *getIPNetWithString("10.241.0.21/16"),
// matches cns ip configuration gateway ip address
Gateway: net.ParseIP("10.241.0.1"),
},
},
},
epIDRegex: `.*`,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
err := tt.plugin.Add(tt.args)
require.NoError(t, err)
allEndpoints, _ := tt.plugin.nm.GetAllEndpoints("")
require.Len(t, allEndpoints, len(tt.want))
for _, wantedEndpointEntry := range tt.want {
epID := "none"
for _, endpointInfo := range allEndpoints {
if !tt.match(wantedEndpointEntry.epInfo, endpointInfo) {
continue
}
// save the endpoint id before removing it
epID = endpointInfo.EndpointID
require.Regexp(t, regexp.MustCompile(wantedEndpointEntry.epIDRegex), epID)
// omit endpoint id and ifname fields as they are nondeterministic
endpointInfo.EndpointID = ""
endpointInfo.IfName = ""
require.Equal(t, wantedEndpointEntry.epInfo, endpointInfo)
}
if epID == "none" {
t.Fail()
}
err = tt.plugin.nm.DeleteEndpoint("", epID, nil)
require.NoError(t, err)
}
// ensure deleted
require.Empty(t, allEndpoints)
})
}
}

Просмотреть файл

@ -167,8 +167,8 @@ func main() {
GetEnvRetryWaitTimeInSecs: config.GetEnvRetryWaitTimeInSecs,
}
if tb.CreateAITelemetryHandle(aiConfig, config.DisableAll, config.DisableTrace, config.DisableMetric) != nil {
logger.Error("AI Handle creation error", zap.Error(err))
if err := tb.CreateAITelemetryHandle(aiConfig, config.DisableAll, config.DisableTrace, config.DisableMetric); err != nil { // nolint
logger.Error("AI Handle creation error:", zap.Error(err))
}
logger.Info("Report to host interval", zap.Duration("seconds", config.ReportToHostIntervalInSeconds))
tb.PushData(context.Background())

Просмотреть файл

@ -99,10 +99,13 @@ const (
Managed = "Managed"
CRD = "CRD"
MultiTenantCRD = "MultiTenantCRD"
AzureHost = "AzureHost"
)
var ErrInvalidNCID = errors.New("invalid NetworkContainerID")
var ErrInvalidIP = errors.New("invalid IP")
var (
ErrInvalidNCID = errors.New("invalid NetworkContainerID")
ErrInvalidIP = errors.New("invalid IP")
)
// CreateNetworkContainerRequest specifies request to create a network container or network isolation boundary.
type CreateNetworkContainerRequest struct {

Просмотреть файл

@ -14,9 +14,10 @@ import (
// NMAgentClientFake can be used to query to VM Host info.
type NMAgentClientFake struct {
SupportedAPIsF func(context.Context) ([]string, error)
GetNCVersionListF func(context.Context) (nmagent.NCVersionList, error)
GetHomeAzF func(context.Context) (nmagent.AzResponse, error)
SupportedAPIsF func(context.Context) ([]string, error)
GetNCVersionListF func(context.Context) (nmagent.NCVersionList, error)
GetHomeAzF func(context.Context) (nmagent.AzResponse, error)
GetInterfaceIPInfoF func(ctx context.Context) (nmagent.Interfaces, error)
}
func (n *NMAgentClientFake) SupportedAPIs(ctx context.Context) ([]string, error) {
@ -30,3 +31,7 @@ func (n *NMAgentClientFake) GetNCVersionList(ctx context.Context) (nmagent.NCVer
func (n *NMAgentClientFake) GetHomeAz(ctx context.Context) (nmagent.AzResponse, error) {
return n.GetHomeAzF(ctx)
}
func (n *NMAgentClientFake) GetInterfaceIPInfo(ctx context.Context) (nmagent.Interfaces, error) {
return n.GetInterfaceIPInfoF(ctx)
}

Просмотреть файл

@ -17,6 +17,7 @@ import (
"github.com/pkg/errors"
)
// TODO redesign hnsclient on windows
const (
// Name of the external hns network
ExtHnsNetworkName = "ext"
@ -53,6 +54,9 @@ const (
// Name of the loopback adapter needed to create Host NC apipa network
hostNCLoopbackAdapterName = "LoopbackAdapterHostNCConnectivity"
// HNS rehydration issue requires this GW to be different than the loopback adapter ip, so we set it to .2
defaultHnsGwIPAddress = "169.254.128.2"
hnsLoopbackAdapterIPAddress = "169.254.128.1"
// protocolTCP indicates the TCP protocol identifier in HCN
protocolTCP = "6"
@ -301,7 +305,7 @@ func createHostNCApipaNetwork(
if interfaceExists, _ := networkcontainers.InterfaceExists(hostNCLoopbackAdapterName); !interfaceExists {
ipconfig := cns.IPConfiguration{
IPSubnet: cns.IPSubnet{
IPAddress: localIPConfiguration.GatewayIPAddress,
IPAddress: hnsLoopbackAdapterIPAddress,
PrefixLength: localIPConfiguration.IPSubnet.PrefixLength,
},
GatewayIPAddress: localIPConfiguration.GatewayIPAddress,
@ -510,7 +514,7 @@ func configureHostNCApipaEndpoint(
endpointPolicies, err := configureAclSettingHostNCApipaEndpoint(
protocolList,
networkContainerApipaIP,
hostApipaIP,
hnsLoopbackAdapterIPAddress,
allowNCToHostCommunication,
allowHostToNCCommunication,
ncPolicies)
@ -573,6 +577,7 @@ func CreateHostNCApipaEndpoint(
return endpoint.Id, nil
}
updateGwForLocalIPConfiguration(&localIPConfiguration)
if network, err = createHostNCApipaNetwork(localIPConfiguration); err != nil {
logger.Errorf("[Azure CNS] Failed to create HostNCApipaNetwork. Error: %v", err)
return "", err
@ -604,6 +609,17 @@ func CreateHostNCApipaEndpoint(
return endpoint.Id, nil
}
// updateGwForLocalIPConfiguration applies change on gw IP address for apipa NW and endpoint.
// Currently, cns using the same ip address "169.254.128.1" for both apipa gw and loopback adapter. This cause conflict issue when hns get restarted and not able to rehydrate the apipa endpoints.
// This func is to overwrite the address to 169.254.128.2 when the gateway address is 169.254.128.1
func updateGwForLocalIPConfiguration(localIPConfiguration *cns.IPConfiguration) {
// When gw address is 169.254.128.1, should use .2 instead. If gw address is not .1, that mean this value is
// configured from dnc, we should keep it
if localIPConfiguration.GatewayIPAddress == "169.254.128.1" {
localIPConfiguration.GatewayIPAddress = defaultHnsGwIPAddress
}
}
func getHostNCApipaEndpointName(
networkContainerID string) string {
return hostNCApipaEndpointNamePrefix + "-" + networkContainerID

Просмотреть файл

@ -0,0 +1,35 @@
package hnsclient
import (
"testing"
"github.com/Azure/azure-container-networking/cns"
"github.com/stretchr/testify/assert"
)
func TestAdhocAdjustIPConfig(t *testing.T) {
tests := []struct {
name string
ipConfig cns.IPConfiguration
expected cns.IPConfiguration
}{
{
name: "expect no change when gw address is not 169.254.128.1",
ipConfig: cns.IPConfiguration{GatewayIPAddress: "169.254.128.3"},
expected: cns.IPConfiguration{GatewayIPAddress: "169.254.128.3"},
},
{
name: "expect default gw address is set when gw address is 169.254.128.1",
ipConfig: cns.IPConfiguration{GatewayIPAddress: "169.254.128.1"},
expected: cns.IPConfiguration{GatewayIPAddress: "169.254.128.2"},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
updateGwForLocalIPConfiguration(&tt.ipConfig)
assert.Equal(t, tt.expected.GatewayIPAddress, tt.ipConfig.GatewayIPAddress)
})
}
}

Просмотреть файл

@ -0,0 +1,36 @@
package nodesubnet
import (
"context"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
cnstypes "github.com/Azure/azure-container-networking/cns/types"
"github.com/pkg/errors"
"golang.org/x/exp/maps"
)
type ipamReconciler interface {
ReconcileIPAMStateForNodeSubnet(ncRequests []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo) cnstypes.ResponseCode
}
func ReconcileInitialCNSState(_ context.Context, ipamReconciler ipamReconciler, podInfoByIPProvider cns.PodInfoByIPProvider) (int, error) {
// Get previous PodInfo state from podInfoByIPProvider
podInfoByIP, err := podInfoByIPProvider.PodInfoByIP()
if err != nil {
return 0, errors.Wrap(err, "provider failed to provide PodInfoByIP")
}
logger.Printf("Reconciling initial CNS state with %d IPs", len(podInfoByIP))
// Create a network container request that holds all the IPs from PodInfoByIP
secondaryIPs := maps.Keys(podInfoByIP)
ncRequest := CreateNodeSubnetNCRequest(secondaryIPs)
responseCode := ipamReconciler.ReconcileIPAMStateForNodeSubnet([]*cns.CreateNetworkContainerRequest{ncRequest}, podInfoByIP)
if responseCode != cnstypes.Success {
return 0, errors.Errorf("failed to reconcile initial CNS state: %d", responseCode)
}
return len(secondaryIPs), nil
}

Просмотреть файл

@ -0,0 +1,114 @@
package nodesubnet_test
import (
"context"
"net"
"testing"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/cnireconciler"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/nodesubnet"
"github.com/Azure/azure-container-networking/cns/restserver"
"github.com/Azure/azure-container-networking/cns/types"
"github.com/Azure/azure-container-networking/store"
)
func getMockStore() store.KeyValueStore {
mockStore := store.NewMockStore("")
endpointState := map[string]*restserver.EndpointInfo{
"12e65d89e58cb23c784e97840cf76866bfc9902089bdc8e87e9f64032e312b0b": {
PodName: "coredns-54b69f46b8-ldmwr",
PodNamespace: "kube-system",
IfnameToIPMap: map[string]*restserver.IPInfo{
"eth0": {
IPv4: []net.IPNet{
{
IP: net.IPv4(10, 10, 0, 52),
Mask: net.CIDRMask(24, 32),
},
},
},
},
},
"1fc5176913a3a1a7facfb823dde3b4ded404041134fef4f4a0c8bba140fc0413": {
PodName: "load-test-7f7d49687d-wxc9p",
PodNamespace: "load-test",
IfnameToIPMap: map[string]*restserver.IPInfo{
"eth0": {
IPv4: []net.IPNet{
{
IP: net.IPv4(10, 10, 0, 63),
Mask: net.CIDRMask(24, 32),
},
},
},
},
},
}
err := mockStore.Write(restserver.EndpointStoreKey, endpointState)
if err != nil {
return nil
}
return mockStore
}
type MockIpamStateReconciler struct{}
func (m *MockIpamStateReconciler) ReconcileIPAMStateForNodeSubnet(ncRequests []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo) types.ResponseCode {
if len(ncRequests) == 1 && len(ncRequests[0].SecondaryIPConfigs) == len(podInfoByIP) {
return types.Success
}
return types.UnexpectedError
}
func TestNewCNSPodInfoProvider(t *testing.T) {
tests := []struct {
name string
store store.KeyValueStore
wantErr bool
reconciler *MockIpamStateReconciler
exp int
}{
{
name: "happy_path",
store: getMockStore(),
wantErr: false,
reconciler: &MockIpamStateReconciler{},
exp: 2,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
ctx, cancel := testContext(t)
defer cancel()
podInfoByIPProvider, err := cnireconciler.NewCNSPodInfoProvider(tt.store)
checkErr(t, err, false)
got, err := nodesubnet.ReconcileInitialCNSState(ctx, tt.reconciler, podInfoByIPProvider)
checkErr(t, err, tt.wantErr)
if got != tt.exp {
t.Errorf("got %d IPs reconciled, expected %d", got, tt.exp)
}
})
}
}
// testContext creates a context from the provided testing.T that will be
// canceled if the test suite is terminated.
func testContext(t *testing.T) (context.Context, context.CancelFunc) {
if deadline, ok := t.Deadline(); ok {
return context.WithDeadline(context.Background(), deadline)
}
return context.WithCancel(context.Background())
}
func init() {
logger.InitLogger("testlogs", 0, 0, "./")
}

Просмотреть файл

@ -0,0 +1,40 @@
package nodesubnet
import (
"strconv"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/crd/nodenetworkconfig/api/v1alpha"
)
const (
// ID for fake NC that we create to store NodeSubnet IPS
NodeSubnetNCID = "55022629-3854-499b-7133-5e6887959f4ea" // md5sum of "NodeSubnetNC_IPv4"
NodeSubnetNCVersion = 0
NodeSubnetHostVersion = "0"
NodeSubnetNCStatus = v1alpha.NCUpdateSuccess
NodeSubnetHostPrimaryIP = ""
)
// CreateNodeSubnetNCRequest generates a CreateNetworkContainerRequest that simply stores the static secondary IPs.
func CreateNodeSubnetNCRequest(secondaryIPs []string) *cns.CreateNetworkContainerRequest {
secondaryIPConfigs := map[string]cns.SecondaryIPConfig{}
for _, secondaryIP := range secondaryIPs {
// iterate through all secondary IP addresses add them to the request as secondary IPConfigs.
secondaryIPConfigs[secondaryIP] = cns.SecondaryIPConfig{
IPAddress: secondaryIP,
NCVersion: NodeSubnetNCVersion,
}
}
return &cns.CreateNetworkContainerRequest{
HostPrimaryIP: NodeSubnetHostPrimaryIP,
SecondaryIPConfigs: secondaryIPConfigs,
NetworkContainerid: NodeSubnetNCID,
NetworkContainerType: cns.Docker, // Using docker as the NC type for NodeSubnet to match Swift. (The NC is not real)
Version: strconv.FormatInt(NodeSubnetNCVersion, 10), //nolint:gomnd // it's decimal
IPConfiguration: cns.IPConfiguration{},
NCStatus: NodeSubnetNCStatus,
}
}

Просмотреть файл

@ -0,0 +1,54 @@
package nodesubnet_test
import (
"testing"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/nodesubnet"
"github.com/Azure/azure-container-networking/crd/nodenetworkconfig/api/v1alpha"
"github.com/google/go-cmp/cmp"
)
func TestCreateNodeSubnetNCRequest_EmptySecondaryIPs(t *testing.T) {
secondaryIPs := []string{}
expectedRequest := &cns.CreateNetworkContainerRequest{
HostPrimaryIP: nodesubnet.NodeSubnetHostPrimaryIP,
SecondaryIPConfigs: map[string]cns.SecondaryIPConfig{},
NetworkContainerid: nodesubnet.NodeSubnetNCID,
NetworkContainerType: cns.Docker,
Version: "0",
IPConfiguration: cns.IPConfiguration{},
NCStatus: v1alpha.NCUpdateSuccess,
}
request := nodesubnet.CreateNodeSubnetNCRequest(secondaryIPs)
if !cmp.Equal(request, expectedRequest) {
t.Errorf("Unexepected diff in NodeSubnetNCRequest: %v", cmp.Diff(request, expectedRequest))
}
}
func TestCreateNodeSubnetNCRequest_NonEmptySecondaryIPs(t *testing.T) {
secondaryIPs := []string{"10.0.0.1", "10.0.0.2"}
expectedRequest := &cns.CreateNetworkContainerRequest{
HostPrimaryIP: nodesubnet.NodeSubnetHostPrimaryIP,
SecondaryIPConfigs: map[string]cns.SecondaryIPConfig{
"10.0.0.1": {IPAddress: "10.0.0.1", NCVersion: nodesubnet.NodeSubnetNCVersion},
"10.0.0.2": {IPAddress: "10.0.0.2", NCVersion: nodesubnet.NodeSubnetNCVersion},
},
NetworkContainerid: nodesubnet.NodeSubnetNCID,
NetworkContainerType: cns.Docker,
Version: "0",
IPConfiguration: cns.IPConfiguration{},
NCStatus: v1alpha.NCUpdateSuccess,
}
request := nodesubnet.CreateNodeSubnetNCRequest(secondaryIPs)
if !cmp.Equal(request, expectedRequest) {
t.Errorf("Unexepected diff in NodeSubnetNCRequest: %v", cmp.Diff(request, expectedRequest))
}
}
func init() {
logger.InitLogger("testlogs", 0, 0, "./")
}

Просмотреть файл

@ -0,0 +1,89 @@
package restserver
import (
"context"
"net/netip"
"testing"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/common"
"github.com/Azure/azure-container-networking/cns/fakes"
"github.com/Azure/azure-container-networking/cns/nodesubnet"
acn "github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/nmagent"
"github.com/Azure/azure-container-networking/store"
)
// GetRestServiceObjectForNodeSubnetTest creates a new HTTPRestService object for use in nodesubnet unit tests.
func GetRestServiceObjectForNodeSubnetTest(t *testing.T, generator CNIConflistGenerator) *HTTPRestService {
config := &common.ServiceConfig{
Name: "test",
Version: "1.0",
ChannelMode: "AzureHost",
Store: store.NewMockStore("test"),
}
interfaces := nmagent.Interfaces{
Entries: []nmagent.Interface{
{
MacAddress: nmagent.MACAddress{0x00, 0x0D, 0x3A, 0xF9, 0xDC, 0xA6},
IsPrimary: true,
InterfaceSubnets: []nmagent.InterfaceSubnet{
{
Prefix: "10.0.0.0/24",
IPAddress: []nmagent.NodeIP{
{
Address: nmagent.IPAddress(netip.AddrFrom4([4]byte{10, 0, 0, 4})),
IsPrimary: true,
},
{
Address: nmagent.IPAddress(netip.AddrFrom4([4]byte{10, 0, 0, 52})),
IsPrimary: false,
},
{
Address: nmagent.IPAddress(netip.AddrFrom4([4]byte{10, 0, 0, 63})),
IsPrimary: false,
},
{
Address: nmagent.IPAddress(netip.AddrFrom4([4]byte{10, 0, 0, 45})),
IsPrimary: false,
},
},
},
},
},
},
}
svc, err := cns.NewService(config.Name, config.Version, config.ChannelMode, config.Store)
if err != nil {
return nil
}
svc.SetOption(acn.OptCnsURL, "")
svc.SetOption(acn.OptCnsPort, "")
err = svc.Initialize(config)
if err != nil {
return nil
}
t.Cleanup(func() { svc.Uninitialize() })
return &HTTPRestService{
Service: svc,
cniConflistGenerator: generator,
state: &httpRestServiceState{},
PodIPConfigState: make(map[string]cns.IPConfigurationStatus),
PodIPIDByPodInterfaceKey: make(map[string][]string),
nma: &fakes.NMAgentClientFake{
GetInterfaceIPInfoF: func(_ context.Context) (nmagent.Interfaces, error) {
return interfaces, nil
},
},
wscli: &fakes.WireserverClientFake{},
}
}
// GetNodesubnetIPFetcher gets the nodesubnetIPFetcher from the HTTPRestService.
func (service *HTTPRestService) GetNodesubnetIPFetcher() *nodesubnet.IPFetcher {
return service.nodesubnetIPFetcher
}

Просмотреть файл

@ -18,6 +18,7 @@ import (
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/nodesubnet"
"github.com/Azure/azure-container-networking/cns/types"
"github.com/Azure/azure-container-networking/common"
"github.com/Azure/azure-container-networking/crd/nodenetworkconfig/api/v1alpha"
@ -275,22 +276,7 @@ func (service *HTTPRestService) syncHostNCVersion(ctx context.Context, channelMo
return len(programmedNCs), nil
}
func (service *HTTPRestService) ReconcileIPAMState(ncReqs []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo, nnc *v1alpha.NodeNetworkConfig) types.ResponseCode {
logger.Printf("Reconciling CNS IPAM state with nc requests: [%+v], PodInfo [%+v], NNC: [%+v]", ncReqs, podInfoByIP, nnc)
// if no nc reqs, there is no CRD state yet
if len(ncReqs) == 0 {
logger.Printf("CNS starting with no NC state, podInfoMap count %d", len(podInfoByIP))
return types.Success
}
// first step in reconciliation is to create all the NCs in CNS, no IP assignment yet.
for _, ncReq := range ncReqs {
returnCode := service.CreateOrUpdateNetworkContainerInternal(ncReq)
if returnCode != types.Success {
return returnCode
}
}
func (service *HTTPRestService) ReconcileIPAssignment(podInfoByIP map[string]cns.PodInfo, ncReqs []*cns.CreateNetworkContainerRequest) types.ResponseCode {
// index all the secondary IP configs for all the nc reqs, for easier lookup later on.
allSecIPsIdx := make(map[string]*cns.CreateNetworkContainerRequest)
for i := range ncReqs {
@ -321,6 +307,7 @@ func (service *HTTPRestService) ReconcileIPAMState(ncReqs []*cns.CreateNetworkCo
// }
//
// such that we can iterate over pod interfaces, and assign all IPs for it at once.
podKeyToPodIPs, err := newPodKeyToPodIPsMap(podInfoByIP)
if err != nil {
logger.Errorf("could not transform pods indexed by IP address to pod IPs indexed by interface: %v", err)
@ -378,12 +365,69 @@ func (service *HTTPRestService) ReconcileIPAMState(ncReqs []*cns.CreateNetworkCo
}
}
return types.Success
}
func (service *HTTPRestService) CreateNCs(ncReqs []*cns.CreateNetworkContainerRequest) types.ResponseCode {
for _, ncReq := range ncReqs {
returnCode := service.CreateOrUpdateNetworkContainerInternal(ncReq)
if returnCode != types.Success {
return returnCode
}
}
return types.Success
}
func (service *HTTPRestService) ReconcileIPAMStateForSwift(ncReqs []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo, nnc *v1alpha.NodeNetworkConfig) types.ResponseCode {
logger.Printf("Reconciling CNS IPAM state with nc requests: [%+v], PodInfo [%+v], NNC: [%+v]", ncReqs, podInfoByIP, nnc)
// if no nc reqs, there is no CRD state yet
if len(ncReqs) == 0 {
logger.Printf("CNS starting with no NC state, podInfoMap count %d", len(podInfoByIP))
return types.Success
}
// first step in reconciliation is to create all the NCs in CNS, no IP assignment yet.
if returnCode := service.CreateNCs(ncReqs); returnCode != types.Success {
return returnCode
}
logger.Debugf("ncReqs created successfully, now save IPs")
// now reconcile IPAM state.
if returnCode := service.ReconcileIPAssignment(podInfoByIP, ncReqs); returnCode != types.Success {
return returnCode
}
if err := service.MarkExistingIPsAsPendingRelease(nnc.Spec.IPsNotInUse); err != nil {
logger.Errorf("[Azure CNS] Error. Failed to mark IPs as pending %v", nnc.Spec.IPsNotInUse)
return types.UnexpectedError
}
return 0
return types.Success
}
// todo: there is some redundancy between this funcation and ReconcileIPAMStateForNodeSubnet. The difference is that this one
// doesn't include the NNC parameter. We may want to unify the common parts.
func (service *HTTPRestService) ReconcileIPAMStateForNodeSubnet(ncReqs []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo) types.ResponseCode {
logger.Printf("Reconciling CNS IPAM state with nc requests: [%+v], PodInfo [%+v]", ncReqs, podInfoByIP)
if len(ncReqs) != 1 {
logger.Errorf("Nodesubnet should always have 1 NC to hold secondary IPs")
return types.NetworkContainerNotSpecified
}
// first step in reconciliation is to create all the NCs in CNS, no IP assignment yet.
if returnCode := service.CreateNCs(ncReqs); returnCode != types.Success {
return returnCode
}
logger.Debugf("ncReqs created successfully, now save IPs")
// now reconcile IPAM state.
if returnCode := service.ReconcileIPAssignment(podInfoByIP, ncReqs); returnCode != types.Success {
return returnCode
}
return types.Success
}
var (
@ -526,11 +570,19 @@ func (service *HTTPRestService) CreateOrUpdateNetworkContainerInternal(req *cns.
return types.UnsupportedOrchestratorType
}
// Validate PrimaryCA must never be empty
err := validateIPSubnet(req.IPConfiguration.IPSubnet)
if err != nil {
logger.Errorf("[Azure CNS] Error. PrimaryCA is invalid, NC Req: %v", req)
return types.InvalidPrimaryIPConfig
if req.NetworkContainerid == nodesubnet.NodeSubnetNCID {
// For NodeSubnet scenarios, Validate PrimaryCA must be empty
if req.IPConfiguration.IPSubnet.IPAddress != "" {
logger.Errorf("[Azure CNS] Error. PrimaryCA is invalid, NC Req: %v", req)
return types.InvalidPrimaryIPConfig
}
} else {
// For Swift scenarios, Validate PrimaryCA must never be empty
err := validateIPSubnet(req.IPConfiguration.IPSubnet)
if err != nil {
logger.Errorf("[Azure CNS] Error. PrimaryCA is invalid, NC Req: %v", req)
return types.InvalidPrimaryIPConfig
}
}
// Validate SecondaryIPConfig
@ -563,7 +615,7 @@ func (service *HTTPRestService) CreateOrUpdateNetworkContainerInternal(req *cns.
// If the NC was created successfully, log NC snapshot.
if returnCode == 0 {
logNCSnapshot(*req)
publishIPStateMetrics(service.buildIPState())
service.publishIPStateMetrics()
} else {
logger.Errorf(returnMessage)
}

Просмотреть файл

@ -93,7 +93,7 @@ func TestReconcileNCStatePrimaryIPChangeShouldFail(t *testing.T) {
}
// now try to reconcile the state where the NC primary IP has changed
resp := svc.ReconcileIPAMState(ncReqs, map[string]cns.PodInfo{}, &v1alpha.NodeNetworkConfig{})
resp := svc.ReconcileIPAMStateForSwift(ncReqs, map[string]cns.PodInfo{}, &v1alpha.NodeNetworkConfig{})
assert.Equal(t, types.PrimaryCANotSame, resp)
}
@ -140,7 +140,7 @@ func TestReconcileNCStateGatewayChange(t *testing.T) {
}
// now try to reconcile the state where the NC gateway has changed
resp := svc.ReconcileIPAMState(ncReqs, map[string]cns.PodInfo{}, &v1alpha.NodeNetworkConfig{})
resp := svc.ReconcileIPAMStateForSwift(ncReqs, map[string]cns.PodInfo{}, &v1alpha.NodeNetworkConfig{})
assert.Equal(t, types.Success, resp)
// assert the new state reflects the gateway update
@ -337,7 +337,7 @@ func TestReconcileNCWithEmptyState(t *testing.T) {
expectedNcCount := len(svc.state.ContainerStatus)
expectedAssignedPods := make(map[string]cns.PodInfo)
returnCode := svc.ReconcileIPAMState(nil, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift(nil, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,
@ -387,7 +387,7 @@ func TestReconcileNCWithEmptyStateAndPendingRelease(t *testing.T) {
return pendingIPs
}()
req := generateNetworkContainerRequest(secondaryIPConfigs, "reconcileNc1", "-1")
returnCode := svc.ReconcileIPAMState([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
Spec: v1alpha.NodeNetworkConfigSpec{
IPsNotInUse: pending,
},
@ -434,7 +434,7 @@ func TestReconcileNCWithExistingStateAndPendingRelease(t *testing.T) {
req := generateNetworkContainerRequest(secondaryIPConfigs, "reconcileNc1", "-1")
expectedNcCount := len(svc.state.ContainerStatus)
returnCode := svc.ReconcileIPAMState([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
Spec: v1alpha.NodeNetworkConfigSpec{
IPsNotInUse: maps.Keys(pendingIPIDs),
},
@ -471,7 +471,7 @@ func TestReconcileNCWithExistingState(t *testing.T) {
}
expectedNcCount := len(svc.state.ContainerStatus)
returnCode := svc.ReconcileIPAMState([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,
@ -522,7 +522,7 @@ func TestReconcileCNSIPAMWithDualStackPods(t *testing.T) {
ncReqs := []*cns.CreateNetworkContainerRequest{ipv4NC, ipv6NC}
returnCode := svc.ReconcileIPAMState(ncReqs, podByIP, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift(ncReqs, podByIP, &v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,
@ -570,7 +570,7 @@ func TestReconcileCNSIPAMWithMultipleIPsPerFamilyPerPod(t *testing.T) {
ncReqs := []*cns.CreateNetworkContainerRequest{ipv4NC, ipv6NC}
returnCode := svc.ReconcileIPAMState(ncReqs, podByIP, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift(ncReqs, podByIP, &v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,
@ -697,7 +697,7 @@ func TestReconcileNCWithExistingStateFromInterfaceID(t *testing.T) {
}
expectedNcCount := len(svc.state.ContainerStatus)
returnCode := svc.ReconcileIPAMState([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,
@ -742,7 +742,7 @@ func TestReconcileCNSIPAMWithKubePodInfoProvider(t *testing.T) {
expectedAssignedPods["192.168.0.1"] = cns.NewPodInfo("", "", "systempod", "kube-system")
expectedNcCount := len(svc.state.ContainerStatus)
returnCode := svc.ReconcileIPAMState([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
returnCode := svc.ReconcileIPAMStateForSwift([]*cns.CreateNetworkContainerRequest{req}, expectedAssignedPods, &v1alpha.NodeNetworkConfig{
Status: v1alpha.NodeNetworkConfigStatus{
Scaler: v1alpha.Scaler{
BatchSize: batchSize,

Просмотреть файл

@ -197,6 +197,7 @@ func (service *HTTPRestService) updatePodInfoWithInterfaces(ctx context.Context,
// RequestIPConfigHandler requests an IPConfig from the CNS state
func (service *HTTPRestService) RequestIPConfigHandler(w http.ResponseWriter, r *http.Request) {
opName := "requestIPConfigHandler"
defer service.publishIPStateMetrics()
var ipconfigRequest cns.IPConfigRequest
err := common.Decode(w, r, &ipconfigRequest)
logger.Request(opName, ipconfigRequest, err)
@ -272,6 +273,7 @@ func (service *HTTPRestService) RequestIPConfigHandler(w http.ResponseWriter, r
// RequestIPConfigsHandler requests multiple IPConfigs from the CNS state
func (service *HTTPRestService) RequestIPConfigsHandler(w http.ResponseWriter, r *http.Request) {
opName := "requestIPConfigsHandler"
defer service.publishIPStateMetrics()
var ipconfigsRequest cns.IPConfigsRequest
err := common.Decode(w, r, &ipconfigsRequest)
logger.Request(opName, ipconfigsRequest, err)
@ -415,6 +417,7 @@ func (service *HTTPRestService) ReleaseIPConfigHandlerHelper(ctx context.Context
// ReleaseIPConfigHandler frees the IP assigned to a pod from CNS
func (service *HTTPRestService) ReleaseIPConfigHandler(w http.ResponseWriter, r *http.Request) {
opName := "releaseIPConfigHandler"
defer service.publishIPStateMetrics()
var ipconfigRequest cns.IPConfigRequest
err := common.Decode(w, r, &ipconfigRequest)
logger.Request(opName, ipconfigRequest, err)
@ -469,6 +472,7 @@ func (service *HTTPRestService) ReleaseIPConfigHandler(w http.ResponseWriter, r
// ReleaseIPConfigsHandler frees multiple IPConfigs from the CNS state
func (service *HTTPRestService) ReleaseIPConfigsHandler(w http.ResponseWriter, r *http.Request) {
opName := "releaseIPConfigsHandler"
defer service.publishIPStateMetrics()
var ipconfigsRequest cns.IPConfigsRequest
err := common.Decode(w, r, &ipconfigsRequest)
logger.Request("releaseIPConfigsHandler", ipconfigsRequest, err)
@ -518,6 +522,7 @@ func (service *HTTPRestService) removeEndpointState(podInfo cns.PodInfo) error {
// MarkIPAsPendingRelease will set the IPs which are in PendingProgramming or Available to PendingRelease state
// It will try to update [totalIpsToRelease] number of ips.
func (service *HTTPRestService) MarkIPAsPendingRelease(totalIpsToRelease int) (map[string]cns.IPConfigurationStatus, error) {
defer service.publishIPStateMetrics()
pendingReleasedIps := make(map[string]cns.IPConfigurationStatus)
service.Lock()
defer service.Unlock()
@ -563,6 +568,7 @@ func (service *HTTPRestService) MarkIPAsPendingRelease(totalIpsToRelease int) (m
// and return an error.
// MarkNIPsPendingRelease is no-op if [n] is not a positive integer.
func (service *HTTPRestService) MarkNIPsPendingRelease(n int) (map[string]cns.IPConfigurationStatus, error) {
defer service.publishIPStateMetrics()
service.Lock()
defer service.Unlock()
// try to release from PendingProgramming

Просмотреть файл

@ -1,58 +0,0 @@
package restserver
import (
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/types"
)
type ipState struct {
// allocatedIPs are all the IPs given to CNS by DNC.
allocatedIPs int64
// assignedIPs are the IPs CNS gives to Pods.
assignedIPs int64
// availableIPs are the IPs in state "Available".
availableIPs int64
// programmingIPs are the IPs in state "PendingProgramming".
programmingIPs int64
// releasingIPs are the IPs in state "PendingReleasr".
releasingIPs int64
}
func (service *HTTPRestService) buildIPState() *ipState {
service.Lock()
defer service.Unlock()
state := ipState{
allocatedIPs: 0,
assignedIPs: 0,
availableIPs: 0,
programmingIPs: 0,
releasingIPs: 0,
}
//nolint:gocritic // This has to iterate over the IP Config state to get the counts.
for _, ipConfig := range service.PodIPConfigState {
state.allocatedIPs++
if ipConfig.GetState() == types.Assigned {
state.assignedIPs++
}
if ipConfig.GetState() == types.Available {
state.availableIPs++
}
if ipConfig.GetState() == types.PendingProgramming {
state.programmingIPs++
}
if ipConfig.GetState() == types.PendingRelease {
state.releasingIPs++
}
}
logger.Printf("[IP Usage] Allocated IPs: %d, Assigned IPs: %d, Available IPs: %d, PendingProgramming IPs: %d, PendingRelease IPs: %d",
state.allocatedIPs,
state.assignedIPs,
state.availableIPs,
state.programmingIPs,
state.releasingIPs,
)
return &state
}

Просмотреть файл

@ -1,10 +1,13 @@
package restserver
import (
"maps"
"net/http"
"sync"
"time"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/types"
"github.com/prometheus/client_golang/prometheus"
"sigs.k8s.io/controller-runtime/pkg/metrics"
@ -122,7 +125,6 @@ func init() {
// Every http response is 200 so we really want cns response code.
// Hard tto do with middleware unless we derserialize the responses but making it an explit header works around it.
// if that doesn't work we could have a separate countervec just for response codes.
func NewHandlerFuncWithHistogram(handler http.HandlerFunc, histogram *prometheus.HistogramVec) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
start := time.Now()
@ -142,7 +144,62 @@ func stateTransitionMiddleware(i *cns.IPConfigurationStatus, s types.IPState) {
ipConfigStatusStateTransitionTime.WithLabelValues(string(i.GetState()), string(s)).Observe(time.Since(i.LastStateTransition).Seconds())
}
func publishIPStateMetrics(state *ipState) {
type ipState struct {
// allocatedIPs are all the IPs given to CNS by DNC.
allocatedIPs int64
// assignedIPs are the IPs CNS gives to Pods.
assignedIPs int64
// availableIPs are the IPs in state "Available".
availableIPs int64
// programmingIPs are the IPs in state "PendingProgramming".
programmingIPs int64
// releasingIPs are the IPs in state "PendingReleasr".
releasingIPs int64
}
type asyncMetricsRecorder struct {
podIPConfigSrc func() map[string]cns.IPConfigurationStatus
sig chan struct{}
once sync.Once
}
// singleton recorder
var recorder asyncMetricsRecorder
// run starts the asyncMetricsRecorder and listens for signals to record the metrics.
func (a *asyncMetricsRecorder) run() {
for range a.sig {
a.record()
}
}
// record records the IP Config state metrics to Prometheus.
func (a *asyncMetricsRecorder) record() {
var state ipState
for ipConfig := range maps.Values(a.podIPConfigSrc()) {
state.allocatedIPs++
if ipConfig.GetState() == types.Assigned {
state.assignedIPs++
}
if ipConfig.GetState() == types.Available {
state.availableIPs++
}
if ipConfig.GetState() == types.PendingProgramming {
state.programmingIPs++
}
if ipConfig.GetState() == types.PendingRelease {
state.releasingIPs++
}
}
logger.Printf("Allocated IPs: %d, Assigned IPs: %d, Available IPs: %d, PendingProgramming IPs: %d, PendingRelease IPs: %d",
state.allocatedIPs,
state.assignedIPs,
state.availableIPs,
state.programmingIPs,
state.releasingIPs,
)
labels := []string{}
allocatedIPCount.WithLabelValues(labels...).Set(float64(state.allocatedIPs))
assignedIPCount.WithLabelValues(labels...).Set(float64(state.assignedIPs))
@ -150,3 +207,24 @@ func publishIPStateMetrics(state *ipState) {
pendingProgrammingIPCount.WithLabelValues(labels...).Set(float64(state.programmingIPs))
pendingReleaseIPCount.WithLabelValues(labels...).Set(float64(state.releasingIPs))
}
// publishIPStateMetrics logs and publishes the IP Config state metrics to Prometheus.
func (service *HTTPRestService) publishIPStateMetrics() {
recorder.once.Do(func() {
recorder.podIPConfigSrc = service.PodIPConfigStates
recorder.sig = make(chan struct{})
go recorder.run()
})
select {
case recorder.sig <- struct{}{}: // signal the recorder to record the metrics
default: // drop the signal if the recorder already has an event queued
}
}
// PodIPConfigStates returns a clone of the IP Config State map.
func (service *HTTPRestService) PodIPConfigStates() map[string]cns.IPConfigurationStatus {
// copy state
service.RLock()
defer service.RUnlock()
return maps.Clone(service.PodIPConfigState)
}

Просмотреть файл

@ -0,0 +1,64 @@
package restserver
import (
"context"
"net/netip"
"github.com/Azure/azure-container-networking/cns"
"github.com/Azure/azure-container-networking/cns/logger"
nodesubnet "github.com/Azure/azure-container-networking/cns/nodesubnet"
"github.com/Azure/azure-container-networking/cns/types"
"github.com/pkg/errors"
)
var _ nodesubnet.IPConsumer = &HTTPRestService{}
// UpdateIPsForNodeSubnet updates the IP pool of HTTPRestService with newly fetched secondary IPs
func (service *HTTPRestService) UpdateIPsForNodeSubnet(secondaryIPs []netip.Addr) error {
secondaryIPStrs := make([]string, len(secondaryIPs))
for i, ip := range secondaryIPs {
secondaryIPStrs[i] = ip.String()
}
networkContainerRequest := nodesubnet.CreateNodeSubnetNCRequest(secondaryIPStrs)
code, msg := service.saveNetworkContainerGoalState(*networkContainerRequest)
if code != types.Success {
return errors.Errorf("failed to save fetched ips. code: %d, message %s", code, msg)
}
logger.Debugf("IP change processed successfully")
// saved NC successfully. UpdateIPsForNodeSubnet is called only when IPs are fetched from NMAgent.
// We now have IPs to serve IPAM requests. Generate conflist to indicate CNS is ready
service.MustGenerateCNIConflistOnce()
return nil
}
// InitializeNodeSubnet prepares CNS for serving NodeSubnet requests.
// It sets the orchestrator type to KubernetesCRD, reconciles the initial
// CNS state from the statefile, then creates an IP fetcher.
func (service *HTTPRestService) InitializeNodeSubnet(ctx context.Context, podInfoByIPProvider cns.PodInfoByIPProvider) error {
// set orchestrator type
orchestrator := cns.SetOrchestratorTypeRequest{
OrchestratorType: cns.KubernetesCRD,
}
service.SetNodeOrchestrator(&orchestrator)
if podInfoByIPProvider == nil {
logger.Printf("PodInfoByIPProvider is nil, this usually means no saved endpoint state. Skipping reconciliation")
} else if _, err := nodesubnet.ReconcileInitialCNSState(ctx, service, podInfoByIPProvider); err != nil {
return errors.Wrap(err, "reconcile initial CNS state")
}
// statefile (if any) is reconciled. Initialize the IP fetcher. Start the IP fetcher only after the service is started,
// because starting the IP fetcher will generate conflist, which should be done only once we are ready to respond to IPAM requests.
service.nodesubnetIPFetcher = nodesubnet.NewIPFetcher(service.nma, service, 0, 0, logger.Log)
return nil
}
// StartNodeSubnet starts the IP fetcher for NodeSubnet. This will cause secondary IPs to be fetched periodically.
// After the first successful fetch, conflist will be generated to indicate CNS is ready.
func (service *HTTPRestService) StartNodeSubnet(ctx context.Context) {
service.nodesubnetIPFetcher.Start(ctx)
}

Просмотреть файл

@ -0,0 +1,144 @@
package restserver_test
import (
"context"
"net"
"testing"
"github.com/Azure/azure-container-networking/cns/cnireconciler"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/restserver"
"github.com/Azure/azure-container-networking/cns/types"
"github.com/Azure/azure-container-networking/store"
)
// getMockStore creates a mock KeyValueStore with some endpoint state
func getMockStore() store.KeyValueStore {
mockStore := store.NewMockStore("")
endpointState := map[string]*restserver.EndpointInfo{
"12e65d89e58cb23c784e97840cf76866bfc9902089bdc8e87e9f64032e312b0b": {
PodName: "coredns-54b69f46b8-ldmwr",
PodNamespace: "kube-system",
IfnameToIPMap: map[string]*restserver.IPInfo{
"eth0": {
IPv4: []net.IPNet{
{
IP: net.IPv4(10, 0, 0, 52),
Mask: net.CIDRMask(24, 32),
},
},
},
},
},
"1fc5176913a3a1a7facfb823dde3b4ded404041134fef4f4a0c8bba140fc0413": {
PodName: "load-test-7f7d49687d-wxc9p",
PodNamespace: "load-test",
IfnameToIPMap: map[string]*restserver.IPInfo{
"eth0": {
IPv4: []net.IPNet{
{
IP: net.IPv4(10, 0, 0, 63),
Mask: net.CIDRMask(24, 32),
},
},
},
},
},
}
err := mockStore.Write(restserver.EndpointStoreKey, endpointState)
if err != nil {
return nil
}
return mockStore
}
// Mock implementation of CNIConflistGenerator
type MockCNIConflistGenerator struct {
GenerateCalled chan struct{}
}
func (m *MockCNIConflistGenerator) Generate() error {
close(m.GenerateCalled)
return nil
}
func (m *MockCNIConflistGenerator) Close() error {
// Implement the Close method logic here if needed
return nil
}
// TestNodeSubnet tests initialization of NodeSubnet with endpoint info, and verfies that
// the conflist is generated after fetching secondary IPs
func TestNodeSubnet(t *testing.T) {
podInfoByIPProvider, err := cnireconciler.NewCNSPodInfoProvider(getMockStore())
if err != nil {
t.Fatalf("NewCNSPodInfoProvider returned an error: %v", err)
}
// create a real HTTPRestService object
mockCNIConflistGenerator := &MockCNIConflistGenerator{
GenerateCalled: make(chan struct{}),
}
service := restserver.GetRestServiceObjectForNodeSubnetTest(t, mockCNIConflistGenerator)
ctx, cancel := testContext(t)
defer cancel()
err = service.InitializeNodeSubnet(ctx, podInfoByIPProvider)
if err != nil {
t.Fatalf("InitializeNodeSubnet returned an error: %v", err)
}
expectedIPs := map[string]types.IPState{
"10.0.0.52": types.Assigned,
"10.0.0.63": types.Assigned,
}
checkIPassignment(t, service, expectedIPs)
service.StartNodeSubnet(ctx)
if service.GetNodesubnetIPFetcher() == nil {
t.Fatal("NodeSubnetIPFetcher is not initialized")
}
select {
case <-ctx.Done():
t.Errorf("test context done - %s", ctx.Err())
return
case <-mockCNIConflistGenerator.GenerateCalled:
break
}
expectedIPs["10.0.0.45"] = types.Available
checkIPassignment(t, service, expectedIPs)
}
// checkIPassignment checks whether the IP assignment state in the HTTPRestService object matches expectation
func checkIPassignment(t *testing.T, service *restserver.HTTPRestService, expectedIPs map[string]types.IPState) {
if len(service.PodIPConfigState) != len(expectedIPs) {
t.Fatalf("expected 2 entries in PodIPConfigState, got %d", len(service.PodIPConfigState))
}
for ip := range service.GetPodIPConfigState() {
config := service.GetPodIPConfigState()[ip]
if assignmentState, exists := expectedIPs[ip]; !exists {
t.Fatalf("unexpected IP %s in PodIPConfigState", ip)
} else if config.GetState() != assignmentState {
t.Fatalf("expected state 'Assigned' for IP %s, got %s", ip, config.GetState())
}
}
}
// testContext creates a context from the provided testing.T that will be
// canceled if the test suite is terminated.
func testContext(t *testing.T) (context.Context, context.CancelFunc) {
if deadline, ok := t.Deadline(); ok {
return context.WithDeadline(context.Background(), deadline)
}
return context.WithCancel(context.Background())
}
func init() {
logger.InitLogger("testlogs", 0, 0, "./")
}

Просмотреть файл

@ -13,6 +13,7 @@ import (
"github.com/Azure/azure-container-networking/cns/dockerclient"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/networkcontainers"
"github.com/Azure/azure-container-networking/cns/nodesubnet"
"github.com/Azure/azure-container-networking/cns/routes"
"github.com/Azure/azure-container-networking/cns/types"
"github.com/Azure/azure-container-networking/cns/types/bounded"
@ -40,6 +41,7 @@ type nmagentClient interface {
SupportedAPIs(context.Context) ([]string, error)
GetNCVersionList(context.Context) (nma.NCVersionList, error)
GetHomeAz(context.Context) (nma.AzResponse, error)
GetInterfaceIPInfo(ctx context.Context) (nma.Interfaces, error)
}
type wireserverProxy interface {
@ -76,6 +78,7 @@ type HTTPRestService struct {
IPConfigsHandlerMiddleware cns.IPConfigsHandlerMiddleware
PnpIDByMacAddress map[string]string
imdsClient imdsClient
nodesubnetIPFetcher *nodesubnet.IPFetcher
}
type CNIConflistGenerator interface {

Просмотреть файл

@ -14,6 +14,7 @@ import (
"github.com/Azure/azure-container-networking/cns/dockerclient"
"github.com/Azure/azure-container-networking/cns/logger"
"github.com/Azure/azure-container-networking/cns/networkcontainers"
"github.com/Azure/azure-container-networking/cns/nodesubnet"
"github.com/Azure/azure-container-networking/cns/types"
"github.com/Azure/azure-container-networking/cns/wireserver"
acn "github.com/Azure/azure-container-networking/common"
@ -158,6 +159,12 @@ func (service *HTTPRestService) saveNetworkContainerGoalState(req cns.CreateNetw
existingSecondaryIPConfigs = existingNCStatus.CreateNetworkContainerRequest.SecondaryIPConfigs
vfpUpdateComplete = existingNCStatus.VfpUpdateComplete
}
if req.NetworkContainerid == nodesubnet.NodeSubnetNCID {
hostVersion = nodesubnet.NodeSubnetHostVersion
vfpUpdateComplete = true
}
if hostVersion == "" {
// Host version is the NC version from NMAgent, set it -1 to indicate no result from NMAgent yet.
// TODO, query NMAgent and with aggresive time out and assign latest host version.
@ -187,9 +194,7 @@ func (service *HTTPRestService) saveNetworkContainerGoalState(req cns.CreateNetw
fallthrough
case cns.JobObject:
fallthrough
case cns.COW, cns.BackendNICNC:
fallthrough
case cns.WebApps:
case cns.COW, cns.BackendNICNC, cns.WebApps:
switch service.state.OrchestratorType {
case cns.Kubernetes:
fallthrough
@ -291,6 +296,7 @@ func (service *HTTPRestService) updateIPConfigsStateUntransacted(
if hostNCVersionInInt, err = strconv.Atoi(hostVersion); err != nil {
return types.UnsupportedNCVersion, fmt.Sprintf("Invalid hostVersion is %s, err:%s", hostVersion, err)
}
service.addIPConfigStateUntransacted(req.NetworkContainerid, hostNCVersionInInt, req.SecondaryIPConfigs,
existingSecondaryIPConfigs)

Просмотреть файл

@ -679,7 +679,7 @@ func main() {
}
if telemetryDaemonEnabled {
logger.Printf("CNI Telemtry is enabled")
logger.Printf("CNI Telemetry is enabled")
go startTelemetryService(rootCtx)
}
@ -743,7 +743,6 @@ func main() {
}
imdsClient := imds.NewClient()
httpRemoteRestService, err := restserver.NewHTTPRestService(&config, wsclient, &wsProxy, nmaClient,
endpointStateStore, conflistGenerator, homeAzMonitor, imdsClient)
if err != nil {
@ -878,6 +877,32 @@ func main() {
}
}
// AzureHost channelmode indicates Nodesubnet. IPs are to be fetched from NMagent.
if config.ChannelMode == cns.AzureHost {
if !cnsconfig.ManageEndpointState {
logger.Errorf("ManageEndpointState must be set to true for AzureHost mode")
return
}
// If cns manageendpointstate is true, then cns maintains its own state and reconciles from it.
// in this case, cns maintains state with containerid as key and so in-memory cache can lookup
// and update based on container id.
cns.GlobalPodInfoScheme = cns.InfraIDPodInfoScheme
var podInfoByIPProvider cns.PodInfoByIPProvider
podInfoByIPProvider, err = getPodInfoByIPProvider(rootCtx, cnsconfig, httpRemoteRestService, nil, "")
if err != nil {
logger.Errorf("[Azure CNS] Failed to get PodInfoByIPProvider: %v", err)
return
}
err = httpRemoteRestService.InitializeNodeSubnet(rootCtx, podInfoByIPProvider)
if err != nil {
logger.Errorf("[Azure CNS] Failed to initialize node subnet: %v", err)
return
}
}
// Initialize multi-tenant controller if the CNS is running in MultiTenantCRD mode.
// It must be started before we start HTTPRemoteRestService.
if config.ChannelMode == cns.MultiTenantCRD {
@ -960,6 +985,7 @@ func main() {
}
// if user provides cns url by -c option, then only start HTTP remote server using this url
logger.Printf("[Azure CNS] Start HTTP Remote server")
if httpRemoteRestService != nil {
if cnsconfig.EnablePprof {
@ -1070,6 +1096,13 @@ func main() {
}(privateEndpoint, infravnet, nodeID)
}
if config.ChannelMode == cns.AzureHost {
// at this point, rest service is running. We can now start serving new requests. So call StartNodeSubnet, which
// will fetch secondary IPs and generate conflist. Do not move this all before rest service start - this will cause
// CNI to start sending requests, and if the service doesn't start successfully, the requests will fail.
httpRemoteRestService.StartNodeSubnet(rootCtx)
}
// mark the service as "ready"
close(readyCh)
// block until process exiting
@ -1260,7 +1293,7 @@ type nodeNetworkConfigGetter interface {
}
type ipamStateReconciler interface {
ReconcileIPAMState(ncRequests []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo, nnc *v1alpha.NodeNetworkConfig) cnstypes.ResponseCode
ReconcileIPAMStateForSwift(ncRequests []*cns.CreateNetworkContainerRequest, podInfoByIP map[string]cns.PodInfo, nnc *v1alpha.NodeNetworkConfig) cnstypes.ResponseCode
}
// TODO(rbtr) where should this live??
@ -1318,7 +1351,7 @@ func reconcileInitialCNSState(ctx context.Context, cli nodeNetworkConfigGetter,
}
// Call cnsclient init cns passing those two things.
if err := restserver.ResponseCodeToError(ipamReconciler.ReconcileIPAMState(ncReqs, podInfoByIP, nnc)); err != nil {
if err := restserver.ResponseCodeToError(ipamReconciler.ReconcileIPAMStateForSwift(ncReqs, podInfoByIP, nnc)); err != nil {
return errors.Wrap(err, "failed to reconcile CNS IPAM state")
}
@ -1385,40 +1418,11 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn
}
}
var podInfoByIPProvider cns.PodInfoByIPProvider
switch {
case cnsconfig.ManageEndpointState:
logger.Printf("Initializing from self managed endpoint store")
podInfoByIPProvider, err = cnireconciler.NewCNSPodInfoProvider(httpRestServiceImplementation.EndpointStateStore) // get reference to endpoint state store from rest server
if err != nil {
if errors.Is(err, store.ErrKeyNotFound) {
logger.Printf("[Azure CNS] No endpoint state found, skipping initializing CNS state")
} else {
return errors.Wrap(err, "failed to create CNS PodInfoProvider")
}
}
case cnsconfig.InitializeFromCNI:
logger.Printf("Initializing from CNI")
podInfoByIPProvider, err = cnireconciler.NewCNIPodInfoProvider()
if err != nil {
return errors.Wrap(err, "failed to create CNI PodInfoProvider")
}
default:
logger.Printf("Initializing from Kubernetes")
podInfoByIPProvider = cns.PodInfoByIPProviderFunc(func() (map[string]cns.PodInfo, error) {
pods, err := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{ //nolint:govet // ignore err shadow
FieldSelector: "spec.nodeName=" + nodeName,
})
if err != nil {
return nil, errors.Wrap(err, "failed to list Pods for PodInfoProvider")
}
podInfo, err := cns.KubePodsToPodInfoByIP(pods.Items)
if err != nil {
return nil, errors.Wrap(err, "failed to convert Pods to PodInfoByIP")
}
return podInfo, nil
})
podInfoByIPProvider, err := getPodInfoByIPProvider(ctx, cnsconfig, httpRestServiceImplementation, clientset, nodeName)
if err != nil {
return errors.Wrap(err, "failed to initialize ip state")
}
// create scoped kube clients.
directcli, err := client.New(kubeConfig, client.Options{Scheme: nodenetworkconfig.Scheme})
if err != nil {
@ -1641,6 +1645,51 @@ func InitializeCRDState(ctx context.Context, httpRestService cns.HTTPService, cn
return nil
}
// getPodInfoByIPProvider returns a PodInfoByIPProvider that reads endpoint state from the configured source
func getPodInfoByIPProvider(
ctx context.Context,
cnsconfig *configuration.CNSConfig,
httpRestServiceImplementation *restserver.HTTPRestService,
clientset *kubernetes.Clientset,
nodeName string,
) (podInfoByIPProvider cns.PodInfoByIPProvider, err error) {
switch {
case cnsconfig.ManageEndpointState:
logger.Printf("Initializing from self managed endpoint store")
podInfoByIPProvider, err = cnireconciler.NewCNSPodInfoProvider(httpRestServiceImplementation.EndpointStateStore) // get reference to endpoint state store from rest server
if err != nil {
if errors.Is(err, store.ErrKeyNotFound) {
logger.Printf("[Azure CNS] No endpoint state found, skipping initializing CNS state")
} else {
return podInfoByIPProvider, errors.Wrap(err, "failed to create CNS PodInfoProvider")
}
}
case cnsconfig.InitializeFromCNI:
logger.Printf("Initializing from CNI")
podInfoByIPProvider, err = cnireconciler.NewCNIPodInfoProvider()
if err != nil {
return podInfoByIPProvider, errors.Wrap(err, "failed to create CNI PodInfoProvider")
}
default:
logger.Printf("Initializing from Kubernetes")
podInfoByIPProvider = cns.PodInfoByIPProviderFunc(func() (map[string]cns.PodInfo, error) {
pods, err := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{ //nolint:govet // ignore err shadow
FieldSelector: "spec.nodeName=" + nodeName,
})
if err != nil {
return nil, errors.Wrap(err, "failed to list Pods for PodInfoProvider")
}
podInfo, err := cns.KubePodsToPodInfoByIP(pods.Items)
if err != nil {
return nil, errors.Wrap(err, "failed to convert Pods to PodInfoByIP")
}
return podInfo, nil
})
}
return podInfoByIPProvider, nil
}
// createOrUpdateNodeInfoCRD polls imds to learn the VM Unique ID and then creates or updates the NodeInfo CRD
// with that vm unique ID
func createOrUpdateNodeInfoCRD(ctx context.Context, restConfig *rest.Config, node *corev1.Node) error {

Просмотреть файл

@ -16,6 +16,7 @@ import (
// +kubebuilder:resource:shortName=nnc
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Requested IPs",type=integer,priority=1,JSONPath=`.spec.requestedIPCount`
// +kubebuilder:printcolumn:name="Availability Zone",type=string,priority=1,JSONPath=`.spec.availabilityZone`
// +kubebuilder:printcolumn:name="Allocated IPs",type=integer,priority=0,JSONPath=`.status.assignedIPCount`
// +kubebuilder:printcolumn:name="Subnet",type=string,priority=1,JSONPath=`.status.networkContainers[*].subnetName`
// +kubebuilder:printcolumn:name="Subnet CIDR",type=string,priority=1,JSONPath=`.status.networkContainers[*].subnetAddressSpace`
@ -46,6 +47,9 @@ type NodeNetworkConfigSpec struct {
// +kubebuilder:validation:Optional
RequestedIPCount int64 `json:"requestedIPCount"`
IPsNotInUse []string `json:"ipsNotInUse,omitempty"`
// AvailabilityZone contains the Azure availability zone for the virtual machine where network containers are placed.
// +kubebuilder:validation:Optional
AvailabilityZone string `json:"availabilityZone,omitempty"`
}
// Status indicates the NNC reconcile status

Просмотреть файл

@ -21,6 +21,10 @@ spec:
name: Requested IPs
priority: 1
type: integer
- jsonPath: .spec.availabilityZone
name: Availability Zone
priority: 1
type: string
- jsonPath: .status.assignedIPCount
name: Allocated IPs
type: integer
@ -71,6 +75,10 @@ spec:
spec:
description: NodeNetworkConfigSpec defines the desired state of NetworkConfig
properties:
availabilityZone:
description: AvailabilityZone contains the Azure availability zone
for the virtual machine where network containers are placed.
type: string
ipsNotInUse:
items:
type: string

Просмотреть файл

@ -31,9 +31,13 @@ type OverlayExtensionConfigList struct {
}
// OverlayExtensionConfigSpec defines the desired state of OverlayExtensionConfig.
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.extensionIPRange) || has(self.extensionIPRange)", message="ExtensionIPRange is required once set"
type OverlayExtensionConfigSpec struct {
// ExtensionIPRange field defines a CIDR that should be able to reach routing domain ip addresses.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
// +kubebuilder:validation:MaxLength=43
// 43 is max length of IPv6 CIDR string
ExtensionIPRange string `json:"extensionIPRange,omitempty"`
}

Просмотреть файл

@ -48,10 +48,18 @@ spec:
description: OverlayExtensionConfigSpec defines the desired state of OverlayExtensionConfig.
properties:
extensionIPRange:
description: ExtensionIPRange field defines a CIDR that should be
able to reach routing domain ip addresses.
description: |-
ExtensionIPRange field defines a CIDR that should be able to reach routing domain ip addresses.
43 is max length of IPv6 CIDR string
maxLength: 43
type: string
x-kubernetes-validations:
- message: Value is immutable
rule: self == oldSelf
type: object
x-kubernetes-validations:
- message: ExtensionIPRange is required once set
rule: '!has(oldSelf.extensionIPRange) || has(self.extensionIPRange)'
status:
description: OverlayExtensionConfigStatus defines the observed state of
OverlayExtensionConfig

24
go.mod
Просмотреть файл

@ -5,12 +5,12 @@ go 1.23
toolchain go1.23.2
require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0
github.com/Masterminds/semver v1.5.0
github.com/Microsoft/go-winio v0.6.2
github.com/Microsoft/hcsshim v0.12.7
github.com/Microsoft/hcsshim v0.12.9
github.com/avast/retry-go/v3 v3.1.1
github.com/avast/retry-go/v4 v4.6.0
github.com/billgraziano/dpapi v0.5.0
@ -30,7 +30,7 @@ require (
github.com/onsi/gomega v1.33.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.20.4
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.1
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
@ -39,14 +39,14 @@ require (
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/sys v0.26.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.67.1
google.golang.org/protobuf v1.35.1
gopkg.in/natefinch/lumberjack.v2 v2.2.1
k8s.io/api v0.30.5
k8s.io/api v0.30.6
k8s.io/apiextensions-apiserver v0.30.1
k8s.io/apimachinery v0.30.5
k8s.io/client-go v0.30.5
k8s.io/apimachinery v0.30.6
k8s.io/client-go v0.30.6
k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.130.1
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
@ -63,7 +63,7 @@ require (
github.com/coreos/go-iptables v0.8.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/fsnotify/fsnotify v1.7.0
github.com/fsnotify/fsnotify v1.8.0
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
@ -93,7 +93,7 @@ require (
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/common v0.60.0
github.com/prometheus/common v0.60.1
github.com/prometheus/procfs v0.15.1 // indirect
github.com/sirupsen/logrus v1.9.3
github.com/spf13/afero v1.11.0 // indirect
@ -137,20 +137,22 @@ require (
)
require (
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/typeurl/v2 v2.2.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
)
require (
github.com/containerd/cgroups/v3 v3.0.3 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/errdefs v0.3.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
k8s.io/kubelet v0.30.5
k8s.io/kubelet v0.30.6
)
replace (

48
go.sum
Просмотреть файл

@ -2,8 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
code.cloudfoundry.org/clock v1.0.0 h1:kFXWQM4bxYvdBw2X8BbBeXwQNgfoWv1vqAk2ZZyBN2o=
code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw=
@ -39,8 +39,8 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Microsoft/hcsshim v0.12.7 h1:MP6R1spmjxTE4EU4J3YsrTxn8CjvN9qwjTKJXldFaRg=
github.com/Microsoft/hcsshim v0.12.7/go.mod h1:HPbAuJ9BvQYYZbB4yEQcyGIsTP5L4yHKeO9XO149AEM=
github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6lLg=
github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/avast/retry-go/v3 v3.1.1 h1:49Scxf4v8PmiQ/nY0aY3p0hDueqSmc7++cBbtiDGu2g=
@ -58,8 +58,12 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0=
github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0=
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
github.com/containerd/errdefs v0.3.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/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso=
github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g=
github.com/containernetworking/cni v1.2.2 h1:9IbP6KJQQxVKo4hhnm8r50YcVKrJbJu3Dqw+Rbt1vYk=
github.com/containernetworking/cni v1.2.2/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc=
@ -87,8 +91,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
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/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@ -234,13 +238,13 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
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.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
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.60.0 h1:+V9PAREWNvJMAuJ1x1BaWl9dewMW4YrHZQbx0sJNllA=
github.com/prometheus/common v0.60.0/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
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/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
@ -390,8 +394,8 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
@ -435,14 +439,14 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.30.5 h1:Coz05sfEVywzGcA96AJPUfs2B8LBMnh+IIsM+HCfaz8=
k8s.io/api v0.30.5/go.mod h1:HfNBGFvq9iNK8dmTKjYIdAtMxu8BXTb9c1SJyO6QjKs=
k8s.io/api v0.30.6 h1:uqRDLnFkmPLorI9D0x1dGXdYeRQMhQHlrHDgZ3/45RE=
k8s.io/api v0.30.6/go.mod h1:6x759Hj7155pXRKStxzM7TMN9hW0x7WrBr51kuDMSHo=
k8s.io/apiextensions-apiserver v0.30.1 h1:4fAJZ9985BmpJG6PkoxVRpXv9vmPUOVzl614xarePws=
k8s.io/apiextensions-apiserver v0.30.1/go.mod h1:R4GuSrlhgq43oRY9sF2IToFh7PVlF1JjfWdoG3pixk4=
k8s.io/apimachinery v0.30.5 h1:CQZO19GFgw4zcOjY2H+mJ3k1u1o7zFACTNCB7nu4O18=
k8s.io/apimachinery v0.30.5/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/client-go v0.30.5 h1:vEDSzfTz0F8TXcWVdXl+aqV7NAV8M3UvC2qnGTTCoKw=
k8s.io/client-go v0.30.5/go.mod h1:/q5fHHBmhAUesOOFJACpD7VJ4e57rVtTPDOsvXrPpMk=
k8s.io/apimachinery v0.30.6 h1:dlplzGrUL/DiPOVVVjDcT9ZoQBOwYeB6hcFy90veggs=
k8s.io/apimachinery v0.30.6/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/client-go v0.30.6 h1:hMo7AUkHy/UqnwPMH+oJvFR9gpvXVfQnsiO+G2fdE30=
k8s.io/client-go v0.30.6/go.mod h1:DDN89/30A1DfatO+c3ksYMM12kL7a/CZvsBaVjwh33g=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
@ -451,8 +455,8 @@ k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7F
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/kubectl v0.28.5 h1:jq8xtiCCZPR8Cl/Qe1D7bLU0h8KtcunwfROqIekCUeU=
k8s.io/kubectl v0.28.5/go.mod h1:9WiwzqeKs3vLiDtEQPbjhqqysX+BIVMLt7C7gN+T5w8=
k8s.io/kubelet v0.30.5 h1:7jsJo1MkmGC3VEE0cf1tHiFKzi8DMBVNih3/OttSBaw=
k8s.io/kubelet v0.30.5/go.mod h1:vzllyQKrbFpTq0WOHV6yX0gUs6KqTwCBAO13cAearMc=
k8s.io/kubelet v0.30.6 h1:jae6hlfOeSA8YCgaPAJRqrWdmGUAtRmbMuatey5e/NA=
k8s.io/kubelet v0.30.6/go.mod h1:blswm8XUMWUXmS3hduLjButEksPbla9mkGXrjTWyX9U=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw=

Просмотреть файл

@ -8,17 +8,18 @@ AZIMG = mcr.microsoft.com/azure-cli
AZCLI ?= docker run --rm -v $(AZCFG):/root/.azure -v $(KUBECFG):/root/.kube -v $(SSH):/root/.ssh -v $(PWD):/root/tmpsrc $(AZIMG) az
# overrideable defaults
AUTOUPGRADE ?= patch
K8S_VER ?= 1.30
NODE_COUNT ?= 2
NODE_COUNT_WIN ?= $(NODE_COUNT)
NODEUPGRADE ?= NodeImage
OS ?= linux # Used to signify if you want to bring up a windows nodePool on byocni clusters
OS_SKU ?= Ubuntu
OS_SKU_WIN ?= Windows2022
REGION ?= westus2
VM_SIZE ?= Standard_B2s
VM_SIZE_WIN ?= Standard_B2s
AUTOUPGRADE ?= patch
K8S_VER ?= 1.30
NODE_COUNT ?= 2
NODE_COUNT_WIN ?= $(NODE_COUNT)
NODEUPGRADE ?= NodeImage
OS ?= linux # Used to signify if you want to bring up a windows nodePool on byocni clusters
OS_SKU ?= Ubuntu
OS_SKU_WIN ?= Windows2022
REGION ?= westus2
VM_SIZE ?= Standard_B2s
VM_SIZE_WIN ?= Standard_B2s
KUBE_PROXY_JSON_PATH ?= ./kube-proxy.json
# overrideable variables
SUB ?= $(AZURE_SUBSCRIPTION)
@ -103,13 +104,13 @@ nodesubnet-byocni-nokubeproxy-up: rg-up overlay-net-up ## Brings up an NodeSubne
--kubernetes-version $(K8S_VER) \
--node-count $(NODE_COUNT) \
--node-vm-size $(VM_SIZE) \
--load-balancer-sku basic \
--load-balancer-sku standard \
--max-pods 250 \
--network-plugin none \
--vnet-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/nodenet \
--os-sku $(OS_SKU) \
--no-ssh-key \
--kube-proxy-config ./kube-proxy.json \
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
--yes
@$(MAKE) set-kubeconf
@ -146,7 +147,7 @@ overlay-byocni-nokubeproxy-up: rg-up overlay-net-up ## Brings up an Overlay BYO
--pod-cidr 192.168.0.0/16 \
--vnet-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/nodenet \
--no-ssh-key \
--kube-proxy-config ./kube-proxy.json \
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
--yes
@$(MAKE) set-kubeconf
@ -215,7 +216,7 @@ swift-byocni-nokubeproxy-up: rg-up swift-net-up ## Bring up a SWIFT BYO CNI clus
--pod-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/podnet \
--no-ssh-key \
--os-sku $(OS_SKU) \
--kube-proxy-config ./kube-proxy.json \
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
--yes
@$(MAKE) set-kubeconf
@ -305,7 +306,7 @@ vnetscale-swift-byocni-nokubeproxy-up: rg-up vnetscale-swift-net-up ## Bring up
--pod-subnet-id /subscriptions/$(SUB)/resourceGroups/$(GROUP)/providers/Microsoft.Network/virtualNetworks/$(VNET)/subnets/podnet \
--no-ssh-key \
--os-sku $(OS_SKU) \
--kube-proxy-config ./kube-proxy.json \
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
--yes
@$(MAKE) set-kubeconf
@ -434,7 +435,7 @@ dualstack-byocni-nokubeproxy-up: rg-up overlay-net-up ## Brings up a Dualstack o
--ip-families ipv4,ipv6 \
--aks-custom-headers AKSHTTPCustomFeatures=Microsoft.ContainerService/AzureOverlayDualStackPreview \
--no-ssh-key \
--kube-proxy-config ./kube-proxy.json \
--kube-proxy-config $(KUBE_PROXY_JSON_PATH) \
--yes
@$(MAKE) set-kubeconf
@ -467,5 +468,5 @@ down: ## Delete the cluster
restart-vmss: ## Restarts the nodes in the cluster
$(AZCLI) vmss restart -g MC_${GROUP}_${CLUSTER}_${REGION} --name $(VMSS_NAME)
scale-vmss: ## Scales the nodes in the cluster
$(AZCLI) vmss scale -g MC_${GROUP}_${CLUSTER}_${REGION} --name $(VMSS_NAME) --new-capacity $(NODE_COUNT)
scale-nodes: ## Scales the nodes in the cluster
$(AZCLI) aks nodepool scale --resource-group $(GROUP) --cluster-name $(CLUSTER) --name $(NODEPOOL) --node-count $(NODE_COUNT)

Просмотреть файл

@ -24,6 +24,7 @@ AKS Clusters
byocni-up Alias to swift-byocni-up
cilium-up Alias to swift-cilium-up
up Alias to swift-up
nodesubnet-byocni-nokubeproxy-up Bring up a Nodesubnet BYO CNI cluster. Does not include secondary IP configs.
overlay-byocni-up Bring up a Overlay BYO CNI cluster
overlay-byocni-nokubeproxy-up Bring up a Overlay BYO CNI cluster without kube-proxy
overlay-cilium-up Bring up a Overlay Cilium cluster

Просмотреть файл

@ -66,7 +66,7 @@ type EndpointInfo struct {
EndpointID string
ContainerID string
NetNsPath string
IfName string // value differs during creation vs. deletion flow
IfName string // value differs during creation vs. deletion flow; used in statefile, not necessarily the nic name
SandboxKey string
IfIndex int
MacAddress net.HardwareAddr
@ -93,7 +93,7 @@ type EndpointInfo struct {
IPV6Mode string
VnetCidrs string
ServiceCidrs string
NATInfo []policy.NATInfo
NATInfo []policy.NATInfo // windows only
NICType cns.NICType
SkipDefaultRoutes bool
HNSEndpointID string

Просмотреть файл

@ -79,6 +79,7 @@ func TestSecondaryAddEndpoints(t *testing.T) {
} else {
require.NoError(t, err)
require.Equal(t, tt.client.ep.SecondaryInterfaces["eth1"].MacAddress, tt.epInfo.MacAddress)
require.Equal(t, "eth1", tt.epInfo.IfName, "interface name should update based on mac address here before being referenced later")
}
})
}

Просмотреть файл

@ -137,6 +137,8 @@ func start(config npmconfig.Config, flags npmconfig.Flags) error {
stopChannel := wait.NeverStop
if config.Toggles.EnableV2NPM {
// update the dataplane config
npmV2DataplaneCfg.EnableNPMLite = config.Toggles.EnableNPMLite
npmV2DataplaneCfg.MaxBatchedACLsPerPod = config.MaxBatchedACLsPerPod
npmV2DataplaneCfg.NetPolInBackground = config.Toggles.NetPolInBackground

Просмотреть файл

@ -172,7 +172,7 @@ data:
"EnableV2NPM": true,
"PlaceAzureChainFirst": false,
"ApplyInBackground": true,
"NetPolInBackground": true
"NetPolInBackground": true,
"EnableNPMLite": true
}
}

Просмотреть файл

@ -153,7 +153,7 @@ data:
"PlaceAzureChainFirst": false,
"ApplyIPSetsOnNeed": false,
"ApplyInBackground": true,
"NetPolInBackground": true
"NetPolInBackground": true,
"EnableNPMLite": true
}
}

Просмотреть файл

@ -192,7 +192,7 @@ func (npMgr *NetworkPolicyManager) Start(config npmconfig.Config, stopCh <-chan
// Starts all informers manufactured by npMgr's informerFactory.
npMgr.InformerFactory.Start(stopCh)
// npn lite
// npm lite
if npMgr.NpmLiteToggle {
npMgr.PodInformerFactory.Start(stopCh)
}

Просмотреть файл

@ -45,6 +45,7 @@ type Config struct {
NetPolInBackground bool
MaxPendingNetPols int
NetPolInterval time.Duration
EnableNPMLite bool
*ipsets.IPSetManagerCfg
*policies.PolicyManagerCfg
}
@ -64,12 +65,13 @@ type DataPlane struct {
nodeName string
// endpointCache stores all endpoints of the network (including off-node)
// Key is PodIP
endpointCache *endpointCache
ioShim *common.IOShim
updatePodCache *updatePodCache
endpointQuery *endpointQuery
applyInfo *applyInfo
netPolQueue *netPolQueue
endpointCache *endpointCache
ioShim *common.IOShim
updatePodCache *updatePodCache
endpointQuery *endpointQuery
endpointQueryAttachedState *endpointQuery // windows -> filter for state 2 (attached) endpoints in l1vh
applyInfo *applyInfo
netPolQueue *netPolQueue
// removePolicyInfo tracks when a policy was removed yet had ApplyIPSet failures.
// This field is only relevant for Linux.
removePolicyInfo removePolicyInfo
@ -88,11 +90,12 @@ func NewDataPlane(nodeName string, ioShim *common.IOShim, cfg *Config, stopChann
policyMgr: policies.NewPolicyManager(ioShim, cfg.PolicyManagerCfg),
ipsetMgr: ipsets.NewIPSetManager(cfg.IPSetManagerCfg, ioShim),
// networkID is set when initializing Windows dataplane
networkID: "",
endpointCache: newEndpointCache(),
nodeName: nodeName,
ioShim: ioShim,
endpointQuery: new(endpointQuery),
networkID: "",
endpointCache: newEndpointCache(),
nodeName: nodeName,
ioShim: ioShim,
endpointQuery: new(endpointQuery),
endpointQueryAttachedState: new(endpointQuery),
applyInfo: &applyInfo{
inBootupPhase: true,
},
@ -128,7 +131,6 @@ func NewDataPlane(nodeName string, ioShim *common.IOShim, cfg *Config, stopChann
} else {
metrics.SendLog(util.DaemonDataplaneID, "[DataPlane] dataplane configured to NOT add netpols in background", true)
}
return dp, nil
}

Просмотреть файл

@ -2,7 +2,6 @@ package dataplane
import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"
@ -12,6 +11,7 @@ import (
"github.com/Azure/azure-container-networking/npm/util"
npmerrors "github.com/Azure/azure-container-networking/npm/util/errors"
"github.com/Microsoft/hcsshim/hcn"
"github.com/pkg/errors"
"k8s.io/klog"
)
@ -50,14 +50,31 @@ func (dp *DataPlane) initializeDataPlane() error {
},
Flags: hcn.HostComputeQueryFlagsNone,
}
// Initialize Endpoint query used to filter healthy endpoints (vNIC) of Windows pods on L1VH Node
dp.endpointQueryAttachedState.query = hcn.HostComputeQuery{
SchemaVersion: hcn.SchemaVersion{
Major: hcnSchemaMajorVersion,
Minor: hcnSchemaMinorVersion,
},
Flags: hcn.HostComputeQueryFlagsNone,
}
// Filter out any endpoints that are not in "AttachedShared" State. All running Windows pods with networking must be in this state.
filterMap := map[string]uint16{"State": hcnEndpointStateAttachedSharing}
filter, err := json.Marshal(filterMap)
if err != nil {
return npmerrors.SimpleErrorWrapper("failed to marshal endpoint filter map", err)
return errors.Wrap(err, "failed to marshal endpoint filter map for attachedsharing state")
}
dp.endpointQuery.query.Filter = string(filter)
// Filter out any endpoints that are not in "Attached" State. All running Windows pods on L1VH with networking must be in this state.
filterMapAttached := map[string]uint16{"State": hcnEndpointStateAttached}
filterAttached, err := json.Marshal(filterMapAttached)
if err != nil {
return errors.Wrap(err, "failed to marshal endpoint filter map for attched state")
}
dp.endpointQueryAttachedState.query.Filter = string(filterAttached)
// reset endpoint cache so that netpol references are removed for all endpoints while refreshing pod endpoints
// no need to lock endpointCache at boot up
dp.endpointCache.cache = make(map[string]*npmEndpoint)
@ -329,14 +346,28 @@ func (dp *DataPlane) getEndpointsToApplyPolicies(netPols []*policies.NPMNetworkP
func (dp *DataPlane) getLocalPodEndpoints() ([]*hcn.HostComputeEndpoint, error) {
klog.Info("getting local endpoints")
// Gets endpoints in state: Attached
timer := metrics.StartNewTimer()
endpointsAttached, err := dp.ioShim.Hns.ListEndpointsQuery(dp.endpointQueryAttachedState.query)
metrics.RecordListEndpointsLatency(timer)
if err != nil {
metrics.IncListEndpointsFailures()
return nil, errors.Wrap(err, "failed to get local pod endpoints in state:attached")
}
// Gets endpoints in state: AttachedSharing
timer = metrics.StartNewTimer()
endpoints, err := dp.ioShim.Hns.ListEndpointsQuery(dp.endpointQuery.query)
metrics.RecordListEndpointsLatency(timer)
if err != nil {
metrics.IncListEndpointsFailures()
return nil, npmerrors.SimpleErrorWrapper("failed to get local pod endpoints", err)
return nil, errors.Wrap(err, "failed to get local pod endpoints in state: attachedSharing")
}
// Get endpoints unique to endpoints and endpointsAttached
endpoints = GetUniqueEndpoints(endpoints, endpointsAttached)
epPointers := make([]*hcn.HostComputeEndpoint, 0, len(endpoints))
for k := range endpoints {
epPointers = append(epPointers, &endpoints[k])
@ -344,6 +375,24 @@ func (dp *DataPlane) getLocalPodEndpoints() ([]*hcn.HostComputeEndpoint, error)
return epPointers, nil
}
func GetUniqueEndpoints(endpoints, endpointsAttached []hcn.HostComputeEndpoint) []hcn.HostComputeEndpoint {
// Store IDs of endpoints list in a map for quick lookup
idMap := make(map[string]struct{}, len(endpoints))
for i := 0; i < len(endpoints); i++ {
ep := endpoints[i]
idMap[ep.Id] = struct{}{}
}
// Add endpointsAttached list endpoints in endpoints list if the endpoint is not in the map
for i := 0; i < len(endpointsAttached); i++ {
ep := endpointsAttached[i]
if _, ok := idMap[ep.Id]; !ok {
endpoints = append(endpoints, ep)
}
}
return endpoints
}
// refreshPodEndpoints will refresh all the pod endpoints and create empty netpol references for new endpoints
/*
Key Assumption: a new pod event (w/ IP) cannot come before HNS knows (and can tell us) about the endpoint.

Просмотреть файл

@ -10,6 +10,8 @@ import (
"github.com/Azure/azure-container-networking/npm/metrics"
"github.com/Azure/azure-container-networking/npm/pkg/dataplane/ipsets"
dptestutils "github.com/Azure/azure-container-networking/npm/pkg/dataplane/testutils"
"github.com/Microsoft/hcsshim/hcn"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
@ -86,6 +88,68 @@ func TestMultiJobApplyInBackground(t *testing.T) {
testMultiJobCases(t, multiJobApplyInBackgroundTests(), time.Duration(1*time.Second))
}
func TestRemoveCommonEndpoints(t *testing.T) {
tests := []struct {
name string
endpoints []hcn.HostComputeEndpoint
endpointsAttached []hcn.HostComputeEndpoint
expected []hcn.HostComputeEndpoint
}{
{
name: "1 value same",
endpoints: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "123456"}, {Id: "560971"}},
endpointsAttached: []hcn.HostComputeEndpoint{{Id: "567890"}, {Id: "123456"}, {Id: "789012"}},
expected: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "123456"}, {Id: "560971"}, {Id: "567890"}, {Id: "789012"}},
},
{
name: "no values same",
endpoints: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "560971"}},
endpointsAttached: []hcn.HostComputeEndpoint{{Id: "567890"}, {Id: "789012"}},
expected: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "560971"}, {Id: "567890"}, {Id: "789012"}},
},
{
name: "1 value same",
endpoints: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "123456"}, {Id: "560971"}},
endpointsAttached: []hcn.HostComputeEndpoint{{Id: "567890"}, {Id: "123456"}, {Id: "789012"}},
expected: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "123456"}, {Id: "560971"}, {Id: "567890"}, {Id: "789012"}},
},
{
name: "two values same",
endpoints: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "560971"}, {Id: "123456"}, {Id: "789012"}},
endpointsAttached: []hcn.HostComputeEndpoint{{Id: "567890"}, {Id: "789012"}, {Id: "123456"}},
expected: []hcn.HostComputeEndpoint{{Id: "456901"}, {Id: "560971"}, {Id: "123456"}, {Id: "789012"}, {Id: "567890"}},
},
{
name: "no values",
endpoints: []hcn.HostComputeEndpoint{},
endpointsAttached: []hcn.HostComputeEndpoint{},
expected: []hcn.HostComputeEndpoint{},
},
{
name: "1 value - same",
endpoints: []hcn.HostComputeEndpoint{{Id: "456901"}},
endpointsAttached: []hcn.HostComputeEndpoint{{Id: "456901"}},
expected: []hcn.HostComputeEndpoint{{Id: "456901"}},
},
{
name: "1 value - different",
endpoints: []hcn.HostComputeEndpoint{{Id: "456901"}},
endpointsAttached: []hcn.HostComputeEndpoint{},
expected: []hcn.HostComputeEndpoint{{Id: "456901"}},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
result := GetUniqueEndpoints(tt.endpoints, tt.endpointsAttached)
if !cmp.Equal(tt.expected, result) {
t.Errorf("Test %s failed: expected %v, got %v", tt.name, tt.expected, result)
}
})
}
}
func testSerialCases(t *testing.T, tests []*SerialTestCase, finalSleep time.Duration) {
for i, tt := range tests {
i := i

Просмотреть файл

@ -17,15 +17,7 @@ func TestCreateAITelemetryHandle(t *testing.T) {
wantErr bool
}{
{
name: "disable telemetry",
aiConfig: aitelemetry.AIConfig{},
disableAll: false,
disableMetric: true,
disableTrace: true,
wantErr: true,
},
{
name: "empty aiconfig",
name: "disabled telemetry with empty aiconfig",
aiConfig: aitelemetry.AIConfig{},
disableAll: true,
disableMetric: true,

Просмотреть файл

@ -12,14 +12,15 @@ import (
"github.com/pkg/errors"
)
func runCommand(command string) (string, error) {
cmd := exec.Command("bash", "-c", command)
func runAzCommand(params ...string) (string, error) {
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
var err error
fmt.Println("Running Azure CLI command ", strings.Join(params, " "))
for i := 0; i < 3; i++ {
cmd := exec.Command("az", params...)
cmd.Stdout = &out
cmd.Stderr = &stderr
err = cmd.Run()
if err == nil {
break
@ -27,7 +28,7 @@ func runCommand(command string) (string, error) {
}
if err != nil {
return "", errors.Wrap(err, "command failed")
return "", errors.Wrap(err, "command failed "+stderr.String())
}
return out.String(), nil
@ -60,16 +61,14 @@ func main() {
os.Exit(1)
}
command := fmt.Sprintf("az vmss list -g %s --query '[0].name' -o tsv", resourceGroup)
result, err := runCommand(command)
result, err := runAzCommand("vmss", "list", "-g", resourceGroup, "--query", "[0].name", "-o", "tsv")
if err != nil {
fmt.Printf("Command failed with error: %s\n", err)
os.Exit(1)
}
vmssName := strings.TrimSpace(result)
command = fmt.Sprintf("az vmss show -g %s -n %s", resourceGroup, vmssName)
result, err = runCommand(command)
result, err = runAzCommand("vmss", "show", "-g", resourceGroup, "-n", vmssName)
if err != nil {
fmt.Printf("Command failed with error: %s\n", err)
os.Exit(1)
@ -104,8 +103,14 @@ func main() {
for i := 2; i <= secondaryConfigCount+1; i++ {
ipConfig := make(map[string]interface{})
for k, v := range primaryIPConfig {
// only the primary config needs loadBalancerBackendAddressPools. Azure doesn't allow
// secondary IP configs to be associated load balancer backend pools.
if k == "loadBalancerBackendAddressPools" {
continue
}
ipConfig[k] = v
}
ipConfigName := fmt.Sprintf("ipconfig%d", i)
if !contains(usedIPConfigNames, ipConfigName) {
ipConfig["name"] = ipConfigName
@ -125,20 +130,13 @@ func main() {
os.Exit(1)
}
escapedNetworkProfileJSON := strings.ReplaceAll(string(networkProfileJSON), `\`, `\\`)
escapedNetworkProfileJSON = strings.ReplaceAll(escapedNetworkProfileJSON, `'`, `\'`)
command = fmt.Sprintf("az vmss update -g %s -n %s --set virtualMachineProfile.networkProfile='%s'", resourceGroup, vmssName, escapedNetworkProfileJSON)
fmt.Println("Command to update VMSS: ", command)
_, err = runCommand(command)
_, err = runAzCommand("vmss", "update", "-g", resourceGroup, "-n", vmssName, "--set", fmt.Sprintf("virtualMachineProfile.networkProfile=%s", networkProfileJSON))
if err != nil {
fmt.Printf("Command failed with error: %s\n", err)
os.Exit(1)
}
command = fmt.Sprintf("az vmss update-instances -g %s -n %s --instance-ids '*'", resourceGroup, vmssName)
fmt.Println("Command to update VMSS instances: ", command)
_, err = runCommand(command)
_, err = runAzCommand("vmss", "update-instances", "-g", resourceGroup, "-n", vmssName, "--instance-ids", "*")
if err != nil {
fmt.Printf("Command failed with error: %s\n", err)
os.Exit(1)

Просмотреть файл

@ -42,12 +42,6 @@ spec:
operator: In
values:
- linux
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
k8s-app: cilium
topologyKey: kubernetes.io/hostname
containers:
- args:
- --config-dir=/tmp/cilium/config-map

Просмотреть файл

@ -42,12 +42,6 @@ spec:
operator: In
values:
- linux
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
k8s-app: cilium
topologyKey: kubernetes.io/hostname
containers:
- args:
- --config-dir=/tmp/cilium/config-map

Просмотреть файл

@ -42,12 +42,6 @@ spec:
operator: In
values:
- linux
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
k8s-app: cilium
topologyKey: kubernetes.io/hostname
containers:
- args:
- --config-dir=/tmp/cilium/config-map

Просмотреть файл

@ -43,12 +43,6 @@ spec:
operator: In
values:
- linux
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
k8s-app: cilium
topologyKey: kubernetes.io/hostname
containers:
- args:
- --config-dir=/tmp/cilium/config-map

Просмотреть файл

@ -43,12 +43,6 @@ spec:
operator: In
values:
- linux
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
k8s-app: cilium
topologyKey: kubernetes.io/hostname
containers:
- args:
- --config-dir=/tmp/cilium/config-map

Просмотреть файл

@ -13,5 +13,6 @@ data:
- 192.168.0.0/16
- 100.64.0.0/10
- 10.244.0.0/16
- 10.10.0.0/16
masqLinkLocal: false
masqLinkLocalIPv6: true

Просмотреть файл

@ -11,4 +11,5 @@ data:
- 192.168.0.0/16
- 100.64.0.0/10
- 10.244.0.0/16
- 10.10.0.0/16
masqLinkLocal: true