Repository: kubernetes-sigs/aws-ebs-csi-driver
Pull request #780 (2021-03-05 21:35:02)

Release 0.8.2
Patch 0.8 version with leaked volume fix

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

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/aws-ebs-csi-driver/pull/780#" title="Author self-approved">AndyXiangLi</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **d-nishi** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @d-nishi` 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-sigs%2Faws-ebs-csi-driver).

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

- **[OWNERS](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/release-0.8/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":["d-nishi"]} -->
k8s-ci-robot: @AndyXiangLi: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-verify | af21925f79e0fed513f4908697e1c61d6ec6ab00 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-verify/1367951816402145280) | `/test pull-aws-ebs-csi-driver-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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: @AndyXiangLi: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-verify | af21925f79e0fed513f4908697e1c61d6ec6ab00 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-verify/1367951816402145280) | `/test pull-aws-ebs-csi-driver-verify`
pull-aws-ebs-csi-driver-unit | af21925f79e0fed513f4908697e1c61d6ec6ab00 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-unit/1367951816427311104) | `/test pull-aws-ebs-csi-driver-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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 -->
coveralls: ## Pull Request Test Coverage Report for [Build 1683](https://coveralls.io/builds/37700147)

* **6** of **7**   **(85.71%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.1%**) to **81.818%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [pkg/cloud/cloud.go](https://coveralls.io/builds/37700147/source?filename=pkg%2Fcloud%2Fcloud.go#L342) | 6 | 7 | 85.71%
<!-- | **Total:** | **6** | **7** | **85.71%** | -->


|  Totals | [![Coverage Status](https://coveralls.io/builds/37700147/badge)](https://coveralls.io/builds/37700147) |
| :-- | --: |
| Change from base [Build 1438](https://coveralls.io/builds/36141413): |  0.1% |
| Covered Lines: | 1629 |
| Relevant Lines: | 1991 |

---
##### 💛  - [Coveralls](https://coveralls.io)

k8s-ci-robot: @AndyXiangLi: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-e2e-multi-az | 6546e29bb631f946156032ce938d160c0fbe48fd | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-multi-az/1367954054562451456) | `/test pull-aws-ebs-csi-driver-e2e-multi-az`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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: @AndyXiangLi: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-e2e-multi-az | 6546e29bb631f946156032ce938d160c0fbe48fd | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-multi-az/1367954054562451456) | `/test pull-aws-ebs-csi-driver-e2e-multi-az`
pull-aws-ebs-csi-driver-e2e-single-az | 6546e29bb631f946156032ce938d160c0fbe48fd | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-single-az/1367954054528897024) | `/test pull-aws-ebs-csi-driver-e2e-single-az`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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 -->
wongma7: ```
 Failed to compile e2e:
../../../../pkg/mod/github.com/container-storage-interface/spec@v1.2.0/lib/go/csi/csi.pb.go:9:2: missing go.sum entry for module providing package github.com/golang/protobuf/proto (imported by github.com/container-storage-interface/spec/lib/go/csi); to add:
	go get github.com/container-storage-interface/spec/lib/go/csi@v1.2.0
../../../../pkg/mod/github.com/container-storage-interface/spec@v1.2.0/lib/go/csi/csi.pb.go:10:2: missing go.sum entry for module providing package github.com/golang/protobuf/protoc-gen-go/descriptor (imported by github.com/container-storage-interface/spec/lib/go/csi); to add:
	go get github.com/container-storage-interface/spec/lib/go/csi@v1.2.0
../../../../pkg/mod/google.golang.org/grpc@v1.26.0/internal/binarylog/method_logger.go:28:2: missing go.sum entry for module providing package github.com/golang/protobuf/ptypes (imported by github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/driver); to add:
	go get github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/driver
../../../../pkg/mod/google.golang.org/genproto@v0.0.0-20191220175831-5c49e3ecc1c1/googleapis/rpc/status/status.pb.go:11:2: missing go.sum entry for module providing package github.com/golang/protobuf/ptypes/any (imported by google.golang.org/genproto/googleapis/rpc/status); to add:
	go get google.golang.org/genproto/googleapis/rpc/status@v0.0.0-20191220175831-5c49e3ecc1c1
../../../../pkg/mod/google.golang.org/grpc@v1.26.0/binarylog/grpc_binarylog_v1/binarylog.pb.go:9:8: missing go.sum entry for module providing package github.com/golang/protobuf/ptypes/duration (imported by google.golang.org/grpc/binarylog/grpc_binarylog_v1); to add:
	go get google.golang.org/grpc/binarylog/grpc_binarylog_v1@v1.26.0
../../../../pkg/mod/github.com/container-storage-interface/spec@v1.2.0/lib/go/csi/csi.pb.go:11:2: missing go.sum entry for module providing package github.com/golang/protobuf/ptypes/timestamp (imported by github.com/container-storage-interface/spec/lib/go/csi); to add:
	go get github.com/container-storage-interface/spec/lib/go/csi@v1.2.0
../../../../pkg/mod/github.com/container-storage-interface/spec@v1.2.0/lib/go/csi/csi.pb.go:12:2: missing go.sum entry for module providing package github.com/golang/protobuf/ptypes/wrappers (imported by github.com/container-storage-interface/spec/lib/go/csi); to add:
	go get github.com/container-storage-interface/spec/lib/go/csi@v1.2.0
../../../../pkg/mod/k8s.io/apimachinery@v0.17.4-beta.0/pkg/util/diff/diff.go:27:2: missing go.sum entry for module providing package github.com/google/go-cmp/cmp (imported by k8s.io/apimachinery/pkg/util/diff); to add:
	go get k8s.io/apimachinery/pkg/util/diff@v0.17.3
tests/e2e/testsuites/dynamically_provisioned_read_only_volume_tester.go:26:2: missing go.sum entry for module providing package github.com/onsi/gomega (imported by github.com/kubernetes-sigs/aws-ebs-csi-driver/tests/e2e/testsuites); to add:
	go get github.com/kubernetes-sigs/aws-ebs-csi-driver/tests/e2e/testsuites
../../../../pkg/mod/k8s.io/kubernetes@v1.17.3/test/e2e/framework/util.go:46:2: missing go.sum entry for module providing package github.com/onsi/gomega/types (imported by k8s.io/kubernetes/test/e2e/framework); to add:
	go get k8s.io/kubernetes/test/e2e/framework@v1.17.3
../../../../pkg/mod/sigs.k8s.io/yaml@v1.1.0/yaml.go:11:2: missing go.sum entry for module providing package gopkg.in/yaml.v2 (imported by k8s.io/kubernetes/test/utils/image); to add:
	go get k8s.io/kubernetes/test/utils/image@v1.17.3 
```
?
/retest
k8s-ci-robot: @AndyXiangLi: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-e2e-single-az | 6546e29bb631f946156032ce938d160c0fbe48fd | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-single-az/1367954054528897024) | `/test pull-aws-ebs-csi-driver-e2e-single-az`
pull-aws-ebs-csi-driver-e2e-multi-az | 6546e29bb631f946156032ce938d160c0fbe48fd | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-multi-az/1367960461269536768) | `/test pull-aws-ebs-csi-driver-e2e-multi-az`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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: @AndyXiangLi: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-e2e-multi-az | 6546e29bb631f946156032ce938d160c0fbe48fd | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-multi-az/1367960461269536768) | `/test pull-aws-ebs-csi-driver-e2e-multi-az`
pull-aws-ebs-csi-driver-e2e-single-az | 443b3ce62d0df61ebeb5b9c8eeeda54138f2a96c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-single-az/1367964663479799808) | `/test pull-aws-ebs-csi-driver-e2e-single-az`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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: @AndyXiangLi: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-e2e-single-az | 443b3ce62d0df61ebeb5b9c8eeeda54138f2a96c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-single-az/1367964663479799808) | `/test pull-aws-ebs-csi-driver-e2e-single-az`
pull-aws-ebs-csi-driver-e2e-multi-az | 443b3ce62d0df61ebeb5b9c8eeeda54138f2a96c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-multi-az/1367964663521742848) | `/test pull-aws-ebs-csi-driver-e2e-multi-az`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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: @AndyXiangLi: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-aws-ebs-csi-driver-e2e-single-az | 443b3ce62d0df61ebeb5b9c8eeeda54138f2a96c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-single-az/1367964663479799808) | `/test pull-aws-ebs-csi-driver-e2e-single-az`
pull-aws-ebs-csi-driver-e2e-multi-az | 443b3ce62d0df61ebeb5b9c8eeeda54138f2a96c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-e2e-multi-az/1367964663521742848) | `/test pull-aws-ebs-csi-driver-e2e-multi-az`
pull-aws-ebs-csi-driver-migration-test-latest | 443b3ce62d0df61ebeb5b9c8eeeda54138f2a96c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_aws-ebs-csi-driver/780/pull-aws-ebs-csi-driver-migration-test-latest/1367964663551102976) | `/test pull-aws-ebs-csi-driver-migration-test-latest`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=aws-ebs-csi-driver&pr=780). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3AAndyXiangLi). 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-sigs/aws-ebs-csi-driver/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 -->

