add csi-test to vendor
This commit is contained in:
13
vendor/github.com/kubernetes-csi/csi-test/.gitignore
generated
vendored
Normal file
13
vendor/github.com/kubernetes-csi/csi-test/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
bin/mock
|
||||
cmd/csi-sanity/csi-sanity
|
11
vendor/github.com/kubernetes-csi/csi-test/.travis.yml
generated
vendored
Normal file
11
vendor/github.com/kubernetes-csi/csi-test/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
language: go
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.10.3
|
||||
script:
|
||||
- make test
|
||||
after_success:
|
||||
- if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then
|
||||
docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" quay.io;
|
||||
make push;
|
||||
fi
|
6
vendor/github.com/kubernetes-csi/csi-test/Dockerfile.mock
generated
vendored
Normal file
6
vendor/github.com/kubernetes-csi/csi-test/Dockerfile.mock
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM alpine
|
||||
LABEL maintainers="Kubernetes Authors"
|
||||
LABEL description="CSI Mock Driver"
|
||||
|
||||
COPY ./bin/mock mock
|
||||
ENTRYPOINT ["/mock"]
|
195
vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock
generated
vendored
Normal file
195
vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/container-storage-interface/spec"
|
||||
packages = ["lib/go/csi/v0"]
|
||||
revision = "2178fdeea87f1150a17a63252eee28d4d8141f72"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/mock"
|
||||
packages = ["gomock"]
|
||||
revision = "c34cdb4725f4c3844d095133c6e40e448b86589b"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"protoc-gen-go/descriptor",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp",
|
||||
"ptypes/wrappers"
|
||||
]
|
||||
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/onsi/ginkgo"
|
||||
packages = [
|
||||
".",
|
||||
"config",
|
||||
"internal/codelocation",
|
||||
"internal/containernode",
|
||||
"internal/failer",
|
||||
"internal/leafnodes",
|
||||
"internal/remote",
|
||||
"internal/spec",
|
||||
"internal/spec_iterator",
|
||||
"internal/specrunner",
|
||||
"internal/suite",
|
||||
"internal/testingtproxy",
|
||||
"internal/writer",
|
||||
"reporters",
|
||||
"reporters/stenographer",
|
||||
"reporters/stenographer/support/go-colorable",
|
||||
"reporters/stenographer/support/go-isatty",
|
||||
"types"
|
||||
]
|
||||
revision = "fa5fabab2a1bfbd924faf4c067d07ae414e2aedf"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/onsi/gomega"
|
||||
packages = [
|
||||
".",
|
||||
"format",
|
||||
"internal/assertion",
|
||||
"internal/asyncassertion",
|
||||
"internal/oraclematcher",
|
||||
"internal/testingtsupport",
|
||||
"matchers",
|
||||
"matchers/support/goraph/bipartitegraph",
|
||||
"matchers/support/goraph/edge",
|
||||
"matchers/support/goraph/node",
|
||||
"matchers/support/goraph/util",
|
||||
"types"
|
||||
]
|
||||
revision = "62bff4df71bdbc266561a0caee19f0594b17c240"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
|
||||
version = "v1.0.5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
"html",
|
||||
"html/atom",
|
||||
"html/charset",
|
||||
"http/httpguts",
|
||||
"http2",
|
||||
"http2/hpack",
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"trace"
|
||||
]
|
||||
revision = "1e491301e022f8f977054da4c2d852decd59571f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows"
|
||||
]
|
||||
revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
"collate/build",
|
||||
"encoding",
|
||||
"encoding/charmap",
|
||||
"encoding/htmlindex",
|
||||
"encoding/internal",
|
||||
"encoding/internal/identifier",
|
||||
"encoding/japanese",
|
||||
"encoding/korean",
|
||||
"encoding/simplifiedchinese",
|
||||
"encoding/traditionalchinese",
|
||||
"encoding/unicode",
|
||||
"internal/colltab",
|
||||
"internal/gen",
|
||||
"internal/tag",
|
||||
"internal/triegen",
|
||||
"internal/ucd",
|
||||
"internal/utf8internal",
|
||||
"language",
|
||||
"runes",
|
||||
"secure/bidirule",
|
||||
"transform",
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable"
|
||||
]
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
revision = "32ee49c4dd805befd833990acba36cb75042378c"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
"balancer",
|
||||
"balancer/base",
|
||||
"balancer/roundrobin",
|
||||
"channelz",
|
||||
"codes",
|
||||
"connectivity",
|
||||
"credentials",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclb/grpc_lb_v1/messages",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"reflection",
|
||||
"reflection/grpc_reflection_v1alpha",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
"transport"
|
||||
]
|
||||
revision = "7a6a684ca69eb4cae85ad0a484f2e531598c047b"
|
||||
version = "v1.12.2"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||
version = "v2.2.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "5dd480018adbb94025564b74bad8dd269cc516183b7b428317f6dd04b07726f4"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
62
vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml
generated
vendored
Normal file
62
vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
#
|
||||
# [prune]
|
||||
# non-go = false
|
||||
# go-tests = true
|
||||
# unused-packages = true
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/container-storage-interface/spec"
|
||||
version = "~0.3.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/golang/mock"
|
||||
version = "1.0.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/golang/protobuf"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/onsi/ginkgo"
|
||||
version = "1.4.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/onsi/gomega"
|
||||
version = "1.3.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
|
||||
[[constraint]]
|
||||
name = "google.golang.org/grpc"
|
||||
version = "1.9.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
version = "v2.1.1"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
201
vendor/github.com/kubernetes-csi/csi-test/LICENSE
generated
vendored
Normal file
201
vendor/github.com/kubernetes-csi/csi-test/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
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.
|
52
vendor/github.com/kubernetes-csi/csi-test/Makefile
generated
vendored
Normal file
52
vendor/github.com/kubernetes-csi/csi-test/Makefile
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# Copyright 2018 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.
|
||||
|
||||
IMAGE_NAME = quay.io/k8scsi/mock-driver
|
||||
IMAGE_VERSION = canary
|
||||
APP := ./bin/mock
|
||||
|
||||
|
||||
ifdef V
|
||||
TESTARGS = -v -args -alsologtostderr -v 5
|
||||
else
|
||||
TESTARGS =
|
||||
endif
|
||||
|
||||
all: $(APP)
|
||||
|
||||
$(APP):
|
||||
mkdir -p bin
|
||||
CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o $(APP) ./mock/main.go
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
|
||||
container: $(APP)
|
||||
docker build -f Dockerfile.mock -t $(IMAGE_NAME):$(IMAGE_VERSION) .
|
||||
|
||||
push: container
|
||||
docker push $(IMAGE_NAME):$(IMAGE_VERSION)
|
||||
|
||||
test:
|
||||
files=$$(find ./ -name '*.go' | grep -v '^./vendor' ); \
|
||||
if [ $$(gofmt -d $$files | wc -l) -ne 0 ]; then \
|
||||
echo "formatting errors:"; \
|
||||
gofmt -d $$files; \
|
||||
false; \
|
||||
fi
|
||||
go vet $$(go list ./... | grep -v vendor)
|
||||
go test $$(go list ./... | grep -v vendor | grep -v "cmd/csi-sanity")
|
||||
./hack/e2e.sh
|
||||
|
||||
.PHONY: all clean container push test
|
4
vendor/github.com/kubernetes-csi/csi-test/OWNERS
generated
vendored
Normal file
4
vendor/github.com/kubernetes-csi/csi-test/OWNERS
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
approvers:
|
||||
- saad-ali
|
||||
- lpabon
|
||||
- pohly
|
29
vendor/github.com/kubernetes-csi/csi-test/README.md
generated
vendored
Normal file
29
vendor/github.com/kubernetes-csi/csi-test/README.md
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
[](https://travis-ci.org/kubernetes-csi/csi-test)
|
||||
[](https://quay.io/repository/k8scsi/mock-driver)
|
||||
|
||||
# csi-test
|
||||
csi-test houses packages and libraries to help test CSI client and plugins.
|
||||
|
||||
## For Container Orchestration Tests
|
||||
CO developers can use this framework to create drivers based on the
|
||||
[Golang mock](https://github.com/golang/mock) framework. Please see
|
||||
[co_test.go](test/co_test.go) for an example.
|
||||
|
||||
### Mock driver for testing
|
||||
We also provide a container called `quay.io/k8scsi/mock-driver:canary` which can be used as an in-memory mock driver.
|
||||
It follows the same release cycle as other containers, so the latest release is `quay.io/k8scsi/mock-driver:v0.3.0`.
|
||||
|
||||
You will need to setup the environment variable `CSI_ENDPOINT` for the mock driver to know where to create the unix
|
||||
domain socket.
|
||||
|
||||
## For CSI Driver Tests
|
||||
To test drivers please take a look at [pkg/sanity](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity).
|
||||
This package and [csi-sanity](https://github.com/kubernetes-csi/csi-test/tree/master/cmd/csi-sanity) are meant to test
|
||||
the CSI API capability of a driver. They are meant to be an additional test to the unit, functional, and e2e tests of a
|
||||
CSI driver.
|
||||
|
||||
### Note
|
||||
|
||||
* Master is for CSI v0.4.0. Please see the branches for other CSI releases.
|
||||
* Only Golang 1.9+ supported. See [gRPC issue](https://github.com/grpc/grpc-go/issues/711#issuecomment-326626790)
|
14
vendor/github.com/kubernetes-csi/csi-test/SECURITY_CONTACTS
generated
vendored
Normal file
14
vendor/github.com/kubernetes-csi/csi-test/SECURITY_CONTACTS
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Defined below are the security contacts for this repo.
|
||||
#
|
||||
# They are the contact point for the Product Security Team to reach out
|
||||
# to for triaging and handling of incoming issues.
|
||||
#
|
||||
# The below names agree to abide by the
|
||||
# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy)
|
||||
# and will be removed and replaced if they violate that agreement.
|
||||
#
|
||||
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
|
||||
# INSTRUCTIONS AT https://kubernetes.io/security/
|
||||
|
||||
saad-ali
|
||||
lpabon
|
61
vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/Makefile
generated
vendored
Normal file
61
vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/Makefile
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
APP_NAME := csi-sanity
|
||||
VER :=$(shell git describe)
|
||||
RELEASEVER := $(shell git describe --abbrev=0)
|
||||
BRANCH := $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD))
|
||||
SHA := $(shell git rev-parse --short HEAD)
|
||||
ARCH := $(shell go env GOARCH)
|
||||
GOOS := $(shell go env GOOS)
|
||||
DIR=.
|
||||
|
||||
ifdef APP_SUFFIX
|
||||
VERSION = $(VER)-$(subst /,-,$(APP_SUFFIX))
|
||||
else
|
||||
ifeq (master,$(BRANCH))
|
||||
VERSION = $(VER)
|
||||
else
|
||||
VERSION = $(VER)-$(BRANCH)
|
||||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS :=-ldflags "-w -X github.com/kubernetes-csi/csi-test/cmd/csi-sanity.VERSION=$(VERSION) -extldflags '-z relro -z now'"
|
||||
PACKAGE :=$(DIR)/dist/$(APP_NAME)-$(RELEASEVER).$(GOOS).$(ARCH).tar.gz
|
||||
|
||||
all: $(APP_NAME)
|
||||
|
||||
$(APP_NAME): Makefile sanity_test.go
|
||||
go test $(LDFLAGS) -c -o $(APP_NAME)
|
||||
|
||||
install: $(APP_NAME)
|
||||
cp $(APP_NAME) $(GOPATH)/bin
|
||||
|
||||
clean:
|
||||
rm -f csi-sanity
|
||||
|
||||
dist-clean:
|
||||
rm -rf $(DIR)/dist
|
||||
|
||||
dist: clean $(PACKAGE)
|
||||
|
||||
$(PACKAGE): $(APP_NAME)
|
||||
@echo Packaging Binaries...
|
||||
@mkdir -p tmp/$(APP_NAME)
|
||||
@cp $(APP_NAME) tmp/$(APP_NAME)/
|
||||
@mkdir -p $(DIR)/dist/
|
||||
tar -czf $@ -C tmp $(APP_NAME);
|
||||
@rm -rf tmp
|
||||
@echo
|
||||
@echo Package $@ saved in dist directory
|
||||
|
||||
linux_amd64_dist:
|
||||
GOOS=linux GOARCH=amd64 $(MAKE) dist
|
||||
|
||||
linux_arm64_dist:
|
||||
GOOS=linux GOARCH=arm64 $(MAKE) dist
|
||||
|
||||
darwin_amd64_dist:
|
||||
GOOS=darwin GOARCH=amd64 $(MAKE) dist
|
||||
|
||||
release: dist-clean darwin_amd64_dist linux_amd64_dist linux_arm64_dist
|
||||
|
||||
.PHONY: release darwin_amd64_dist linux_arm64_dist linux_amd64_dist \
|
||||
linux_arm_dist linux_amd64_dist clean dist-clean
|
58
vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/README.md
generated
vendored
Normal file
58
vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/README.md
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# Sanity Test Command Line Program
|
||||
This is the command line program that tests a CSI driver using the [`sanity`](https://github.com/kubernetes-csi/csi-test/tree/master/pkg/sanity) package test suite.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
$ csi-sanity --csi.endpoint=<your csi driver endpoint>
|
||||
```
|
||||
|
||||
If you want to specify a mount point:
|
||||
|
||||
```
|
||||
$ csi-sanity --csi.endpoint=<your csi driver endpoint> --csi.mountpoint=/mnt
|
||||
```
|
||||
|
||||
For verbose type:
|
||||
|
||||
```
|
||||
$ csi-sanity --ginkgo.v --csi.endpoint=<your csi driver endpoint>
|
||||
```
|
||||
|
||||
For csi-credentials, create a secrets file with all the secrets in it:
|
||||
```yaml
|
||||
CreateVolumeSecret:
|
||||
secretKey: secretval1
|
||||
DeleteVolumeSecret:
|
||||
secretKey: secretval2
|
||||
ControllerPublishVolumeSecret:
|
||||
secretKey: secretval3
|
||||
ControllerUnpublishVolumeSecret:
|
||||
secretKey: secretval4
|
||||
NodeStageVolumeSecret:
|
||||
secretKey: secretval5
|
||||
NodePublishVolumeSecret:
|
||||
secretKey: secretval6
|
||||
```
|
||||
|
||||
Pass the file path to csi-sanity as:
|
||||
```
|
||||
$ csi-sanity --csi.endpoint=<your csi driver endpoint> --csi.secrets=<path to secrets file>
|
||||
```
|
||||
|
||||
Replace the keys and values of the credentials appropriately. Since the whole
|
||||
secret is passed in the request, multiple key-val pairs can be used.
|
||||
|
||||
### Help
|
||||
The full Ginkgo and golang unit test parameters are available. Type
|
||||
|
||||
```
|
||||
$ csi-sanity -h
|
||||
```
|
||||
|
||||
to get more information
|
||||
|
||||
### Download
|
||||
|
||||
Please see the [Releases](https://github.com/kubernetes-csi/csi-test/releases) page
|
||||
to download the latest version of `csi-sanity`
|
56
vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go
generated
vendored
Normal file
56
vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package sanity
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-csi/csi-test/pkg/sanity"
|
||||
)
|
||||
|
||||
const (
|
||||
prefix string = "csi."
|
||||
)
|
||||
|
||||
var (
|
||||
VERSION = "(dev)"
|
||||
version bool
|
||||
config sanity.Config
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&config.Address, prefix+"endpoint", "", "CSI endpoint")
|
||||
flag.BoolVar(&version, prefix+"version", false, "Version of this program")
|
||||
flag.StringVar(&config.TargetPath, prefix+"mountdir", os.TempDir()+"/csi", "Mount point for NodePublish")
|
||||
flag.StringVar(&config.StagingPath, prefix+"stagingdir", os.TempDir()+"/csi", "Mount point for NodeStage if staging is supported")
|
||||
flag.StringVar(&config.SecretsFile, prefix+"secrets", "", "CSI secrets file")
|
||||
flag.Int64Var(&config.TestVolumeSize, prefix+"testvolumesize", sanity.DefTestVolumeSize, "Base volume size used for provisioned volumes")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func TestSanity(t *testing.T) {
|
||||
if version {
|
||||
fmt.Printf("Version = %s\n", VERSION)
|
||||
return
|
||||
}
|
||||
if len(config.Address) == 0 {
|
||||
t.Fatalf("--%sendpoint must be provided with an CSI endpoint", prefix)
|
||||
}
|
||||
sanity.Test(t, &config)
|
||||
}
|
3
vendor/github.com/kubernetes-csi/csi-test/code-of-conduct.md
generated
vendored
Normal file
3
vendor/github.com/kubernetes-csi/csi-test/code-of-conduct.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Kubernetes Community Code of Conduct
|
||||
|
||||
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
|
247
vendor/github.com/kubernetes-csi/csi-test/driver/driver.go
generated
vendored
Normal file
247
vendor/github.com/kubernetes-csi/csi-test/driver/driver.go
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
//go:generate mockgen -package=driver -destination=driver.mock.go github.com/container-storage-interface/spec/lib/go/csi/v0 IdentityServer,ControllerServer,NodeServer
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoCredentials is the error when a secret is enabled but not passed in the request.
|
||||
ErrNoCredentials = errors.New("secret must be provided")
|
||||
// ErrAuthFailed is the error when the secret is incorrect.
|
||||
ErrAuthFailed = errors.New("authentication failed")
|
||||
)
|
||||
|
||||
type CSIDriverServers struct {
|
||||
Controller csi.ControllerServer
|
||||
Identity csi.IdentityServer
|
||||
Node csi.NodeServer
|
||||
}
|
||||
|
||||
// This is the key name in all the CSI secret objects.
|
||||
const secretField = "secretKey"
|
||||
|
||||
// CSICreds is a driver specific secret type. Drivers can have a key-val pair of
|
||||
// secrets. This mock driver has a single string secret with secretField as the
|
||||
// key.
|
||||
type CSICreds struct {
|
||||
CreateVolumeSecret string
|
||||
DeleteVolumeSecret string
|
||||
ControllerPublishVolumeSecret string
|
||||
ControllerUnpublishVolumeSecret string
|
||||
NodeStageVolumeSecret string
|
||||
NodePublishVolumeSecret string
|
||||
CreateSnapshotSecret string
|
||||
DeleteSnapshotSecret string
|
||||
}
|
||||
|
||||
type CSIDriver struct {
|
||||
listener net.Listener
|
||||
server *grpc.Server
|
||||
servers *CSIDriverServers
|
||||
wg sync.WaitGroup
|
||||
running bool
|
||||
lock sync.Mutex
|
||||
creds *CSICreds
|
||||
}
|
||||
|
||||
func NewCSIDriver(servers *CSIDriverServers) *CSIDriver {
|
||||
return &CSIDriver{
|
||||
servers: servers,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CSIDriver) goServe(started chan<- bool) {
|
||||
c.wg.Add(1)
|
||||
go func() {
|
||||
defer c.wg.Done()
|
||||
started <- true
|
||||
err := c.server.Serve(c.listener)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *CSIDriver) Address() string {
|
||||
return c.listener.Addr().String()
|
||||
}
|
||||
func (c *CSIDriver) Start(l net.Listener) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
// Set listener
|
||||
c.listener = l
|
||||
|
||||
// Create a new grpc server
|
||||
c.server = grpc.NewServer(
|
||||
grpc.UnaryInterceptor(c.authInterceptor),
|
||||
)
|
||||
|
||||
// Register Mock servers
|
||||
if c.servers.Controller != nil {
|
||||
csi.RegisterControllerServer(c.server, c.servers.Controller)
|
||||
}
|
||||
if c.servers.Identity != nil {
|
||||
csi.RegisterIdentityServer(c.server, c.servers.Identity)
|
||||
}
|
||||
if c.servers.Node != nil {
|
||||
csi.RegisterNodeServer(c.server, c.servers.Node)
|
||||
}
|
||||
reflection.Register(c.server)
|
||||
|
||||
// Start listening for requests
|
||||
waitForServer := make(chan bool)
|
||||
c.goServe(waitForServer)
|
||||
<-waitForServer
|
||||
c.running = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CSIDriver) Stop() {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if !c.running {
|
||||
return
|
||||
}
|
||||
|
||||
c.server.Stop()
|
||||
c.wg.Wait()
|
||||
}
|
||||
|
||||
func (c *CSIDriver) Close() {
|
||||
c.server.Stop()
|
||||
}
|
||||
|
||||
func (c *CSIDriver) IsRunning() bool {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
return c.running
|
||||
}
|
||||
|
||||
// SetDefaultCreds sets the default secrets for CSI creds.
|
||||
func (c *CSIDriver) SetDefaultCreds() {
|
||||
c.creds = &CSICreds{
|
||||
CreateVolumeSecret: "secretval1",
|
||||
DeleteVolumeSecret: "secretval2",
|
||||
ControllerPublishVolumeSecret: "secretval3",
|
||||
ControllerUnpublishVolumeSecret: "secretval4",
|
||||
NodeStageVolumeSecret: "secretval5",
|
||||
NodePublishVolumeSecret: "secretval6",
|
||||
CreateSnapshotSecret: "secretval7",
|
||||
DeleteSnapshotSecret: "secretval8",
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CSIDriver) authInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
if c.creds != nil {
|
||||
authenticated, authErr := isAuthenticated(req, c.creds)
|
||||
if !authenticated {
|
||||
if authErr == ErrNoCredentials {
|
||||
return nil, status.Error(codes.InvalidArgument, authErr.Error())
|
||||
}
|
||||
if authErr == ErrAuthFailed {
|
||||
return nil, status.Error(codes.Unauthenticated, authErr.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h, err := handler(ctx, req)
|
||||
|
||||
return h, err
|
||||
}
|
||||
|
||||
func isAuthenticated(req interface{}, creds *CSICreds) (bool, error) {
|
||||
switch r := req.(type) {
|
||||
case *csi.CreateVolumeRequest:
|
||||
return authenticateCreateVolume(r, creds)
|
||||
case *csi.DeleteVolumeRequest:
|
||||
return authenticateDeleteVolume(r, creds)
|
||||
case *csi.ControllerPublishVolumeRequest:
|
||||
return authenticateControllerPublishVolume(r, creds)
|
||||
case *csi.ControllerUnpublishVolumeRequest:
|
||||
return authenticateControllerUnpublishVolume(r, creds)
|
||||
case *csi.NodeStageVolumeRequest:
|
||||
return authenticateNodeStageVolume(r, creds)
|
||||
case *csi.NodePublishVolumeRequest:
|
||||
return authenticateNodePublishVolume(r, creds)
|
||||
case *csi.CreateSnapshotRequest:
|
||||
return authenticateCreateSnapshot(r, creds)
|
||||
case *csi.DeleteSnapshotRequest:
|
||||
return authenticateDeleteSnapshot(r, creds)
|
||||
default:
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
func authenticateCreateVolume(req *csi.CreateVolumeRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetControllerCreateSecrets(), creds.CreateVolumeSecret)
|
||||
}
|
||||
|
||||
func authenticateDeleteVolume(req *csi.DeleteVolumeRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetControllerDeleteSecrets(), creds.DeleteVolumeSecret)
|
||||
}
|
||||
|
||||
func authenticateControllerPublishVolume(req *csi.ControllerPublishVolumeRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetControllerPublishSecrets(), creds.ControllerPublishVolumeSecret)
|
||||
}
|
||||
|
||||
func authenticateControllerUnpublishVolume(req *csi.ControllerUnpublishVolumeRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetControllerUnpublishSecrets(), creds.ControllerUnpublishVolumeSecret)
|
||||
}
|
||||
|
||||
func authenticateNodeStageVolume(req *csi.NodeStageVolumeRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetNodeStageSecrets(), creds.NodeStageVolumeSecret)
|
||||
}
|
||||
|
||||
func authenticateNodePublishVolume(req *csi.NodePublishVolumeRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetNodePublishSecrets(), creds.NodePublishVolumeSecret)
|
||||
}
|
||||
|
||||
func authenticateCreateSnapshot(req *csi.CreateSnapshotRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetCreateSnapshotSecrets(), creds.CreateSnapshotSecret)
|
||||
}
|
||||
|
||||
func authenticateDeleteSnapshot(req *csi.DeleteSnapshotRequest, creds *CSICreds) (bool, error) {
|
||||
return credsCheck(req.GetDeleteSnapshotSecrets(), creds.DeleteSnapshotSecret)
|
||||
}
|
||||
|
||||
func credsCheck(secrets map[string]string, secretVal string) (bool, error) {
|
||||
if len(secrets) == 0 {
|
||||
return false, ErrNoCredentials
|
||||
}
|
||||
|
||||
if secrets[secretField] != secretVal {
|
||||
return false, ErrAuthFailed
|
||||
}
|
||||
return true, nil
|
||||
}
|
354
vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go
generated
vendored
Normal file
354
vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go
generated
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/container-storage-interface/spec/lib/go/csi/v0 (interfaces: IdentityServer,ControllerServer,NodeServer)
|
||||
|
||||
// Package driver is a generated GoMock package.
|
||||
package driver
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v0 "github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockIdentityServer is a mock of IdentityServer interface
|
||||
type MockIdentityServer struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockIdentityServerMockRecorder
|
||||
}
|
||||
|
||||
// MockIdentityServerMockRecorder is the mock recorder for MockIdentityServer
|
||||
type MockIdentityServerMockRecorder struct {
|
||||
mock *MockIdentityServer
|
||||
}
|
||||
|
||||
// NewMockIdentityServer creates a new mock instance
|
||||
func NewMockIdentityServer(ctrl *gomock.Controller) *MockIdentityServer {
|
||||
mock := &MockIdentityServer{ctrl: ctrl}
|
||||
mock.recorder = &MockIdentityServerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockIdentityServer) EXPECT() *MockIdentityServerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetPluginCapabilities mocks base method
|
||||
func (m *MockIdentityServer) GetPluginCapabilities(arg0 context.Context, arg1 *v0.GetPluginCapabilitiesRequest) (*v0.GetPluginCapabilitiesResponse, error) {
|
||||
ret := m.ctrl.Call(m, "GetPluginCapabilities", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.GetPluginCapabilitiesResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetPluginCapabilities indicates an expected call of GetPluginCapabilities
|
||||
func (mr *MockIdentityServerMockRecorder) GetPluginCapabilities(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginCapabilities", reflect.TypeOf((*MockIdentityServer)(nil).GetPluginCapabilities), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetPluginInfo mocks base method
|
||||
func (m *MockIdentityServer) GetPluginInfo(arg0 context.Context, arg1 *v0.GetPluginInfoRequest) (*v0.GetPluginInfoResponse, error) {
|
||||
ret := m.ctrl.Call(m, "GetPluginInfo", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.GetPluginInfoResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetPluginInfo indicates an expected call of GetPluginInfo
|
||||
func (mr *MockIdentityServerMockRecorder) GetPluginInfo(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginInfo", reflect.TypeOf((*MockIdentityServer)(nil).GetPluginInfo), arg0, arg1)
|
||||
}
|
||||
|
||||
// Probe mocks base method
|
||||
func (m *MockIdentityServer) Probe(arg0 context.Context, arg1 *v0.ProbeRequest) (*v0.ProbeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "Probe", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.ProbeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Probe indicates an expected call of Probe
|
||||
func (mr *MockIdentityServerMockRecorder) Probe(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Probe", reflect.TypeOf((*MockIdentityServer)(nil).Probe), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockControllerServer is a mock of ControllerServer interface
|
||||
type MockControllerServer struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockControllerServerMockRecorder
|
||||
}
|
||||
|
||||
// MockControllerServerMockRecorder is the mock recorder for MockControllerServer
|
||||
type MockControllerServerMockRecorder struct {
|
||||
mock *MockControllerServer
|
||||
}
|
||||
|
||||
// NewMockControllerServer creates a new mock instance
|
||||
func NewMockControllerServer(ctrl *gomock.Controller) *MockControllerServer {
|
||||
mock := &MockControllerServer{ctrl: ctrl}
|
||||
mock.recorder = &MockControllerServerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockControllerServer) EXPECT() *MockControllerServerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// ControllerGetCapabilities mocks base method
|
||||
func (m *MockControllerServer) ControllerGetCapabilities(arg0 context.Context, arg1 *v0.ControllerGetCapabilitiesRequest) (*v0.ControllerGetCapabilitiesResponse, error) {
|
||||
ret := m.ctrl.Call(m, "ControllerGetCapabilities", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.ControllerGetCapabilitiesResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ControllerGetCapabilities indicates an expected call of ControllerGetCapabilities
|
||||
func (mr *MockControllerServerMockRecorder) ControllerGetCapabilities(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControllerGetCapabilities", reflect.TypeOf((*MockControllerServer)(nil).ControllerGetCapabilities), arg0, arg1)
|
||||
}
|
||||
|
||||
// ControllerPublishVolume mocks base method
|
||||
func (m *MockControllerServer) ControllerPublishVolume(arg0 context.Context, arg1 *v0.ControllerPublishVolumeRequest) (*v0.ControllerPublishVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "ControllerPublishVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.ControllerPublishVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ControllerPublishVolume indicates an expected call of ControllerPublishVolume
|
||||
func (mr *MockControllerServerMockRecorder) ControllerPublishVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControllerPublishVolume", reflect.TypeOf((*MockControllerServer)(nil).ControllerPublishVolume), arg0, arg1)
|
||||
}
|
||||
|
||||
// ControllerUnpublishVolume mocks base method
|
||||
func (m *MockControllerServer) ControllerUnpublishVolume(arg0 context.Context, arg1 *v0.ControllerUnpublishVolumeRequest) (*v0.ControllerUnpublishVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "ControllerUnpublishVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.ControllerUnpublishVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ControllerUnpublishVolume indicates an expected call of ControllerUnpublishVolume
|
||||
func (mr *MockControllerServerMockRecorder) ControllerUnpublishVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControllerUnpublishVolume", reflect.TypeOf((*MockControllerServer)(nil).ControllerUnpublishVolume), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateSnapshot mocks base method
|
||||
func (m *MockControllerServer) CreateSnapshot(arg0 context.Context, arg1 *v0.CreateSnapshotRequest) (*v0.CreateSnapshotResponse, error) {
|
||||
ret := m.ctrl.Call(m, "CreateSnapshot", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.CreateSnapshotResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateSnapshot indicates an expected call of CreateSnapshot
|
||||
func (mr *MockControllerServerMockRecorder) CreateSnapshot(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSnapshot", reflect.TypeOf((*MockControllerServer)(nil).CreateSnapshot), arg0, arg1)
|
||||
}
|
||||
|
||||
// CreateVolume mocks base method
|
||||
func (m *MockControllerServer) CreateVolume(arg0 context.Context, arg1 *v0.CreateVolumeRequest) (*v0.CreateVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "CreateVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.CreateVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateVolume indicates an expected call of CreateVolume
|
||||
func (mr *MockControllerServerMockRecorder) CreateVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateVolume", reflect.TypeOf((*MockControllerServer)(nil).CreateVolume), arg0, arg1)
|
||||
}
|
||||
|
||||
// DeleteSnapshot mocks base method
|
||||
func (m *MockControllerServer) DeleteSnapshot(arg0 context.Context, arg1 *v0.DeleteSnapshotRequest) (*v0.DeleteSnapshotResponse, error) {
|
||||
ret := m.ctrl.Call(m, "DeleteSnapshot", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.DeleteSnapshotResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DeleteSnapshot indicates an expected call of DeleteSnapshot
|
||||
func (mr *MockControllerServerMockRecorder) DeleteSnapshot(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSnapshot", reflect.TypeOf((*MockControllerServer)(nil).DeleteSnapshot), arg0, arg1)
|
||||
}
|
||||
|
||||
// DeleteVolume mocks base method
|
||||
func (m *MockControllerServer) DeleteVolume(arg0 context.Context, arg1 *v0.DeleteVolumeRequest) (*v0.DeleteVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "DeleteVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.DeleteVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DeleteVolume indicates an expected call of DeleteVolume
|
||||
func (mr *MockControllerServerMockRecorder) DeleteVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVolume", reflect.TypeOf((*MockControllerServer)(nil).DeleteVolume), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetCapacity mocks base method
|
||||
func (m *MockControllerServer) GetCapacity(arg0 context.Context, arg1 *v0.GetCapacityRequest) (*v0.GetCapacityResponse, error) {
|
||||
ret := m.ctrl.Call(m, "GetCapacity", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.GetCapacityResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetCapacity indicates an expected call of GetCapacity
|
||||
func (mr *MockControllerServerMockRecorder) GetCapacity(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCapacity", reflect.TypeOf((*MockControllerServer)(nil).GetCapacity), arg0, arg1)
|
||||
}
|
||||
|
||||
// ListSnapshots mocks base method
|
||||
func (m *MockControllerServer) ListSnapshots(arg0 context.Context, arg1 *v0.ListSnapshotsRequest) (*v0.ListSnapshotsResponse, error) {
|
||||
ret := m.ctrl.Call(m, "ListSnapshots", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.ListSnapshotsResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListSnapshots indicates an expected call of ListSnapshots
|
||||
func (mr *MockControllerServerMockRecorder) ListSnapshots(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSnapshots", reflect.TypeOf((*MockControllerServer)(nil).ListSnapshots), arg0, arg1)
|
||||
}
|
||||
|
||||
// ListVolumes mocks base method
|
||||
func (m *MockControllerServer) ListVolumes(arg0 context.Context, arg1 *v0.ListVolumesRequest) (*v0.ListVolumesResponse, error) {
|
||||
ret := m.ctrl.Call(m, "ListVolumes", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.ListVolumesResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListVolumes indicates an expected call of ListVolumes
|
||||
func (mr *MockControllerServerMockRecorder) ListVolumes(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListVolumes", reflect.TypeOf((*MockControllerServer)(nil).ListVolumes), arg0, arg1)
|
||||
}
|
||||
|
||||
// ValidateVolumeCapabilities mocks base method
|
||||
func (m *MockControllerServer) ValidateVolumeCapabilities(arg0 context.Context, arg1 *v0.ValidateVolumeCapabilitiesRequest) (*v0.ValidateVolumeCapabilitiesResponse, error) {
|
||||
ret := m.ctrl.Call(m, "ValidateVolumeCapabilities", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.ValidateVolumeCapabilitiesResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ValidateVolumeCapabilities indicates an expected call of ValidateVolumeCapabilities
|
||||
func (mr *MockControllerServerMockRecorder) ValidateVolumeCapabilities(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateVolumeCapabilities", reflect.TypeOf((*MockControllerServer)(nil).ValidateVolumeCapabilities), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockNodeServer is a mock of NodeServer interface
|
||||
type MockNodeServer struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockNodeServerMockRecorder
|
||||
}
|
||||
|
||||
// MockNodeServerMockRecorder is the mock recorder for MockNodeServer
|
||||
type MockNodeServerMockRecorder struct {
|
||||
mock *MockNodeServer
|
||||
}
|
||||
|
||||
// NewMockNodeServer creates a new mock instance
|
||||
func NewMockNodeServer(ctrl *gomock.Controller) *MockNodeServer {
|
||||
mock := &MockNodeServer{ctrl: ctrl}
|
||||
mock.recorder = &MockNodeServerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockNodeServer) EXPECT() *MockNodeServerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// NodeGetCapabilities mocks base method
|
||||
func (m *MockNodeServer) NodeGetCapabilities(arg0 context.Context, arg1 *v0.NodeGetCapabilitiesRequest) (*v0.NodeGetCapabilitiesResponse, error) {
|
||||
ret := m.ctrl.Call(m, "NodeGetCapabilities", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.NodeGetCapabilitiesResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NodeGetCapabilities indicates an expected call of NodeGetCapabilities
|
||||
func (mr *MockNodeServerMockRecorder) NodeGetCapabilities(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetCapabilities", reflect.TypeOf((*MockNodeServer)(nil).NodeGetCapabilities), arg0, arg1)
|
||||
}
|
||||
|
||||
// NodeGetId mocks base method
|
||||
func (m *MockNodeServer) NodeGetId(arg0 context.Context, arg1 *v0.NodeGetIdRequest) (*v0.NodeGetIdResponse, error) {
|
||||
ret := m.ctrl.Call(m, "NodeGetId", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.NodeGetIdResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NodeGetId indicates an expected call of NodeGetId
|
||||
func (mr *MockNodeServerMockRecorder) NodeGetId(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetId", reflect.TypeOf((*MockNodeServer)(nil).NodeGetId), arg0, arg1)
|
||||
}
|
||||
|
||||
// NodeGetInfo mocks base method
|
||||
func (m *MockNodeServer) NodeGetInfo(arg0 context.Context, arg1 *v0.NodeGetInfoRequest) (*v0.NodeGetInfoResponse, error) {
|
||||
ret := m.ctrl.Call(m, "NodeGetInfo", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.NodeGetInfoResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NodeGetInfo indicates an expected call of NodeGetInfo
|
||||
func (mr *MockNodeServerMockRecorder) NodeGetInfo(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetInfo", reflect.TypeOf((*MockNodeServer)(nil).NodeGetInfo), arg0, arg1)
|
||||
}
|
||||
|
||||
// NodePublishVolume mocks base method
|
||||
func (m *MockNodeServer) NodePublishVolume(arg0 context.Context, arg1 *v0.NodePublishVolumeRequest) (*v0.NodePublishVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "NodePublishVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.NodePublishVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NodePublishVolume indicates an expected call of NodePublishVolume
|
||||
func (mr *MockNodeServerMockRecorder) NodePublishVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodePublishVolume", reflect.TypeOf((*MockNodeServer)(nil).NodePublishVolume), arg0, arg1)
|
||||
}
|
||||
|
||||
// NodeStageVolume mocks base method
|
||||
func (m *MockNodeServer) NodeStageVolume(arg0 context.Context, arg1 *v0.NodeStageVolumeRequest) (*v0.NodeStageVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "NodeStageVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.NodeStageVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NodeStageVolume indicates an expected call of NodeStageVolume
|
||||
func (mr *MockNodeServerMockRecorder) NodeStageVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeStageVolume", reflect.TypeOf((*MockNodeServer)(nil).NodeStageVolume), arg0, arg1)
|
||||
}
|
||||
|
||||
// NodeUnpublishVolume mocks base method
|
||||
func (m *MockNodeServer) NodeUnpublishVolume(arg0 context.Context, arg1 *v0.NodeUnpublishVolumeRequest) (*v0.NodeUnpublishVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "NodeUnpublishVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.NodeUnpublishVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NodeUnpublishVolume indicates an expected call of NodeUnpublishVolume
|
||||
func (mr *MockNodeServerMockRecorder) NodeUnpublishVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeUnpublishVolume", reflect.TypeOf((*MockNodeServer)(nil).NodeUnpublishVolume), arg0, arg1)
|
||||
}
|
||||
|
||||
// NodeUnstageVolume mocks base method
|
||||
func (m *MockNodeServer) NodeUnstageVolume(arg0 context.Context, arg1 *v0.NodeUnstageVolumeRequest) (*v0.NodeUnstageVolumeResponse, error) {
|
||||
ret := m.ctrl.Call(m, "NodeUnstageVolume", arg0, arg1)
|
||||
ret0, _ := ret[0].(*v0.NodeUnstageVolumeResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NodeUnstageVolume indicates an expected call of NodeUnstageVolume
|
||||
func (mr *MockNodeServerMockRecorder) NodeUnstageVolume(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeUnstageVolume", reflect.TypeOf((*MockNodeServer)(nil).NodeUnstageVolume), arg0, arg1)
|
||||
}
|
83
vendor/github.com/kubernetes-csi/csi-test/driver/mock.go
generated
vendored
Normal file
83
vendor/github.com/kubernetes-csi/csi-test/driver/mock.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package driver
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/kubernetes-csi/csi-test/utils"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type MockCSIDriverServers struct {
|
||||
Controller *MockControllerServer
|
||||
Identity *MockIdentityServer
|
||||
Node *MockNodeServer
|
||||
}
|
||||
|
||||
type MockCSIDriver struct {
|
||||
CSIDriver
|
||||
conn *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewMockCSIDriver(servers *MockCSIDriverServers) *MockCSIDriver {
|
||||
return &MockCSIDriver{
|
||||
CSIDriver: CSIDriver{
|
||||
servers: &CSIDriverServers{
|
||||
Controller: servers.Controller,
|
||||
Node: servers.Node,
|
||||
Identity: servers.Identity,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockCSIDriver) Start() error {
|
||||
// Listen on a port assigned by the net package
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := m.CSIDriver.Start(l); err != nil {
|
||||
l.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockCSIDriver) Nexus() (*grpc.ClientConn, error) {
|
||||
// Start server
|
||||
err := m.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create a client connection
|
||||
m.conn, err = utils.Connect(m.Address())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m.conn, nil
|
||||
}
|
||||
|
||||
func (m *MockCSIDriver) Close() {
|
||||
m.conn.Close()
|
||||
m.server.Stop()
|
||||
}
|
50
vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh
generated
vendored
Executable file
50
vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh
generated
vendored
Executable file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
TESTARGS=$@
|
||||
UDS="/tmp/e2e-csi-sanity.sock"
|
||||
CSI_ENDPOINTS="$CSI_ENDPOINTS ${UDS}"
|
||||
CSI_MOCK_VERSION="master"
|
||||
|
||||
#
|
||||
# $1 - endpoint for mock.
|
||||
# $2 - endpoint for csi-sanity in Grpc format.
|
||||
# See https://github.com/grpc/grpc/blob/master/doc/naming.md
|
||||
runTest()
|
||||
{
|
||||
CSI_ENDPOINT=$1 ./bin/mock &
|
||||
local pid=$!
|
||||
|
||||
./cmd/csi-sanity/csi-sanity $TESTARGS --csi.endpoint=$2; ret=$?
|
||||
kill -9 $pid
|
||||
|
||||
if [ $ret -ne 0 ] ; then
|
||||
exit $ret
|
||||
fi
|
||||
}
|
||||
|
||||
runTestWithCreds()
|
||||
{
|
||||
CSI_ENDPOINT=$1 CSI_ENABLE_CREDS=true ./bin/mock &
|
||||
local pid=$!
|
||||
|
||||
./cmd/csi-sanity/csi-sanity $TESTARGS --csi.endpoint=$2 --csi.secrets=mock/mocksecret.yaml; ret=$?
|
||||
kill -9 $pid
|
||||
|
||||
if [ $ret -ne 0 ] ; then
|
||||
exit $ret
|
||||
fi
|
||||
}
|
||||
|
||||
go build -o bin/mock ./mock || exit 1
|
||||
|
||||
cd cmd/csi-sanity
|
||||
make clean install || exit 1
|
||||
cd ../..
|
||||
|
||||
runTest "${UDS}" "${UDS}"
|
||||
rm -f $UDS
|
||||
|
||||
runTestWithCreds "${UDS}" "${UDS}"
|
||||
rm -f $UDS
|
||||
|
||||
exit 0
|
2
vendor/github.com/kubernetes-csi/csi-test/mock/AUTHORS
generated
vendored
Normal file
2
vendor/github.com/kubernetes-csi/csi-test/mock/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
TheCodeTeam
|
||||
Kubernetes Authors
|
2
vendor/github.com/kubernetes-csi/csi-test/mock/README.md
generated
vendored
Normal file
2
vendor/github.com/kubernetes-csi/csi-test/mock/README.md
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Mock CSI Driver
|
||||
Extremely simple mock driver used to test `csi-sanity` based on `rexray/gocsi/mock`
|
89
vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go
generated
vendored
Normal file
89
vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
)
|
||||
|
||||
type SnapshotCache interface {
|
||||
Add(snapshot Snapshot)
|
||||
|
||||
Delete(i int)
|
||||
|
||||
List(status csi.SnapshotStatus_Type) []csi.Snapshot
|
||||
|
||||
FindSnapshot(k, v string) (int, Snapshot)
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Name string
|
||||
Parameters map[string]string
|
||||
SnapshotCSI csi.Snapshot
|
||||
}
|
||||
|
||||
type snapshotCache struct {
|
||||
snapshotsRWL sync.RWMutex
|
||||
snapshots []Snapshot
|
||||
}
|
||||
|
||||
func NewSnapshotCache() SnapshotCache {
|
||||
return &snapshotCache{
|
||||
snapshots: make([]Snapshot, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (snap *snapshotCache) Add(snapshot Snapshot) {
|
||||
snap.snapshotsRWL.Lock()
|
||||
defer snap.snapshotsRWL.Unlock()
|
||||
|
||||
snap.snapshots = append(snap.snapshots, snapshot)
|
||||
}
|
||||
|
||||
func (snap *snapshotCache) Delete(i int) {
|
||||
snap.snapshotsRWL.Lock()
|
||||
defer snap.snapshotsRWL.Unlock()
|
||||
|
||||
copy(snap.snapshots[i:], snap.snapshots[i+1:])
|
||||
snap.snapshots = snap.snapshots[:len(snap.snapshots)-1]
|
||||
}
|
||||
|
||||
func (snap *snapshotCache) List(status csi.SnapshotStatus_Type) []csi.Snapshot {
|
||||
snap.snapshotsRWL.RLock()
|
||||
defer snap.snapshotsRWL.RUnlock()
|
||||
|
||||
snapshots := make([]csi.Snapshot, 0)
|
||||
for _, v := range snap.snapshots {
|
||||
if v.SnapshotCSI.GetStatus() != nil && v.SnapshotCSI.GetStatus().Type == status {
|
||||
snapshots = append(snapshots, v.SnapshotCSI)
|
||||
}
|
||||
}
|
||||
|
||||
return snapshots
|
||||
}
|
||||
|
||||
func (snap *snapshotCache) FindSnapshot(k, v string) (int, Snapshot) {
|
||||
snap.snapshotsRWL.RLock()
|
||||
defer snap.snapshotsRWL.RUnlock()
|
||||
|
||||
snapshotIdx := -1
|
||||
for i, vi := range snap.snapshots {
|
||||
switch k {
|
||||
case "id":
|
||||
if strings.EqualFold(v, vi.SnapshotCSI.Id) {
|
||||
return i, vi
|
||||
}
|
||||
case "sourceVolumeId":
|
||||
if strings.EqualFold(v, vi.SnapshotCSI.SourceVolumeId) {
|
||||
return i, vi
|
||||
}
|
||||
case "name":
|
||||
if vi.Name == v {
|
||||
return i, vi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return snapshotIdx, Snapshot{}
|
||||
}
|
88
vendor/github.com/kubernetes-csi/csi-test/mock/main.go
generated
vendored
Normal file
88
vendor/github.com/kubernetes-csi/csi-test/mock/main.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright 2018 Kubernetes Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/kubernetes-csi/csi-test/driver"
|
||||
"github.com/kubernetes-csi/csi-test/mock/service"
|
||||
)
|
||||
|
||||
func main() {
|
||||
endpoint := os.Getenv("CSI_ENDPOINT")
|
||||
if len(endpoint) == 0 {
|
||||
fmt.Println("CSI_ENDPOINT must be defined and must be a path")
|
||||
os.Exit(1)
|
||||
}
|
||||
if strings.Contains(endpoint, ":") {
|
||||
fmt.Println("CSI_ENDPOINT must be a unix path")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Create mock driver
|
||||
s := service.New()
|
||||
servers := &driver.CSIDriverServers{
|
||||
Controller: s,
|
||||
Identity: s,
|
||||
Node: s,
|
||||
}
|
||||
d := driver.NewCSIDriver(servers)
|
||||
|
||||
// If creds is enabled, set the default creds.
|
||||
setCreds := os.Getenv("CSI_ENABLE_CREDS")
|
||||
if len(setCreds) > 0 && setCreds == "true" {
|
||||
d.SetDefaultCreds()
|
||||
}
|
||||
|
||||
// Listen
|
||||
os.Remove(endpoint)
|
||||
l, err := net.Listen("unix", endpoint)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: Unable to listen on %s socket: %v\n",
|
||||
endpoint,
|
||||
err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer os.Remove(endpoint)
|
||||
|
||||
// Start server
|
||||
if err := d.Start(l); err != nil {
|
||||
fmt.Printf("Error: Unable to start mock CSI server: %v\n",
|
||||
err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("mock driver started")
|
||||
|
||||
// Wait for signal
|
||||
sigc := make(chan os.Signal, 1)
|
||||
sigs := []os.Signal{
|
||||
syscall.SIGTERM,
|
||||
syscall.SIGHUP,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGQUIT,
|
||||
}
|
||||
signal.Notify(sigc, sigs...)
|
||||
|
||||
<-sigc
|
||||
d.Stop()
|
||||
fmt.Println("mock driver stopped")
|
||||
}
|
16
vendor/github.com/kubernetes-csi/csi-test/mock/mocksecret.yaml
generated
vendored
Normal file
16
vendor/github.com/kubernetes-csi/csi-test/mock/mocksecret.yaml
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
CreateVolumeSecret:
|
||||
secretKey: secretval1
|
||||
DeleteVolumeSecret:
|
||||
secretKey: secretval2
|
||||
ControllerPublishVolumeSecret:
|
||||
secretKey: secretval3
|
||||
ControllerUnpublishVolumeSecret:
|
||||
secretKey: secretval4
|
||||
NodeStageVolumeSecret:
|
||||
secretKey: secretval5
|
||||
NodePublishVolumeSecret:
|
||||
secretKey: secretval6
|
||||
CreateSnapshotSecret:
|
||||
secretKey: secretval7
|
||||
DeleteSnapshotSecret:
|
||||
secretKey: secretval8
|
559
vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go
generated
vendored
Normal file
559
vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go
generated
vendored
Normal file
@@ -0,0 +1,559 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxStorageCapacity = tib
|
||||
ReadOnlyKey = "readonly"
|
||||
)
|
||||
|
||||
func (s *service) CreateVolume(
|
||||
ctx context.Context,
|
||||
req *csi.CreateVolumeRequest) (
|
||||
*csi.CreateVolumeResponse, error) {
|
||||
|
||||
if len(req.Name) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume Name cannot be empty")
|
||||
}
|
||||
if req.VolumeCapabilities == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume Capabilities cannot be empty")
|
||||
}
|
||||
|
||||
// Check to see if the volume already exists.
|
||||
if i, v := s.findVolByName(ctx, req.Name); i >= 0 {
|
||||
// Requested volume name already exists, need to check if the existing volume's
|
||||
// capacity is more or equal to new request's capacity.
|
||||
if v.GetCapacityBytes() < req.GetCapacityRange().GetRequiredBytes() {
|
||||
return nil, status.Error(codes.AlreadyExists,
|
||||
fmt.Sprintf("Volume with name %s already exists", req.GetName()))
|
||||
}
|
||||
return &csi.CreateVolumeResponse{Volume: &v}, nil
|
||||
}
|
||||
|
||||
// If no capacity is specified then use 100GiB
|
||||
capacity := gib100
|
||||
if cr := req.CapacityRange; cr != nil {
|
||||
if rb := cr.RequiredBytes; rb > 0 {
|
||||
capacity = rb
|
||||
}
|
||||
if lb := cr.LimitBytes; lb > 0 {
|
||||
capacity = lb
|
||||
}
|
||||
}
|
||||
// Check for maximum available capacity
|
||||
if capacity >= MaxStorageCapacity {
|
||||
return nil, status.Errorf(codes.OutOfRange, "Requested capacity %d exceeds maximum allowed %d", capacity, MaxStorageCapacity)
|
||||
}
|
||||
// Create the volume and add it to the service's in-mem volume slice.
|
||||
v := s.newVolume(req.Name, capacity)
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
s.vols = append(s.vols, v)
|
||||
MockVolumes[v.Id] = Volume{
|
||||
VolumeCSI: v,
|
||||
NodeID: "",
|
||||
ISStaged: false,
|
||||
ISPublished: false,
|
||||
StageTargetPath: "",
|
||||
TargetPath: "",
|
||||
}
|
||||
|
||||
return &csi.CreateVolumeResponse{Volume: &v}, nil
|
||||
}
|
||||
|
||||
func (s *service) DeleteVolume(
|
||||
ctx context.Context,
|
||||
req *csi.DeleteVolumeRequest) (
|
||||
*csi.DeleteVolumeResponse, error) {
|
||||
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
|
||||
// If the volume is not specified, return error
|
||||
if len(req.VolumeId) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
|
||||
// If the volume does not exist then return an idempotent response.
|
||||
i, _ := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return &csi.DeleteVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
// This delete logic preserves order and prevents potential memory
|
||||
// leaks. The slice's elements may not be pointers, but the structs
|
||||
// themselves have fields that are.
|
||||
copy(s.vols[i:], s.vols[i+1:])
|
||||
s.vols[len(s.vols)-1] = csi.Volume{}
|
||||
s.vols = s.vols[:len(s.vols)-1]
|
||||
log.WithField("volumeID", req.VolumeId).Debug("mock delete volume")
|
||||
return &csi.DeleteVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *service) ControllerPublishVolume(
|
||||
ctx context.Context,
|
||||
req *csi.ControllerPublishVolumeRequest) (
|
||||
*csi.ControllerPublishVolumeResponse, error) {
|
||||
|
||||
if len(req.VolumeId) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
if len(req.NodeId) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Node ID cannot be empty")
|
||||
}
|
||||
if req.VolumeCapability == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume Capabilities cannot be empty")
|
||||
}
|
||||
|
||||
if req.NodeId != s.nodeID {
|
||||
return nil, status.Errorf(codes.NotFound, "Not matching Node ID %s to Mock Node ID %s", req.NodeId, s.nodeID)
|
||||
}
|
||||
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
|
||||
i, v := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return nil, status.Error(codes.NotFound, req.VolumeId)
|
||||
}
|
||||
|
||||
// devPathKey is the key in the volume's attributes that is set to a
|
||||
// mock device path if the volume has been published by the controller
|
||||
// to the specified node.
|
||||
devPathKey := path.Join(req.NodeId, "dev")
|
||||
|
||||
// Check to see if the volume is already published.
|
||||
if device := v.Attributes[devPathKey]; device != "" {
|
||||
var volRo bool
|
||||
var roVal string
|
||||
if ro, ok := v.Attributes[ReadOnlyKey]; ok {
|
||||
roVal = ro
|
||||
}
|
||||
|
||||
if roVal == "true" {
|
||||
volRo = true
|
||||
} else {
|
||||
volRo = false
|
||||
}
|
||||
|
||||
// Check if readonly flag is compatible with the publish request.
|
||||
if req.GetReadonly() != volRo {
|
||||
return nil, status.Error(codes.AlreadyExists, "Volume published but has incompatible readonly flag")
|
||||
}
|
||||
|
||||
return &csi.ControllerPublishVolumeResponse{
|
||||
PublishInfo: map[string]string{
|
||||
"device": device,
|
||||
"readonly": roVal,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var roVal string
|
||||
if req.GetReadonly() {
|
||||
roVal = "true"
|
||||
} else {
|
||||
roVal = "false"
|
||||
}
|
||||
|
||||
// Publish the volume.
|
||||
device := "/dev/mock"
|
||||
v.Attributes[devPathKey] = device
|
||||
v.Attributes[ReadOnlyKey] = roVal
|
||||
s.vols[i] = v
|
||||
|
||||
return &csi.ControllerPublishVolumeResponse{
|
||||
PublishInfo: map[string]string{
|
||||
"device": device,
|
||||
"readonly": roVal,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) ControllerUnpublishVolume(
|
||||
ctx context.Context,
|
||||
req *csi.ControllerUnpublishVolumeRequest) (
|
||||
*csi.ControllerUnpublishVolumeResponse, error) {
|
||||
|
||||
if len(req.VolumeId) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
nodeID := req.NodeId
|
||||
if len(nodeID) == 0 {
|
||||
// If node id is empty, no failure as per Spec
|
||||
nodeID = s.nodeID
|
||||
}
|
||||
|
||||
if req.NodeId != s.nodeID {
|
||||
return nil, status.Errorf(codes.NotFound, "Node ID %s does not match to expected Node ID %s", req.NodeId, s.nodeID)
|
||||
}
|
||||
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
|
||||
i, v := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return nil, status.Error(codes.NotFound, req.VolumeId)
|
||||
}
|
||||
|
||||
// devPathKey is the key in the volume's attributes that is set to a
|
||||
// mock device path if the volume has been published by the controller
|
||||
// to the specified node.
|
||||
devPathKey := path.Join(nodeID, "dev")
|
||||
|
||||
// Check to see if the volume is already unpublished.
|
||||
if v.Attributes[devPathKey] == "" {
|
||||
return &csi.ControllerUnpublishVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
// Unpublish the volume.
|
||||
delete(v.Attributes, devPathKey)
|
||||
delete(v.Attributes, ReadOnlyKey)
|
||||
s.vols[i] = v
|
||||
|
||||
return &csi.ControllerUnpublishVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *service) ValidateVolumeCapabilities(
|
||||
ctx context.Context,
|
||||
req *csi.ValidateVolumeCapabilitiesRequest) (
|
||||
*csi.ValidateVolumeCapabilitiesResponse, error) {
|
||||
|
||||
if len(req.GetVolumeId()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
if len(req.VolumeCapabilities) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, req.VolumeId)
|
||||
}
|
||||
i, _ := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return nil, status.Error(codes.NotFound, req.VolumeId)
|
||||
}
|
||||
|
||||
return &csi.ValidateVolumeCapabilitiesResponse{
|
||||
Supported: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) ListVolumes(
|
||||
ctx context.Context,
|
||||
req *csi.ListVolumesRequest) (
|
||||
*csi.ListVolumesResponse, error) {
|
||||
|
||||
// Copy the mock volumes into a new slice in order to avoid
|
||||
// locking the service's volume slice for the duration of the
|
||||
// ListVolumes RPC.
|
||||
var vols []csi.Volume
|
||||
func() {
|
||||
s.volsRWL.RLock()
|
||||
defer s.volsRWL.RUnlock()
|
||||
vols = make([]csi.Volume, len(s.vols))
|
||||
copy(vols, s.vols)
|
||||
}()
|
||||
|
||||
var (
|
||||
ulenVols = int32(len(vols))
|
||||
maxEntries = req.MaxEntries
|
||||
startingToken int32
|
||||
)
|
||||
|
||||
if v := req.StartingToken; v != "" {
|
||||
i, err := strconv.ParseUint(v, 10, 32)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"startingToken=%d !< int32=%d",
|
||||
startingToken, math.MaxUint32)
|
||||
}
|
||||
startingToken = int32(i)
|
||||
}
|
||||
|
||||
if startingToken > ulenVols {
|
||||
return nil, status.Errorf(
|
||||
codes.InvalidArgument,
|
||||
"startingToken=%d > len(vols)=%d",
|
||||
startingToken, ulenVols)
|
||||
}
|
||||
|
||||
// Discern the number of remaining entries.
|
||||
rem := ulenVols - startingToken
|
||||
|
||||
// If maxEntries is 0 or greater than the number of remaining entries then
|
||||
// set maxEntries to the number of remaining entries.
|
||||
if maxEntries == 0 || maxEntries > rem {
|
||||
maxEntries = rem
|
||||
}
|
||||
|
||||
var (
|
||||
i int
|
||||
j = startingToken
|
||||
entries = make(
|
||||
[]*csi.ListVolumesResponse_Entry,
|
||||
maxEntries)
|
||||
)
|
||||
|
||||
for i = 0; i < len(entries); i++ {
|
||||
entries[i] = &csi.ListVolumesResponse_Entry{
|
||||
Volume: &vols[j],
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
var nextToken string
|
||||
if n := startingToken + int32(i); n < ulenVols {
|
||||
nextToken = fmt.Sprintf("%d", n)
|
||||
}
|
||||
|
||||
return &csi.ListVolumesResponse{
|
||||
Entries: entries,
|
||||
NextToken: nextToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) GetCapacity(
|
||||
ctx context.Context,
|
||||
req *csi.GetCapacityRequest) (
|
||||
*csi.GetCapacityResponse, error) {
|
||||
|
||||
return &csi.GetCapacityResponse{
|
||||
AvailableCapacity: MaxStorageCapacity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) ControllerGetCapabilities(
|
||||
ctx context.Context,
|
||||
req *csi.ControllerGetCapabilitiesRequest) (
|
||||
*csi.ControllerGetCapabilitiesResponse, error) {
|
||||
|
||||
return &csi.ControllerGetCapabilitiesResponse{
|
||||
Capabilities: []*csi.ControllerServiceCapability{
|
||||
{
|
||||
Type: &csi.ControllerServiceCapability_Rpc{
|
||||
Rpc: &csi.ControllerServiceCapability_RPC{
|
||||
Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: &csi.ControllerServiceCapability_Rpc{
|
||||
Rpc: &csi.ControllerServiceCapability_RPC{
|
||||
Type: csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: &csi.ControllerServiceCapability_Rpc{
|
||||
Rpc: &csi.ControllerServiceCapability_RPC{
|
||||
Type: csi.ControllerServiceCapability_RPC_LIST_VOLUMES,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: &csi.ControllerServiceCapability_Rpc{
|
||||
Rpc: &csi.ControllerServiceCapability_RPC{
|
||||
Type: csi.ControllerServiceCapability_RPC_GET_CAPACITY,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: &csi.ControllerServiceCapability_Rpc{
|
||||
Rpc: &csi.ControllerServiceCapability_RPC{
|
||||
Type: csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: &csi.ControllerServiceCapability_Rpc{
|
||||
Rpc: &csi.ControllerServiceCapability_RPC{
|
||||
Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) CreateSnapshot(ctx context.Context,
|
||||
req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
|
||||
// Check arguments
|
||||
if len(req.GetName()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Snapshot Name cannot be empty")
|
||||
}
|
||||
if len(req.GetSourceVolumeId()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Snapshot SourceVolumeId cannot be empty")
|
||||
}
|
||||
|
||||
// Check to see if the snapshot already exists.
|
||||
if i, v := s.snapshots.FindSnapshot("name", req.GetName()); i >= 0 {
|
||||
// Requested snapshot name already exists
|
||||
if v.SnapshotCSI.GetSourceVolumeId() != req.GetSourceVolumeId() || !reflect.DeepEqual(v.Parameters, req.GetParameters()) {
|
||||
return nil, status.Error(codes.AlreadyExists,
|
||||
fmt.Sprintf("Snapshot with name %s already exists", req.GetName()))
|
||||
}
|
||||
return &csi.CreateSnapshotResponse{Snapshot: &v.SnapshotCSI}, nil
|
||||
}
|
||||
|
||||
// Create the snapshot and add it to the service's in-mem snapshot slice.
|
||||
snapshot := s.newSnapshot(req.GetName(), req.GetSourceVolumeId(), req.GetParameters())
|
||||
s.snapshots.Add(snapshot)
|
||||
|
||||
return &csi.CreateSnapshotResponse{Snapshot: &snapshot.SnapshotCSI}, nil
|
||||
}
|
||||
|
||||
func (s *service) DeleteSnapshot(ctx context.Context,
|
||||
req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
|
||||
|
||||
// If the snapshot is not specified, return error
|
||||
if len(req.SnapshotId) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Snapshot ID cannot be empty")
|
||||
}
|
||||
|
||||
// If the snapshot does not exist then return an idempotent response.
|
||||
i, _ := s.snapshots.FindSnapshot("id", req.SnapshotId)
|
||||
if i < 0 {
|
||||
return &csi.DeleteSnapshotResponse{}, nil
|
||||
}
|
||||
|
||||
// This delete logic preserves order and prevents potential memory
|
||||
// leaks. The slice's elements may not be pointers, but the structs
|
||||
// themselves have fields that are.
|
||||
s.snapshots.Delete(i)
|
||||
log.WithField("SnapshotId", req.SnapshotId).Debug("mock delete snapshot")
|
||||
return &csi.DeleteSnapshotResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *service) ListSnapshots(ctx context.Context,
|
||||
req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
|
||||
|
||||
// case 1: SnapshotId is not empty, return snapshots that match the snapshot id.
|
||||
if len(req.GetSnapshotId()) != 0 {
|
||||
return getSnapshotById(s, req)
|
||||
}
|
||||
|
||||
// case 2: SourceVolumeId is not empty, return snapshots that match the source volume id.
|
||||
if len(req.GetSourceVolumeId()) != 0 {
|
||||
return getSnapshotByVolumeId(s, req)
|
||||
}
|
||||
|
||||
// case 3: no parameter is set, so we return all the snapshots.
|
||||
return getAllSnapshots(s, req)
|
||||
}
|
||||
|
||||
func getSnapshotById(s *service, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
|
||||
if len(req.GetSnapshotId()) != 0 {
|
||||
i, snapshot := s.snapshots.FindSnapshot("id", req.GetSnapshotId())
|
||||
if i < 0 {
|
||||
return &csi.ListSnapshotsResponse{}, nil
|
||||
}
|
||||
|
||||
if len(req.GetSourceVolumeId()) != 0 {
|
||||
if snapshot.SnapshotCSI.GetSourceVolumeId() != req.GetSourceVolumeId() {
|
||||
return &csi.ListSnapshotsResponse{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &csi.ListSnapshotsResponse{
|
||||
Entries: []*csi.ListSnapshotsResponse_Entry{
|
||||
{
|
||||
Snapshot: &snapshot.SnapshotCSI,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func getSnapshotByVolumeId(s *service, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
|
||||
if len(req.GetSourceVolumeId()) != 0 {
|
||||
i, snapshot := s.snapshots.FindSnapshot("sourceVolumeId", req.SourceVolumeId)
|
||||
if i < 0 {
|
||||
return &csi.ListSnapshotsResponse{}, nil
|
||||
}
|
||||
return &csi.ListSnapshotsResponse{
|
||||
Entries: []*csi.ListSnapshotsResponse_Entry{
|
||||
{
|
||||
Snapshot: &snapshot.SnapshotCSI,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func getAllSnapshots(s *service, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
|
||||
// Copy the mock snapshots into a new slice in order to avoid
|
||||
// locking the service's snapshot slice for the duration of the
|
||||
// ListSnapshots RPC.
|
||||
snapshots := s.snapshots.List(csi.SnapshotStatus_READY)
|
||||
|
||||
var (
|
||||
ulenSnapshots = int32(len(snapshots))
|
||||
maxEntries = req.MaxEntries
|
||||
startingToken int32
|
||||
)
|
||||
|
||||
if v := req.StartingToken; v != "" {
|
||||
i, err := strconv.ParseUint(v, 10, 32)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(
|
||||
codes.Aborted,
|
||||
"startingToken=%d !< int32=%d",
|
||||
startingToken, math.MaxUint32)
|
||||
}
|
||||
startingToken = int32(i)
|
||||
}
|
||||
|
||||
if startingToken > ulenSnapshots {
|
||||
return nil, status.Errorf(
|
||||
codes.Aborted,
|
||||
"startingToken=%d > len(snapshots)=%d",
|
||||
startingToken, ulenSnapshots)
|
||||
}
|
||||
|
||||
// Discern the number of remaining entries.
|
||||
rem := ulenSnapshots - startingToken
|
||||
|
||||
// If maxEntries is 0 or greater than the number of remaining entries then
|
||||
// set maxEntries to the number of remaining entries.
|
||||
if maxEntries == 0 || maxEntries > rem {
|
||||
maxEntries = rem
|
||||
}
|
||||
|
||||
var (
|
||||
i int
|
||||
j = startingToken
|
||||
entries = make(
|
||||
[]*csi.ListSnapshotsResponse_Entry,
|
||||
maxEntries)
|
||||
)
|
||||
|
||||
for i = 0; i < len(entries); i++ {
|
||||
entries[i] = &csi.ListSnapshotsResponse_Entry{
|
||||
Snapshot: &snapshots[j],
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
var nextToken string
|
||||
if n := startingToken + int32(i); n < ulenSnapshots {
|
||||
nextToken = fmt.Sprintf("%d", n)
|
||||
}
|
||||
|
||||
return &csi.ListSnapshotsResponse{
|
||||
Entries: entries,
|
||||
NextToken: nextToken,
|
||||
}, nil
|
||||
}
|
48
vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go
generated
vendored
Normal file
48
vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
)
|
||||
|
||||
func (s *service) GetPluginInfo(
|
||||
ctx context.Context,
|
||||
req *csi.GetPluginInfoRequest) (
|
||||
*csi.GetPluginInfoResponse, error) {
|
||||
|
||||
return &csi.GetPluginInfoResponse{
|
||||
Name: Name,
|
||||
VendorVersion: VendorVersion,
|
||||
Manifest: Manifest,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) Probe(
|
||||
ctx context.Context,
|
||||
req *csi.ProbeRequest) (
|
||||
*csi.ProbeResponse, error) {
|
||||
|
||||
return &csi.ProbeResponse{
|
||||
Ready: &wrappers.BoolValue{Value: true},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) GetPluginCapabilities(
|
||||
ctx context.Context,
|
||||
req *csi.GetPluginCapabilitiesRequest) (
|
||||
*csi.GetPluginCapabilitiesResponse, error) {
|
||||
|
||||
return &csi.GetPluginCapabilitiesResponse{
|
||||
Capabilities: []*csi.PluginCapability{
|
||||
{
|
||||
Type: &csi.PluginCapability_Service_{
|
||||
Service: &csi.PluginCapability_Service{
|
||||
Type: csi.PluginCapability_Service_CONTROLLER_SERVICE,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
236
vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go
generated
vendored
Normal file
236
vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go
generated
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
)
|
||||
|
||||
func (s *service) NodeStageVolume(
|
||||
ctx context.Context,
|
||||
req *csi.NodeStageVolumeRequest) (
|
||||
*csi.NodeStageVolumeResponse, error) {
|
||||
|
||||
device, ok := req.PublishInfo["device"]
|
||||
if !ok {
|
||||
return nil, status.Error(
|
||||
codes.InvalidArgument,
|
||||
"stage volume info 'device' key required")
|
||||
}
|
||||
|
||||
if len(req.GetVolumeId()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
|
||||
if len(req.GetStagingTargetPath()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Staging Target Path cannot be empty")
|
||||
}
|
||||
|
||||
if req.GetVolumeCapability() == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume Capability cannot be empty")
|
||||
}
|
||||
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
|
||||
i, v := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return nil, status.Error(codes.NotFound, req.VolumeId)
|
||||
}
|
||||
|
||||
// nodeStgPathKey is the key in the volume's attributes that is set to a
|
||||
// mock stage path if the volume has been published by the node
|
||||
nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath)
|
||||
|
||||
// Check to see if the volume has already been staged.
|
||||
if v.Attributes[nodeStgPathKey] != "" {
|
||||
// TODO: Check for the capabilities to be equal. Return "ALREADY_EXISTS"
|
||||
// if the capabilities don't match.
|
||||
return &csi.NodeStageVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
// Stage the volume.
|
||||
v.Attributes[nodeStgPathKey] = device
|
||||
s.vols[i] = v
|
||||
|
||||
return &csi.NodeStageVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *service) NodeUnstageVolume(
|
||||
ctx context.Context,
|
||||
req *csi.NodeUnstageVolumeRequest) (
|
||||
*csi.NodeUnstageVolumeResponse, error) {
|
||||
|
||||
if len(req.GetVolumeId()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
|
||||
if len(req.GetStagingTargetPath()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Staging Target Path cannot be empty")
|
||||
}
|
||||
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
|
||||
i, v := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return nil, status.Error(codes.NotFound, req.VolumeId)
|
||||
}
|
||||
|
||||
// nodeStgPathKey is the key in the volume's attributes that is set to a
|
||||
// mock stage path if the volume has been published by the node
|
||||
nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath)
|
||||
|
||||
// Check to see if the volume has already been unstaged.
|
||||
if v.Attributes[nodeStgPathKey] == "" {
|
||||
return &csi.NodeUnstageVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
// Unpublish the volume.
|
||||
delete(v.Attributes, nodeStgPathKey)
|
||||
s.vols[i] = v
|
||||
|
||||
return &csi.NodeUnstageVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *service) NodePublishVolume(
|
||||
ctx context.Context,
|
||||
req *csi.NodePublishVolumeRequest) (
|
||||
*csi.NodePublishVolumeResponse, error) {
|
||||
|
||||
device, ok := req.PublishInfo["device"]
|
||||
if !ok {
|
||||
return nil, status.Error(
|
||||
codes.InvalidArgument,
|
||||
"publish volume info 'device' key required")
|
||||
}
|
||||
|
||||
if len(req.GetVolumeId()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
|
||||
if len(req.GetTargetPath()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Target Path cannot be empty")
|
||||
}
|
||||
|
||||
if req.GetVolumeCapability() == nil {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume Capability cannot be empty")
|
||||
}
|
||||
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
|
||||
i, v := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return nil, status.Error(codes.NotFound, req.VolumeId)
|
||||
}
|
||||
|
||||
// nodeMntPathKey is the key in the volume's attributes that is set to a
|
||||
// mock mount path if the volume has been published by the node
|
||||
nodeMntPathKey := path.Join(s.nodeID, req.TargetPath)
|
||||
|
||||
// Check to see if the volume has already been published.
|
||||
if v.Attributes[nodeMntPathKey] != "" {
|
||||
|
||||
// Requests marked Readonly fail due to volumes published by
|
||||
// the Mock driver supporting only RW mode.
|
||||
if req.Readonly {
|
||||
return nil, status.Error(codes.AlreadyExists, req.VolumeId)
|
||||
}
|
||||
|
||||
return &csi.NodePublishVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
// Publish the volume.
|
||||
if req.GetStagingTargetPath() != "" {
|
||||
v.Attributes[nodeMntPathKey] = req.GetStagingTargetPath()
|
||||
} else {
|
||||
v.Attributes[nodeMntPathKey] = device
|
||||
}
|
||||
s.vols[i] = v
|
||||
|
||||
return &csi.NodePublishVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *service) NodeUnpublishVolume(
|
||||
ctx context.Context,
|
||||
req *csi.NodeUnpublishVolumeRequest) (
|
||||
*csi.NodeUnpublishVolumeResponse, error) {
|
||||
|
||||
if len(req.GetVolumeId()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
|
||||
}
|
||||
if len(req.GetTargetPath()) == 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "Target Path cannot be empty")
|
||||
}
|
||||
|
||||
s.volsRWL.Lock()
|
||||
defer s.volsRWL.Unlock()
|
||||
|
||||
i, v := s.findVolNoLock("id", req.VolumeId)
|
||||
if i < 0 {
|
||||
return nil, status.Error(codes.NotFound, req.VolumeId)
|
||||
}
|
||||
|
||||
// nodeMntPathKey is the key in the volume's attributes that is set to a
|
||||
// mock mount path if the volume has been published by the node
|
||||
nodeMntPathKey := path.Join(s.nodeID, req.TargetPath)
|
||||
|
||||
// Check to see if the volume has already been unpublished.
|
||||
if v.Attributes[nodeMntPathKey] == "" {
|
||||
return &csi.NodeUnpublishVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
// Unpublish the volume.
|
||||
delete(v.Attributes, nodeMntPathKey)
|
||||
s.vols[i] = v
|
||||
|
||||
return &csi.NodeUnpublishVolumeResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *service) NodeGetId(
|
||||
ctx context.Context,
|
||||
req *csi.NodeGetIdRequest) (
|
||||
*csi.NodeGetIdResponse, error) {
|
||||
|
||||
return &csi.NodeGetIdResponse{
|
||||
NodeId: s.nodeID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) NodeGetCapabilities(
|
||||
ctx context.Context,
|
||||
req *csi.NodeGetCapabilitiesRequest) (
|
||||
*csi.NodeGetCapabilitiesResponse, error) {
|
||||
|
||||
return &csi.NodeGetCapabilitiesResponse{
|
||||
Capabilities: []*csi.NodeServiceCapability{
|
||||
{
|
||||
Type: &csi.NodeServiceCapability_Rpc{
|
||||
Rpc: &csi.NodeServiceCapability_RPC{
|
||||
Type: csi.NodeServiceCapability_RPC_UNKNOWN,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: &csi.NodeServiceCapability_Rpc{
|
||||
Rpc: &csi.NodeServiceCapability_RPC{
|
||||
Type: csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *service) NodeGetInfo(ctx context.Context,
|
||||
req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
|
||||
return &csi.NodeGetInfoResponse{
|
||||
NodeId: s.nodeID,
|
||||
}, nil
|
||||
}
|
137
vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go
generated
vendored
Normal file
137
vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
"github.com/kubernetes-csi/csi-test/mock/cache"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
// Name is the name of the CSI plug-in.
|
||||
Name = "io.kubernetes.storage.mock"
|
||||
|
||||
// VendorVersion is the version returned by GetPluginInfo.
|
||||
VendorVersion = "0.3.0"
|
||||
)
|
||||
|
||||
// Manifest is the SP's manifest.
|
||||
var Manifest = map[string]string{
|
||||
"url": "https://github.com/kubernetes-csi/csi-test/mock",
|
||||
}
|
||||
|
||||
// Service is the CSI Mock service provider.
|
||||
type Service interface {
|
||||
csi.ControllerServer
|
||||
csi.IdentityServer
|
||||
csi.NodeServer
|
||||
}
|
||||
|
||||
type service struct {
|
||||
sync.Mutex
|
||||
nodeID string
|
||||
vols []csi.Volume
|
||||
volsRWL sync.RWMutex
|
||||
volsNID uint64
|
||||
snapshots cache.SnapshotCache
|
||||
snapshotsNID uint64
|
||||
}
|
||||
|
||||
type Volume struct {
|
||||
sync.Mutex
|
||||
VolumeCSI csi.Volume
|
||||
NodeID string
|
||||
ISStaged bool
|
||||
ISPublished bool
|
||||
StageTargetPath string
|
||||
TargetPath string
|
||||
}
|
||||
|
||||
var MockVolumes map[string]Volume
|
||||
|
||||
// New returns a new Service.
|
||||
func New() Service {
|
||||
s := &service{nodeID: Name}
|
||||
s.snapshots = cache.NewSnapshotCache()
|
||||
s.vols = []csi.Volume{
|
||||
s.newVolume("Mock Volume 1", gib100),
|
||||
s.newVolume("Mock Volume 2", gib100),
|
||||
s.newVolume("Mock Volume 3", gib100),
|
||||
}
|
||||
MockVolumes = map[string]Volume{}
|
||||
|
||||
s.snapshots.Add(s.newSnapshot("Mock Snapshot 1", "1", map[string]string{"Description": "snapshot 1"}))
|
||||
s.snapshots.Add(s.newSnapshot("Mock Snapshot 2", "2", map[string]string{"Description": "snapshot 2"}))
|
||||
s.snapshots.Add(s.newSnapshot("Mock Snapshot 3", "3", map[string]string{"Description": "snapshot 3"}))
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
const (
|
||||
kib int64 = 1024
|
||||
mib int64 = kib * 1024
|
||||
gib int64 = mib * 1024
|
||||
gib100 int64 = gib * 100
|
||||
tib int64 = gib * 1024
|
||||
tib100 int64 = tib * 100
|
||||
)
|
||||
|
||||
func (s *service) newVolume(name string, capcity int64) csi.Volume {
|
||||
return csi.Volume{
|
||||
Id: fmt.Sprintf("%d", atomic.AddUint64(&s.volsNID, 1)),
|
||||
Attributes: map[string]string{"name": name},
|
||||
CapacityBytes: capcity,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) findVol(k, v string) (volIdx int, volInfo csi.Volume) {
|
||||
s.volsRWL.RLock()
|
||||
defer s.volsRWL.RUnlock()
|
||||
return s.findVolNoLock(k, v)
|
||||
}
|
||||
|
||||
func (s *service) findVolNoLock(k, v string) (volIdx int, volInfo csi.Volume) {
|
||||
volIdx = -1
|
||||
|
||||
for i, vi := range s.vols {
|
||||
switch k {
|
||||
case "id":
|
||||
if strings.EqualFold(v, vi.Id) {
|
||||
return i, vi
|
||||
}
|
||||
case "name":
|
||||
if n, ok := vi.Attributes["name"]; ok && strings.EqualFold(v, n) {
|
||||
return i, vi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *service) findVolByName(
|
||||
ctx context.Context, name string) (int, csi.Volume) {
|
||||
|
||||
return s.findVol("name", name)
|
||||
}
|
||||
|
||||
func (s *service) newSnapshot(name, sourceVolumeId string, parameters map[string]string) cache.Snapshot {
|
||||
return cache.Snapshot{
|
||||
Name: name,
|
||||
Parameters: parameters,
|
||||
SnapshotCSI: csi.Snapshot{
|
||||
Id: fmt.Sprintf("%d", atomic.AddUint64(&s.snapshotsNID, 1)),
|
||||
CreatedAt: time.Now().UnixNano(),
|
||||
SourceVolumeId: sourceVolumeId,
|
||||
Status: &csi.SnapshotStatus{
|
||||
Type: csi.SnapshotStatus_READY,
|
||||
Details: "snapshot ready",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
62
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md
generated
vendored
Normal file
62
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# CSI Driver Sanity Tester
|
||||
|
||||
This library provides a simple way to ensure that a CSI driver conforms to
|
||||
the CSI specification. There are two ways to leverage this testing framework.
|
||||
For CSI drivers written in Golang, the framework provides a simple API function
|
||||
to call to test the driver. Another way to run the test suite is to use the
|
||||
command line program [csi-sanity](https://github.com/kubernetes-csi/csi-test/tree/master/cmd/csi-sanity).
|
||||
|
||||
## For Golang CSI Drivers
|
||||
This framework leverages the Ginkgo BDD testing framework to deliver a descriptive
|
||||
test suite for your driver. To test your driver, simply call the API in one of your
|
||||
Golang `TestXXX` functions. For example:
|
||||
|
||||
```go
|
||||
func TestMyDriver(t *testing.T) {
|
||||
// Setup the full driver and its environment
|
||||
... setup driver ...
|
||||
config := &sanity.Config{
|
||||
TargetPath: ...
|
||||
StagingPath: ...
|
||||
Address: endpoint,
|
||||
}
|
||||
|
||||
|
||||
// Now call the test suite
|
||||
sanity.Test(t, config)
|
||||
}
|
||||
```
|
||||
|
||||
Only one such test function is supported because under the hood a
|
||||
Ginkgo test suite gets constructed and executed by the call.
|
||||
|
||||
Alternatively, the tests can also be embedded inside a Ginkgo test
|
||||
suite. In that case it is possible to define multiple tests with
|
||||
different configurations:
|
||||
|
||||
```go
|
||||
var _ = Describe("MyCSIDriver", func () {
|
||||
Context("Config A", func () {
|
||||
var config &sanity.Config
|
||||
|
||||
BeforeEach() {
|
||||
... setup driver and config...
|
||||
}
|
||||
|
||||
AfterEach() {
|
||||
...tear down driver...
|
||||
}
|
||||
|
||||
Describe("CSI sanity", func() {
|
||||
sanity.GinkgoTest(config)
|
||||
})
|
||||
})
|
||||
|
||||
Context("Config B", func () {
|
||||
...
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## Command line program
|
||||
Please see [csi-sanity](https://github.com/kubernetes-csi/csi-test/tree/master/cmd/csi-sanity)
|
134
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go
generated
vendored
Normal file
134
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sanity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
)
|
||||
|
||||
// VolumeInfo keeps track of the information needed to delete a volume.
|
||||
type VolumeInfo struct {
|
||||
// Node on which the volume was published, empty if none
|
||||
// or publishing is not supported.
|
||||
NodeID string
|
||||
|
||||
// Volume ID assigned by CreateVolume.
|
||||
VolumeID string
|
||||
}
|
||||
|
||||
// Cleanup keeps track of resources, in particular volumes, which need
|
||||
// to be freed when testing is done.
|
||||
type Cleanup struct {
|
||||
Context *SanityContext
|
||||
ControllerClient csi.ControllerClient
|
||||
NodeClient csi.NodeClient
|
||||
ControllerPublishSupported bool
|
||||
NodeStageSupported bool
|
||||
|
||||
// Maps from volume name to the node ID for which the volume
|
||||
// is published and the volume ID.
|
||||
volumes map[string]VolumeInfo
|
||||
}
|
||||
|
||||
// RegisterVolume adds or updates an entry for the volume with the
|
||||
// given name.
|
||||
func (cl *Cleanup) RegisterVolume(name string, info VolumeInfo) {
|
||||
if cl.volumes == nil {
|
||||
cl.volumes = make(map[string]VolumeInfo)
|
||||
}
|
||||
cl.volumes[name] = info
|
||||
}
|
||||
|
||||
// MaybeRegisterVolume adds or updates an entry for the volume with
|
||||
// the given name if CreateVolume was successful.
|
||||
func (cl *Cleanup) MaybeRegisterVolume(name string, vol *csi.CreateVolumeResponse, err error) {
|
||||
if err == nil && vol.GetVolume().GetId() != "" {
|
||||
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})
|
||||
}
|
||||
}
|
||||
|
||||
// UnregisterVolume removes the entry for the volume with the
|
||||
// given name, thus preventing all cleanup operations for it.
|
||||
func (cl *Cleanup) UnregisterVolume(name string) {
|
||||
if cl.volumes != nil {
|
||||
delete(cl.volumes, name)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteVolumes stops using the registered volumes and tries to delete all of them.
|
||||
func (cl *Cleanup) DeleteVolumes() {
|
||||
if cl.volumes == nil {
|
||||
return
|
||||
}
|
||||
logger := log.New(GinkgoWriter, "cleanup: ", 0)
|
||||
ctx := context.Background()
|
||||
|
||||
for name, info := range cl.volumes {
|
||||
logger.Printf("deleting %s = %s", name, info.VolumeID)
|
||||
if _, err := cl.NodeClient.NodeUnpublishVolume(
|
||||
ctx,
|
||||
&csi.NodeUnpublishVolumeRequest{
|
||||
VolumeId: info.VolumeID,
|
||||
TargetPath: cl.Context.Config.TargetPath,
|
||||
},
|
||||
); err != nil {
|
||||
logger.Printf("warning: NodeUnpublishVolume: %s", err)
|
||||
}
|
||||
|
||||
if cl.NodeStageSupported {
|
||||
if _, err := cl.NodeClient.NodeUnstageVolume(
|
||||
ctx,
|
||||
&csi.NodeUnstageVolumeRequest{
|
||||
VolumeId: info.VolumeID,
|
||||
StagingTargetPath: cl.Context.Config.StagingPath,
|
||||
},
|
||||
); err != nil {
|
||||
logger.Printf("warning: NodeUnstageVolume: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if cl.ControllerPublishSupported && info.NodeID != "" {
|
||||
if _, err := cl.ControllerClient.ControllerUnpublishVolume(
|
||||
ctx,
|
||||
&csi.ControllerUnpublishVolumeRequest{
|
||||
VolumeId: info.VolumeID,
|
||||
NodeId: info.NodeID,
|
||||
ControllerUnpublishSecrets: cl.Context.Secrets.ControllerUnpublishVolumeSecret,
|
||||
},
|
||||
); err != nil {
|
||||
logger.Printf("warning: ControllerUnpublishVolume: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := cl.ControllerClient.DeleteVolume(
|
||||
ctx,
|
||||
&csi.DeleteVolumeRequest{
|
||||
VolumeId: info.VolumeID,
|
||||
ControllerDeleteSecrets: cl.Context.Secrets.DeleteVolumeSecret,
|
||||
},
|
||||
); err != nil {
|
||||
logger.Printf("error: DeleteVolume: %s", err)
|
||||
}
|
||||
|
||||
cl.UnregisterVolume(name)
|
||||
}
|
||||
}
|
1626
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go
generated
vendored
Normal file
1626
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
99
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go
generated
vendored
Normal file
99
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sanity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = DescribeSanity("Identity Service", func(sc *SanityContext) {
|
||||
var (
|
||||
c csi.IdentityClient
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
c = csi.NewIdentityClient(sc.Conn)
|
||||
})
|
||||
|
||||
Describe("GetPluginCapabilities", func() {
|
||||
It("should return appropriate capabilities", func() {
|
||||
req := &csi.GetPluginCapabilitiesRequest{}
|
||||
res, err := c.GetPluginCapabilities(context.Background(), req)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(res).NotTo(BeNil())
|
||||
|
||||
By("checking successful response")
|
||||
Expect(res.GetCapabilities()).NotTo(BeNil())
|
||||
for _, cap := range res.GetCapabilities() {
|
||||
switch cap.GetService().GetType() {
|
||||
case csi.PluginCapability_Service_CONTROLLER_SERVICE:
|
||||
case csi.PluginCapability_Service_ACCESSIBILITY_CONSTRAINTS:
|
||||
default:
|
||||
Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetService().GetType()))
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
Describe("Probe", func() {
|
||||
It("should return appropriate information", func() {
|
||||
req := &csi.ProbeRequest{}
|
||||
res, err := c.Probe(context.Background(), req)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(res).NotTo(BeNil())
|
||||
|
||||
By("verifying return status")
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code() == codes.FailedPrecondition ||
|
||||
serverError.Code() == codes.OK).To(BeTrue())
|
||||
|
||||
if res.GetReady() != nil {
|
||||
Expect(res.GetReady().GetValue() == true ||
|
||||
res.GetReady().GetValue() == false).To(BeTrue())
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Describe("GetPluginInfo", func() {
|
||||
It("should return appropriate information", func() {
|
||||
req := &csi.GetPluginInfoRequest{}
|
||||
res, err := c.GetPluginInfo(context.Background(), req)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(res).NotTo(BeNil())
|
||||
|
||||
By("verifying name size and characters")
|
||||
Expect(res.GetName()).ToNot(HaveLen(0))
|
||||
Expect(len(res.GetName())).To(BeNumerically("<=", 63))
|
||||
Expect(regexp.
|
||||
MustCompile("^[a-zA-Z][A-Za-z0-9-\\.\\_]{0,61}[a-zA-Z]$").
|
||||
MatchString(res.GetName())).To(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
528
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go
generated
vendored
Normal file
528
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go
generated
vendored
Normal file
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
Copyright 2017 Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sanity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func isNodeCapabilitySupported(c csi.NodeClient,
|
||||
capType csi.NodeServiceCapability_RPC_Type,
|
||||
) bool {
|
||||
|
||||
caps, err := c.NodeGetCapabilities(
|
||||
context.Background(),
|
||||
&csi.NodeGetCapabilitiesRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(caps).NotTo(BeNil())
|
||||
|
||||
for _, cap := range caps.GetCapabilities() {
|
||||
Expect(cap.GetRpc()).NotTo(BeNil())
|
||||
if cap.GetRpc().GetType() == capType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isPluginCapabilitySupported(c csi.IdentityClient,
|
||||
capType csi.PluginCapability_Service_Type,
|
||||
) bool {
|
||||
|
||||
caps, err := c.GetPluginCapabilities(
|
||||
context.Background(),
|
||||
&csi.GetPluginCapabilitiesRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(caps).NotTo(BeNil())
|
||||
Expect(caps.GetCapabilities()).NotTo(BeNil())
|
||||
|
||||
for _, cap := range caps.GetCapabilities() {
|
||||
Expect(cap.GetService()).NotTo(BeNil())
|
||||
if cap.GetService().GetType() == capType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
|
||||
var (
|
||||
cl *Cleanup
|
||||
c csi.NodeClient
|
||||
s csi.ControllerClient
|
||||
|
||||
controllerPublishSupported bool
|
||||
nodeStageSupported bool
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
c = csi.NewNodeClient(sc.Conn)
|
||||
s = csi.NewControllerClient(sc.Conn)
|
||||
|
||||
controllerPublishSupported = isControllerCapabilitySupported(
|
||||
s,
|
||||
csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME)
|
||||
nodeStageSupported = isNodeCapabilitySupported(c, csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME)
|
||||
if nodeStageSupported {
|
||||
err := createMountTargetLocation(sc.Config.StagingPath)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
cl = &Cleanup{
|
||||
Context: sc,
|
||||
NodeClient: c,
|
||||
ControllerClient: s,
|
||||
ControllerPublishSupported: controllerPublishSupported,
|
||||
NodeStageSupported: nodeStageSupported,
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
cl.DeleteVolumes()
|
||||
})
|
||||
|
||||
Describe("NodeGetCapabilities", func() {
|
||||
It("should return appropriate capabilities", func() {
|
||||
caps, err := c.NodeGetCapabilities(
|
||||
context.Background(),
|
||||
&csi.NodeGetCapabilitiesRequest{})
|
||||
|
||||
By("checking successful response")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(caps).NotTo(BeNil())
|
||||
|
||||
for _, cap := range caps.GetCapabilities() {
|
||||
Expect(cap.GetRpc()).NotTo(BeNil())
|
||||
|
||||
switch cap.GetRpc().GetType() {
|
||||
case csi.NodeServiceCapability_RPC_UNKNOWN:
|
||||
case csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME:
|
||||
default:
|
||||
Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType()))
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Describe("NodeGetId", func() {
|
||||
It("should return appropriate values", func() {
|
||||
nid, err := c.NodeGetId(
|
||||
context.Background(),
|
||||
&csi.NodeGetIdRequest{})
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(nid).NotTo(BeNil())
|
||||
Expect(nid.GetNodeId()).NotTo(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("NodeGetInfo", func() {
|
||||
var (
|
||||
i csi.IdentityClient
|
||||
accessibilityConstraintSupported bool
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
i = csi.NewIdentityClient(sc.Conn)
|
||||
accessibilityConstraintSupported = isPluginCapabilitySupported(i, csi.PluginCapability_Service_ACCESSIBILITY_CONSTRAINTS)
|
||||
})
|
||||
|
||||
It("should return approproate values", func() {
|
||||
ninfo, err := c.NodeGetInfo(
|
||||
context.Background(),
|
||||
&csi.NodeGetInfoRequest{})
|
||||
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(ninfo).NotTo(BeNil())
|
||||
Expect(ninfo.GetNodeId()).NotTo(BeEmpty())
|
||||
Expect(ninfo.GetMaxVolumesPerNode()).NotTo(BeNumerically("<", 0))
|
||||
|
||||
if accessibilityConstraintSupported {
|
||||
Expect(ninfo.GetAccessibleTopology()).NotTo(BeNil())
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Describe("NodePublishVolume", func() {
|
||||
It("should fail when no volume id is provided", func() {
|
||||
_, err := c.NodePublishVolume(
|
||||
context.Background(),
|
||||
&csi.NodePublishVolumeRequest{
|
||||
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
|
||||
It("should fail when no target path is provided", func() {
|
||||
_, err := c.NodePublishVolume(
|
||||
context.Background(),
|
||||
&csi.NodePublishVolumeRequest{
|
||||
VolumeId: "id",
|
||||
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
|
||||
It("should fail when no volume capability is provided", func() {
|
||||
_, err := c.NodePublishVolume(
|
||||
context.Background(),
|
||||
&csi.NodePublishVolumeRequest{
|
||||
VolumeId: "id",
|
||||
TargetPath: sc.Config.TargetPath,
|
||||
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("NodeUnpublishVolume", func() {
|
||||
It("should fail when no volume id is provided", func() {
|
||||
|
||||
_, err := c.NodeUnpublishVolume(
|
||||
context.Background(),
|
||||
&csi.NodeUnpublishVolumeRequest{})
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
|
||||
It("should fail when no target path is provided", func() {
|
||||
|
||||
_, err := c.NodeUnpublishVolume(
|
||||
context.Background(),
|
||||
&csi.NodeUnpublishVolumeRequest{
|
||||
VolumeId: "id",
|
||||
})
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("NodeStageVolume", func() {
|
||||
var (
|
||||
device string
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
if !nodeStageSupported {
|
||||
Skip("NodeStageVolume not supported")
|
||||
}
|
||||
|
||||
device = "/dev/mock"
|
||||
})
|
||||
|
||||
It("should fail when no volume id is provided", func() {
|
||||
_, err := c.NodeStageVolume(
|
||||
context.Background(),
|
||||
&csi.NodeStageVolumeRequest{
|
||||
StagingTargetPath: sc.Config.StagingPath,
|
||||
VolumeCapability: &csi.VolumeCapability{
|
||||
AccessType: &csi.VolumeCapability_Mount{
|
||||
Mount: &csi.VolumeCapability_MountVolume{},
|
||||
},
|
||||
AccessMode: &csi.VolumeCapability_AccessMode{
|
||||
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
|
||||
},
|
||||
},
|
||||
PublishInfo: map[string]string{
|
||||
"device": device,
|
||||
},
|
||||
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
|
||||
It("should fail when no staging target path is provided", func() {
|
||||
_, err := c.NodeStageVolume(
|
||||
context.Background(),
|
||||
&csi.NodeStageVolumeRequest{
|
||||
VolumeId: "id",
|
||||
VolumeCapability: &csi.VolumeCapability{
|
||||
AccessType: &csi.VolumeCapability_Mount{
|
||||
Mount: &csi.VolumeCapability_MountVolume{},
|
||||
},
|
||||
AccessMode: &csi.VolumeCapability_AccessMode{
|
||||
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
|
||||
},
|
||||
},
|
||||
PublishInfo: map[string]string{
|
||||
"device": device,
|
||||
},
|
||||
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
|
||||
It("should fail when no volume capability is provided", func() {
|
||||
_, err := c.NodeStageVolume(
|
||||
context.Background(),
|
||||
&csi.NodeStageVolumeRequest{
|
||||
VolumeId: "id",
|
||||
StagingTargetPath: sc.Config.StagingPath,
|
||||
PublishInfo: map[string]string{
|
||||
"device": device,
|
||||
},
|
||||
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("NodeUnstageVolume", func() {
|
||||
BeforeEach(func() {
|
||||
if !nodeStageSupported {
|
||||
Skip("NodeUnstageVolume not supported")
|
||||
}
|
||||
})
|
||||
|
||||
It("should fail when no volume id is provided", func() {
|
||||
|
||||
_, err := c.NodeUnstageVolume(
|
||||
context.Background(),
|
||||
&csi.NodeUnstageVolumeRequest{
|
||||
StagingTargetPath: sc.Config.StagingPath,
|
||||
})
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
|
||||
It("should fail when no staging target path is provided", func() {
|
||||
|
||||
_, err := c.NodeUnstageVolume(
|
||||
context.Background(),
|
||||
&csi.NodeUnstageVolumeRequest{
|
||||
VolumeId: "id",
|
||||
})
|
||||
Expect(err).To(HaveOccurred())
|
||||
|
||||
serverError, ok := status.FromError(err)
|
||||
Expect(ok).To(BeTrue())
|
||||
Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
|
||||
})
|
||||
})
|
||||
|
||||
It("should work", func() {
|
||||
name := uniqueString("sanity-node-full")
|
||||
|
||||
// Create Volume First
|
||||
By("creating a single node writer volume")
|
||||
vol, err := s.CreateVolume(
|
||||
context.Background(),
|
||||
&csi.CreateVolumeRequest{
|
||||
Name: name,
|
||||
VolumeCapabilities: []*csi.VolumeCapability{
|
||||
{
|
||||
AccessType: &csi.VolumeCapability_Mount{
|
||||
Mount: &csi.VolumeCapability_MountVolume{},
|
||||
},
|
||||
AccessMode: &csi.VolumeCapability_AccessMode{
|
||||
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
|
||||
},
|
||||
},
|
||||
},
|
||||
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(vol).NotTo(BeNil())
|
||||
Expect(vol.GetVolume()).NotTo(BeNil())
|
||||
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty())
|
||||
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()})
|
||||
|
||||
By("getting a node id")
|
||||
nid, err := c.NodeGetId(
|
||||
context.Background(),
|
||||
&csi.NodeGetIdRequest{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(nid).NotTo(BeNil())
|
||||
Expect(nid.GetNodeId()).NotTo(BeEmpty())
|
||||
|
||||
var conpubvol *csi.ControllerPublishVolumeResponse
|
||||
if controllerPublishSupported {
|
||||
By("controller publishing volume")
|
||||
|
||||
conpubvol, err = s.ControllerPublishVolume(
|
||||
context.Background(),
|
||||
&csi.ControllerPublishVolumeRequest{
|
||||
VolumeId: vol.GetVolume().GetId(),
|
||||
NodeId: nid.GetNodeId(),
|
||||
VolumeCapability: &csi.VolumeCapability{
|
||||
AccessType: &csi.VolumeCapability_Mount{
|
||||
Mount: &csi.VolumeCapability_MountVolume{},
|
||||
},
|
||||
AccessMode: &csi.VolumeCapability_AccessMode{
|
||||
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
|
||||
},
|
||||
},
|
||||
VolumeAttributes: vol.GetVolume().GetAttributes(),
|
||||
Readonly: false,
|
||||
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()})
|
||||
Expect(conpubvol).NotTo(BeNil())
|
||||
}
|
||||
// NodeStageVolume
|
||||
if nodeStageSupported {
|
||||
By("node staging volume")
|
||||
nodestagevol, err := c.NodeStageVolume(
|
||||
context.Background(),
|
||||
&csi.NodeStageVolumeRequest{
|
||||
VolumeId: vol.GetVolume().GetId(),
|
||||
VolumeCapability: &csi.VolumeCapability{
|
||||
AccessType: &csi.VolumeCapability_Mount{
|
||||
Mount: &csi.VolumeCapability_MountVolume{},
|
||||
},
|
||||
AccessMode: &csi.VolumeCapability_AccessMode{
|
||||
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
|
||||
},
|
||||
},
|
||||
StagingTargetPath: sc.Config.StagingPath,
|
||||
VolumeAttributes: vol.GetVolume().GetAttributes(),
|
||||
PublishInfo: conpubvol.GetPublishInfo(),
|
||||
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(nodestagevol).NotTo(BeNil())
|
||||
}
|
||||
// NodePublishVolume
|
||||
By("publishing the volume on a node")
|
||||
var stagingPath string
|
||||
if nodeStageSupported {
|
||||
stagingPath = sc.Config.StagingPath
|
||||
}
|
||||
nodepubvol, err := c.NodePublishVolume(
|
||||
context.Background(),
|
||||
&csi.NodePublishVolumeRequest{
|
||||
VolumeId: vol.GetVolume().GetId(),
|
||||
TargetPath: sc.Config.TargetPath,
|
||||
StagingTargetPath: stagingPath,
|
||||
VolumeCapability: &csi.VolumeCapability{
|
||||
AccessType: &csi.VolumeCapability_Mount{
|
||||
Mount: &csi.VolumeCapability_MountVolume{},
|
||||
},
|
||||
AccessMode: &csi.VolumeCapability_AccessMode{
|
||||
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
|
||||
},
|
||||
},
|
||||
VolumeAttributes: vol.GetVolume().GetAttributes(),
|
||||
PublishInfo: conpubvol.GetPublishInfo(),
|
||||
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(nodepubvol).NotTo(BeNil())
|
||||
|
||||
// NodeUnpublishVolume
|
||||
By("cleaning up calling nodeunpublish")
|
||||
nodeunpubvol, err := c.NodeUnpublishVolume(
|
||||
context.Background(),
|
||||
&csi.NodeUnpublishVolumeRequest{
|
||||
VolumeId: vol.GetVolume().GetId(),
|
||||
TargetPath: sc.Config.TargetPath,
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(nodeunpubvol).NotTo(BeNil())
|
||||
|
||||
if nodeStageSupported {
|
||||
By("cleaning up calling nodeunstage")
|
||||
nodeunstagevol, err := c.NodeUnstageVolume(
|
||||
context.Background(),
|
||||
&csi.NodeUnstageVolumeRequest{
|
||||
VolumeId: vol.GetVolume().GetId(),
|
||||
StagingTargetPath: sc.Config.StagingPath,
|
||||
},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(nodeunstagevol).NotTo(BeNil())
|
||||
}
|
||||
|
||||
if controllerPublishSupported {
|
||||
By("cleaning up calling controllerunpublishing")
|
||||
|
||||
controllerunpubvol, err := s.ControllerUnpublishVolume(
|
||||
context.Background(),
|
||||
&csi.ControllerUnpublishVolumeRequest{
|
||||
VolumeId: vol.GetVolume().GetId(),
|
||||
NodeId: nid.GetNodeId(),
|
||||
ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(controllerunpubvol).NotTo(BeNil())
|
||||
}
|
||||
|
||||
By("cleaning up deleting the volume")
|
||||
|
||||
_, err = s.DeleteVolume(
|
||||
context.Background(),
|
||||
&csi.DeleteVolumeRequest{
|
||||
VolumeId: vol.GetVolume().GetId(),
|
||||
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret,
|
||||
},
|
||||
)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
163
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go
generated
vendored
Normal file
163
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sanity
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/kubernetes-csi/csi-test/utils"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
// CSISecrets consists of secrets used in CSI credentials.
|
||||
type CSISecrets struct {
|
||||
CreateVolumeSecret map[string]string `yaml:"CreateVolumeSecret"`
|
||||
DeleteVolumeSecret map[string]string `yaml:"DeleteVolumeSecret"`
|
||||
ControllerPublishVolumeSecret map[string]string `yaml:"ControllerPublishVolumeSecret"`
|
||||
ControllerUnpublishVolumeSecret map[string]string `yaml:"ControllerUnpublishVolumeSecret"`
|
||||
NodeStageVolumeSecret map[string]string `yaml:"NodeStageVolumeSecret"`
|
||||
NodePublishVolumeSecret map[string]string `yaml:"NodePublishVolumeSecret"`
|
||||
CreateSnapshotSecret map[string]string `yaml:"CreateSnapshotSecret"`
|
||||
DeleteSnapshotSecret map[string]string `yaml:"DeleteSnapshotSecret"`
|
||||
}
|
||||
|
||||
// Config provides the configuration for the sanity tests. It
|
||||
// needs to be initialized by the user of the sanity package.
|
||||
type Config struct {
|
||||
TargetPath string
|
||||
StagingPath string
|
||||
Address string
|
||||
SecretsFile string
|
||||
TestVolumeSize int64
|
||||
}
|
||||
|
||||
// SanityContext holds the variables that each test can depend on. It
|
||||
// gets initialized before each test block runs.
|
||||
type SanityContext struct {
|
||||
Config *Config
|
||||
Conn *grpc.ClientConn
|
||||
Secrets *CSISecrets
|
||||
}
|
||||
|
||||
// Test will test the CSI driver at the specified address by
|
||||
// setting up a Ginkgo suite and running it.
|
||||
func Test(t *testing.T, reqConfig *Config) {
|
||||
sc := &SanityContext{
|
||||
Config: reqConfig,
|
||||
}
|
||||
|
||||
registerTestsInGinkgo(sc)
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "CSI Driver Test Suite")
|
||||
}
|
||||
|
||||
func GinkgoTest(reqConfig *Config) {
|
||||
sc := &SanityContext{
|
||||
Config: reqConfig,
|
||||
}
|
||||
|
||||
registerTestsInGinkgo(sc)
|
||||
}
|
||||
|
||||
func (sc *SanityContext) setup() {
|
||||
var err error
|
||||
|
||||
if len(sc.Config.SecretsFile) > 0 {
|
||||
sc.Secrets, err = loadSecrets(sc.Config.SecretsFile)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
} else {
|
||||
sc.Secrets = &CSISecrets{}
|
||||
}
|
||||
|
||||
By("connecting to CSI driver")
|
||||
sc.Conn, err = utils.Connect(sc.Config.Address)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("creating mount and staging directories")
|
||||
err = createMountTargetLocation(sc.Config.TargetPath)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
if len(sc.Config.StagingPath) > 0 {
|
||||
err = createMountTargetLocation(sc.Config.StagingPath)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *SanityContext) teardown() {
|
||||
if sc.Conn != nil {
|
||||
sc.Conn.Close()
|
||||
sc.Conn = nil
|
||||
}
|
||||
}
|
||||
|
||||
func createMountTargetLocation(targetPath string) error {
|
||||
fileInfo, err := os.Stat(targetPath)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
return os.MkdirAll(targetPath, 0755)
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
if !fileInfo.IsDir() {
|
||||
return fmt.Errorf("Target location %s is not a directory", targetPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadSecrets(path string) (*CSISecrets, error) {
|
||||
var creds CSISecrets
|
||||
|
||||
yamlFile, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return &creds, fmt.Errorf("failed to read file %q: #%v", path, err)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(yamlFile, &creds)
|
||||
if err != nil {
|
||||
return &creds, fmt.Errorf("error unmarshaling yaml: #%v", err)
|
||||
}
|
||||
|
||||
return &creds, nil
|
||||
}
|
||||
|
||||
var uniqueSuffix = "-" + pseudoUUID()
|
||||
|
||||
// pseudoUUID returns a unique string generated from random
|
||||
// bytes, empty string in case of error.
|
||||
func pseudoUUID() string {
|
||||
b := make([]byte, 8)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
// Shouldn't happen?!
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%08X-%08X", b[0:4], b[4:8])
|
||||
}
|
||||
|
||||
// uniqueString returns a unique string by appending a random
|
||||
// number. In case of an error, just the prefix is returned, so it
|
||||
// alone should already be fairly unique.
|
||||
func uniqueString(prefix string) string {
|
||||
return prefix + uniqueSuffix
|
||||
}
|
56
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/tests.go
generated
vendored
Normal file
56
vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/tests.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright 2018 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package sanity
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
text string
|
||||
body func(*SanityContext)
|
||||
}
|
||||
|
||||
var tests []test
|
||||
|
||||
// DescribeSanity must be used instead of the usual Ginkgo Describe to
|
||||
// register a test block. The difference is that the body function
|
||||
// will be called multiple times with the right context (when
|
||||
// setting up a Ginkgo suite or a testing.T test, with the right
|
||||
// configuration).
|
||||
func DescribeSanity(text string, body func(*SanityContext)) bool {
|
||||
tests = append(tests, test{text, body})
|
||||
return true
|
||||
}
|
||||
|
||||
// registerTestsInGinkgo invokes the actual Gingko Describe
|
||||
// for the tests registered earlier with DescribeSanity.
|
||||
func registerTestsInGinkgo(sc *SanityContext) {
|
||||
for _, test := range tests {
|
||||
Describe(test.text, func() {
|
||||
BeforeEach(func() {
|
||||
sc.setup()
|
||||
})
|
||||
|
||||
test.body(sc)
|
||||
|
||||
AfterEach(func() {
|
||||
sc.teardown()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
188
vendor/github.com/kubernetes-csi/csi-test/test/co_test.go
generated
vendored
Normal file
188
vendor/github.com/kubernetes-csi/csi-test/test/co_test.go
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/golang/protobuf/proto"
|
||||
mock_driver "github.com/kubernetes-csi/csi-test/driver"
|
||||
mock_utils "github.com/kubernetes-csi/csi-test/utils"
|
||||
)
|
||||
|
||||
func TestPluginInfoResponse(t *testing.T) {
|
||||
|
||||
// Setup mock
|
||||
m := gomock.NewController(t)
|
||||
defer m.Finish()
|
||||
driver := mock_driver.NewMockIdentityServer(m)
|
||||
|
||||
// Setup input
|
||||
in := &csi.GetPluginInfoRequest{}
|
||||
|
||||
// Setup mock outout
|
||||
out := &csi.GetPluginInfoResponse{
|
||||
Name: "mock",
|
||||
VendorVersion: "0.1.1",
|
||||
Manifest: map[string]string{
|
||||
"hello": "world",
|
||||
},
|
||||
}
|
||||
|
||||
// Setup expectation
|
||||
driver.EXPECT().GetPluginInfo(nil, in).Return(out, nil).Times(1)
|
||||
|
||||
// Actual call
|
||||
r, err := driver.GetPluginInfo(nil, in)
|
||||
name := r.GetName()
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
if name != "mock" {
|
||||
t.Errorf("Unknown name: %s\n", name)
|
||||
}
|
||||
}
|
||||
|
||||
type pbMatcher struct {
|
||||
x proto.Message
|
||||
}
|
||||
|
||||
func (p pbMatcher) Matches(x interface{}) bool {
|
||||
y := x.(proto.Message)
|
||||
return proto.Equal(p.x, y)
|
||||
}
|
||||
|
||||
func (p pbMatcher) String() string {
|
||||
return fmt.Sprintf("pb equal to %v", p.x)
|
||||
}
|
||||
|
||||
func pbMatch(x interface{}) gomock.Matcher {
|
||||
v := x.(proto.Message)
|
||||
return &pbMatcher{v}
|
||||
}
|
||||
|
||||
func TestGRPCGetPluginInfoReponse(t *testing.T) {
|
||||
|
||||
// Setup mock
|
||||
m := gomock.NewController(&mock_utils.SafeGoroutineTester{})
|
||||
defer m.Finish()
|
||||
driver := mock_driver.NewMockIdentityServer(m)
|
||||
|
||||
// Setup input
|
||||
in := &csi.GetPluginInfoRequest{}
|
||||
|
||||
// Setup mock outout
|
||||
out := &csi.GetPluginInfoResponse{
|
||||
Name: "mock",
|
||||
VendorVersion: "0.1.1",
|
||||
Manifest: map[string]string{
|
||||
"hello": "world",
|
||||
},
|
||||
}
|
||||
|
||||
// Setup expectation
|
||||
// !IMPORTANT!: Must set context expected value to gomock.Any() to match any value
|
||||
driver.EXPECT().GetPluginInfo(gomock.Any(), pbMatch(in)).Return(out, nil).Times(1)
|
||||
|
||||
// Create a new RPC
|
||||
server := mock_driver.NewMockCSIDriver(&mock_driver.MockCSIDriverServers{
|
||||
Identity: driver,
|
||||
})
|
||||
conn, err := server.Nexus()
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
// Make call
|
||||
c := csi.NewIdentityClient(conn)
|
||||
r, err := c.GetPluginInfo(context.Background(), in)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
|
||||
name := r.GetName()
|
||||
if name != "mock" {
|
||||
t.Errorf("Unknown name: %s\n", name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCAttach(t *testing.T) {
|
||||
|
||||
// Setup mock
|
||||
m := gomock.NewController(&mock_utils.SafeGoroutineTester{})
|
||||
defer m.Finish()
|
||||
driver := mock_driver.NewMockControllerServer(m)
|
||||
|
||||
// Setup input
|
||||
defaultVolumeID := "myname"
|
||||
defaultNodeID := "MyNodeID"
|
||||
defaultCaps := &csi.VolumeCapability{
|
||||
AccessType: &csi.VolumeCapability_Mount{
|
||||
Mount: &csi.VolumeCapability_MountVolume{},
|
||||
},
|
||||
AccessMode: &csi.VolumeCapability_AccessMode{
|
||||
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
|
||||
},
|
||||
}
|
||||
publishVolumeInfo := map[string]string{
|
||||
"first": "foo",
|
||||
"second": "bar",
|
||||
"third": "baz",
|
||||
}
|
||||
defaultRequest := &csi.ControllerPublishVolumeRequest{
|
||||
VolumeId: defaultVolumeID,
|
||||
NodeId: defaultNodeID,
|
||||
VolumeCapability: defaultCaps,
|
||||
Readonly: false,
|
||||
}
|
||||
|
||||
// Setup mock outout
|
||||
out := &csi.ControllerPublishVolumeResponse{
|
||||
PublishInfo: publishVolumeInfo,
|
||||
}
|
||||
|
||||
// Setup expectation
|
||||
// !IMPORTANT!: Must set context expected value to gomock.Any() to match any value
|
||||
driver.EXPECT().ControllerPublishVolume(gomock.Any(), pbMatch(defaultRequest)).Return(out, nil).Times(1)
|
||||
|
||||
// Create a new RPC
|
||||
server := mock_driver.NewMockCSIDriver(&mock_driver.MockCSIDriverServers{
|
||||
Controller: driver,
|
||||
})
|
||||
conn, err := server.Nexus()
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
// Make call
|
||||
c := csi.NewControllerClient(conn)
|
||||
r, err := c.ControllerPublishVolume(context.Background(), defaultRequest)
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
|
||||
info := r.GetPublishInfo()
|
||||
if !reflect.DeepEqual(info, publishVolumeInfo) {
|
||||
t.Errorf("Invalid publish info: %v", info)
|
||||
}
|
||||
}
|
127
vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go
generated
vendored
Normal file
127
vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi/v0"
|
||||
"github.com/kubernetes-csi/csi-test/utils"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
// Example simple driver
|
||||
// This example assumes that your driver will create the server and listen on
|
||||
// some unix domain socket or port for tests.
|
||||
type simpleDriver struct {
|
||||
listener net.Listener
|
||||
server *grpc.Server
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
func (s *simpleDriver) GetPluginCapabilities(context.Context, *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) {
|
||||
// TODO: Return some simple Plugin Capabilities
|
||||
return &csi.GetPluginCapabilitiesResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *simpleDriver) Probe(context.Context, *csi.ProbeRequest) (*csi.ProbeResponse, error) {
|
||||
return &csi.ProbeResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *simpleDriver) GetPluginInfo(
|
||||
context.Context, *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) {
|
||||
return &csi.GetPluginInfoResponse{
|
||||
Name: "simpleDriver",
|
||||
VendorVersion: "0.1.1",
|
||||
Manifest: map[string]string{
|
||||
"hello": "world",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *simpleDriver) goServe() {
|
||||
s.wg.Add(1)
|
||||
go func() {
|
||||
defer s.wg.Done()
|
||||
s.server.Serve(s.listener)
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *simpleDriver) Address() string {
|
||||
return s.listener.Addr().String()
|
||||
}
|
||||
|
||||
func (s *simpleDriver) Start() error {
|
||||
// Listen on a port assigned by the net package
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.listener = l
|
||||
|
||||
// Create a new grpc server
|
||||
s.server = grpc.NewServer()
|
||||
|
||||
csi.RegisterIdentityServer(s.server, s)
|
||||
reflection.Register(s.server)
|
||||
|
||||
// Start listening for requests
|
||||
s.goServe()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *simpleDriver) Stop() {
|
||||
s.server.Stop()
|
||||
s.wg.Wait()
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
func TestSimpleDriver(t *testing.T) {
|
||||
|
||||
// Setup simple driver
|
||||
s := &simpleDriver{}
|
||||
err := s.Start()
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
defer s.Stop()
|
||||
|
||||
// Setup a connection to the driver
|
||||
conn, err := utils.Connect(s.Address())
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// Make a call
|
||||
c := csi.NewIdentityClient(conn)
|
||||
r, err := c.GetPluginInfo(context.Background(), &csi.GetPluginInfoRequest{})
|
||||
if err != nil {
|
||||
t.Errorf("Error: %s", err.Error())
|
||||
}
|
||||
|
||||
// Verify
|
||||
name := r.GetName()
|
||||
if name != "simpleDriver" {
|
||||
t.Errorf("Unknown name: %s\n", name)
|
||||
}
|
||||
}
|
59
vendor/github.com/kubernetes-csi/csi-test/utils/grpcutil.go
generated
vendored
Normal file
59
vendor/github.com/kubernetes-csi/csi-test/utils/grpcutil.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
)
|
||||
|
||||
// Connect address by grpc
|
||||
func Connect(address string) (*grpc.ClientConn, error) {
|
||||
dialOptions := []grpc.DialOption{
|
||||
grpc.WithInsecure(),
|
||||
}
|
||||
u, err := url.Parse(address)
|
||||
if err == nil && (!u.IsAbs() || u.Scheme == "unix") {
|
||||
dialOptions = append(dialOptions,
|
||||
grpc.WithDialer(
|
||||
func(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
return net.DialTimeout("unix", u.Path, timeout)
|
||||
}))
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(address, dialOptions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
for {
|
||||
if !conn.WaitForStateChange(ctx, conn.GetState()) {
|
||||
return conn, fmt.Errorf("Connection timed out")
|
||||
}
|
||||
if conn.GetState() == connectivity.Ready {
|
||||
return conn, nil
|
||||
}
|
||||
}
|
||||
}
|
40
vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go
generated
vendored
Normal file
40
vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2017 Luis Pabón luis@portworx.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import "fmt"
|
||||
|
||||
// SafeGoroutineTester is an implementation of the mock ... interface
|
||||
// which can be used to use the mock functions in another go routine.
|
||||
//
|
||||
// The major issue is that the golang mock framework uses t.Fatalf()
|
||||
// which causes a deadlock when called in another goroutine. To avoid
|
||||
// this issue, this simple implementation prints the error then panics,
|
||||
// which avoids the deadlock.
|
||||
type SafeGoroutineTester struct{}
|
||||
|
||||
// Errorf prints the error to the screen then panics
|
||||
func (s *SafeGoroutineTester) Errorf(format string, args ...interface{}) {
|
||||
fmt.Printf(format, args)
|
||||
panic("MOCK TEST ERROR")
|
||||
}
|
||||
|
||||
// Fatalf prints the error to the screen then panics
|
||||
func (s *SafeGoroutineTester) Fatalf(format string, args ...interface{}) {
|
||||
fmt.Printf(format+"\n", args...)
|
||||
panic("MOCK TEST FATAL FAILURE")
|
||||
}
|
Reference in New Issue
Block a user