Repository: kubernetes-csi/external-provisioner
Pull request #501 (2020-10-08 14:44:22)

topology: also control for immediate binding
**What type of PR is this?**
/kind feature

**What this PR does / why we need it**:

A CSI driver for local volumes doesn't care about the (long!) list of nodes where the driver is currently running. It needs to track that itself anyway if it supports volume provisioning with immediate binding. The `CreateVolumeRequest` can be made a lot shorter by omitting the topology requirements in that case.

**Does this PR introduce a user-facing change?**:
```release-note
TBD
```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-csi/external-provisioner/pull/501#" title="Author self-approved">pohly</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **msau42** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @msau42` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-csi%2Fexternal-provisioner).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-csi/external-provisioner/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["msau42"]} -->
k8s-ci-robot: @pohly: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-kubernetes-csi-external-provisioner-unit | 24b8d5d1f8e4d375039a6b256b7d865940c36bed | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_external-provisioner/501/pull-kubernetes-csi-external-provisioner-unit/1314215067050315776) | `/test pull-kubernetes-csi-external-provisioner-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=external-provisioner&pr=501). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Apohly). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/external-provisioner/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-csi/external-provisioner/pull/501#pullrequestreview-535828543" title="Approved">msau42</a>*, *<a href="https://github.com/kubernetes-csi/external-provisioner/pull/501#" title="Author self-approved">pohly</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-csi%2Fexternal-provisioner).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-csi/external-provisioner/blob/master/OWNERS)~~ [msau42]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/README.md b/README.md
index 73bc15452..909c076b1 100644
--- a/README.md
+++ b/README.md
@@ -89,6 +89,8 @@ See the [storage capacity section](#capacity-support) below for details.
 
 * `--strict-topology`: This controls what topology information is passed to `CreateVolumeRequest.AccessibilityRequirements` in case of delayed binding. See [the table below](#topology-support) for an explanation how this option changes the result. This option has no effect if either `Topology` feature is disabled or `Immediate` volume binding mode is used.
 
+* `--immediate-topology`: This controls what topology information is passed to `CreateVolumeRequest.AccessibilityRequirements` in case of immediate binding. See [the table below](#topology-support) for an explanation how this option changes the result. This option has no effect if either `Topology` feature is disabled or `WaitForFirstConsumer` (= delayed) volume binding mode is used. The default is true, so use `--immediate-topology=false` to disable it. It should not be disabled if the CSI driver might create volumes in a topology segment that is not accessible in the cluster. Such a driver should use the topology information to create new volumes where they can be accessed.
+
 * `--kubeconfig <path>`: Path to Kubernetes client configuration that the external-provisioner uses to connect to Kubernetes API server. When omitted, default token provided by Kubernetes will be used. This option is useful only when the external-provisioner does not run as a Kubernetes pod, e.g. for debugging. Either this or `--master` needs to be set if the external-provisioner is being run out of cluster.
 
 * `--master <url>`: Master URL to build a client config from. When omitted, default token provided by Kubernetes will be used. This option is useful only when the external-provisioner does not run as a Kubernetes pod, e.g. for debugging. Either this or `--kubeconfig` needs to be set if the external-provisioner is being run out of cluster.
@@ -104,13 +106,14 @@ See the [storage capacity section](#capacity-support) below for details.
 ### Topology support
 When `Topology` feature is enabled and the driver specifies `VOLUME_ACCESSIBILITY_CONSTRAINTS` in its plugin capabilities, external-provisioner prepares `CreateVolumeRequest.AccessibilityRequirements` while calling `Controller.CreateVolume`. The driver has to consider these topology constraints while creating the volume. Below table shows how these `AccessibilityRequirements` are prepared:
 
-[Delayed binding](https://kubernetes.io/docs/concepts/storage/storage-classes/#volume-binding-mode) | Strict topology | [Allowed topologies](https://kubernetes.io/docs/concepts/storage/storage-classes/#allowed-topologies) | [Resulting accessability requirements](https://github.com/container-storage-interface/spec/blob/master/spec.md#createvolume)
-:---: |:---:|:---:|:---|
-Yes | Yes | Irrelevant | `Requisite` = `Preferred` = Selected node topology
-Yes | No  | No | `Requisite` = Aggregated cluster topology<br>`Preferred` = `Requisite` with selected node topology as first element
-Yes | No | Yes | `Requisite` = Allowed topologies<br>`Preferred` = `Requisite` with selected node topology as first element
-No | Irrelevant | No | `Requisite` = Aggregated cluster topology<br>`Preferred` = `Requisite` with randomly selected node topology as first element
-No | Irrelevant | Yes | `Requisite` = Allowed topologies<br>`Preferred` = `Requisite` with randomly selected node topology as first element
+[Delayed binding](https://kubernetes.io/docs/concepts/storage/storage-classes/#volume-binding-mode) | Strict topology | [Allowed topologies](https://kubernetes.io/docs/concepts/storage/storage-classes/#allowed-topologies) | Immediate Topology | [Resulting accessability requirements](https://github.com/container-storage-interface/spec/blob/master/spec.md#createvolume)
+:---: |:---:|:---:|:---:|:---|
+Yes | Yes | Irrelevant | Irrelevant | `Requisite` = `Preferred` = Selected node topology
+Yes | No  | No  | Irrelevant | `Requisite` = Aggregated cluster topology<br>`Preferred` = `Requisite` with selected node topology as first element
+Yes | No  | Yes | Irrelevant | `Requisite` = Allowed topologies<br>`Preferred` = `Requisite` with selected node topology as first element
+No | Irrelevant | Yes | Irrelevant | `Requisite` = Allowed topologies<br>`Preferred` = `Requisite` with randomly selected node topology as first element
+No | Irrelevant | No  | Yes | `Requisite` = Aggregated cluster topology<br>`Preferred` = `Requisite` with randomly selected node topology as first element
+No | Irrelevant | No  | No  | `Requisite` and `Preferred` both nil
 
 ### Capacity support
 
@@ -121,7 +124,7 @@ No | Irrelevant | Yes | `Requisite` = Allowed topologies<br>`Preferred` = `Requi
 The external-provisioner can be used to create CSIStorageCapacity
 objects that hold information about the storage capacity available
 through the driver. The Kubernetes scheduler then [uses that
-information](https://kubernetes.io/docs/concepts/storage/storage-capacity)
+information](https://kubernetes.io/docs/concepts/storage/storage-capacity]
 when selecting nodes for pods with unbound volumes that wait for the
 first consumer.
 
@@ -218,11 +221,11 @@ other driver.
 ### CSI error and timeout handling
 The external-provisioner invokes all gRPC calls to CSI driver with timeout provided by `--timeout` command line argument (15 seconds by default).
 
-Correct timeout value and number of worker threads depends on the storage backend and how quickly it is able to process `ControllerCreateVolume` and `ControllerDeleteVolume` calls. The value should be set to accommodate majority of them. It is fine if some calls time out - such calls will be retried after exponential backoff (starting with 1s by default), however, this backoff will introduce delay when the call times out several times for a single volume.
+Correct timeout value and number of worker threads depends on the storage backend and how quickly it is able to processes `ControllerCreateVolume` and `ControllerDeleteVolume` calls. The value should be set to accommodate majority of them. It is fine if some calls time out - such calls will be retried after exponential backoff (starting with 1s by default), however, this backoff will introduce delay when the call times out several times for a single volume.
 
 Frequency of `ControllerCreateVolume` and `ControllerDeleteVolume` retries can be configured by `--retry-interval-start` and `--retry-interval-max` parameters. The external-provisioner starts retries with `retry-interval-start` interval (1s by default) and doubles it with each failure until it reaches `retry-interval-max` (5 minutes by default). The external provisioner stops increasing the retry interval when it reaches `retry-interval-max`, however, it still retries provisioning/deletion of a volume until it's provisioned. The external-provisioner keeps its own number of provisioning/deletion failures for each volume.
 
-The external-provisioner can invoke up to `--worker-threads` (100 by default) `ControllerCreateVolume` **and** up to `--worker-threads` (100 by default) `ControllerDeleteVolume` calls in parallel, i.e. these two calls are counted separately. The external-provisioner assumes that the storage backend can cope with such high number of parallel requests and that the requests are handled in relatively short time (ideally sub-second). Lower value should be used for storage backends that expect slower processing related to newly created / deleted volumes or can handle lower amount of parallel calls.
+The external-provisioner can invoke up to `--worker-threads` (100 by default) `ControllerCreateVolume` **and** up to `--worker-threads` `ControllerDeleteVolume` calls in parallel, i.e. these two calls are counted separately. The external-provisioner assumes that the storage backend can cope with such high number of parallel requests and that the requests are handled in relatively short time (ideally sub-second). Lower value should be used for storage backends that expect slower processing related to newly created / deleted volumes or can handle lower amount of parallel calls.
 
 Details of error handling of individual CSI calls:
 * `ControllerCreateVolume`: The call might have timed out just before the driver provisioned a volume and was sending a response. From that reason, timeouts from `ControllerCreateVolume` is considered as "*volume may be provisioned*" or "*volume is being provisioned in the background*." The external-provisioner will retry calling `ControllerCreateVolume` after exponential backoff until it gets either successful response or final (non-timeout) error that the volume cannot be created.
diff --git a/cmd/csi-provisioner/csi-provisioner.go b/cmd/csi-provisioner/csi-provisioner.go
index 7d8069c21..4e9b3e645 100644
--- a/cmd/csi-provisioner/csi-provisioner.go
+++ b/cmd/csi-provisioner/csi-provisioner.go
@@ -48,7 +48,7 @@ import (
 	"github.com/kubernetes-csi/external-provisioner/pkg/capacity/topology"
 	ctrl "github.com/kubernetes-csi/external-provisioner/pkg/controller"
 	"github.com/kubernetes-csi/external-provisioner/pkg/owner"
-	snapclientset "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned"
+	snapclientset "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned"
 )
 
 var (
@@ -68,7 +68,8 @@ var (
 	enableLeaderElection = flag.Bool("leader-election", false, "Enables leader election. If leader election is enabled, additional RBAC rules are required. Please refer to the Kubernetes CSI documentation for instructions on setting up these RBAC rules.")
 
 	leaderElectionNamespace = flag.String("leader-election-namespace", "", "Namespace where the leader election resource lives. Defaults to the pod namespace if not set.")
-	strictTopology          = flag.Bool("strict-topology", false, "Passes only selected node topology to CreateVolume Request, unlike default behavior of passing aggregated cluster topologies that match with topology keys of the selected node.")
+	strictTopology          = flag.Bool("strict-topology", false, "Late binding: pass only selected node topology to CreateVolume Request, unlike default behavior of passing aggregated cluster topologies that match with topology keys of the selected node.")
+	immediateTopology       = flag.Bool("immediate-topology", true, "Immediate binding: pass aggregated cluster topologies for all nodes where the CSI driver is available (enabled, the default) or no topology requirements (if disabled).")
 	extraCreateMetadata     = flag.Bool("extra-create-metadata", false, "If set, add pv/pvc metadata to plugin create requests as parameters.")
 
 	metricsAddress = flag.String("metrics-address", "", "The TCP network address where the prometheus metrics endpoint will listen (example: `:8080`). The default is empty string, which means metrics endpoint is disabled.")
@@ -259,6 +260,7 @@ func main() {
 		controllerCapabilities,
 		supportsMigrationFromInTreePluginName,
 		*strictTopology,
+		*immediateTopology,
 		translator,
 		scLister,
 		csiNodeLister,
diff --git a/go.mod b/go.mod
index 088202287..7fdb6b75d 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/golang/mock v1.4.3
 	github.com/kubernetes-csi/csi-lib-utils v0.8.1
 	github.com/kubernetes-csi/csi-test/v3 v3.1.1
-	github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0
+	github.com/kubernetes-csi/external-snapshotter/client/v2 v2.2.0-rc3
 	github.com/spf13/pflag v1.0.5
 	google.golang.org/grpc v1.29.1
 	k8s.io/api v0.19.3
diff --git a/go.sum b/go.sum
index 62daf5561..c70131d05 100644
--- a/go.sum
+++ b/go.sum
@@ -363,8 +363,8 @@ github.com/kubernetes-csi/csi-lib-utils v0.8.1 h1:DHFs4MgzjSGF/FH95TEdLVa7R1CCi9
 github.com/kubernetes-csi/csi-lib-utils v0.8.1/go.mod h1:FZflf0cCYlCquPQxVHa6Tyy0i/so6VAZTiEVK1do7CU=
 github.com/kubernetes-csi/csi-test/v3 v3.1.1 h1:mFxPbUf7pti663WTCsfaT3YRPVIzy0yLx8HWbVKfN4I=
 github.com/kubernetes-csi/csi-test/v3 v3.1.1/go.mod h1:UWxYP5cDlD6iSNVKEiLFqfJnJinuhtI7MLt61rQQOfI=
-github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0 h1:OYDCOjVcx/5wNzlZ/At8otRibUlw0T6R0xOD31f32bw=
-github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0/go.mod h1:Q7VUue/CIrKbtpBdF04a1yjGGgsMaDws1HUxtjzgnEY=
+github.com/kubernetes-csi/external-snapshotter/client/v2 v2.2.0-rc3 h1://kqMNFTDX6gD13dbDfIKepSasiPbGMPw+kT90kxV2Y=
+github.com/kubernetes-csi/external-snapshotter/client/v2 v2.2.0-rc3/go.mod h1:speZ9Q5gEevndGNLFUKXCfNYZ9s8BBapHAfPGryOxKE=
 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
 github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go
index 9a4cd1212..8f8420a30 100644
--- a/pkg/controller/controller.go
+++ b/pkg/controller/controller.go
@@ -51,8 +51,8 @@ import (
 	"github.com/kubernetes-csi/csi-lib-utils/connection"
 	"github.com/kubernetes-csi/csi-lib-utils/metrics"
 	"github.com/kubernetes-csi/csi-lib-utils/rpc"
-	snapapi "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
-	snapclientset "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned"
+	snapapi "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
+	snapclientset "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned"
 )
 
 //secretParamsMap provides a mapping of current as well as deprecated secret keys
@@ -218,6 +218,7 @@ type csiProvisioner struct {
 	controllerCapabilities                rpc.ControllerCapabilitySet
 	supportsMigrationFromInTreePluginName string
 	strictTopology                        bool
+	immediateTopology                     bool
 	translator                            ProvisionerCSITranslator
 	scLister                              storagelistersv1.StorageClassLister
 	csiNodeLister                         storagelistersv1.CSINodeLister
@@ -287,6 +288,7 @@ func NewCSIProvisioner(client kubernetes.Interface,
 	controllerCapabilities rpc.ControllerCapabilitySet,
 	supportsMigrationFromInTreePluginName string,
 	strictTopology bool,
+	immediateTopology bool,
 	translator ProvisionerCSITranslator,
 	scLister storagelistersv1.StorageClassLister,
 	csiNodeLister storagelistersv1.CSINodeLister,
@@ -317,6 +319,7 @@ func NewCSIProvisioner(client kubernetes.Interface,
 		controllerCapabilities:                controllerCapabilities,
 		supportsMigrationFromInTreePluginName: supportsMigrationFromInTreePluginName,
 		strictTopology:                        strictTopology,
+		immediateTopology:                     immediateTopology,
 		translator:                            translator,
 		scLister:                              scLister,
 		csiNodeLister:                         csiNodeLister,
@@ -562,6 +565,7 @@ func (p *csiProvisioner) Provision(ctx context.Context, options controller.Provi
 			options.StorageClass.AllowedTopologies,
 			options.SelectedNode,
 			p.strictTopology,
+			p.immediateTopology,
 			p.csiNodeLister,
 			p.nodeLister)
 		if err != nil {
diff --git a/pkg/controller/topology.go b/pkg/controller/topology.go
index a1b989ef0..0285dc236 100644
--- a/pkg/controller/topology.go
+++ b/pkg/controller/topology.go
@@ -119,6 +119,7 @@ func GenerateAccessibilityRequirements(
 	allowedTopologies []v1.TopologySelectorTerm,
 	selectedNode *v1.Node,
 	strictTopology bool,
+	immediateTopology bool,
 	csiNodeLister storagelistersv1.CSINodeLister,
 	nodeLister corelisters.NodeLister) (*csi.TopologyRequirement, error) {
 	requirement := &csi.TopologyRequirement{}
@@ -181,6 +182,13 @@ func GenerateAccessibilityRequirements(
 			// Distribute out one of the OR layers in allowedTopologies
 			requisiteTerms = flatten(allowedTopologies)
 		} else {
+			if selectedNode == nil && !immediateTopology {
+				// Don't specify any topology requirements because neither the PVC nor
+				// the storage class have limitations and the CSI driver is not interested
+				// in being told where it runs (perhaps it already knows, for example).
+				return nil, nil
+			}
+
 			// Aggregate existing topologies in nodes across the entire cluster.
 			requisiteTerms, err = aggregateTopologies(kubeClient, driverName, selectedCSINode, csiNodeLister, nodeLister)
 			if err != nil {
diff --git a/release-tools/prow.sh b/release-tools/prow.sh
index 44511fb23..1ada24803 100755
--- a/release-tools/prow.sh
+++ b/release-tools/prow.sh
@@ -330,14 +330,7 @@ configvar CSI_PROW_E2E_ALPHA_GATES_LATEST 'GenericEphemeralVolume=true,CSIStorag
 configvar CSI_PROW_E2E_ALPHA_GATES "$(get_versioned_variable CSI_PROW_E2E_ALPHA_GATES "${csi_prow_kubernetes_version_suffix}")" "alpha E2E feature gates"
 
 # Which external-snapshotter tag to use for the snapshotter CRD and snapshot-controller deployment
-default_csi_snapshotter_version () {
-	if [ "${CSI_PROW_KUBERNETES_VERSION}" = "latest" ] || [ "${CSI_PROW_DRIVER_CANARY}" = "canary" ]; then
-		echo "master"
-	else
-		echo "v3.0.2"
-	fi
-}
-configvar CSI_SNAPSHOTTER_VERSION "$(default_csi_snapshotter_version)" "external-snapshotter version tag"
+configvar CSI_SNAPSHOTTER_VERSION 'v3.0.0' "external-snapshotter version tag"
 
 # Some tests are known to be unusable in a KinD cluster. For example,
 # stopping kubelet with "ssh <node IP> systemctl stop kubelet" simply
@@ -700,10 +693,6 @@ install_csi_driver () {
 install_snapshot_crds() {
   # Wait until volumesnapshot CRDs are in place.
   CRD_BASE_DIR="https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${CSI_SNAPSHOTTER_VERSION}/client/config/crd"
-  if [[ ${REPO_DIR} == *"external-snapshotter"* ]]; then
-      CRD_BASE_DIR="${REPO_DIR}/client/config/crd"
-  fi
-  echo "Installing snapshot CRDs from ${CRD_BASE_DIR}"
   kubectl apply -f "${CRD_BASE_DIR}/snapshot.storage.k8s.io_volumesnapshotclasses.yaml" --validate=false
   kubectl apply -f "${CRD_BASE_DIR}/snapshot.storage.k8s.io_volumesnapshots.yaml" --validate=false
   kubectl apply -f "${CRD_BASE_DIR}/snapshot.storage.k8s.io_volumesnapshotcontents.yaml" --validate=false
@@ -723,16 +712,7 @@ install_snapshot_crds() {
 
 # Install snapshot controller and associated RBAC, retrying until the pod is running.
 install_snapshot_controller() {
-  CONTROLLER_DIR="https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${CSI_SNAPSHOTTER_VERSION}"
-  if [[ ${REPO_DIR} == *"external-snapshotter"* ]]; then
-      CONTROLLER_DIR="${REPO_DIR}"
-  fi
-  SNAPSHOT_RBAC_YAML="${CONTROLLER_DIR}/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml"
-  echo "kubectl apply -f ${SNAPSHOT_RBAC_YAML}"
-  # Ignore: Double quote to prevent globbing and word splitting.
-  # shellcheck disable=SC2086
-  kubectl apply -f ${SNAPSHOT_RBAC_YAML}
-
+  kubectl apply -f "https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${CSI_SNAPSHOTTER_VERSION}/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml"
   cnt=0
   until kubectl get clusterrolebinding snapshot-controller-role; do
      if [ $cnt -gt 30 ]; then
@@ -746,60 +726,8 @@ install_snapshot_controller() {
     sleep 10   
   done
 
-  SNAPSHOT_CONTROLLER_YAML="${CONTROLLER_DIR}/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml"
-  if [[ ${REPO_DIR} == *"external-snapshotter"* ]]; then
-      # snapshot-controller image built from the PR will get a "csiprow" tag.
-      # Load it into the "kind" cluster so that we can deploy it.
-      NEW_TAG="csiprow"
-      NEW_IMG="snapshot-controller:${NEW_TAG}"
-      echo "kind load docker-image --name csi-prow ${NEW_IMG}"
-      kind load docker-image --name csi-prow ${NEW_IMG} || die "could not load the snapshot-controller:csiprow image into the kind cluster"
-
-      # deploy snapshot-controller
-      echo "Deploying snapshot-controller"
-      # Replace image in SNAPSHOT_CONTROLLER_YAML with snapshot-controller:csiprow and deploy
-      # NOTE: This logic is similar to the logic here:
-      # https://github.com/kubernetes-csi/csi-driver-host-path/blob/v1.4.0/deploy/util/deploy-hostpath.sh#L155
-      # Ignore: Double quote to prevent globbing and word splitting.
-      # shellcheck disable=SC2086
-      # Ignore: Use find instead of ls to better handle non-alphanumeric filenames.
-      # shellcheck disable=SC2012
-      for i in $(ls ${SNAPSHOT_CONTROLLER_YAML} | sort); do
-          echo "   $i"
-          # Ignore: Useless cat. Consider 'cmd < file | ..' or 'cmd file | ..' instead.
-          # shellcheck disable=SC2002
-          # Ignore: See if you can use ${variable//search/replace} instead.
-          # shellcheck disable=SC2001
-          modified="$(cat "$i" | while IFS= read -r line; do
-              nocomments="$(echo "$line" | sed -e 's/ *#.*$//')"
-              if echo "$nocomments" | grep -q '^[[:space:]]*image:[[:space:]]*'; then
-                  # Split 'image: k8s.gcr.io/sig-storage/snapshot-controller:v3.0.0'
-                  # into image (snapshot-controller:v3.0.0),
-                  # name (snapshot-controller),
-                  # tag (v3.0.0).
-                  image=$(echo "$nocomments" | sed -e 's;.*image:[[:space:]]*;;')
-                  name=$(echo "$image" | sed -e 's;.*/\([^:]*\).*;\1;')
-                  tag=$(echo "$image" | sed -e 's;.*:;;')
-
-                  # Now replace registry and/or tag
-                  NEW_TAG="csiprow"
-                  line="$(echo "$nocomments" | sed -e "s;$image;${name}:${NEW_TAG};")"
-	          echo "        using $line" >&2
-              fi
-              echo "$line"
-          done)"
-          if ! echo "$modified" | kubectl apply -f -; then
-              echo "modified version of $i:"
-              echo "$modified"
-              exit 1
-          fi
-	  echo "kubectl apply -f ${SNAPSHOT_CONTROLLER_YAML}(modified)"
-      done
-  else
-      echo "kubectl apply -f ${CONTROLLER_DIR}/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml"
-      kubectl apply -f "${CONTROLLER_DIR}/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml"
-  fi
 
+  kubectl apply -f "https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${CSI_SNAPSHOTTER_VERSION}/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml"
   cnt=0
   expected_running_pods=$(curl https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/"${CSI_SNAPSHOTTER_VERSION}"/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml | grep replicas | cut -d ':' -f 2-)
   while [ "$(kubectl get pods -l app=snapshot-controller | grep 'Running' -c)" -lt "$expected_running_pods" ]; do
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/LICENSE b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/LICENSE
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/LICENSE
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/LICENSE
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/doc.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/doc.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/doc.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/doc.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/register.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/register.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/register.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/register.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/types.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/types.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/types.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/types.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/zz_generated.deepcopy.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/zz_generated.deepcopy.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1/zz_generated.deepcopy.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1/zz_generated.deepcopy.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/clientset.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/clientset.go
similarity index 98%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/clientset.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/clientset.go
index 82bef6d6c..8ac6951db 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/clientset.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/clientset.go
@@ -21,7 +21,7 @@ package versioned
 import (
 	"fmt"
 
-	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1"
+	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1"
 	discovery "k8s.io/client-go/discovery"
 	rest "k8s.io/client-go/rest"
 	flowcontrol "k8s.io/client-go/util/flowcontrol"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/doc.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/doc.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/doc.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/doc.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/clientset_generated.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/clientset_generated.go
similarity index 94%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/clientset_generated.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/clientset_generated.go
index a912b23f4..92c2fa21c 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/clientset_generated.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/clientset_generated.go
@@ -19,9 +19,9 @@ limitations under the License.
 package fake
 
 import (
-	clientset "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned"
-	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1"
-	fakesnapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake"
+	clientset "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned"
+	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1"
+	fakesnapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/watch"
 	"k8s.io/client-go/discovery"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/doc.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/doc.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/doc.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/doc.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/register.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/register.go
similarity index 97%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/register.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/register.go
index 93ef2c632..1772f9c35 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake/register.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake/register.go
@@ -19,7 +19,7 @@ limitations under the License.
 package fake
 
 import (
-	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
+	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme/doc.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme/doc.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme/doc.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme/doc.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme/register.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme/register.go
similarity index 97%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme/register.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme/register.go
index 51773e8e1..c0c02d70c 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme/register.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme/register.go
@@ -19,7 +19,7 @@ limitations under the License.
 package scheme
 
 import (
-	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
+	snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/doc.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/doc.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/doc.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/doc.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/doc.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/doc.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/doc.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/doc.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot.go
similarity index 99%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot.go
index 216b18676..48429885b 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot.go
@@ -21,7 +21,7 @@ package fake
 import (
 	"context"
 
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	labels "k8s.io/apimachinery/pkg/labels"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot_client.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot_client.go
similarity index 96%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot_client.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot_client.go
index f237715b7..743f500c0 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot_client.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshot_client.go
@@ -19,7 +19,7 @@ limitations under the License.
 package fake
 
 import (
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1"
 	rest "k8s.io/client-go/rest"
 	testing "k8s.io/client-go/testing"
 )
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotclass.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotclass.go
similarity index 99%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotclass.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotclass.go
index 188cc854b..f341fbd29 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotclass.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotclass.go
@@ -21,7 +21,7 @@ package fake
 import (
 	"context"
 
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	labels "k8s.io/apimachinery/pkg/labels"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotcontent.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotcontent.go
similarity index 99%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotcontent.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotcontent.go
index f1c0a4d90..6ac2ef07b 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotcontent.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake/fake_volumesnapshotcontent.go
@@ -21,7 +21,7 @@ package fake
 import (
 	"context"
 
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	labels "k8s.io/apimachinery/pkg/labels"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/generated_expansion.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/generated_expansion.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/generated_expansion.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/generated_expansion.go
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot.go
similarity index 99%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot.go
index 4d75fe090..161d35e37 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot.go
@@ -22,8 +22,8 @@ import (
 	"context"
 	"time"
 
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
-	scheme "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
+	scheme "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	types "k8s.io/apimachinery/pkg/types"
 	watch "k8s.io/apimachinery/pkg/watch"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot_client.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot_client.go
similarity index 96%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot_client.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot_client.go
index 39d092eb5..eaebb1340 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot_client.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshot_client.go
@@ -19,8 +19,8 @@ limitations under the License.
 package v1beta1
 
 import (
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
-	"github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
+	"github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme"
 	rest "k8s.io/client-go/rest"
 )
 
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotclass.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotclass.go
similarity index 99%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotclass.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotclass.go
index d6fe61c00..38cb15a36 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotclass.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotclass.go
@@ -22,8 +22,8 @@ import (
 	"context"
 	"time"
 
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
-	scheme "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
+	scheme "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	types "k8s.io/apimachinery/pkg/types"
 	watch "k8s.io/apimachinery/pkg/watch"
diff --git a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotcontent.go b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotcontent.go
similarity index 99%
rename from vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotcontent.go
rename to vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotcontent.go
index b592b2970..d32060c10 100644
--- a/vendor/github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotcontent.go
+++ b/vendor/github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/volumesnapshotcontent.go
@@ -22,8 +22,8 @@ import (
 	"context"
 	"time"
 
-	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
-	scheme "github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme"
+	v1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
+	scheme "github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	types "k8s.io/apimachinery/pkg/types"
 	watch "k8s.io/apimachinery/pkg/watch"
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 8ce2542ab..208c17d0a 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -62,14 +62,14 @@ github.com/kubernetes-csi/csi-lib-utils/rpc
 ## explicit
 github.com/kubernetes-csi/csi-test/v3/driver
 github.com/kubernetes-csi/csi-test/v3/utils
-# github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0
+# github.com/kubernetes-csi/external-snapshotter/client/v2 v2.2.0-rc3
 ## explicit
-github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1
-github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned
-github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake
-github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/scheme
-github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1
-github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/typed/volumesnapshot/v1beta1/fake
+github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1
+github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned
+github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake
+github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/scheme
+github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1
+github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/typed/volumesnapshot/v1beta1/fake
 # github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369
 github.com/matttproud/golang_protobuf_extensions/pbutil
 # github.com/miekg/dns v1.1.29


Test patch:
diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go
index 857823b03..882b4b9b1 100644
--- a/pkg/controller/controller_test.go
+++ b/pkg/controller/controller_test.go
@@ -52,8 +52,8 @@ import (
 	"github.com/kubernetes-csi/csi-lib-utils/rpc"
 	"github.com/kubernetes-csi/csi-test/v3/driver"
 	"github.com/kubernetes-csi/external-provisioner/pkg/features"
-	crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1"
-	"github.com/kubernetes-csi/external-snapshotter/client/v3/clientset/versioned/fake"
+	crdv1 "github.com/kubernetes-csi/external-snapshotter/client/v2/apis/volumesnapshot/v1beta1"
+	"github.com/kubernetes-csi/external-snapshotter/client/v2/clientset/versioned/fake"
 )
 
 func init() {
@@ -413,7 +413,7 @@ func TestCreateDriverReturnsInvalidCapacityDuringProvision(t *testing.T) {
 
 	pluginCaps, controllerCaps := provisionCapabilities()
 	csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test",
-		5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, csitrans.New(), nil, nil, nil, nil, nil, false, defaultfsType)
+		5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, false, defaultfsType)
 
 	// Requested PVC with requestedBytes storage
 	deletePolicy := v1.PersistentVolumeReclaimDelete
@@ -1856,7 +1856,7 @@ func runFSTypeProvisionTest(t *testing.T, k string, tc provisioningFSTypeTestcas
 		myDefaultfsType = ""
 	}
 	csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
-		nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, csitrans.New(), nil, nil, nil, nil, nil, false, myDefaultfsType)
+		nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, true, csitrans.New(), nil, nil, nil, nil, nil, false, myDefaultfsType)
 	out := &csi.CreateVolumeResponse{
 		Volume: &csi.Volume{
 			CapacityBytes: requestedBytes,
@@ -1932,7 +1932,7 @@ func runProvisionTest(t *testing.T, k string, tc provisioningTestcase, requested
 	clientSet := fakeclientset.NewSimpleClientset(tc.clientSetObjects...)
 	pluginCaps, controllerCaps := provisionCapabilities()
 	csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
-		nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, csitrans.New(), nil, nil, nil, nil, nil, tc.withExtraMetadata, defaultfsType)
+		nil, provisionDriverName, pluginCaps, controllerCaps, supportsMigrationFromInTreePluginName, false, true, csitrans.New(), nil, nil, nil, nil, nil, tc.withExtraMetadata, defaultfsType)
 	out := &csi.CreateVolumeResponse{
 		Volume: &csi.Volume{
 			CapacityBytes: requestedBytes,
@@ -2667,7 +2667,7 @@ func TestProvisionFromSnapshot(t *testing.T) {
 
 		pluginCaps, controllerCaps := provisionFromSnapshotCapabilities()
 		csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
-			client, driverName, pluginCaps, controllerCaps, "", false, csitrans.New(), nil, nil, nil, nil, nil, false, defaultfsType)
+			client, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, false, defaultfsType)
 
 		out := &csi.CreateVolumeResponse{
 			Volume: &csi.Volume{
@@ -2841,7 +2841,7 @@ func TestProvisionWithTopologyEnabled(t *testing.T) {
 			defer close(stopChan)
 
 			csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
-				csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, false, defaultfsType)
+				csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, false, defaultfsType)
 
 			pv, _, err := csiProvisioner.Provision(context.Background(), controller.ProvisionOptions{
 				StorageClass: &storagev1.StorageClass{},
@@ -2935,7 +2935,7 @@ func TestProvisionErrorHandling(t *testing.T) {
 					defer close(stopChan)
 
 					csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
-						csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, false, defaultfsType)
+						csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, csiNodeLister, nodeLister, claimLister, vaLister, false, defaultfsType)
 
 					options := controller.ProvisionOptions{
 						StorageClass: &storagev1.StorageClass{},
@@ -3008,7 +3008,7 @@ func TestProvisionWithTopologyDisabled(t *testing.T) {
 	clientSet := fakeclientset.NewSimpleClientset()
 	pluginCaps, controllerCaps := provisionWithTopologyCapabilities()
 	csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
-		csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, csitrans.New(), nil, nil, nil, nil, nil, false, defaultfsType)
+		csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, nil, nil, false, defaultfsType)
 
 	out := &csi.CreateVolumeResponse{
 		Volume: &csi.Volume{
@@ -3345,7 +3345,7 @@ func runDeleteTest(t *testing.T, k string, tc deleteTestcase) {
 	pluginCaps, controllerCaps := provisionCapabilities()
 	scLister, _, _, _, vaLister, _ := listers(clientSet)
 	csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5,
-		csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, csitrans.New(), scLister, nil, nil, nil, vaLister, false, defaultfsType)
+		csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), scLister, nil, nil, nil, vaLister, false, defaultfsType)
 
 	err = csiProvisioner.Delete(context.Background(), tc.persistentVolume)
 	if tc.expectErr && err == nil {
@@ -3766,7 +3766,7 @@ func TestProvisionFromPVC(t *testing.T) {
 
 			// Phase: execute the test
 			csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner", "test", 5, csiConn.conn,
-				nil, driverName, pluginCaps, controllerCaps, "", false, csitrans.New(), nil, nil, nil, claimLister, nil, false, defaultfsType)
+				nil, driverName, pluginCaps, controllerCaps, "", false, true, csitrans.New(), nil, nil, nil, claimLister, nil, false, defaultfsType)
 
 			pv, _, err = csiProvisioner.Provision(context.Background(), tc.volOpts)
 			if tc.expectErr && err == nil {
@@ -3884,7 +3884,7 @@ func TestProvisionWithMigration(t *testing.T) {
 			pluginCaps, controllerCaps := provisionCapabilities()
 			csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner",
 				"test", 5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps,
-				inTreePluginName, false, mockTranslator, nil, nil, nil, nil, nil, false, defaultfsType)
+				inTreePluginName, false, true, mockTranslator, nil, nil, nil, nil, nil, false, defaultfsType)
 
 			// Set up return values (AnyTimes to avoid overfitting on implementation)
 
@@ -4046,7 +4046,7 @@ func TestDeleteMigration(t *testing.T) {
 			defer close(stopCh)
 			csiProvisioner := NewCSIProvisioner(clientSet, 5*time.Second, "test-provisioner",
 				"test", 5, csiConn.conn, nil, driverName, pluginCaps, controllerCaps, "",
-				false, mockTranslator, nil, nil, nil, nil, vaLister, false, defaultfsType)
+				false, true, mockTranslator, nil, nil, nil, nil, vaLister, false, defaultfsType)
 
 			// Set mock return values (AnyTimes to avoid overfitting on implementation details)
 			mockTranslator.EXPECT().IsPVMigratable(gomock.Any()).Return(tc.expectTranslation).AnyTimes()
diff --git a/pkg/controller/topology_test.go b/pkg/controller/topology_test.go
index f8abe1535..150d49504 100644
--- a/pkg/controller/topology_test.go
+++ b/pkg/controller/topology_test.go
@@ -36,6 +36,8 @@ const (
 	testDriverName = "com.example.csi/test-driver"
 )
 
+var withWithout = map[bool]string{false: "without", true: "with"}
+
 func TestGenerateVolumeNodeAffinity(t *testing.T) {
 	// TODO (verult) more test cases
 	testcases := map[string]struct {
@@ -397,37 +399,49 @@ func TestStatefulSetSpreading(t *testing.T) {
 	defer close(stopChan)
 
 	for name, tc := range testcases {
-		for _, strictTopology := range []bool{false, true} {
-			if strictTopology {
-				name += " with strict topology"
-			}
-			t.Run(name, func(t *testing.T) {
-				requirements, err := GenerateAccessibilityRequirements(
-					kubeClient,
-					testDriverName,
-					tc.pvcName,
-					tc.allowedTopologies,
-					nil,
-					strictTopology,
-					csiNodeLister,
-					nodeLister,
-				)
+		t.Run(name, func(t *testing.T) {
+			for strictTopology, withOrWithout := range withWithout {
+				t.Run(withOrWithout+" strict topology", func(t *testing.T) {
+					for immediateTopology, withOrWithout := range withWithout {
+						t.Run(withOrWithout+" immediate topology", func(t *testing.T) {
+							requirements, err := GenerateAccessibilityRequirements(
+								kubeClient,
+								testDriverName,
+								tc.pvcName,
+								tc.allowedTopologies,
+								nil,
+								strictTopology,
+								immediateTopology,
+								csiNodeLister,
+								nodeLister,
+							)
 
-				if err != nil {
-					t.Fatalf("unexpected error found: %v", err)
-				}
+							if err != nil {
+								t.Fatalf("unexpected error found: %v", err)
+							}
 
-				if requirements == nil {
-					t.Fatalf("expected preferred to be %v but requirements is nil", tc.expectedPreferred)
-				}
-				if requirements.Preferred == nil {
-					t.Fatalf("expected preferred to be %v but requirements.Preferred is nil", tc.expectedPreferred)
-				}
-				if !helper.Semantic.DeepEqual(requirements.Preferred, tc.expectedPreferred) {
-					t.Errorf("expected preferred requisite %v; got: %v", tc.expectedPreferred, requirements.Preferred)
-				}
-			})
-		}
+							expected := tc.expectedPreferred
+							if !immediateTopology && tc.allowedTopologies == nil {
+								expected = nil
+							}
+
+							if expected == nil && requirements != nil && requirements.Preferred != nil {
+								t.Fatalf("expected no preferred but requirements is %v", requirements)
+							}
+							if expected != nil && requirements == nil {
+								t.Fatalf("expected preferred to be %v but requirements is nil", expected)
+							}
+							if expected != nil && requirements.Preferred == nil {
+								t.Fatalf("expected preferred to be %v but requirements.Preferred is nil", expected)
+							}
+							if expected != nil && !helper.Semantic.DeepEqual(requirements.Preferred, expected) {
+								t.Errorf("expected preferred requisite %v; got: %v", expected, requirements.Preferred)
+							}
+						})
+					}
+				})
+			}
+		})
 	}
 }
 
@@ -790,33 +804,37 @@ func TestAllowedTopologies(t *testing.T) {
 	}
 
 	for name, tc := range testcases {
-		for _, strictTopology := range []bool{false, true} {
-			if strictTopology {
-				name += " with strict topology"
-			}
-			t.Run(name, func(t *testing.T) {
-				requirements, err := GenerateAccessibilityRequirements(
-					nil,           /* kubeClient */
-					"test-driver", /* driverName */
-					"testpvc",
-					tc.allowedTopologies,
-					nil, /* selectedNode */
-					strictTopology,
-					nil,
-					nil,
-				)
+		t.Run(name, func(t *testing.T) {
+			for strictTopology, withOrWithout := range withWithout {
+				t.Run(withOrWithout+" strict topology", func(t *testing.T) {
+					for immediateTopology, withOrWithout := range withWithout {
+						t.Run(withOrWithout+" immediate topology", func(t *testing.T) {
+							requirements, err := GenerateAccessibilityRequirements(
+								nil,           /* kubeClient */
+								"test-driver", /* driverName */
+								"testpvc",
+								tc.allowedTopologies,
+								nil, /* selectedNode */
+								strictTopology,
+								immediateTopology,
+								nil,
+								nil,
+							)
 
-				if err != nil {
-					t.Fatalf("expected no error but got: %v", err)
-				}
-				if requirements == nil {
-					t.Fatalf("expected requirements not to be nil")
-				}
-				if !requisiteEqual(requirements.Requisite, tc.expectedRequisite) {
-					t.Errorf("expected requisite %v; got: %v", tc.expectedRequisite, requirements.Requisite)
-				}
-			})
-		}
+							if err != nil {
+								t.Fatalf("expected no error but got: %v", err)
+							}
+							if requirements == nil {
+								t.Fatalf("expected requirements not to be nil")
+							}
+							if !requisiteEqual(requirements.Requisite, tc.expectedRequisite) {
+								t.Errorf("expected requisite %v; got: %v", tc.expectedRequisite, requirements.Requisite)
+							}
+						})
+					}
+				})
+			}
+		})
 	}
 }
 
@@ -1054,58 +1072,69 @@ func TestTopologyAggregation(t *testing.T) {
 	}
 
 	for name, tc := range testcases {
-		for _, strictTopology := range []bool{false, true} {
-			if strictTopology {
-				name += " with strict topology"
-			}
-			t.Run(name, func(t *testing.T) {
-				nodes := buildNodes(tc.nodeLabels)
-				csiNodes := buildCSINodes(tc.topologyKeys)
+		t.Run(name, func(t *testing.T) {
+			for strictTopology, withOrWithout := range withWithout {
+				t.Run(withOrWithout+" strict topology", func(t *testing.T) {
+					for immediateTopology, withOrWithout := range withWithout {
+						t.Run(withOrWithout+" immediate topology", func(t *testing.T) {
+							nodes := buildNodes(tc.nodeLabels)
+							csiNodes := buildCSINodes(tc.topologyKeys)
 
-				kubeClient := fakeclientset.NewSimpleClientset(nodes, csiNodes)
+							kubeClient := fakeclientset.NewSimpleClientset(nodes, csiNodes)
 
-				_, csiNodeLister, nodeLister, _, _, stopChan := listers(kubeClient)
-				defer close(stopChan)
+							_, csiNodeLister, nodeLister, _, _, stopChan := listers(kubeClient)
+							defer close(stopChan)
 
-				var selectedNode *v1.Node
-				if tc.hasSelectedNode {
-					selectedNode = &nodes.Items[0]
-				}
-				requirements, err := GenerateAccessibilityRequirements(
-					kubeClient,
-					testDriverName,
-					"testpvc",
-					nil, /* allowedTopologies */
-					selectedNode,
-					strictTopology,
-					csiNodeLister,
-					nodeLister,
-				)
+							var selectedNode *v1.Node
+							if tc.hasSelectedNode {
+								selectedNode = &nodes.Items[0]
+							}
+							requirements, err := GenerateAccessibilityRequirements(
+								kubeClient,
+								testDriverName,
+								"testpvc",
+								nil, /* allowedTopologies */
+								selectedNode,
+								strictTopology,
+								immediateTopology,
+								csiNodeLister,
+								nodeLister,
+							)
 
-				if tc.expectError && err == nil {
-					t.Fatalf("expected error but got none")
-				}
-				if !tc.expectError && err != nil {
-					t.Fatalf("expected no error but got: %v", err)
-				}
-				expectedRequisite := tc.expectedRequisite
-				if strictTopology && tc.expectedStrictRequisite != nil {
-					expectedRequisite = tc.expectedStrictRequisite
-				}
-				if expectedRequisite == nil {
-					if requirements != nil {
-						t.Fatalf("expected requirements to be nil but got requisite: %v", requirements.Requisite)
-					}
-				} else {
-					if requirements == nil {
-						t.Fatalf("expected requisite to be %v but requirements is nil", expectedRequisite)
-					}
-					if !requisiteEqual(requirements.Requisite, expectedRequisite) {
-						t.Errorf("expected requisite %v; got: %v", tc.expectedRequisite, requirements.Requisite)
+							expectError := tc.expectError
+							expectedRequisite := tc.expectedRequisite
+							if strictTopology && tc.expectedStrictRequisite != nil {
+								expectedRequisite = tc.expectedStrictRequisite
+							}
+							if !immediateTopology && selectedNode == nil {
+								expectedRequisite = nil
+								expectError = false
+							}
+
+							if expectError && err == nil {
+								t.Fatalf("expected error but got none")
+							}
+							if !expectError && err != nil {
+								t.Fatalf("expected no error but got: %v", err)
+							}
+
+							if expectedRequisite == nil {
+								if requirements != nil {
+									t.Fatalf("expected requirements to be nil but got requisite: %v", requirements.Requisite)
+								}
+							} else {
+								if requirements == nil {
+									t.Fatalf("expected requisite to be %v but requirements is nil", expectedRequisite)
+								}
+								if !requisiteEqual(requirements.Requisite, expectedRequisite) {
+									t.Errorf("expected requisite %v; got: %v", expectedRequisite, requirements.Requisite)
+								}
+							}
+						})
 					}
-				}
-			})
-		}
+				})
+			}
+		})
 	}
 }
 
@@ -1368,56 +1397,59 @@ func TestPreferredTopologies(t *testing.T) {
 	}
 
 	for name, tc := range testcases {
-		for _, strictTopology := range []bool{false, true} {
-			if strictTopology {
-				name += " with strict topology"
-			}
-			t.Run(name, func(t *testing.T) {
-
-				nodes := buildNodes(tc.nodeLabels)
-				csiNodes := buildCSINodes(tc.topologyKeys)
+		t.Run(name, func(t *testing.T) {
+			for strictTopology, withOrWithout := range withWithout {
+				t.Run(withOrWithout+" strict topology", func(t *testing.T) {
+					for immediateTopology, withOrWithout := range withWithout {
+						t.Run(withOrWithout+" immediate topology", func(t *testing.T) {
+							nodes := buildNodes(tc.nodeLabels)
+							csiNodes := buildCSINodes(tc.topologyKeys)
 
-				kubeClient := fakeclientset.NewSimpleClientset(nodes, csiNodes)
-				selectedNode := &nodes.Items[0]
+							kubeClient := fakeclientset.NewSimpleClientset(nodes, csiNodes)
+							selectedNode := &nodes.Items[0]
 
-				_, csiNodeLister, nodeLister, _, _, stopChan := listers(kubeClient)
-				defer close(stopChan)
+							_, csiNodeLister, nodeLister, _, _, stopChan := listers(kubeClient)
+							defer close(stopChan)
 
-				requirements, err := GenerateAccessibilityRequirements(
-					kubeClient,
-					testDriverName,
-					"testpvc",
-					tc.allowedTopologies,
-					selectedNode,
-					strictTopology,
-					csiNodeLister,
-					nodeLister,
-				)
+							requirements, err := GenerateAccessibilityRequirements(
+								kubeClient,
+								testDriverName,
+								"testpvc",
+								tc.allowedTopologies,
+								selectedNode,
+								strictTopology,
+								immediateTopology,
+								csiNodeLister,
+								nodeLister,
+							)
 
-				if tc.expectError && err == nil {
-					t.Fatalf("expected error but got none")
-				}
-				if !tc.expectError && err != nil {
-					t.Fatalf("expected no error but got: %v", err)
-				}
-				expectedPreferred := tc.expectedPreferred
-				if strictTopology && tc.expectedStrictPreferred != nil {
-					expectedPreferred = tc.expectedStrictPreferred
-				}
-				if expectedPreferred == nil {
-					if requirements != nil {
-						t.Fatalf("expected requirements to be nil but got preferred: %v", requirements.Preferred)
-					}
-				} else {
-					if requirements == nil {
-						t.Fatalf("expected preferred to be %v but requirements is nil", expectedPreferred)
+							if tc.expectError && err == nil {
+								t.Fatalf("expected error but got none")
+							}
+							if !tc.expectError && err != nil {
+								t.Fatalf("expected no error but got: %v", err)
+							}
+							expectedPreferred := tc.expectedPreferred
+							if strictTopology && tc.expectedStrictPreferred != nil {
+								expectedPreferred = tc.expectedStrictPreferred
+							}
+							if expectedPreferred == nil {
+								if requirements != nil {
+									t.Fatalf("expected requirements to be nil but got preferred: %v", requirements.Preferred)
+								}
+							} else {
+								if requirements == nil {
+									t.Fatalf("expected preferred to be %v but requirements is nil", expectedPreferred)
+								}
+								if !helper.Semantic.DeepEqual(requirements.Preferred, expectedPreferred) {
+									t.Errorf("expected requisite %v; got: %v", tc.expectedPreferred, requirements.Preferred)
+								}
+							}
+						})
 					}
-					if !helper.Semantic.DeepEqual(requirements.Preferred, expectedPreferred) {
-						t.Errorf("expected requisite %v; got: %v", tc.expectedPreferred, requirements.Preferred)
-					}
-				}
-			})
-		}
+				})
+			}
+		})
 	}
 }