Patch:
diff --git a/.travis.yml b/.travis.yml
index 5c9344f4..08bd05da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,7 @@ env:
     - GO111MODULE=on
 
 go:
-  - "1.14.1"
+  - "1.15.6"
 
 before_install:
   - go get github.com/mattn/goveralls
diff --git a/CHANGELOG-0.x.md b/CHANGELOG-0.x.md
index 1a61e088..01663a40 100644
--- a/CHANGELOG-0.x.md
+++ b/CHANGELOG-0.x.md
@@ -1,3 +1,15 @@
+# v0.8.2
+
+## Notable changes
+- delete leaked volume if driver don't know the volume status
+- Refactor e2e testing scripts to be more reusable and use them instead… ([#694](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/pull/694), [@wongma7](https://github.com/wongma7))
+
+### Bug fixes
+* delete leaked volume if driver don't know the volume status ([#771](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/pull/771), [@AndyXiangLi](https://github.com/AndyXiangLi))
+* Update test k8s version to 1.18.16 ([#759](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/pull/759), [@ayberk](https://github.com/ayberk))
+* Bring Go to 1.15.6 in Travis ([#648](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/pull/648), [@gliptak](https://github.com/gliptak))
+* Update to golang@1.15.6 ([#699](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/pull/699), [@ialidzhikov](https://github.com/ialidzhikov))
+
 # v0.8.1
 
 ## Notable changes
diff --git a/Dockerfile b/Dockerfile
index d1b42b57..aa6464e6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-FROM golang:1.14.1-stretch AS builder
+FROM golang:1.15.6 AS builder
 WORKDIR /go/src/github.com/kubernetes-sigs/aws-ebs-csi-driver
 COPY . .
 RUN make
diff --git a/Makefile b/Makefile
index 53fd4b14..f793e099 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@
 
 PKG=github.com/kubernetes-sigs/aws-ebs-csi-driver
 IMAGE?=amazon/aws-ebs-csi-driver
-VERSION=v0.8.1
+VERSION=v0.8.2
 VERSION_AMAZONLINUX=$(VERSION)-amazonlinux
 GIT_COMMIT?=$(shell git rev-parse HEAD)
 BUILD_DATE?=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
@@ -73,22 +73,31 @@ test-sanity:
 	#go test -v ./tests/sanity/...
 	echo "succeed"
 
-bin/k8s-e2e-tester: | bin
-	go get github.com/aws/aws-k8s-tester/e2e/tester/cmd/k8s-e2e-tester@master
-
 .PHONY: test-e2e-single-az
-test-e2e-single-az: bin/k8s-e2e-tester
-	TESTCONFIG=./tester/single-az-config.yaml ${GOBIN}/k8s-e2e-tester
+test-e2e-single-az:
+	AWS_REGION=us-west-2 \
+	AWS_AVAILABILITY_ZONES=us-west-2a \
+	TEST_PATH=./tests/e2e/... \
+	GINKGO_FOCUS="\[ebs-csi-e2e\] \[single-az\]" \
+	GINKGO_SKIP="\"sc1\"|\"st1\"" \
+	./hack/e2e/run.sh
 
 .PHONY: test-e2e-multi-az
-test-e2e-multi-az: bin/k8s-e2e-tester
-	TESTCONFIG=./tester/multi-az-config.yaml ${GOBIN}/k8s-e2e-tester
+test-e2e-multi-az:
+	AWS_REGION=us-west-2 \
+	AWS_AVAILABILITY_ZONES=us-west-2a,us-west-2b,us-west-2c \
+	TEST_PATH=./tests/e2e/... \
+	GINKGO_FOCUS="\[ebs-csi-e2e\] \[multi-az\]" \
+	./hack/e2e/run.sh
 
 .PHONY: test-e2e-migration
 test-e2e-migration:
-	AWS_REGION=us-west-2 AWS_AVAILABILITY_ZONES=us-west-2a GINKGO_FOCUS="\[ebs-csi-migration\]" ./hack/run-e2e-test
-	# TODO: enable migration test to use new framework
-	#TESTCONFIG=./tester/migration-test-config.yaml go run tester/cmd/main.go
+	AWS_REGION=us-west-2 \
+	AWS_AVAILABILITY_ZONES=us-west-2a \
+	TEST_PATH=./tests/e2e-migration/... \
+	GINKGO_FOCUS="\[ebs-csi-migration\]" \
+	EBS_CHECK_MIGRATION=true \
+	./hack/e2e/run.sh
 
 .PHONY: image-release
 image-release:
diff --git a/charts/aws-ebs-csi-driver/Chart.yaml b/charts/aws-ebs-csi-driver/Chart.yaml
index 539c8c5b..294ff335 100644
--- a/charts/aws-ebs-csi-driver/Chart.yaml
+++ b/charts/aws-ebs-csi-driver/Chart.yaml
@@ -1,5 +1,5 @@
 apiVersion: v1
-appVersion: "0.8.0"
+appVersion: "0.8.2"
 name: aws-ebs-csi-driver
 description: A Helm chart for AWS EBS CSI Driver
 version: 0.7.0
diff --git a/charts/aws-ebs-csi-driver/values.yaml b/charts/aws-ebs-csi-driver/values.yaml
index 8c6a420f..722cbd53 100644
--- a/charts/aws-ebs-csi-driver/values.yaml
+++ b/charts/aws-ebs-csi-driver/values.yaml
@@ -6,7 +6,7 @@ replicaCount: 2
 
 image:
   repository: k8s.gcr.io/provider-aws/aws-ebs-csi-driver
-  tag: "v0.8.1"
+  tag: "v0.8.2"
   pullPolicy: IfNotPresent
 
 sidecars:
diff --git a/deploy/kubernetes/base/clusterrole-attacher.yaml b/deploy/kubernetes/base/clusterrole-attacher.yaml
index a41b9f5d..5805412a 100644
--- a/deploy/kubernetes/base/clusterrole-attacher.yaml
+++ b/deploy/kubernetes/base/clusterrole-attacher.yaml
@@ -19,3 +19,6 @@ rules:
   - apiGroups: ["storage.k8s.io"]
     resources: ["volumeattachments"]
     verbs: ["get", "list", "watch", "update", "patch"]
+  - apiGroups: ["storage.k8s.io"]
+    resources: ["volumeattachments/status"]
+    verbs: ["patch"]
diff --git a/deploy/kubernetes/overlays/stable/arm64/kustomization.yaml b/deploy/kubernetes/overlays/stable/arm64/kustomization.yaml
index 099a97c4..f2dc5f73 100644
--- a/deploy/kubernetes/overlays/stable/arm64/kustomization.yaml
+++ b/deploy/kubernetes/overlays/stable/arm64/kustomization.yaml
@@ -4,7 +4,7 @@ bases:
   - ../../../base
 images:
   - name: k8s.gcr.io/provider-aws/aws-ebs-csi-driver
-    newTag: v0.8.1
+    newTag: v0.8.2
   - name: quay.io/k8scsi/csi-provisioner
     newName: raspbernetes/csi-external-provisioner
     newTag: "1.6.0"
diff --git a/deploy/kubernetes/overlays/stable/kustomization.yaml b/deploy/kubernetes/overlays/stable/kustomization.yaml
index a815e3dd..10b41185 100644
--- a/deploy/kubernetes/overlays/stable/kustomization.yaml
+++ b/deploy/kubernetes/overlays/stable/kustomization.yaml
@@ -4,7 +4,7 @@ bases:
   - ../../base
 images:
   - name: k8s.gcr.io/provider-aws/aws-ebs-csi-driver
-    newTag: v0.8.1
+    newTag: v0.8.2
   - name: quay.io/k8scsi/csi-provisioner
     newTag: v1.5.0
   - name: quay.io/k8scsi/csi-attacher
diff --git a/docs/README.md b/docs/README.md
index 0131c4aa..93837aad 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -65,6 +65,7 @@ Following sections are Kubernetes specific. If you are Kubernetes user, use foll
 |AWS EBS CSI Driver Version | Image                                            |
 |---------------------------|--------------------------------------------------|
 |master branch              |amazon/aws-ebs-csi-driver:latest                  |
+|v0.8.2                     |k8s.gcr.io/provider-aws/aws-ebs-csi-driver:v0.8.2 |
 |v0.8.1                     |k8s.gcr.io/provider-aws/aws-ebs-csi-driver:v0.8.1 |
 |v0.7.1                     |amazon/aws-ebs-csi-driver:v0.7.1                  |
 |v0.6.0                     |amazon/aws-ebs-csi-driver:v0.6.0                  |
@@ -161,7 +162,7 @@ To make sure dynamically provisioned EBS volumes have all tags that the in-tree
 Please go through [CSI Spec](https://github.com/container-storage-interface/spec/blob/master/spec.md) and [General CSI driver development guideline](https://kubernetes-csi.github.io/docs/developing.html) to get some basic understanding of CSI driver before you start.
 
 ### Requirements
-* Golang 1.14.+
+* Golang 1.15.+
 * [Ginkgo](https://github.com/onsi/ginkgo) in your PATH for integration testing and end-to-end testing
 * Docker 17.05+ for releasing
 
diff --git a/go.sum b/go.sum
index 28abc539..e67c21f0 100644
--- a/go.sum
+++ b/go.sum
@@ -304,7 +304,6 @@ github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
 github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
 github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
@@ -332,7 +331,6 @@ github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo
 github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -431,7 +429,6 @@ github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 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=
@@ -564,7 +561,6 @@ golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -640,7 +636,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191220220014-0732a990476f h1:72l8qCJ1nGxMGH26QVBVIxKd/D34cfGt0OvrPtpemyY=
 golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -649,7 +644,6 @@ golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fq
 golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
diff --git a/hack/utils/helm.sh b/hack/e2e/helm.sh
old mode 100755
new mode 100644
similarity index 92%
rename from hack/utils/helm.sh
rename to hack/e2e/helm.sh
index 95ab5c38..500441e1
--- a/hack/utils/helm.sh
+++ b/hack/e2e/helm.sh
@@ -2,7 +2,7 @@
 
 set -uo pipefail
 
-helm::install() {
+function helm_install() {
   INSTALL_PATH=${1}
   if [[ ! -e ${INSTALL_PATH}/helm ]]; then
     curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
diff --git a/hack/utils/kops.sh b/hack/utils/kops.sh
deleted file mode 100644
index 0cddae6c..00000000
--- a/hack/utils/kops.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-set -uo pipefail
-
-OS_ARCH=$(go env GOOS)-amd64
-
-kops::install() {
-  INSTALL_PATH=${1}
-  KOPS_VERSION=${2}
-  if [[ ! -e ${INSTALL_PATH}/kops ]]; then
-    KOPS_DOWNLOAD_URL=https://github.com/kubernetes/kops/releases/download/v${KOPS_VERSION}/kops-${OS_ARCH}
-    curl -L -X GET "${KOPS_DOWNLOAD_URL}" -o "${INSTALL_PATH}"/kops
-    chmod +x "${INSTALL_PATH}"/kops
-  fi
-}
diff --git a/hack/utils/tiller-rbac.yaml b/hack/utils/tiller-rbac.yaml
deleted file mode 100644
index 1fcf47dc..00000000
--- a/hack/utils/tiller-rbac.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: tiller
-  namespace: kube-system
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
-  name: tiller
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: cluster-admin
-subjects:
-  - kind: ServiceAccount
-    name: tiller
-    namespace: kube-system
diff --git a/pkg/cloud/cloud.go b/pkg/cloud/cloud.go
index 16407b95..cd2db125 100644
--- a/pkg/cloud/cloud.go
+++ b/pkg/cloud/cloud.go
@@ -336,6 +336,13 @@ func (c *cloud) CreateDisk(ctx context.Context, volumeName string, diskOptions *
 	}
 
 	if err := c.waitForVolume(ctx, volumeID); err != nil {
+		// To avoid leaking volume, we should delete the volume just created
+		// TODO: Need to figure out how to handle DeleteDisk failed scenario instead of just log the error
+		if _, error := c.DeleteDisk(ctx, volumeID); error != nil {
+			klog.Errorf("%v failed to be deleted, this may cause volume leak", volumeID)
+		} else {
+			klog.V(5).Infof("%v is deleted because it is not in desired state within retry limit", volumeID)
+		}
 		return nil, fmt.Errorf("failed to get an available volume in EC2: %v", err)
 	}
 


Test patch:
diff --git a/hack/e2e/.gitignore b/hack/e2e/.gitignore
new file mode 100644
index 00000000..7eb9af1f
--- /dev/null
+++ b/hack/e2e/.gitignore
@@ -0,0 +1,1 @@
+/csi-test-artifacts
diff --git a/hack/e2e/README.md b/hack/e2e/README.md
new file mode 100644
index 00000000..108d66ac
--- /dev/null
+++ b/hack/e2e/README.md
@@ -0,0 +1,26 @@
+# Usage
+
+run.sh will build and push a driver image, create a kops cluster, helm install the driver pointing to the built image, run ginkgo tests, then clean everything up.
+
+See below for an example.
+
+KOPS_STATE_FILE is an S3 bucket you have write access to.
+
+TEST_ID is a token used for idempotency.
+
+For more details, see the script itself.
+
+For more examples, see the top-level Makefile.
+
+```
+TEST_PATH=./tests/e2e-migration/... \
+EBS_CHECK_MIGRATION=true \
+TEST_ID=18512 \
+CLEAN=false \
+KOPS_STATE_FILE=s3://mattwon \
+AWS_REGION=us-west-2 \
+AWS_AVAILABILITY_ZONES=us-west-2a \
+GINKGO_FOCUS=Dynamic.\*xfs.\*should.store.data \
+GINKGO_NODES=1 \
+./hack/e2e/run.sh
+```
diff --git a/hack/e2e/ebs.sh b/hack/e2e/ebs.sh
new file mode 100644
index 00000000..0ca3646b
--- /dev/null
+++ b/hack/e2e/ebs.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+set -uo pipefail
+
+BASE_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
+source "${BASE_DIR}"/util.sh
+
+function ebs_check_migration() {
+  loudecho "Checking migration"
+  # There should have been no calls to the in-tree driver kubernetes.io/aws-ebs but many calls to ebs.csi.aws.com
+  # Find the controller-manager log and read its metrics to verify
+  NODE=$(kubectl get node -l kubernetes.io/role=master -o json | jq -r ".items[].metadata.name")
+  kubectl port-forward kube-controller-manager-"${NODE}" 10252:10252 -n kube-system &
+
+  # Ensure port forwarding succeeded
+  n=0
+  until [ "$n" -ge 30 ]; do
+    set +e
+    HEALTHZ=$(curl -s 127.0.0.1:10252/healthz)
+    set -e
+    if [[ ${HEALTHZ} == "ok" ]]; then
+      loudecho "Port forwarding succeeded"
+      break
+    else
+      loudecho "Port forwarding is not yet ready"
+    fi
+    n=$((n + 1))
+    sleep 1
+  done
+  if [[ "$n" -eq 30 ]]; then
+    loudecho "Timed out waiting for port forward"
+    for PROC in $(jobs -p); do
+      kill "${PROC}"
+    done
+    return 1
+  fi
+
+  set +e
+  curl 127.0.0.1:10252/metrics -s | grep -a 'volume_operation_total_seconds_bucket{operation_name="provision",plugin_name="ebs.csi.aws.com"'
+  CSI_CALLED=${PIPESTATUS[1]}
+  set -e
+
+  set +e
+  curl 127.0.0.1:10252/metrics -s | grep -a 'volume_operation_total_seconds_bucket{operation_name="provision",plugin_name="kubernetes.io/aws-ebs"'
+  INTREE_CALLED=${PIPESTATUS[1]}
+  set -e
+
+  for PROC in $(jobs -p); do
+    kill "${PROC}"
+  done
+
+  loudecho "CSI_CALLED: ${CSI_CALLED}"
+  loudecho "INTREE_CALLED: ${INTREE_CALLED}"
+
+  # if CSI was called and In-tree was not called, return 0/true/success
+  if [ "${CSI_CALLED}" == 0 ] && [ "${INTREE_CALLED}" == 1 ]; then
+    echo 0
+  else
+    echo 1
+  fi
+}
diff --git a/hack/e2e/ecr.sh b/hack/e2e/ecr.sh
new file mode 100644
index 00000000..8f710d95
--- /dev/null
+++ b/hack/e2e/ecr.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -uo pipefail
+
+BASE_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
+source "${BASE_DIR}"/util.sh
+
+function ecr_build_and_push() {
+  REGION=${1}
+  AWS_ACCOUNT_ID=${2}
+  IMAGE_NAME=${3}
+  IMAGE_TAG=${4}
+  set +e
+  if docker images | grep "${IMAGE_NAME}" | grep "${IMAGE_TAG}"; then
+    set -e
+    loudecho "Assuming ${IMAGE_NAME}:${IMAGE_TAG} has been built and pushed"
+  else
+    set -e
+    loudecho "Building and pushing test driver image to ${IMAGE_NAME}:${IMAGE_TAG}"
+    aws ecr get-login-password --region "${REGION}" | docker login --username AWS --password-stdin "${AWS_ACCOUNT_ID}".dkr.ecr."${REGION}".amazonaws.com
+    docker build -t "${IMAGE_NAME}":"${IMAGE_TAG}" .
+    docker push "${IMAGE_NAME}":"${IMAGE_TAG}"
+  fi
+}
diff --git a/hack/e2e/kops.sh b/hack/e2e/kops.sh
new file mode 100644
index 00000000..4f7cb989
--- /dev/null
+++ b/hack/e2e/kops.sh
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+set -uo pipefail
+
+OS_ARCH=$(go env GOOS)-amd64
+
+BASE_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
+source "${BASE_DIR}"/util.sh
+
+function kops_install() {
+  INSTALL_PATH=${1}
+  KOPS_VERSION=${2}
+  if [[ ! -e ${INSTALL_PATH}/kops ]]; then
+    KOPS_DOWNLOAD_URL=https://github.com/kubernetes/kops/releases/download/v${KOPS_VERSION}/kops-${OS_ARCH}
+    curl -L -X GET "${KOPS_DOWNLOAD_URL}" -o "${INSTALL_PATH}"/kops
+    chmod +x "${INSTALL_PATH}"/kops
+  fi
+}
+
+function kops_create_cluster() {
+  SSH_KEY_PATH=${1}
+  KOPS_STATE_FILE=${2}
+  CLUSTER_NAME=${3}
+  KOPS_BIN=${4}
+  ZONES=${5}
+  INSTANCE_TYPE=${6}
+  K8S_VERSION=${7}
+  TEST_DIR=${8}
+  KOPS_FEATURE_GATES_FILE=${10}
+  KOPS_ADDITIONAL_POLICIES_FILE=${11}
+
+  loudecho "Generating SSH key $SSH_KEY_PATH"
+  if [[ ! -e ${SSH_KEY_PATH} ]]; then
+    ssh-keygen -P csi-e2e -f "${SSH_KEY_PATH}"
+  fi
+
+  set +e
+  if ${KOPS_BIN} get cluster --state "${KOPS_STATE_FILE}" "${CLUSTER_NAME}"; then
+    set -e
+    loudecho "Updating cluster $CLUSTER_NAME"
+  else
+    set -e
+    loudecho "Creating cluster $CLUSTER_NAME"
+    ${KOPS_BIN} create cluster --state "${KOPS_STATE_FILE}" \
+      --zones "${ZONES}" \
+      --node-count=3 \
+      --node-size="${INSTANCE_TYPE}" \
+      --kubernetes-version="${K8S_VERSION}" \
+      --ssh-public-key="${SSH_KEY_PATH}".pub \
+      "${CLUSTER_NAME}"
+  fi
+
+  CLUSTER_YAML_PATH=${TEST_DIR}/${CLUSTER_NAME}.yaml
+  ${KOPS_BIN} get cluster --state "${KOPS_STATE_FILE}" "${CLUSTER_NAME}" -o yaml > "${CLUSTER_YAML_PATH}"
+  cat "${KOPS_FEATURE_GATES_FILE}" >> "${CLUSTER_YAML_PATH}"
+  cat "${KOPS_ADDITIONAL_POLICIES_FILE}" >> "${CLUSTER_YAML_PATH}"
+  ${KOPS_BIN} replace --state "${KOPS_STATE_FILE}" -f "${CLUSTER_YAML_PATH}"
+  ${KOPS_BIN} update cluster --state "${KOPS_STATE_FILE}" "${CLUSTER_NAME}" --yes
+
+  loudecho "Validating cluster $CLUSTER_NAME"
+  ${KOPS_BIN} validate cluster --state "${KOPS_STATE_FILE}" --wait 10m
+  return $?
+}
+
+function kops_delete_cluster() {
+  KOPS_BIN=${1}
+  CLUSTER_NAME=${2}
+  KOPS_STATE_FILE=${3}
+  loudecho "Deleting cluster ${CLUSTER_NAME}"
+  ${KOPS_BIN} delete cluster --name "${CLUSTER_NAME}" --state "${KOPS_STATE_FILE}" --yes
+}
diff --git a/hack/e2e/run.sh b/hack/e2e/run.sh
new file mode 100755
index 00000000..595d5ef5
--- /dev/null
+++ b/hack/e2e/run.sh
@@ -0,0 +1,163 @@
+#!/bin/bash
+
+# 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.
+
+set -euo pipefail
+
+BASE_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")")
+source "${BASE_DIR}"/ebs.sh
+source "${BASE_DIR}"/ecr.sh
+source "${BASE_DIR}"/helm.sh
+source "${BASE_DIR}"/kops.sh
+source "${BASE_DIR}"/util.sh
+
+DRIVER_NAME=${DRIVER_NAME:-aws-ebs-csi-driver}
+
+TEST_ID=${TEST_ID:-$RANDOM}
+CLUSTER_NAME=test-cluster-${TEST_ID}.k8s.local
+
+TEST_DIR=${BASE_DIR}/csi-test-artifacts
+BIN_DIR=${TEST_DIR}/bin
+SSH_KEY_PATH=${TEST_DIR}/id_rsa
+
+REGION=${AWS_REGION:-us-west-2}
+ZONES=${AWS_AVAILABILITY_ZONES:-us-west-2a,us-west-2b,us-west-2c}
+INSTANCE_TYPE=${INSTANCE_TYPE:-c4.large}
+
+AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
+IMAGE_NAME=${IMAGE_NAME:-${AWS_ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${DRIVER_NAME}}
+IMAGE_TAG=${IMAGE_TAG:-${TEST_ID}}
+
+K8S_VERSION=${K8S_VERSION:-1.18.16}
+KOPS_VERSION=${KOPS_VERSION:-1.18.2}
+KOPS_STATE_FILE=${KOPS_STATE_FILE:-s3://k8s-kops-csi-e2e}
+KOPS_FEATURE_GATES_FILE=${KOPS_FEATURE_GATES_FILE:-./hack/feature-gates.yaml}
+KOPS_ADDITIONAL_POLICIES_FILE=${KOPS_ADDITIONAL_POLICIES_FILE:-./hack/additional-policies.yaml}
+
+TEST_PATH=${TEST_PATH:-"./tests/e2e/..."}
+KUBECONFIG=${KUBECONFIG:-"${HOME}/.kube/config"}
+ARTIFACTS=${ARTIFACTS:-"${TEST_DIR}/artifacts"}
+GINKGO_FOCUS=${GINKGO_FOCUS:-"\[ebs-csi-e2e\]"}
+GINKGO_SKIP=${GINKGO_SKIP:-"\[Disruptive\]"}
+GINKGO_NODES=${GINKGO_NODES:-4}
+TEST_EXTRA_FLAGS=${TEST_EXTRA_FLAGS:-}
+
+EBS_SNAPSHOT_CRD=${EBS_SNAPSHOT_CRD:-"./deploy/kubernetes/cluster/crd_snapshotter.yaml"}
+EBS_CHECK_MIGRATION=${EBS_CHECK_MIGRATION:-"false"}
+
+CLEAN=${CLEAN:-"true"}
+
+loudecho "Testing in region ${REGION} and zones ${ZONES}"
+mkdir -p "${BIN_DIR}"
+export PATH=${PATH}:${BIN_DIR}
+
+loudecho "Installing kops ${KOPS_VERSION} to ${BIN_DIR}"
+kops_install "${BIN_DIR}" "${KOPS_VERSION}"
+KOPS_BIN=${BIN_DIR}/kops
+
+loudecho "Installing helm to ${BIN_DIR}"
+helm_install "${BIN_DIR}"
+HELM_BIN=${BIN_DIR}/helm
+
+loudecho "Installing ginkgo to ${BIN_DIR}"
+GINKGO_BIN=${BIN_DIR}/ginkgo
+if [[ ! -e ${GINKGO_BIN} ]]; then
+  pushd /tmp
+  GOPATH=${TEST_DIR} GOBIN=${BIN_DIR} GO111MODULE=on go get github.com/onsi/ginkgo/ginkgo@v1.12.0
+  popd
+fi
+
+ecr_build_and_push "${REGION}" \
+  "${AWS_ACCOUNT_ID}" \
+  "${IMAGE_NAME}" \
+  "${IMAGE_TAG}"
+
+kops_create_cluster \
+  "$SSH_KEY_PATH" \
+  "$KOPS_STATE_FILE" \
+  "$CLUSTER_NAME" \
+  "$KOPS_BIN" \
+  "$ZONES" \
+  "$INSTANCE_TYPE" \
+  "$K8S_VERSION" \
+  "$TEST_DIR" \
+  "$BASE_DIR" \
+  "$KOPS_FEATURE_GATES_FILE" \
+  "$KOPS_ADDITIONAL_POLICIES_FILE"
+if [[ $? -ne 0 ]]; then
+  exit 1
+fi
+
+loudecho "Deploying driver"
+"${HELM_BIN}" upgrade --install "${DRIVER_NAME}" \
+  --namespace kube-system \
+  --set enableVolumeScheduling=true \
+  --set enableVolumeResizing=true \
+  --set enableVolumeSnapshot=true \
+  --set image.repository="${IMAGE_NAME}" \
+  --set image.tag="${IMAGE_TAG}" \
+  ./charts/"${DRIVER_NAME}"
+
+if [[ -n "${EBS_SNAPSHOT_CRD}" ]]; then
+  loudecho "Deploying snapshot CRD"
+  kubectl apply -f "$EBS_SNAPSHOT_CRD"
+  # TODO deploy snapshot controller too instead of including in helm chart
+fi
+
+loudecho "Testing focus ${GINKGO_FOCUS}"
+eval "EXPANDED_TEST_EXTRA_FLAGS=$TEST_EXTRA_FLAGS"
+set -x
+${GINKGO_BIN} -p -nodes="${GINKGO_NODES}" -v --focus="${GINKGO_FOCUS}" --skip="${GINKGO_SKIP}" "${TEST_PATH}" -- -kubeconfig="${KUBECONFIG}" -report-dir="${ARTIFACTS}" -gce-zone="${ZONES%,*}" "${EXPANDED_TEST_EXTRA_FLAGS}"
+TEST_PASSED=$?
+set +x
+loudecho "TEST_PASSED: ${TEST_PASSED}"
+
+OVERALL_TEST_PASSED="${TEST_PASSED}"
+if [[ "${EBS_CHECK_MIGRATION}" == true ]]; then
+  exec 5>&1
+  OUTPUT=$(ebs_check_migration | tee /dev/fd/5)
+  MIGRATION_PASSED=$(echo "${OUTPUT}" | tail -1)
+  loudecho "MIGRATION_PASSED: ${MIGRATION_PASSED}"
+  if [ "${TEST_PASSED}" == 0 ] && [ "${MIGRATION_PASSED}" == 0 ]; then
+    loudecho "Both test and migration passed"
+    OVERALL_TEST_PASSED=0
+  else
+    loudecho "One of test or migration failed"
+    OVERALL_TEST_PASSED=1
+  fi
+fi
+
+if [[ "${CLEAN}" == true ]]; then
+  loudecho "Cleaning"
+
+  loudecho "Removing driver"
+  ${HELM_BIN} del "${DRIVER_NAME}" \
+    --namespace kube-system
+
+  kops_delete_cluster \
+    "${KOPS_BIN}" \
+    "${CLUSTER_NAME}" \
+    "${KOPS_STATE_FILE}"
+else
+  loudecho "Not cleaning"
+fi
+
+loudecho "OVERALL_TEST_PASSED: ${OVERALL_TEST_PASSED}"
+if [[ $OVERALL_TEST_PASSED -ne 0 ]]; then
+  loudecho "FAIL!"
+  exit 1
+else
+  loudecho "SUCCESS!"
+fi
diff --git a/hack/e2e/util.sh b/hack/e2e/util.sh
new file mode 100644
index 00000000..46bb5b16
--- /dev/null
+++ b/hack/e2e/util.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -uo pipefail
+
+function loudecho() {
+  echo "###"
+  echo "## ${1}"
+  echo "#"
+}
diff --git a/hack/run-e2e-test b/hack/run-e2e-test
deleted file mode 100755
index 8338b861..00000000
--- a/hack/run-e2e-test
+++ /dev/null
@@ -1,205 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-set -euo pipefail
-
-TEST_ID=${TEST_ID:-$RANDOM}
-CLUSTER_NAME=test-cluster-${TEST_ID}
-
-BASE=$(realpath "${BASH_SOURCE[0]}")
-BASE_DIR=$(dirname "${BASE}")
-TEST_DIR=${BASE_DIR}/ebs-e2e-test
-BIN_DIR=${TEST_DIR}/bin
-SSH_KEY_PATH=${TEST_DIR}/id_rsa
-
-REGION=${AWS_REGION-us-west-2}
-ZONES=${AWS_AVAILABILITY_ZONES:-us-west-2a,us-west-2b,us-west-2c}
-INSTANCE_TYPE=${INSTANCE_TYPE:-c4.large}
-
-K8S_VERSION=${K8S_VERSION:-1.18.10}
-KOPS_VERSION=${KOPS_VERSION:-1.18.2}
-KOPS_STATE_FILE=${KOPS_STATE_FILE:-s3://k8s-kops-csi-e2e}
-
-KUBECONFIG=${KUBECONFIG:-"${HOME}/.kube/config"}
-ARTIFACTS=${ARTIFACTS:-"${TEST_DIR}/artifacts"}
-GINKGO_FOCUS=${GINKGO_FOCUS:-"\[ebs-csi-migration\]"}
-GINKGO_SKIP=${GINKGO_SKIP:-"\[Disruptive\]"}
-GINKGO_NODES=${GINKGO_NODES:-4}
-CHECK_MIGRATION=${CHECK_MIGRATION:-"true"}
-
-CLEAN=${CLEAN:-"true"}
-
-loudecho() {
-  echo "###"
-  echo "## ${1}"
-  echo "#"
-}
-
-loudecho "Testing in region ${REGION} and zones ${ZONES}"
-mkdir -p "${BIN_DIR}"
-export PATH=${PATH}:${BIN_DIR}
-
-loudecho "Installing kops ${KOPS_VERSION} to ${BIN_DIR}"
-source "${BASE_DIR}"/utils/kops.sh
-kops::install "${BIN_DIR}" "${KOPS_VERSION}"
-KOPS_BIN=${BIN_DIR}/kops
-
-loudecho "Installing helm to ${BIN_DIR}"
-source "${BASE_DIR}"/utils/helm.sh
-helm::install "${BIN_DIR}"
-HELM_BIN=${BIN_DIR}/helm
-
-loudecho "Installing ginkgo to ${BIN_DIR}"
-GINKGO_BIN=${BIN_DIR}/ginkgo
-if [[ ! -e ${GINKGO_BIN} ]]; then
-  pushd /tmp
-  GOPATH=${TEST_DIR} GOBIN=${BIN_DIR} GO111MODULE=on go get github.com/onsi/ginkgo/ginkgo@v1.12.0
-  popd
-fi
-
-AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
-IMAGE_NAME=${AWS_ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/aws-ebs-csi-driver
-IMAGE_TAG=${TEST_ID}
-set +e
-if docker images | grep "${IMAGE_NAME}" | grep "${IMAGE_TAG}"; then
-  set -e
-  loudecho "Assuming ${IMAGE_NAME}:${IMAGE_TAG} has been built and pushed"
-else
-  set -e
-  loudecho "Building and pushing test driver image to ${IMAGE_NAME}:${IMAGE_TAG}"
-  eval "$(aws ecr get-login --region "${REGION}" --no-include-email)"
-  docker build -t "${IMAGE_NAME}":"${IMAGE_TAG}" .
-  docker push "${IMAGE_NAME}":"${IMAGE_TAG}"
-fi
-
-loudecho "Generating SSH key $SSH_KEY_PATH"
-if [[ ! -e ${SSH_KEY_PATH} ]]; then
-  ssh-keygen -P csi-e2e -f "${SSH_KEY_PATH}"
-fi
-
-set +e
-if ${KOPS_BIN} get cluster --state "${KOPS_STATE_FILE}" "${CLUSTER_NAME}".k8s.local; then
-  set -e
-  loudecho "Updating cluster $CLUSTER_NAME"
-else
-  set -e
-  loudecho "Creating cluster $CLUSTER_NAME"
-  ${KOPS_BIN} create cluster --state "${KOPS_STATE_FILE}" \
-    --zones "${ZONES}" \
-    --node-count=3 \
-    --node-size="${INSTANCE_TYPE}" \
-    --kubernetes-version="${K8S_VERSION}" \
-    --ssh-public-key="${SSH_KEY_PATH}".pub \
-    "${CLUSTER_NAME}".k8s.local
-fi
-
-CLUSTER_YAML_PATH=${TEST_DIR}/${CLUSTER_NAME}.yaml
-${KOPS_BIN} get cluster --state "${KOPS_STATE_FILE}" "${CLUSTER_NAME}".k8s.local -o yaml > "${CLUSTER_YAML_PATH}"
-cat "${BASE_DIR}"/feature-gates.yaml >> "${CLUSTER_YAML_PATH}"
-cat "${BASE_DIR}"/additional-policies.yaml >> "${CLUSTER_YAML_PATH}"
-${KOPS_BIN} replace --state "${KOPS_STATE_FILE}" -f "${CLUSTER_YAML_PATH}"
-${KOPS_BIN} update cluster --state "${KOPS_STATE_FILE}" "${CLUSTER_NAME}".k8s.local --yes
-
-loudecho "Validating cluster $CLUSTER_NAME"
-${KOPS_BIN} validate cluster --state "${KOPS_STATE_FILE}" --wait 10m
-VALID=$?
-if [[ $VALID -ne 0 ]]; then
-  exit 1
-fi
-
-loudecho "Deploying driver"
-${HELM_BIN} upgrade --install aws-ebs-csi-driver \
-  --namespace kube-system \
-  --set enableVolumeScheduling=true \
-  --set enableVolumeResizing=true \
-  --set enableVolumeSnapshot=true \
-  --set image.repository="${IMAGE_NAME}" \
-  --set image.tag="${IMAGE_TAG}" \
-  ./charts/aws-ebs-csi-driver
-
-loudecho "Testing focus ${GINKGO_FOCUS}"
-set -x
-${GINKGO_BIN} -p -nodes="${GINKGO_NODES}" -v --focus="${GINKGO_FOCUS}" --skip="${GINKGO_SKIP}" ./tests/e2e-migration/... -- -kubeconfig="${KUBECONFIG}" -report-dir="${ARTIFACTS}" -gce-zone="${ZONES%,*}"
-TEST_PASSED=$?
-set +x
-
-if [[ "${CHECK_MIGRATION}" == true ]]; then
-  loudecho "Checking migration"
-  # There should have been no calls to the in-tree driver kubernetes.io/aws-ebs but many calls to ebs.csi.aws.com
-  # Find the controller-manager log and read its metrics to verify
-  NODE=$(kubectl get node -l kubernetes.io/role=master -o json | jq -r ".items[].metadata.name")
-  kubectl port-forward kube-controller-manager-"${NODE}" 10252:10252 -n kube-system &
-
-  # Ensure port forwarding succeeded
-  while true; do
-    set +e
-    HEALTHZ=$(curl -s 127.0.0.1:10252/healthz)
-    set -e
-    if [[ ${HEALTHZ} == "ok" ]]; then
-      loudecho "Port forwarding succeeded"
-      break
-    else
-      loudecho "Port forwarding is not yet ready"
-    fi
-    sleep 1
-  done
-
-  set +e
-  curl 127.0.0.1:10252/metrics -s | grep -a 'volume_operation_total_seconds_bucket{operation_name="provision",plugin_name="ebs.csi.aws.com"'
-  CSI_CALLED=${PIPESTATUS[1]}
-  set -e
-
-  set +e
-  curl 127.0.0.1:10252/metrics -s | grep -a 'volume_operation_total_seconds_bucket{operation_name="provision",plugin_name="kubernetes.io/aws-ebs"'
-  INTREE_CALLED=${PIPESTATUS[1]}
-  set -e
-
-  for PROC in $(jobs -p); do
-    kill "${PROC}"
-  done
-
-  loudecho "CSI_CALLED: ${CSI_CALLED}"
-  loudecho "INTREE_CALLED: ${INTREE_CALLED}"
-
-  # TEST_PASSED if tests passed, CSI was called, and In-tree was not called
-  if [ "${TEST_PASSED}" == 0 ] && [ "${CSI_CALLED}" == 0 ] && [ "${INTREE_CALLED}" == 1 ]; then
-    TEST_PASSED=0
-  else
-    TEST_PASSED=1
-  fi
-fi
-
-if [[ "${CLEAN}" == true ]]; then
-  loudecho "Cleaning"
-
-  loudecho "Removing driver"
-  ${HELM_BIN} del aws-ebs-csi-driver
-
-  loudecho "Deleting cluster ${CLUSTER_NAME}"
-  ${KOPS_BIN} delete cluster --name "${CLUSTER_NAME}".k8s.local --state "${KOPS_STATE_FILE}" --yes
-
-  rm -rf "${TEST_DIR}"
-else
-  loudecho "Not cleaning"
-fi
-
-loudecho "TEST_PASSED: ${TEST_PASSED}"
-if [[ $TEST_PASSED -ne 0 ]]; then
-  loudecho "FAIL!"
-  exit 1
-else
-  loudecho "SUCCESS!"
-fi
diff --git a/hack/run-integration-test b/hack/run-integration-test
deleted file mode 100755
index 81b154a1..00000000
--- a/hack/run-integration-test
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-# Hard-coded version is needed in case GitHub API rate limit is exceeded.
-# TODO: When aws-k8s-tester becomes a full release (https://developer.github.com/v3/repos/releases/#get-the-latest-release), use:
-# $(shell curl -s --request GET --url https://api.github.com/repos/aws/aws-k8s-tester/releases/latest | jq -r '.tag_name? // "<current version number>"')
-AWS_K8S_TESTER_VERSION=$(curl -s --request GET --url https://api.github.com/repos/aws/aws-k8s-tester/tags | jq -r '.[0]?.name // "0.2.5"')
-AWS_K8S_TESTER_OS_ARCH=$(go env GOOS)-amd64
-AWS_K8S_TESTER_DOWNLOAD_URL=https://github.com/aws/aws-k8s-tester/releases/download/${AWS_K8S_TESTER_VERSION}/aws-k8s-tester-${AWS_K8S_TESTER_VERSION}-${AWS_K8S_TESTER_OS_ARCH}
-AWS_K8S_TESTER_PATH=/tmp/aws-k8s-tester
-
-VPC_ID_FLAG=""
-if [ -z "$AWS_K8S_TESTER_VPC_ID" ]; then
-    VPC_ID_FLAG=--vpc-id=${AWS_K8S_TESTER_VPC_ID}
-fi
-
-PR_NUM_FLAG=""
-if [ -z "$PULL_NUMBER" ]; then
-    PR_NUM_FLAG=--pr-num=${PULL_NUMBER}
-fi
-
-curl -L ${AWS_K8S_TESTER_DOWNLOAD_URL} -o ${AWS_K8S_TESTER_PATH}
-chmod +x ${AWS_K8S_TESTER_PATH}
-${AWS_K8S_TESTER_PATH} csi test integration --terminate-on-exit=true --timeout=20m ${PR_NUM_FLAG} ${VPC_ID_FLAG}
diff --git a/pkg/cloud/cloud_test.go b/pkg/cloud/cloud_test.go
index 225ab76c..e4c81e41 100644
--- a/pkg/cloud/cloud_test.go
+++ b/pkg/cloud/cloud_test.go
@@ -41,14 +41,15 @@ const (
 
 func TestCreateDisk(t *testing.T) {
 	testCases := []struct {
-		name               string
-		volumeName         string
-		volState           string
-		diskOptions        *DiskOptions
-		expDisk            *Disk
-		expErr             error
-		expCreateVolumeErr error
-		expDescVolumeErr   error
+		name                string
+		volumeName          string
+		volState            string
+		diskOptions         *DiskOptions
+		expDisk             *Disk
+		cleanUpFailedVolume bool
+		expErr              error
+		expCreateVolumeErr  error
+		expDescVolumeErr    error
 	}{
 		{
 			name:       "success: normal",
@@ -163,7 +164,7 @@ func TestCreateDisk(t *testing.T) {
 			expErr: nil,
 		},
 		{
-			name:       "fail: CreateVolume returned CreateVolume error",
+			name:       "fail: ec2.CreateVolume returned CreateVolume error",
 			volumeName: "vol-test-name-error",
 			diskOptions: &DiskOptions{
 				CapacityBytes:    util.GiBToBytes(1),
@@ -174,7 +175,7 @@ func TestCreateDisk(t *testing.T) {
 			expCreateVolumeErr: fmt.Errorf("CreateVolume generic error"),
 		},
 		{
-			name:       "fail: CreateVolume returned a DescribeVolumes error",
+			name:       "fail: ec2.DescribeVolumes error after volume created",
 			volumeName: "vol-test-name-error",
 			volState:   "creating",
 			diskOptions: &DiskOptions{
@@ -182,11 +183,12 @@ func TestCreateDisk(t *testing.T) {
 				Tags:             map[string]string{VolumeNameTagKey: "vol-test"},
 				AvailabilityZone: "",
 			},
-			expErr:             fmt.Errorf("could not create volume in EC2: DescribeVolumes generic error"),
-			expCreateVolumeErr: fmt.Errorf("DescribeVolumes generic error"),
+			expErr:              fmt.Errorf("failed to get an available volume in EC2: DescribeVolumes generic error"),
+			expDescVolumeErr:    fmt.Errorf("DescribeVolumes generic error"),
+			cleanUpFailedVolume: true,
 		},
 		{
-			name:       "fail: CreateVolume returned a volume with wrong state",
+			name:       "fail: Volume is not ready to use, volume stuck in creating status and controller timed out waiting for the condition",
 			volumeName: "vol-test-name-error",
 			volState:   "creating",
 			diskOptions: &DiskOptions{
@@ -194,7 +196,8 @@ func TestCreateDisk(t *testing.T) {
 				Tags:             map[string]string{VolumeNameTagKey: "vol-test"},
 				AvailabilityZone: "",
 			},
-			expErr: fmt.Errorf("failed to get an available volume in EC2: timed out waiting for the condition"),
+			cleanUpFailedVolume: true,
+			expErr:              fmt.Errorf("failed to get an available volume in EC2: timed out waiting for the condition"),
 		},
 		{
 			name:       "success: normal from snapshot",
@@ -243,7 +246,9 @@ func TestCreateDisk(t *testing.T) {
 			if len(tc.diskOptions.SnapshotID) > 0 {
 				mockEC2.EXPECT().DescribeSnapshotsWithContext(gomock.Eq(ctx), gomock.Any()).Return(&ec2.DescribeSnapshotsOutput{Snapshots: []*ec2.Snapshot{snapshot}}, nil).AnyTimes()
 			}
-
+			if tc.cleanUpFailedVolume == true {
+				mockEC2.EXPECT().DeleteVolumeWithContext(gomock.Eq(ctx), gomock.Any()).Return(&ec2.DeleteVolumeOutput{}, nil)
+			}
 			if len(tc.diskOptions.AvailabilityZone) == 0 {
 				mockEC2.EXPECT().DescribeAvailabilityZonesWithContext(gomock.Eq(ctx), gomock.Any()).Return(&ec2.DescribeAvailabilityZonesOutput{
 					AvailabilityZones: []*ec2.AvailabilityZone{
diff --git a/tester/migration-test-config.yaml b/tester/migration-test-config.yaml
deleted file mode 100644
index 77c7a253..00000000
--- a/tester/migration-test-config.yaml
+++ /dev/null
@@ -1,139 +0,0 @@
-cluster:
-  kops:
-    stateFile: s3://k8s-kops-csi-e2e
-    zones: us-west-2a
-    nodeCount: 3
-    nodeSize: c5.large
-    kubernetesVersion: 1.18.9
-    featureGates: |2
-        kubeAPIServer:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            CSIMigrationAWSComplete: "true"
-            ExpandCSIVolumes: "true"
-            VolumeSnapshotDataSource: "true"
-            CSIInlineVolume: "true"
-        kubeControllerManager:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            CSIMigrationAWSComplete: "true"
-            ExpandCSIVolumes: "true"
-            CSIInlineVolume: "true"
-        kubelet:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            CSIMigrationAWSComplete: "true"
-            ExpandCSIVolumes: "true"
-            CSIInlineVolume: "true"
-    iamPolicies: |2
-        additionalPolicies:
-          node: |
-            [
-              {
-                "Effect": "Allow",
-                "Action": [
-                  "ec2:AttachVolume",
-                  "ec2:CreateSnapshot",
-                  "ec2:CreateTags",
-                  "ec2:CreateVolume",
-                  "ec2:DeleteSnapshot",
-                  "ec2:DeleteTags",
-                  "ec2:DeleteVolume",
-                  "ec2:DescribeInstances",
-                  "ec2:DescribeSnapshots",
-                  "ec2:DescribeTags",
-                  "ec2:DescribeVolumes",
-                  "ec2:DetachVolume",
-                  "ec2:ModifyVolume",
-                  "ec2:DescribeVolumesModifications"
-                ],
-                "Resource": "*"
-              }
-            ]
-
-build: |
-  eval $(aws ecr get-login --region us-west-2 --no-include-email)
-  AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
-  IMAGE_TAG={{TEST_ID}}
-  IMAGE_NAME=$AWS_ACCOUNT_ID.dkr.ecr.us-west-2.amazonaws.com/aws-ebs-csi-driver
-  docker build -t $IMAGE_NAME:$IMAGE_TAG .
-  docker push $IMAGE_NAME:$IMAGE_TAG
-
-install: |
-  echo "Deploying driver"
-  # install helm
-  OS_ARCH=$(go env GOOS)-amd64
-  helm_name=helm-v2.14.1-$OS_ARCH.tar.gz
-  wget https://get.helm.sh/$helm_name
-  tar xvzf $helm_name
-  mv $OS_ARCH/helm /usr/local/bin/helm
-
-  AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
-  IMAGE_TAG={{TEST_ID}}
-  IMAGE_NAME=$AWS_ACCOUNT_ID.dkr.ecr.us-west-2.amazonaws.com/aws-ebs-csi-driver
-
-  # install tiller
-  kubectl apply -f ./hack/utils/tiller-rbac.yaml 
-  helm init --service-account tiller --history-max 200 --wait
-  kubectl get po -n kube-system
-
-  helm install --name aws-ebs-csi-driver \
-      --set enableVolumeScheduling=true \
-      --set enableVolumeResizing=true \
-      --set enableVolumeSnapshot=true \
-      --set image.repository=$IMAGE_NAME \
-      --set image.tag=$IMAGE_TAG \
-      ./charts/aws-ebs-csi-driver
-
-uninstall: |
-  echo "Removing driver"
-  helm del --purge aws-ebs-csi-driver
-
-test: |
-  # TODO known test failures to skip temporarily
-  # - should not allow expansion of pvcs without AllowVolumeExpansion property
-  #   - Test passes but cleanup fails, need https://github.com/kubernetes/kubernetes/pull/81107
-  # - (block volmode) Verify if offline PVC expansion works / should resize volume when PVC is edited while pod is using it
-  #   - NodeExpand for BlockVolumes not well-defined, need more investigation and possibly https://github.com/container-storage-interface/spec/issues/380
-  # - should provision storage with mount options
-  #   - Known bug, need https://github.com/kubernetes/kubernetes/pull/80191 but not yet in a patch release
-  cd ./tests/e2e-migration
-  go test -v -timeout 0 ./... -kubeconfig=$HOME/.kube/config -report-dir=$ARTIFACTS -ginkgo.focus="\[ebs-csi-migration\]" -ginkgo.skip="\[Disruptive\]\
-    |should.not.allow.expansion\
-    |block.volmode.+volume-expand\
-    |should.provision.storage.with.mount.options\
-    |should.not.mount./.map.unused.volumes.in.a.pod" -gce-zone=us-west-2a
-  TEST_PASS=$?
-  cd ../..
-
-  # There should have been no calls to the in-tree driver kubernetes.io/aws-ebs but many calls to ebs.csi.aws.com
-  # Find the controller-manager log and read its metrics to verify
-  NODE=$(kubectl get node -l kubernetes.io/role=master -o json | jq -r ".items[].metadata.name")
-  kubectl port-forward kube-controller-manager-$NODE 10252:10252 -n kube-system&
-  curl 127.0.0.1:10252/metrics -s | grep -a 'volume_operation_total_seconds_bucket{operation_name="provision",plugin_name="ebs.csi.aws.com"'
-  CSI_CALLED=$?
-  curl 127.0.0.1:10252/metrics -s | grep -a 'volume_operation_total_seconds_bucket{operation_name="provision",plugin_name="kubernetes.io/aws-ebs"'
-  INTREE_CALLED=$?
-
-  # TEST_PASS if tests passed, CSI was called, and In-tree was not called
-  if [ "$TEST_PASS" == 0 ] && [ "$CSI_CALLED" == 0 ] && [ "$INTREE_CALLED" == 1 ]; then
-      TEST_PASS=0
-  else
-      TEST_PASS=1
-  fi
-
-  if [[ $TEST_PASS -ne 0 ]]; then
-      exit 1
-  fi
diff --git a/tester/multi-az-config.yaml b/tester/multi-az-config.yaml
deleted file mode 100644
index 55fa187d..00000000
--- a/tester/multi-az-config.yaml
+++ /dev/null
@@ -1,99 +0,0 @@
-cluster:
-  kops:
-    stateFile: s3://k8s-kops-csi-e2e
-    zones: us-west-2a,us-west-2b,us-west-2c
-    nodeCount: 3
-    nodeSize: c5.large
-    kubernetesVersion: 1.18.9
-    featureGates: |2
-        kubeAPIServer:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            ExpandCSIVolumes: "true"
-            VolumeSnapshotDataSource: "true"
-            CSIInlineVolume: "true"
-        kubeControllerManager:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            ExpandCSIVolumes: "true"
-            CSIInlineVolume: "true"
-        kubelet:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            ExpandCSIVolumes: "true"
-            CSIInlineVolume: "true"
-    iamPolicies: |2
-        additionalPolicies:
-          node: |
-            [
-              {
-                "Effect": "Allow",
-                "Action": [
-                  "ec2:AttachVolume",
-                  "ec2:CreateSnapshot",
-                  "ec2:CreateTags",
-                  "ec2:CreateVolume",
-                  "ec2:DeleteSnapshot",
-                  "ec2:DeleteTags",
-                  "ec2:DeleteVolume",
-                  "ec2:DescribeInstances",
-                  "ec2:DescribeSnapshots",
-                  "ec2:DescribeTags",
-                  "ec2:DescribeVolumes",
-                  "ec2:DetachVolume",
-                  "ec2:ModifyVolume",
-                  "ec2:DescribeVolumesModifications"
-                ],
-                "Resource": "*"
-              }
-            ]
-
-build: |
-  eval $(aws ecr get-login --region us-west-2 --no-include-email)
-  AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
-  IMAGE_TAG={{TEST_ID}}
-  IMAGE_NAME=$AWS_ACCOUNT_ID.dkr.ecr.us-west-2.amazonaws.com/aws-ebs-csi-driver
-  docker build -t $IMAGE_NAME:$IMAGE_TAG .
-  docker push $IMAGE_NAME:$IMAGE_TAG
-
-install: |
-  echo "Deploying driver"
-  # install helm
-  make bin/helm
-
-  AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
-  IMAGE_TAG={{TEST_ID}}
-  IMAGE_NAME=$AWS_ACCOUNT_ID.dkr.ecr.us-west-2.amazonaws.com/aws-ebs-csi-driver
-
-  bin/helm install aws-ebs-csi-driver \
-      --set enableVolumeScheduling=true \
-      --set enableVolumeResizing=true \
-      --set enableVolumeSnapshot=true \
-      --set image.repository=$IMAGE_NAME \
-      --set image.tag=$IMAGE_TAG \
-      ./charts/aws-ebs-csi-driver
-
-  kubectl get po -n kube-system
-
-uninstall: |
-  echo "Removing driver"
-  bin/helm delete aws-ebs-csi-driver
-
-test: |
-  go get github.com/onsi/ginkgo/ginkgo
-  export KUBECONFIG=$HOME/.kube/config
-  export AWS_AVAILABILITY_ZONES=us-west-2a,us-west-2b,us-west-2c
-  ARTIFACTS=${ARTIFACTS-/tmp/ebs-csi/artifacts}
-  $(go env GOBIN)/ginkgo -p -nodes=32 -v --focus="\[ebs-csi-e2e\] \[multi-az\]" tests/e2e -- -report-dir=$ARTIFACTS
diff --git a/tester/single-az-config.yaml b/tester/single-az-config.yaml
deleted file mode 100644
index a45340b9..00000000
--- a/tester/single-az-config.yaml
+++ /dev/null
@@ -1,102 +0,0 @@
-cluster:
-  kops:
-    stateFile: s3://k8s-kops-csi-e2e
-    zones: us-west-2a
-    nodeCount: 3
-    nodeSize: c5.large
-    kubernetesVersion: 1.18.9
-    featureGates: |2
-        kubeAPIServer:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            ExpandCSIVolumes: "true"
-            VolumeSnapshotDataSource: "true"
-            CSIInlineVolume: "true"
-        kubeControllerManager:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            ExpandCSIVolumes: "true"
-            CSIInlineVolume: "true"
-        kubelet:
-          featureGates:
-            CSIDriverRegistry: "true"
-            CSINodeInfo: "true"
-            CSIBlockVolume: "true"
-            CSIMigration: "true"
-            CSIMigrationAWS: "true"
-            ExpandCSIVolumes: "true"
-            CSIInlineVolume: "true"
-    iamPolicies: |2
-        additionalPolicies:
-          node: |
-            [
-              {
-                "Effect": "Allow",
-                "Action": [
-                  "ec2:AttachVolume",
-                  "ec2:CreateSnapshot",
-                  "ec2:CreateTags",
-                  "ec2:CreateVolume",
-                  "ec2:DeleteSnapshot",
-                  "ec2:DeleteTags",
-                  "ec2:DeleteVolume",
-                  "ec2:DescribeInstances",
-                  "ec2:DescribeSnapshots",
-                  "ec2:DescribeTags",
-                  "ec2:DescribeVolumes",
-                  "ec2:DetachVolume",
-                  "ec2:ModifyVolume",
-                  "ec2:DescribeVolumesModifications"
-                ],
-                "Resource": "*"
-              }
-            ]
-
-build: |
-  eval $(aws ecr get-login --region us-west-2 --no-include-email)
-  AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
-  IMAGE_TAG={{TEST_ID}}
-  IMAGE_NAME=$AWS_ACCOUNT_ID.dkr.ecr.us-west-2.amazonaws.com/aws-ebs-csi-driver
-  docker build -t $IMAGE_NAME:$IMAGE_TAG .
-  docker push $IMAGE_NAME:$IMAGE_TAG
-
-install: |
-  echo "Deploying driver"
-  # install helm
-  make bin/helm
-
-  AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
-  IMAGE_TAG={{TEST_ID}}
-  IMAGE_NAME=$AWS_ACCOUNT_ID.dkr.ecr.us-west-2.amazonaws.com/aws-ebs-csi-driver
-
-  # install snapshot CRD
-  kubectl apply -f deploy/kubernetes/cluster/
-
-  bin/helm install aws-ebs-csi-driver \
-      --set enableVolumeScheduling=true \
-      --set enableVolumeResizing=true \
-      --set enableVolumeSnapshot=true \
-      --set image.repository=$IMAGE_NAME \
-      --set image.tag=$IMAGE_TAG \
-      ./charts/aws-ebs-csi-driver
-
-  kubectl get po -n kube-system
-
-uninstall: |
-  echo "Removing driver"
-  bin/helm delete aws-ebs-csi-driver
-
-test: |
-  go get github.com/onsi/ginkgo/ginkgo
-  export KUBECONFIG=$HOME/.kube/config
-  export AWS_AVAILABILITY_ZONES=us-west-2a
-  ARTIFACTS=${ARTIFACTS-/tmp/ebs-csi/artifacts}
-  $(go env GOBIN)/ginkgo -p -nodes=32 -v --focus="\[ebs-csi-e2e\] \[single-az\]" --skip="\"sc1\"|\"st1\"" tests/e2e -- -report-dir=$ARTIFACTS