diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1c1bbf05b..35a37aa13 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -44,7 +44,7 @@ jobs: id: go - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index a462ff20d..f50123213 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -8,7 +8,7 @@ jobs: name: Check for spelling errors runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: codespell-project/actions-codespell@master with: check_filenames: true diff --git a/.github/workflows/darwin.yaml b/.github/workflows/darwin.yaml index 4e8c06025..83681c3f1 100644 --- a/.github/workflows/darwin.yaml +++ b/.github/workflows/darwin.yaml @@ -13,7 +13,7 @@ jobs: go-version: ^1.16 id: go - name: Check out code into the Go module directory - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build Test run: | make blob-darwin diff --git a/.github/workflows/linux.yaml b/.github/workflows/linux.yaml index c0dd05bcb..80cbaf9b4 100644 --- a/.github/workflows/linux.yaml +++ b/.github/workflows/linux.yaml @@ -16,7 +16,7 @@ jobs: id: go - name: Check out code into the Go module directory - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Run unit test run: | @@ -25,7 +25,7 @@ jobs: sudo dpkg -i packages-microsoft-prod.deb sudo apt-get update sudo apt-get install blobfuse - make verify + go test -covermode=count -coverprofile=profile.cov ./pkg/... - name: Run build test run: | diff --git a/.github/workflows/pluto.yaml b/.github/workflows/pluto.yaml index 648ff6855..48714f2f5 100644 --- a/.github/workflows/pluto.yaml +++ b/.github/workflows/pluto.yaml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Download pluto uses: FairwindsOps/pluto/github-action@master diff --git a/.github/workflows/shellcheck.yaml b/.github/workflows/shellcheck.yaml index 40ed2ce01..716f2f7d4 100644 --- a/.github/workflows/shellcheck.yaml +++ b/.github/workflows/shellcheck.yaml @@ -16,7 +16,7 @@ jobs: name: Shellcheck runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run ShellCheck uses: ludeeus/action-shellcheck@master env: diff --git a/.github/workflows/trivy.yaml b/.github/workflows/trivy.yaml index f7e5fb3d8..55c85e579 100644 --- a/.github/workflows/trivy.yaml +++ b/.github/workflows/trivy.yaml @@ -16,7 +16,7 @@ jobs: id: go - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build an image from Dockerfile run: | diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index 6846f120a..fbba0c715 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -16,7 +16,7 @@ jobs: go-version: ^1.16 id: go - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Build Test run: | make blob-windows diff --git a/.trivyignore b/.trivyignore new file mode 100644 index 000000000..b01025946 --- /dev/null +++ b/.trivyignore @@ -0,0 +1,2 @@ +CVE-2023-39325 +CVE-2023-44487 \ No newline at end of file diff --git a/Makefile b/Makefile index 2be3cd3f0..96e2f8c61 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ GIT_COMMIT ?= $(shell git rev-parse HEAD) REGISTRY ?= andyzhangx REGISTRY_NAME ?= $(shell echo $(REGISTRY) | sed "s/.azurecr.io//g") IMAGE_NAME ?= blob-csi -IMAGE_VERSION ?= v1.23.0 +IMAGE_VERSION ?= v1.24.0 CLOUD ?= AzurePublicCloud # Use a custom version for E2E tests if we are in Prow ifdef CI @@ -29,9 +29,10 @@ CSI_IMAGE_TAG ?= $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_VERSION) CSI_IMAGE_TAG_LATEST = $(REGISTRY)/$(IMAGE_NAME):latest BUILD_DATE ?= $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") LDFLAGS ?= "-X ${PKG}/pkg/blob.driverVersion=${IMAGE_VERSION} -X ${PKG}/pkg/blob.gitCommit=${GIT_COMMIT} -X ${PKG}/pkg/blob.buildDate=${BUILD_DATE} -s -w -extldflags '-static'" -E2E_HELM_OPTIONS ?= --set image.blob.pullPolicy=Always --set image.blob.repository=$(REGISTRY)/$(IMAGE_NAME) --set image.blob.tag=$(IMAGE_VERSION) --set driver.userAgentSuffix="e2e-test" ifdef ENABLE_BLOBFUSE_PROXY -override E2E_HELM_OPTIONS := $(E2E_HELM_OPTIONS) --set controller.logLevel=6 --set node.logLevel=6 --set node.enableBlobfuseProxy=true +E2E_HELM_OPTIONS ?= --set image.blob.pullPolicy=Always --set image.blob.repository=$(REGISTRY)/$(IMAGE_NAME) --set image.blob.tag=$(IMAGE_VERSION) --set driver.userAgentSuffix="e2e-test" --set controller.logLevel=6 --set node.logLevel=6 --set node.enableBlobfuseProxy=true +else +E2E_HELM_OPTIONS ?= --set image.blob.pullPolicy=Always --set image.blob.repository=$(REGISTRY)/$(IMAGE_NAME) --set image.blob.tag=$(IMAGE_VERSION) --set driver.userAgentSuffix="e2e-test" endif E2E_HELM_OPTIONS += ${EXTRA_HELM_OPTIONS} GO111MODULE = on @@ -111,13 +112,13 @@ blob: blobfuse-proxy blob-windows: CGO_ENABLED=0 GOOS=windows go build -a -ldflags ${LDFLAGS} -mod vendor -o _output/blobplugin.exe ./pkg/blobplugin -.PHONT: blob-darwin +.PHONY: blob-darwin blob-darwin: CGO_ENABLED=0 GOOS=darwin go build -a -ldflags ${LDFLAGS} -mod vendor -o _output/blobplugin ./pkg/blobplugin .PHONY: container container: blob - docker build -t $(CSI_IMAGE_TAG) --output=type=docker -f ./pkg/blobplugin/Dockerfile . + docker build -t $(CSI_IMAGE_TAG) --build-arg ARCH=$(ARCH) --output=type=docker -f ./pkg/blobplugin/Dockerfile . .PHONY: container-linux container-linux: @@ -182,4 +183,4 @@ delete-metrics-svc: .PHONY: blobfuse-proxy blobfuse-proxy: - CGO_ENABLED=0 GOOS=linux go build -mod vendor -ldflags="-s -w" -o _output/${ARCH}/blobfuse-proxy ./pkg/blobfuse-proxy + CGO_ENABLED=0 GOOS=linux GOARCH=$(ARCH) go build -mod vendor -ldflags="-s -w" -o _output/${ARCH}/blobfuse-proxy ./pkg/blobfuse-proxy diff --git a/OWNERS b/OWNERS index a73e0f9da..fc4341e98 100644 --- a/OWNERS +++ b/OWNERS @@ -1,6 +1,5 @@ reviewers: - andyzhangx -- ZeroMagic - cvvz approvers: diff --git a/README.md b/README.md index 57a545a1f..19669a415 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,12 @@ Disclaimer: Deploying this driver manually is not an officially supported Micros ### Project status: GA ### Container Images & Kubernetes Compatibility: -|driver version |Image | supported k8s version | built-in blobfuse v1 version | built-in blobfuse v2 version| -|----------------|------------------------------------------------------|-----------------------|------------------------------| ----------------------------| -|master branch |mcr.microsoft.com/k8s/csi/blob-csi:latest | 1.21+ | 1.4.5 | 2.0.3 | -|v1.22.0 |mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.0 | 1.21+ | 1.4.5 | 2.0.3 | -|v1.21.3 |mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.3 | 1.21+ | 1.4.5 | 2.0.3 | -|v1.20.2 |mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.20.2 | 1.21+ | 1.4.5 | 2.0.3 | +|driver version |Image | supported k8s version | +|----------------|------------------------------------------------------|-----------------------| +|master branch |mcr.microsoft.com/k8s/csi/blob-csi:latest | 1.21+ | +|v1.23.0 |mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.23.0 | 1.21+ | +|v1.22.2 |mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.2 | 1.21+ | +|v1.21.4 |mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.4 | 1.21+ | ### Driver parameters Please refer to `blob.csi.azure.com` [driver parameters](./docs/driver-parameters.md) @@ -47,7 +47,7 @@ This option does not depend on cloud provider config file, supports cross subscr > > To install specific blobfuse v2 version, run following command directly after driver is running on the agent node: > ```console -> kubectl patch daemonset csi-blob-node -n kube-system -p '{"spec":{"template":{"spec":{"initContainers":[{"env":[{"name":"INSTALL_BLOBFUSE2","value":"true"},{"name":"BLOBFUSE2_VERSION","value":"2.0.3"}],"name":"install-blobfuse-proxy"}]}}}}' +> kubectl patch daemonset csi-blob-node -n kube-system -p '{"spec":{"template":{"spec":{"initContainers":[{"env":[{"name":"INSTALL_BLOBFUSE2","value":"true"},{"name":"BLOBFUSE2_VERSION","value":"2.1.0"}],"name":"install-blobfuse-proxy"}]}}}}' > ``` > - install by [helm charts](./charts) @@ -57,7 +57,6 @@ This option does not depend on cloud provider config file, supports cross subscr - [Azure RedHat OpenShift](https://github.com/ezYakaEagle442/aro-pub-storage/blob/master/setup-store-CSI-driver-azure-blob.md) - install managed CSI driver on following platforms: - [AKS](https://learn.microsoft.com/en-us/azure/aks/azure-blob-csi) - - [Azure RedHat OpenShift](https://github.com/ezYakaEagle442/aro-pub-storage/blob/master/setup-store-CSI-driver-azure-blob.md) ### Usage - [Basic usage](./deploy/example/e2e_usage.md) diff --git a/charts/README.md b/charts/README.md index ccbe27c43..719149236 100644 --- a/charts/README.md +++ b/charts/README.md @@ -66,16 +66,16 @@ The following table lists the configurable parameters of the latest Azure Blob S | `image.blob.tag` | blob-csi-driver docker image tag | `latest` | | `image.blob.pullPolicy` | blob-csi-driver image pull policy | `IfNotPresent` | | `image.csiProvisioner.repository` | csi-provisioner docker image | `mcr.microsoft.com/oss/kubernetes-csi/csi-provisioner` | -| `image.csiProvisioner.tag` | csi-provisioner docker image tag | `v3.5.0` | +| `image.csiProvisioner.tag` | csi-provisioner docker image tag | `v3.6.1` | | `image.csiProvisioner.pullPolicy` | csi-provisioner image pull policy | `IfNotPresent` | | `image.livenessProbe.repository` | liveness-probe docker image | `mcr.microsoft.com/oss/kubernetes-csi/livenessprobe` | -| `image.livenessProbe.tag` | liveness-probe docker image tag | `v2.10.0` | +| `image.livenessProbe.tag` | liveness-probe docker image tag | `v2.11.0` | | `image.livenessProbe.pullPolicy` | liveness-probe image pull policy | `IfNotPresent` | | `image.nodeDriverRegistrar.repository` | csi-node-driver-registrar docker image | `mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar` | -| `image.nodeDriverRegistrar.tag` | csi-node-driver-registrar docker image tag | `v2.8.0` | +| `image.nodeDriverRegistrar.tag` | csi-node-driver-registrar docker image tag | `v2.9.0` | | `image.nodeDriverRegistrar.pullPolicy` | csi-node-driver-registrar image pull policy | `IfNotPresent` | | `image.csiResizer.repository` | csi-resizer docker image | `mcr.microsoft.com/oss/kubernetes-csi/csi-resizer` | -| `image.csiResizer.tag` | csi-resizer docker image tag | `v1.8.0` | +| `image.csiResizer.tag` | csi-resizer docker image tag | `v1.9.1` | | `image.csiResizer.pullPolicy` | csi-resizer image pull policy | `IfNotPresent` | | `imagePullSecrets` | Specify docker-registry secret names as an array | [] (does not add image pull secrets to deployed pods) | | `cloud` | the cloud environment the driver is running on | `AzurePublicCloud` | @@ -148,6 +148,7 @@ The following table lists the configurable parameters of the latest Azure Blob S | `linux.distro` | configure ssl certificates for different Linux distribution(available values: `debian`, `fedora`) | `debian` | `workloadIdentity.clientID` | client ID of workload identity | '' | `workloadIdentity.tenantID` | [optional] If the AAD application or user-assigned managed identity is not in the same tenant as the cluster then set tenantID with the AAD application or user-assigned managed identity tenant ID | '' +| `node.enableAznfsMount` | enable [AZNFS mount helper](https://github.com/Azure/AZNFS-mount/) for NFS protocol | true ## troubleshooting - Add `--wait -v=5 --debug` in `helm install` command to get detailed error diff --git a/charts/index.yaml b/charts/index.yaml index ffd769628..eec6e6a4a 100644 --- a/charts/index.yaml +++ b/charts/index.yaml @@ -2,26 +2,44 @@ apiVersion: v1 entries: blob-csi-driver: - apiVersion: v1 - appVersion: v1.22.0 - created: "2023-06-05T13:16:16.091696745Z" + appVersion: v1.23.0 + created: "2023-09-14T07:10:07.895401784Z" description: Azure Blob Storage CSI driver - digest: 174eaf21b8e1f5f5c8e3f67d75ae4e5570c5e577ba663e5aca2b588a10597fb9 + digest: 57151e21e33660522f25694bd8ae985e5e17c7ffe09904ad2af4025e8bf1da72 name: blob-csi-driver urls: - - https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/master/charts/v1.22.0/blob-csi-driver-v1.22.0.tgz - version: v1.22.0 + - https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/master/charts/v1.23.0/blob-csi-driver-v1.23.0.tgz + version: v1.23.0 - apiVersion: v1 - appVersion: v1.21.3 - created: "2023-06-05T13:16:16.091107597Z" + appVersion: v1.22.2 + created: "2023-09-14T07:10:07.894776849Z" description: Azure Blob Storage CSI driver - digest: 7598ef899e6fd53f8346cacba4093475647369a56b59f049b9a388590b0ffa0a + digest: 259e66dc12db7310fe1c51e49c964398e0a6b7d511133916dd7d25f748f0b791 name: blob-csi-driver urls: - - https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/master/charts/v1.21.3/blob-csi-driver-v1.21.3.tgz - version: v1.21.3 + - https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/master/charts/v1.22.2/blob-csi-driver-v1.22.2.tgz + version: v1.22.2 + - apiVersion: v1 + appVersion: v1.22.1 + created: "2023-09-14T07:10:07.894161608Z" + description: Azure Blob Storage CSI driver + digest: 8329d477d55c82f97bb09fb172c5f39a1677bedc13c7410bd93b306194516438 + name: blob-csi-driver + urls: + - https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/master/charts/v1.22.1/blob-csi-driver-v1.22.1.tgz + version: v1.22.1 + - apiVersion: v1 + appVersion: v1.21.4 + created: "2023-09-14T07:10:07.893545411Z" + description: Azure Blob Storage CSI driver + digest: e4fa13670caf6b0d3e9fefa55d100daa439cd7187dabd45318ab03c7d4b17710 + name: blob-csi-driver + urls: + - https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/master/charts/v1.21.4/blob-csi-driver-v1.21.4.tgz + version: v1.21.4 - apiVersion: v1 appVersion: v1.20.3 - created: "2023-06-05T13:16:16.090513561Z" + created: "2023-09-14T07:10:07.892937422Z" description: Azure Blob Storage CSI driver digest: 8c2c20547b2e0e1b39d2f2efd04c1bd778f14af5feae2bda86d722dac3c02643 name: blob-csi-driver @@ -30,7 +48,7 @@ entries: version: v1.20.3 - apiVersion: v1 appVersion: v1.19.5 - created: "2023-06-05T13:16:16.089251589Z" + created: "2023-09-14T07:10:07.891871785Z" description: Azure Blob Storage CSI driver digest: 183c3e5cd84b709f1455cc7c84ed5bd573e8a24149fd6442d38999835b0a1711 name: blob-csi-driver @@ -39,7 +57,7 @@ entries: version: v1.19.5 - apiVersion: v1 appVersion: v1.18.0 - created: "2023-06-05T13:16:16.088635557Z" + created: "2023-09-14T07:10:07.891255613Z" description: Azure Blob Storage CSI driver digest: 3eac15488da5be7d1e78431929f7cda35bceb1af3fe107ffbd84606e047c9204 name: blob-csi-driver @@ -48,7 +66,7 @@ entries: version: v1.18.0 - apiVersion: v1 appVersion: v1.17.0 - created: "2023-06-05T13:16:16.087855613Z" + created: "2023-09-14T07:10:07.8902352Z" description: Azure Blob Storage CSI driver digest: 22cfa17fc5e8d771ff8edd26729266a9a8ee55c0e150df85ef15698f7fe985e9 name: blob-csi-driver @@ -57,7 +75,7 @@ entries: version: v1.17.0 - apiVersion: v1 appVersion: v1.16.0 - created: "2023-06-05T13:16:16.087034393Z" + created: "2023-09-14T07:10:07.889144209Z" description: Azure Blob Storage CSI driver digest: bf6249c0e3e3d3d009d4c79ceb7fda9a56c0565b969de753628792ea3ea5ece8 name: blob-csi-driver @@ -66,7 +84,7 @@ entries: version: v1.16.0 - apiVersion: v1 appVersion: v1.15.0 - created: "2023-06-05T13:16:16.085140755Z" + created: "2023-09-14T07:10:07.888518009Z" description: Azure Blob Storage CSI driver digest: 8daa35cd4957695cb64b45da05a15b4020df5545a8ac44c4668dad4bba82c8a9 name: blob-csi-driver @@ -75,7 +93,7 @@ entries: version: v1.15.0 - apiVersion: v1 appVersion: v1.14.0 - created: "2023-06-05T13:16:16.08439763Z" + created: "2023-09-14T07:10:07.887919949Z" description: Azure Blob Storage CSI driver digest: 442bc579b231aab626b9e474e2c0ed3f101d47d61c99aa9a7f863af7ce268d9d name: blob-csi-driver @@ -84,7 +102,7 @@ entries: version: v1.14.0 - apiVersion: v1 appVersion: v1.13.0 - created: "2023-06-05T13:16:16.083657708Z" + created: "2023-09-14T07:10:07.887324297Z" description: Azure Blob Storage CSI driver digest: b577b0b771138109aa90eb09d56fc07273ca0b584a263ee8f789e35796279f31 name: blob-csi-driver @@ -93,7 +111,7 @@ entries: version: v1.13.0 - apiVersion: v1 appVersion: v1.12.0 - created: "2023-06-05T13:16:16.082881061Z" + created: "2023-09-14T07:10:07.886741071Z" description: Azure Blob Storage CSI driver digest: 124e87af2581b374b89a39940698620c23d3eae6dcee518d302461ffea93e9a8 name: blob-csi-driver @@ -102,7 +120,7 @@ entries: version: v1.12.0 - apiVersion: v1 appVersion: v1.11.0 - created: "2023-06-05T13:16:16.082130547Z" + created: "2023-09-14T07:10:07.886122719Z" description: Azure Blob Storage CSI driver digest: 07c4d76017491b3d0bdd70de90e814096938bf7916da0c149c3805294bd57560 name: blob-csi-driver @@ -111,7 +129,7 @@ entries: version: v1.11.0 - apiVersion: v1 appVersion: v1.10.0 - created: "2023-06-05T13:16:16.081374716Z" + created: "2023-09-14T07:10:07.88549666Z" description: Azure Blob Storage CSI driver digest: 79716efa958385adf57eb3570843e1b4512d8c801e8e070625e94264f3e917a9 name: blob-csi-driver @@ -120,7 +138,7 @@ entries: version: v1.10.0 - apiVersion: v1 appVersion: v1.9.0 - created: "2023-06-05T13:16:16.099821296Z" + created: "2023-09-14T07:10:07.900772998Z" description: Azure Blob Storage CSI driver digest: fca0b9215d3277346f68c643fb3ead75158971f0d1945ab01ec559196f3cf842 name: blob-csi-driver @@ -129,7 +147,7 @@ entries: version: v1.9.0 - apiVersion: v1 appVersion: v1.8.0 - created: "2023-06-05T13:16:16.099009651Z" + created: "2023-09-14T07:10:07.900207312Z" description: Azure Blob Storage CSI driver digest: 3b78e2ab4f33577c54d4f57276c824717d2ad2aa3741210e938fcaf927bc751f name: blob-csi-driver @@ -138,7 +156,7 @@ entries: version: v1.8.0 - apiVersion: v1 appVersion: v1.7.0 - created: "2023-06-05T13:16:16.09825268Z" + created: "2023-09-14T07:10:07.89963445Z" description: Azure Blob Storage CSI driver digest: 28da5b55c3d2689d6da85eb7da344385e9cb99bdb2af18c24fea93670abfe7ea name: blob-csi-driver @@ -147,7 +165,7 @@ entries: version: v1.7.0 - apiVersion: v1 appVersion: v1.6.0 - created: "2023-06-05T13:16:16.096418255Z" + created: "2023-09-14T07:10:07.899045279Z" description: Azure Blob Storage CSI driver digest: 6f24f2e6623f6f8862e47d4fbdf13b5f351ceec6bb9a4591ef7fc2fca9fc1eef name: blob-csi-driver @@ -156,7 +174,7 @@ entries: version: v1.6.0 - apiVersion: v1 appVersion: v1.5.0 - created: "2023-06-05T13:16:16.095690263Z" + created: "2023-09-14T07:10:07.898388106Z" description: Azure Blob Storage CSI driver digest: 95d14c9b70b319760d388ea47727c8c97e9287867a8852aeb67b7175b52fe8f5 name: blob-csi-driver @@ -165,7 +183,7 @@ entries: version: v1.5.0 - apiVersion: v1 appVersion: v1.4.1 - created: "2023-06-05T13:16:16.094993568Z" + created: "2023-09-14T07:10:07.89687391Z" description: Azure Blob Storage CSI driver digest: 5fcf69c449f065fa1d5722e5a7fed8a28000efa790907e9ff4b552c5fbd16d22 name: blob-csi-driver @@ -174,7 +192,7 @@ entries: version: v1.4.1 - apiVersion: v1 appVersion: v1.4.0 - created: "2023-06-05T13:16:16.094196456Z" + created: "2023-09-14T07:10:07.896376484Z" description: Azure Blob Storage CSI driver digest: b466543344a6411f6130ba87b093955d39ab8614c6b4ed8505a0a0c96073cb33 name: blob-csi-driver @@ -183,7 +201,7 @@ entries: version: v1.4.0 - apiVersion: v1 appVersion: v1.3.0 - created: "2023-06-05T13:16:16.092364577Z" + created: "2023-09-14T07:10:07.89587395Z" description: Azure Blob Storage CSI driver digest: 58d02cb70a3a966b349d62e880b7149fb06ac009474e35e580784fd3c98a5b07 name: blob-csi-driver @@ -192,7 +210,7 @@ entries: version: v1.3.0 - apiVersion: v1 appVersion: v1.2.0 - created: "2023-06-05T13:16:16.089912329Z" + created: "2023-09-14T07:10:07.892325402Z" description: Azure Blob Storage CSI driver digest: 27fb89f20b5fddc7329e6d7c2374857b22c1d61592e397a53f47121eea68c344 name: blob-csi-driver @@ -201,7 +219,7 @@ entries: version: v1.2.0 - apiVersion: v1 appVersion: v1.1.0 - created: "2023-06-05T13:16:16.080623443Z" + created: "2023-09-14T07:10:07.884828709Z" description: Azure Blob Storage CSI driver digest: a251a55243de207c69ef53f72abee45e93b72fa4fc43dc204b7f1cdfd459acdb name: blob-csi-driver @@ -210,7 +228,7 @@ entries: version: v1.1.0 - apiVersion: v1 appVersion: v1.0.0 - created: "2023-06-05T13:16:16.080003074Z" + created: "2023-09-14T07:10:07.884368201Z" description: Azure Blob Storage CSI driver digest: e83f037a165eafc83a978bd7e6bf6221b052ac34363aecb12e6a73607dc58b89 name: blob-csi-driver @@ -264,7 +282,7 @@ entries: version: v4.3.0 - apiVersion: v1 appVersion: latest - created: "2023-06-05T13:16:16.079514405Z" + created: "2023-09-14T07:10:07.884046607Z" description: Azure Blob Storage CSI driver digest: fe19afaa31f86ee3902c3e85e98f2f42b205756959df68665c29e8b1845d1120 name: blob-csi-driver diff --git a/charts/v1.21.3/blob-csi-driver-v1.21.3.tgz b/charts/v1.21.3/blob-csi-driver-v1.21.3.tgz deleted file mode 100644 index 482e9f34f..000000000 Binary files a/charts/v1.21.3/blob-csi-driver-v1.21.3.tgz and /dev/null differ diff --git a/charts/v1.21.4/blob-csi-driver-v1.21.4.tgz b/charts/v1.21.4/blob-csi-driver-v1.21.4.tgz new file mode 100644 index 000000000..3e3284dd9 Binary files /dev/null and b/charts/v1.21.4/blob-csi-driver-v1.21.4.tgz differ diff --git a/charts/v1.22.0/blob-csi-driver/Chart.yaml b/charts/v1.21.4/blob-csi-driver/Chart.yaml similarity index 68% rename from charts/v1.22.0/blob-csi-driver/Chart.yaml rename to charts/v1.21.4/blob-csi-driver/Chart.yaml index 0f2ce14f8..ecff5b139 100644 --- a/charts/v1.22.0/blob-csi-driver/Chart.yaml +++ b/charts/v1.21.4/blob-csi-driver/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: v1.22.0 +appVersion: v1.21.4 description: Azure Blob Storage CSI driver name: blob-csi-driver -version: v1.22.0 +version: v1.21.4 diff --git a/charts/v1.21.3/blob-csi-driver/templates/NOTES.txt b/charts/v1.21.4/blob-csi-driver/templates/NOTES.txt similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/NOTES.txt rename to charts/v1.21.4/blob-csi-driver/templates/NOTES.txt diff --git a/charts/v1.21.3/blob-csi-driver/templates/_helpers.tpl b/charts/v1.21.4/blob-csi-driver/templates/_helpers.tpl similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/_helpers.tpl rename to charts/v1.21.4/blob-csi-driver/templates/_helpers.tpl diff --git a/charts/v1.21.3/blob-csi-driver/templates/csi-blob-controller.yaml b/charts/v1.21.4/blob-csi-driver/templates/csi-blob-controller.yaml similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/csi-blob-controller.yaml rename to charts/v1.21.4/blob-csi-driver/templates/csi-blob-controller.yaml diff --git a/charts/v1.21.3/blob-csi-driver/templates/csi-blob-driver.yaml b/charts/v1.21.4/blob-csi-driver/templates/csi-blob-driver.yaml similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/csi-blob-driver.yaml rename to charts/v1.21.4/blob-csi-driver/templates/csi-blob-driver.yaml diff --git a/charts/v1.21.3/blob-csi-driver/templates/csi-blob-node.yaml b/charts/v1.21.4/blob-csi-driver/templates/csi-blob-node.yaml similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/csi-blob-node.yaml rename to charts/v1.21.4/blob-csi-driver/templates/csi-blob-node.yaml diff --git a/charts/v1.21.3/blob-csi-driver/templates/rbac-csi-blob-controller.yaml b/charts/v1.21.4/blob-csi-driver/templates/rbac-csi-blob-controller.yaml similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/rbac-csi-blob-controller.yaml rename to charts/v1.21.4/blob-csi-driver/templates/rbac-csi-blob-controller.yaml diff --git a/charts/v1.21.3/blob-csi-driver/templates/rbac-csi-blob-node.yaml b/charts/v1.21.4/blob-csi-driver/templates/rbac-csi-blob-node.yaml similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/rbac-csi-blob-node.yaml rename to charts/v1.21.4/blob-csi-driver/templates/rbac-csi-blob-node.yaml diff --git a/charts/v1.21.3/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml b/charts/v1.21.4/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml rename to charts/v1.21.4/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml diff --git a/charts/v1.21.3/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml b/charts/v1.21.4/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml similarity index 100% rename from charts/v1.21.3/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml rename to charts/v1.21.4/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml diff --git a/charts/v1.21.3/blob-csi-driver/values.yaml b/charts/v1.21.4/blob-csi-driver/values.yaml similarity index 99% rename from charts/v1.21.3/blob-csi-driver/values.yaml rename to charts/v1.21.4/blob-csi-driver/values.yaml index 633956169..7b3a958a5 100644 --- a/charts/v1.21.3/blob-csi-driver/values.yaml +++ b/charts/v1.21.4/blob-csi-driver/values.yaml @@ -2,7 +2,7 @@ image: baseRepo: mcr.microsoft.com blob: repository: /oss/kubernetes-csi/blob-csi - tag: v1.21.3 + tag: v1.21.4 pullPolicy: IfNotPresent csiProvisioner: repository: /oss/kubernetes-csi/csi-provisioner diff --git a/charts/v1.22.0/blob-csi-driver-v1.22.0.tgz b/charts/v1.22.0/blob-csi-driver-v1.22.0.tgz deleted file mode 100644 index 256fde9e9..000000000 Binary files a/charts/v1.22.0/blob-csi-driver-v1.22.0.tgz and /dev/null differ diff --git a/charts/v1.22.1/blob-csi-driver-v1.22.1.tgz b/charts/v1.22.1/blob-csi-driver-v1.22.1.tgz new file mode 100644 index 000000000..ac29c7e24 Binary files /dev/null and b/charts/v1.22.1/blob-csi-driver-v1.22.1.tgz differ diff --git a/charts/v1.21.3/blob-csi-driver/Chart.yaml b/charts/v1.22.1/blob-csi-driver/Chart.yaml similarity index 68% rename from charts/v1.21.3/blob-csi-driver/Chart.yaml rename to charts/v1.22.1/blob-csi-driver/Chart.yaml index da2b8cf78..0dcede6d1 100644 --- a/charts/v1.21.3/blob-csi-driver/Chart.yaml +++ b/charts/v1.22.1/blob-csi-driver/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: v1.21.3 +appVersion: v1.22.1 description: Azure Blob Storage CSI driver name: blob-csi-driver -version: v1.21.3 +version: v1.22.1 diff --git a/charts/v1.22.0/blob-csi-driver/templates/NOTES.txt b/charts/v1.22.1/blob-csi-driver/templates/NOTES.txt similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/NOTES.txt rename to charts/v1.22.1/blob-csi-driver/templates/NOTES.txt diff --git a/charts/v1.22.0/blob-csi-driver/templates/_helpers.tpl b/charts/v1.22.1/blob-csi-driver/templates/_helpers.tpl similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/_helpers.tpl rename to charts/v1.22.1/blob-csi-driver/templates/_helpers.tpl diff --git a/charts/v1.22.0/blob-csi-driver/templates/csi-blob-controller.yaml b/charts/v1.22.1/blob-csi-driver/templates/csi-blob-controller.yaml similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/csi-blob-controller.yaml rename to charts/v1.22.1/blob-csi-driver/templates/csi-blob-controller.yaml diff --git a/charts/v1.22.0/blob-csi-driver/templates/csi-blob-driver.yaml b/charts/v1.22.1/blob-csi-driver/templates/csi-blob-driver.yaml similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/csi-blob-driver.yaml rename to charts/v1.22.1/blob-csi-driver/templates/csi-blob-driver.yaml diff --git a/charts/v1.22.0/blob-csi-driver/templates/csi-blob-node.yaml b/charts/v1.22.1/blob-csi-driver/templates/csi-blob-node.yaml similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/csi-blob-node.yaml rename to charts/v1.22.1/blob-csi-driver/templates/csi-blob-node.yaml diff --git a/charts/v1.22.0/blob-csi-driver/templates/rbac-csi-blob-controller.yaml b/charts/v1.22.1/blob-csi-driver/templates/rbac-csi-blob-controller.yaml similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/rbac-csi-blob-controller.yaml rename to charts/v1.22.1/blob-csi-driver/templates/rbac-csi-blob-controller.yaml diff --git a/charts/v1.22.0/blob-csi-driver/templates/rbac-csi-blob-node.yaml b/charts/v1.22.1/blob-csi-driver/templates/rbac-csi-blob-node.yaml similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/rbac-csi-blob-node.yaml rename to charts/v1.22.1/blob-csi-driver/templates/rbac-csi-blob-node.yaml diff --git a/charts/v1.22.0/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml b/charts/v1.22.1/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml rename to charts/v1.22.1/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml diff --git a/charts/v1.22.0/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml b/charts/v1.22.1/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml similarity index 100% rename from charts/v1.22.0/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml rename to charts/v1.22.1/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml diff --git a/charts/v1.22.0/blob-csi-driver/values.yaml b/charts/v1.22.1/blob-csi-driver/values.yaml similarity index 99% rename from charts/v1.22.0/blob-csi-driver/values.yaml rename to charts/v1.22.1/blob-csi-driver/values.yaml index 1247f915b..aa4ce22b0 100644 --- a/charts/v1.22.0/blob-csi-driver/values.yaml +++ b/charts/v1.22.1/blob-csi-driver/values.yaml @@ -2,7 +2,7 @@ image: baseRepo: mcr.microsoft.com blob: repository: /oss/kubernetes-csi/blob-csi - tag: v1.22.0 + tag: v1.22.1 pullPolicy: IfNotPresent csiProvisioner: repository: /oss/kubernetes-csi/csi-provisioner diff --git a/charts/v1.22.2/blob-csi-driver-v1.22.2.tgz b/charts/v1.22.2/blob-csi-driver-v1.22.2.tgz new file mode 100644 index 000000000..b05e9a6a0 Binary files /dev/null and b/charts/v1.22.2/blob-csi-driver-v1.22.2.tgz differ diff --git a/charts/v1.22.2/blob-csi-driver/Chart.yaml b/charts/v1.22.2/blob-csi-driver/Chart.yaml new file mode 100644 index 000000000..7534d091c --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: v1.22.2 +description: Azure Blob Storage CSI driver +name: blob-csi-driver +version: v1.22.2 diff --git a/charts/v1.22.2/blob-csi-driver/templates/NOTES.txt b/charts/v1.22.2/blob-csi-driver/templates/NOTES.txt new file mode 100644 index 000000000..9ad135dd4 --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/NOTES.txt @@ -0,0 +1,5 @@ +The Azure Blob Storage CSI driver is getting deployed to your cluster. + +To check Azure Blob Storage CSI driver pods status, please run: + + kubectl --namespace={{ .Release.Namespace }} get pods --selector="release={{ .Release.Name }}" --watch diff --git a/charts/v1.22.2/blob-csi-driver/templates/_helpers.tpl b/charts/v1.22.2/blob-csi-driver/templates/_helpers.tpl new file mode 100644 index 000000000..d99392f32 --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* Expand the name of the chart.*/}} +{{- define "blob.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "blob.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common selectors. +*/}} +{{- define "blob.selectorLabels" -}} +app.kubernetes.io/name: {{ template "blob.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Common labels. +*/}} +{{- define "blob.labels" -}} +{{- include "blob.selectorLabels" . }} +app.kubernetes.io/component: csi-driver +app.kubernetes.io/part-of: {{ template "blob.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +helm.sh/chart: {{ template "blob.chart" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels }} +{{- end }} +{{- end -}} + + +{{/* pull secrets for containers */}} +{{- define "blob.pullSecrets" -}} +{{- if .Values.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/v1.22.2/blob-csi-driver/templates/csi-blob-controller.yaml b/charts/v1.22.2/blob-csi-driver/templates/csi-blob-controller.yaml new file mode 100644 index 000000000..6f1c552ae --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/csi-blob-controller.yaml @@ -0,0 +1,215 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: {{ .Values.controller.name }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.controller.name }} + {{- include "blob.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.controller.replicas }} + selector: + matchLabels: + app: {{ .Values.controller.name }} + {{- include "blob.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + app: {{ .Values.controller.name }} + {{- include "blob.labels" . | nindent 8 }} + {{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + {{- end }} + {{- if .Values.podLabels }} +{{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} +{{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- with .Values.controller.affinity }} + affinity: +{{ toYaml . | indent 8 }} +{{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + hostNetwork: {{ .Values.controller.hostNetwork }} + serviceAccountName: {{ .Values.serviceAccount.controller }} + nodeSelector: + kubernetes.io/os: linux + {{- if .Values.controller.runOnMaster}} + node-role.kubernetes.io/master: "" + {{- end}} + {{- if .Values.controller.runOnControlPlane}} + node-role.kubernetes.io/control-plane: "" + {{- end}} +{{- with .Values.controller.nodeSelector }} +{{ toYaml . | indent 8 }} +{{- end }} + priorityClassName: {{ .Values.priorityClassName | quote }} + securityContext: + seccompProfile: + type: RuntimeDefault +{{- with .Values.controller.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} + containers: + - name: csi-provisioner +{{- if hasPrefix "/" .Values.image.csiProvisioner.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiProvisioner.repository }}:{{ .Values.image.csiProvisioner.tag }}" +{{- else }} + image: "{{ .Values.image.csiProvisioner.repository }}:{{ .Values.image.csiProvisioner.tag }}" +{{- end }} + args: + - "-v=2" + - "--csi-address=$(ADDRESS)" + - "--leader-election" + - "--leader-election-namespace={{ .Release.Namespace }}" + - "--timeout=120s" + - "--extra-create-metadata=true" + - "--kube-api-qps=50" + - "--kube-api-burst=100" + env: + - name: ADDRESS + value: /csi/csi.sock + imagePullPolicy: {{ .Values.image.csiProvisioner.pullPolicy }} + volumeMounts: + - mountPath: /csi + name: socket-dir + resources: {{- toYaml .Values.controller.resources.csiProvisioner | nindent 12 }} + - name: liveness-probe +{{- if hasPrefix "/" .Values.image.livenessProbe.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- else }} + image: "{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- end }} + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port={{ .Values.controller.livenessProbe.healthPort }} + imagePullPolicy: {{ .Values.image.livenessProbe.pullPolicy }} + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: {{- toYaml .Values.controller.resources.livenessProbe | nindent 12 }} + - name: blob +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + args: + - "--v={{ .Values.controller.logLevel }}" + - "--endpoint=$(CSI_ENDPOINT)" + - "--metrics-address=0.0.0.0:{{ .Values.controller.metricsPort }}" + - "--drivername={{ .Values.driver.name }}" + - "--custom-user-agent={{ .Values.driver.customUserAgent }}" + - "--user-agent-suffix={{ .Values.driver.userAgentSuffix }}" + - "--cloud-config-secret-name={{ .Values.controller.cloudConfigSecretName }}" + - "--cloud-config-secret-namespace={{ .Values.controller.cloudConfigSecretNamespace }}" + - "--allow-empty-cloud-config={{ .Values.controller.allowEmptyCloudConfig }}" + ports: + - containerPort: {{ .Values.controller.livenessProbe.healthPort }} + name: healthz + protocol: TCP + - containerPort: {{ .Values.controller.metricsPort }} + name: metrics + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + {{- if ne .Values.driver.httpsProxy "" }} + - name: HTTPS_PROXY + value: {{ .Values.driver.httpsProxy }} + {{- end }} + {{- if ne .Values.driver.httpProxy "" }} + - name: HTTP_PROXY + value: {{ .Values.driver.httpProxy }} + {{- end }} + - name: AZURE_GO_SDK_LOG_LEVEL + value: {{ .Values.driver.azureGoSDKLogLevel }} + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: AZURE_ENVIRONMENT_FILEPATH + value: /etc/kubernetes/azurestackcloud.json + {{- end }} + imagePullPolicy: {{ .Values.image.blob.pullPolicy }} + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + - name: ssl-pki + mountPath: /etc/pki/ca-trust/extracted + readOnly: true + {{- end }} + resources: {{- toYaml .Values.controller.resources.blob | nindent 12 }} + - name: csi-resizer +{{- if hasPrefix "/" .Values.image.csiResizer.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}" +{{- else }} + image: "{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}" +{{- end }} + args: + - "-csi-address=$(ADDRESS)" + - "-v=2" + - "-leader-election" + - "--leader-election-namespace={{ .Release.Namespace }}" + - '-handle-volume-inuse-error=false' + env: + - name: ADDRESS + value: /csi/csi.sock + imagePullPolicy: {{ .Values.image.csiResizer.pullPolicy }} + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: {{- toYaml .Values.controller.resources.csiResizer | nindent 12 }} + volumes: + - name: socket-dir + emptyDir: {} + - name: azure-cred + hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + - name: ssl-pki + hostPath: + path: /etc/pki/ca-trust/extracted + {{- end }} + {{- if .Values.securityContext }} + securityContext: {{- toYaml .Values.securityContext | nindent 8 }} + {{- end }} diff --git a/charts/v1.22.2/blob-csi-driver/templates/csi-blob-driver.yaml b/charts/v1.22.2/blob-csi-driver/templates/csi-blob-driver.yaml new file mode 100644 index 000000000..9a6aea64a --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/csi-blob-driver.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: storage.k8s.io/v1 +kind: CSIDriver +metadata: + name: {{ .Values.driver.name }} + labels: + {{- include "blob.labels" . | nindent 4 }} +spec: + attachRequired: false + podInfoOnMount: true + fsGroupPolicy: {{ .Values.feature.fsGroupPolicy }} + volumeLifecycleModes: + - Persistent + - Ephemeral diff --git a/charts/v1.22.2/blob-csi-driver/templates/csi-blob-node.yaml b/charts/v1.22.2/blob-csi-driver/templates/csi-blob-node.yaml new file mode 100644 index 000000000..f7b6a48f3 --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/csi-blob-node.yaml @@ -0,0 +1,316 @@ +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: {{ .Values.node.name }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.node.name }} + {{- include "blob.labels" . | nindent 4 }} +spec: + updateStrategy: + rollingUpdate: + maxUnavailable: {{ .Values.node.maxUnavailable }} + type: RollingUpdate + selector: + matchLabels: + app: {{ .Values.node.name }} + {{- include "blob.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + app: {{ .Values.node.name }} + {{- include "blob.labels" . | nindent 8 }} + {{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + {{- end }} + {{- if .Values.podLabels }} +{{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} +{{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} +{{- end }} + spec: + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + {{- if or .Values.node.enableBlobfuseProxy .Values.node.enableAznfsMount }} + hostPID: true + {{- end }} + hostNetwork: true + dnsPolicy: Default + serviceAccountName: {{ .Values.serviceAccount.node }} + nodeSelector: + kubernetes.io/os: linux +{{- with .Values.node.nodeSelector }} +{{ toYaml . | indent 8 }} +{{- end }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: type + operator: NotIn + values: + - virtual-kubelet + {{- if .Values.node.affinity }} +{{- toYaml .Values.node.affinity | nindent 8 }} + {{- end }} + priorityClassName: {{ .Values.priorityClassName | quote }} + securityContext: + seccompProfile: + type: RuntimeDefault +{{- with .Values.node.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} +{{- if .Values.node.enableBlobfuseProxy }} + initContainers: + - name: install-blobfuse-proxy +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + imagePullPolicy: IfNotPresent + command: + - "/blobfuse-proxy/init.sh" + securityContext: + privileged: true + env: + - name: DEBIAN_FRONTEND + value: "noninteractive" + - name: INSTALL_BLOBFUSE + value: "{{ .Values.node.blobfuseProxy.installBlobfuse }}" + - name: BLOBFUSE_VERSION + value: "{{ .Values.node.blobfuseProxy.blobfuseVersion }}" + - name: INSTALL_BLOBFUSE2 + value: "{{ .Values.node.blobfuseProxy.installBlobfuse2 }}" + - name: BLOBFUSE2_VERSION + value: "{{ .Values.node.blobfuseProxy.blobfuse2Version }}" + - name: SET_MAX_OPEN_FILE_NUM + value: "{{ .Values.node.blobfuseProxy.setMaxOpenFileNum }}" + - name: MAX_FILE_NUM + value: "{{ .Values.node.blobfuseProxy.maxOpenFileNum }}" + - name: DISABLE_UPDATEDB + value: "{{ .Values.node.blobfuseProxy.disableUpdateDB }}" + volumeMounts: + - name: host-usr + mountPath: /host/usr + - name: host-etc + mountPath: /host/etc +{{- end }} + containers: + - name: liveness-probe + imagePullPolicy: {{ .Values.image.livenessProbe.pullPolicy }} + volumeMounts: + - mountPath: /csi + name: socket-dir +{{- if hasPrefix "/" .Values.image.livenessProbe.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- else }} + image: "{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- end }} + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port={{ .Values.node.livenessProbe.healthPort }} + - --v=2 + resources: {{- toYaml .Values.node.resources.livenessProbe | nindent 12 }} + - name: node-driver-registrar +{{- if hasPrefix "/" .Values.image.nodeDriverRegistrar.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.nodeDriverRegistrar.repository }}:{{ .Values.image.nodeDriverRegistrar.tag }}" +{{- else }} + image: "{{ .Values.image.nodeDriverRegistrar.repository }}:{{ .Values.image.nodeDriverRegistrar.tag }}" +{{- end }} + args: + - --csi-address=$(ADDRESS) + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --v=2 + livenessProbe: + exec: + command: + - /csi-node-driver-registrar + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --mode=kubelet-registration-probe + initialDelaySeconds: 30 + timeoutSeconds: 15 + env: + - name: ADDRESS + value: /csi/csi.sock + - name: DRIVER_REG_SOCK_PATH + value: {{ .Values.linux.kubelet }}/plugins/{{ .Values.driver.name }}/csi.sock + volumeMounts: + - name: socket-dir + mountPath: /csi + - name: registration-dir + mountPath: /registration + resources: {{- toYaml .Values.node.resources.nodeDriverRegistrar | nindent 12 }} + - name: blob +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + args: + - "--v={{ .Values.node.logLevel }}" + - "--endpoint=$(CSI_ENDPOINT)" + - "--blobfuse-proxy-endpoint=$(BLOBFUSE_PROXY_ENDPOINT)" + - "--enable-blobfuse-proxy={{ .Values.node.enableBlobfuseProxy }}" + - "--nodeid=$(KUBE_NODE_NAME)" + - "--drivername={{ .Values.driver.name }}" + - "--cloud-config-secret-name={{ .Values.node.cloudConfigSecretName }}" + - "--cloud-config-secret-namespace={{ .Values.node.cloudConfigSecretNamespace }}" + - "--custom-user-agent={{ .Values.driver.customUserAgent }}" + - "--user-agent-suffix={{ .Values.driver.userAgentSuffix }}" + - "--allow-empty-cloud-config={{ .Values.node.allowEmptyCloudConfig }}" + - "--enable-get-volume-stats={{ .Values.feature.enableGetVolumeStats }}" + - "--append-timestamp-cache-dir={{ .Values.node.appendTimeStampInCacheDir }}" + - "--mount-permissions={{ .Values.node.mountPermissions }}" + - "--allow-inline-volume-key-access-with-idenitity={{ .Values.node.allowInlineVolumeKeyAccessWithIdentity }}" + - "--enable-aznfs-mount={{ .Values.node.enableAznfsMount }}" + ports: + - containerPort: {{ .Values.node.livenessProbe.healthPort }} + name: healthz + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + - name: BLOBFUSE_PROXY_ENDPOINT + value: unix:///csi/blobfuse-proxy.sock + {{- if ne .Values.driver.httpsProxy "" }} + - name: HTTPS_PROXY + value: {{ .Values.driver.httpsProxy }} + {{- end }} + {{- if ne .Values.driver.httpProxy "" }} + - name: HTTP_PROXY + value: {{ .Values.driver.httpProxy }} + {{- end }} + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: AZURE_GO_SDK_LOG_LEVEL + value: {{ .Values.driver.azureGoSDKLogLevel }} + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: AZURE_ENVIRONMENT_FILEPATH + value: /etc/kubernetes/azurestackcloud.json + {{- end }} + imagePullPolicy: {{ .Values.image.blob.pullPolicy }} + securityContext: + privileged: true + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: {{ .Values.linux.kubelet }}/ + mountPropagation: Bidirectional + name: mountpoint-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + - mountPath: /mnt + name: blob-cache + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + - name: ssl-pki + mountPath: /etc/pki/ca-trust/extracted + readOnly: true + {{- end }} + {{- if .Values.node.enableAznfsMount }} + - mountPath: /opt/microsoft/aznfs/data + name: aznfs-data + {{- end }} + resources: {{- toYaml .Values.node.resources.blob | nindent 12 }} +{{- if .Values.node.enableAznfsMount }} + - name: aznfswatchdog +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + command: + - "aznfswatchdog" + imagePullPolicy: {{ .Values.image.blob.pullPolicy }} + securityContext: + privileged: true + resources: {{- toYaml .Values.node.resources.aznfswatchdog | nindent 12 }} + volumeMounts: + - mountPath: /opt/microsoft/aznfs/data + name: aznfs-data + - mountPath: {{ .Values.linux.kubelet }}/ + mountPropagation: Bidirectional + name: mountpoint-dir +{{- end }} + volumes: +{{- if .Values.node.enableBlobfuseProxy }} + - name: host-usr + hostPath: + path: /usr + - name: host-etc + hostPath: + path: /etc +{{- end }} + - hostPath: + path: {{ .Values.linux.kubelet }}/plugins/{{ .Values.driver.name }} + type: DirectoryOrCreate + name: socket-dir + - hostPath: + path: {{ .Values.linux.kubelet }}/ + type: DirectoryOrCreate + name: mountpoint-dir + - hostPath: + path: {{ .Values.linux.kubelet }}/plugins_registry/ + type: DirectoryOrCreate + name: registration-dir + - hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate + name: azure-cred + - hostPath: + path: {{ .Values.node.blobfuseCachePath }} + name: blob-cache + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + - name: ssl-pki + hostPath: + path: /etc/pki/ca-trust/extracted + {{- end }} + {{- if .Values.node.enableAznfsMount }} + - hostPath: + path: /opt/microsoft/aznfs/data + type: DirectoryOrCreate + name: aznfs-data + {{- end }} + {{- if .Values.securityContext }} + securityContext: {{- toYaml .Values.securityContext | nindent 8 }} + {{- end }} diff --git a/charts/v1.22.2/blob-csi-driver/templates/rbac-csi-blob-controller.yaml b/charts/v1.22.2/blob-csi-driver/templates/rbac-csi-blob-controller.yaml new file mode 100644 index 000000000..833dcc640 --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/rbac-csi-blob-controller.yaml @@ -0,0 +1,115 @@ +{{- if .Values.rbac.create -}} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-external-provisioner-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "create", "delete"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "update"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: ["storage.k8s.io"] + resources: ["csinodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-csi-provisioner-binding + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ .Values.rbac.name }}-external-provisioner-role + apiGroup: rbac.authorization.k8s.io + +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-external-resizer-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "update", "patch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims/status"] + verbs: ["update", "patch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["list", "watch", "create", "update", "patch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-csi-resizer-role + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ .Values.rbac.name }}-external-resizer-role + apiGroup: rbac.authorization.k8s.io + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-controller-secret-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-controller-secret-binding + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: csi-{{ .Values.rbac.name }}-controller-secret-role + apiGroup: rbac.authorization.k8s.io +{{ end }} diff --git a/charts/v1.22.2/blob-csi-driver/templates/rbac-csi-blob-node.yaml b/charts/v1.22.2/blob-csi-driver/templates/rbac-csi-blob-node.yaml new file mode 100644 index 000000000..c041cf8db --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/rbac-csi-blob-node.yaml @@ -0,0 +1,29 @@ +{{- if .Values.rbac.create -}} +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-node-secret-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-node-secret-binding + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.node }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: csi-{{ .Values.rbac.name }}-node-secret-role + apiGroup: rbac.authorization.k8s.io +{{ end }} diff --git a/charts/v1.22.2/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml b/charts/v1.22.2/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml new file mode 100644 index 000000000..7433bccf1 --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "blob.labels" . | nindent 4 }} +{{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + annotations: + azure.workload.identity/client-id: {{ .Values.workloadIdentity.clientID }} +{{- if .Values.workloadIdentity.tenantID }} + azure.workload.identity/tenant-id: {{ .Values.workloadIdentity.tenantID }} +{{- end }} +{{- end }} +{{- end -}} diff --git a/charts/v1.22.2/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml b/charts/v1.22.2/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml new file mode 100644 index 000000000..a25090e30 --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.node }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "blob.labels" . | nindent 4 }} +{{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + annotations: + azure.workload.identity/client-id: {{ .Values.workloadIdentity.clientID }} +{{- if .Values.workloadIdentity.tenantID }} + azure.workload.identity/tenant-id: {{ .Values.workloadIdentity.tenantID }} +{{- end }} +{{- end }} +{{- end -}} diff --git a/charts/v1.22.2/blob-csi-driver/values.yaml b/charts/v1.22.2/blob-csi-driver/values.yaml new file mode 100644 index 000000000..30b43cc8b --- /dev/null +++ b/charts/v1.22.2/blob-csi-driver/values.yaml @@ -0,0 +1,180 @@ +image: + baseRepo: mcr.microsoft.com + blob: + repository: /oss/kubernetes-csi/blob-csi + tag: v1.22.2 + pullPolicy: IfNotPresent + csiProvisioner: + repository: /oss/kubernetes-csi/csi-provisioner + tag: v3.5.0 + pullPolicy: IfNotPresent + livenessProbe: + repository: /oss/kubernetes-csi/livenessprobe + tag: v2.10.0 + pullPolicy: IfNotPresent + nodeDriverRegistrar: + repository: /oss/kubernetes-csi/csi-node-driver-registrar + tag: v2.8.0 + pullPolicy: IfNotPresent + csiResizer: + repository: /oss/kubernetes-csi/csi-resizer + tag: v1.8.0 + pullPolicy: IfNotPresent + +cloud: AzurePublicCloud + +## Reference to one or more secrets to be used when pulling images +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: [] +# - name: myRegistryKeySecretName + +serviceAccount: + create: true # When true, service accounts will be created for you. Set to false if you want to use your own. + controller: csi-blob-controller-sa # Name of Service Account to be created or used + node: csi-blob-node-sa # Name of Service Account to be created or used + +rbac: + create: true + name: blob + +## Collection of annotations to add to all the pods +podAnnotations: {} +## Collection of labels to add to all the pods +podLabels: {} +# -- Custom labels to add into metadata +customLabels: {} + # k8s-app: blob-csi-driver + +## Leverage a PriorityClass to ensure your pods survive resource shortages +## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +priorityClassName: system-cluster-critical +## Security context give the opportunity to run container as nonroot by setting a securityContext +## by example : +## securityContext: { runAsUser: 1001 } +securityContext: {} + +controller: + name: csi-blob-controller + cloudConfigSecretName: azure-cloud-provider + cloudConfigSecretNamespace: kube-system + allowEmptyCloudConfig: true + hostNetwork: true # this setting could be disabled if controller does not depend on MSI setting + metricsPort: 29634 + livenessProbe: + healthPort: 29632 + replicas: 2 + runOnMaster: false + runOnControlPlane: false + logLevel: 5 + resources: + csiProvisioner: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + livenessProbe: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + blob: + limits: + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + csiResizer: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + affinity: {} + nodeSelector: {} + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/controlplane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + +node: + name: csi-blob-node + cloudConfigSecretName: azure-cloud-provider + cloudConfigSecretNamespace: kube-system + allowEmptyCloudConfig: true + allowInlineVolumeKeyAccessWithIdentity: false + maxUnavailable: 1 + livenessProbe: + healthPort: 29633 + logLevel: 5 + enableBlobfuseProxy: false + blobfuseProxy: + installBlobfuse: true + blobfuseVersion: "1.4.5" + installBlobfuse2: true + blobfuse2Version: "2.0.5" + setMaxOpenFileNum: true + maxOpenFileNum: "9000000" + disableUpdateDB: true + blobfuseCachePath: /mnt + appendTimeStampInCacheDir: false + mountPermissions: 0777 + resources: + livenessProbe: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + nodeDriverRegistrar: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + blob: + limits: + memory: 2100Mi + requests: + cpu: 10m + memory: 20Mi + aznfswatchdog: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + affinity: {} + nodeSelector: {} + tolerations: + - operator: "Exists" + enableAznfsMount: true + +feature: + fsGroupPolicy: ReadWriteOnceWithFSType + enableGetVolumeStats: false + +driver: + name: blob.csi.azure.com + customUserAgent: "" + userAgentSuffix: "OSS-helm" + azureGoSDKLogLevel: "" # available values: ""(no logs), DEBUG, INFO, WARNING, ERROR + httpsProxy: "" + httpProxy: "" + +linux: + kubelet: /var/lib/kubelet + distro: debian + +workloadIdentity: + clientID: "" + # [optional] If the AAD application or user-assigned managed identity is not in the same tenant as the cluster + # then set tenantID with the application or user-assigned managed identity tenant ID + tenantID: "" diff --git a/charts/v1.23.0/blob-csi-driver-v1.23.0.tgz b/charts/v1.23.0/blob-csi-driver-v1.23.0.tgz new file mode 100644 index 000000000..ce96847b9 Binary files /dev/null and b/charts/v1.23.0/blob-csi-driver-v1.23.0.tgz differ diff --git a/charts/v1.23.0/blob-csi-driver/Chart.yaml b/charts/v1.23.0/blob-csi-driver/Chart.yaml new file mode 100644 index 000000000..940914d35 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: v1.23.0 +description: Azure Blob Storage CSI driver +name: blob-csi-driver +version: v1.23.0 diff --git a/charts/v1.23.0/blob-csi-driver/templates/NOTES.txt b/charts/v1.23.0/blob-csi-driver/templates/NOTES.txt new file mode 100644 index 000000000..9ad135dd4 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/NOTES.txt @@ -0,0 +1,5 @@ +The Azure Blob Storage CSI driver is getting deployed to your cluster. + +To check Azure Blob Storage CSI driver pods status, please run: + + kubectl --namespace={{ .Release.Namespace }} get pods --selector="release={{ .Release.Name }}" --watch diff --git a/charts/v1.23.0/blob-csi-driver/templates/_helpers.tpl b/charts/v1.23.0/blob-csi-driver/templates/_helpers.tpl new file mode 100644 index 000000000..d99392f32 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* Expand the name of the chart.*/}} +{{- define "blob.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "blob.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common selectors. +*/}} +{{- define "blob.selectorLabels" -}} +app.kubernetes.io/name: {{ template "blob.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Common labels. +*/}} +{{- define "blob.labels" -}} +{{- include "blob.selectorLabels" . }} +app.kubernetes.io/component: csi-driver +app.kubernetes.io/part-of: {{ template "blob.name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +helm.sh/chart: {{ template "blob.chart" . }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels }} +{{- end }} +{{- end -}} + + +{{/* pull secrets for containers */}} +{{- define "blob.pullSecrets" -}} +{{- if .Values.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/v1.23.0/blob-csi-driver/templates/csi-blob-controller.yaml b/charts/v1.23.0/blob-csi-driver/templates/csi-blob-controller.yaml new file mode 100644 index 000000000..dc11a59c2 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/csi-blob-controller.yaml @@ -0,0 +1,216 @@ +kind: Deployment +apiVersion: apps/v1 +metadata: + name: {{ .Values.controller.name }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.controller.name }} + {{- include "blob.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.controller.replicas }} + selector: + matchLabels: + app: {{ .Values.controller.name }} + {{- include "blob.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + app: {{ .Values.controller.name }} + {{- include "blob.labels" . | nindent 8 }} + {{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + {{- end }} + {{- if .Values.podLabels }} +{{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} +{{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} +{{- end }} + spec: +{{- with .Values.controller.affinity }} + affinity: +{{ toYaml . | indent 8 }} +{{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + hostNetwork: {{ .Values.controller.hostNetwork }} + serviceAccountName: {{ .Values.serviceAccount.controller }} + nodeSelector: + kubernetes.io/os: linux + {{- if .Values.controller.runOnMaster}} + node-role.kubernetes.io/master: "" + {{- end}} + {{- if .Values.controller.runOnControlPlane}} + node-role.kubernetes.io/control-plane: "" + {{- end}} +{{- with .Values.controller.nodeSelector }} +{{ toYaml . | indent 8 }} +{{- end }} + priorityClassName: {{ .Values.priorityClassName | quote }} + securityContext: + seccompProfile: + type: RuntimeDefault +{{- with .Values.controller.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} + containers: + - name: csi-provisioner +{{- if hasPrefix "/" .Values.image.csiProvisioner.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiProvisioner.repository }}:{{ .Values.image.csiProvisioner.tag }}" +{{- else }} + image: "{{ .Values.image.csiProvisioner.repository }}:{{ .Values.image.csiProvisioner.tag }}" +{{- end }} + args: + - "-v=2" + - "--csi-address=$(ADDRESS)" + - "--leader-election" + - "--leader-election-namespace={{ .Release.Namespace }}" + - "--timeout=120s" + - "--extra-create-metadata=true" + - "--kube-api-qps=50" + - "--kube-api-burst=100" + - "--feature-gates=HonorPVReclaimPolicy=true" + env: + - name: ADDRESS + value: /csi/csi.sock + imagePullPolicy: {{ .Values.image.csiProvisioner.pullPolicy }} + volumeMounts: + - mountPath: /csi + name: socket-dir + resources: {{- toYaml .Values.controller.resources.csiProvisioner | nindent 12 }} + - name: liveness-probe +{{- if hasPrefix "/" .Values.image.livenessProbe.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- else }} + image: "{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- end }} + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port={{ .Values.controller.livenessProbe.healthPort }} + imagePullPolicy: {{ .Values.image.livenessProbe.pullPolicy }} + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: {{- toYaml .Values.controller.resources.livenessProbe | nindent 12 }} + - name: blob +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + args: + - "--v={{ .Values.controller.logLevel }}" + - "--endpoint=$(CSI_ENDPOINT)" + - "--metrics-address=0.0.0.0:{{ .Values.controller.metricsPort }}" + - "--drivername={{ .Values.driver.name }}" + - "--custom-user-agent={{ .Values.driver.customUserAgent }}" + - "--user-agent-suffix={{ .Values.driver.userAgentSuffix }}" + - "--cloud-config-secret-name={{ .Values.controller.cloudConfigSecretName }}" + - "--cloud-config-secret-namespace={{ .Values.controller.cloudConfigSecretNamespace }}" + - "--allow-empty-cloud-config={{ .Values.controller.allowEmptyCloudConfig }}" + ports: + - containerPort: {{ .Values.controller.livenessProbe.healthPort }} + name: healthz + protocol: TCP + - containerPort: {{ .Values.controller.metricsPort }} + name: metrics + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + {{- if ne .Values.driver.httpsProxy "" }} + - name: HTTPS_PROXY + value: {{ .Values.driver.httpsProxy }} + {{- end }} + {{- if ne .Values.driver.httpProxy "" }} + - name: HTTP_PROXY + value: {{ .Values.driver.httpProxy }} + {{- end }} + - name: AZURE_GO_SDK_LOG_LEVEL + value: {{ .Values.driver.azureGoSDKLogLevel }} + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: AZURE_ENVIRONMENT_FILEPATH + value: /etc/kubernetes/azurestackcloud.json + {{- end }} + imagePullPolicy: {{ .Values.image.blob.pullPolicy }} + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + - name: ssl-pki + mountPath: /etc/pki/ca-trust/extracted + readOnly: true + {{- end }} + resources: {{- toYaml .Values.controller.resources.blob | nindent 12 }} + - name: csi-resizer +{{- if hasPrefix "/" .Values.image.csiResizer.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}" +{{- else }} + image: "{{ .Values.image.csiResizer.repository }}:{{ .Values.image.csiResizer.tag }}" +{{- end }} + args: + - "-csi-address=$(ADDRESS)" + - "-v=2" + - "-leader-election" + - "--leader-election-namespace={{ .Release.Namespace }}" + - '-handle-volume-inuse-error=false' + env: + - name: ADDRESS + value: /csi/csi.sock + imagePullPolicy: {{ .Values.image.csiResizer.pullPolicy }} + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: {{- toYaml .Values.controller.resources.csiResizer | nindent 12 }} + volumes: + - name: socket-dir + emptyDir: {} + - name: azure-cred + hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + - name: ssl-pki + hostPath: + path: /etc/pki/ca-trust/extracted + {{- end }} + {{- if .Values.securityContext }} + securityContext: {{- toYaml .Values.securityContext | nindent 8 }} + {{- end }} diff --git a/charts/v1.23.0/blob-csi-driver/templates/csi-blob-driver.yaml b/charts/v1.23.0/blob-csi-driver/templates/csi-blob-driver.yaml new file mode 100644 index 000000000..9a6aea64a --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/csi-blob-driver.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: storage.k8s.io/v1 +kind: CSIDriver +metadata: + name: {{ .Values.driver.name }} + labels: + {{- include "blob.labels" . | nindent 4 }} +spec: + attachRequired: false + podInfoOnMount: true + fsGroupPolicy: {{ .Values.feature.fsGroupPolicy }} + volumeLifecycleModes: + - Persistent + - Ephemeral diff --git a/charts/v1.23.0/blob-csi-driver/templates/csi-blob-node.yaml b/charts/v1.23.0/blob-csi-driver/templates/csi-blob-node.yaml new file mode 100644 index 000000000..f7b6a48f3 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/csi-blob-node.yaml @@ -0,0 +1,316 @@ +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: {{ .Values.node.name }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Values.node.name }} + {{- include "blob.labels" . | nindent 4 }} +spec: + updateStrategy: + rollingUpdate: + maxUnavailable: {{ .Values.node.maxUnavailable }} + type: RollingUpdate + selector: + matchLabels: + app: {{ .Values.node.name }} + {{- include "blob.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + app: {{ .Values.node.name }} + {{- include "blob.labels" . | nindent 8 }} + {{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + {{- end }} + {{- if .Values.podLabels }} +{{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} +{{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} +{{- end }} + spec: + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + {{- if or .Values.node.enableBlobfuseProxy .Values.node.enableAznfsMount }} + hostPID: true + {{- end }} + hostNetwork: true + dnsPolicy: Default + serviceAccountName: {{ .Values.serviceAccount.node }} + nodeSelector: + kubernetes.io/os: linux +{{- with .Values.node.nodeSelector }} +{{ toYaml . | indent 8 }} +{{- end }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: type + operator: NotIn + values: + - virtual-kubelet + {{- if .Values.node.affinity }} +{{- toYaml .Values.node.affinity | nindent 8 }} + {{- end }} + priorityClassName: {{ .Values.priorityClassName | quote }} + securityContext: + seccompProfile: + type: RuntimeDefault +{{- with .Values.node.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} +{{- if .Values.node.enableBlobfuseProxy }} + initContainers: + - name: install-blobfuse-proxy +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + imagePullPolicy: IfNotPresent + command: + - "/blobfuse-proxy/init.sh" + securityContext: + privileged: true + env: + - name: DEBIAN_FRONTEND + value: "noninteractive" + - name: INSTALL_BLOBFUSE + value: "{{ .Values.node.blobfuseProxy.installBlobfuse }}" + - name: BLOBFUSE_VERSION + value: "{{ .Values.node.blobfuseProxy.blobfuseVersion }}" + - name: INSTALL_BLOBFUSE2 + value: "{{ .Values.node.blobfuseProxy.installBlobfuse2 }}" + - name: BLOBFUSE2_VERSION + value: "{{ .Values.node.blobfuseProxy.blobfuse2Version }}" + - name: SET_MAX_OPEN_FILE_NUM + value: "{{ .Values.node.blobfuseProxy.setMaxOpenFileNum }}" + - name: MAX_FILE_NUM + value: "{{ .Values.node.blobfuseProxy.maxOpenFileNum }}" + - name: DISABLE_UPDATEDB + value: "{{ .Values.node.blobfuseProxy.disableUpdateDB }}" + volumeMounts: + - name: host-usr + mountPath: /host/usr + - name: host-etc + mountPath: /host/etc +{{- end }} + containers: + - name: liveness-probe + imagePullPolicy: {{ .Values.image.livenessProbe.pullPolicy }} + volumeMounts: + - mountPath: /csi + name: socket-dir +{{- if hasPrefix "/" .Values.image.livenessProbe.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- else }} + image: "{{ .Values.image.livenessProbe.repository }}:{{ .Values.image.livenessProbe.tag }}" +{{- end }} + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port={{ .Values.node.livenessProbe.healthPort }} + - --v=2 + resources: {{- toYaml .Values.node.resources.livenessProbe | nindent 12 }} + - name: node-driver-registrar +{{- if hasPrefix "/" .Values.image.nodeDriverRegistrar.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.nodeDriverRegistrar.repository }}:{{ .Values.image.nodeDriverRegistrar.tag }}" +{{- else }} + image: "{{ .Values.image.nodeDriverRegistrar.repository }}:{{ .Values.image.nodeDriverRegistrar.tag }}" +{{- end }} + args: + - --csi-address=$(ADDRESS) + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --v=2 + livenessProbe: + exec: + command: + - /csi-node-driver-registrar + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --mode=kubelet-registration-probe + initialDelaySeconds: 30 + timeoutSeconds: 15 + env: + - name: ADDRESS + value: /csi/csi.sock + - name: DRIVER_REG_SOCK_PATH + value: {{ .Values.linux.kubelet }}/plugins/{{ .Values.driver.name }}/csi.sock + volumeMounts: + - name: socket-dir + mountPath: /csi + - name: registration-dir + mountPath: /registration + resources: {{- toYaml .Values.node.resources.nodeDriverRegistrar | nindent 12 }} + - name: blob +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + args: + - "--v={{ .Values.node.logLevel }}" + - "--endpoint=$(CSI_ENDPOINT)" + - "--blobfuse-proxy-endpoint=$(BLOBFUSE_PROXY_ENDPOINT)" + - "--enable-blobfuse-proxy={{ .Values.node.enableBlobfuseProxy }}" + - "--nodeid=$(KUBE_NODE_NAME)" + - "--drivername={{ .Values.driver.name }}" + - "--cloud-config-secret-name={{ .Values.node.cloudConfigSecretName }}" + - "--cloud-config-secret-namespace={{ .Values.node.cloudConfigSecretNamespace }}" + - "--custom-user-agent={{ .Values.driver.customUserAgent }}" + - "--user-agent-suffix={{ .Values.driver.userAgentSuffix }}" + - "--allow-empty-cloud-config={{ .Values.node.allowEmptyCloudConfig }}" + - "--enable-get-volume-stats={{ .Values.feature.enableGetVolumeStats }}" + - "--append-timestamp-cache-dir={{ .Values.node.appendTimeStampInCacheDir }}" + - "--mount-permissions={{ .Values.node.mountPermissions }}" + - "--allow-inline-volume-key-access-with-idenitity={{ .Values.node.allowInlineVolumeKeyAccessWithIdentity }}" + - "--enable-aznfs-mount={{ .Values.node.enableAznfsMount }}" + ports: + - containerPort: {{ .Values.node.livenessProbe.healthPort }} + name: healthz + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + - name: BLOBFUSE_PROXY_ENDPOINT + value: unix:///csi/blobfuse-proxy.sock + {{- if ne .Values.driver.httpsProxy "" }} + - name: HTTPS_PROXY + value: {{ .Values.driver.httpsProxy }} + {{- end }} + {{- if ne .Values.driver.httpProxy "" }} + - name: HTTP_PROXY + value: {{ .Values.driver.httpProxy }} + {{- end }} + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + - name: AZURE_GO_SDK_LOG_LEVEL + value: {{ .Values.driver.azureGoSDKLogLevel }} + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: AZURE_ENVIRONMENT_FILEPATH + value: /etc/kubernetes/azurestackcloud.json + {{- end }} + imagePullPolicy: {{ .Values.image.blob.pullPolicy }} + securityContext: + privileged: true + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: {{ .Values.linux.kubelet }}/ + mountPropagation: Bidirectional + name: mountpoint-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + - mountPath: /mnt + name: blob-cache + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + mountPath: /etc/ssl/certs + readOnly: true + - name: ssl-pki + mountPath: /etc/pki/ca-trust/extracted + readOnly: true + {{- end }} + {{- if .Values.node.enableAznfsMount }} + - mountPath: /opt/microsoft/aznfs/data + name: aznfs-data + {{- end }} + resources: {{- toYaml .Values.node.resources.blob | nindent 12 }} +{{- if .Values.node.enableAznfsMount }} + - name: aznfswatchdog +{{- if hasPrefix "/" .Values.image.blob.repository }} + image: "{{ .Values.image.baseRepo }}{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- else }} + image: "{{ .Values.image.blob.repository }}:{{ .Values.image.blob.tag }}" +{{- end }} + command: + - "aznfswatchdog" + imagePullPolicy: {{ .Values.image.blob.pullPolicy }} + securityContext: + privileged: true + resources: {{- toYaml .Values.node.resources.aznfswatchdog | nindent 12 }} + volumeMounts: + - mountPath: /opt/microsoft/aznfs/data + name: aznfs-data + - mountPath: {{ .Values.linux.kubelet }}/ + mountPropagation: Bidirectional + name: mountpoint-dir +{{- end }} + volumes: +{{- if .Values.node.enableBlobfuseProxy }} + - name: host-usr + hostPath: + path: /usr + - name: host-etc + hostPath: + path: /etc +{{- end }} + - hostPath: + path: {{ .Values.linux.kubelet }}/plugins/{{ .Values.driver.name }} + type: DirectoryOrCreate + name: socket-dir + - hostPath: + path: {{ .Values.linux.kubelet }}/ + type: DirectoryOrCreate + name: mountpoint-dir + - hostPath: + path: {{ .Values.linux.kubelet }}/plugins_registry/ + type: DirectoryOrCreate + name: registration-dir + - hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate + name: azure-cred + - hostPath: + path: {{ .Values.node.blobfuseCachePath }} + name: blob-cache + {{- if eq .Values.cloud "AzureStackCloud" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + {{- end }} + {{- if eq .Values.linux.distro "fedora" }} + - name: ssl + hostPath: + path: /etc/ssl/certs + - name: ssl-pki + hostPath: + path: /etc/pki/ca-trust/extracted + {{- end }} + {{- if .Values.node.enableAznfsMount }} + - hostPath: + path: /opt/microsoft/aznfs/data + type: DirectoryOrCreate + name: aznfs-data + {{- end }} + {{- if .Values.securityContext }} + securityContext: {{- toYaml .Values.securityContext | nindent 8 }} + {{- end }} diff --git a/charts/v1.23.0/blob-csi-driver/templates/rbac-csi-blob-controller.yaml b/charts/v1.23.0/blob-csi-driver/templates/rbac-csi-blob-controller.yaml new file mode 100644 index 000000000..833dcc640 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/rbac-csi-blob-controller.yaml @@ -0,0 +1,115 @@ +{{- if .Values.rbac.create -}} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-external-provisioner-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "create", "delete"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "update"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: ["storage.k8s.io"] + resources: ["csinodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-csi-provisioner-binding + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ .Values.rbac.name }}-external-provisioner-role + apiGroup: rbac.authorization.k8s.io + +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-external-resizer-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "update", "patch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims/status"] + verbs: ["update", "patch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["list", "watch", "create", "update", "patch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ .Values.rbac.name }}-csi-resizer-role + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ .Values.rbac.name }}-external-resizer-role + apiGroup: rbac.authorization.k8s.io + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-controller-secret-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-controller-secret-binding + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: csi-{{ .Values.rbac.name }}-controller-secret-role + apiGroup: rbac.authorization.k8s.io +{{ end }} diff --git a/charts/v1.23.0/blob-csi-driver/templates/rbac-csi-blob-node.yaml b/charts/v1.23.0/blob-csi-driver/templates/rbac-csi-blob-node.yaml new file mode 100644 index 000000000..c041cf8db --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/rbac-csi-blob-node.yaml @@ -0,0 +1,29 @@ +{{- if .Values.rbac.create -}} +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-node-secret-role + labels: + {{- include "blob.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-{{ .Values.rbac.name }}-node-secret-binding + labels: + {{- include "blob.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ .Values.serviceAccount.node }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: csi-{{ .Values.rbac.name }}-node-secret-role + apiGroup: rbac.authorization.k8s.io +{{ end }} diff --git a/charts/v1.23.0/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml b/charts/v1.23.0/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml new file mode 100644 index 000000000..7433bccf1 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/serviceaccount-csi-blob-controller.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.controller }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "blob.labels" . | nindent 4 }} +{{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + annotations: + azure.workload.identity/client-id: {{ .Values.workloadIdentity.clientID }} +{{- if .Values.workloadIdentity.tenantID }} + azure.workload.identity/tenant-id: {{ .Values.workloadIdentity.tenantID }} +{{- end }} +{{- end }} +{{- end -}} diff --git a/charts/v1.23.0/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml b/charts/v1.23.0/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml new file mode 100644 index 000000000..a25090e30 --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/templates/serviceaccount-csi-blob-node.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.node }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "blob.labels" . | nindent 4 }} +{{- if .Values.workloadIdentity.clientID }} + azure.workload.identity/use: "true" + annotations: + azure.workload.identity/client-id: {{ .Values.workloadIdentity.clientID }} +{{- if .Values.workloadIdentity.tenantID }} + azure.workload.identity/tenant-id: {{ .Values.workloadIdentity.tenantID }} +{{- end }} +{{- end }} +{{- end -}} diff --git a/charts/v1.23.0/blob-csi-driver/values.yaml b/charts/v1.23.0/blob-csi-driver/values.yaml new file mode 100644 index 000000000..c72b078af --- /dev/null +++ b/charts/v1.23.0/blob-csi-driver/values.yaml @@ -0,0 +1,180 @@ +image: + baseRepo: mcr.microsoft.com + blob: + repository: /oss/kubernetes-csi/blob-csi + tag: v1.23.0 + pullPolicy: IfNotPresent + csiProvisioner: + repository: /oss/kubernetes-csi/csi-provisioner + tag: v3.5.0 + pullPolicy: IfNotPresent + livenessProbe: + repository: /oss/kubernetes-csi/livenessprobe + tag: v2.10.0 + pullPolicy: IfNotPresent + nodeDriverRegistrar: + repository: /oss/kubernetes-csi/csi-node-driver-registrar + tag: v2.8.0 + pullPolicy: IfNotPresent + csiResizer: + repository: /oss/kubernetes-csi/csi-resizer + tag: v1.8.0 + pullPolicy: IfNotPresent + +cloud: AzurePublicCloud + +## Reference to one or more secrets to be used when pulling images +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: [] +# - name: myRegistryKeySecretName + +serviceAccount: + create: true # When true, service accounts will be created for you. Set to false if you want to use your own. + controller: csi-blob-controller-sa # Name of Service Account to be created or used + node: csi-blob-node-sa # Name of Service Account to be created or used + +rbac: + create: true + name: blob + +## Collection of annotations to add to all the pods +podAnnotations: {} +## Collection of labels to add to all the pods +podLabels: {} +# -- Custom labels to add into metadata +customLabels: {} + # k8s-app: blob-csi-driver + +## Leverage a PriorityClass to ensure your pods survive resource shortages +## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +priorityClassName: system-cluster-critical +## Security context give the opportunity to run container as nonroot by setting a securityContext +## by example : +## securityContext: { runAsUser: 1001 } +securityContext: {} + +controller: + name: csi-blob-controller + cloudConfigSecretName: azure-cloud-provider + cloudConfigSecretNamespace: kube-system + allowEmptyCloudConfig: true + hostNetwork: true # this setting could be disabled if controller does not depend on MSI setting + metricsPort: 29634 + livenessProbe: + healthPort: 29632 + replicas: 2 + runOnMaster: false + runOnControlPlane: false + logLevel: 5 + resources: + csiProvisioner: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + livenessProbe: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + blob: + limits: + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + csiResizer: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + affinity: {} + nodeSelector: {} + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/controlplane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + +node: + name: csi-blob-node + cloudConfigSecretName: azure-cloud-provider + cloudConfigSecretNamespace: kube-system + allowEmptyCloudConfig: true + allowInlineVolumeKeyAccessWithIdentity: false + maxUnavailable: 1 + livenessProbe: + healthPort: 29633 + logLevel: 5 + enableBlobfuseProxy: false + blobfuseProxy: + installBlobfuse: true + blobfuseVersion: "1.4.5" + installBlobfuse2: true + blobfuse2Version: "2.1.0" + setMaxOpenFileNum: true + maxOpenFileNum: "9000000" + disableUpdateDB: true + blobfuseCachePath: /mnt + appendTimeStampInCacheDir: false + mountPermissions: 0777 + resources: + livenessProbe: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + nodeDriverRegistrar: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + blob: + limits: + memory: 2100Mi + requests: + cpu: 10m + memory: 20Mi + aznfswatchdog: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + affinity: {} + nodeSelector: {} + tolerations: + - operator: "Exists" + enableAznfsMount: true + +feature: + fsGroupPolicy: ReadWriteOnceWithFSType + enableGetVolumeStats: false + +driver: + name: blob.csi.azure.com + customUserAgent: "" + userAgentSuffix: "OSS-helm" + azureGoSDKLogLevel: "" # available values: ""(no logs), DEBUG, INFO, WARNING, ERROR + httpsProxy: "" + httpProxy: "" + +linux: + kubelet: /var/lib/kubelet + distro: debian + +workloadIdentity: + clientID: "" + # [optional] If the AAD application or user-assigned managed identity is not in the same tenant as the cluster + # then set tenantID with the application or user-assigned managed identity tenant ID + tenantID: "" diff --git a/deploy/csi-blob-controller.yaml b/deploy/csi-blob-controller.yaml index ab8d824d4..55e005281 100644 --- a/deploy/csi-blob-controller.yaml +++ b/deploy/csi-blob-controller.yaml @@ -35,16 +35,17 @@ spec: effect: "NoSchedule" containers: - name: csi-provisioner - image: mcr.microsoft.com/oss/kubernetes-csi/csi-provisioner:v3.5.0 + image: mcr.microsoft.com/oss/kubernetes-csi/csi-provisioner:v3.6.1 args: - "-v=2" - "--csi-address=$(ADDRESS)" - "--leader-election" - "--leader-election-namespace=kube-system" - - "--timeout=120s" + - "--timeout=1200s" - "--extra-create-metadata=true" - "--kube-api-qps=50" - "--kube-api-burst=100" + - "--feature-gates=HonorPVReclaimPolicy=true" env: - name: ADDRESS value: /csi/csi.sock @@ -58,7 +59,7 @@ spec: cpu: 10m memory: 20Mi - name: liveness-probe - image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.10.0 + image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.11.0 args: - --csi-address=/csi/csi.sock - --probe-timeout=3s @@ -116,7 +117,7 @@ spec: cpu: 10m memory: 20Mi - name: csi-resizer - image: mcr.microsoft.com/oss/kubernetes-csi/csi-resizer:v1.8.0 + image: mcr.microsoft.com/oss/kubernetes-csi/csi-resizer:v1.9.1 args: - "-csi-address=$(ADDRESS)" - "-v=2" diff --git a/deploy/csi-blob-node.yaml b/deploy/csi-blob-node.yaml index 1087018ae..de9a03248 100644 --- a/deploy/csi-blob-node.yaml +++ b/deploy/csi-blob-node.yaml @@ -58,7 +58,7 @@ spec: - name: INSTALL_BLOBFUSE2 value: "true" - name: BLOBFUSE2_VERSION - value: "2.0.3" + value: "2.1.0" - name: SET_MAX_OPEN_FILE_NUM value: "true" - name: MAX_FILE_NUM @@ -75,7 +75,7 @@ spec: volumeMounts: - mountPath: /csi name: socket-dir - image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.10.0 + image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.11.0 args: - --csi-address=/csi/csi.sock - --probe-timeout=3s @@ -88,7 +88,7 @@ spec: cpu: 10m memory: 20Mi - name: node-driver-registrar - image: mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar:v2.8.0 + image: mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar:v2.9.0 args: - --csi-address=$(ADDRESS) - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) @@ -128,6 +128,7 @@ spec: - "--blobfuse-proxy-endpoint=$(BLOBFUSE_PROXY_ENDPOINT)" - "--nodeid=$(KUBE_NODE_NAME)" - "--user-agent-suffix=OSS-kubectl" + - "--metrics-address=0.0.0.0:29635" ports: - containerPort: 29633 name: healthz diff --git a/deploy/example/e2e_usage.md b/deploy/example/e2e_usage.md index 87eebc35f..2a670357e 100644 --- a/deploy/example/e2e_usage.md +++ b/deploy/example/e2e_usage.md @@ -95,7 +95,7 @@ spec: driver: blob.csi.azure.com readOnly: false # make sure volumeid is unique for every storage blob container in the cluster - # the # character is reserved for internal use + # the # character is reserved for internal use, the / character is not allowed volumeHandle: account-name_container-name volumeAttributes: containerName: EXISTING_CONTAINER_NAME @@ -134,9 +134,8 @@ blobfuse 14G 41M 13G 1% /mnt/blob In the above example, there is a `/mnt/blob` directory mounted as `blobfuse` filesystem. #### Option#3: Inline volume - > only available from `v1.2.0` for blobfuse protocol (NFS protocol is not supported) - - Create `azure-secret` with existing storage account name and key in the same namespace as pod - > in below example, both secret and pod are in `default` namespace + > to avoid performance issue, use persistent volume instead of inline volume when numerous pods are accessing the same volume. + - in below blobfuse mount example, create `azure-secret` with existing storage account name and key in the same namespace as pod, both secret and pod are in `default` namespace ```console kubectl create secret generic azure-secret --from-literal azurestorageaccountname=NAME --from-literal azurestorageaccountkey="KEY" --type=Opaque ``` diff --git a/deploy/example/pv-blobfuse-auth.yaml b/deploy/example/pv-blobfuse-auth.yaml index ddfea4e1a..1b132a612 100644 --- a/deploy/example/pv-blobfuse-auth.yaml +++ b/deploy/example/pv-blobfuse-auth.yaml @@ -19,7 +19,7 @@ spec: driver: blob.csi.azure.com readOnly: false # make sure volumeid is unique for every storage blob container in the cluster - # the # character is reserved for internal use + # the # character is reserved for internal use, the / character is not allowed volumeHandle: account-name_container-name volumeAttributes: resourceGroup: EXISTING_RESOURCE_GROUP_NAME diff --git a/deploy/example/pv-blobfuse-csi-keyvault.yaml b/deploy/example/pv-blobfuse-csi-keyvault.yaml index d9a1d1af6..49dd56098 100644 --- a/deploy/example/pv-blobfuse-csi-keyvault.yaml +++ b/deploy/example/pv-blobfuse-csi-keyvault.yaml @@ -16,7 +16,7 @@ spec: driver: blob.csi.azure.com readOnly: false # make sure volumeid is unique for every storage blob container in the cluster - # the # character is reserved for internal use + # the # character is reserved for internal use, the / character is not allowed volumeHandle: account-name_container-name volumeAttributes: containerName: EXISTING_CONTAINER_NAME diff --git a/deploy/example/pv-blobfuse-csi.yaml b/deploy/example/pv-blobfuse-csi.yaml index da7826cd5..a83a9302f 100644 --- a/deploy/example/pv-blobfuse-csi.yaml +++ b/deploy/example/pv-blobfuse-csi.yaml @@ -19,7 +19,7 @@ spec: driver: blob.csi.azure.com readOnly: false # make sure volumeid is unique for every storage blob container in the cluster - # the # character is reserved for internal use + # the # character is reserved for internal use, the / character is not allowed volumeHandle: account-name_container-name volumeAttributes: resourceGroup: EXISTING_RESOURCE_GROUP_NAME diff --git a/deploy/example/pv-blobfuse-nfs.yaml b/deploy/example/pv-blobfuse-nfs.yaml index a9dace3d8..796132f69 100644 --- a/deploy/example/pv-blobfuse-nfs.yaml +++ b/deploy/example/pv-blobfuse-nfs.yaml @@ -16,7 +16,7 @@ spec: driver: blob.csi.azure.com readOnly: false # make sure volumeid is unique for every storage blob container in the cluster - # the # character is reserved for internal use + # the # character is reserved for internal use, the / character is not allowed volumeHandle: account-name_container-name volumeAttributes: resourceGroup: EXISTING_RESOURCE_GROUP_NAME diff --git a/deploy/example/pvc-blob-csi-clone.yaml b/deploy/example/pvc-blob-csi-clone.yaml new file mode 100644 index 000000000..d24da9016 --- /dev/null +++ b/deploy/example/pvc-blob-csi-clone.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: pvc-blob-clone + namespace: default +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 100Gi + storageClassName: blob-fuse + dataSource: + kind: PersistentVolumeClaim + name: pvc-blob diff --git a/deploy/uninstall-driver.sh b/deploy/uninstall-driver.sh index f194ea600..060dc485b 100755 --- a/deploy/uninstall-driver.sh +++ b/deploy/uninstall-driver.sh @@ -33,8 +33,8 @@ if [ $ver != "master" ]; then repo="$repo/$ver" fi - echo "Uninstalling Azure Blob Storage CSI driver, version: $ver ..." +kubectl delete daemonset csi-blobfuse-proxy -n kube-system --ignore-not-found kubectl delete -f $repo/csi-blob-controller.yaml --ignore-not-found kubectl delete -f $repo/csi-blob-node.yaml --ignore-not-found kubectl delete -f $repo/csi-blob-driver.yaml --ignore-not-found diff --git a/deploy/v1.21.3/csi-blob-controller.yaml b/deploy/v1.21.4/csi-blob-controller.yaml similarity index 99% rename from deploy/v1.21.3/csi-blob-controller.yaml rename to deploy/v1.21.4/csi-blob-controller.yaml index a84b3798d..5cd2c57ae 100644 --- a/deploy/v1.21.3/csi-blob-controller.yaml +++ b/deploy/v1.21.4/csi-blob-controller.yaml @@ -72,7 +72,7 @@ spec: cpu: 10m memory: 20Mi - name: blob - image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.3 + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.4 imagePullPolicy: IfNotPresent args: - "--v=5" diff --git a/deploy/v1.21.3/csi-blob-driver.yaml b/deploy/v1.21.4/csi-blob-driver.yaml similarity index 100% rename from deploy/v1.21.3/csi-blob-driver.yaml rename to deploy/v1.21.4/csi-blob-driver.yaml diff --git a/deploy/v1.21.3/csi-blob-node.yaml b/deploy/v1.21.4/csi-blob-node.yaml similarity index 99% rename from deploy/v1.21.3/csi-blob-node.yaml rename to deploy/v1.21.4/csi-blob-node.yaml index 81c4c0c49..46fd5bc06 100644 --- a/deploy/v1.21.3/csi-blob-node.yaml +++ b/deploy/v1.21.4/csi-blob-node.yaml @@ -40,7 +40,7 @@ spec: - operator: "Exists" initContainers: - name: install-blobfuse-proxy - image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.3 + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.4 imagePullPolicy: IfNotPresent command: - "/blobfuse-proxy/init.sh" @@ -118,7 +118,7 @@ spec: cpu: 10m memory: 20Mi - name: blob - image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.3 + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.21.4 imagePullPolicy: IfNotPresent args: - "--v=5" diff --git a/deploy/v1.21.3/kustomization.yaml b/deploy/v1.21.4/kustomization.yaml similarity index 100% rename from deploy/v1.21.3/kustomization.yaml rename to deploy/v1.21.4/kustomization.yaml diff --git a/deploy/v1.21.3/rbac-csi-blob-controller.yaml b/deploy/v1.21.4/rbac-csi-blob-controller.yaml similarity index 100% rename from deploy/v1.21.3/rbac-csi-blob-controller.yaml rename to deploy/v1.21.4/rbac-csi-blob-controller.yaml diff --git a/deploy/v1.21.3/rbac-csi-blob-node.yaml b/deploy/v1.21.4/rbac-csi-blob-node.yaml similarity index 100% rename from deploy/v1.21.3/rbac-csi-blob-node.yaml rename to deploy/v1.21.4/rbac-csi-blob-node.yaml diff --git a/deploy/v1.22.0/csi-blob-controller.yaml b/deploy/v1.22.1/csi-blob-controller.yaml similarity index 99% rename from deploy/v1.22.0/csi-blob-controller.yaml rename to deploy/v1.22.1/csi-blob-controller.yaml index 82e456b29..8125edb78 100644 --- a/deploy/v1.22.0/csi-blob-controller.yaml +++ b/deploy/v1.22.1/csi-blob-controller.yaml @@ -72,7 +72,7 @@ spec: cpu: 10m memory: 20Mi - name: blob - image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.0 + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.1 imagePullPolicy: IfNotPresent args: - "--v=5" diff --git a/deploy/v1.22.0/csi-blob-driver.yaml b/deploy/v1.22.1/csi-blob-driver.yaml similarity index 100% rename from deploy/v1.22.0/csi-blob-driver.yaml rename to deploy/v1.22.1/csi-blob-driver.yaml diff --git a/deploy/v1.22.0/csi-blob-node.yaml b/deploy/v1.22.1/csi-blob-node.yaml similarity index 99% rename from deploy/v1.22.0/csi-blob-node.yaml rename to deploy/v1.22.1/csi-blob-node.yaml index 2fdf7611e..11703c05a 100644 --- a/deploy/v1.22.0/csi-blob-node.yaml +++ b/deploy/v1.22.1/csi-blob-node.yaml @@ -40,7 +40,7 @@ spec: - operator: "Exists" initContainers: - name: install-blobfuse-proxy - image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.0 + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.1 imagePullPolicy: IfNotPresent command: - "/blobfuse-proxy/init.sh" @@ -118,7 +118,7 @@ spec: cpu: 10m memory: 20Mi - name: blob - image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.0 + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.1 imagePullPolicy: IfNotPresent args: - "--v=5" diff --git a/deploy/v1.22.0/kustomization.yaml b/deploy/v1.22.1/kustomization.yaml similarity index 100% rename from deploy/v1.22.0/kustomization.yaml rename to deploy/v1.22.1/kustomization.yaml diff --git a/deploy/v1.22.0/rbac-csi-blob-controller.yaml b/deploy/v1.22.1/rbac-csi-blob-controller.yaml similarity index 100% rename from deploy/v1.22.0/rbac-csi-blob-controller.yaml rename to deploy/v1.22.1/rbac-csi-blob-controller.yaml diff --git a/deploy/v1.22.0/rbac-csi-blob-node.yaml b/deploy/v1.22.1/rbac-csi-blob-node.yaml similarity index 100% rename from deploy/v1.22.0/rbac-csi-blob-node.yaml rename to deploy/v1.22.1/rbac-csi-blob-node.yaml diff --git a/deploy/v1.22.2/csi-blob-controller.yaml b/deploy/v1.22.2/csi-blob-controller.yaml new file mode 100644 index 000000000..3f2dc69f8 --- /dev/null +++ b/deploy/v1.22.2/csi-blob-controller.yaml @@ -0,0 +1,143 @@ +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: csi-blob-controller + namespace: kube-system +spec: + replicas: 2 + selector: + matchLabels: + app: csi-blob-controller + template: + metadata: + labels: + app: csi-blob-controller + spec: + hostNetwork: true + serviceAccountName: csi-blob-controller-sa + nodeSelector: + kubernetes.io/os: linux # add "kubernetes.io/role: master" to run controller on master node + priorityClassName: system-cluster-critical + securityContext: + seccompProfile: + type: RuntimeDefault + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/controlplane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + containers: + - name: csi-provisioner + image: mcr.microsoft.com/oss/kubernetes-csi/csi-provisioner:v3.5.0 + args: + - "-v=2" + - "--csi-address=$(ADDRESS)" + - "--leader-election" + - "--leader-election-namespace=kube-system" + - "--timeout=120s" + - "--extra-create-metadata=true" + - "--kube-api-qps=50" + - "--kube-api-burst=100" + env: + - name: ADDRESS + value: /csi/csi.sock + volumeMounts: + - mountPath: /csi + name: socket-dir + resources: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + - name: liveness-probe + image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.10.0 + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port=29632 + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + - name: blob + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.2 + imagePullPolicy: IfNotPresent + args: + - "--v=5" + - "--endpoint=$(CSI_ENDPOINT)" + - "--metrics-address=0.0.0.0:29634" + - "--user-agent-suffix=OSS-kubectl" + ports: + - containerPort: 29632 + name: healthz + protocol: TCP + - containerPort: 29634 + name: metrics + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + resources: + limits: + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: csi-resizer + image: mcr.microsoft.com/oss/kubernetes-csi/csi-resizer:v1.8.0 + args: + - "-csi-address=$(ADDRESS)" + - "-v=2" + - "-leader-election" + - "--leader-election-namespace=kube-system" + - '-handle-volume-inuse-error=false' + env: + - name: ADDRESS + value: /csi/csi.sock + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + volumes: + - name: socket-dir + emptyDir: {} + - name: azure-cred + hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate diff --git a/deploy/v1.22.2/csi-blob-driver.yaml b/deploy/v1.22.2/csi-blob-driver.yaml new file mode 100644 index 000000000..d2de725d8 --- /dev/null +++ b/deploy/v1.22.2/csi-blob-driver.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: storage.k8s.io/v1 +kind: CSIDriver +metadata: + name: blob.csi.azure.com +spec: + attachRequired: false + podInfoOnMount: true + fsGroupPolicy: ReadWriteOnceWithFSType + volumeLifecycleModes: + - Persistent + - Ephemeral diff --git a/deploy/v1.22.2/csi-blob-node.yaml b/deploy/v1.22.2/csi-blob-node.yaml new file mode 100644 index 000000000..37ac583f4 --- /dev/null +++ b/deploy/v1.22.2/csi-blob-node.yaml @@ -0,0 +1,203 @@ +--- +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: csi-blob-node + namespace: kube-system +spec: + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + app: csi-blob-node + template: + metadata: + labels: + app: csi-blob-node + spec: + hostNetwork: true + hostPID: true + dnsPolicy: Default + serviceAccountName: csi-blob-node-sa + nodeSelector: + kubernetes.io/os: linux + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: type + operator: NotIn + values: + - virtual-kubelet + priorityClassName: system-node-critical + securityContext: + seccompProfile: + type: RuntimeDefault + tolerations: + - operator: "Exists" + initContainers: + - name: install-blobfuse-proxy + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.2 + imagePullPolicy: IfNotPresent + command: + - "/blobfuse-proxy/init.sh" + securityContext: + privileged: true + env: + - name: DEBIAN_FRONTEND + value: "noninteractive" + - name: INSTALL_BLOBFUSE_PROXY + value: "true" + - name: INSTALL_BLOBFUSE + value: "true" + - name: BLOBFUSE_VERSION + value: "1.4.5" + - name: INSTALL_BLOBFUSE2 + value: "true" + - name: BLOBFUSE2_VERSION + value: "2.0.5" + - name: SET_MAX_OPEN_FILE_NUM + value: "true" + - name: MAX_FILE_NUM + value: "9000000" + - name: DISABLE_UPDATEDB + value: "true" + volumeMounts: + - name: host-usr + mountPath: /host/usr + - name: host-etc + mountPath: /host/etc + containers: + - name: liveness-probe + volumeMounts: + - mountPath: /csi + name: socket-dir + image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.10.0 + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port=29633 + - --v=2 + resources: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + - name: node-driver-registrar + image: mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar:v2.8.0 + args: + - --csi-address=$(ADDRESS) + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --v=2 + livenessProbe: + exec: + command: + - /csi-node-driver-registrar + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --mode=kubelet-registration-probe + initialDelaySeconds: 30 + timeoutSeconds: 15 + env: + - name: ADDRESS + value: /csi/csi.sock + - name: DRIVER_REG_SOCK_PATH + value: /var/lib/kubelet/plugins/blob.csi.azure.com/csi.sock + volumeMounts: + - name: socket-dir + mountPath: /csi + - name: registration-dir + mountPath: /registration + resources: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + - name: blob + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.22.2 + imagePullPolicy: IfNotPresent + args: + - "--v=5" + - "--endpoint=$(CSI_ENDPOINT)" + - "--enable-blobfuse-proxy=false" + - "--blobfuse-proxy-endpoint=$(BLOBFUSE_PROXY_ENDPOINT)" + - "--nodeid=$(KUBE_NODE_NAME)" + - "--user-agent-suffix=OSS-kubectl" + ports: + - containerPort: 29633 + name: healthz + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + - name: BLOBFUSE_PROXY_ENDPOINT + value: unix:///csi/blobfuse-proxy.sock + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + securityContext: + privileged: true + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: /var/lib/kubelet/ + mountPropagation: Bidirectional + name: mountpoint-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + - mountPath: /mnt + name: blob-cache + resources: + limits: + memory: 2100Mi + requests: + cpu: 10m + memory: 20Mi + volumes: + - name: host-usr + hostPath: + path: /usr + - name: host-etc + hostPath: + path: /etc + - hostPath: + path: /var/lib/kubelet/plugins/blob.csi.azure.com + type: DirectoryOrCreate + name: socket-dir + - hostPath: + path: /var/lib/kubelet/ + type: DirectoryOrCreate + name: mountpoint-dir + - hostPath: + path: /var/lib/kubelet/plugins_registry/ + type: DirectoryOrCreate + name: registration-dir + - hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate + name: azure-cred + - hostPath: + path: /mnt + type: DirectoryOrCreate + name: blob-cache +--- diff --git a/deploy/v1.22.2/kustomization.yaml b/deploy/v1.22.2/kustomization.yaml new file mode 100644 index 000000000..8b7f5fcac --- /dev/null +++ b/deploy/v1.22.2/kustomization.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - csi-blob-controller.yaml + - csi-blob-driver.yaml + - csi-blob-node.yaml + - rbac-csi-blob-controller.yaml + - rbac-csi-blob-node.yaml + - blobfuse-proxy.yaml diff --git a/deploy/v1.22.2/rbac-csi-blob-controller.yaml b/deploy/v1.22.2/rbac-csi-blob-controller.yaml new file mode 100644 index 000000000..89c2f1f38 --- /dev/null +++ b/deploy/v1.22.2/rbac-csi-blob-controller.yaml @@ -0,0 +1,108 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: csi-blob-controller-sa + namespace: kube-system +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-external-provisioner-role +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "create", "delete"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "update"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: ["storage.k8s.io"] + resources: ["csinodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-csi-provisioner-binding +subjects: + - kind: ServiceAccount + name: csi-blob-controller-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: blob-external-provisioner-role + apiGroup: rbac.authorization.k8s.io +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-external-resizer-role +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "update", "patch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims/status"] + verbs: ["update", "patch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["list", "watch", "create", "update", "patch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-csi-resizer-role +subjects: + - kind: ServiceAccount + name: csi-blob-controller-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: blob-external-resizer-role + apiGroup: rbac.authorization.k8s.io +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-controller-secret-role +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-controller-secret-binding +subjects: + - kind: ServiceAccount + name: csi-blob-controller-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: csi-blob-controller-secret-role + apiGroup: rbac.authorization.k8s.io diff --git a/deploy/v1.22.2/rbac-csi-blob-node.yaml b/deploy/v1.22.2/rbac-csi-blob-node.yaml new file mode 100644 index 000000000..ce06d862c --- /dev/null +++ b/deploy/v1.22.2/rbac-csi-blob-node.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: csi-blob-node-sa + namespace: kube-system + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-node-secret-role +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-node-secret-binding +subjects: + - kind: ServiceAccount + name: csi-blob-node-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: csi-blob-node-secret-role + apiGroup: rbac.authorization.k8s.io diff --git a/deploy/v1.23.0/csi-blob-controller.yaml b/deploy/v1.23.0/csi-blob-controller.yaml new file mode 100644 index 000000000..c5e450acc --- /dev/null +++ b/deploy/v1.23.0/csi-blob-controller.yaml @@ -0,0 +1,144 @@ +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: csi-blob-controller + namespace: kube-system +spec: + replicas: 2 + selector: + matchLabels: + app: csi-blob-controller + template: + metadata: + labels: + app: csi-blob-controller + spec: + hostNetwork: true + serviceAccountName: csi-blob-controller-sa + nodeSelector: + kubernetes.io/os: linux # add "kubernetes.io/role: master" to run controller on master node + priorityClassName: system-cluster-critical + securityContext: + seccompProfile: + type: RuntimeDefault + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/controlplane" + operator: "Exists" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Exists" + effect: "NoSchedule" + containers: + - name: csi-provisioner + image: mcr.microsoft.com/oss/kubernetes-csi/csi-provisioner:v3.5.0 + args: + - "-v=2" + - "--csi-address=$(ADDRESS)" + - "--leader-election" + - "--leader-election-namespace=kube-system" + - "--timeout=120s" + - "--extra-create-metadata=true" + - "--kube-api-qps=50" + - "--kube-api-burst=100" + - "--feature-gates=HonorPVReclaimPolicy=true" + env: + - name: ADDRESS + value: /csi/csi.sock + volumeMounts: + - mountPath: /csi + name: socket-dir + resources: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + - name: liveness-probe + image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.10.0 + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port=29632 + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + - name: blob + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.23.0 + imagePullPolicy: IfNotPresent + args: + - "--v=5" + - "--endpoint=$(CSI_ENDPOINT)" + - "--metrics-address=0.0.0.0:29634" + - "--user-agent-suffix=OSS-kubectl" + ports: + - containerPort: 29632 + name: healthz + protocol: TCP + - containerPort: 29634 + name: metrics + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + resources: + limits: + memory: 200Mi + requests: + cpu: 10m + memory: 20Mi + - name: csi-resizer + image: mcr.microsoft.com/oss/kubernetes-csi/csi-resizer:v1.8.0 + args: + - "-csi-address=$(ADDRESS)" + - "-v=2" + - "-leader-election" + - "--leader-election-namespace=kube-system" + - '-handle-volume-inuse-error=false' + env: + - name: ADDRESS + value: /csi/csi.sock + volumeMounts: + - name: socket-dir + mountPath: /csi + resources: + limits: + memory: 500Mi + requests: + cpu: 10m + memory: 20Mi + volumes: + - name: socket-dir + emptyDir: {} + - name: azure-cred + hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate diff --git a/deploy/v1.23.0/csi-blob-driver.yaml b/deploy/v1.23.0/csi-blob-driver.yaml new file mode 100644 index 000000000..d2de725d8 --- /dev/null +++ b/deploy/v1.23.0/csi-blob-driver.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: storage.k8s.io/v1 +kind: CSIDriver +metadata: + name: blob.csi.azure.com +spec: + attachRequired: false + podInfoOnMount: true + fsGroupPolicy: ReadWriteOnceWithFSType + volumeLifecycleModes: + - Persistent + - Ephemeral diff --git a/deploy/v1.23.0/csi-blob-node.yaml b/deploy/v1.23.0/csi-blob-node.yaml new file mode 100644 index 000000000..94904b4cb --- /dev/null +++ b/deploy/v1.23.0/csi-blob-node.yaml @@ -0,0 +1,203 @@ +--- +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: csi-blob-node + namespace: kube-system +spec: + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + type: RollingUpdate + selector: + matchLabels: + app: csi-blob-node + template: + metadata: + labels: + app: csi-blob-node + spec: + hostNetwork: true + hostPID: true + dnsPolicy: Default + serviceAccountName: csi-blob-node-sa + nodeSelector: + kubernetes.io/os: linux + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: type + operator: NotIn + values: + - virtual-kubelet + priorityClassName: system-node-critical + securityContext: + seccompProfile: + type: RuntimeDefault + tolerations: + - operator: "Exists" + initContainers: + - name: install-blobfuse-proxy + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.23.0 + imagePullPolicy: IfNotPresent + command: + - "/blobfuse-proxy/init.sh" + securityContext: + privileged: true + env: + - name: DEBIAN_FRONTEND + value: "noninteractive" + - name: INSTALL_BLOBFUSE_PROXY + value: "true" + - name: INSTALL_BLOBFUSE + value: "true" + - name: BLOBFUSE_VERSION + value: "1.4.5" + - name: INSTALL_BLOBFUSE2 + value: "true" + - name: BLOBFUSE2_VERSION + value: "2.1.0" + - name: SET_MAX_OPEN_FILE_NUM + value: "true" + - name: MAX_FILE_NUM + value: "9000000" + - name: DISABLE_UPDATEDB + value: "true" + volumeMounts: + - name: host-usr + mountPath: /host/usr + - name: host-etc + mountPath: /host/etc + containers: + - name: liveness-probe + volumeMounts: + - mountPath: /csi + name: socket-dir + image: mcr.microsoft.com/oss/kubernetes-csi/livenessprobe:v2.10.0 + args: + - --csi-address=/csi/csi.sock + - --probe-timeout=3s + - --health-port=29633 + - --v=2 + resources: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + - name: node-driver-registrar + image: mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar:v2.8.0 + args: + - --csi-address=$(ADDRESS) + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --v=2 + livenessProbe: + exec: + command: + - /csi-node-driver-registrar + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + - --mode=kubelet-registration-probe + initialDelaySeconds: 30 + timeoutSeconds: 15 + env: + - name: ADDRESS + value: /csi/csi.sock + - name: DRIVER_REG_SOCK_PATH + value: /var/lib/kubelet/plugins/blob.csi.azure.com/csi.sock + volumeMounts: + - name: socket-dir + mountPath: /csi + - name: registration-dir + mountPath: /registration + resources: + limits: + memory: 100Mi + requests: + cpu: 10m + memory: 20Mi + - name: blob + image: mcr.microsoft.com/oss/kubernetes-csi/blob-csi:v1.23.0 + imagePullPolicy: IfNotPresent + args: + - "--v=5" + - "--endpoint=$(CSI_ENDPOINT)" + - "--enable-blobfuse-proxy=false" + - "--blobfuse-proxy-endpoint=$(BLOBFUSE_PROXY_ENDPOINT)" + - "--nodeid=$(KUBE_NODE_NAME)" + - "--user-agent-suffix=OSS-kubectl" + ports: + - containerPort: 29633 + name: healthz + protocol: TCP + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: healthz + initialDelaySeconds: 30 + timeoutSeconds: 10 + periodSeconds: 30 + env: + - name: AZURE_CREDENTIAL_FILE + valueFrom: + configMapKeyRef: + name: azure-cred-file + key: path + optional: true + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + - name: BLOBFUSE_PROXY_ENDPOINT + value: unix:///csi/blobfuse-proxy.sock + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + securityContext: + privileged: true + volumeMounts: + - mountPath: /csi + name: socket-dir + - mountPath: /var/lib/kubelet/ + mountPropagation: Bidirectional + name: mountpoint-dir + - mountPath: /etc/kubernetes/ + name: azure-cred + - mountPath: /mnt + name: blob-cache + resources: + limits: + memory: 2100Mi + requests: + cpu: 10m + memory: 20Mi + volumes: + - name: host-usr + hostPath: + path: /usr + - name: host-etc + hostPath: + path: /etc + - hostPath: + path: /var/lib/kubelet/plugins/blob.csi.azure.com + type: DirectoryOrCreate + name: socket-dir + - hostPath: + path: /var/lib/kubelet/ + type: DirectoryOrCreate + name: mountpoint-dir + - hostPath: + path: /var/lib/kubelet/plugins_registry/ + type: DirectoryOrCreate + name: registration-dir + - hostPath: + path: /etc/kubernetes/ + type: DirectoryOrCreate + name: azure-cred + - hostPath: + path: /mnt + type: DirectoryOrCreate + name: blob-cache +--- diff --git a/deploy/v1.23.0/kustomization.yaml b/deploy/v1.23.0/kustomization.yaml new file mode 100644 index 000000000..8b7f5fcac --- /dev/null +++ b/deploy/v1.23.0/kustomization.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - csi-blob-controller.yaml + - csi-blob-driver.yaml + - csi-blob-node.yaml + - rbac-csi-blob-controller.yaml + - rbac-csi-blob-node.yaml + - blobfuse-proxy.yaml diff --git a/deploy/v1.23.0/rbac-csi-blob-controller.yaml b/deploy/v1.23.0/rbac-csi-blob-controller.yaml new file mode 100644 index 000000000..89c2f1f38 --- /dev/null +++ b/deploy/v1.23.0/rbac-csi-blob-controller.yaml @@ -0,0 +1,108 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: csi-blob-controller-sa + namespace: kube-system +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-external-provisioner-role +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "create", "delete"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch", "update"] + - apiGroups: ["storage.k8s.io"] + resources: ["storageclasses"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["get", "list", "watch", "create", "update", "patch"] + - apiGroups: ["storage.k8s.io"] + resources: ["csinodes"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list", "watch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-csi-provisioner-binding +subjects: + - kind: ServiceAccount + name: csi-blob-controller-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: blob-external-provisioner-role + apiGroup: rbac.authorization.k8s.io +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-external-resizer-role +rules: + - apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "list", "watch", "update", "patch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["persistentvolumeclaims/status"] + verbs: ["update", "patch"] + - apiGroups: [""] + resources: ["events"] + verbs: ["list", "watch", "create", "update", "patch"] + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: ["get", "list", "watch", "create", "update", "patch"] +--- + +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: blob-csi-resizer-role +subjects: + - kind: ServiceAccount + name: csi-blob-controller-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: blob-external-resizer-role + apiGroup: rbac.authorization.k8s.io +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-controller-secret-role +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-controller-secret-binding +subjects: + - kind: ServiceAccount + name: csi-blob-controller-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: csi-blob-controller-secret-role + apiGroup: rbac.authorization.k8s.io diff --git a/deploy/v1.23.0/rbac-csi-blob-node.yaml b/deploy/v1.23.0/rbac-csi-blob-node.yaml new file mode 100644 index 000000000..ce06d862c --- /dev/null +++ b/deploy/v1.23.0/rbac-csi-blob-node.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: csi-blob-node-sa + namespace: kube-system + +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-node-secret-role +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get"] + +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: csi-blob-node-secret-binding +subjects: + - kind: ServiceAccount + name: csi-blob-node-sa + namespace: kube-system +roleRef: + kind: ClusterRole + name: csi-blob-node-secret-role + apiGroup: rbac.authorization.k8s.io diff --git a/docs/csi-debug.md b/docs/csi-debug.md index cadd32945..bdb9bff50 100644 --- a/docs/csi-debug.md +++ b/docs/csi-debug.md @@ -81,7 +81,7 @@ change below deployment config, e.g. blobfuse2 -v ```
-blobfuse2 version 2.0.3
+blobfuse2 version 2.1.0
 
### check blobfuse mount on the agent node @@ -102,7 +102,7 @@ export AZURE_STORAGE_ACCOUNT= export AZURE_STORAGE_ACCESS_KEY= # only for sovereign cloud # export AZURE_STORAGE_BLOB_ENDPOINT=accountname.blob.core.chinacloudapi.cn -blobfuse test --container-name=CONTAINER-NAME --tmp-path=/tmp/blobfuse -o allow_other --file-cache-timeout-in-seconds=120 +blobfuse2 test --container-name=CONTAINER-NAME --tmp-path=/tmp/blobfuse -o allow_other --file-cache-timeout-in-seconds=120 ``` > You can find more detailed information about environment variables at https://github.com/Azure/azure-storage-fuse#environment-variables. diff --git a/docs/driver-parameters.md b/docs/driver-parameters.md index 56cc9a798..9bcde90a3 100644 --- a/docs/driver-parameters.md +++ b/docs/driver-parameters.md @@ -1,6 +1,17 @@ ## Driver Parameters > parameter names are case-insensitive +
required permissions for CSI driver +
+    - Microsoft.Storage/storageAccounts/blobServices/read
+    - Microsoft.Storage/storageAccounts/blobServices/containers/write
+    - Microsoft.Storage/storageAccounts/listKeys/action
+    - Microsoft.Storage/storageAccounts/read
+    - Microsoft.Storage/storageAccounts/write
+    - Microsoft.Storage/storageAccounts/delete
+
+
+ ### Dynamic Provisioning > [blobfuse example](../deploy/example/storageclass-blobfuse.yaml) @@ -12,7 +23,7 @@ skuName | Azure storage account type (alias: `storageAccountType`) | `Standard_L location | Azure location | `eastus`, `westus`, etc. | No | if empty, driver will use the same location name as current k8s cluster resourceGroup | Azure resource group name | existing resource group name | No | if empty, driver will use the same resource group name as current k8s cluster storageAccount | specify Azure storage account name| STORAGE_ACCOUNT_NAME | No | If the driver is not provided with a specific storage account name, it will search for a suitable storage account that matches the account settings within the same resource group. If it cannot find a matching storage account, it will create a new one. However, if a storage account name is specified, the storage account must already exist. -protocol | specify blobfuse, blobfuse2 or NFSv3 mount (blobfuse2 is still in Preview) | `fuse`, `fuse2`, `nfs` | No | `fuse` +protocol | specify blobfuse, blobfuse2 or NFSv3 mount | `fuse`, `fuse2`, `nfs` | No | `fuse` networkEndpointType | specify network endpoint type for the storage account created by driver. If `privateEndpoint` is specified, a private endpoint will be created for the storage account. For other cases, a service endpoint will be created for NFS protocol. | "",`privateEndpoint` | No | ``
for AKS cluster, make sure cluster Control plane identity (that is, your AKS cluster name) is added to the Contributor role in the resource group hosting the VNet storageEndpointSuffix | specify Azure storage endpoint suffix | `core.windows.net`, `core.chinacloudapi.cn`, etc | No | if empty, driver will use default storage endpoint suffix according to cloud environment, e.g. `core.windows.net` containerName | specify the existing container(directory) name | existing container name | No | if empty, driver will create a new container name, starting with `pvc-fuse` for blobfuse or `pvc-nfs` for NFSv3 @@ -28,6 +39,7 @@ useDataPlaneAPI | specify whether use data plane API for blob container create/d --- | **Following parameters are only for blobfuse** | --- | --- | subscriptionID | specify Azure subscription ID in which blob storage directory will be created | Azure subscription ID | No | if not empty, `resourceGroup` must be provided storeAccountKey | whether store account key to k8s secret

Note:
`false` means driver would leverage kubelet identity to get account key | `true`,`false` | No | `true` +getLatestAccountKey | whether getting the latest account key based on the creation time, this driver would get the first key by default | `true`,`false` | No | `false` secretName | specify secret name to store account key | | No | secretNamespace | specify the namespace of secret to store account key | `default`,`kube-system`, etc | No | pvc namespace isHnsEnabled | enable `Hierarchical namespace` for Azure DataLake storage account | `true`,`false` | No | `false` @@ -44,9 +56,9 @@ enableBlobVersioning | Enable [blob versioning](https://learn.microsoft.com/en-u Blobfuse driver does not honor `fsGroup` securityContext setting, instead user could use `-o gid=1000` in `mountOptions` to set ownership, check [here](https://github.com/Azure/azure-storage-fuse/tree/blobfuse-1.4.5#mount-options) for more mountoptions. - - Regarding the support for [Azure DataLake storage account](https://docs.microsoft.com/en-us/azure/storage/blobs/upgrade-to-data-lake-storage-gen2-how-to) when using blobfuse mount - - To create an ADLS account using the driver in dynamic provisioning, you need to specify `isHnsEnabled: "true"` in the storage class parameters. - - To enable blobfuse access to an ADLS account in static provisioning, you need to specify the mount option `--use-adls=true` in the persistent volume. + - To support an [Azure DataLake storage account](https://docs.microsoft.com/en-us/azure/storage/blobs/upgrade-to-data-lake-storage-gen2-how-to) when using blobfuse mount, you'll need to do the following: + - To create an ADLS account using the driver in dynamic provisioning, specify `isHnsEnabled: "true"` in the storage class parameters. + - To enable blobfuse access to an ADLS account in static provisioning, specify the mount option `--use-adls=true` in the persistent volume. - account tags format created by dynamic provisioning ``` @@ -72,7 +84,7 @@ pvc-92a4d7f2-f23b-4904-bad4-2cbfcff6e388 Name | Meaning | Available Value | Mandatory | Default value --- | --- | --- | --- | --- -volumeHandle | Specify a value the driver can use to uniquely identify the storage blob container in the cluster. | A recommended way to produce a unique value is to combine the globally unique storage account name and container name: {account-name}_{container-name}. Note: the # character is reserved for internal use. | Yes | +volumeHandle | Specify a value the driver can use to uniquely identify the storage blob container in the cluster. | A recommended way to produce a unique value is to combine the globally unique storage account name and container name: {account-name}_{container-name}. Note: the # character is reserved for internal use, the / character is not allowed. | Yes | volumeAttributes.resourceGroup | Azure resource group name | existing resource group name | No | if empty, driver will use the same resource group name as current k8s cluster volumeAttributes.storageAccount | existing storage account name | existing storage account name | Yes | volumeAttributes.containerName | existing container name | existing container name | Yes | @@ -80,6 +92,7 @@ volumeAttributes.protocol | specify blobfuse, blobfuse2 or NFSv3 mount (blobfuse --- | **Following parameters are only for blobfuse** | --- | --- | volumeAttributes.secretName | secret name that stores storage account name and key(only applies for SMB) | | No | volumeAttributes.secretNamespace | secret namespace | `default`,`kube-system`, etc | No | pvc namespace +volumeAttributes.getLatestAccountKey | whether getting the latest account key based on the creation time, this driver would get the first key by default | `true`,`false` | No | `false` nodeStageSecretRef.name | secret name that stores(check below examples):
`azurestorageaccountkey`
`azurestorageaccountsastoken`
`msisecret`
`azurestoragespnclientsecret` | existing Kubernetes secret name | No | nodeStageSecretRef.namespace | secret namespace | k8s namespace | Yes | --- | **Following parameters are only for NFS protocol** | --- | --- | diff --git a/docs/install-blob-csi-driver.md b/docs/install-blob-csi-driver.md index bde4861ca..668fea9f7 100644 --- a/docs/install-blob-csi-driver.md +++ b/docs/install-blob-csi-driver.md @@ -4,6 +4,6 @@ > - please use helm install method for more customization, e.g. Azure Stack, RedHat OpenShift support. > - [install CSI driver master version](./install-csi-driver-master.md) (only for testing purpose) - - [install v1.22.0 CSI driver](./install-csi-driver-v1.22.0.md) - - [install v1.21.3 CSI driver](./install-csi-driver-v1.21.3.md) - - [install v1.20.2 CSI driver](./install-csi-driver-v1.20.2.md) + - [install v1.23.0 CSI driver](./install-csi-driver-v1.23.0.md) + - [install v1.22.2 CSI driver](./install-csi-driver-v1.22.2.md) + - [install v1.21.4 CSI driver](./install-csi-driver-v1.21.4.md) diff --git a/docs/install-csi-driver-v1.21.3.md b/docs/install-csi-driver-v1.21.4.md similarity index 83% rename from docs/install-csi-driver-v1.21.3.md rename to docs/install-csi-driver-v1.21.4.md index 61a85fbd7..8e00b8184 100644 --- a/docs/install-csi-driver-v1.21.3.md +++ b/docs/install-csi-driver-v1.21.4.md @@ -1,4 +1,4 @@ -# Install Azure Blob Storage CSI driver v1.21.3 version on a kubernetes cluster +# Install Azure Blob Storage CSI driver v1.21.4 version on a kubernetes cluster > `blobfuse-proxy` is only available for debian based agent nodes, remove `blobfuse-proxy` parameter in installation steps if it's not applicable. > If you have already installed Helm, you can also use it to install this driver. Please check [Installation with Helm](../charts/README.md). @@ -6,14 +6,14 @@ If you have already installed Helm, you can also use it to install this driver. ## Install with kubectl - Option#1. remote install ```console -curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.21.3/deploy/install-driver.sh | bash -s v1.21.3 blobfuse-proxy -- +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.21.4/deploy/install-driver.sh | bash -s v1.21.4 blobfuse-proxy -- ``` - Option#2. local install ```console git clone https://github.com/kubernetes-sigs/blob-csi-driver.git cd blob-csi-driver -./deploy/install-driver.sh v1.21.3 local,blobfuse-proxy +./deploy/install-driver.sh v1.21.4 local,blobfuse-proxy ``` - check pods status: @@ -35,13 +35,13 @@ csi-blob-node-dr4s4 3/3 Running 0 35s ### clean up Blob CSI driver - Option#1. remote uninstall ```console -curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.21.3/deploy/uninstall-driver.sh | bash -s v1.21.3 -- +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.21.4/deploy/uninstall-driver.sh | bash -s v1.21.4 -- ``` - Option#2. local uninstall ```console git clone https://github.com/kubernetes-sigs/blob-csi-driver.git cd blob-csi-driver -git checkout v1.21.3 -./deploy/uninstall-driver.sh v1.21.3 local +git checkout v1.21.4 +./deploy/uninstall-driver.sh v1.21.4 local ``` diff --git a/docs/install-csi-driver-v1.22.1.md b/docs/install-csi-driver-v1.22.1.md new file mode 100644 index 000000000..0f2fbd3d9 --- /dev/null +++ b/docs/install-csi-driver-v1.22.1.md @@ -0,0 +1,47 @@ +# Install Azure Blob Storage CSI driver v1.22.1 version on a kubernetes cluster +> `blobfuse-proxy` is only available for debian based agent nodes, remove `blobfuse-proxy` parameter in installation steps if it's not applicable. +> +If you have already installed Helm, you can also use it to install this driver. Please check [Installation with Helm](../charts/README.md). + +## Install with kubectl + - Option#1. remote install +```console +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.22.1/deploy/install-driver.sh | bash -s v1.22.1 blobfuse-proxy -- +``` + + - Option#2. local install +```console +git clone https://github.com/kubernetes-sigs/blob-csi-driver.git +cd blob-csi-driver +./deploy/install-driver.sh v1.22.1 local,blobfuse-proxy +``` + +- check pods status: +```console +kubectl -n kube-system get pod -o wide -l app=csi-blob-controller +kubectl -n kube-system get pod -o wide -l app=csi-blob-node +``` + +example output: + +```console +NAME READY STATUS RESTARTS AGE IP NODE +csi-blob-controller-56bfddd689-dh5tk 4/4 Running 0 35s 10.240.0.19 k8s-agentpool-22533604-0 +csi-blob-controller-56bfddd689-8pgr4 4/4 Running 0 35s 10.240.0.35 k8s-agentpool-22533604-1 +csi-blob-node-cvgbs 3/3 Running 0 35s 10.240.0.35 k8s-agentpool-22533604-1 +csi-blob-node-dr4s4 3/3 Running 0 35s 10.240.0.4 k8s-agentpool-22533604-0 +``` + +### clean up Blob CSI driver +- Option#1. remote uninstall +```console +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.22.1/deploy/uninstall-driver.sh | bash -s v1.22.1 -- +``` + + - Option#2. local uninstall +```console +git clone https://github.com/kubernetes-sigs/blob-csi-driver.git +cd blob-csi-driver +git checkout v1.22.1 +./deploy/uninstall-driver.sh v1.22.1 local +``` diff --git a/docs/install-csi-driver-v1.22.2.md b/docs/install-csi-driver-v1.22.2.md new file mode 100644 index 000000000..ad56f14d4 --- /dev/null +++ b/docs/install-csi-driver-v1.22.2.md @@ -0,0 +1,47 @@ +# Install Azure Blob Storage CSI driver v1.22.2 version on a kubernetes cluster +> `blobfuse-proxy` is only available for debian based agent nodes, remove `blobfuse-proxy` parameter in installation steps if it's not applicable. +> +If you have already installed Helm, you can also use it to install this driver. Please check [Installation with Helm](../charts/README.md). + +## Install with kubectl + - Option#1. remote install +```console +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.22.2/deploy/install-driver.sh | bash -s v1.22.2 blobfuse-proxy -- +``` + + - Option#2. local install +```console +git clone https://github.com/kubernetes-sigs/blob-csi-driver.git +cd blob-csi-driver +./deploy/install-driver.sh v1.22.2 local,blobfuse-proxy +``` + +- check pods status: +```console +kubectl -n kube-system get pod -o wide -l app=csi-blob-controller +kubectl -n kube-system get pod -o wide -l app=csi-blob-node +``` + +example output: + +```console +NAME READY STATUS RESTARTS AGE IP NODE +csi-blob-controller-56bfddd689-dh5tk 4/4 Running 0 35s 10.240.0.19 k8s-agentpool-22533604-0 +csi-blob-controller-56bfddd689-8pgr4 4/4 Running 0 35s 10.240.0.35 k8s-agentpool-22533604-1 +csi-blob-node-cvgbs 3/3 Running 0 35s 10.240.0.35 k8s-agentpool-22533604-1 +csi-blob-node-dr4s4 3/3 Running 0 35s 10.240.0.4 k8s-agentpool-22533604-0 +``` + +### clean up Blob CSI driver +- Option#1. remote uninstall +```console +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.22.2/deploy/uninstall-driver.sh | bash -s v1.22.2 -- +``` + + - Option#2. local uninstall +```console +git clone https://github.com/kubernetes-sigs/blob-csi-driver.git +cd blob-csi-driver +git checkout v1.22.2 +./deploy/uninstall-driver.sh v1.22.2 local +``` diff --git a/docs/install-csi-driver-v1.22.0.md b/docs/install-csi-driver-v1.23.0.md similarity index 83% rename from docs/install-csi-driver-v1.22.0.md rename to docs/install-csi-driver-v1.23.0.md index c5f8d38d0..4bb4fdcb7 100644 --- a/docs/install-csi-driver-v1.22.0.md +++ b/docs/install-csi-driver-v1.23.0.md @@ -1,4 +1,4 @@ -# Install Azure Blob Storage CSI driver v1.22.0 version on a kubernetes cluster +# Install Azure Blob Storage CSI driver v1.23.0 version on a kubernetes cluster > `blobfuse-proxy` is only available for debian based agent nodes, remove `blobfuse-proxy` parameter in installation steps if it's not applicable. > If you have already installed Helm, you can also use it to install this driver. Please check [Installation with Helm](../charts/README.md). @@ -6,14 +6,14 @@ If you have already installed Helm, you can also use it to install this driver. ## Install with kubectl - Option#1. remote install ```console -curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.22.0/deploy/install-driver.sh | bash -s v1.22.0 blobfuse-proxy -- +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.23.0/deploy/install-driver.sh | bash -s v1.23.0 blobfuse-proxy -- ``` - Option#2. local install ```console git clone https://github.com/kubernetes-sigs/blob-csi-driver.git cd blob-csi-driver -./deploy/install-driver.sh v1.22.0 local,blobfuse-proxy +./deploy/install-driver.sh v1.23.0 local,blobfuse-proxy ``` - check pods status: @@ -35,13 +35,13 @@ csi-blob-node-dr4s4 3/3 Running 0 35s ### clean up Blob CSI driver - Option#1. remote uninstall ```console -curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.22.0/deploy/uninstall-driver.sh | bash -s v1.22.0 -- +curl -skSL https://raw.githubusercontent.com/kubernetes-sigs/blob-csi-driver/v1.23.0/deploy/uninstall-driver.sh | bash -s v1.23.0 -- ``` - Option#2. local uninstall ```console git clone https://github.com/kubernetes-sigs/blob-csi-driver.git cd blob-csi-driver -git checkout v1.22.0 -./deploy/uninstall-driver.sh v1.22.0 local +git checkout v1.23.0 +./deploy/uninstall-driver.sh v1.23.0 local ``` diff --git a/go.mod b/go.mod index 6bad0e8be..bf554ed55 100644 --- a/go.mod +++ b/go.mod @@ -4,69 +4,69 @@ go 1.20 require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 - github.com/Azure/go-autorest/autorest v0.11.28 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 + github.com/Azure/go-autorest/autorest v0.11.29 github.com/Azure/go-autorest/autorest/adal v0.9.23 github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/container-storage-interface/spec v1.8.0 - github.com/gofrs/uuid v4.2.0+incompatible // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 github.com/imdario/mergo v0.3.9 // indirect github.com/kubernetes-csi/csi-lib-utils v0.13.0 - github.com/onsi/gomega v1.27.6 - github.com/pborman/uuid v1.2.0 - github.com/pelletier/go-toml v1.9.4 - github.com/stretchr/testify v1.8.2 - golang.org/x/net v0.10.0 - google.golang.org/grpc v1.51.0 - google.golang.org/protobuf v1.30.0 - k8s.io/api v0.27.1 - k8s.io/apimachinery v0.27.1 - k8s.io/client-go v0.27.1 - k8s.io/component-base v0.27.1 - k8s.io/klog/v2 v2.90.1 - k8s.io/kubernetes v1.27.3 - k8s.io/mount-utils v0.27.1 - k8s.io/utils v0.0.0-20230209194617-a36077c30491 - sigs.k8s.io/cloud-provider-azure v1.27.1-0.20230423180712-b979bea29b6a + github.com/onsi/gomega v1.27.10 + github.com/pborman/uuid v1.2.1 + github.com/pelletier/go-toml v1.9.5 + github.com/stretchr/testify v1.8.4 + golang.org/x/net v0.17.0 + google.golang.org/grpc v1.58.3 + google.golang.org/protobuf v1.31.0 + k8s.io/api v0.28.1 + k8s.io/apimachinery v0.28.1 + k8s.io/client-go v0.28.1 + k8s.io/component-base v0.28.1 + k8s.io/klog/v2 v2.100.1 + k8s.io/kubernetes v1.28.2 + k8s.io/mount-utils v0.28.1 + k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 + sigs.k8s.io/cloud-provider-azure v1.27.1-0.20230907063607-e9994a5f9c7a sigs.k8s.io/yaml v1.3.0 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.0.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1 github.com/go-ini/ini v1.67.0 - github.com/jongio/azidext/go/azidext v0.4.0 - github.com/onsi/ginkgo/v2 v2.9.5 + github.com/jongio/azidext/go/azidext v0.5.0 + github.com/onsi/ginkgo/v2 v2.13.0 github.com/pkg/errors v0.9.1 github.com/satori/go.uuid v1.2.0 golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 - k8s.io/apiserver v0.27.1 - k8s.io/pod-security-admission v0.27.1 + k8s.io/apiserver v0.28.1 + k8s.io/pod-security-admission v0.28.1 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/autorest/mocks v0.4.2 // indirect github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect + github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v4 v4.2.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/coreos/go-semver v0.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.4.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/felixge/httpsnoop v1.0.3 // indirect @@ -74,16 +74,16 @@ require ( github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.1 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/cel-go v0.12.6 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/cel-go v0.16.1 // indirect + github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/uuid v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect @@ -93,8 +93,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -104,16 +103,16 @@ require ( github.com/opencontainers/selinux v1.10.0 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.7 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect - go.etcd.io/etcd/client/v3 v3.5.7 // indirect + go.etcd.io/etcd/api/v3 v3.5.9 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect + go.etcd.io/etcd/client/v3 v3.5.9 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.1 // indirect go.opentelemetry.io/otel v1.10.0 // indirect @@ -124,31 +123,33 @@ require ( go.opentelemetry.io/otel/sdk v1.10.0 // indirect go.opentelemetry.io/otel/trace v1.10.0 // indirect go.opentelemetry.io/proto/otlp v0.19.0 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.19.0 // indirect - golang.org/x/crypto v0.8.0 // indirect - golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.org/x/tools v0.9.1 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.12.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 // indirect + google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.0.0 // indirect - k8s.io/cloud-provider v0.27.1 // indirect - k8s.io/component-helpers v0.27.1 // indirect - k8s.io/controller-manager v0.27.1 // indirect - k8s.io/kms v0.27.1 // indirect - k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect + k8s.io/cloud-provider v0.28.1 // indirect + k8s.io/component-helpers v0.28.1 // indirect + k8s.io/controller-manager v0.28.1 // indirect + k8s.io/kms v0.28.1 // indirect + k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect k8s.io/kubectl v0.0.0 // indirect - k8s.io/kubelet v0.27.1 // indirect + k8s.io/kubelet v0.28.1 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect @@ -157,31 +158,33 @@ require ( replace ( github.com/niemeyer/pretty => github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e go.etcd.io/etcd => go.etcd.io/etcd v0.0.0-20200410171415-59f5fb25a533 - k8s.io/api => k8s.io/api v0.27.1 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.27.1 - k8s.io/apimachinery => k8s.io/apimachinery v0.27.1 - k8s.io/apiserver => k8s.io/apiserver v0.27.1 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.27.1 - k8s.io/client-go => k8s.io/client-go v0.27.1 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.27.1 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.27.1 - k8s.io/code-generator => k8s.io/code-generator v0.27.1 - k8s.io/component-base => k8s.io/component-base v0.27.1 - k8s.io/component-helpers => k8s.io/component-helpers v0.27.1 - k8s.io/controller-manager => k8s.io/controller-manager v0.27.1 - k8s.io/cri-api => k8s.io/cri-api v0.27.1 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.27.1 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.27.1 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.27.1 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.27.1 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.27.1 - k8s.io/kubectl => k8s.io/kubectl v0.27.1 - k8s.io/kubelet => k8s.io/kubelet v0.27.1 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.27.1 - k8s.io/metrics => k8s.io/metrics v0.27.1 - k8s.io/mount-utils => k8s.io/mount-utils v0.27.1 - k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.27.1 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.27.1 - k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.27.1 - k8s.io/sample-controller => k8s.io/sample-controller v0.27.1 + k8s.io/api => k8s.io/api v0.28.1 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.1 + k8s.io/apimachinery => k8s.io/apimachinery v0.28.1 + k8s.io/apiserver => k8s.io/apiserver v0.28.1 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.28.1 + k8s.io/client-go => k8s.io/client-go v0.28.1 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.28.1 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.28.1 + k8s.io/code-generator => k8s.io/code-generator v0.28.1 + k8s.io/component-base => k8s.io/component-base v0.28.1 + k8s.io/component-helpers => k8s.io/component-helpers v0.28.1 + k8s.io/controller-manager => k8s.io/controller-manager v0.28.1 + k8s.io/cri-api => k8s.io/cri-api v0.28.1 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.28.1 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.28.1 + k8s.io/endpointslice => k8s.io/endpointslice v0.28.1 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.1 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.28.1 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.28.1 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.28.1 + k8s.io/kubectl => k8s.io/kubectl v0.28.1 + k8s.io/kubelet => k8s.io/kubelet v0.28.1 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.28.1 + k8s.io/metrics => k8s.io/metrics v0.28.1 + k8s.io/mount-utils => k8s.io/mount-utils v0.28.1 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.28.1 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.28.1 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.28.1 + k8s.io/sample-controller => k8s.io/sample-controller v0.28.1 ) diff --git a/go.sum b/go.sum index a6ec66363..69feca44f 100644 --- a/go.sum +++ b/go.sum @@ -13,13 +13,15 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.97.0 h1:3DXvAyifywvq64LfkKaMOmkWPS1CikIQdMe2lY9vxU8= +cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= @@ -34,23 +36,23 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 h1:sVW/AFBTGyJxDaMYlq0ct3jUXTtj12tQ6zE2GZUgVQw= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 h1:t/W5MYAuQy81cvM8VUNfRLzhtKpXhVUAN7Cd7KVbTyc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0/go.mod h1:NBanQUfSWiWn3QEpWDTCU0IjBECKOYvl2R8xdRtMtiM= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 h1:Oj853U9kG+RLTCQXpjvOnrv0WaZHxgmZz1TlLywgOPY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.0.0 h1:lMW1lD/17LUA5z1XTURo7LcVG2ICBPlyMHjIUrcFZNQ= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.0.0 h1:Jc2KcpCDMu7wJfkrzn7fs/53QMDXH78GuqnH4HOd7zs= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.0.0/go.mod h1:PFVgFsclKzPqYRT/BiwpfUN22cab0C7FlgXR3iWpwMo= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1 h1:SEy2xmstIphdPwNBUi7uhvjyjhVKISfwjfOJmuy7kg4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.6.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.2.0 h1:8d4U82r7ItT1Es91x3eUcAQweih36KWvUha8AZ9X0Rs= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/keyvault/armkeyvault v1.2.0/go.mod h1:/1bkGperHinQbAHMWivoec/Ucu6//iXo6jn5mhmqCVU= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1 h1:YvQv9Mz6T8oR5ypQOL6erY0Z5t71ak1uHV4QFokCOZk= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.6.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM= -github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA= -github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= +github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= @@ -66,40 +68,32 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0 h1:VgSJlZH5u0k2qxSpqyghcFQKmvYckj46uymKK5XzkBM= -github.com/AzureAD/microsoft-authentication-library-for-go v0.7.0/go.mod h1:BDJ5qMFKx9DugEg3+uQSDCdbYPr5s9vBTrL9P8TpqOU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= -github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= +github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= -github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -110,24 +104,23 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/container-storage-interface/spec v1.8.0 h1:D0vhF3PLIZwlwZEf2eNbpujGCNwspwTYf2idJRJx4xI= github.com/container-storage-interface/spec v1.8.0/go.mod h1:ROLik+GhPslwwWRNFF1KasPzroNARibH2rfz1rkg4H0= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU= -github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -136,8 +129,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= @@ -150,14 +143,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= @@ -167,26 +152,23 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= -github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -222,10 +204,10 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/cel-go v0.12.6 h1:kjeKudqV0OygrAqA9fX6J55S8gj+Jre2tckIm5RoG4M= -github.com/google/cel-go v0.12.6/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw= -github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= -github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/cel-go v0.16.1 h1:3hZfSNiAU3KOiNtxuFXVp5WFy4hf/Ly3Sa4/7F8SXNo= +github.com/google/cel-go v0.16.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +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= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -233,14 +215,13 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/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.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -278,29 +259,19 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= -github.com/jongio/azidext/go/azidext v0.4.0 h1:TOYyVFMeWGgXNhURSgrEtUCu7JAAKgsy+5C4+AEfYlw= -github.com/jongio/azidext/go/azidext v0.4.0/go.mod h1:VrlpGde5B+pPbTUxnThE5UIQQkcebdr3jrC2MmlMVSI= +github.com/jongio/azidext/go/azidext v0.5.0 h1:uPInXD4NZ3J0k79FPwIA0YXknFn+WcqZqSgs3/jPgvQ= +github.com/jongio/azidext/go/azidext v0.5.0/go.mod h1:TVRX/hJhzbsCKaOIzicH6a8IvOH0hpjWk/JwZZgtXeU= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -311,11 +282,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= @@ -323,69 +291,44 @@ github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGp github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= +github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= +github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -396,10 +339,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -408,8 +349,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -418,17 +360,17 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/etcd/api/v3 v3.5.7 h1:sbcmosSVesNrWOJ58ZQFitHMdncusIifYcrBfwrlJSY= -go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= -go.etcd.io/etcd/client/pkg/v3 v3.5.7 h1:y3kf5Gbp4e4q7egZdn5T7W9TSHUvkClN6u+Rq9mEOmg= -go.etcd.io/etcd/client/pkg/v3 v3.5.7/go.mod h1:o0Abi1MK86iad3YrWhgUsbGx1pmTS+hrORWc2CamuhY= -go.etcd.io/etcd/client/v2 v2.305.7 h1:AELPkjNR3/igjbO7CjyF1fPuVPjrblliiKj+Y6xSGOU= -go.etcd.io/etcd/client/v3 v3.5.7 h1:u/OhpiuCgYY8awOHlhIhmGIGpxfBU/GZBUP3m/3/Iz4= -go.etcd.io/etcd/client/v3 v3.5.7/go.mod h1:sOWmj9DZUMyAngS7QQwCyAXXAL6WhgTOPLNS/NabQgw= -go.etcd.io/etcd/pkg/v3 v3.5.7 h1:obOzeVwerFwZ9trMWapU/VjDcYUJb5OfgC1zqEGWO/0= -go.etcd.io/etcd/raft/v3 v3.5.7 h1:aN79qxLmV3SvIq84aNTliYGmjwsW6NqJSnqmI1HLJKc= -go.etcd.io/etcd/server/v3 v3.5.7 h1:BTBD8IJUV7YFgsczZMHhMTS67XuA4KpRquL0MFOJGRk= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/v2 v2.305.9 h1:YZ2OLi0OvR0H75AcgSUajjd5uqKDKocQUqROTG11jIo= +go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= +go.etcd.io/etcd/pkg/v3 v3.5.9 h1:6R2jg/aWd/zB9+9JxmijDKStGJAPFsX3e6BeJkMi6eQ= +go.etcd.io/etcd/raft/v3 v3.5.9 h1:ZZ1GIHoUlHsn0QVqiRysAm3/81Xx7+i2d7nSdWxlOiI= +go.etcd.io/etcd/server/v3 v3.5.9 h1:vomEmmxeztLtS5OEH7d0hBAg4cjVIu9wXuNzUZx2ZA0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -455,15 +397,16 @@ go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/A go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +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.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -472,8 +415,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -508,10 +451,9 @@ 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.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= 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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -519,7 +461,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -540,23 +481,19 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -566,18 +503,14 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -587,7 +520,6 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -600,32 +532,25 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -635,13 +560,13 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -687,8 +612,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= -golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= 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= @@ -747,10 +672,13 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21 h1:hrbNEivu7Zn1pxvHk6MBrq9iE22woVILTHqexqBxe6I= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -767,9 +695,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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= @@ -783,31 +710,23 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 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.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= @@ -818,50 +737,50 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.27.1 h1:Z6zUGQ1Vd10tJ+gHcNNNgkV5emCyW+v2XTmn+CLjSd0= -k8s.io/api v0.27.1/go.mod h1:z5g/BpAiD+f6AArpqNjkY+cji8ueZDU/WV1jcj5Jk4E= -k8s.io/apiextensions-apiserver v0.27.1 h1:Hp7B3KxKHBZ/FxmVFVpaDiXI6CCSr49P1OJjxKO6o4g= -k8s.io/apiextensions-apiserver v0.27.1/go.mod h1:8jEvRDtKjVtWmdkhOqE84EcNWJt/uwF8PC4627UZghY= -k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc= -k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM= -k8s.io/apiserver v0.27.1 h1:phY+BtXjjzd+ta3a4kYbomC81azQSLa1K8jo9RBw7Lg= -k8s.io/apiserver v0.27.1/go.mod h1:UGrOjLY2KsieA9Fw6lLiTObxTb8Z1xEba4uqSuMY0WU= -k8s.io/client-go v0.27.1 h1:oXsfhW/qncM1wDmWBIuDzRHNS2tLhK3BZv512Nc59W8= -k8s.io/client-go v0.27.1/go.mod h1:f8LHMUkVb3b9N8bWturc+EDtVVVwZ7ueTVquFAJb2vA= -k8s.io/cloud-provider v0.27.1 h1:482W9e2Yp8LDgTUKrXAxT+nH4pHS2TiBElI/CnfGWac= -k8s.io/cloud-provider v0.27.1/go.mod h1:oN7Zci2Ls2dorwSNd2fMiW/6DA40+F4o2QL70p63bqo= -k8s.io/component-base v0.27.1 h1:kEB8p8lzi4gCs5f2SPU242vOumHJ6EOsOnDM3tTuDTM= -k8s.io/component-base v0.27.1/go.mod h1:UGEd8+gxE4YWoigz5/lb3af3Q24w98pDseXcXZjw+E0= -k8s.io/component-helpers v0.27.1 h1:uY63v834MAHuf3fBiKGQGPq/cToU5kY5SW/58Xv0gl4= -k8s.io/component-helpers v0.27.1/go.mod h1:oOpwSYW1AdL+pU7abHADwX1ZcJl+5c8mnIkvoFZNFWA= -k8s.io/controller-manager v0.27.1 h1:+4OGWAzg4JVLEauPSmyQFIfrYrYQoUsC4MbHmRuPaFU= -k8s.io/controller-manager v0.27.1/go.mod h1:oe9vKl0RPiedlCXmeVbhkDV2yX8r7C4K/B8OGaKdYtY= -k8s.io/csi-translation-lib v0.27.1 h1:D9Hw2iBZzFPriFH0FDyUFdfflYAW6S032P6Yps9sKq8= -k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= -k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kms v0.27.1 h1:JTSQbJb+mcobScQwF0bOmZhIwP17k8GvBsiLlA6SQqw= -k8s.io/kms v0.27.1/go.mod h1:VuTsw0uHlSycKLCkypCGxfFCjLfzf/5YMeATECd/zJA= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= -k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= -k8s.io/kubectl v0.27.1 h1:9T5c5KdpburYiW8XKQSH0Uly1kMNE90aGSnbYUZNdcA= -k8s.io/kubectl v0.27.1/go.mod h1:QsAkSmrRsKTPlAFzF8kODGDl4p35BIwQnc9XFhkcsy8= -k8s.io/kubelet v0.27.1 h1:IkfZ0N9CX/g6EDis7nJw8ZsOuHcpFA6cm0pXQx0g5TY= -k8s.io/kubelet v0.27.1/go.mod h1:g3cIhpZPawo/MvsdnmcLmqDJvDPdbUFkzfyLNz03nQg= -k8s.io/kubernetes v1.27.3 h1:gwufSj7y6X18Q2Gl8v4Ev+AJHdzWkG7A8VNFffS9vu0= -k8s.io/kubernetes v1.27.3/go.mod h1:U8ZXeKBAPxeb4J4/HOaxjw1A9K6WfSH+fY2SS7CR6IM= -k8s.io/mount-utils v0.27.1 h1:RSd0wslbIuwLRaGGNAGMZ3m9FLcvukxJ3FWlOm76W2A= -k8s.io/mount-utils v0.27.1/go.mod h1:vmcjYdi2Vg1VTWY7KkhvwJVY6WDHxb/QQhiQKkR8iNs= -k8s.io/pod-security-admission v0.27.1 h1:if4d1zzcpNOZNvljvJ0nTCshFPUmnkIsy7KYJg7FP08= -k8s.io/pod-security-admission v0.27.1/go.mod h1:dICAHAC4DE0q+yrGuPJ8kuJ5dEsWtqNkclzCDckHj/s= -k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.28.1 h1:i+0O8k2NPBCPYaMB+uCkseEbawEt/eFaiRqUx8aB108= +k8s.io/api v0.28.1/go.mod h1:uBYwID+66wiL28Kn2tBjBYQdEU0Xk0z5qF8bIBqk/Dg= +k8s.io/apiextensions-apiserver v0.28.1 h1:l2ThkBRjrWpw4f24uq0Da2HaEgqJZ7pcgiEUTKSmQZw= +k8s.io/apiextensions-apiserver v0.28.1/go.mod h1:sVvrI+P4vxh2YBBcm8n2ThjNyzU4BQGilCQ/JAY5kGs= +k8s.io/apimachinery v0.28.1 h1:EJD40og3GizBSV3mkIoXQBsws32okPOy+MkRyzh6nPY= +k8s.io/apimachinery v0.28.1/go.mod h1:X0xh/chESs2hP9koe+SdIAcXWcQ+RM5hy0ZynB+yEvw= +k8s.io/apiserver v0.28.1 h1:dw2/NKauDZCnOUAzIo2hFhtBRUo6gQK832NV8kuDbGM= +k8s.io/apiserver v0.28.1/go.mod h1:d8aizlSRB6yRgJ6PKfDkdwCy2DXt/d1FDR6iJN9kY1w= +k8s.io/client-go v0.28.1 h1:pRhMzB8HyLfVwpngWKE8hDcXRqifh1ga2Z/PU9SXVK8= +k8s.io/client-go v0.28.1/go.mod h1:pEZA3FqOsVkCc07pFVzK076R+P/eXqsgx5zuuRWukNE= +k8s.io/cloud-provider v0.28.1 h1:bR7lIRYBHqxfsOkUsY2hJ7V7vmStxb0wjJJdrID8+7I= +k8s.io/cloud-provider v0.28.1/go.mod h1:7jxsc3c15go606KLXnUq8Cy4nX1R1dxFRgn/czIJp/Q= +k8s.io/component-base v0.28.1 h1:LA4AujMlK2mr0tZbQDZkjWbdhTV5bRyEyAFe0TJxlWg= +k8s.io/component-base v0.28.1/go.mod h1:jI11OyhbX21Qtbav7JkhehyBsIRfnO8oEgoAR12ArIU= +k8s.io/component-helpers v0.28.1 h1:ts/vykhyUmPLhUl/hdLdf+a4BWA0giQ3f25HAIhl+RI= +k8s.io/component-helpers v0.28.1/go.mod h1:rHFPj33uXNbgppg+ilmjJ4oR73prZQNRRmg+utVOAb0= +k8s.io/controller-manager v0.28.1 h1:+md/3DAsdLVoMe3AewhyTxljnPLE/gyshTDZ8sX4Rf0= +k8s.io/controller-manager v0.28.1/go.mod h1:yZ8aOBpMYOBTAI/Jd0qpaUzZUlQigmtRcdYg2VgWKiU= +k8s.io/csi-translation-lib v0.28.1 h1:6EdpqKbwgJEcLxRzcGR1GnbyJrcTcUMhHTYfMwFT3LA= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.28.1 h1:QLNTIc0k7Yebkt9yobj9Y9qBoRCMB4dq+pFCxVXVBnY= +k8s.io/kms v0.28.1/go.mod h1:I2TwA8oerDRInHWWBOqSUzv1EJDC1+55FQKYkxaPxh0= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ= +k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM= +k8s.io/kubectl v0.28.1 h1:jAq4yKEqQL+fwkWcEsUWxhJ7uIRcOYQraJxx4SyAMTY= +k8s.io/kubectl v0.28.1/go.mod h1:a0nk/lMMeKBulp0lMTJAKbkjZg1ykqfLfz/d6dnv1ak= +k8s.io/kubelet v0.28.1 h1:QRfx+jrzNgkLnMSw/nxGkAN7cjHPO446MDbjPITxLkk= +k8s.io/kubelet v0.28.1/go.mod h1:xYBbbJ0e2Rtb/hv+QFie448lFF81J990ImIptce2AHk= +k8s.io/kubernetes v1.28.2 h1:GhcnYeNTukeaC0dD5BC+UWBvzQsFEpWj7XBVMQptfYc= +k8s.io/kubernetes v1.28.2/go.mod h1:FmB1Mlp9ua0ezuwQCTGs/y6wj/fVisN2sVxhzjj0WDk= +k8s.io/mount-utils v0.28.1 h1:oyPtn8ZVxniBfwSlQaBF4fr7QVNYzUuk+gkuxEJgil0= +k8s.io/mount-utils v0.28.1/go.mod h1:AyP8LmZSLgpGdFQr+vzHTerlPiGvXUdP99n98Er47jw= +k8s.io/pod-security-admission v0.28.1 h1:d3jvo/+C6yDR1wnlX9ot1WvLyJ5R4uachJyxhdn9cW8= +k8s.io/pod-security-admission v0.28.1/go.mod h1:Qm1rSy3l96m6QXGNU/8u+cmdpNdmAeA3OYDinrXhi6U= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk= +k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0= -sigs.k8s.io/cloud-provider-azure v1.27.1-0.20230423180712-b979bea29b6a h1:wscyx3uWXA8OiV8v8x18ak1lIK8U3q6yS2laIHfe8RQ= -sigs.k8s.io/cloud-provider-azure v1.27.1-0.20230423180712-b979bea29b6a/go.mod h1:vRG0GaFye/VlBpSNUGxYHdC3ZTBwFUnc5ZLng+YoE9g= +sigs.k8s.io/cloud-provider-azure v1.27.1-0.20230907063607-e9994a5f9c7a h1:7/WSpSvXdr/mwDoEMjz0tqlyaACPT9dL/+c1FnbhV6U= +sigs.k8s.io/cloud-provider-azure v1.27.1-0.20230907063607-e9994a5f9c7a/go.mod h1:T86YMaSDRFlMqX5Kmb+KqeASg4Px75GQfcs0sD0yqAw= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/apis/config/doc.go b/hack/boilerplate/boilerplate.generatego.txt similarity index 75% rename from vendor/k8s.io/kubernetes/pkg/kubelet/apis/config/doc.go rename to hack/boilerplate/boilerplate.generatego.txt index ad40e6834..0926592d3 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/apis/config/doc.go +++ b/hack/boilerplate/boilerplate.generatego.txt @@ -1,5 +1,5 @@ /* -Copyright 2017 The Kubernetes Authors. +Copyright The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -13,8 +13,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ - -// +k8s:deepcopy-gen=package -// +groupName=kubelet.config.k8s.io - -package config // import "k8s.io/kubernetes/pkg/kubelet/apis/config" diff --git a/hack/boilerplate/boilerplate.gomock.txt b/hack/boilerplate/boilerplate.gomock.txt new file mode 100644 index 000000000..b66f79dd4 --- /dev/null +++ b/hack/boilerplate/boilerplate.gomock.txt @@ -0,0 +1,15 @@ +// /* +// Copyright The Kubernetes Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// */ diff --git a/hack/boilerplate/boilerplate.py b/hack/boilerplate/boilerplate.py index 1c1b5a744..58e5f4214 100755 --- a/hack/boilerplate/boilerplate.py +++ b/hack/boilerplate/boilerplate.py @@ -65,6 +65,14 @@ def get_refs(): return refs +def is_generated_file(filename, data, regexs): + for d in skipped_ungenerated_files: + if d in filename: + return False + + p = regexs["generated"] + return p.search(data) + def file_passes(filename, refs, regexs): try: f = open(filename, 'r') @@ -75,15 +83,21 @@ def file_passes(filename, refs, regexs): data = f.read() f.close() + # determine if the file is automatically generated + generated = is_generated_file(filename, data, regexs) + basename = os.path.basename(filename) extension = file_extension(filename) + if generated: + if extension == "go": + extension = "gomock" if extension != "": ref = refs[extension] else: ref = refs[basename] # remove build tags from the top of Go files - if extension == "go": + if extension == "go" or extension == "gomock": p = regexs["go_build_constraints"] (data, found) = p.subn("", data, 1) if is_autogenerated(data, regexs): @@ -142,6 +156,10 @@ def file_extension(filename): 'cluster/env.sh', 'vendor', 'test/e2e/generated/bindata.go', 'repo-infra/verify/boilerplate/test', '.glide'] + # list all the files contain 'DO NOT EDIT', but are not generated +skipped_ungenerated_files = [ + 'hack/boilerplate/boilerplate.py'] + def normalize_files(files): newfiles = [] for pathname in files: @@ -191,6 +209,8 @@ def get_regexs(): regexs["go_build_constraints"] = re.compile(r"^(// \+build.*\n)+\n", re.MULTILINE) # strip #!.* from shell scripts regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE) + # Search for generated files + regexs["generated"] = re.compile('DO NOT EDIT') return regexs diff --git a/hack/update-mock.sh b/hack/update-mock.sh new file mode 100644 index 000000000..29010a696 --- /dev/null +++ b/hack/update-mock.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Copyright 2020 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -euo pipefail + +REPO_ROOT=$(realpath $(dirname ${BASH_SOURCE})/..) +COPYRIGHT_FILE="${REPO_ROOT}/hack/boilerplate/boilerplate.generatego.txt" + +if ! type mockgen &> /dev/null; then + echo "mockgen not exist, install it" + go install github.com/golang/mock/mockgen@v1.6.0 +fi + +echo "Updating mocks for util.go" +mockgen -copyright_file=$COPYRIGHT_FILE -source=pkg/util/util.go -package=util -destination=pkg/util/util_mock.go diff --git a/hack/verify-examples.sh b/hack/verify-examples.sh index 5174da809..a84e059e7 100755 --- a/hack/verify-examples.sh +++ b/hack/verify-examples.sh @@ -42,9 +42,6 @@ EXAMPLES=(\ deploy/example/deployment.yaml \ deploy/example/statefulset.yaml \ deploy/example/statefulset-nonroot.yaml \ - deploy/example/deployment-nfs.yaml \ - deploy/example/statefulset-nfs.yaml \ - deploy/example/statefulset-nonroot-nfs.yaml \ ) for EXAMPLE in "${EXAMPLES[@]}"; do diff --git a/hack/verify-gomod.sh b/hack/verify-gomod.sh index d45a265df..77f67ef7b 100755 --- a/hack/verify-gomod.sh +++ b/hack/verify-gomod.sh @@ -30,3 +30,5 @@ if [[ -n "${diff}" ]]; then exit 1 fi echo "Done" + +go list -mod readonly -m all diff --git a/hack/verify-helm-chart.sh b/hack/verify-helm-chart.sh index 337ff53e6..f5591c363 100755 --- a/hack/verify-helm-chart.sh +++ b/hack/verify-helm-chart.sh @@ -58,7 +58,7 @@ if [[ -z "$(command -v jq)" ]]; then fi # jq-equivalent for yaml -pip install yq --ignore-installed PyYAML +pip install yq --break-system-packages --ignore-installed PyYAML # Extract images from csi-blob-controller.yaml expected_csi_provisioner_image="$(cat ${PKG_ROOT}/deploy/csi-blob-controller.yaml | yq -r .spec.template.spec.containers[0].image | head -n 1)" diff --git a/pkg/blob/azure.go b/pkg/blob/azure.go index 751fcc9dd..9e53c7cb1 100644 --- a/pkg/blob/azure.go +++ b/pkg/blob/azure.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" + "k8s.io/utils/pointer" azure "sigs.k8s.io/cloud-provider-azure/pkg/provider" providerconfig "sigs.k8s.io/cloud-provider-azure/pkg/provider/config" @@ -251,7 +252,7 @@ func (d *Driver) updateSubnetServiceEndpoints(ctx context.Context, vnetResourceG } serviceEndpoints := *subnet.SubnetPropertiesFormat.ServiceEndpoints for _, v := range serviceEndpoints { - if v.Service != nil && *v.Service == storageService { + if strings.HasPrefix(pointer.StringDeref(v.Service, ""), storageService) { storageServiceExists = true klog.V(4).Infof("serviceEndpoint(%s) is already in subnet(%s)", storageService, subnetName) break diff --git a/pkg/blob/blob.go b/pkg/blob/blob.go index 2d53f76e8..be78a2159 100644 --- a/pkg/blob/blob.go +++ b/pkg/blob/blob.go @@ -19,6 +19,7 @@ package blob import ( "fmt" "os" + "strconv" "strings" "sync" "time" @@ -48,64 +49,72 @@ import ( const ( // DefaultDriverName holds the name of the csi-driver - DefaultDriverName = "blob.csi.azure.com" - blobCSIDriverName = "blob_csi_driver" - separator = "#" - volumeIDTemplate = "%s#%s#%s#%s#%s#%s" - secretNameTemplate = "azure-storage-account-%s-secret" - serverNameField = "server" - storageEndpointSuffixField = "storageendpointsuffix" - tagsField = "tags" - matchTagsField = "matchtags" - protocolField = "protocol" - accountNameField = "accountname" - accountKeyField = "accountkey" - storageAccountField = "storageaccount" - storageAccountTypeField = "storageaccounttype" - skuNameField = "skuname" - subscriptionIDField = "subscriptionid" - resourceGroupField = "resourcegroup" - locationField = "location" - secretNameField = "secretname" - secretNamespaceField = "secretnamespace" - containerNameField = "containername" - containerNamePrefixField = "containernameprefix" - storeAccountKeyField = "storeaccountkey" - isHnsEnabledField = "ishnsenabled" - softDeleteBlobsField = "softdeleteblobs" - softDeleteContainersField = "softdeletecontainers" - enableBlobVersioningField = "enableblobversioning" - getAccountKeyFromSecretField = "getaccountkeyfromsecret" - storageSPNClientIDField = "azurestoragespnclientid" - storageSPNTenantIDField = "azurestoragespntenantid" - keyVaultURLField = "keyvaulturl" - keyVaultSecretNameField = "keyvaultsecretname" - keyVaultSecretVersionField = "keyvaultsecretversion" - storageAccountNameField = "storageaccountname" - allowBlobPublicAccessField = "allowblobpublicaccess" - requireInfraEncryptionField = "requireinfraencryption" - ephemeralField = "csi.storage.k8s.io/ephemeral" - podNamespaceField = "csi.storage.k8s.io/pod.namespace" - mountOptionsField = "mountoptions" - falseValue = "false" - trueValue = "true" - defaultSecretAccountName = "azurestorageaccountname" - defaultSecretAccountKey = "azurestorageaccountkey" - accountSasTokenField = "azurestorageaccountsastoken" - msiSecretField = "msisecret" - storageSPNClientSecretField = "azurestoragespnclientsecret" - EcProtocol = "edgecache" - Fuse = "fuse" - Fuse2 = "fuse2" - NFS = "nfs" - vnetResourceGroupField = "vnetresourcegroup" - vnetNameField = "vnetname" - subnetNameField = "subnetname" - accessTierField = "accesstier" - networkEndpointTypeField = "networkendpointtype" - mountPermissionsField = "mountpermissions" - useDataPlaneAPIField = "usedataplaneapi" - EcStrgAuthenticationField = "edgecache-storage-auth" + DefaultDriverName = "blob.csi.azure.com" + blobCSIDriverName = "blob_csi_driver" + separator = "#" + volumeIDTemplate = "%s#%s#%s#%s#%s#%s" + secretNameTemplate = "azure-storage-account-%s-secret" + serverNameField = "server" + storageEndpointSuffixField = "storageendpointsuffix" + tagsField = "tags" + matchTagsField = "matchtags" + protocolField = "protocol" + accountNameField = "accountname" + accountKeyField = "accountkey" + storageAccountField = "storageaccount" + storageAccountTypeField = "storageaccounttype" + skuNameField = "skuname" + subscriptionIDField = "subscriptionid" + resourceGroupField = "resourcegroup" + locationField = "location" + secretNameField = "secretname" + secretNamespaceField = "secretnamespace" + containerNameField = "containername" + containerNamePrefixField = "containernameprefix" + storeAccountKeyField = "storeaccountkey" + isHnsEnabledField = "ishnsenabled" + softDeleteBlobsField = "softdeleteblobs" + softDeleteContainersField = "softdeletecontainers" + enableBlobVersioningField = "enableblobversioning" + getAccountKeyFromSecretField = "getaccountkeyfromsecret" + storageSPNClientIDField = "azurestoragespnclientid" + storageSPNTenantIDField = "azurestoragespntenantid" + keyVaultURLField = "keyvaulturl" + keyVaultSecretNameField = "keyvaultsecretname" + keyVaultSecretVersionField = "keyvaultsecretversion" + storageAccountNameField = "storageaccountname" + allowBlobPublicAccessField = "allowblobpublicaccess" + requireInfraEncryptionField = "requireinfraencryption" + ephemeralField = "csi.storage.k8s.io/ephemeral" + podNamespaceField = "csi.storage.k8s.io/pod.namespace" + mountOptionsField = "mountoptions" + falseValue = "false" + trueValue = "true" + defaultSecretAccountName = "azurestorageaccountname" + defaultSecretAccountKey = "azurestorageaccountkey" + accountSasTokenField = "azurestorageaccountsastoken" + msiSecretField = "msisecret" + storageSPNClientSecretField = "azurestoragespnclientsecret" + EcProtocol = "edgecache" + Fuse = "fuse" + Fuse2 = "fuse2" + NFS = "nfs" + AZNFS = "aznfs" + vnetResourceGroupField = "vnetresourcegroup" + vnetNameField = "vnetname" + subnetNameField = "subnetname" + accessTierField = "accesstier" + networkEndpointTypeField = "networkendpointtype" + mountPermissionsField = "mountpermissions" + useDataPlaneAPIField = "usedataplaneapi" + EcStrgAuthenticationField = "edgecache-storage-auth" + getLatestAccountKeyField = "getlatestaccountkey" + storageAuthTypeField = "azurestorageauthtype" + storageIentityClientIDField = "azurestorageidentityclientid" + storageIdentityObjectIDField = "azurestorageidentityobjectid" + storageIdentityResourceIDField = "azurestorageidentityresourceid" + msiEndpointField = "msiendpoint" + storageAADEndpointField = "azurestorageaadendpoint" // See https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names containerNameMinLength = 3 @@ -167,6 +176,9 @@ type DriverOptions struct { MountPermissions uint64 KubeAPIQPS float64 KubeAPIBurst int + EnableAznfsMount bool + VolStatsCacheExpireInMinutes int + SasTokenExpirationMinutes int } // Driver implements all interfaces of CSI drivers @@ -193,6 +205,7 @@ type Driver struct { edgeCacheManager *edgecache.Manager kubeAPIQPS float64 kubeAPIBurst int + enableAznfsMount bool mounter *mount.SafeFormatAndMount volLockMap *util.LockMap // A map storing all volumes with ongoing operations so that additional operations @@ -203,9 +216,15 @@ type Driver struct { // a map storing all volumes created by this driver volMap sync.Map // a timed cache storing all volumeIDs and storage accounts that are using data plane API - dataPlaneAPIVolCache *azcache.TimedCache + dataPlaneAPIVolCache azcache.Resource // a timed cache storing account search history (solve account list throttling issue) - accountSearchCache *azcache.TimedCache + accountSearchCache azcache.Resource + // a timed cache storing volume stats + volStatsCache azcache.Resource + // sas expiry time for azcopy in volume clone + sasTokenExpirationMinutes int + // azcopy for provide exec mock for ut + azcopy *util.Azcopy } // NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version & @@ -232,6 +251,9 @@ func NewDriver(options *DriverOptions) *Driver { mountPermissions: options.MountPermissions, kubeAPIQPS: options.KubeAPIQPS, kubeAPIBurst: options.KubeAPIBurst, + enableAznfsMount: options.EnableAznfsMount, + sasTokenExpirationMinutes: options.SasTokenExpirationMinutes, + azcopy: &util.Azcopy{}, } d.Name = options.DriverName d.Version = driverVersion @@ -239,10 +261,17 @@ func NewDriver(options *DriverOptions) *Driver { var err error getter := func(key string) (interface{}, error) { return nil, nil } - if d.accountSearchCache, err = azcache.NewTimedcache(time.Minute, getter); err != nil { + if d.accountSearchCache, err = azcache.NewTimedCache(time.Minute, getter, false); err != nil { klog.Fatalf("%v", err) } - if d.dataPlaneAPIVolCache, err = azcache.NewTimedcache(10*time.Minute, getter); err != nil { + if d.dataPlaneAPIVolCache, err = azcache.NewTimedCache(10*time.Minute, getter, false); err != nil { + klog.Fatalf("%v", err) + } + + if options.VolStatsCacheExpireInMinutes <= 0 { + options.VolStatsCacheExpireInMinutes = 10 // default expire in 10 minutes + } + if d.volStatsCache, err = azcache.NewTimedCache(time.Duration(options.VolStatsCacheExpireInMinutes)*time.Minute, getter, false); err != nil { klog.Fatalf("%v", err) } return &d @@ -277,6 +306,7 @@ func (d *Driver) Run(endpoint, kubeconfig string, testBool bool) { //csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS, csi.ControllerServiceCapability_RPC_EXPAND_VOLUME, csi.ControllerServiceCapability_RPC_SINGLE_NODE_MULTI_WRITER, + csi.ControllerServiceCapability_RPC_CLONE_VOLUME, }) d.AddVolumeCapabilityAccessModes([]csi.VolumeCapability_AccessMode_Mode{ csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, @@ -392,6 +422,7 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr azureStorageAuthType string authEnv []string getAccountKeyFromSecret bool + getLatestAccountKey bool ) for k, v := range attrib { @@ -420,23 +451,27 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr pvcNamespace = v case getAccountKeyFromSecretField: getAccountKeyFromSecret = strings.EqualFold(v, trueValue) - case "azurestorageauthtype": + case storageAuthTypeField: azureStorageAuthType = v authEnv = append(authEnv, "AZURE_STORAGE_AUTH_TYPE="+v) - case "azurestorageidentityclientid": + case storageIentityClientIDField: authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_CLIENT_ID="+v) - case "azurestorageidentityobjectid": + case storageIdentityObjectIDField: authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_OBJECT_ID="+v) - case "azurestorageidentityresourceid": + case storageIdentityResourceIDField: authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_RESOURCE_ID="+v) - case "msiendpoint": + case msiEndpointField: authEnv = append(authEnv, "MSI_ENDPOINT="+v) case storageSPNClientIDField: storageSPNClientID = v case storageSPNTenantIDField: storageSPNTenantID = v - case "azurestorageaadendpoint": + case storageAADEndpointField: authEnv = append(authEnv, "AZURE_STORAGE_AAD_ENDPOINT="+v) + case getLatestAccountKeyField: + if getLatestAccountKey, err = strconv.ParseBool(v); err != nil { + return rgName, accountName, accountKey, containerName, secretName, secretNamespace, authEnv, fmt.Errorf("invalid %s: %s in volume context", getLatestAccountKeyField, v) + } } } klog.V(2).Infof("volumeID(%s) authEnv: %s", volumeID, authEnv) @@ -496,7 +531,7 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr if err != nil && !getAccountKeyFromSecret && (azureStorageAuthType == "" || strings.EqualFold(azureStorageAuthType, "key")) { klog.V(2).Infof("get account(%s) key from secret(%s, %s) failed with error: %v, use cluster identity to get account key instead", accountName, secretNamespace, secretName, err) - accountKey, err = d.cloud.GetStorageAccesskey(ctx, subsID, accountName, rgName) + accountKey, err = d.cloud.GetStorageAccesskey(ctx, subsID, accountName, rgName, getLatestAccountKey) if err != nil { return rgName, accountName, accountKey, containerName, secretName, secretNamespace, authEnv, fmt.Errorf("no key for storage account(%s) under resource group(%s), err %w", accountName, rgName, err) } @@ -578,6 +613,7 @@ func (d *Driver) GetStorageAccountAndContainer(ctx context.Context, volumeID str keyVaultURL string keyVaultSecretName string keyVaultSecretVersion string + getLatestAccountKey bool err error ) @@ -597,6 +633,10 @@ func (d *Driver) GetStorageAccountAndContainer(ctx context.Context, volumeID str accountName = v case storageAccountNameField: // for compatibility accountName = v + case getLatestAccountKeyField: + if getLatestAccountKey, err = strconv.ParseBool(v); err != nil { + return "", "", "", "", fmt.Errorf("invalid %s: %s in volume context", getLatestAccountKeyField, v) + } } } @@ -625,7 +665,7 @@ func (d *Driver) GetStorageAccountAndContainer(ctx context.Context, volumeID str rgName = d.cloud.ResourceGroup } - accountKey, err = d.cloud.GetStorageAccesskey(ctx, subsID, accountName, rgName) + accountKey, err = d.cloud.GetStorageAccesskey(ctx, subsID, accountName, rgName, getLatestAccountKey) if err != nil { return "", "", "", "", fmt.Errorf("no key for storage account(%s) under resource group(%s), err %w", accountName, rgName, err) } @@ -721,10 +761,10 @@ func getStorageAccount(secrets map[string]string) (string, string, error) { } if accountName == "" { - return accountName, accountKey, fmt.Errorf("could not find %s or %s field secrets(%v)", accountNameField, defaultSecretAccountName, secrets) + return accountName, accountKey, fmt.Errorf("could not find %s or %s field in secrets", accountNameField, defaultSecretAccountName) } if accountKey == "" { - return accountName, accountKey, fmt.Errorf("could not find %s or %s field in secrets(%v)", accountKeyField, defaultSecretAccountKey, secrets) + return accountName, accountKey, fmt.Errorf("could not find %s or %s field in secrets", accountKeyField, defaultSecretAccountKey) } accountName = strings.TrimSpace(accountName) @@ -795,7 +835,7 @@ func (d *Driver) GetStorageAccesskey(ctx context.Context, accountOptions *azure. _, accountKey, _, _, _, _, _, err := d.GetInfoFromSecret(ctx, secretName, secretNamespace) //nolint if err != nil { klog.V(2).Infof("could not get account(%s) key from secret(%s) namespace(%s), error: %v, use cluster identity to get account key instead", accountOptions.Name, secretName, secretNamespace, err) - accountKey, err = d.cloud.GetStorageAccesskey(ctx, accountOptions.SubscriptionID, accountOptions.Name, accountOptions.ResourceGroup) + accountKey, err = d.cloud.GetStorageAccesskey(ctx, accountOptions.SubscriptionID, accountOptions.Name, accountOptions.ResourceGroup, accountOptions.GetLatestAccountKey) } return accountOptions.Name, accountKey, err } @@ -820,7 +860,7 @@ func (d *Driver) GetInfoFromSecret(ctx context.Context, secretName, secretNamesp spnClientID := strings.TrimSpace(string(secret.Data[storageSPNClientIDField][:])) spnTenantID := strings.TrimSpace(string(secret.Data[storageSPNTenantIDField][:])) - klog.V(4).Infof("got storage account(%s) from secret", accountName) + klog.V(4).Infof("got storage account(%s) from secret(%s) namespace(%s)", accountName, secretName, secretNamespace) return accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, spnClientID, spnTenantID, nil } diff --git a/pkg/blob/blob_test.go b/pkg/blob/blob_test.go index 3021cfd3f..ea1f2a653 100644 --- a/pkg/blob/blob_test.go +++ b/pkg/blob/blob_test.go @@ -61,6 +61,7 @@ func NewFakeDriver() *Driver { driver.Name = fakeDriverName driver.Version = vendorVersion driver.subnetLockMap = util.NewLockMap() + driver.cloud = &azure.Cloud{} return driver } @@ -92,6 +93,8 @@ func TestNewDriver(t *testing.T) { fakedriver.Version = driverVersion fakedriver.accountSearchCache = driver.accountSearchCache fakedriver.dataPlaneAPIVolCache = driver.dataPlaneAPIVolCache + fakedriver.volStatsCache = driver.volStatsCache + fakedriver.cloud = driver.cloud assert.Equal(t, driver, fakedriver) } @@ -552,6 +555,37 @@ func TestGetAuthEnv(t *testing.T) { } }, }, + { + name: "invalid getLatestAccountKey value", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + attrib := map[string]string{ + getLatestAccountKeyField: "invalid", + } + secret := make(map[string]string) + volumeID := "rg#f5713de20cde511e8ba4900#pvc-fuse-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41" + d.cloud = &azure.Cloud{} + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl) + d.cloud.StorageAccountClient = mockStorageAccountsClient + s := "unit-test" + accountkey := storage.AccountKey{ + Value: &s, + } + accountkeylist := []storage.AccountKey{} + accountkeylist = append(accountkeylist, accountkey) + list := storage.AccountListKeysResult{ + Keys: &accountkeylist, + } + mockStorageAccountsClient.EXPECT().ListKeys(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(list, nil).AnyTimes() + _, _, _, _, _, _, _, err := d.GetAuthEnv(context.TODO(), volumeID, "", attrib, secret) + expectedErr := fmt.Errorf("invalid getlatestaccountkey: %s in volume context", "invalid") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr) + } + }, + }, { name: "secret not empty", testFunc: func(t *testing.T) { @@ -721,6 +755,37 @@ func TestGetStorageAccountAndContainer(t *testing.T) { } }, }, + { + name: "invalid getLatestAccountKey value", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + attrib := map[string]string{ + getLatestAccountKeyField: "invalid", + } + secret := make(map[string]string) + volumeID := "rg#f5713de20cde511e8ba4900#pvc-fuse-dynamic-17e43f84-f474-11e8-acd0-000d3a00df41" + d.cloud = &azure.Cloud{} + ctrl := gomock.NewController(t) + defer ctrl.Finish() + mockStorageAccountsClient := mockstorageaccountclient.NewMockInterface(ctrl) + d.cloud.StorageAccountClient = mockStorageAccountsClient + s := "unit-test" + accountkey := storage.AccountKey{ + Value: &s, + } + accountkeylist := []storage.AccountKey{} + accountkeylist = append(accountkeylist, accountkey) + list := storage.AccountListKeysResult{ + Keys: &accountkeylist, + } + mockStorageAccountsClient.EXPECT().ListKeys(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(list, nil).AnyTimes() + _, _, _, _, err := d.GetStorageAccountAndContainer(context.TODO(), volumeID, attrib, secret) + expectedErr := fmt.Errorf("invalid getlatestaccountkey: %s in volume context", "invalid") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr) + } + }, + }, } for _, tc := range testCases { t.Run(tc.name, tc.testFunc) @@ -779,31 +844,31 @@ func TestGetStorageAccount(t *testing.T) { }, expectedAccountName: "", expectedAccountKey: "", - expectedError: fmt.Errorf("could not find accountname or azurestorageaccountname field secrets(map[accountname: accountkey:])"), + expectedError: fmt.Errorf("could not find accountname or azurestorageaccountname field"), }, { options: emptyAccountKeyMap, expectedAccountName: "testaccount", expectedAccountKey: "", - expectedError: fmt.Errorf("could not find accountkey or azurestorageaccountkey field in secrets(%v)", emptyAccountKeyMap), + expectedError: fmt.Errorf("could not find accountkey or azurestorageaccountkey field in secrets"), }, { options: emptyAccountNameMap, expectedAccountName: "", expectedAccountKey: "testkey", - expectedError: fmt.Errorf("could not find accountname or azurestorageaccountname field secrets(%v)", emptyAccountNameMap), + expectedError: fmt.Errorf("could not find accountname or azurestorageaccountname field in secrets"), }, { options: emptyAzureAccountKeyMap, expectedAccountName: "testaccount", expectedAccountKey: "", - expectedError: fmt.Errorf("could not find accountkey or azurestorageaccountkey field in secrets(%v)", emptyAzureAccountKeyMap), + expectedError: fmt.Errorf("could not find accountkey or azurestorageaccountkey field in secrets"), }, { options: emptyAzureAccountNameMap, expectedAccountName: "", expectedAccountKey: "testkey", - expectedError: fmt.Errorf("could not find accountname or azurestorageaccountname field secrets(%v)", emptyAzureAccountNameMap), + expectedError: fmt.Errorf("could not find accountname or azurestorageaccountname field in secrets"), }, { options: nil, @@ -844,9 +909,7 @@ func TestGetContainerReference(t *testing.T) { secrets: map[string]string{ "accountKey": fakeAccountKey, }, - expectedError: fmt.Errorf("could not find %s or %s field secrets(%v)", accountNameField, defaultSecretAccountName, map[string]string{ - "accountKey": fakeAccountKey, - }), + expectedError: fmt.Errorf("could not find %s or %s field in secrets", accountNameField, defaultSecretAccountName), }, { name: "failed to retrieve accountKey", @@ -854,9 +917,7 @@ func TestGetContainerReference(t *testing.T) { secrets: map[string]string{ "accountName": fakeAccountName, }, - expectedError: fmt.Errorf("could not find %s or %s field in secrets(%v)", accountKeyField, defaultSecretAccountKey, map[string]string{ - "accountName": fakeAccountName, - }), + expectedError: fmt.Errorf("could not find %s or %s field in secrets", accountKeyField, defaultSecretAccountKey), }, { name: "failed to obtain client", diff --git a/pkg/blob/controllerserver.go b/pkg/blob/controllerserver.go index ed1f552a4..eb7beabd6 100644 --- a/pkg/blob/controllerserver.go +++ b/pkg/blob/controllerserver.go @@ -19,12 +19,18 @@ package blob import ( "context" "fmt" + "net/url" + "os/exec" "strconv" "strings" + "time" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service" "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-09-01/storage" azstorage "github.com/Azure/azure-sdk-for-go/storage" "github.com/container-storage-interface/spec/lib/go/csi" @@ -42,6 +48,9 @@ import ( const ( privateEndpoint = "privateendpoint" + + waitForCopyInterval = 5 * time.Second + waitForCopyTimeout = 3 * time.Minute ) // CreateVolume provisions a volume @@ -61,6 +70,11 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) } if acquired := d.volumeLocks.TryAcquire(volName); !acquired { + // logging the job status if it's volume cloning + if req.GetVolumeContentSource() != nil { + jobState, percent, err := d.azcopy.GetAzcopyJob(volName) + klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err) + } return nil, status.Errorf(codes.Aborted, volumeOperationAlreadyExistsFmt, volName) } defer d.volumeLocks.Release(volName) @@ -73,10 +87,12 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) parameters = make(map[string]string) } var storageAccountType, subsID, resourceGroup, location, account, containerName, containerNamePrefix, protocol, customTags, secretName, secretNamespace, pvcNamespace string - var isHnsEnabled, requireInfraEncryption, enableBlobVersioning *bool + var isHnsEnabled, requireInfraEncryption, enableBlobVersioning, createPrivateEndpoint, enableNfsV3 *bool var vnetResourceGroup, vnetName, subnetName, accessTier, networkEndpointType, storageEndpointSuffix string - var matchTags, useDataPlaneAPI bool + var matchTags, useDataPlaneAPI, getLatestAccountKey bool var softDeleteBlobs, softDeleteContainers int32 + var vnetResourceIDs []string + var err error // set allowBlobPublicAccess as false by default allowBlobPublicAccess := pointer.Bool(false) @@ -137,6 +153,10 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) if strings.EqualFold(v, falseValue) { storeAccountKey = false } + case getLatestAccountKeyField: + if getLatestAccountKey, err = strconv.ParseBool(v); err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid %s: %s in volume context", getLatestAccountKeyField, v) + } case allowBlobPublicAccessField: if strings.EqualFold(v, trueValue) { allowBlobPublicAccess = pointer.Bool(true) @@ -153,6 +173,12 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) case pvNameKey: containerNameReplaceMap[pvNameMetadata] = v case serverNameField: + case storageAuthTypeField: + case storageIentityClientIDField: + case storageIdentityObjectIDField: + case storageIdentityResourceIDField: + case msiEndpointField: + case storageAADEndpointField: // no op, only used in NodeStageVolume case storageEndpointSuffixField: storageEndpointSuffix = v @@ -235,21 +261,16 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) } enableHTTPSTrafficOnly := true - createPrivateEndpoint := false if strings.EqualFold(networkEndpointType, privateEndpoint) { - createPrivateEndpoint = true + createPrivateEndpoint = pointer.BoolPtr(true) } accountKind := string(storage.KindStorageV2) - var ( - vnetResourceIDs []string - enableNfsV3 *bool - ) if protocol == NFS { isHnsEnabled = pointer.Bool(true) enableNfsV3 = pointer.Bool(true) // NFS protocol does not need account key storeAccountKey = false - if !createPrivateEndpoint { + if !pointer.BoolDeref(createPrivateEndpoint, false) { // set VirtualNetworkResourceIDs for storage account firewall setting vnetResourceID := d.getSubnetResourceID(vnetResourceGroup, vnetName, subnetName) klog.V(2).Infof("set vnetResourceID(%s) for NFS protocol", vnetResourceID) @@ -308,7 +329,24 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) EnableBlobVersioning: enableBlobVersioning, SoftDeleteBlobs: softDeleteBlobs, SoftDeleteContainers: softDeleteContainers, + GetLatestAccountKey: getLatestAccountKey, + } + + var volumeID string + requestName := "controller_create_volume" + if req.GetVolumeContentSource() != nil { + switch req.VolumeContentSource.Type.(type) { + case *csi.VolumeContentSource_Snapshot: + requestName = "controller_create_volume_from_snapshot" + case *csi.VolumeContentSource_Volume: + requestName = "controller_create_volume_from_volume" + } } + mc := metrics.NewMetricContext(blobCSIDriverName, requestName, d.cloud.ResourceGroup, d.cloud.SubscriptionID, d.Name) + isOperationSucceeded := false + defer func() { + mc.ObserveOperationWithResult(isOperationSucceeded, VolumeID, volumeID) + }() var accountKey string accountName := account @@ -317,7 +355,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) if v, ok := d.volMap.Load(volName); ok { accountName = v.(string) } else { - lockKey := fmt.Sprintf("%s%s%s%s%s%v", storageAccountType, accountKind, resourceGroup, location, protocol, createPrivateEndpoint) + lockKey := fmt.Sprintf("%s%s%s%s%s%v", storageAccountType, accountKind, resourceGroup, location, protocol, pointer.BoolDeref(createPrivateEndpoint, false)) // search in cache first cache, err := d.accountSearchCache.Get(lockKey, azcache.CacheReadTypeDefault) if err != nil { @@ -346,7 +384,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) } } - if createPrivateEndpoint && protocol == NFS { + if pointer.BoolDeref(createPrivateEndpoint, false) && protocol == NFS { // As for blobfuse/blobfuse2, serverName, i.e.,AZURE_STORAGE_BLOB_ENDPOINT env variable can't include // "privatelink", issue: https://github.com/Azure/azure-storage-fuse/issues/1014 // @@ -378,16 +416,20 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) setKeyValueInMap(parameters, containerNameField, validContainerName) } - var volumeID string - mc := metrics.NewMetricContext(blobCSIDriverName, "controller_create_volume", d.cloud.ResourceGroup, d.cloud.SubscriptionID, d.Name) - isOperationSucceeded := false - defer func() { - mc.ObserveOperationWithResult(isOperationSucceeded, VolumeID, volumeID) - }() - - klog.V(2).Infof("begin to create container(%s) on account(%s) type(%s) subsID(%s) rg(%s) location(%s) size(%d)", validContainerName, accountName, storageAccountType, subsID, resourceGroup, location, requestGiB) - if err := d.CreateBlobContainer(ctx, subsID, resourceGroup, accountName, validContainerName, secrets); err != nil { - return nil, status.Errorf(codes.Internal, "failed to create container(%s) on account(%s) type(%s) rg(%s) location(%s) size(%d), error: %v", validContainerName, accountName, storageAccountType, resourceGroup, location, requestGiB, err) + if req.GetVolumeContentSource() != nil { + if accountKey == "" { + if _, accountKey, err = d.GetStorageAccesskey(ctx, accountOptions, secrets, secretName, secretNamespace); err != nil { + return nil, status.Errorf(codes.Internal, "failed to GetStorageAccesskey on account(%s) rg(%s), error: %v", accountOptions.Name, accountOptions.ResourceGroup, err) + } + } + if err := d.copyVolume(ctx, req, accountKey, validContainerName, storageEndpointSuffix); err != nil { + return nil, err + } + } else { + klog.V(2).Infof("begin to create container(%s) on account(%s) type(%s) subsID(%s) rg(%s) location(%s) size(%d)", validContainerName, accountName, storageAccountType, subsID, resourceGroup, location, requestGiB) + if err := d.CreateBlobContainer(ctx, subsID, resourceGroup, accountName, validContainerName, secrets); err != nil { + return nil, status.Errorf(codes.Internal, "failed to create container(%s) on account(%s) type(%s) rg(%s) location(%s) size(%d), error: %v", validContainerName, accountName, storageAccountType, resourceGroup, location, requestGiB, err) + } } if storeAccountKey && len(req.GetSecrets()) == 0 { @@ -428,6 +470,7 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) VolumeId: volumeID, CapacityBytes: req.GetCapacityRange().GetRequiredBytes(), VolumeContext: parameters, + ContentSource: req.GetVolumeContentSource(), }, }, nil } @@ -673,6 +716,75 @@ func (d *Driver) DeleteBlobContainer(ctx context.Context, subsID, resourceGroupN }) } +// CopyBlobContainer copies a blob container in the same storage account +func (d *Driver) copyBlobContainer(ctx context.Context, req *csi.CreateVolumeRequest, accountKey, dstContainerName, storageEndpointSuffix string) error { + var sourceVolumeID string + if req.GetVolumeContentSource() != nil && req.GetVolumeContentSource().GetVolume() != nil { + sourceVolumeID = req.GetVolumeContentSource().GetVolume().GetVolumeId() + + } + resourceGroupName, accountName, srcContainerName, _, _, err := GetContainerInfo(sourceVolumeID) //nolint:dogsled + if err != nil { + return status.Error(codes.NotFound, err.Error()) + } + if srcContainerName == "" || dstContainerName == "" { + return fmt.Errorf("srcContainerName(%s) or dstContainerName(%s) is empty", srcContainerName, dstContainerName) + } + + klog.V(2).Infof("generate sas token for account(%s)", accountName) + accountSasToken, genErr := generateSASToken(accountName, accountKey, storageEndpointSuffix, d.sasTokenExpirationMinutes) + if genErr != nil { + return genErr + } + + timeAfter := time.After(waitForCopyTimeout) + timeTick := time.Tick(waitForCopyInterval) + srcPath := fmt.Sprintf("https://%s.blob.%s/%s%s", accountName, storageEndpointSuffix, srcContainerName, accountSasToken) + dstPath := fmt.Sprintf("https://%s.blob.%s/%s%s", accountName, storageEndpointSuffix, dstContainerName, accountSasToken) + + jobState, percent, err := d.azcopy.GetAzcopyJob(dstContainerName) + klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err) + if jobState == util.AzcopyJobError || jobState == util.AzcopyJobCompleted { + return err + } + klog.V(2).Infof("begin to copy blob container %s to %s", srcContainerName, dstContainerName) + for { + select { + case <-timeTick: + jobState, percent, err := d.azcopy.GetAzcopyJob(dstContainerName) + klog.V(2).Infof("azcopy job status: %s, copy percent: %s%%, error: %v", jobState, percent, err) + switch jobState { + case util.AzcopyJobError, util.AzcopyJobCompleted: + return err + case util.AzcopyJobNotFound: + klog.V(2).Infof("copy blob container %s to %s", srcContainerName, dstContainerName) + out, copyErr := exec.Command("azcopy", "copy", srcPath, dstPath, "--recursive", "--check-length=false").CombinedOutput() + if copyErr != nil { + klog.Warningf("CopyBlobContainer(%s, %s, %s) failed with error(%v): %v", resourceGroupName, accountName, dstPath, copyErr, string(out)) + } else { + klog.V(2).Infof("copied blob container %s to %s successfully", srcContainerName, dstContainerName) + } + return copyErr + } + case <-timeAfter: + return fmt.Errorf("timeout waiting for copy blob container %s to %s succeed", srcContainerName, dstContainerName) + } + } +} + +// copyVolume copies a volume form volume or snapshot, snapshot is not supported now +func (d *Driver) copyVolume(ctx context.Context, req *csi.CreateVolumeRequest, accountKey, dstContainerName, storageEndpointSuffix string) error { + vs := req.VolumeContentSource + switch vs.Type.(type) { + case *csi.VolumeContentSource_Snapshot: + return status.Errorf(codes.InvalidArgument, "copy volume from volumeSnapshot is not supported") + case *csi.VolumeContentSource_Volume: + return d.copyBlobContainer(ctx, req, accountKey, dstContainerName, storageEndpointSuffix) + default: + return status.Errorf(codes.InvalidArgument, "%v is not a proper volume source", vs) + } +} + // isValidVolumeCapabilities validates the given VolumeCapability array is valid func isValidVolumeCapabilities(volCaps []*csi.VolumeCapability) error { if len(volCaps) == 0 { @@ -697,3 +809,27 @@ func parseDays(dayStr string) (int32, error) { return int32(days), nil } + +// generateSASToken generate a sas token for storage account +func generateSASToken(accountName, accountKey, storageEndpointSuffix string, expiryTime int) (string, error) { + credential, err := azblob.NewSharedKeyCredential(accountName, accountKey) + if err != nil { + return "", status.Errorf(codes.Internal, fmt.Sprintf("failed to generate sas token in creating new shared key credential, accountName: %s, err: %s", accountName, err.Error())) + } + serviceClient, err := service.NewClientWithSharedKeyCredential(fmt.Sprintf("https://%s.blob.%s/", accountName, storageEndpointSuffix), credential, nil) + if err != nil { + return "", status.Errorf(codes.Internal, fmt.Sprintf("failed to generate sas token in creating new client with shared key credential, accountName: %s, err: %s", accountName, err.Error())) + } + sasURL, err := serviceClient.GetSASURL( + sas.AccountResourceTypes{Object: true, Service: false, Container: true}, + sas.AccountPermissions{Read: true, List: true, Write: true}, + sas.AccountServices{Blob: true}, time.Now(), time.Now().Add(time.Duration(expiryTime)*time.Minute)) + if err != nil { + return "", err + } + u, err := url.Parse(sasURL) + if err != nil { + return "", err + } + return "?" + u.RawQuery, nil +} diff --git a/pkg/blob/controllerserver_test.go b/pkg/blob/controllerserver_test.go index 316237547..92fd5944f 100644 --- a/pkg/blob/controllerserver_test.go +++ b/pkg/blob/controllerserver_test.go @@ -32,6 +32,7 @@ import ( "google.golang.org/grpc/status" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/utils/pointer" + "sigs.k8s.io/blob-csi-driver/pkg/util" "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/blobclient" "sigs.k8s.io/cloud-provider-azure/pkg/azureclients/storageaccountclient/mockstorageaccountclient" azure "sigs.k8s.io/cloud-provider-azure/pkg/provider" @@ -229,15 +230,9 @@ func TestCreateVolume(t *testing.T) { testFunc: func(t *testing.T) { d := NewFakeDriver() d.cloud = &azure.Cloud{} - mp := make(map[string]string) - mp[protocolField] = "unit-test" - mp[skuNameField] = "unit-test" - mp[storageAccountTypeField] = "unit-test" - mp[locationField] = "unit-test" - mp[storageAccountField] = "unit-test" - mp[resourceGroupField] = "unit-test" - mp[containerNameField] = "unit-test" - mp[mountPermissionsField] = "0750" + mp := map[string]string{ + protocolField: "unit-test", + } req := &csi.CreateVolumeRequest{ Name: "unit-test", VolumeCapabilities: stdVolumeCapabilities, @@ -253,6 +248,29 @@ func TestCreateVolume(t *testing.T) { } }, }, + { + name: "invalid getLatestAccountKey value", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + d.cloud = &azure.Cloud{} + mp := map[string]string{ + getLatestAccountKeyField: "invalid", + } + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + } + d.Cap = []*csi.ControllerServiceCapability{ + controllerServiceCapability, + } + _, err := d.CreateVolume(context.Background(), req) + expectedErr := status.Errorf(codes.InvalidArgument, "invalid %s: %s in volume context", getLatestAccountKeyField, "invalid") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("actualErr: (%v), expectedErr: (%v)", err, expectedErr) + } + }, + }, { name: "storageAccount and matchTags conflict", testFunc: func(t *testing.T) { @@ -513,6 +531,12 @@ func TestCreateVolume(t *testing.T) { mp[resourceGroupField] = "unit-test" mp[containerNameField] = "unit-test" mp[mountPermissionsField] = "0750" + mp[storageAuthTypeField] = "msi" + mp[storageIentityClientIDField] = "msi" + mp[storageIdentityObjectIDField] = "msi" + mp[storageIdentityResourceIDField] = "msi" + mp[msiEndpointField] = "msi" + mp[storageAADEndpointField] = "msi" req := &csi.CreateVolumeRequest{ Name: "unit-test", VolumeCapabilities: stdVolumeCapabilities, @@ -728,6 +752,116 @@ func TestCreateVolume(t *testing.T) { } }, }, + { + name: "create volume from copy volumesnapshot is not supported", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + d.cloud = &azure.Cloud{} + d.cloud.SubscriptionID = "subID" + + keyList := make([]storage.AccountKey, 1) + fakeKey := "fakeKey" + fakeValue := "fakeValue" + keyList[0] = (storage.AccountKey{ + KeyName: &fakeKey, + Value: &fakeValue, + }) + d.cloud.StorageAccountClient = NewMockSAClient(context.Background(), gomock.NewController(t), "subID", "unit-test", "unit-test", &keyList) + + errorType := NULL + d.cloud.BlobClient = &mockBlobClient{errorType: &errorType} + + mp := make(map[string]string) + mp[protocolField] = "fuse" + mp[skuNameField] = "unit-test" + mp[storageAccountTypeField] = "unit-test" + mp[locationField] = "unit-test" + mp[storageAccountField] = "unittest" + mp[resourceGroupField] = "unit-test" + mp[containerNameField] = "unit-test" + mp[mountPermissionsField] = "0750" + + volumeSnapshotSource := &csi.VolumeContentSource_SnapshotSource{ + SnapshotId: "unit-test", + } + volumeContentSourceSnapshotSource := &csi.VolumeContentSource_Snapshot{ + Snapshot: volumeSnapshotSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceSnapshotSource, + } + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + d.Cap = []*csi.ControllerServiceCapability{ + controllerServiceCapability, + } + + expectedErr := status.Errorf(codes.InvalidArgument, "copy volume from volumeSnapshot is not supported") + _, err := d.CreateVolume(context.Background(), req) + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, + { + name: "create volume from copy volume not found", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + d.cloud = &azure.Cloud{} + d.cloud.SubscriptionID = "subID" + + keyList := make([]storage.AccountKey, 1) + fakeKey := "fakeKey" + fakeValue := "fakeValue" + keyList[0] = (storage.AccountKey{ + KeyName: &fakeKey, + Value: &fakeValue, + }) + d.cloud.StorageAccountClient = NewMockSAClient(context.Background(), gomock.NewController(t), "subID", "unit-test", "unit-test", &keyList) + + errorType := NULL + d.cloud.BlobClient = &mockBlobClient{errorType: &errorType} + + mp := make(map[string]string) + mp[protocolField] = "fuse" + mp[skuNameField] = "unit-test" + mp[storageAccountTypeField] = "unit-test" + mp[locationField] = "unit-test" + mp[storageAccountField] = "unittest" + mp[resourceGroupField] = "unit-test" + mp[containerNameField] = "unit-test" + mp[mountPermissionsField] = "0750" + + volumeSource := &csi.VolumeContentSource_VolumeSource{ + VolumeId: "unit-test", + } + volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{ + Volume: volumeSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceVolumeSource, + } + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + d.Cap = []*csi.ControllerServiceCapability{ + controllerServiceCapability, + } + + expectedErr := status.Errorf(codes.NotFound, "error parsing volume id: \"unit-test\", should at least contain two #") + _, err := d.CreateVolume(context.Background(), req) + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, } for _, tc := range testCases { t.Run(tc.name, tc.testFunc) @@ -1363,6 +1497,242 @@ func TestDeleteBlobContainer(t *testing.T) { } } +func TestCopyVolume(t *testing.T) { + stdVolumeCapability := &csi.VolumeCapability{ + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + } + stdVolumeCapabilities := []*csi.VolumeCapability{ + stdVolumeCapability, + } + testCases := []struct { + name string + testFunc func(t *testing.T) + }{ + { + name: "copy volume from volumeSnapshot is not supported", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + mp := map[string]string{} + + volumeSnapshotSource := &csi.VolumeContentSource_SnapshotSource{ + SnapshotId: "unit-test", + } + volumeContentSourceSnapshotSource := &csi.VolumeContentSource_Snapshot{ + Snapshot: volumeSnapshotSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceSnapshotSource, + } + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + + ctx := context.Background() + + expectedErr := status.Errorf(codes.InvalidArgument, "copy volume from volumeSnapshot is not supported") + err := d.copyVolume(ctx, req, "", "", "core.windows.net") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, + { + name: "copy volume from volume not found", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + mp := map[string]string{} + + volumeSource := &csi.VolumeContentSource_VolumeSource{ + VolumeId: "unit-test", + } + volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{ + Volume: volumeSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceVolumeSource, + } + + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + + ctx := context.Background() + + expectedErr := status.Errorf(codes.NotFound, "error parsing volume id: \"unit-test\", should at least contain two #") + err := d.copyVolume(ctx, req, "", "dstContainer", "core.windows.net") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, + { + name: "src blob container is empty", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + mp := map[string]string{} + + volumeSource := &csi.VolumeContentSource_VolumeSource{ + VolumeId: "rg#unit-test##", + } + volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{ + Volume: volumeSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceVolumeSource, + } + + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + + ctx := context.Background() + + expectedErr := fmt.Errorf("srcContainerName() or dstContainerName(dstContainer) is empty") + err := d.copyVolume(ctx, req, "", "dstContainer", "core.windows.net") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, + { + name: "dst blob container is empty", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + mp := map[string]string{} + + volumeSource := &csi.VolumeContentSource_VolumeSource{ + VolumeId: "vol_1#f5713de20cde511e8ba4900#fileshare#", + } + volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{ + Volume: volumeSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceVolumeSource, + } + + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + + ctx := context.Background() + + expectedErr := fmt.Errorf("srcContainerName(fileshare) or dstContainerName() is empty") + err := d.copyVolume(ctx, req, "", "", "core.windows.net") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, + { + name: "azcopy job is already completed", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + mp := map[string]string{} + + volumeSource := &csi.VolumeContentSource_VolumeSource{ + VolumeId: "vol_1#f5713de20cde511e8ba4900#fileshare#", + } + volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{ + Volume: volumeSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceVolumeSource, + } + + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + m := util.NewMockEXEC(ctrl) + listStr := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false" + m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstContainer -B 3")).Return(listStr, nil) + // if test.enableShow { + // m.EXPECT().RunCommand(gomock.Not("azcopy jobs list | grep dstContainer -B 3")).Return(test.showStr, test.showErr) + // } + + d.azcopy.ExecCmd = m + + ctx := context.Background() + + var expectedErr error + err := d.copyVolume(ctx, req, "", "dstContainer", "core.windows.net") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, + { + name: "azcopy job is first in progress and then be completed", + testFunc: func(t *testing.T) { + d := NewFakeDriver() + mp := map[string]string{} + + volumeSource := &csi.VolumeContentSource_VolumeSource{ + VolumeId: "vol_1#f5713de20cde511e8ba4900#fileshare#", + } + volumeContentSourceVolumeSource := &csi.VolumeContentSource_Volume{ + Volume: volumeSource, + } + volumecontensource := csi.VolumeContentSource{ + Type: volumeContentSourceVolumeSource, + } + + req := &csi.CreateVolumeRequest{ + Name: "unit-test", + VolumeCapabilities: stdVolumeCapabilities, + Parameters: mp, + VolumeContentSource: &volumecontensource, + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + m := util.NewMockEXEC(ctrl) + listStr1 := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: InProgress\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false" + listStr2 := "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false" + o1 := m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstContainer -B 3")).Return(listStr1, nil).Times(1) + m.EXPECT().RunCommand(gomock.Not("azcopy jobs list | grep dstBlobContainer -B 3")).Return("Percent Complete (approx): 50.0", nil) + o2 := m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstContainer -B 3")).Return(listStr2, nil) + gomock.InOrder(o1, o2) + + d.azcopy.ExecCmd = m + + ctx := context.Background() + + var expectedErr error + err := d.copyVolume(ctx, req, "", "dstContainer", "core.windows.net") + if !reflect.DeepEqual(err, expectedErr) { + t.Errorf("Unexpected error: %v", err) + } + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, tc.testFunc) + } +} + func Test_parseDays(t *testing.T) { type args struct { dayStr string @@ -1411,3 +1781,41 @@ func Test_parseDays(t *testing.T) { }) } } + +func Test_generateSASToken(t *testing.T) { + storageEndpointSuffix := "core.windows.net" + tests := []struct { + name string + accountName string + accountKey string + want string + expectedErr error + }{ + { + name: "accountName nil", + accountName: "", + accountKey: "", + want: "se=", + expectedErr: nil, + }, + { + name: "account key illegal", + accountName: "unit-test", + accountKey: "fakeValue", + want: "", + expectedErr: status.Errorf(codes.Internal, fmt.Sprintf("failed to generate sas token in creating new shared key credential, accountName: %s, err: %s", "unit-test", "decode account key: illegal base64 data at input byte 8")), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sas, err := generateSASToken(tt.accountName, tt.accountKey, storageEndpointSuffix, 30) + if !reflect.DeepEqual(err, tt.expectedErr) { + t.Errorf("generateSASToken error = %v, expectedErr %v, sas token = %v, want %v", err, tt.expectedErr, sas, tt.want) + return + } + if !strings.Contains(sas, tt.want) { + t.Errorf("sas token = %v, want %v", sas, tt.want) + } + }) + } +} diff --git a/pkg/blob/nodeserver.go b/pkg/blob/nodeserver.go index c56e052f4..668ea5681 100644 --- a/pkg/blob/nodeserver.go +++ b/pkg/blob/nodeserver.go @@ -29,6 +29,8 @@ import ( "sigs.k8s.io/blob-csi-driver/pkg/edgecache" cv "sigs.k8s.io/blob-csi-driver/pkg/edgecache/cachevolume" blobcsiutil "sigs.k8s.io/blob-csi-driver/pkg/util" + azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache" + "sigs.k8s.io/cloud-provider-azure/pkg/metrics" "github.com/Azure/azure-sdk-for-go/storage" "github.com/container-storage-interface/spec/lib/go/csi" @@ -257,6 +259,12 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe attrib := req.GetVolumeContext() secrets := req.GetSecrets() + mc := metrics.NewMetricContext(blobCSIDriverName, "node_stage_volume", d.cloud.ResourceGroup, "", d.Name) + isOperationSucceeded := false + defer func() { + mc.ObserveOperationWithResult(isOperationSucceeded, VolumeID, volumeID) + }() + var serverAddress, storageEndpointSuffix, protocol, ephemeralVolMountOptions string var ephemeralVol, isHnsEnabled bool @@ -378,10 +386,15 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe klog.V(2).Infof("target %v\nprotocol %v\n\nvolumeId %v\ncontext %v\nmountflags %v\nserverAddress %v", targetPath, protocol, volumeID, attrib, mountFlags, serverAddress) + mountType := AZNFS + if !d.enableAznfsMount { + mountType = NFS + } + source := fmt.Sprintf("%s:/%s/%s", serverAddress, accountName, containerName) mountOptions := util.JoinMountOptions(mountFlags, []string{"sec=sys,vers=3,nolock"}) if err := wait.PollImmediate(1*time.Second, 2*time.Minute, func() (bool, error) { - return true, d.mounter.MountSensitive(source, targetPath, NFS, mountOptions, []string{}) + return true, d.mounter.MountSensitive(source, targetPath, mountType, mountOptions, []string{}) }); err != nil { var helpLinkMsg string if d.appendMountErrorHelpLink { @@ -398,6 +411,7 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe klog.V(2).Infof("skip chmod on targetPath(%s) since mountPermissions is set as 0", targetPath) } + isOperationSucceeded = true klog.V(2).Infof("volume(%s) mount %s on %s succeeded", volumeID, source, targetPath) return &csi.NodeStageVolumeResponse{}, nil } @@ -500,6 +514,12 @@ func (d *Driver) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolu } defer d.volumeLocks.Release(volumeID) + mc := metrics.NewMetricContext(blobCSIDriverName, "node_unstage_volume", d.cloud.ResourceGroup, "", d.Name) + isOperationSucceeded := false + defer func() { + mc.ObserveOperationWithResult(isOperationSucceeded, VolumeID, volumeID) + }() + klog.V(2).Infof("NodeUnstageVolume: volume %s unmounting on %s", volumeID, stagingTargetPath) // Check if there is a mount at the edgecache suffix @@ -526,6 +546,7 @@ func (d *Driver) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolu } klog.V(2).Infof("NodeUnstageVolume: volume %s unmount on %s successfully", volumeID, stagingTargetPath) + isOperationSucceeded = true return &csi.NodeUnstageVolumeResponse{}, nil } @@ -557,6 +578,23 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS return nil, status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume path was empty") } + // check if the volume stats is cached + cache, err := d.volStatsCache.Get(req.VolumeId, azcache.CacheReadTypeDefault) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + if cache != nil { + resp := cache.(csi.NodeGetVolumeStatsResponse) + klog.V(6).Infof("NodeGetVolumeStats: volume stats for volume %s path %s is cached", req.VolumeId, req.VolumePath) + return &resp, nil + } + + mc := metrics.NewMetricContext(blobCSIDriverName, "node_get_volume_stats", d.cloud.ResourceGroup, "", d.Name) + isOperationSucceeded := false + defer func() { + mc.ObserveOperationWithResult(isOperationSucceeded, VolumeID, req.VolumeId) + }() + if _, err := os.Lstat(req.VolumePath); err != nil { if os.IsNotExist(err) { return nil, status.Errorf(codes.NotFound, "path %s does not exist", req.VolumePath) @@ -564,6 +602,8 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS return nil, status.Errorf(codes.Internal, "failed to stat file %s: %v", req.VolumePath, err) } + klog.V(6).Infof("NodeGetVolumeStats: begin to get VolumeStats on volume %s path %s", req.VolumeId, req.VolumePath) + volumeMetrics, err := volume.NewMetricsStatFS(req.VolumePath).GetMetrics() if err != nil { return nil, status.Errorf(codes.Internal, "failed to get metrics: %v", err) @@ -595,7 +635,7 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS return nil, status.Errorf(codes.Internal, "failed to transform disk inodes used(%v)", volumeMetrics.InodesUsed) } - return &csi.NodeGetVolumeStatsResponse{ + resp := &csi.NodeGetVolumeStatsResponse{ Usage: []*csi.VolumeUsage{ { Unit: csi.VolumeUsage_BYTES, @@ -610,7 +650,13 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS Used: inodesUsed, }, }, - }, nil + } + + isOperationSucceeded = true + klog.V(6).Infof("NodeGetVolumeStats: volume stats for volume %s path %s is %v", req.VolumeId, req.VolumePath, resp) + // cache the volume stats per volume + d.volStatsCache.Set(req.VolumeId, *resp) + return resp, nil } // ensureMountPoint: create mount point if not exists diff --git a/pkg/blobfuse-proxy/init.sh b/pkg/blobfuse-proxy/init.sh index 40643f51a..380f2beca 100755 --- a/pkg/blobfuse-proxy/init.sh +++ b/pkg/blobfuse-proxy/init.sh @@ -26,6 +26,8 @@ HOST_CMD="nsenter --mount=/proc/1/ns/mnt" DISTRIBUTION=$($HOST_CMD cat /etc/os-release | grep ^ID= | cut -d'=' -f2 | tr -d '"') echo "Linux distribution: $DISTRIBUTION" +ARCH=$($HOST_CMD uname -m) +echo "Linux Arch is $(uname -m)" if [ "${DISTRIBUTION}" = "ubuntu" ] && { [ "${INSTALL_BLOBFUSE}" = "true" ] || [ "${INSTALL_BLOBFUSE2}" = "true" ]; } then diff --git a/pkg/blobfuse-proxy/main.go b/pkg/blobfuse-proxy/main.go index 7d9f4d04e..50ca18960 100644 --- a/pkg/blobfuse-proxy/main.go +++ b/pkg/blobfuse-proxy/main.go @@ -27,16 +27,13 @@ import ( csicommon "sigs.k8s.io/blob-csi-driver/pkg/csi-common" ) -func init() { - _ = flag.Set("logtostderr", "true") -} - var ( blobfuseProxyEndpoint = flag.String("blobfuse-proxy-endpoint", "unix://tmp/blobfuse-proxy.sock", "blobfuse-proxy endpoint") ) func main() { klog.InitFlags(nil) + _ = flag.Set("logtostderr", "true") flag.Parse() proto, addr, err := csicommon.ParseEndpoint(*blobfuseProxyEndpoint) if err != nil { diff --git a/pkg/blobplugin/Dockerfile b/pkg/blobplugin/Dockerfile index 6c99d6f07..d579f0b55 100644 --- a/pkg/blobplugin/Dockerfile +++ b/pkg/blobplugin/Dockerfile @@ -28,8 +28,10 @@ RUN chmod +x /blobfuse-proxy/init.sh && \ chmod +x /blobfuse-proxy/blobfuse-proxy.service && \ chmod +x /blobfuse-proxy/blobfuse-proxy +# Currently no CBL-Mariner image with fix for "curl" CVE-2023-38545/CVE-2023-38546. +# So, temporarily do update here. Remove "curl" when image is updated. RUN tdnf updateinfo && \ - tdnf install -y util-linux e2fsprogs nfs-utils quota-rpc rpcbind blobfuse2 fuse3 libcap-ng libcap ca-certificates && \ + tdnf install -y util-linux e2fsprogs nfs-utils quota-rpc rpcbind blobfuse2 fuse3 libcap-ng libcap ca-certificates curl && \ tdnf clean all LABEL maintainers="andyzhangx" diff --git a/pkg/blobplugin/main.go b/pkg/blobplugin/main.go index c3b5ac2be..4402192ff 100644 --- a/pkg/blobplugin/main.go +++ b/pkg/blobplugin/main.go @@ -31,10 +31,6 @@ import ( "k8s.io/klog/v2" ) -func init() { - _ = flag.Set("logtostderr", "true") -} - var ( endpoint = flag.String("endpoint", "unix://tmp/csi.sock", "CSI endpoint") blobfuseProxyEndpoint = flag.String("blobfuse-proxy-endpoint", "unix://tmp/blobfuse-proxy.sock", "blobfuse-proxy endpoint") @@ -61,10 +57,14 @@ var ( kubeAPIQPS = flag.Float64("kube-api-qps", 25.0, "QPS to use while communicating with the kubernetes apiserver.") kubeAPIBurst = flag.Int("kube-api-burst", 50, "Burst to use while communicating with the kubernetes apiserver.") appendMountErrorHelpLink = flag.Bool("append-mount-error-help-link", true, "Whether to include a link for help with mount errors when a mount error occurs.") + enableAznfsMount = flag.Bool("enable-aznfs-mount", false, "replace nfs mount with aznfs mount") + volStatsCacheExpireInMinutes = flag.Int("vol-stats-cache-expire-in-minutes", 10, "The cache expire time in minutes for volume stats cache") + sasTokenExpirationMinutes = flag.Int("sas-token-expiration-minutes", 1440, "sas token expiration minutes during volume cloning") ) func main() { klog.InitFlags(nil) + _ = flag.Set("logtostderr", "true") flag.Parse() if *version { info, err := blob.GetVersionYAML(*driverName) @@ -104,6 +104,9 @@ func handle() { AppendMountErrorHelpLink: *appendMountErrorHelpLink, KubeAPIQPS: *kubeAPIQPS, KubeAPIBurst: *kubeAPIBurst, + EnableAznfsMount: *enableAznfsMount, + VolStatsCacheExpireInMinutes: *volStatsCacheExpireInMinutes, + SasTokenExpirationMinutes: *sasTokenExpirationMinutes, } driver := blob.NewDriver(&driverOptions) if driver == nil { diff --git a/pkg/csi-common/driver_test.go b/pkg/csi-common/driver_test.go index fcad5c197..170c91dd8 100644 --- a/pkg/csi-common/driver_test.go +++ b/pkg/csi-common/driver_test.go @@ -105,6 +105,7 @@ func TestValidateControllerServiceRequest(t *testing.T) { csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME, csi.ControllerServiceCapability_RPC_GET_CAPACITY, csi.ControllerServiceCapability_RPC_LIST_VOLUMES, + csi.ControllerServiceCapability_RPC_CLONE_VOLUME, }) // Test controller service publish/unpublish is supported @@ -123,6 +124,10 @@ func TestValidateControllerServiceRequest(t *testing.T) { err = d.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_GET_CAPACITY) assert.NoError(t, err) + // Test controller service clone volumes is supported + err = d.ValidateControllerServiceRequest(csi.ControllerServiceCapability_RPC_CLONE_VOLUME) + assert.NoError(t, err) + } func TestAddNodeServiceCapabilities(t *testing.T) { diff --git a/pkg/csi-common/utils_test.go b/pkg/csi-common/utils_test.go index a347e994b..6769cf18f 100644 --- a/pkg/csi-common/utils_test.go +++ b/pkg/csi-common/utils_test.go @@ -156,6 +156,9 @@ func TestNewControllerServiceCapability(t *testing.T) { { cap: csi.ControllerServiceCapability_RPC_GET_CAPACITY, }, + { + cap: csi.ControllerServiceCapability_RPC_CLONE_VOLUME, + }, } for _, test := range tests { resp := NewControllerServiceCapability(test.cap) diff --git a/pkg/util/util.go b/pkg/util/util.go index 78d20a931..70ed8cab2 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -19,6 +19,7 @@ package util import ( "fmt" "os" + "os/exec" "regexp" "strings" "sync" @@ -35,6 +36,15 @@ const ( tagKeyValueDelimiter = "=" ) +type AzcopyJobState string + +const ( + AzcopyJobError AzcopyJobState = "Error" + AzcopyJobNotFound AzcopyJobState = "NotFound" + AzcopyJobRunning AzcopyJobState = "Running" + AzcopyJobCompleted AzcopyJobState = "Completed" +) + // RoundUpBytes rounds up the volume size in bytes up to multiplications of GiB // in the unit of Bytes func RoundUpBytes(volumeSizeBytes int64) int64 { @@ -223,3 +233,108 @@ func TrimDuplicatedSpace(s string) string { s = reg.ReplaceAllString(s, " ") return s } + +type EXEC interface { + RunCommand(string) (string, error) +} + +type ExecCommand struct { +} + +func (ec *ExecCommand) RunCommand(cmd string) (string, error) { + out, err := exec.Command("sh", "-c", cmd).CombinedOutput() + return string(out), err +} + +type Azcopy struct { + ExecCmd EXEC +} + +// GetAzcopyJob get the azcopy job status if job existed +func (ac *Azcopy) GetAzcopyJob(dstBlobContainer string) (AzcopyJobState, string, error) { + cmdStr := fmt.Sprintf("azcopy jobs list | grep %s -B 3", dstBlobContainer) + // cmd output example: + // JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9 + // Start Time: Monday, 07-Aug-23 03:29:54 UTC + // Status: Completed (or Cancelled, InProgress) + // Command: copy https://{accountName}.file.core.windows.net/{srcBlobContainer}{SAStoken} https://{accountName}.file.core.windows.net/{dstBlobContainer}{SAStoken} --recursive --check-length=false + // -- + // JobId: b598cce3-9aa9-9640-7793-c2bf3c385a9a + // Start Time: Wednesday, 09-Aug-23 09:09:03 UTC + // Status: Cancelled + // Command: copy https://{accountName}.file.core.windows.net/{srcBlobContainer}{SAStoken} https://{accountName}.file.core.windows.net/{dstBlobContainer}{SAStoken} --recursive --check-length=false + if ac.ExecCmd == nil { + ac.ExecCmd = &ExecCommand{} + } + out, err := ac.ExecCmd.RunCommand(cmdStr) + // if grep command returns nothing, the exec will return exit status 1 error, so filter this error + if err != nil && err.Error() != "exit status 1" { + klog.Warningf("failed to get azcopy job with error: %v, jobState: %v", err, AzcopyJobError) + return AzcopyJobError, "", fmt.Errorf("couldn't list jobs in azcopy %v", err) + } + jobid, jobState, err := parseAzcopyJobList(out, dstBlobContainer) + if err != nil || jobState == AzcopyJobError { + klog.Warningf("failed to get azcopy job with error: %v, jobState: %v", err, jobState) + return AzcopyJobError, "", fmt.Errorf("couldn't parse azcopy job list in azcopy %v", err) + } + if jobState == AzcopyJobCompleted { + return jobState, "100.0", err + } + if jobid == "" { + return jobState, "", err + } + cmdPercentStr := fmt.Sprintf("azcopy jobs show %s | grep Percent", jobid) + // cmd out example: + // Percent Complete (approx): 100.0 + summary, err := ac.ExecCmd.RunCommand(cmdPercentStr) + if err != nil { + klog.Warningf("failed to get azcopy job with error: %v, jobState: %v", err, AzcopyJobError) + return AzcopyJobError, "", fmt.Errorf("couldn't show jobs summary in azcopy %v", err) + } + jobState, percent, err := parseAzcopyJobShow(summary) + if err != nil || jobState == AzcopyJobError { + klog.Warningf("failed to get azcopy job with error: %v, jobState: %v", err, jobState) + return AzcopyJobError, "", fmt.Errorf("couldn't parse azcopy job show in azcopy %v", err) + } + return jobState, percent, nil +} + +// parseAzcopyJobList parse command azcopy jobs list, get jobid and state from joblist containing dstBlobContainer +func parseAzcopyJobList(joblist string, dstBlobContainer string) (string, AzcopyJobState, error) { + jobid := "" + jobSegments := strings.Split(joblist, "JobId: ") + if len(jobSegments) < 2 { + return jobid, AzcopyJobNotFound, nil + } + jobSegments = jobSegments[1:] + for _, job := range jobSegments { + segments := strings.Split(job, "\n") + if len(segments) < 4 { + return jobid, AzcopyJobError, fmt.Errorf("error parsing jobs list: %s", job) + } + statusSegments := strings.Split(segments[2], ": ") + if len(statusSegments) < 2 { + return jobid, AzcopyJobError, fmt.Errorf("error parsing jobs list status: %s", segments[2]) + } + status := statusSegments[1] + switch status { + case "InProgress": + jobid = segments[0] + case "Completed": + return jobid, AzcopyJobCompleted, nil + } + } + if jobid == "" { + return jobid, AzcopyJobNotFound, nil + } + return jobid, AzcopyJobRunning, nil +} + +// parseAzcopyJobShow parse command azcopy jobs show jobid, get job state and copy percent +func parseAzcopyJobShow(jobshow string) (AzcopyJobState, string, error) { + segments := strings.Split(jobshow, ": ") + if len(segments) < 2 { + return AzcopyJobError, "", fmt.Errorf("error parsing jobs summary: %s in Percent Complete (approx)", jobshow) + } + return AzcopyJobRunning, strings.ReplaceAll(segments[1], "\n", ""), nil +} diff --git a/pkg/util/util_mock.go b/pkg/util/util_mock.go new file mode 100644 index 000000000..f381ec968 --- /dev/null +++ b/pkg/util/util_mock.go @@ -0,0 +1,66 @@ +// /* +// Copyright The Kubernetes Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// */ +// + +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/util/util.go + +// Package util is a generated GoMock package. +package util + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockEXEC is a mock of EXEC interface. +type MockEXEC struct { + ctrl *gomock.Controller + recorder *MockEXECMockRecorder +} + +// MockEXECMockRecorder is the mock recorder for MockEXEC. +type MockEXECMockRecorder struct { + mock *MockEXEC +} + +// NewMockEXEC creates a new mock instance. +func NewMockEXEC(ctrl *gomock.Controller) *MockEXEC { + mock := &MockEXEC{ctrl: ctrl} + mock.recorder = &MockEXECMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockEXEC) EXPECT() *MockEXECMockRecorder { + return m.recorder +} + +// RunCommand mocks base method. +func (m *MockEXEC) RunCommand(arg0 string) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunCommand", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RunCommand indicates an expected call of RunCommand. +func (mr *MockEXECMockRecorder) RunCommand(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunCommand", reflect.TypeOf((*MockEXEC)(nil).RunCommand), arg0) +} diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index 63e63d421..c3b1ec021 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -23,6 +23,7 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" ) @@ -406,3 +407,207 @@ func TestTrimDuplicatedSpace(t *testing.T) { }) } } + +func TestGetAzcopyJob(t *testing.T) { + tests := []struct { + desc string + listStr string + listErr error + enableShow bool + showStr string + showErr error + expectedJobState AzcopyJobState + expectedPercent string + expectedErr error + }{ + { + desc: "run exec get error", + listStr: "", + listErr: fmt.Errorf("error"), + enableShow: false, + showStr: "", + showErr: nil, + expectedJobState: AzcopyJobError, + expectedPercent: "", + expectedErr: fmt.Errorf("couldn't list jobs in azcopy error"), + }, + { + desc: "run exec parse azcopy job list get error", + listStr: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC", + listErr: nil, + enableShow: false, + showStr: "", + showErr: nil, + expectedJobState: AzcopyJobError, + expectedPercent: "", + expectedErr: fmt.Errorf("couldn't parse azcopy job list in azcopy error parsing jobs list: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC"), + }, + { + desc: "run exec parse azcopy job not found jobid when Status is Canceled", + listStr: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Cancelled\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + listErr: nil, + enableShow: false, + showStr: "", + showErr: nil, + expectedJobState: AzcopyJobNotFound, + expectedPercent: "", + expectedErr: nil, + }, + { + desc: "run exec parse azcopy job Completed", + listStr: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + listErr: nil, + enableShow: false, + showStr: "", + showErr: nil, + expectedJobState: AzcopyJobCompleted, + expectedPercent: "100.0", + expectedErr: nil, + }, + { + desc: "run exec get error in azcopy jobs show", + listStr: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: InProgress\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + listErr: nil, + enableShow: true, + showStr: "", + showErr: fmt.Errorf("error"), + expectedJobState: AzcopyJobError, + expectedPercent: "", + expectedErr: fmt.Errorf("couldn't show jobs summary in azcopy error"), + }, + { + desc: "run exec parse azcopy job show error", + listStr: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: InProgress\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + listErr: nil, + enableShow: true, + showStr: "", + showErr: nil, + expectedJobState: AzcopyJobError, + expectedPercent: "", + expectedErr: fmt.Errorf("couldn't parse azcopy job show in azcopy error parsing jobs summary: in Percent Complete (approx)"), + }, + { + desc: "run exec parse azcopy job show succeed", + listStr: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: InProgress\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + listErr: nil, + enableShow: true, + showStr: "Percent Complete (approx): 50.0", + showErr: nil, + expectedJobState: AzcopyJobRunning, + expectedPercent: "50.0", + expectedErr: nil, + }, + } + for _, test := range tests { + dstBlobContainer := "dstBlobContainer" + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + m := NewMockEXEC(ctrl) + m.EXPECT().RunCommand(gomock.Eq("azcopy jobs list | grep dstBlobContainer -B 3")).Return(test.listStr, test.listErr) + if test.enableShow { + m.EXPECT().RunCommand(gomock.Not("azcopy jobs list | grep dstBlobContainer -B 3")).Return(test.showStr, test.showErr) + } + + azcopyFunc := &Azcopy{} + azcopyFunc.ExecCmd = m + jobState, percent, err := azcopyFunc.GetAzcopyJob(dstBlobContainer) + if jobState != test.expectedJobState || percent != test.expectedPercent || !reflect.DeepEqual(err, test.expectedErr) { + t.Errorf("test[%s]: unexpected jobState: %v, percent: %v, err: %v, expected jobState: %v, percent: %v, err: %v", test.desc, jobState, percent, err, test.expectedJobState, test.expectedPercent, test.expectedErr) + } + } +} + +func TestParseAzcopyJobList(t *testing.T) { + tests := []struct { + desc string + str string + expectedJobid string + expectedJobState AzcopyJobState + expectedErr error + }{ + { + desc: "azcopy job not found", + str: "", + expectedJobid: "", + expectedJobState: AzcopyJobNotFound, + expectedErr: nil, + }, + { + desc: "parse azcopy job list error", + str: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC", + expectedJobid: "", + expectedJobState: AzcopyJobError, + expectedErr: fmt.Errorf("error parsing jobs list: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC"), + }, + { + desc: "parse azcopy job list status error", + str: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus Cancelled\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + expectedJobid: "", + expectedJobState: AzcopyJobError, + expectedErr: fmt.Errorf("error parsing jobs list status: Status Cancelled"), + }, + { + desc: "parse azcopy job not found jobid when Status is Canceled", + str: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Cancelled\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + expectedJobid: "", + expectedJobState: AzcopyJobNotFound, + expectedErr: nil, + }, + { + desc: "parse azcopy job Completed", + str: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: Completed\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + expectedJobid: "", + expectedJobState: AzcopyJobCompleted, + expectedErr: nil, + }, + { + desc: "parse azcopy job InProgress", + str: "JobId: ed1c3833-eaff-fe42-71d7-513fb065a9d9\nStart Time: Monday, 07-Aug-23 03:29:54 UTC\nStatus: InProgress\nCommand: copy https://{accountName}.file.core.windows.net/{srcFileshare}{SAStoken} https://{accountName}.file.core.windows.net/{dstFileshare}{SAStoken} --recursive --check-length=false", + expectedJobid: "ed1c3833-eaff-fe42-71d7-513fb065a9d9", + expectedJobState: AzcopyJobRunning, + expectedErr: nil, + }, + } + + for _, test := range tests { + dstBlobContainer := "dstBlobContainer" + jobid, jobState, err := parseAzcopyJobList(test.str, dstBlobContainer) + if jobid != test.expectedJobid || jobState != test.expectedJobState || !reflect.DeepEqual(err, test.expectedErr) { + t.Errorf("test[%s]: unexpected jobid: %v, jobState: %v, err: %v, expected jobid: %v, jobState: %v, err: %v", test.desc, jobid, jobState, err, test.expectedJobid, test.expectedJobState, test.expectedErr) + } + } +} + +func TestParseAzcopyJobShow(t *testing.T) { + tests := []struct { + desc string + str string + expectedJobState AzcopyJobState + expectedPercent string + expectedErr error + }{ + { + desc: "error parse azcopy job show", + str: "", + expectedJobState: AzcopyJobError, + expectedPercent: "", + expectedErr: fmt.Errorf("error parsing jobs summary: in Percent Complete (approx)"), + }, + { + desc: "parse azcopy job show succeed", + str: "Percent Complete (approx): 50.0", + expectedJobState: AzcopyJobRunning, + expectedPercent: "50.0", + expectedErr: nil, + }, + } + + for _, test := range tests { + jobState, percent, err := parseAzcopyJobShow(test.str) + if jobState != test.expectedJobState || percent != test.expectedPercent || !reflect.DeepEqual(err, test.expectedErr) { + t.Errorf("test[%s]: unexpected jobState: %v, percent: %v, err: %v, expected jobState: %v, percent: %v, err: %v", test.desc, jobState, percent, err, test.expectedJobState, test.expectedPercent, test.expectedErr) + } + } +} diff --git a/test/e2e/driver/blob_csi_driver.go b/test/e2e/driver/blob_csi_driver.go index f554f31bf..aace41a39 100644 --- a/test/e2e/driver/blob_csi_driver.go +++ b/test/e2e/driver/blob_csi_driver.go @@ -32,7 +32,7 @@ type blobCSIDriver struct { driverName string } -// InitBlobCSIDriver returns blobCSIDriver that implemnts DynamicPVTestDriver interface +// InitBlobCSIDriver returns blobCSIDriver that implements DynamicPVTestDriver interface func InitBlobCSIDriver() PVTestDriver { return &blobCSIDriver{ driverName: blob.DefaultDriverName, diff --git a/test/e2e/dynamic_provisioning_test.go b/test/e2e/dynamic_provisioning_test.go index e6eef215c..0f2ee5697 100644 --- a/test/e2e/dynamic_provisioning_test.go +++ b/test/e2e/dynamic_provisioning_test.go @@ -82,6 +82,7 @@ var _ = ginkgo.Describe("[blob-csi-e2e] Dynamic Provisioning", func() { "secretNamespace": "default", // make sure this is the first test case due to storeAccountKey is set as false "storeAccountKey": "false", + "getLatestAccountKey": "true", "requireInfraEncryption": "true", "accessTier": "Hot", }, @@ -840,4 +841,132 @@ var _ = ginkgo.Describe("[blob-csi-e2e] Dynamic Provisioning", func() { } test.Run(ctx, cs, ns) }) + + ginkgo.It("should clone a volume from an existing NFSv3 volume [nfs]", func(ctx ginkgo.SpecContext) { + pod := testsuites.PodDetails{ + Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", + Volumes: []testsuites.VolumeDetails{ + { + ClaimSize: "10Gi", + MountOptions: []string{ + "nconnect=8", + }, + VolumeMount: testsuites.VolumeMountDetails{ + NameGenerate: "test-volume-", + MountPathGenerate: "/mnt/test-", + }, + }, + }, + } + podWithClonedVolume := testsuites.PodDetails{ + Cmd: "grep 'hello world' /mnt/test-1/data", + } + test := testsuites.DynamicallyProvisionedVolumeCloningTest{ + CSIDriver: testDriver, + Pod: pod, + PodWithClonedVolume: podWithClonedVolume, + StorageClassParameters: map[string]string{ + "skuName": "Premium_LRS", + "protocol": "nfs", + "mountPermissions": "0755", + }, + } + test.Run(ctx, cs, ns) + }) + + ginkgo.It("should clone a large size volume from an existing NFSv3 volume [nfs]", func(ctx ginkgo.SpecContext) { + pod := testsuites.PodDetails{ + Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data && dd if=/dev/zero of=/mnt/test-1/test bs=99G count=5", + Volumes: []testsuites.VolumeDetails{ + { + ClaimSize: "100Gi", + MountOptions: []string{ + "nconnect=8", + }, + VolumeMount: testsuites.VolumeMountDetails{ + NameGenerate: "test-volume-", + MountPathGenerate: "/mnt/test-", + }, + }, + }, + } + podWithClonedVolume := testsuites.PodDetails{ + Cmd: "grep 'hello world' /mnt/test-1/data", + } + test := testsuites.DynamicallyProvisionedVolumeCloningTest{ + CSIDriver: testDriver, + Pod: pod, + PodWithClonedVolume: podWithClonedVolume, + StorageClassParameters: map[string]string{ + "skuName": "Premium_LRS", + "protocol": "nfs", + "mountPermissions": "0755", + }, + } + test.Run(ctx, cs, ns) + }) + + ginkgo.It("should clone a volume from an existing blobfuse2 volume [fuse2]", func(ctx ginkgo.SpecContext) { + pod := testsuites.PodDetails{ + Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", + Volumes: []testsuites.VolumeDetails{ + { + ClaimSize: "10Gi", + MountOptions: []string{ + "-o allow_other", + "--virtual-directory=true", // blobfuse2 mount options + }, + VolumeMount: testsuites.VolumeMountDetails{ + NameGenerate: "test-volume-", + MountPathGenerate: "/mnt/test-", + }, + }, + }, + } + podWithClonedVolume := testsuites.PodDetails{ + Cmd: "grep 'hello world' /mnt/test-1/data", + } + test := testsuites.DynamicallyProvisionedVolumeCloningTest{ + CSIDriver: testDriver, + Pod: pod, + PodWithClonedVolume: podWithClonedVolume, + StorageClassParameters: map[string]string{ + "skuName": "Standard_LRS", + "protocol": "fuse2", + }, + } + test.Run(ctx, cs, ns) + }) + + ginkgo.It("should clone a large size volume from an existing blobfuse2 volume [fuse2]", func(ctx ginkgo.SpecContext) { + pod := testsuites.PodDetails{ + Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data && dd if=/dev/zero of=/mnt/test-1/test bs=99G count=5", + Volumes: []testsuites.VolumeDetails{ + { + ClaimSize: "100Gi", + MountOptions: []string{ + "-o allow_other", + "--virtual-directory=true", // blobfuse2 mount options + }, + VolumeMount: testsuites.VolumeMountDetails{ + NameGenerate: "test-volume-", + MountPathGenerate: "/mnt/test-", + }, + }, + }, + } + podWithClonedVolume := testsuites.PodDetails{ + Cmd: "grep 'hello world' /mnt/test-1/data", + } + test := testsuites.DynamicallyProvisionedVolumeCloningTest{ + CSIDriver: testDriver, + Pod: pod, + PodWithClonedVolume: podWithClonedVolume, + StorageClassParameters: map[string]string{ + "skuName": "Standard_LRS", + "protocol": "fuse2", + }, + } + test.Run(ctx, cs, ns) + }) }) diff --git a/test/e2e/testsuites/dynamically_provisioned_volume_cloning_tester.go b/test/e2e/testsuites/dynamically_provisioned_volume_cloning_tester.go new file mode 100644 index 000000000..955926078 --- /dev/null +++ b/test/e2e/testsuites/dynamically_provisioned_volume_cloning_tester.go @@ -0,0 +1,82 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testsuites + +import ( + "context" + "time" + + "github.com/onsi/ginkgo/v2" + v1 "k8s.io/api/core/v1" + clientset "k8s.io/client-go/kubernetes" + "sigs.k8s.io/blob-csi-driver/test/e2e/driver" +) + +// DynamicallyProvisionedVolumeCloningTest will provision required StorageClass(es), PVC(s) and Pod(s) +// ClonedVolumeSize optional for when testing for cloned volume with different size to the original volume +type DynamicallyProvisionedVolumeCloningTest struct { + CSIDriver driver.DynamicPVTestDriver + Pod PodDetails + PodWithClonedVolume PodDetails + ClonedVolumeSize string + StorageClassParameters map[string]string +} + +func (t *DynamicallyProvisionedVolumeCloningTest) Run(ctx context.Context, client clientset.Interface, namespace *v1.Namespace) { + // create the storageClass + tsc, tscCleanup := t.Pod.Volumes[0].CreateStorageClass(ctx, client, namespace, t.CSIDriver, t.StorageClassParameters) + defer tscCleanup(ctx) + + // create the pod + t.Pod.Volumes[0].StorageClass = tsc.storageClass + tpod, cleanups := t.Pod.SetupWithDynamicVolumes(ctx, client, namespace, t.CSIDriver, t.StorageClassParameters) + for i := range cleanups { + defer cleanups[i](ctx) + } + + ginkgo.By("deploying the pod") + tpod.Create(ctx) + defer tpod.Cleanup(ctx) + ginkgo.By("checking that the pod's command exits with no error") + tpod.WaitForSuccess(ctx) + ginkgo.By("sleep 5s and then clone volume") + time.Sleep(5 * time.Second) + + ginkgo.By("cloning existing volume") + clonedVolume := t.Pod.Volumes[0] + clonedVolume.DataSource = &DataSource{ + Name: tpod.pod.Spec.Volumes[0].VolumeSource.PersistentVolumeClaim.ClaimName, + Kind: VolumePVCKind, + } + clonedVolume.StorageClass = tsc.storageClass + + if t.ClonedVolumeSize != "" { + clonedVolume.ClaimSize = t.ClonedVolumeSize + } + + t.PodWithClonedVolume.Volumes = []VolumeDetails{clonedVolume} + tpod, cleanups = t.PodWithClonedVolume.SetupWithDynamicVolumes(ctx, client, namespace, t.CSIDriver, t.StorageClassParameters) + for i := range cleanups { + defer cleanups[i](ctx) + } + + ginkgo.By("deploying a second pod with cloned volume") + tpod.Create(ctx) + defer tpod.Cleanup(ctx) + ginkgo.By("checking that the pod's command exits with no error") + tpod.WaitForSuccess(ctx) +} diff --git a/test/e2e/testsuites/specs.go b/test/e2e/testsuites/specs.go index 006e1e8ed..e785decc6 100644 --- a/test/e2e/testsuites/specs.go +++ b/test/e2e/testsuites/specs.go @@ -50,7 +50,9 @@ type VolumeDetails struct { // Optional, used with pre-provisioned volumes VolumeID string // Optional, used with PVCs created from snapshots - DataSource *DataSource + DataSource *DataSource + // Optional, used with specified StorageClass + StorageClass *storagev1.StorageClass NodeStageSecretRef string Attrib map[string]string } @@ -63,6 +65,7 @@ const ( ) const ( + VolumePVCKind = "PersistentVolumeClaim" APIVersionv1alpha1 = "v1alpha1" ) @@ -84,6 +87,7 @@ type VolumeDeviceDetails struct { } type DataSource struct { + Kind string Name string } @@ -186,6 +190,7 @@ func (volume *VolumeDetails) SetupDynamicPersistentVolumeClaim(ctx context.Conte if volume.DataSource != nil { dataSource := &v1.TypedLocalObjectReference{ Name: volume.DataSource.Name, + Kind: volume.DataSource.Kind, } tpvc = NewTestPersistentVolumeClaimWithDataSource(client, namespace, volume.ClaimSize, volume.VolumeMode, &createdStorageClass, dataSource) } else { @@ -220,3 +225,11 @@ func (volume *VolumeDetails) SetupPreProvisionedPersistentVolumeClaim(ctx contex return tpvc, cleanupFuncs } + +func (volume *VolumeDetails) CreateStorageClass(ctx context.Context, client clientset.Interface, namespace *v1.Namespace, csiDriver driver.DynamicPVTestDriver, storageClassParameters map[string]string) (*TestStorageClass, func(ctx context.Context)) { + ginkgo.By("setting up the StorageClass") + storageClass := csiDriver.GetProvisionStorageClass(storageClassParameters, volume.MountOptions, volume.ReclaimPolicy, volume.VolumeBindingMode, volume.AllowedTopologyValues, namespace.Name) + tsc := NewTestStorageClass(client, namespace, storageClass) + tsc.Create(ctx) + return tsc, tsc.Cleanup +} diff --git a/test/external-e2e/run.sh b/test/external-e2e/run.sh index 542f10b62..64caa2b2e 100755 --- a/test/external-e2e/run.sh +++ b/test/external-e2e/run.sh @@ -17,7 +17,7 @@ set -xe PROJECT_ROOT=$(git rev-parse --show-toplevel) -DRIVER="test" +DRIVER="blob" setup_e2e_binaries() { # download k8s external e2e binary @@ -40,7 +40,6 @@ setup_e2e_binaries() { } print_logs() { - bash ./hack/verify-examples.sh echo "print out driver logs ..." bash ./test/utils/blob_log.sh $DRIVER } @@ -66,7 +65,7 @@ if [ ! -z ${EXTERNAL_E2E_TEST_BLOBFUSE_v2} ]; then cp deploy/example/storageclass-blobfuse2.yaml /tmp/csi/storageclass.yaml # achieve close-to-open cache consistency like in NFSv3 sed -i 's/file-cache-timeout-in-seconds=120/file-cache-timeout-in-seconds=0/g' /tmp/csi/storageclass.yaml - ginkgo -p -v --fail-fast --flake-attempts 2 -focus="External.Storage.*$DRIVER.csi.azure.com" \ + ginkgo -p -v --fail-fast --flake-attempts 8 -focus="External.Storage.*$DRIVER.csi.azure.com" \ -skip='\[Disruptive\]|allow exec of files on the volume|unmount after the subpath directory is deleted|should concurrently access the single volume from pods on different node|pod created with an initial fsgroup, volume contents ownership changed via chgrp in first pod, new pod with same fsgroup skips ownership changes to the volume contents|should provision storage with any volume data source|should mount multiple PV pointing to the same storage on the same node' kubernetes/test/bin/e2e.test -- \ -storage.testdriver=$PROJECT_ROOT/test/external-e2e/testdriver-blobfuse.yaml \ --kubeconfig=$KUBECONFIG @@ -80,3 +79,6 @@ if [ ! -z ${EXTERNAL_E2E_TEST_NFS} ]; then -storage.testdriver=$PROJECT_ROOT/test/external-e2e/testdriver-nfs.yaml \ --kubeconfig=$KUBECONFIG fi + +echo "begin to run verify-examples.sh ...." +bash ./hack/verify-examples.sh diff --git a/test/external-e2e/testdriver-blobfuse.yaml b/test/external-e2e/testdriver-blobfuse.yaml index bd67c3246..debd66558 100644 --- a/test/external-e2e/testdriver-blobfuse.yaml +++ b/test/external-e2e/testdriver-blobfuse.yaml @@ -5,7 +5,7 @@ ShortName: blobfuse StorageClass: FromFile: /tmp/csi/storageclass.yaml DriverInfo: - Name: test.csi.azure.com + Name: blob.csi.azure.com Capabilities: persistence: true exec: true @@ -16,4 +16,5 @@ DriverInfo: controllerExpansion: true nodeExpansion: true volumeLimits: false - snapshotDataSource: false \ No newline at end of file + snapshotDataSource: false + pvcDataSource: true diff --git a/test/external-e2e/testdriver-nfs.yaml b/test/external-e2e/testdriver-nfs.yaml index a26a3d432..8a7b07ca7 100644 --- a/test/external-e2e/testdriver-nfs.yaml +++ b/test/external-e2e/testdriver-nfs.yaml @@ -5,7 +5,7 @@ ShortName: blobfuse StorageClass: FromFile: /tmp/csi/storageclass.yaml DriverInfo: - Name: test.csi.azure.com + Name: blob.csi.azure.com Capabilities: persistence: true exec: true @@ -17,3 +17,4 @@ DriverInfo: nodeExpansion: true volumeLimits: false snapshotDataSource: false + pvcDataSource: true diff --git a/test/sanity/run-test.sh b/test/sanity/run-test.sh index b4ba71a12..d82fb6b56 100755 --- a/test/sanity/run-test.sh +++ b/test/sanity/run-test.sh @@ -32,9 +32,20 @@ if [[ "$#" -gt 0 ]] && [[ -n "$1" ]]; then nodeid="$1" fi +azcopyPath="/usr/local/bin/azcopy" +if [ ! -f "$azcopyPath" ]; then + azcopyVersion=azcopy_linux_amd64_10.18.1 + echo 'Downloading azcopy...' + wget -c https://azcopyvnext.azureedge.net/release20230420/$azcopyVersion.tar.gz + tar -zxvf $azcopyVersion.tar.gz + mv ./$azcopyVersion/azcopy /usr/local/bin/azcopy + rm -rf ./$azcopyVersion* + chmod +x /usr/local/bin/azcopy +fi + _output/amd64/blobplugin --endpoint "$controllerendpoint" -v=5 & _output/amd64/blobplugin --endpoint "$nodeendpoint" --nodeid "$nodeid" --enable-blob-mock-mount -v=5 & echo "Begin to run sanity test..." readonly CSI_SANITY_BIN='csi-sanity' -"$CSI_SANITY_BIN" --ginkgo.v --csi.endpoint=$nodeendpoint --csi.controllerendpoint=$controllerendpoint -ginkgo.skip="should fail when requesting to create a volume with already existing name and different capacity" +"$CSI_SANITY_BIN" --ginkgo.v --csi.endpoint=$nodeendpoint --csi.controllerendpoint=$controllerendpoint -ginkgo.skip="should fail when requesting to create a volume with already existing name and different capacity|should create volume from an existing source snapshot" diff --git a/test/utils/blob_log.sh b/test/utils/blob_log.sh index 3ba0039e0..493ee46c6 100755 --- a/test/utils/blob_log.sh +++ b/test/utils/blob_log.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -e +# set -e NS=kube-system CONTAINER=blob @@ -23,6 +23,13 @@ if [[ "$#" -gt 0 ]]; then DRIVER=$1 fi +cleanup() { + echo "hit unexpected error during log print, exit 0" + exit 0 +} + +trap cleanup ERR + echo "print out all nodes status ..." kubectl get nodes -o wide echo "======================================================================================" @@ -49,11 +56,6 @@ kubectl get pods -n${NS} -l${LABEL} \ | awk 'NR>1 {print $1}' \ | xargs -I {} kubectl logs {} --prefix -c${CONTAINER} -n${NS} -echo "print out cloudprovider_azure metrics ..." -echo "======================================================================================" -ip=`kubectl get svc csi-$DRIVER-controller -n kube-system | awk '{print $4}'` -curl http://$ip:29634/metrics - if [ -n "$ENABLE_BLOBFUSE_PROXY" ]; then echo "print out install-blobfuse-proxy logs ..." echo "======================================================================================" @@ -64,4 +66,12 @@ if [ -n "$ENABLE_BLOBFUSE_PROXY" ]; then | xargs -I {} kubectl logs {} --prefix -c${PROXY} -n${NS} fi - +echo "======================================================================================" +ip=`kubectl get svc csi-$DRIVER-controller -n kube-system | awk '{print $4}'` +if echo "$ip" | grep -q "\."; then + echo "print out cloudprovider_azure metrics ..." + curl http://$ip:29634/metrics +else + echo "csi-$DRIVER-controller service ip is empty" + kubectl get svc csi-$DRIVER-controller -n kube-system +fi diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md index 80321d29a..c4da5d78f 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md @@ -1,5 +1,74 @@ # Release History +## 1.6.1 (2023-06-06) + +### Bugs Fixed +* Retry policy always clones the underlying `*http.Request` before invoking the next policy. +* Added some non-standard error codes to the list of error codes for unregistered resource providers. +* Fixed an issue in `azcore.NewClient()` and `arm.NewClient()` that could cause an incorrect module name to be used in telemetry. + +## 1.6.0 (2023-05-04) + +### Features Added +* Added support for ARM cross-tenant authentication. Set the `AuxiliaryTenants` field of `arm.ClientOptions` to enable. +* Added `TenantID` field to `policy.TokenRequestOptions`. + +## 1.5.0 (2023-04-06) + +### Features Added +* Added `ShouldRetry` to `policy.RetryOptions` for finer-grained control over when to retry. + +### Breaking Changes +> These changes affect only code written against a beta version such as v1.5.0-beta.1 +> These features will return in v1.6.0-beta.1. +* Removed `TokenRequestOptions.Claims` and `.TenantID` +* Removed ARM client support for CAE and cross-tenant auth. + +### Bugs Fixed +* Added non-conformant LRO terminal states `Cancelled` and `Completed`. + +### Other Changes +* Updated to latest `internal` module. + +## 1.5.0-beta.1 (2023-03-02) + +### Features Added +* This release includes the features added in v1.4.0-beta.1 + +## 1.4.0 (2023-03-02) +> This release doesn't include features added in v1.4.0-beta.1. They will return in v1.5.0-beta.1. + +### Features Added +* Add `Clone()` method for `arm/policy.ClientOptions`. + +### Bugs Fixed +* ARM's RP registration policy will no longer swallow unrecognized errors. +* Fixed an issue in `runtime.NewPollerFromResumeToken()` when resuming a `Poller` with a custom `PollingHandler`. +* Fixed wrong policy copy in `arm/runtime.NewPipeline()`. + +## 1.4.0-beta.1 (2023-02-02) + +### Features Added +* Added support for ARM cross-tenant authentication. Set the `AuxiliaryTenants` field of `arm.ClientOptions` to enable. +* Added `Claims` and `TenantID` fields to `policy.TokenRequestOptions`. +* ARM bearer token policy handles CAE challenges. + +## 1.3.1 (2023-02-02) + +### Other Changes +* Update dependencies to latest versions. + +## 1.3.0 (2023-01-06) + +### Features Added +* Added `BearerTokenOptions.AuthorizationHandler` to enable extending `runtime.BearerTokenPolicy` + with custom authorization logic +* Added `Client` types and matching constructors to the `azcore` and `arm` packages. These represent a basic client for HTTP and ARM respectively. + +### Other Changes +* Updated `internal` module to latest version. +* `policy/Request.SetBody()` allows replacing a request's body with an empty one + ## 1.2.0 (2022-11-04) ### Features Added diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/client.go new file mode 100644 index 000000000..aa34575f6 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/client.go @@ -0,0 +1,78 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package arm + +import ( + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" + armruntime "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing" +) + +// ClientOptions contains configuration settings for a client's pipeline. +type ClientOptions = armpolicy.ClientOptions + +// Client is a HTTP client for use with ARM endpoints. It consists of an endpoint, pipeline, and tracing provider. +type Client struct { + ep string + pl runtime.Pipeline + tr tracing.Tracer +} + +// NewClient creates a new Client instance with the provided values. +// This client is intended to be used with Azure Resource Manager endpoints. +// - clientName - the fully qualified name of the client ("module/package.Client"); this is used by the telemetry policy and tracing provider. +// if module and package are the same value, the "module/" prefix can be omitted. +// - moduleVersion - the version of the containing module; used by the telemetry policy +// - cred - the TokenCredential used to authenticate the request +// - options - optional client configurations; pass nil to accept the default values +func NewClient(clientName, moduleVersion string, cred azcore.TokenCredential, options *ClientOptions) (*Client, error) { + mod, client, err := shared.ExtractModuleName(clientName) + if err != nil { + return nil, err + } + + if options == nil { + options = &ClientOptions{} + } + + if !options.Telemetry.Disabled { + if err := shared.ValidateModVer(moduleVersion); err != nil { + return nil, err + } + } + + ep := cloud.AzurePublic.Services[cloud.ResourceManager].Endpoint + if c, ok := options.Cloud.Services[cloud.ResourceManager]; ok { + ep = c.Endpoint + } + pl, err := armruntime.NewPipeline(mod, moduleVersion, cred, runtime.PipelineOptions{}, options) + if err != nil { + return nil, err + } + + tr := options.TracingProvider.NewTracer(client, moduleVersion) + return &Client{ep: ep, pl: pl, tr: tr}, nil +} + +// Endpoint returns the service's base URL for this client. +func (c *Client) Endpoint() string { + return c.ep +} + +// Pipeline returns the pipeline for this client. +func (c *Client) Pipeline() runtime.Pipeline { + return c.pl +} + +// Tracer returns the tracer for this client. +func (c *Client) Tracer() tracing.Tracer { + return c.tr +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/client_options.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/client_options.go deleted file mode 100644 index 3e0f22e57..000000000 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/client_options.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build go1.18 -// +build go1.18 - -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package arm - -import "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" - -// ClientOptions contains configuration settings for a client's pipeline. -type ClientOptions struct { - policy.ClientOptions - - // DisableRPRegistration disables the auto-RP registration policy. Defaults to false. - DisableRPRegistration bool -} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go new file mode 100644 index 000000000..187fe82b9 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_identifier.go @@ -0,0 +1,224 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package resource + +import ( + "fmt" + "strings" +) + +const ( + providersKey = "providers" + subscriptionsKey = "subscriptions" + resourceGroupsLowerKey = "resourcegroups" + locationsKey = "locations" + builtInResourceNamespace = "Microsoft.Resources" +) + +// RootResourceID defines the tenant as the root parent of all other ResourceID. +var RootResourceID = &ResourceID{ + Parent: nil, + ResourceType: TenantResourceType, + Name: "", +} + +// ResourceID represents a resource ID such as `/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg`. +// Don't create this type directly, use ParseResourceID instead. +type ResourceID struct { + // Parent is the parent ResourceID of this instance. + // Can be nil if there is no parent. + Parent *ResourceID + + // SubscriptionID is the subscription ID in this resource ID. + // The value can be empty if the resource ID does not contain a subscription ID. + SubscriptionID string + + // ResourceGroupName is the resource group name in this resource ID. + // The value can be empty if the resource ID does not contain a resource group name. + ResourceGroupName string + + // Provider represents the provider name in this resource ID. + // This is only valid when the resource ID represents a resource provider. + // Example: `/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Insights` + Provider string + + // Location is the location in this resource ID. + // The value can be empty if the resource ID does not contain a location name. + Location string + + // ResourceType represents the type of this resource ID. + ResourceType ResourceType + + // Name is the resource name of this resource ID. + Name string + + isChild bool + stringValue string +} + +// ParseResourceID parses a string to an instance of ResourceID +func ParseResourceID(id string) (*ResourceID, error) { + if len(id) == 0 { + return nil, fmt.Errorf("invalid resource ID: id cannot be empty") + } + + if !strings.HasPrefix(id, "/") { + return nil, fmt.Errorf("invalid resource ID: resource id '%s' must start with '/'", id) + } + + parts := splitStringAndOmitEmpty(id, "/") + + if len(parts) < 2 { + return nil, fmt.Errorf("invalid resource ID: %s", id) + } + + if !strings.EqualFold(parts[0], subscriptionsKey) && !strings.EqualFold(parts[0], providersKey) { + return nil, fmt.Errorf("invalid resource ID: %s", id) + } + + return appendNext(RootResourceID, parts, id) +} + +// String returns the string of the ResourceID +func (id *ResourceID) String() string { + if len(id.stringValue) > 0 { + return id.stringValue + } + + if id.Parent == nil { + return "" + } + + builder := strings.Builder{} + builder.WriteString(id.Parent.String()) + + if id.isChild { + builder.WriteString(fmt.Sprintf("/%s", id.ResourceType.lastType())) + if len(id.Name) > 0 { + builder.WriteString(fmt.Sprintf("/%s", id.Name)) + } + } else { + builder.WriteString(fmt.Sprintf("/providers/%s/%s/%s", id.ResourceType.Namespace, id.ResourceType.Type, id.Name)) + } + + id.stringValue = builder.String() + + return id.stringValue +} + +func newResourceID(parent *ResourceID, resourceTypeName string, resourceName string) *ResourceID { + id := &ResourceID{} + id.init(parent, chooseResourceType(resourceTypeName, parent), resourceName, true) + return id +} + +func newResourceIDWithResourceType(parent *ResourceID, resourceType ResourceType, resourceName string) *ResourceID { + id := &ResourceID{} + id.init(parent, resourceType, resourceName, true) + return id +} + +func newResourceIDWithProvider(parent *ResourceID, providerNamespace, resourceTypeName, resourceName string) *ResourceID { + id := &ResourceID{} + id.init(parent, NewResourceType(providerNamespace, resourceTypeName), resourceName, false) + return id +} + +func chooseResourceType(resourceTypeName string, parent *ResourceID) ResourceType { + if strings.EqualFold(resourceTypeName, resourceGroupsLowerKey) { + return ResourceGroupResourceType + } else if strings.EqualFold(resourceTypeName, subscriptionsKey) && parent != nil && parent.ResourceType.String() == TenantResourceType.String() { + return SubscriptionResourceType + } + + return parent.ResourceType.AppendChild(resourceTypeName) +} + +func (id *ResourceID) init(parent *ResourceID, resourceType ResourceType, name string, isChild bool) { + if parent != nil { + id.Provider = parent.Provider + id.SubscriptionID = parent.SubscriptionID + id.ResourceGroupName = parent.ResourceGroupName + id.Location = parent.Location + } + + if resourceType.String() == SubscriptionResourceType.String() { + id.SubscriptionID = name + } + + if resourceType.lastType() == locationsKey { + id.Location = name + } + + if resourceType.String() == ResourceGroupResourceType.String() { + id.ResourceGroupName = name + } + + if resourceType.String() == ProviderResourceType.String() { + id.Provider = name + } + + if parent == nil { + id.Parent = RootResourceID + } else { + id.Parent = parent + } + id.isChild = isChild + id.ResourceType = resourceType + id.Name = name +} + +func appendNext(parent *ResourceID, parts []string, id string) (*ResourceID, error) { + if len(parts) == 0 { + return parent, nil + } + + if len(parts) == 1 { + // subscriptions and resourceGroups are not valid ids without their names + if strings.EqualFold(parts[0], subscriptionsKey) || strings.EqualFold(parts[0], resourceGroupsLowerKey) { + return nil, fmt.Errorf("invalid resource ID: %s", id) + } + + // resourceGroup must contain either child or provider resource type + if parent.ResourceType.String() == ResourceGroupResourceType.String() { + return nil, fmt.Errorf("invalid resource ID: %s", id) + } + + return newResourceID(parent, parts[0], ""), nil + } + + if strings.EqualFold(parts[0], providersKey) && (len(parts) == 2 || strings.EqualFold(parts[2], providersKey)) { + //provider resource can only be on a tenant or a subscription parent + if parent.ResourceType.String() != SubscriptionResourceType.String() && parent.ResourceType.String() != TenantResourceType.String() { + return nil, fmt.Errorf("invalid resource ID: %s", id) + } + + return appendNext(newResourceIDWithResourceType(parent, ProviderResourceType, parts[1]), parts[2:], id) + } + + if len(parts) > 3 && strings.EqualFold(parts[0], providersKey) { + return appendNext(newResourceIDWithProvider(parent, parts[1], parts[2], parts[3]), parts[4:], id) + } + + if len(parts) > 1 && !strings.EqualFold(parts[0], providersKey) { + return appendNext(newResourceID(parent, parts[0], parts[1]), parts[2:], id) + } + + return nil, fmt.Errorf("invalid resource ID: %s", id) +} + +func splitStringAndOmitEmpty(v, sep string) []string { + r := make([]string, 0) + for _, s := range strings.Split(v, sep) { + if len(s) == 0 { + continue + } + r = append(r, s) + } + + return r +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_type.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_type.go new file mode 100644 index 000000000..ca03ac971 --- /dev/null +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource/resource_type.go @@ -0,0 +1,114 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package resource + +import ( + "fmt" + "strings" +) + +// SubscriptionResourceType is the ResourceType of a subscription +var SubscriptionResourceType = NewResourceType(builtInResourceNamespace, "subscriptions") + +// ResourceGroupResourceType is the ResourceType of a resource group +var ResourceGroupResourceType = NewResourceType(builtInResourceNamespace, "resourceGroups") + +// TenantResourceType is the ResourceType of a tenant +var TenantResourceType = NewResourceType(builtInResourceNamespace, "tenants") + +// ProviderResourceType is the ResourceType of a provider +var ProviderResourceType = NewResourceType(builtInResourceNamespace, "providers") + +// ResourceType represents an Azure resource type, e.g. "Microsoft.Network/virtualNetworks/subnets". +// Don't create this type directly, use ParseResourceType or NewResourceType instead. +type ResourceType struct { + // Namespace is the namespace of the resource type. + // e.g. "Microsoft.Network" in resource type "Microsoft.Network/virtualNetworks/subnets" + Namespace string + + // Type is the full type name of the resource type. + // e.g. "virtualNetworks/subnets" in resource type "Microsoft.Network/virtualNetworks/subnets" + Type string + + // Types is the slice of all the sub-types of this resource type. + // e.g. ["virtualNetworks", "subnets"] in resource type "Microsoft.Network/virtualNetworks/subnets" + Types []string + + stringValue string +} + +// String returns the string of the ResourceType +func (t ResourceType) String() string { + return t.stringValue +} + +// IsParentOf returns true when the receiver is the parent resource type of the child. +func (t ResourceType) IsParentOf(child ResourceType) bool { + if !strings.EqualFold(t.Namespace, child.Namespace) { + return false + } + if len(t.Types) >= len(child.Types) { + return false + } + for i := range t.Types { + if !strings.EqualFold(t.Types[i], child.Types[i]) { + return false + } + } + + return true +} + +// AppendChild creates an instance of ResourceType using the receiver as the parent with childType appended to it. +func (t ResourceType) AppendChild(childType string) ResourceType { + return NewResourceType(t.Namespace, fmt.Sprintf("%s/%s", t.Type, childType)) +} + +// NewResourceType creates an instance of ResourceType using a provider namespace +// such as "Microsoft.Network" and type such as "virtualNetworks/subnets". +func NewResourceType(providerNamespace, typeName string) ResourceType { + return ResourceType{ + Namespace: providerNamespace, + Type: typeName, + Types: splitStringAndOmitEmpty(typeName, "/"), + stringValue: fmt.Sprintf("%s/%s", providerNamespace, typeName), + } +} + +// ParseResourceType parses the ResourceType from a resource type string (e.g. Microsoft.Network/virtualNetworks/subsets) +// or a resource identifier string. +// e.g. /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/mySubnet) +func ParseResourceType(resourceIDOrType string) (ResourceType, error) { + // split the path into segments + parts := splitStringAndOmitEmpty(resourceIDOrType, "/") + + // There must be at least a namespace and type name + if len(parts) < 1 { + return ResourceType{}, fmt.Errorf("invalid resource ID or type: %s", resourceIDOrType) + } + + // if the type is just subscriptions, it is a built-in type in the Microsoft.Resources namespace + if len(parts) == 1 { + // Simple resource type + return NewResourceType(builtInResourceNamespace, parts[0]), nil + } else if strings.Contains(parts[0], ".") { + // Handle resource types (Microsoft.Compute/virtualMachines, Microsoft.Network/virtualNetworks/subnets) + // it is a full type name + return NewResourceType(parts[0], strings.Join(parts[1:], "/")), nil + } else { + // Check if ResourceID + id, err := ParseResourceID(resourceIDOrType) + if err != nil { + return ResourceType{}, err + } + return NewResourceType(id.ResourceType.Namespace, id.ResourceType.Type), nil + } +} + +func (t ResourceType) lastType() string { + return t.Types[len(t.Types)-1] +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy/policy.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy/policy.go index ddf347093..83cf91e3e 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy/policy.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy/policy.go @@ -14,6 +14,12 @@ import ( // BearerTokenOptions configures the bearer token policy's behavior. type BearerTokenOptions struct { + // AuxiliaryTenants are additional tenant IDs for authenticating cross-tenant requests. + // The policy will add a token from each of these tenants to every request. The + // authenticating user or service principal must be a guest in these tenants, and the + // policy's credential must support multitenant authentication. + AuxiliaryTenants []string + // Scopes contains the list of permission scopes required for the token. Scopes []string } @@ -39,3 +45,54 @@ type RegistrationOptions struct { // NOTE: Setting this to a small value might cause the policy to prematurely fail. PollingDuration time.Duration } + +// ClientOptions contains configuration settings for a client's pipeline. +type ClientOptions struct { + policy.ClientOptions + + // AuxiliaryTenants are additional tenant IDs for authenticating cross-tenant requests. + // The client will add a token from each of these tenants to every request. The + // authenticating user or service principal must be a guest in these tenants, and the + // client's credential must support multitenant authentication. + AuxiliaryTenants []string + + // DisableRPRegistration disables the auto-RP registration policy. Defaults to false. + DisableRPRegistration bool +} + +// Clone return a deep copy of the current options. +func (o *ClientOptions) Clone() *ClientOptions { + if o == nil { + return nil + } + copiedOptions := *o + copiedOptions.Cloud.Services = copyMap(copiedOptions.Cloud.Services) + copiedOptions.Logging.AllowedHeaders = copyArray(copiedOptions.Logging.AllowedHeaders) + copiedOptions.Logging.AllowedQueryParams = copyArray(copiedOptions.Logging.AllowedQueryParams) + copiedOptions.Retry.StatusCodes = copyArray(copiedOptions.Retry.StatusCodes) + copiedOptions.PerRetryPolicies = copyArray(copiedOptions.PerRetryPolicies) + copiedOptions.PerCallPolicies = copyArray(copiedOptions.PerCallPolicies) + return &copiedOptions +} + +// copyMap return a new map with all the key value pair in the src map +func copyMap[K comparable, V any](src map[K]V) map[K]V { + if src == nil { + return nil + } + copiedMap := make(map[K]V) + for k, v := range src { + copiedMap[k] = v + } + return copiedMap +} + +// copyMap return a new array with all the elements in the src array +func copyArray[T any](src []T) []T { + if src == nil { + return nil + } + copiedArray := make([]T, len(src)) + copy(copiedArray, src) + return copiedArray +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_identifier.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_identifier.go index 6e2efed8b..d35d6374f 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_identifier.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_identifier.go @@ -7,218 +7,17 @@ package arm import ( - "fmt" - "strings" -) - -const ( - providersKey = "providers" - subscriptionsKey = "subscriptions" - resourceGroupsLowerKey = "resourcegroups" - locationsKey = "locations" - builtInResourceNamespace = "Microsoft.Resources" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource" ) // RootResourceID defines the tenant as the root parent of all other ResourceID. -var RootResourceID = &ResourceID{ - Parent: nil, - ResourceType: TenantResourceType, - Name: "", -} +var RootResourceID = resource.RootResourceID // ResourceID represents a resource ID such as `/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg`. // Don't create this type directly, use ParseResourceID instead. -type ResourceID struct { - // Parent is the parent ResourceID of this instance. - // Can be nil if there is no parent. - Parent *ResourceID - - // SubscriptionID is the subscription ID in this resource ID. - // The value can be empty if the resource ID does not contain a subscription ID. - SubscriptionID string - - // ResourceGroupName is the resource group name in this resource ID. - // The value can be empty if the resource ID does not contain a resource group name. - ResourceGroupName string - - // Provider represents the provider name in this resource ID. - // This is only valid when the resource ID represents a resource provider. - // Example: `/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Insights` - Provider string - - // Location is the location in this resource ID. - // The value can be empty if the resource ID does not contain a location name. - Location string - - // ResourceType represents the type of this resource ID. - ResourceType ResourceType - - // Name is the resource name of this resource ID. - Name string - - isChild bool - stringValue string -} +type ResourceID = resource.ResourceID // ParseResourceID parses a string to an instance of ResourceID func ParseResourceID(id string) (*ResourceID, error) { - if len(id) == 0 { - return nil, fmt.Errorf("invalid resource ID: id cannot be empty") - } - - if !strings.HasPrefix(id, "/") { - return nil, fmt.Errorf("invalid resource ID: resource id '%s' must start with '/'", id) - } - - parts := splitStringAndOmitEmpty(id, "/") - - if len(parts) < 2 { - return nil, fmt.Errorf("invalid resource ID: %s", id) - } - - if !strings.EqualFold(parts[0], subscriptionsKey) && !strings.EqualFold(parts[0], providersKey) { - return nil, fmt.Errorf("invalid resource ID: %s", id) - } - - return appendNext(RootResourceID, parts, id) -} - -// String returns the string of the ResourceID -func (id *ResourceID) String() string { - if len(id.stringValue) > 0 { - return id.stringValue - } - - if id.Parent == nil { - return "" - } - - builder := strings.Builder{} - builder.WriteString(id.Parent.String()) - - if id.isChild { - builder.WriteString(fmt.Sprintf("/%s", id.ResourceType.lastType())) - if len(id.Name) > 0 { - builder.WriteString(fmt.Sprintf("/%s", id.Name)) - } - } else { - builder.WriteString(fmt.Sprintf("/providers/%s/%s/%s", id.ResourceType.Namespace, id.ResourceType.Type, id.Name)) - } - - id.stringValue = builder.String() - - return id.stringValue -} - -func newResourceID(parent *ResourceID, resourceTypeName string, resourceName string) *ResourceID { - id := &ResourceID{} - id.init(parent, chooseResourceType(resourceTypeName, parent), resourceName, true) - return id -} - -func newResourceIDWithResourceType(parent *ResourceID, resourceType ResourceType, resourceName string) *ResourceID { - id := &ResourceID{} - id.init(parent, resourceType, resourceName, true) - return id -} - -func newResourceIDWithProvider(parent *ResourceID, providerNamespace, resourceTypeName, resourceName string) *ResourceID { - id := &ResourceID{} - id.init(parent, NewResourceType(providerNamespace, resourceTypeName), resourceName, false) - return id -} - -func chooseResourceType(resourceTypeName string, parent *ResourceID) ResourceType { - if strings.EqualFold(resourceTypeName, resourceGroupsLowerKey) { - return ResourceGroupResourceType - } else if strings.EqualFold(resourceTypeName, subscriptionsKey) && parent != nil && parent.ResourceType.String() == TenantResourceType.String() { - return SubscriptionResourceType - } - - return parent.ResourceType.AppendChild(resourceTypeName) -} - -func (id *ResourceID) init(parent *ResourceID, resourceType ResourceType, name string, isChild bool) { - if parent != nil { - id.Provider = parent.Provider - id.SubscriptionID = parent.SubscriptionID - id.ResourceGroupName = parent.ResourceGroupName - id.Location = parent.Location - } - - if resourceType.String() == SubscriptionResourceType.String() { - id.SubscriptionID = name - } - - if resourceType.lastType() == locationsKey { - id.Location = name - } - - if resourceType.String() == ResourceGroupResourceType.String() { - id.ResourceGroupName = name - } - - if resourceType.String() == ProviderResourceType.String() { - id.Provider = name - } - - if parent == nil { - id.Parent = RootResourceID - } else { - id.Parent = parent - } - id.isChild = isChild - id.ResourceType = resourceType - id.Name = name -} - -func appendNext(parent *ResourceID, parts []string, id string) (*ResourceID, error) { - if len(parts) == 0 { - return parent, nil - } - - if len(parts) == 1 { - // subscriptions and resourceGroups are not valid ids without their names - if strings.EqualFold(parts[0], subscriptionsKey) || strings.EqualFold(parts[0], resourceGroupsLowerKey) { - return nil, fmt.Errorf("invalid resource ID: %s", id) - } - - // resourceGroup must contain either child or provider resource type - if parent.ResourceType.String() == ResourceGroupResourceType.String() { - return nil, fmt.Errorf("invalid resource ID: %s", id) - } - - return newResourceID(parent, parts[0], ""), nil - } - - if strings.EqualFold(parts[0], providersKey) && (len(parts) == 2 || strings.EqualFold(parts[2], providersKey)) { - //provider resource can only be on a tenant or a subscription parent - if parent.ResourceType.String() != SubscriptionResourceType.String() && parent.ResourceType.String() != TenantResourceType.String() { - return nil, fmt.Errorf("invalid resource ID: %s", id) - } - - return appendNext(newResourceIDWithResourceType(parent, ProviderResourceType, parts[1]), parts[2:], id) - } - - if len(parts) > 3 && strings.EqualFold(parts[0], providersKey) { - return appendNext(newResourceIDWithProvider(parent, parts[1], parts[2], parts[3]), parts[4:], id) - } - - if len(parts) > 1 && !strings.EqualFold(parts[0], providersKey) { - return appendNext(newResourceID(parent, parts[0], parts[1]), parts[2:], id) - } - - return nil, fmt.Errorf("invalid resource ID: %s", id) -} - -func splitStringAndOmitEmpty(v, sep string) []string { - r := make([]string, 0) - for _, s := range strings.Split(v, sep) { - if len(s) == 0 { - continue - } - r = append(r, s) - } - - return r + return resource.ParseResourceID(id) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_type.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_type.go index 6e9dbec8d..fc7fbffd2 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_type.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/resource_type.go @@ -7,108 +7,34 @@ package arm import ( - "fmt" - "strings" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource" ) // SubscriptionResourceType is the ResourceType of a subscription -var SubscriptionResourceType = NewResourceType(builtInResourceNamespace, "subscriptions") +var SubscriptionResourceType = resource.SubscriptionResourceType // ResourceGroupResourceType is the ResourceType of a resource group -var ResourceGroupResourceType = NewResourceType(builtInResourceNamespace, "resourceGroups") +var ResourceGroupResourceType = resource.ResourceGroupResourceType // TenantResourceType is the ResourceType of a tenant -var TenantResourceType = NewResourceType(builtInResourceNamespace, "tenants") +var TenantResourceType = resource.TenantResourceType // ProviderResourceType is the ResourceType of a provider -var ProviderResourceType = NewResourceType(builtInResourceNamespace, "providers") +var ProviderResourceType = resource.ProviderResourceType // ResourceType represents an Azure resource type, e.g. "Microsoft.Network/virtualNetworks/subnets". // Don't create this type directly, use ParseResourceType or NewResourceType instead. -type ResourceType struct { - // Namespace is the namespace of the resource type. - // e.g. "Microsoft.Network" in resource type "Microsoft.Network/virtualNetworks/subnets" - Namespace string - - // Type is the full type name of the resource type. - // e.g. "virtualNetworks/subnets" in resource type "Microsoft.Network/virtualNetworks/subnets" - Type string - - // Types is the slice of all the sub-types of this resource type. - // e.g. ["virtualNetworks", "subnets"] in resource type "Microsoft.Network/virtualNetworks/subnets" - Types []string - - stringValue string -} - -// String returns the string of the ResourceType -func (t ResourceType) String() string { - return t.stringValue -} - -// IsParentOf returns true when the receiver is the parent resource type of the child. -func (t ResourceType) IsParentOf(child ResourceType) bool { - if !strings.EqualFold(t.Namespace, child.Namespace) { - return false - } - if len(t.Types) >= len(child.Types) { - return false - } - for i := range t.Types { - if !strings.EqualFold(t.Types[i], child.Types[i]) { - return false - } - } - - return true -} - -// AppendChild creates an instance of ResourceType using the receiver as the parent with childType appended to it. -func (t ResourceType) AppendChild(childType string) ResourceType { - return NewResourceType(t.Namespace, fmt.Sprintf("%s/%s", t.Type, childType)) -} +type ResourceType = resource.ResourceType // NewResourceType creates an instance of ResourceType using a provider namespace // such as "Microsoft.Network" and type such as "virtualNetworks/subnets". func NewResourceType(providerNamespace, typeName string) ResourceType { - return ResourceType{ - Namespace: providerNamespace, - Type: typeName, - Types: splitStringAndOmitEmpty(typeName, "/"), - stringValue: fmt.Sprintf("%s/%s", providerNamespace, typeName), - } + return resource.NewResourceType(providerNamespace, typeName) } // ParseResourceType parses the ResourceType from a resource type string (e.g. Microsoft.Network/virtualNetworks/subsets) // or a resource identifier string. // e.g. /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myRg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/mySubnet) func ParseResourceType(resourceIDOrType string) (ResourceType, error) { - // split the path into segments - parts := splitStringAndOmitEmpty(resourceIDOrType, "/") - - // There must be at least a namespace and type name - if len(parts) < 1 { - return ResourceType{}, fmt.Errorf("invalid resource ID or type: %s", resourceIDOrType) - } - - // if the type is just subscriptions, it is a built-in type in the Microsoft.Resources namespace - if len(parts) == 1 { - // Simple resource type - return NewResourceType(builtInResourceNamespace, parts[0]), nil - } else if strings.Contains(parts[0], ".") { - // Handle resource types (Microsoft.Compute/virtualMachines, Microsoft.Network/virtualNetworks/subnets) - // it is a full type name - return NewResourceType(parts[0], strings.Join(parts[1:], "/")), nil - } else { - // Check if ResourceID - id, err := ParseResourceID(resourceIDOrType) - if err != nil { - return ResourceType{}, err - } - return NewResourceType(id.ResourceType.Namespace, id.ResourceType.Type), nil - } -} - -func (t ResourceType) lastType() string { - return t.Types[len(t.Types)-1] + return resource.ParseResourceType(resourceIDOrType) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/pipeline.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/pipeline.go index 556484c62..266c74b17 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/pipeline.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/pipeline.go @@ -11,7 +11,6 @@ import ( "reflect" "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" azpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" @@ -21,16 +20,19 @@ import ( // NewPipeline creates a pipeline from connection options. Policies from ClientOptions are // placed after policies from PipelineOptions. The telemetry policy, when enabled, will // use the specified module and version info. -func NewPipeline(module, version string, cred azcore.TokenCredential, plOpts azruntime.PipelineOptions, options *arm.ClientOptions) (azruntime.Pipeline, error) { +func NewPipeline(module, version string, cred azcore.TokenCredential, plOpts azruntime.PipelineOptions, options *armpolicy.ClientOptions) (azruntime.Pipeline, error) { if options == nil { - options = &arm.ClientOptions{} + options = &armpolicy.ClientOptions{} } conf, err := getConfiguration(&options.ClientOptions) if err != nil { return azruntime.Pipeline{}, err } - authPolicy := NewBearerTokenPolicy(cred, &armpolicy.BearerTokenOptions{Scopes: []string{conf.Audience + "/.default"}}) - perRetry := make([]azpolicy.Policy, 0, len(plOpts.PerRetry)+1) + authPolicy := NewBearerTokenPolicy(cred, &armpolicy.BearerTokenOptions{ + AuxiliaryTenants: options.AuxiliaryTenants, + Scopes: []string{conf.Audience + "/.default"}, + }) + perRetry := make([]azpolicy.Policy, len(plOpts.PerRetry), len(plOpts.PerRetry)+1) copy(perRetry, plOpts.PerRetry) plOpts.PerRetry = append(perRetry, authPolicy) if !options.DisableRPRegistration { @@ -39,7 +41,7 @@ func NewPipeline(module, version string, cred azcore.TokenCredential, plOpts azr if err != nil { return azruntime.Pipeline{}, err } - perCall := make([]azpolicy.Policy, 0, len(plOpts.PerCall)+1) + perCall := make([]azpolicy.Policy, len(plOpts.PerCall), len(plOpts.PerCall)+1) copy(perCall, plOpts.PerCall) plOpts.PerCall = append(perCall, regPolicy) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_bearer_token.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_bearer_token.go index 10a3606e9..07f15991e 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_bearer_token.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_bearer_token.go @@ -14,9 +14,13 @@ import ( armpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" azpolicy "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + azruntime "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/internal/temporal" ) +const headerAuxiliaryAuthorization = "x-ms-authorization-auxiliary" + +// acquiringResourceState holds data for an auxiliary token request type acquiringResourceState struct { ctx context.Context p *BearerTokenPolicy @@ -26,7 +30,10 @@ type acquiringResourceState struct { // acquire acquires or updates the resource; only one // thread/goroutine at a time ever calls this function func acquire(state acquiringResourceState) (newResource azcore.AccessToken, newExpiration time.Time, err error) { - tk, err := state.p.cred.GetToken(state.ctx, azpolicy.TokenRequestOptions{Scopes: state.p.options.Scopes}) + tk, err := state.p.cred.GetToken(state.ctx, azpolicy.TokenRequestOptions{ + Scopes: state.p.scopes, + TenantID: state.tenant, + }) if err != nil { return azcore.AccessToken{}, time.Time{}, err } @@ -35,13 +42,10 @@ func acquire(state acquiringResourceState) (newResource azcore.AccessToken, newE // BearerTokenPolicy authorizes requests with bearer tokens acquired from a TokenCredential. type BearerTokenPolicy struct { - // mainResource is the resource to be retreived using the tenant specified in the credential - mainResource *temporal.Resource[azcore.AccessToken, acquiringResourceState] - // auxResources are additional resources that are required for cross-tenant applications auxResources map[string]*temporal.Resource[azcore.AccessToken, acquiringResourceState] - // the following fields are read-only - cred azcore.TokenCredential - options armpolicy.BearerTokenOptions + btp *azruntime.BearerTokenPolicy + cred azcore.TokenCredential + scopes []string } // NewBearerTokenPolicy creates a policy object that authorizes requests with bearer tokens. @@ -51,36 +55,45 @@ func NewBearerTokenPolicy(cred azcore.TokenCredential, opts *armpolicy.BearerTok if opts == nil { opts = &armpolicy.BearerTokenOptions{} } - p := &BearerTokenPolicy{ - cred: cred, - options: *opts, - mainResource: temporal.NewResource(acquire), + p := &BearerTokenPolicy{cred: cred} + p.auxResources = make(map[string]*temporal.Resource[azcore.AccessToken, acquiringResourceState], len(opts.AuxiliaryTenants)) + for _, t := range opts.AuxiliaryTenants { + p.auxResources[t] = temporal.NewResource(acquire) } + p.scopes = make([]string, len(opts.Scopes)) + copy(p.scopes, opts.Scopes) + p.btp = azruntime.NewBearerTokenPolicy(cred, opts.Scopes, &azpolicy.BearerTokenOptions{ + AuthorizationHandler: azpolicy.AuthorizationHandler{OnRequest: p.onRequest}, + }) return p } -// Do authorizes a request with a bearer token -func (b *BearerTokenPolicy) Do(req *azpolicy.Request) (*http.Response, error) { +// onRequest authorizes requests with one or more bearer tokens +func (b *BearerTokenPolicy) onRequest(req *azpolicy.Request, authNZ func(azpolicy.TokenRequestOptions) error) error { + // authorize the request with a token for the primary tenant + err := authNZ(azpolicy.TokenRequestOptions{Scopes: b.scopes}) + if err != nil || len(b.auxResources) == 0 { + return err + } + // add tokens for auxiliary tenants as := acquiringResourceState{ ctx: req.Raw().Context(), p: b, } - tk, err := b.mainResource.Get(as) - if err != nil { - return nil, err - } - req.Raw().Header.Set(shared.HeaderAuthorization, shared.BearerTokenPrefix+tk.Token) - auxTokens := []string{} + auxTokens := make([]string, 0, len(b.auxResources)) for tenant, er := range b.auxResources { as.tenant = tenant auxTk, err := er.Get(as) if err != nil { - return nil, err + return err } auxTokens = append(auxTokens, fmt.Sprintf("%s%s", shared.BearerTokenPrefix, auxTk.Token)) } - if len(auxTokens) > 0 { - req.Raw().Header.Set(shared.HeaderAuxiliaryAuthorization, strings.Join(auxTokens, ", ")) - } - return req.Next() + req.Raw().Header.Set(headerAuxiliaryAuthorization, strings.Join(auxTokens, ", ")) + return nil +} + +// Do authorizes a request with a bearer token +func (b *BearerTokenPolicy) Do(req *azpolicy.Request) (*http.Response, error) { + return b.btp.Do(req) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_register_rp.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_register_rp.go index 4590d39be..c3f5eeafe 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_register_rp.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/policy_register_rp.go @@ -80,7 +80,6 @@ func (r *rpRegistrationPolicy) Do(req *azpolicy.Request) (*http.Response, error) // policy is disabled return req.Next() } - const unregisteredRPCode = "MissingSubscriptionRegistration" const registeredState = "Registered" var rp string var resp *http.Response @@ -97,10 +96,13 @@ func (r *rpRegistrationPolicy) Do(req *azpolicy.Request) (*http.Response, error) return resp, err } if reqErr.ServiceError == nil { - return resp, errors.New("missing error information") + // missing service error info. just return the response + // to the caller so its error unmarshalling will kick in + return resp, err } - if !strings.EqualFold(reqErr.ServiceError.Code, unregisteredRPCode) { - // not a 409 due to unregistered RP + if !isUnregisteredRPCode(reqErr.ServiceError.Code) { + // not a 409 due to unregistered RP. just return the response + // to the caller so its error unmarshalling will kick in return resp, err } // RP needs to be registered. start by getting the subscription ID from the original request @@ -170,6 +172,21 @@ func (r *rpRegistrationPolicy) Do(req *azpolicy.Request) (*http.Response, error) return resp, fmt.Errorf("exceeded attempts to register %s", rp) } +var unregisteredRPCodes = []string{ + "MissingSubscriptionRegistration", + "MissingRegistrationForResourceProvider", + "Subscription Not Registered", +} + +func isUnregisteredRPCode(errorCode string) bool { + for _, code := range unregisteredRPCodes { + if strings.EqualFold(errorCode, code) { + return true + } + } + return false +} + func getSubscription(path string) (string, error) { parts := strings.Split(path, "/") for i, v := range parts { diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/arm.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/runtime.go similarity index 97% rename from vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/arm.go rename to vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/runtime.go index 3a0cb6442..1400d4379 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/arm.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/runtime/runtime.go @@ -4,7 +4,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package arm +package runtime import "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/core.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/core.go index f9fb23422..27231ad92 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/core.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/core.go @@ -7,25 +7,20 @@ package azcore import ( - "context" "reflect" - "time" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing" ) // AccessToken represents an Azure service bearer access token with expiry information. -type AccessToken struct { - Token string - ExpiresOn time.Time -} +type AccessToken = exported.AccessToken // TokenCredential represents a credential capable of providing an OAuth token. -type TokenCredential interface { - // GetToken requests an access token for the specified set of scopes. - GetToken(ctx context.Context, options policy.TokenRequestOptions) (AccessToken, error) -} +type TokenCredential = exported.TokenCredential // holds sentinel values used to send nulls var nullables map[reflect.Type]interface{} = map[reflect.Type]interface{}{} @@ -73,3 +68,47 @@ func IsNullValue[T any](v T) bool { // ClientOptions contains configuration settings for a client's pipeline. type ClientOptions = policy.ClientOptions + +// Client is a basic HTTP client. It consists of a pipeline and tracing provider. +type Client struct { + pl runtime.Pipeline + tr tracing.Tracer +} + +// NewClient creates a new Client instance with the provided values. +// - clientName - the fully qualified name of the client ("module/package.Client"); this is used by the telemetry policy and tracing provider. +// if module and package are the same value, the "module/" prefix can be omitted. +// - moduleVersion - the semantic version of the containing module; used by the telemetry policy +// - plOpts - pipeline configuration options; can be the zero-value +// - options - optional client configurations; pass nil to accept the default values +func NewClient(clientName, moduleVersion string, plOpts runtime.PipelineOptions, options *ClientOptions) (*Client, error) { + mod, client, err := shared.ExtractModuleName(clientName) + if err != nil { + return nil, err + } + + if options == nil { + options = &ClientOptions{} + } + + if !options.Telemetry.Disabled { + if err := shared.ValidateModVer(moduleVersion); err != nil { + return nil, err + } + } + + pl := runtime.NewPipeline(mod, moduleVersion, plOpts, options) + + tr := options.TracingProvider.NewTracer(client, moduleVersion) + return &Client{pl: pl, tr: tr}, nil +} + +// Pipeline returns the pipeline for this client. +func (c *Client) Pipeline() runtime.Pipeline { + return c.pl +} + +// Tracer returns the tracer for this client. +func (c *Client) Tracer() tracing.Tracer { + return c.tr +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go index 6e029d493..a1236b362 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/exported.go @@ -7,10 +7,10 @@ package exported import ( + "context" "io" "net/http" - - "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "time" ) type nopCloser struct { @@ -41,20 +41,27 @@ func HasStatusCode(resp *http.Response, statusCodes ...int) bool { return false } -// Payload reads and returns the response body or an error. -// On a successful read, the response body is cached. -// Subsequent reads will access the cached value. -// Exported as runtime.Payload(). -func Payload(resp *http.Response) ([]byte, error) { - // r.Body won't be a nopClosingBytesReader if downloading was skipped - if buf, ok := resp.Body.(*shared.NopClosingBytesReader); ok { - return buf.Bytes(), nil - } - bytesBody, err := io.ReadAll(resp.Body) - resp.Body.Close() - if err != nil { - return nil, err - } - resp.Body = shared.NewNopClosingBytesReader(bytesBody) - return bytesBody, nil +// AccessToken represents an Azure service bearer access token with expiry information. +// Exported as azcore.AccessToken. +type AccessToken struct { + Token string + ExpiresOn time.Time +} + +// TokenRequestOptions contain specific parameter that may be used by credentials types when attempting to get a token. +// Exported as policy.TokenRequestOptions. +type TokenRequestOptions struct { + // Scopes contains the list of permission scopes required for the token. + Scopes []string + + // TenantID identifies the tenant from which to request the token. azidentity credentials authenticate in + // their configured default tenants when this field isn't set. + TenantID string +} + +// TokenCredential represents a credential capable of providing an OAuth token. +// Exported as azcore.TokenCredential. +type TokenCredential interface { + // GetToken requests an access token for the specified set of scopes. + GetToken(ctx context.Context, options TokenRequestOptions) (AccessToken, error) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/request.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/request.go index 4aeec1589..fa99d1b7e 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/request.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/request.go @@ -100,32 +100,47 @@ func (req *Request) OperationValue(value interface{}) bool { return req.values.get(value) } -// SetBody sets the specified ReadSeekCloser as the HTTP request body. +// SetBody sets the specified ReadSeekCloser as the HTTP request body, and sets Content-Type and Content-Length +// accordingly. If the ReadSeekCloser is nil or empty, Content-Length won't be set. If contentType is "", +// Content-Type won't be set. +// Use streaming.NopCloser to turn an io.ReadSeeker into an io.ReadSeekCloser. func (req *Request) SetBody(body io.ReadSeekCloser, contentType string) error { - // Set the body and content length. - size, err := body.Seek(0, io.SeekEnd) // Seek to the end to get the stream's size - if err != nil { - return err + var err error + var size int64 + if body != nil { + size, err = body.Seek(0, io.SeekEnd) // Seek to the end to get the stream's size + if err != nil { + return err + } } if size == 0 { - body.Close() - return nil - } - _, err = body.Seek(0, io.SeekStart) - if err != nil { - return err + // treat an empty stream the same as a nil one: assign req a nil body + body = nil + // RFC 9110 specifies a client shouldn't set Content-Length on a request containing no content + // (Del is a no-op when the header has no value) + req.req.Header.Del(shared.HeaderContentLength) + } else { + _, err = body.Seek(0, io.SeekStart) + if err != nil { + return err + } + req.req.Header.Set(shared.HeaderContentLength, strconv.FormatInt(size, 10)) + req.Raw().GetBody = func() (io.ReadCloser, error) { + _, err := body.Seek(0, io.SeekStart) // Seek back to the beginning of the stream + return body, err + } } - req.Raw().GetBody = func() (io.ReadCloser, error) { - _, err := body.Seek(0, io.SeekStart) // Seek back to the beginning of the stream - return body, err - } - // keep a copy of the original body. this is to handle cases + // keep a copy of the body argument. this is to handle cases // where req.Body is replaced, e.g. httputil.DumpRequest and friends. req.body = body req.req.Body = body req.req.ContentLength = size - req.req.Header.Set(shared.HeaderContentType, contentType) - req.req.Header.Set(shared.HeaderContentLength, strconv.FormatInt(size, 10)) + if contentType == "" { + // Del is a no-op when the header has no value + req.req.Header.Del(shared.HeaderContentType) + } else { + req.req.Header.Set(shared.HeaderContentType, contentType) + } return nil } @@ -154,3 +169,14 @@ func (req *Request) Clone(ctx context.Context) *Request { r2.req = req.req.Clone(ctx) return &r2 } + +// not exported but dependent on Request + +// PolicyFunc is a type that implements the Policy interface. +// Use this type when implementing a stateless policy as a first-class function. +type PolicyFunc func(*Request) (*http.Response, error) + +// Do implements the Policy interface on policyFunc. +func (pf PolicyFunc) Do(req *Request) (*http.Response, error) { + return pf(req) +} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/response_error.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/response_error.go index 3db6acc83..7df2f88c1 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/response_error.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported/response_error.go @@ -12,6 +12,8 @@ import ( "fmt" "net/http" "regexp" + + "github.com/Azure/azure-sdk-for-go/sdk/internal/exported" ) // NewResponseError creates a new *ResponseError from the provided HTTP response. @@ -29,7 +31,7 @@ func NewResponseError(resp *http.Response) error { } // if we didn't get x-ms-error-code, check in the response body - body, err := Payload(resp) + body, err := exported.Payload(resp, nil) if err != nil { return err } @@ -121,7 +123,7 @@ func (e *ResponseError) Error() string { fmt.Fprintln(msg, "ERROR CODE UNAVAILABLE") } fmt.Fprintln(msg, "--------------------------------------------------------------------------------") - body, err := Payload(e.RawResponse) + body, err := exported.Payload(e.RawResponse, nil) if err != nil { // this really shouldn't fail at this point as the response // body is already cached (it was read in NewResponseError) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async/async.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async/async.go index d34f161c7..b05bd8b38 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async/async.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/async/async.go @@ -16,6 +16,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "github.com/Azure/azure-sdk-for-go/sdk/internal/poller" ) // see https://github.com/Azure/azure-resource-manager-rpc/blob/master/v1.0/async-api-reference.md @@ -68,15 +69,15 @@ func New[T any](pl exported.Pipeline, resp *http.Response, finalState pollers.Fi if asyncURL == "" { return nil, errors.New("response is missing Azure-AsyncOperation header") } - if !pollers.IsValidURL(asyncURL) { + if !poller.IsValidURL(asyncURL) { return nil, fmt.Errorf("invalid polling URL %s", asyncURL) } // check for provisioning state. if the operation is a RELO // and terminates synchronously this will prevent extra polling. // it's ok if there's no provisioning state. - state, _ := pollers.GetProvisioningState(resp) + state, _ := poller.GetProvisioningState(resp) if state == "" { - state = pollers.StatusInProgress + state = poller.StatusInProgress } p := &Poller[T]{ pl: pl, @@ -93,17 +94,17 @@ func New[T any](pl exported.Pipeline, resp *http.Response, finalState pollers.Fi // Done returns true if the LRO is in a terminal state. func (p *Poller[T]) Done() bool { - return pollers.IsTerminalState(p.CurState) + return poller.IsTerminalState(p.CurState) } // Poll retrieves the current state of the LRO. func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { err := pollers.PollHelper(ctx, p.AsyncURL, p.pl, func(resp *http.Response) (string, error) { - if !pollers.StatusCodeValid(resp) { + if !poller.StatusCodeValid(resp) { p.resp = resp return "", exported.NewResponseError(resp) } - state, err := pollers.GetStatus(resp) + state, err := poller.GetStatus(resp) if err != nil { return "", err } else if state == "" { @@ -122,7 +123,7 @@ func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { func (p *Poller[T]) Result(ctx context.Context, out *T) error { if p.resp.StatusCode == http.StatusNoContent { return nil - } else if pollers.Failed(p.CurState) { + } else if poller.Failed(p.CurState) { return exported.NewResponseError(p.resp) } var req *exported.Request @@ -154,5 +155,5 @@ func (p *Poller[T]) Result(ctx context.Context, out *T) error { p.resp = resp } - return pollers.ResultHelper(p.resp, pollers.Failed(p.CurState), out) + return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), out) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body/body.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body/body.go index 7efdd8a0d..2bb9e105b 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body/body.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/body/body.go @@ -14,6 +14,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers" + "github.com/Azure/azure-sdk-for-go/sdk/internal/poller" ) // Kind is the identifier of this type in a resume token. @@ -72,9 +73,9 @@ func New[T any](pl exported.Pipeline, resp *http.Response) (*Poller[T], error) { } // default initial state to InProgress. depending on the HTTP // status code and provisioning state, we might change the value. - curState := pollers.StatusInProgress - provState, err := pollers.GetProvisioningState(resp) - if err != nil && !errors.Is(err, pollers.ErrNoBody) { + curState := poller.StatusInProgress + provState, err := poller.GetProvisioningState(resp) + if err != nil && !errors.Is(err, poller.ErrNoBody) { return nil, err } if resp.StatusCode == http.StatusCreated && provState != "" { @@ -85,37 +86,37 @@ func New[T any](pl exported.Pipeline, resp *http.Response) (*Poller[T], error) { curState = provState } else if provState == "" { // for a 200, absense of provisioning state indicates success - curState = pollers.StatusSucceeded + curState = poller.StatusSucceeded } } else if resp.StatusCode == http.StatusNoContent { - curState = pollers.StatusSucceeded + curState = poller.StatusSucceeded } p.CurState = curState return p, nil } func (p *Poller[T]) Done() bool { - return pollers.IsTerminalState(p.CurState) + return poller.IsTerminalState(p.CurState) } func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { err := pollers.PollHelper(ctx, p.PollURL, p.pl, func(resp *http.Response) (string, error) { - if !pollers.StatusCodeValid(resp) { + if !poller.StatusCodeValid(resp) { p.resp = resp return "", exported.NewResponseError(resp) } if resp.StatusCode == http.StatusNoContent { p.resp = resp - p.CurState = pollers.StatusSucceeded + p.CurState = poller.StatusSucceeded return p.CurState, nil } - state, err := pollers.GetProvisioningState(resp) - if errors.Is(err, pollers.ErrNoBody) { + state, err := poller.GetProvisioningState(resp) + if errors.Is(err, poller.ErrNoBody) { // a missing response body in non-204 case is an error return "", err } else if state == "" { // a response body without provisioning state is considered terminal success - state = pollers.StatusSucceeded + state = poller.StatusSucceeded } else if err != nil { return "", err } @@ -130,5 +131,5 @@ func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { } func (p *Poller[T]) Result(ctx context.Context, out *T) error { - return pollers.ResultHelper(p.resp, pollers.Failed(p.CurState), out) + return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), out) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc/loc.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc/loc.go index 276685da4..d6be89876 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc/loc.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc/loc.go @@ -16,6 +16,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "github.com/Azure/azure-sdk-for-go/sdk/internal/poller" ) // Kind is the identifier of this type in a resume token. @@ -61,15 +62,15 @@ func New[T any](pl exported.Pipeline, resp *http.Response) (*Poller[T], error) { if locURL == "" { return nil, errors.New("response is missing Location header") } - if !pollers.IsValidURL(locURL) { + if !poller.IsValidURL(locURL) { return nil, fmt.Errorf("invalid polling URL %s", locURL) } // check for provisioning state. if the operation is a RELO // and terminates synchronously this will prevent extra polling. // it's ok if there's no provisioning state. - state, _ := pollers.GetProvisioningState(resp) + state, _ := poller.GetProvisioningState(resp) if state == "" { - state = pollers.StatusInProgress + state = poller.StatusInProgress } return &Poller[T]{ pl: pl, @@ -81,7 +82,7 @@ func New[T any](pl exported.Pipeline, resp *http.Response) (*Poller[T], error) { } func (p *Poller[T]) Done() bool { - return pollers.IsTerminalState(p.CurState) + return poller.IsTerminalState(p.CurState) } func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { @@ -93,17 +94,17 @@ func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { // if provisioning state is available, use that. this is only // for some ARM LRO scenarios (e.g. DELETE with a Location header) // so if it's missing then use HTTP status code. - provState, _ := pollers.GetProvisioningState(resp) + provState, _ := poller.GetProvisioningState(resp) p.resp = resp if provState != "" { p.CurState = provState } else if resp.StatusCode == http.StatusAccepted { - p.CurState = pollers.StatusInProgress + p.CurState = poller.StatusInProgress } else if resp.StatusCode > 199 && resp.StatusCode < 300 { // any 2xx other than a 202 indicates success - p.CurState = pollers.StatusSucceeded + p.CurState = poller.StatusSucceeded } else { - p.CurState = pollers.StatusFailed + p.CurState = poller.StatusFailed } return p.CurState, nil }) @@ -114,5 +115,5 @@ func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { } func (p *Poller[T]) Result(ctx context.Context, out *T) error { - return pollers.ResultHelper(p.resp, pollers.Failed(p.CurState), out) + return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), out) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op/op.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op/op.go index c3c648266..1bc7ad0ac 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op/op.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op/op.go @@ -16,6 +16,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "github.com/Azure/azure-sdk-for-go/sdk/internal/poller" ) // Applicable returns true if the LRO is using Operation-Location. @@ -54,19 +55,19 @@ func New[T any](pl exported.Pipeline, resp *http.Response, finalState pollers.Fi if opURL == "" { return nil, errors.New("response is missing Operation-Location header") } - if !pollers.IsValidURL(opURL) { + if !poller.IsValidURL(opURL) { return nil, fmt.Errorf("invalid Operation-Location URL %s", opURL) } locURL := resp.Header.Get(shared.HeaderLocation) // Location header is optional - if locURL != "" && !pollers.IsValidURL(locURL) { + if locURL != "" && !poller.IsValidURL(locURL) { return nil, fmt.Errorf("invalid Location URL %s", locURL) } // default initial state to InProgress. if the // service sent us a status then use that instead. - curState := pollers.StatusInProgress - status, err := pollers.GetStatus(resp) - if err != nil && !errors.Is(err, pollers.ErrNoBody) { + curState := poller.StatusInProgress + status, err := poller.GetStatus(resp) + if err != nil && !errors.Is(err, poller.ErrNoBody) { return nil, err } if status != "" { @@ -86,16 +87,16 @@ func New[T any](pl exported.Pipeline, resp *http.Response, finalState pollers.Fi } func (p *Poller[T]) Done() bool { - return pollers.IsTerminalState(p.CurState) + return poller.IsTerminalState(p.CurState) } func (p *Poller[T]) Poll(ctx context.Context) (*http.Response, error) { err := pollers.PollHelper(ctx, p.OpLocURL, p.pl, func(resp *http.Response) (string, error) { - if !pollers.StatusCodeValid(resp) { + if !poller.StatusCodeValid(resp) { p.resp = resp return "", exported.NewResponseError(resp) } - state, err := pollers.GetStatus(resp) + state, err := poller.GetStatus(resp) if err != nil { return "", err } else if state == "" { @@ -118,7 +119,7 @@ func (p *Poller[T]) Result(ctx context.Context, out *T) error { req, err = exported.NewRequest(ctx, http.MethodGet, p.LocURL) } else if p.FinalState == pollers.FinalStateViaOpLocation && p.Method == http.MethodPost { // no final GET required, terminal response should have it - } else if rl, rlErr := pollers.GetResourceLocation(p.resp); rlErr != nil && !errors.Is(rlErr, pollers.ErrNoBody) { + } else if rl, rlErr := poller.GetResourceLocation(p.resp); rlErr != nil && !errors.Is(rlErr, poller.ErrNoBody) { return rlErr } else if rl != "" { req, err = exported.NewRequest(ctx, http.MethodGet, rl) @@ -140,5 +141,5 @@ func (p *Poller[T]) Result(ctx context.Context, out *T) error { p.resp = resp } - return pollers.ResultHelper(p.resp, pollers.Failed(p.CurState), out) + return pollers.ResultHelper(p.resp, poller.Failed(p.CurState), out) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/util.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/util.go index 17ab7dadc..d8d86a46c 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/util.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/util.go @@ -12,49 +12,15 @@ import ( "errors" "fmt" "net/http" - "net/url" "reflect" - "strings" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" + azexported "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/log" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "github.com/Azure/azure-sdk-for-go/sdk/internal/exported" + "github.com/Azure/azure-sdk-for-go/sdk/internal/poller" ) -// the well-known set of LRO status/provisioning state values. -const ( - StatusSucceeded = "Succeeded" - StatusCanceled = "Canceled" - StatusFailed = "Failed" - StatusInProgress = "InProgress" -) - -// IsTerminalState returns true if the LRO's state is terminal. -func IsTerminalState(s string) bool { - return strings.EqualFold(s, StatusSucceeded) || strings.EqualFold(s, StatusFailed) || strings.EqualFold(s, StatusCanceled) -} - -// Failed returns true if the LRO's state is terminal failure. -func Failed(s string) bool { - return strings.EqualFold(s, StatusFailed) || strings.EqualFold(s, StatusCanceled) -} - -// Succeeded returns true if the LRO's state is terminal success. -func Succeeded(s string) bool { - return strings.EqualFold(s, StatusSucceeded) -} - -// returns true if the LRO response contains a valid HTTP status code -func StatusCodeValid(resp *http.Response) bool { - return exported.HasStatusCode(resp, http.StatusOK, http.StatusAccepted, http.StatusCreated, http.StatusNoContent) -} - -// IsValidURL verifies that the URL is valid and absolute. -func IsValidURL(s string) bool { - u, err := url.Parse(s) - return err == nil && u.IsAbs() -} - // getTokenTypeName creates a type name from the type parameter T. func getTokenTypeName[T any]() (string, error) { tt := shared.TypeOfT[T]() @@ -130,102 +96,6 @@ func IsTokenValid[T any](token string) error { return nil } -// ErrNoBody is returned if the response didn't contain a body. -var ErrNoBody = errors.New("the response did not contain a body") - -// GetJSON reads the response body into a raw JSON object. -// It returns ErrNoBody if there was no content. -func GetJSON(resp *http.Response) (map[string]interface{}, error) { - body, err := exported.Payload(resp) - if err != nil { - return nil, err - } - if len(body) == 0 { - return nil, ErrNoBody - } - // unmarshall the body to get the value - var jsonBody map[string]interface{} - if err = json.Unmarshal(body, &jsonBody); err != nil { - return nil, err - } - return jsonBody, nil -} - -// provisioningState returns the provisioning state from the response or the empty string. -func provisioningState(jsonBody map[string]interface{}) string { - jsonProps, ok := jsonBody["properties"] - if !ok { - return "" - } - props, ok := jsonProps.(map[string]interface{}) - if !ok { - return "" - } - rawPs, ok := props["provisioningState"] - if !ok { - return "" - } - ps, ok := rawPs.(string) - if !ok { - return "" - } - return ps -} - -// status returns the status from the response or the empty string. -func status(jsonBody map[string]interface{}) string { - rawStatus, ok := jsonBody["status"] - if !ok { - return "" - } - status, ok := rawStatus.(string) - if !ok { - return "" - } - return status -} - -// GetStatus returns the LRO's status from the response body. -// Typically used for Azure-AsyncOperation flows. -// If there is no status in the response body the empty string is returned. -func GetStatus(resp *http.Response) (string, error) { - jsonBody, err := GetJSON(resp) - if err != nil { - return "", err - } - return status(jsonBody), nil -} - -// GetProvisioningState returns the LRO's state from the response body. -// If there is no state in the response body the empty string is returned. -func GetProvisioningState(resp *http.Response) (string, error) { - jsonBody, err := GetJSON(resp) - if err != nil { - return "", err - } - return provisioningState(jsonBody), nil -} - -// GetResourceLocation returns the LRO's resourceLocation value from the response body. -// Typically used for Operation-Location flows. -// If there is no resourceLocation in the response body the empty string is returned. -func GetResourceLocation(resp *http.Response) (string, error) { - jsonBody, err := GetJSON(resp) - if err != nil { - return "", err - } - v, ok := jsonBody["resourceLocation"] - if !ok { - // it might be ok if the field doesn't exist, the caller must make that determination - return "", nil - } - vv, ok := v.(string) - if !ok { - return "", fmt.Errorf("the resourceLocation value %v was not in string format", v) - } - return vv, nil -} - // used if the operation synchronously completed type NopPoller[T any] struct { resp *http.Response @@ -239,7 +109,7 @@ func NewNopPoller[T any](resp *http.Response) (*NopPoller[T], error) { if resp.StatusCode == http.StatusNoContent { return np, nil } - payload, err := exported.Payload(resp) + payload, err := exported.Payload(resp, nil) if err != nil { return nil, err } @@ -269,8 +139,8 @@ func (p *NopPoller[T]) Result(ctx context.Context, out *T) error { // If the request fails, the update func is not called. // The update func returns the state of the operation for logging purposes or an error // if it fails to extract the required state from the response. -func PollHelper(ctx context.Context, endpoint string, pl exported.Pipeline, update func(resp *http.Response) (string, error)) error { - req, err := exported.NewRequest(ctx, http.MethodGet, endpoint) +func PollHelper(ctx context.Context, endpoint string, pl azexported.Pipeline, update func(resp *http.Response) (string, error)) error { + req, err := azexported.NewRequest(ctx, http.MethodGet, endpoint) if err != nil { return err } @@ -296,13 +166,13 @@ func ResultHelper[T any](resp *http.Response, failed bool, out *T) error { } defer resp.Body.Close() - if !StatusCodeValid(resp) || failed { + if !poller.StatusCodeValid(resp) || failed { // the LRO failed. unmarshall the error and update state - return exported.NewResponseError(resp) + return azexported.NewResponseError(resp) } // success case - payload, err := exported.Payload(resp) + payload, err := exported.Payload(resp, nil) if err != nil { return err } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go index 75d241c5b..269a831ed 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go @@ -21,6 +21,8 @@ const ( HeaderOperationLocation = "Operation-Location" HeaderRetryAfter = "Retry-After" HeaderUserAgent = "User-Agent" + HeaderWWWAuthenticate = "WWW-Authenticate" + HeaderXMSClientRequestID = "x-ms-client-request-id" ) const BearerTokenPrefix = "Bearer " @@ -30,5 +32,5 @@ const ( Module = "azcore" // Version is the semantic version (see http://semver.org) of this module. - Version = "v1.2.0" + Version = "v1.6.1" ) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/shared.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/shared.go index 96eef2956..db0aaa7cb 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/shared.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/shared.go @@ -8,10 +8,10 @@ package shared import ( "context" - "errors" - "io" + "fmt" "net/http" "reflect" + "regexp" "strconv" "time" ) @@ -61,75 +61,43 @@ func TypeOfT[T any]() reflect.Type { return reflect.TypeOf((*T)(nil)).Elem() } -// BytesSetter abstracts replacing a byte slice on some type. -type BytesSetter interface { - Set(b []byte) -} - -// NewNopClosingBytesReader creates a new *NopClosingBytesReader for the specified slice. -func NewNopClosingBytesReader(data []byte) *NopClosingBytesReader { - return &NopClosingBytesReader{s: data} -} - -// NopClosingBytesReader is an io.ReadSeekCloser around a byte slice. -// It also provides direct access to the byte slice to avoid rereading. -type NopClosingBytesReader struct { - s []byte - i int64 -} +// TransportFunc is a helper to use a first-class func to satisfy the Transporter interface. +type TransportFunc func(*http.Request) (*http.Response, error) -// Bytes returns the underlying byte slice. -func (r *NopClosingBytesReader) Bytes() []byte { - return r.s +// Do implements the Transporter interface for the TransportFunc type. +func (pf TransportFunc) Do(req *http.Request) (*http.Response, error) { + return pf(req) } -// Close implements the io.Closer interface. -func (*NopClosingBytesReader) Close() error { +// ValidateModVer verifies that moduleVersion is a valid semver 2.0 string. +func ValidateModVer(moduleVersion string) error { + modVerRegx := regexp.MustCompile(`^v\d+\.\d+\.\d+(?:-[a-zA-Z0-9_.-]+)?$`) + if !modVerRegx.MatchString(moduleVersion) { + return fmt.Errorf("malformed moduleVersion param value %s", moduleVersion) + } return nil } -// Read implements the io.Reader interface. -func (r *NopClosingBytesReader) Read(b []byte) (n int, err error) { - if r.i >= int64(len(r.s)) { - return 0, io.EOF +// ExtractModuleName returns "module", "package.Client" from "module/package.Client" or +// "package", "package.Client" from "package.Client" when there's no "module/" prefix. +// If clientName is malformed, an error is returned. +func ExtractModuleName(clientName string) (string, string, error) { + // uses unnamed capturing for "module", "package.Client", and "package" + regex, err := regexp.Compile(`^(?:([a-z0-9]+)/)?(([a-z0-9]+)\.(?:[A-Za-z0-9]+))$`) + if err != nil { + return "", "", err } - n = copy(b, r.s[r.i:]) - r.i += int64(n) - return -} -// Set replaces the existing byte slice with the specified byte slice and resets the reader. -func (r *NopClosingBytesReader) Set(b []byte) { - r.s = b - r.i = 0 -} - -// Seek implements the io.Seeker interface. -func (r *NopClosingBytesReader) Seek(offset int64, whence int) (int64, error) { - var i int64 - switch whence { - case io.SeekStart: - i = offset - case io.SeekCurrent: - i = r.i + offset - case io.SeekEnd: - i = int64(len(r.s)) + offset - default: - return 0, errors.New("nopClosingBytesReader: invalid whence") - } - if i < 0 { - return 0, errors.New("nopClosingBytesReader: negative position") + matches := regex.FindStringSubmatch(clientName) + if len(matches) < 4 { + return "", "", fmt.Errorf("malformed clientName %s", clientName) } - r.i = i - return i, nil -} - -var _ BytesSetter = (*NopClosingBytesReader)(nil) - -// TransportFunc is a helper to use a first-class func to satisfy the Transporter interface. -type TransportFunc func(*http.Request) (*http.Response, error) -// Do implements the Transporter interface for the TransportFunc type. -func (pf TransportFunc) Do(req *http.Request) (*http.Response, error) { - return pf(req) + // the first match is the entire string, the second is "module", the third is + // "package.Client" and the fourth is "package". + // if there was no "module/" prefix, the second match will be the empty string + if matches[1] != "" { + return matches[1], matches[2], nil + } + return matches[3], matches[2], nil } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/policy.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/policy.go index 27c302298..b20004783 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/policy.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/policy/policy.go @@ -7,6 +7,7 @@ package policy import ( + "net/http" "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud" @@ -98,7 +99,7 @@ type RetryOptions struct { // MaxRetryDelay specifies the maximum delay allowed before retrying an operation. // Typically the value is greater than or equal to the value specified in RetryDelay. - // The default Value is 120 seconds. A value less than zero means there is no cap. + // The default Value is 60 seconds. A value less than zero means there is no cap. MaxRetryDelay time.Duration // StatusCodes specifies the HTTP status codes that indicate the operation should be retried. @@ -112,6 +113,15 @@ type RetryOptions struct { // Specifying values will replace the default values. // Specifying an empty slice will disable retries for HTTP status codes. StatusCodes []int + + // ShouldRetry evaluates if the retry policy should retry the request. + // When specified, the function overrides comparison against the list of + // HTTP status codes and error checking within the retry policy. Context + // and NonRetriable errors remain evaluated before calling ShouldRetry. + // The *http.Response and error parameters are mutually exclusive, i.e. + // if one is nil, the other is not nil. + // A return value of true means the retry policy should retry. + ShouldRetry func(*http.Response, error) bool } // TelemetryOptions configures the telemetry policy's behavior. @@ -125,12 +135,30 @@ type TelemetryOptions struct { } // TokenRequestOptions contain specific parameter that may be used by credentials types when attempting to get a token. -type TokenRequestOptions struct { - // Scopes contains the list of permission scopes required for the token. - Scopes []string -} +type TokenRequestOptions = exported.TokenRequestOptions // BearerTokenOptions configures the bearer token policy's behavior. type BearerTokenOptions struct { - // placeholder for future options + // AuthorizationHandler allows SDK developers to run client-specific logic when BearerTokenPolicy must authorize a request. + // When this field isn't set, the policy follows its default behavior of authorizing every request with a bearer token from + // its given credential. + AuthorizationHandler AuthorizationHandler +} + +// AuthorizationHandler allows SDK developers to insert custom logic that runs when BearerTokenPolicy must authorize a request. +type AuthorizationHandler struct { + // OnRequest is called each time the policy receives a request. Its func parameter authorizes the request with a token + // from the policy's given credential. Implementations that need to perform I/O should use the Request's context, + // available from Request.Raw().Context(). When OnRequest returns an error, the policy propagates that error and doesn't + // send the request. When OnRequest is nil, the policy follows its default behavior, authorizing the request with a + // token from its credential according to its configuration. + OnRequest func(*Request, func(TokenRequestOptions) error) error + + // OnChallenge is called when the policy receives a 401 response, allowing the AuthorizationHandler to re-authorize the + // request according to an authentication challenge (the Response's WWW-Authenticate header). OnChallenge is responsible + // for parsing parameters from the challenge. Its func parameter will authorize the request with a token from the policy's + // given credential. Implementations that need to perform I/O should use the Request's context, available from + // Request.Raw().Context(). When OnChallenge returns nil, the policy will send the request again. When OnChallenge is nil, + // the policy will return any 401 response to the client. + OnChallenge func(*Request, *http.Response, func(TokenRequestOptions) error) error } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pipeline.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pipeline.go index a2906f51b..9d9288f53 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pipeline.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/pipeline.go @@ -7,8 +7,6 @@ package runtime import ( - "net/http" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" ) @@ -46,7 +44,7 @@ func NewPipeline(module, version string, plOpts PipelineOptions, options *policy } // we put the includeResponsePolicy at the very beginning so that the raw response // is populated with the final response (some policies might mutate the response) - policies := []policy.Policy{policyFunc(includeResponsePolicy)} + policies := []policy.Policy{exported.PolicyFunc(includeResponsePolicy)} if cp.APIVersion != "" { policies = append(policies, newAPIVersionPolicy(cp.APIVersion, &plOpts.APIVersion)) } @@ -59,19 +57,10 @@ func NewPipeline(module, version string, plOpts PipelineOptions, options *policy policies = append(policies, plOpts.PerRetry...) policies = append(policies, cp.PerRetryPolicies...) policies = append(policies, NewLogPolicy(&cp.Logging)) - policies = append(policies, policyFunc(httpHeaderPolicy), policyFunc(bodyDownloadPolicy)) + policies = append(policies, exported.PolicyFunc(httpHeaderPolicy), exported.PolicyFunc(bodyDownloadPolicy)) transport := cp.Transport if transport == nil { transport = defaultHTTPClient } return exported.NewPipeline(transport, policies...) } - -// policyFunc is a type that implements the Policy interface. -// Use this type when implementing a stateless policy as a first-class function. -type policyFunc func(*policy.Request) (*http.Response, error) - -// Do implements the Policy interface on policyFunc. -func (pf policyFunc) Do(req *policy.Request) (*http.Response, error) { - return pf(req) -} diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_bearer_token.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_bearer_token.go index 71e3062be..b61e4c121 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_bearer_token.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_bearer_token.go @@ -4,35 +4,39 @@ package runtime import ( + "errors" "net/http" "time" - "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo" "github.com/Azure/azure-sdk-for-go/sdk/internal/temporal" ) // BearerTokenPolicy authorizes requests with bearer tokens acquired from a TokenCredential. type BearerTokenPolicy struct { // mainResource is the resource to be retreived using the tenant specified in the credential - mainResource *temporal.Resource[azcore.AccessToken, acquiringResourceState] + mainResource *temporal.Resource[exported.AccessToken, acquiringResourceState] // the following fields are read-only - cred azcore.TokenCredential - scopes []string + authzHandler policy.AuthorizationHandler + cred exported.TokenCredential + scopes []string } type acquiringResourceState struct { req *policy.Request p *BearerTokenPolicy + tro policy.TokenRequestOptions } // acquire acquires or updates the resource; only one // thread/goroutine at a time ever calls this function -func acquire(state acquiringResourceState) (newResource azcore.AccessToken, newExpiration time.Time, err error) { - tk, err := state.p.cred.GetToken(state.req.Raw().Context(), policy.TokenRequestOptions{Scopes: state.p.scopes}) +func acquire(state acquiringResourceState) (newResource exported.AccessToken, newExpiration time.Time, err error) { + tk, err := state.p.cred.GetToken(state.req.Raw().Context(), state.tro) if err != nil { - return azcore.AccessToken{}, time.Time{}, err + return exported.AccessToken{}, time.Time{}, err } return tk, tk.ExpiresOn, nil } @@ -41,24 +45,72 @@ func acquire(state acquiringResourceState) (newResource azcore.AccessToken, newE // cred: an azcore.TokenCredential implementation such as a credential object from azidentity // scopes: the list of permission scopes required for the token. // opts: optional settings. Pass nil to accept default values; this is the same as passing a zero-value options. -func NewBearerTokenPolicy(cred azcore.TokenCredential, scopes []string, opts *policy.BearerTokenOptions) *BearerTokenPolicy { +func NewBearerTokenPolicy(cred exported.TokenCredential, scopes []string, opts *policy.BearerTokenOptions) *BearerTokenPolicy { + if opts == nil { + opts = &policy.BearerTokenOptions{} + } return &BearerTokenPolicy{ + authzHandler: opts.AuthorizationHandler, cred: cred, scopes: scopes, mainResource: temporal.NewResource(acquire), } } +// authenticateAndAuthorize returns a function which authorizes req with a token from the policy's credential +func (b *BearerTokenPolicy) authenticateAndAuthorize(req *policy.Request) func(policy.TokenRequestOptions) error { + return func(tro policy.TokenRequestOptions) error { + as := acquiringResourceState{p: b, req: req, tro: tro} + tk, err := b.mainResource.Get(as) + if err != nil { + return err + } + req.Raw().Header.Set(shared.HeaderAuthorization, shared.BearerTokenPrefix+tk.Token) + return nil + } +} + // Do authorizes a request with a bearer token func (b *BearerTokenPolicy) Do(req *policy.Request) (*http.Response, error) { - as := acquiringResourceState{ - p: b, - req: req, + var err error + if b.authzHandler.OnRequest != nil { + err = b.authzHandler.OnRequest(req, b.authenticateAndAuthorize(req)) + } else { + err = b.authenticateAndAuthorize(req)(policy.TokenRequestOptions{Scopes: b.scopes}) } - tk, err := b.mainResource.Get(as) + if err != nil { + return nil, ensureNonRetriable(err) + } + + res, err := req.Next() if err != nil { return nil, err } - req.Raw().Header.Set(shared.HeaderAuthorization, shared.BearerTokenPrefix+tk.Token) - return req.Next() + + if res.StatusCode == http.StatusUnauthorized { + b.mainResource.Expire() + if res.Header.Get("WWW-Authenticate") != "" && b.authzHandler.OnChallenge != nil { + if err = b.authzHandler.OnChallenge(req, res, b.authenticateAndAuthorize(req)); err == nil { + res, err = req.Next() + } + } + } + return res, ensureNonRetriable(err) +} + +func ensureNonRetriable(err error) error { + var nre errorinfo.NonRetriable + if err != nil && !errors.As(err, &nre) { + err = btpError{err} + } + return err } + +// btpError is a wrapper that ensures RetryPolicy doesn't retry requests BearerTokenPolicy couldn't authorize +type btpError struct { + error +} + +func (btpError) NonRetriable() {} + +var _ errorinfo.NonRetriable = (*btpError)(nil) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_body_download.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_body_download.go index 02d621ee8..99dc029f0 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_body_download.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_body_download.go @@ -11,7 +11,6 @@ import ( "net/http" "strings" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo" ) @@ -29,7 +28,7 @@ func bodyDownloadPolicy(req *policy.Request) (*http.Response, error) { } // Either bodyDownloadPolicyOpValues was not specified (so skip is false) // or it was specified and skip is false: don't skip downloading the body - _, err = exported.Payload(resp) + _, err = Payload(resp) if err != nil { return resp, newBodyDownloadError(err, req) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_logging.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_logging.go index 30a02a7a4..8514f57d5 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_logging.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_logging.go @@ -11,6 +11,7 @@ import ( "fmt" "io" "net/http" + "net/url" "sort" "strings" "time" @@ -66,12 +67,7 @@ func NewLogPolicy(o *policy.LogOptions) policy.Policy { allowedHeaders[strings.ToLower(ah)] = struct{}{} } // now do the same thing for query params - allowedQP := map[string]struct{}{ - "api-version": {}, - } - for _, qp := range o.AllowedQueryParams { - allowedQP[strings.ToLower(qp)] = struct{}{} - } + allowedQP := getAllowedQueryParams(o.AllowedQueryParams) return &logPolicy{ includeBody: o.IncludeBody, allowedHeaders: allowedHeaders, @@ -79,6 +75,18 @@ func NewLogPolicy(o *policy.LogOptions) policy.Policy { } } +// getAllowedQueryParams merges the default set of allowed query parameters +// with a custom set (usually comes from client options). +func getAllowedQueryParams(customAllowedQP []string) map[string]struct{} { + allowedQP := map[string]struct{}{ + "api-version": {}, + } + for _, qp := range customAllowedQP { + allowedQP[strings.ToLower(qp)] = struct{}{} + } + return allowedQP +} + // logPolicyOpValues is the struct containing the per-operation values type logPolicyOpValues struct { try int32 @@ -140,20 +148,24 @@ func (p *logPolicy) Do(req *policy.Request) (*http.Response, error) { const redactedValue = "REDACTED" -// writeRequestWithResponse appends a formatted HTTP request into a Buffer. If request and/or err are -// not nil, then these are also written into the Buffer. -func (p *logPolicy) writeRequestWithResponse(b *bytes.Buffer, req *policy.Request, resp *http.Response, err error) { +// getSanitizedURL returns a sanitized string for the provided url.URL +func getSanitizedURL(u url.URL, allowedQueryParams map[string]struct{}) string { // redact applicable query params - cpURL := *req.Raw().URL - qp := cpURL.Query() + qp := u.Query() for k := range qp { - if _, ok := p.allowedQP[strings.ToLower(k)]; !ok { + if _, ok := allowedQueryParams[strings.ToLower(k)]; !ok { qp.Set(k, redactedValue) } } - cpURL.RawQuery = qp.Encode() + u.RawQuery = qp.Encode() + return u.String() +} + +// writeRequestWithResponse appends a formatted HTTP request into a Buffer. If request and/or err are +// not nil, then these are also written into the Buffer. +func (p *logPolicy) writeRequestWithResponse(b *bytes.Buffer, req *policy.Request, resp *http.Response, err error) { // Write the request into the buffer. - fmt.Fprint(b, " "+req.Raw().Method+" "+cpURL.String()+"\n") + fmt.Fprint(b, " "+req.Raw().Method+" "+getSanitizedURL(*req.Raw().URL, p.allowedQP)+"\n") p.writeHeader(b, req.Raw().Header) if resp != nil { fmt.Fprintln(b, " --------------------------------------------------------------------------------") diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_request_id.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_request_id.go index db70955b2..360a7f211 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_request_id.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_request_id.go @@ -9,6 +9,7 @@ package runtime import ( "net/http" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/internal/uuid" ) @@ -21,13 +22,12 @@ func NewRequestIDPolicy() policy.Policy { } func (r *requestIDPolicy) Do(req *policy.Request) (*http.Response, error) { - const requestIdHeader = "x-ms-client-request-id" - if req.Raw().Header.Get(requestIdHeader) == "" { + if req.Raw().Header.Get(shared.HeaderXMSClientRequestID) == "" { id, err := uuid.New() if err != nil { return nil, err } - req.Raw().Header.Set(requestIdHeader, id.String()) + req.Raw().Header.Set(shared.HeaderXMSClientRequestID, id.String()) } return req.Next() diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_retry.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_retry.go index b33002018..e0c5929f3 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_retry.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/policy_retry.go @@ -19,6 +19,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/internal/errorinfo" + "github.com/Azure/azure-sdk-for-go/sdk/internal/exported" ) const ( @@ -124,7 +125,8 @@ func (p *retryPolicy) Do(req *policy.Request) (resp *http.Response, err error) { } if options.TryTimeout == 0 { - resp, err = req.Next() + clone := req.Clone(req.Raw().Context()) + resp, err = clone.Next() } else { // Set the per-try time for this particular retry operation and then Do the operation. tryCtx, tryCancel := context.WithTimeout(req.Raw().Context(), options.TryTimeout) @@ -133,7 +135,7 @@ func (p *retryPolicy) Do(req *policy.Request) (resp *http.Response, err error) { // if the body was already downloaded or there was an error it's safe to cancel the context now if err != nil { tryCancel() - } else if _, ok := resp.Body.(*shared.NopClosingBytesReader); ok { + } else if exported.PayloadDownloaded(resp) { tryCancel() } else { // must cancel the context after the body has been read and closed @@ -146,11 +148,7 @@ func (p *retryPolicy) Do(req *policy.Request) (resp *http.Response, err error) { log.Writef(log.EventRetryPolicy, "error %v", err) } - if err == nil && !HasStatusCode(resp, options.StatusCodes...) { - // if there is no error and the response code isn't in the list of retry codes then we're done. - log.Write(log.EventRetryPolicy, "exit due to non-retriable status code") - return - } else if ctxErr := req.Raw().Context().Err(); ctxErr != nil { + if ctxErr := req.Raw().Context().Err(); ctxErr != nil { // don't retry if the parent context has been cancelled or its deadline exceeded err = ctxErr log.Writef(log.EventRetryPolicy, "abort due to %v", err) @@ -165,6 +163,19 @@ func (p *retryPolicy) Do(req *policy.Request) (resp *http.Response, err error) { return } + if options.ShouldRetry != nil { + // a non-nil ShouldRetry overrides our HTTP status code check + if !options.ShouldRetry(resp, err) { + // predicate says we shouldn't retry + log.Write(log.EventRetryPolicy, "exit due to ShouldRetry") + return + } + } else if err == nil && !HasStatusCode(resp, options.StatusCodes...) { + // if there is no error and the response code isn't in the list of retry codes then we're done. + log.Write(log.EventRetryPolicy, "exit due to non-retriable status code") + return + } + if try == options.MaxRetries+1 { // max number of tries has been reached, don't sleep again log.Writef(log.EventRetryPolicy, "MaxRetries %d exceeded", options.MaxRetries) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go index 14c90fecf..3d029a3d1 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/poller.go @@ -23,6 +23,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/loc" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/pollers/op" "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "github.com/Azure/azure-sdk-for-go/sdk/internal/poller" ) // FinalStateVia is the enumerated type for the possible final-state-via values. @@ -75,7 +76,7 @@ func NewPoller[T any](resp *http.Response, pl exported.Pipeline, options *NewPol defer resp.Body.Close() // this is a back-stop in case the swagger is incorrect (i.e. missing one or more status codes for success). // ideally the codegen should return an error if the initial response failed and not even create a poller. - if !pollers.StatusCodeValid(resp) { + if !poller.StatusCodeValid(resp) { return nil, errors.New("the operation failed or was cancelled") } @@ -146,7 +147,9 @@ func NewPollerFromResumeToken[T any](token string, pl exported.Pipeline, options opr := options.Handler // now rehydrate the poller based on the encoded poller type - if async.CanResume(asJSON) { + if opr != nil { + log.Writef(log.EventLRO, "Resuming custom poller %T.", opr) + } else if async.CanResume(asJSON) { opr, _ = async.New[T](pl, nil, "") } else if body.CanResume(asJSON) { opr, _ = body.New[T](pl, nil) @@ -154,8 +157,6 @@ func NewPollerFromResumeToken[T any](token string, pl exported.Pipeline, options opr, _ = loc.New[T](pl, nil) } else if op.CanResume(asJSON) { opr, _ = op.New[T](pl, nil, "") - } else if opr != nil { - log.Writef(log.EventLRO, "Resuming custom poller %T.", opr) } else { return nil, fmt.Errorf("unhandled poller token %s", string(raw)) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/response.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/response.go index f86ec0b95..d1f58e9e2 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/response.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime/response.go @@ -15,15 +15,14 @@ import ( "io" "net/http" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/exported" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared" + "github.com/Azure/azure-sdk-for-go/sdk/internal/exported" ) // Payload reads and returns the response body or an error. // On a successful read, the response body is cached. // Subsequent reads will access the cached value. func Payload(resp *http.Response) ([]byte, error) { - return exported.Payload(resp) + return exported.Payload(resp, nil) } // HasStatusCode returns true if the Response's status code is one of the specified values. @@ -92,15 +91,15 @@ func Drain(resp *http.Response) { // removeBOM removes any byte-order mark prefix from the payload if present. func removeBOM(resp *http.Response) error { - payload, err := Payload(resp) + _, err := exported.Payload(resp, &exported.PayloadOptions{ + BytesModifier: func(b []byte) []byte { + // UTF8 + return bytes.TrimPrefix(b, []byte("\xef\xbb\xbf")) + }, + }) if err != nil { return err } - // UTF8 - trimmed := bytes.TrimPrefix(payload, []byte("\xef\xbb\xbf")) - if len(trimmed) < len(payload) { - resp.Body.(shared.BytesSetter).Set(trimmed) - } return nil } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/progress.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/progress.go index 8563375af..fbcd48311 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/progress.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming/progress.go @@ -20,6 +20,9 @@ type progress struct { } // NopCloser returns a ReadSeekCloser with a no-op close method wrapping the provided io.ReadSeeker. +// In addition to adding a Close method to an io.ReadSeeker, this can also be used to wrap an +// io.ReadSeekCloser with a no-op Close method to allow explicit control of when the io.ReedSeekCloser +// has its underlying stream closed. func NopCloser(rs io.ReadSeeker) io.ReadSeekCloser { return exported.NopCloser(rs) } diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md index 5877e476f..cc8034cf7 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md @@ -1,5 +1,89 @@ # Release History +## 1.3.0 (2023-05-09) + +### Breaking Changes +> These changes affect only code written against a beta version such as v1.3.0-beta.5 +* Renamed `NewOnBehalfOfCredentialFromCertificate` to `NewOnBehalfOfCredentialWithCertificate` +* Renamed `NewOnBehalfOfCredentialFromSecret` to `NewOnBehalfOfCredentialWithSecret` + +### Other Changes +* Upgraded to MSAL v1.0.0 + +## 1.3.0-beta.5 (2023-04-11) + +### Breaking Changes +> These changes affect only code written against a beta version such as v1.3.0-beta.4 +* Moved `NewWorkloadIdentityCredential()` parameters into `WorkloadIdentityCredentialOptions`. + The constructor now reads default configuration from environment variables set by the Azure + workload identity webhook by default. + ([#20478](https://github.com/Azure/azure-sdk-for-go/pull/20478)) +* Removed CAE support. It will return in v1.4.0-beta.1 + ([#20479](https://github.com/Azure/azure-sdk-for-go/pull/20479)) + +### Bugs Fixed +* Fixed an issue in `DefaultAzureCredential` that could cause the managed identity endpoint check to fail in rare circumstances. + +## 1.3.0-beta.4 (2023-03-08) + +### Features Added +* Added `WorkloadIdentityCredentialOptions.AdditionallyAllowedTenants` and `.DisableInstanceDiscovery` + +### Bugs Fixed +* Credentials now synchronize within `GetToken()` so a single instance can be shared among goroutines + ([#20044](https://github.com/Azure/azure-sdk-for-go/issues/20044)) + +### Other Changes +* Upgraded dependencies + +## 1.2.2 (2023-03-07) + +### Other Changes +* Upgraded dependencies + +## 1.3.0-beta.3 (2023-02-07) + +### Features Added +* By default, credentials set client capability "CP1" to enable support for + [Continuous Access Evaluation (CAE)](https://docs.microsoft.com/azure/active-directory/develop/app-resilience-continuous-access-evaluation). + This indicates to Azure Active Directory that your application can handle CAE claims challenges. + You can disable this behavior by setting the environment variable "AZURE_IDENTITY_DISABLE_CP1" to "true". +* `InteractiveBrowserCredentialOptions.LoginHint` enables pre-populating the login + prompt with a username ([#15599](https://github.com/Azure/azure-sdk-for-go/pull/15599)) +* Service principal and user credentials support ADFS authentication on Azure Stack. + Specify "adfs" as the credential's tenant. +* Applications running in private or disconnected clouds can prevent credentials from + requesting Azure AD instance metadata by setting the `DisableInstanceDiscovery` + field on credential options. +* Many credentials can now be configured to authenticate in multiple tenants. The + options types for these credentials have an `AdditionallyAllowedTenants` field + that specifies additional tenants in which the credential may authenticate. + +## 1.3.0-beta.2 (2023-01-10) + +### Features Added +* Added `OnBehalfOfCredential` to support the on-behalf-of flow + ([#16642](https://github.com/Azure/azure-sdk-for-go/issues/16642)) + +### Bugs Fixed +* `AzureCLICredential` reports token expiration in local time (should be UTC) + +### Other Changes +* `AzureCLICredential` imposes its default timeout only when the `Context` + passed to `GetToken()` has no deadline +* Added `NewCredentialUnavailableError()`. This function constructs an error indicating + a credential can't authenticate and an encompassing `ChainedTokenCredential` should + try its next credential, if any. + +## 1.3.0-beta.1 (2022-12-13) + +### Features Added +* `WorkloadIdentityCredential` and `DefaultAzureCredential` support + Workload Identity Federation on Kubernetes. `DefaultAzureCredential` + support requires environment variable configuration as set by the + Workload Identity webhook. + ([#15615](https://github.com/Azure/azure-sdk-for-go/issues/15615)) + ## 1.2.0 (2022-11-08) ### Other Changes diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md index 2df42c813..da0baa9ad 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md @@ -55,8 +55,9 @@ an Azure AD access token. See [Credential Types](#credential-types "Credential T ![DefaultAzureCredential authentication flow](img/mermaidjs/DefaultAzureCredentialAuthFlow.svg) 1. **Environment** - `DefaultAzureCredential` will read account information specified via [environment variables](#environment-variables) and use it to authenticate. -2. **Managed Identity** - If the app is deployed to an Azure host with managed identity enabled, `DefaultAzureCredential` will authenticate with it. -3. **Azure CLI** - If a user or service principal has authenticated via the Azure CLI `az login` command, `DefaultAzureCredential` will authenticate that identity. +1. **Workload Identity** - If the app is deployed on Kubernetes with environment variables set by the workload identity webhook, `DefaultAzureCredential` will authenticate the configured identity. +1. **Managed Identity** - If the app is deployed to an Azure host with managed identity enabled, `DefaultAzureCredential` will authenticate with it. +1. **Azure CLI** - If a user or service principal has authenticated via the Azure CLI `az login` command, `DefaultAzureCredential` will authenticate that identity. > Note: `DefaultAzureCredential` is intended to simplify getting started with the SDK by handling common scenarios with reasonable default behaviors. Developers who want more control or whose scenario isn't served by the default settings should use other credential types. @@ -128,12 +129,13 @@ client := armresources.NewResourceGroupsClient("subscription ID", chain, nil) |[ChainedTokenCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ChainedTokenCredential)|Define custom authentication flows, composing multiple credentials |[EnvironmentCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#EnvironmentCredential)|Authenticate a service principal or user configured by environment variables |[ManagedIdentityCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ManagedIdentityCredential)|Authenticate the managed identity of an Azure resource +|[WorkloadIdentityCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#WorkloadIdentityCredential)|Authenticate a workload identity on Kubernetes ### Authenticating Service Principals |Credential|Usage |-|- -|[ClientAssertionCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity@v1.2.0-beta.2#ClientAssertionCredential)|Authenticate a service principal with a signed client assertion +|[ClientAssertionCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ClientAssertionCredential)|Authenticate a service principal with a signed client assertion |[ClientCertificateCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ClientCertificateCredential)|Authenticate a service principal with a certificate |[ClientSecretCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ClientSecretCredential)|Authenticate a service principal with a secret diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md index affa91d08..7b7515eba 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md @@ -8,16 +8,17 @@ This troubleshooting guide covers failure investigation techniques, common error - [Permission issues](#permission-issues) - [Find relevant information in errors](#find-relevant-information-in-errors) - [Enable and configure logging](#enable-and-configure-logging) +- [Troubleshoot AzureCliCredential authentication issues](#troubleshoot-azureclicredential-authentication-issues) +- [Troubleshoot ClientCertificateCredential authentication issues](#troubleshoot-clientcertificatecredential-authentication-issues) +- [Troubleshoot ClientSecretCredential authentication issues](#troubleshoot-clientsecretcredential-authentication-issues) - [Troubleshoot DefaultAzureCredential authentication issues](#troubleshoot-defaultazurecredential-authentication-issues) - [Troubleshoot EnvironmentCredential authentication issues](#troubleshoot-environmentcredential-authentication-issues) -- [Troubleshoot ClientSecretCredential authentication issues](#troubleshoot-clientsecretcredential-authentication-issues) -- [Troubleshoot ClientCertificateCredential authentication issues](#troubleshoot-clientcertificatecredential-authentication-issues) -- [Troubleshoot UsernamePasswordCredential authentication issues](#troubleshoot-usernamepasswordcredential-authentication-issues) - [Troubleshoot ManagedIdentityCredential authentication issues](#troubleshoot-managedidentitycredential-authentication-issues) - - [Azure Virtual Machine managed identity](#azure-virtual-machine-managed-identity) - [Azure App Service and Azure Functions managed identity](#azure-app-service-and-azure-functions-managed-identity) - [Azure Kubernetes Service managed identity](#azure-kubernetes-service-managed-identity) -- [Troubleshoot AzureCliCredential authentication issues](#troubleshoot-azureclicredential-authentication-issues) + - [Azure Virtual Machine managed identity](#azure-virtual-machine-managed-identity) +- [Troubleshoot UsernamePasswordCredential authentication issues](#troubleshoot-usernamepasswordcredential-authentication-issues) +- [Troubleshoot WorkloadIdentityCredential authentication issues](#troubleshoot-workloadidentitycredential-authentication-issues) - [Get additional help](#get-additional-help) ## Handle azidentity errors @@ -79,7 +80,7 @@ azlog.SetEvents(azidentity.EventAuthentication) | Error |Description| Mitigation | |---|---|---| -|"DefaultAzureCredential failed to acquire a token"|No credential in the `DefaultAzureCredential` chain provided a token|