Update vendor csi spec and csi-test to 1.0.0-rc2

This commit is contained in:
Michelle Au
2018-11-14 13:27:37 -08:00
parent 92f87c14e7
commit 9be7a7dd24
42 changed files with 2674 additions and 1964 deletions

206
Gopkg.lock generated
View File

@@ -2,125 +2,96 @@
[[projects]] [[projects]]
digest = "1:8e47871087b94913898333f37af26732faaab30cdb41571136cf7aec9921dae7"
name = "github.com/PuerkitoBio/purell" name = "github.com/PuerkitoBio/purell"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4"
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:331a419049c2be691e5ba1d24342fc77c7e767a80c666a18fd8a9f7b82419c1c"
name = "github.com/PuerkitoBio/urlesc" name = "github.com/PuerkitoBio/urlesc"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "de5bf2ad457846296e2031421a34e2568e304e35" revision = "de5bf2ad457846296e2031421a34e2568e304e35"
[[projects]] [[projects]]
digest = "1:cf4f5171128e62b46299b0a7cd79543f50e62f483d2ca9364e4957c7bbee7a38"
name = "github.com/container-storage-interface/spec" name = "github.com/container-storage-interface/spec"
packages = ["lib/go/csi/v0"] packages = ["lib/go/csi"]
pruneopts = "" revision = "8efcc85c45550571fba8134182013ed7dc34038a"
revision = "2178fdeea87f1150a17a63252eee28d4d8141f72" version = "v1.0.0-rc2"
version = "v0.3.0"
[[projects]] [[projects]]
digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b"
name = "github.com/davecgh/go-spew" name = "github.com/davecgh/go-spew"
packages = ["spew"] packages = ["spew"]
pruneopts = ""
revision = "346938d642f2ec3594ed81d874461961cd0faa76" revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
digest = "1:8a34d7a37b8f07239487752e14a5faafcbbc718fc385ad429a2c4ac6f27a207f"
name = "github.com/emicklei/go-restful" name = "github.com/emicklei/go-restful"
packages = [ packages = [
".", ".",
"log", "log"
] ]
pruneopts = ""
revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0" revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0"
version = "v2.8.0" version = "v2.8.0"
[[projects]] [[projects]]
digest = "1:b13707423743d41665fd23f0c36b2f37bb49c30e94adb813319c44188a51ba22"
name = "github.com/ghodss/yaml" name = "github.com/ghodss/yaml"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:e116a4866bffeec941056a1fcfd37e520fad1ee60e4e3579719f19a43c392e10"
name = "github.com/go-openapi/jsonpointer" name = "github.com/go-openapi/jsonpointer"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2" revision = "3a0015ad55fa9873f41605d3e8f28cd279c32ab2"
version = "0.15.0" version = "0.15.0"
[[projects]] [[projects]]
digest = "1:3830527ef0f4f9b268d9286661c0f52f9115f8aefd9f45ee7352516f93489ac9"
name = "github.com/go-openapi/jsonreference" name = "github.com/go-openapi/jsonreference"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "3fb327e6747da3043567ee86abd02bb6376b6be2" revision = "3fb327e6747da3043567ee86abd02bb6376b6be2"
version = "0.15.0" version = "0.15.0"
[[projects]] [[projects]]
digest = "1:6caee195f5da296689270037c5a25c0bc3cc6e54ae5a356e395aa8946356dbc9"
name = "github.com/go-openapi/spec" name = "github.com/go-openapi/spec"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "bce47c9386f9ecd6b86f450478a80103c3fe1402" revision = "bce47c9386f9ecd6b86f450478a80103c3fe1402"
version = "0.15.0" version = "0.15.0"
[[projects]] [[projects]]
digest = "1:22da48dbccb0539f511efbbbdeba68081866892234e57a9d7c7f9848168ae30c"
name = "github.com/go-openapi/swag" name = "github.com/go-openapi/swag"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "2b0bd4f193d011c203529df626a65d63cb8a79e8" revision = "2b0bd4f193d011c203529df626a65d63cb8a79e8"
version = "0.15.0" version = "0.15.0"
[[projects]] [[projects]]
digest = "1:0a3f6a0c68ab8f3d455f8892295503b179e571b7fefe47cc6c556405d1f83411"
name = "github.com/gogo/protobuf" name = "github.com/gogo/protobuf"
packages = [ packages = [
"proto", "proto",
"sortkeys", "sortkeys"
] ]
pruneopts = ""
revision = "1adfc126b41513cc696b209667c8656ea7aac67c" revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:107b233e45174dbab5b1324201d092ea9448e58243ab9f039e4c0f332e121e3a"
name = "github.com/golang/glog" name = "github.com/golang/glog"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:b7677b91b9250563c6851dd5f2d8083972188bfe4f8fb7b61489a2f832f19b11"
name = "github.com/golang/groupcache" name = "github.com/golang/groupcache"
packages = ["lru"] packages = ["lru"]
pruneopts = ""
revision = "66deaeb636dff1ac7d938ce666d090556056a4b0" revision = "66deaeb636dff1ac7d938ce666d090556056a4b0"
[[projects]] [[projects]]
digest = "1:73a7106c799f98af4f3da7552906efc6a2570329f4cd2d2f5fb8f9d6c053ff2f"
name = "github.com/golang/mock" name = "github.com/golang/mock"
packages = ["gomock"] packages = ["gomock"]
pruneopts = ""
revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" revision = "c34cdb4725f4c3844d095133c6e40e448b86589b"
version = "v1.1.1" version = "v1.1.1"
[[projects]] [[projects]]
digest = "1:f958a1c137db276e52f0b50efee41a1a389dcdded59a69711f3e872757dab34b"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
packages = [ packages = [
"proto", "proto",
@@ -129,152 +100,120 @@
"ptypes/any", "ptypes/any",
"ptypes/duration", "ptypes/duration",
"ptypes/timestamp", "ptypes/timestamp",
"ptypes/wrappers", "ptypes/wrappers"
] ]
pruneopts = ""
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265"
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:be28c0531a755f2178acf1e327e6f5a8a3968feb5f2567cdc968064253141751"
name = "github.com/google/btree" name = "github.com/google/btree"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4" revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:754f77e9c839b24778a4b64422236d38515301d2baeb63113aa3edc42e6af692"
name = "github.com/google/gofuzz" name = "github.com/google/gofuzz"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1"
[[projects]] [[projects]]
digest = "1:2a131706ff80636629ab6373f2944569b8252ecc018cda8040931b05d32e3c16"
name = "github.com/googleapis/gnostic" name = "github.com/googleapis/gnostic"
packages = [ packages = [
"OpenAPIv2", "OpenAPIv2",
"compiler", "compiler",
"extensions", "extensions"
] ]
pruneopts = ""
revision = "ee43cbb60db7bd22502942cccbc39059117352ab" revision = "ee43cbb60db7bd22502942cccbc39059117352ab"
version = "v0.1.0" version = "v0.1.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:009a1928b8c096338b68b5822d838a72b4d8520715c1463614476359f3282ec8"
name = "github.com/gregjones/httpcache" name = "github.com/gregjones/httpcache"
packages = [ packages = [
".", ".",
"diskcache", "diskcache"
] ]
pruneopts = ""
revision = "9cad4c3443a7200dd6400aef47183728de563a38" revision = "9cad4c3443a7200dd6400aef47183728de563a38"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94"
name = "github.com/hashicorp/golang-lru" name = "github.com/hashicorp/golang-lru"
packages = [ packages = [
".", ".",
"simplelru", "simplelru"
] ]
pruneopts = ""
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
[[projects]] [[projects]]
digest = "1:23bc0b496ba341c6e3ba24d6358ff4a40a704d9eb5f9a3bd8e8fbd57ad869013"
name = "github.com/imdario/mergo" name = "github.com/imdario/mergo"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "163f41321a19dd09362d4c63cc2489db2015f1f4" revision = "163f41321a19dd09362d4c63cc2489db2015f1f4"
version = "0.3.2" version = "0.3.2"
[[projects]] [[projects]]
digest = "1:53ac4e911e12dde0ab68655e2006449d207a5a681f084974da2b06e5dbeaca72"
name = "github.com/json-iterator/go" name = "github.com/json-iterator/go"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "ab8a2e0c74be9d3be70b3184d9acc634935ded82" revision = "ab8a2e0c74be9d3be70b3184d9acc634935ded82"
version = "1.1.4" version = "1.1.4"
[[projects]] [[projects]]
branch = "master"
digest = "1:6a0b17f72d5b3f5d5edc905a3ece920ec0eb368fe0ad59499b6db2624421b460"
name = "github.com/kubernetes-csi/csi-test" name = "github.com/kubernetes-csi/csi-test"
packages = [ packages = [
"driver", "driver",
"utils", "utils"
] ]
pruneopts = "" revision = "42947e04c4a0d2087448841a1dc3ccb20fb903b1"
revision = "e11d328ecca7fe91939284a8e878ebe77df8756d" version = "v1.0.0-rc2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:d9e483f4b9e306facf126bd90b02d512bd22ea4471e1568867e32221a8abbb16"
name = "github.com/mailru/easyjson" name = "github.com/mailru/easyjson"
packages = [ packages = [
"buffer", "buffer",
"jlexer", "jlexer",
"jwriter", "jwriter"
] ]
pruneopts = ""
revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485" revision = "3fdea8d05856a0c8df22ed4bc71b3219245e4485"
[[projects]] [[projects]]
digest = "1:76a22f13ffa6d5d0b91beecdcec5c7651a42d3c5fcc12757e578808826fe4b0a"
name = "github.com/modern-go/concurrent" name = "github.com/modern-go/concurrent"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "938152ca6a933f501bb238954eebd3cbcbf489ff" revision = "938152ca6a933f501bb238954eebd3cbcbf489ff"
version = "1.0.2" version = "1.0.2"
[[projects]] [[projects]]
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
name = "github.com/modern-go/reflect2" name = "github.com/modern-go/reflect2"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
version = "1.0.1" version = "1.0.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:c24598ffeadd2762552269271b3b1510df2d83ee6696c1e543a0ff653af494bc"
name = "github.com/petar/GoLLRB" name = "github.com/petar/GoLLRB"
packages = ["llrb"] packages = ["llrb"]
pruneopts = ""
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
[[projects]] [[projects]]
digest = "1:b46305723171710475f2dd37547edd57b67b9de9f2a6267cafdd98331fd6897f"
name = "github.com/peterbourgon/diskv" name = "github.com/peterbourgon/diskv"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
version = "v2.0.1" version = "v2.0.1"
[[projects]] [[projects]]
digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000"
name = "github.com/spf13/pflag" name = "github.com/spf13/pflag"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66" revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:79b763a59bc081a752605854f75ac04d4b8fba22bab9bbb11689efd2de255864"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = ["ssh/terminal"] packages = ["ssh/terminal"]
pruneopts = ""
revision = "91a49db82a88618983a78a06c1cbd4e00ab749ab" revision = "91a49db82a88618983a78a06c1cbd4e00ab749ab"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:4a65e28058fde372f1febbf1bca01ee4aed7472569fd1bc81db9e91bf105f7c8"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"context", "context",
@@ -284,35 +223,29 @@
"idna", "idna",
"internal/timeseries", "internal/timeseries",
"lex/httplex", "lex/httplex",
"trace", "trace"
] ]
pruneopts = ""
revision = "22ae77b79946ea320088417e4d50825671d82d57" revision = "22ae77b79946ea320088417e4d50825671d82d57"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:b697592485cb412be4188c08ca0beed9aab87f36b86418e21acc4a3998f63734"
name = "golang.org/x/oauth2" name = "golang.org/x/oauth2"
packages = [ packages = [
".", ".",
"internal", "internal"
] ]
pruneopts = ""
revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9" revision = "d2e6202438beef2727060aa7cabdd924d92ebfd9"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:0a0c73aced706c77f4f128971976b0ee94db7bdcc95b6088bda9e72594598634"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = [ packages = [
"unix", "unix",
"windows", "windows"
] ]
pruneopts = ""
revision = "dd2ff4accc098aceecb86b36eaa7829b2a17b1c9" revision = "dd2ff4accc098aceecb86b36eaa7829b2a17b1c9"
[[projects]] [[projects]]
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
name = "golang.org/x/text" name = "golang.org/x/text"
packages = [ packages = [
"collate", "collate",
@@ -329,34 +262,28 @@
"unicode/cldr", "unicode/cldr",
"unicode/norm", "unicode/norm",
"unicode/rangetable", "unicode/rangetable",
"width", "width"
] ]
pruneopts = ""
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0" version = "v0.3.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:55a681cb66f28755765fa5fa5104cbd8dc85c55c02d206f9f89566451e3fe1aa"
name = "golang.org/x/time" name = "golang.org/x/time"
packages = ["rate"] packages = ["rate"]
pruneopts = ""
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650" revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:b3123d1f332e4536a69174a97ae8333cfef1ef502942a9d956dee761314b44c9"
name = "golang.org/x/tools" name = "golang.org/x/tools"
packages = [ packages = [
"go/ast/astutil", "go/ast/astutil",
"imports", "imports",
"internal/fastwalk", "internal/fastwalk"
] ]
pruneopts = ""
revision = "2087f8c10712366cfc2f4fcb1bf99eeef61ab21e" revision = "2087f8c10712366cfc2f4fcb1bf99eeef61ab21e"
[[projects]] [[projects]]
digest = "1:c1771ca6060335f9768dff6558108bc5ef6c58506821ad43377ee23ff059e472"
name = "google.golang.org/appengine" name = "google.golang.org/appengine"
packages = [ packages = [
"internal", "internal",
@@ -365,22 +292,18 @@
"internal/log", "internal/log",
"internal/remote_api", "internal/remote_api",
"internal/urlfetch", "internal/urlfetch",
"urlfetch", "urlfetch"
] ]
pruneopts = ""
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612" revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:02b227168a215a14f7f16af45ca649b7c1efc33919ce27a03996dfb54dcf556c"
name = "google.golang.org/genproto" name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"] packages = ["googleapis/rpc/status"]
pruneopts = ""
revision = "2c5e7ac708aaa719366570dd82bda44541ca2a63" revision = "2c5e7ac708aaa719366570dd82bda44541ca2a63"
[[projects]] [[projects]]
digest = "1:d2dc833c73202298c92b63a7e180e2b007b5a3c3c763e3b9fe1da249b5c7f5b9"
name = "google.golang.org/grpc" name = "google.golang.org/grpc"
packages = [ packages = [
".", ".",
@@ -407,30 +330,24 @@
"stats", "stats",
"status", "status",
"tap", "tap",
"transport", "transport"
] ]
pruneopts = ""
revision = "8e4536a86ab602859c20df5ebfd0bd4228d08655" revision = "8e4536a86ab602859c20df5ebfd0bd4228d08655"
version = "v1.10.0" version = "v1.10.0"
[[projects]] [[projects]]
digest = "1:e5d1fb981765b6f7513f793a3fcaac7158408cca77f75f7311ac82cc88e9c445"
name = "gopkg.in/inf.v0" name = "gopkg.in/inf.v0"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4"
version = "v0.9.0" version = "v0.9.0"
[[projects]] [[projects]]
digest = "1:5fe876313b07628905b2181e537faabe45032cb9c79c01b49b51c25a0a40040d"
name = "gopkg.in/yaml.v2" name = "gopkg.in/yaml.v2"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5" revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5"
version = "v2.1.1" version = "v2.1.1"
[[projects]] [[projects]]
digest = "1:5f076f6f9c3ac4f2b99d79dc7974eabd3f51be35254aa0d8c4cf920fdb9c7ff8"
name = "k8s.io/api" name = "k8s.io/api"
packages = [ packages = [
"admissionregistration/v1alpha1", "admissionregistration/v1alpha1",
@@ -463,28 +380,24 @@
"settings/v1alpha1", "settings/v1alpha1",
"storage/v1", "storage/v1",
"storage/v1alpha1", "storage/v1alpha1",
"storage/v1beta1", "storage/v1beta1"
] ]
pruneopts = ""
revision = "fd83cbc87e7632ccd8bbab63d2b673d4e0c631cc" revision = "fd83cbc87e7632ccd8bbab63d2b673d4e0c631cc"
version = "kubernetes-1.12.0" version = "kubernetes-1.12.0"
[[projects]] [[projects]]
digest = "1:466583feeb1602ea9f19fef76e96b55c08c49ce88743a9d38c7726891ffe0436"
name = "k8s.io/apiextensions-apiserver" name = "k8s.io/apiextensions-apiserver"
packages = [ packages = [
"pkg/apis/apiextensions", "pkg/apis/apiextensions",
"pkg/apis/apiextensions/v1beta1", "pkg/apis/apiextensions/v1beta1",
"pkg/client/clientset/clientset", "pkg/client/clientset/clientset",
"pkg/client/clientset/clientset/scheme", "pkg/client/clientset/clientset/scheme",
"pkg/client/clientset/clientset/typed/apiextensions/v1beta1", "pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
] ]
pruneopts = ""
revision = "1748dfb29e8a4432b78514bc88a1b07937a9805a" revision = "1748dfb29e8a4432b78514bc88a1b07937a9805a"
version = "kubernetes-1.12.0" version = "kubernetes-1.12.0"
[[projects]] [[projects]]
digest = "1:7aa037a4df5432be2820d164f378d7c22335e5cbba124e90e42114757ebd11ac"
name = "k8s.io/apimachinery" name = "k8s.io/apimachinery"
packages = [ packages = [
"pkg/api/errors", "pkg/api/errors",
@@ -528,14 +441,12 @@
"pkg/version", "pkg/version",
"pkg/watch", "pkg/watch",
"third_party/forked/golang/json", "third_party/forked/golang/json",
"third_party/forked/golang/reflect", "third_party/forked/golang/reflect"
] ]
pruneopts = ""
revision = "6dd46049f39503a1fc8d65de4bd566829e95faff" revision = "6dd46049f39503a1fc8d65de4bd566829e95faff"
version = "kubernetes-1.12.0" version = "kubernetes-1.12.0"
[[projects]] [[projects]]
digest = "1:5d4153d12c3aed2c90a94262520d2498d5afa4d692554af55e65a7c5af0bc399"
name = "k8s.io/client-go" name = "k8s.io/client-go"
packages = [ packages = [
"discovery", "discovery",
@@ -631,14 +542,12 @@
"util/homedir", "util/homedir",
"util/integer", "util/integer",
"util/retry", "util/retry",
"util/workqueue", "util/workqueue"
] ]
pruneopts = ""
revision = "1638f8970cefaa404ff3a62950f88b08292b2696" revision = "1638f8970cefaa404ff3a62950f88b08292b2696"
version = "kubernetes-1.12.0" version = "kubernetes-1.12.0"
[[projects]] [[projects]]
digest = "1:e6fffdf0dfeb0d189a7c6d735e76e7564685d3b6513f8b19d3651191cb6b084b"
name = "k8s.io/code-generator" name = "k8s.io/code-generator"
packages = [ packages = [
"cmd/client-gen", "cmd/client-gen",
@@ -661,15 +570,13 @@
"cmd/lister-gen/generators", "cmd/lister-gen/generators",
"cmd/openapi-gen", "cmd/openapi-gen",
"cmd/openapi-gen/args", "cmd/openapi-gen/args",
"pkg/util", "pkg/util"
] ]
pruneopts = ""
revision = "3dcf91f64f638563e5106f21f50c31fa361c918d" revision = "3dcf91f64f638563e5106f21f50c31fa361c918d"
version = "kubernetes-1.12.0" version = "kubernetes-1.12.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:f3ce5a03c50cf794f17d331fa9d8741db6fd8aeb5ec07d2a68eb039619f22967"
name = "k8s.io/gengo" name = "k8s.io/gengo"
packages = [ packages = [
"args", "args",
@@ -679,87 +586,32 @@
"generator", "generator",
"namer", "namer",
"parser", "parser",
"types", "types"
] ]
pruneopts = ""
revision = "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2" revision = "fdcf9f9480fdd5bf2b3c3df9bf4ecd22b25b87e2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:9a648ff9eb89673d2870c22fc011ec5db0fcff6c4e5174a650298e51be71bbf1"
name = "k8s.io/kube-openapi" name = "k8s.io/kube-openapi"
packages = [ packages = [
"pkg/common", "pkg/common",
"pkg/generators", "pkg/generators",
"pkg/util/proto", "pkg/util/proto"
] ]
pruneopts = ""
revision = "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf" revision = "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
[[projects]] [[projects]]
digest = "1:f76bd44abec76c842b33c3ba178ace57cc5573307abd77d213d7da31fae912f5"
name = "k8s.io/kubernetes" name = "k8s.io/kubernetes"
packages = [ packages = [
"pkg/util/goroutinemap", "pkg/util/goroutinemap",
"pkg/util/goroutinemap/exponentialbackoff", "pkg/util/goroutinemap/exponentialbackoff"
] ]
pruneopts = ""
revision = "91e7b4fd31fcd3d5f436da26c980becec37ceefe" revision = "91e7b4fd31fcd3d5f436da26c980becec37ceefe"
version = "v1.11.0" version = "v1.11.0"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
input-imports = [ inputs-digest = "8e82141d5167c6c058ee2700de4573cbf90e428f8e62ff93b159e8a73cc284e0"
"github.com/container-storage-interface/spec/lib/go/csi/v0",
"github.com/golang/glog",
"github.com/golang/mock/gomock",
"github.com/kubernetes-csi/csi-test/driver",
"google.golang.org/grpc",
"google.golang.org/grpc/codes",
"google.golang.org/grpc/connectivity",
"google.golang.org/grpc/status",
"k8s.io/api/core/v1",
"k8s.io/api/storage/v1",
"k8s.io/api/storage/v1beta1",
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1",
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset",
"k8s.io/apimachinery/pkg/api/errors",
"k8s.io/apimachinery/pkg/api/meta",
"k8s.io/apimachinery/pkg/api/resource",
"k8s.io/apimachinery/pkg/apis/meta/v1",
"k8s.io/apimachinery/pkg/labels",
"k8s.io/apimachinery/pkg/runtime",
"k8s.io/apimachinery/pkg/runtime/schema",
"k8s.io/apimachinery/pkg/runtime/serializer",
"k8s.io/apimachinery/pkg/types",
"k8s.io/apimachinery/pkg/util/diff",
"k8s.io/apimachinery/pkg/util/sets",
"k8s.io/apimachinery/pkg/util/validation",
"k8s.io/apimachinery/pkg/util/wait",
"k8s.io/apimachinery/pkg/watch",
"k8s.io/client-go/discovery",
"k8s.io/client-go/discovery/fake",
"k8s.io/client-go/kubernetes",
"k8s.io/client-go/kubernetes/fake",
"k8s.io/client-go/kubernetes/scheme",
"k8s.io/client-go/kubernetes/typed/core/v1",
"k8s.io/client-go/rest",
"k8s.io/client-go/testing",
"k8s.io/client-go/tools/cache",
"k8s.io/client-go/tools/clientcmd",
"k8s.io/client-go/tools/record",
"k8s.io/client-go/tools/reference",
"k8s.io/client-go/util/flowcontrol",
"k8s.io/client-go/util/workqueue",
"k8s.io/code-generator/cmd/client-gen",
"k8s.io/code-generator/cmd/deepcopy-gen",
"k8s.io/code-generator/cmd/defaulter-gen",
"k8s.io/code-generator/cmd/informer-gen",
"k8s.io/code-generator/cmd/lister-gen",
"k8s.io/code-generator/cmd/openapi-gen",
"k8s.io/kubernetes/pkg/util/goroutinemap",
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff",
]
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -12,19 +12,19 @@ required = [
[[constraint]] [[constraint]]
name = "github.com/container-storage-interface/spec" name = "github.com/container-storage-interface/spec"
version = "~0.3.0" version = "1.0.0-rc2"
[[override]] [[override]]
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
version = "v1.1.0" version = "v1.1.0"
[[constraint]] [[constraint]]
branch = "master" branch = "master"
name = "github.com/golang/glog" name = "github.com/golang/glog"
[[constraint]] [[constraint]]
branch = "master"
name = "github.com/kubernetes-csi/csi-test" name = "github.com/kubernetes-csi/csi-test"
version = "1.0.0-rc2"
[[constraint]] [[constraint]]
name = "google.golang.org/grpc" name = "google.golang.org/grpc"

View File

@@ -1,3 +1,4 @@
*.tmp *.tmp
.DS_Store .DS_Store
.build .build
*.swp

View File

@@ -29,7 +29,7 @@ jobs:
# Lang stage: Go # Lang stage: Go
- stage: lang - stage: lang
language: go language: go
go: 1.9.5 go: 1.10.4
go_import_path: github.com/container-storage-interface/spec go_import_path: github.com/container-storage-interface/spec
install: install:
- make -C lib/go protoc - make -C lib/go protoc

Binary file not shown.

View File

@@ -1,6 +1,9 @@
# How to Contribute # How to Contribute
CSI is under [Apache 2.0](LICENSE) and accepts contributions via GitHub pull requests. CSI is under [Apache 2.0](LICENSE) and accepts contributions via GitHub pull requests.
Contributions require signing an individual or Corporate CLA available [here](https://github.com/container-storage-interface/spec/blob/master/CCLA.pdf) which should be signed and mailed to the [mailing list]( https://groups.google.com/forum/#!topic/container-storage-interface-community/).
This document outlines some of the conventions on development workflow, commit message formatting, contact points and other resources to make it easier to get your contribution accepted. This document outlines some of the conventions on development workflow, commit message formatting, contact points and other resources to make it easier to get your contribution accepted.
## Markdown style ## Markdown style

View File

@@ -3,8 +3,8 @@ approvers:
- thockin # Representing Kubernetes - thockin # Representing Kubernetes
- jieyu # Representing Mesos - jieyu # Representing Mesos
- jdef # Representing Mesos - jdef # Representing Mesos
- cpuguy83 # Representing Docker - anusha-ragunathan # Representing Docker
- mycure # Representing Docker - ddebroy # Representing Docker
- julian-hj # Representing Cloud Foundry - julian-hj # Representing Cloud Foundry
- paulcwarren # Representing Cloud Foundry - paulcwarren # Representing Cloud Foundry
reviewers: reviewers:

View File

@@ -8,6 +8,6 @@ This project contains the CSI [specification](spec.md) and [protobuf](csi.proto)
### Container Orchestrators (CO) ### Container Orchestrators (CO)
* [Cloud Foundry](https://github.com/cloudfoundry/csi-local-volume-release) * [Cloud Foundry](https://github.com/cloudfoundry/csi-plugins-release/blob/master/CSI_SUPPORT.md)
* [Kubernetes](https://kubernetes-csi.github.io/docs/) * [Kubernetes](https://kubernetes-csi.github.io/docs/)
* [Mesos](http://mesos.apache.org/documentation/latest/csi/) * [Mesos](http://mesos.apache.org/documentation/latest/csi/)

View File

@@ -1 +1 @@
0.3.0 1.0.0

View File

@@ -1,10 +1,18 @@
// Code generated by make; DO NOT EDIT. // Code generated by make; DO NOT EDIT.
syntax = "proto3"; syntax = "proto3";
package csi.v0; package csi.v1;
import "google/protobuf/descriptor.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto"; import "google/protobuf/wrappers.proto";
option go_package = "csi"; option go_package = "csi";
extend google.protobuf.FieldOptions {
// Indicates that a field MAY contain information that is sensitive
// and MUST be treated as such (e.g. not logged).
bool csi_secret = 1059;
}
service Identity { service Identity {
rpc GetPluginInfo(GetPluginInfoRequest) rpc GetPluginInfo(GetPluginInfoRequest)
returns (GetPluginInfoResponse) {} returns (GetPluginInfoResponse) {}
@@ -64,20 +72,12 @@ service Node {
rpc NodeUnpublishVolume (NodeUnpublishVolumeRequest) rpc NodeUnpublishVolume (NodeUnpublishVolumeRequest)
returns (NodeUnpublishVolumeResponse) {} returns (NodeUnpublishVolumeResponse) {}
// NodeGetId is being deprecated in favor of NodeGetInfo and will be rpc NodeGetVolumeStats (NodeGetVolumeStatsRequest)
// removed in CSI 1.0. Existing drivers, however, may depend on this returns (NodeGetVolumeStatsResponse) {}
// RPC call and hence this RPC call MUST be implemented by the CSI
// plugin prior to v1.0.
rpc NodeGetId (NodeGetIdRequest)
returns (NodeGetIdResponse) {
option deprecated = true;
}
rpc NodeGetCapabilities (NodeGetCapabilitiesRequest) rpc NodeGetCapabilities (NodeGetCapabilitiesRequest)
returns (NodeGetCapabilitiesResponse) {} returns (NodeGetCapabilitiesResponse) {}
// Prior to CSI 1.0 - CSI plugins MUST implement both NodeGetId and
// NodeGetInfo RPC calls.
rpc NodeGetInfo (NodeGetInfoRequest) rpc NodeGetInfo (NodeGetInfoRequest)
returns (NodeGetInfoResponse) {} returns (NodeGetInfoResponse) {}
} }
@@ -86,13 +86,13 @@ message GetPluginInfoRequest {
} }
message GetPluginInfoResponse { message GetPluginInfoResponse {
// The name MUST follow reverse domain name notation format // The name MUST follow domain name notation format
// (https://en.wikipedia.org/wiki/Reverse_domain_name_notation). // (https://tools.ietf.org/html/rfc1035#section-2.3.1). It SHOULD
// It SHOULD include the plugin's host company name and the plugin // include the plugin's host company name and the plugin name,
// name, to minimize the possibility of collisions. It MUST be 63 // to minimize the possibility of collisions. It MUST be 63
// characters or less, beginning and ending with an alphanumeric // characters or less, beginning and ending with an alphanumeric
// character ([a-z0-9A-Z]) with dashes (-), underscores (_), // character ([a-z0-9A-Z]) with dashes (-), dots (.), and
// dots (.), and alphanumerics between. This field is REQUIRED. // alphanumerics between. This field is REQUIRED.
string name = 1; string name = 1;
// This field is REQUIRED. Value of this field is opaque to the CO. // This field is REQUIRED. Value of this field is opaque to the CO.
@@ -108,7 +108,7 @@ message GetPluginCapabilitiesRequest {
message GetPluginCapabilitiesResponse { message GetPluginCapabilitiesResponse {
// All the capabilities that the controller service supports. This // All the capabilities that the controller service supports. This
// field is OPTIONAL. // field is OPTIONAL.
repeated PluginCapability capabilities = 2; repeated PluginCapability capabilities = 1;
} }
// Specifies a capability of the plugin. // Specifies a capability of the plugin.
@@ -119,7 +119,7 @@ message PluginCapability {
// CONTROLLER_SERVICE indicates that the Plugin provides RPCs for // CONTROLLER_SERVICE indicates that the Plugin provides RPCs for
// the ControllerService. Plugins SHOULD provide this capability. // the ControllerService. Plugins SHOULD provide this capability.
// In rare cases certain plugins may wish to omit the // In rare cases certain plugins MAY wish to omit the
// ControllerService entirely from their implementation, but such // ControllerService entirely from their implementation, but such
// SHOULD NOT be the common case. // SHOULD NOT be the common case.
// The presence of this capability determines whether the CO will // The presence of this capability determines whether the CO will
@@ -127,13 +127,13 @@ message PluginCapability {
// as specific RPCs as indicated by ControllerGetCapabilities. // as specific RPCs as indicated by ControllerGetCapabilities.
CONTROLLER_SERVICE = 1; CONTROLLER_SERVICE = 1;
// ACCESSIBILITY_CONSTRAINTS indicates that the volumes for this // VOLUME_ACCESSIBILITY_CONSTRAINTS indicates that the volumes for
// plugin may not be equally accessible by all nodes in the // this plugin MAY NOT be equally accessible by all nodes in the
// cluster. The CO MUST use the topology information returned by // cluster. The CO MUST use the topology information returned by
// CreateVolumeRequest along with the topology information // CreateVolumeRequest along with the topology information
// returned by NodeGetInfo to ensure that a given volume is // returned by NodeGetInfo to ensure that a given volume is
// accessible from a given node when scheduling workloads. // accessible from a given node when scheduling workloads.
ACCESSIBILITY_CONSTRAINTS = 2; VOLUME_ACCESSIBILITY_CONSTRAINTS = 2;
} }
Type type = 1; Type type = 1;
} }
@@ -174,37 +174,53 @@ message CreateVolumeRequest {
// The suggested name for the storage space. This field is REQUIRED. // The suggested name for the storage space. This field is REQUIRED.
// It serves two purposes: // It serves two purposes:
// 1) Idempotency - This name is generated by the CO to achieve // 1) Idempotency - This name is generated by the CO to achieve
// idempotency. If `CreateVolume` fails, the volume may or may not // idempotency. The Plugin SHOULD ensure that multiple
// be provisioned. In this case, the CO may call `CreateVolume` // `CreateVolume` calls for the same name do not result in more
// again, with the same name, to ensure the volume exists. The // than one piece of storage provisioned corresponding to that
// Plugin should ensure that multiple `CreateVolume` calls for the // name. If a Plugin is unable to enforce idempotency, the CO's
// same name do not result in more than one piece of storage // error recovery logic could result in multiple (unused) volumes
// provisioned corresponding to that name. If a Plugin is unable to // being provisioned.
// enforce idempotency, the CO's error recovery logic could result // In the case of error, the CO MUST handle the gRPC error codes
// in multiple (unused) volumes being provisioned. // per the recovery behavior defined in the "CreateVolume Errors"
// section below.
// The CO is responsible for cleaning up volumes it provisioned
// that it no longer needs. If the CO is uncertain whether a volume
// was provisioned or not when a `CreateVolume` call fails, the CO
// MAY call `CreateVolume` again, with the same name, to ensure the
// volume exists and to retrieve the volume's `volume_id` (unless
// otherwise prohibited by "CreateVolume Errors").
// 2) Suggested name - Some storage systems allow callers to specify // 2) Suggested name - Some storage systems allow callers to specify
// an identifier by which to refer to the newly provisioned // an identifier by which to refer to the newly provisioned
// storage. If a storage system supports this, it can optionally // storage. If a storage system supports this, it can optionally
// use this name as the identifier for the new volume. // use this name as the identifier for the new volume.
// Any Unicode string that conforms to the length limit is allowed
// except those containing the following banned characters:
// U+0000-U+0008, U+000B, U+000C, U+000E-U+001F, U+007F-U+009F.
// (These are control characters other than commonly used whitespace.)
string name = 1; string name = 1;
// This field is OPTIONAL. This allows the CO to specify the capacity // This field is OPTIONAL. This allows the CO to specify the capacity
// requirement of the volume to be provisioned. If not specified, the // requirement of the volume to be provisioned. If not specified, the
// Plugin MAY choose an implementation-defined capacity range. If // Plugin MAY choose an implementation-defined capacity range. If
// specified it MUST always be honored, even when creating volumes // specified it MUST always be honored, even when creating volumes
// from a source; which may force some backends to internally extend // from a source; which MAY force some backends to internally extend
// the volume after creating it. // the volume after creating it.
CapacityRange capacity_range = 2; CapacityRange capacity_range = 2;
// The capabilities that the provisioned volume MUST have: the Plugin // The capabilities that the provisioned volume MUST have. SP MUST
// MUST provision a volume that could satisfy ALL of the // provision a volume that will satisfy ALL of the capabilities
// capabilities specified in this list. The Plugin MUST assume that // specified in this list. Otherwise SP MUST return the appropriate
// the CO MAY use the provisioned volume later with ANY of the // gRPC error code.
// capabilities specified in this list. This also enables the CO to do // The Plugin MUST assume that the CO MAY use the provisioned volume
// early validation: if ANY of the specified volume capabilities are // with ANY of the capabilities specified in this list.
// not supported by the Plugin, the call SHALL fail. This field is // For example, a CO MAY specify two volume capabilities: one with
// REQUIRED. // access mode SINGLE_NODE_WRITER and another with access mode
// MULTI_NODE_READER_ONLY. In this case, the SP MUST verify that the
// provisioned volume can be used in either mode.
// This also enables the CO to do early validation: If ANY of the
// specified volume capabilities are not supported by the SP, the call
// MUST return the appropriate gRPC error code.
// This field is REQUIRED.
repeated VolumeCapability volume_capabilities = 3; repeated VolumeCapability volume_capabilities = 3;
// Plugin specific parameters passed in as opaque key-value pairs. // Plugin specific parameters passed in as opaque key-value pairs.
@@ -215,7 +231,7 @@ message CreateVolumeRequest {
// Secrets required by plugin to complete volume creation request. // Secrets required by plugin to complete volume creation request.
// This field is OPTIONAL. Refer to the `Secrets Requirements` // This field is OPTIONAL. Refer to the `Secrets Requirements`
// section on how to use this field. // section on how to use this field.
map<string, string> controller_create_secrets = 5; map<string, string> secrets = 5 [(csi_secret) = true];
// If specified, the new volume will be pre-populated with data from // If specified, the new volume will be pre-populated with data from
// this source. This field is OPTIONAL. // this source. This field is OPTIONAL.
@@ -228,10 +244,10 @@ message CreateVolumeRequest {
// topological accessibility information supported by the SP. // topological accessibility information supported by the SP.
// This field is OPTIONAL. // This field is OPTIONAL.
// This field SHALL NOT be specified unless the SP has the // This field SHALL NOT be specified unless the SP has the
// ACCESSIBILITY_CONSTRAINTS plugin capability. // VOLUME_ACCESSIBILITY_CONSTRAINTS plugin capability.
// If this field is not specified and the SP has the // If this field is not specified and the SP has the
// ACCESSIBILITY_CONSTRAINTS plugin capability, the SP MAY choose // VOLUME_ACCESSIBILITY_CONSTRAINTS plugin capability, the SP MAY
// where the provisioned volume is accessible from. // choose where the provisioned volume is accessible from.
TopologyRequirement accessibility_requirements = 7; TopologyRequirement accessibility_requirements = 7;
} }
@@ -243,11 +259,19 @@ message VolumeContentSource {
// This field is REQUIRED. Plugin is REQUIRED to support creating // This field is REQUIRED. Plugin is REQUIRED to support creating
// volume from snapshot if it supports the capability // volume from snapshot if it supports the capability
// CREATE_DELETE_SNAPSHOT. // CREATE_DELETE_SNAPSHOT.
string id = 1; string snapshot_id = 1;
}
message VolumeSource {
// Contains identity information for the existing source volume.
// This field is REQUIRED. Plugins reporting CLONE_VOLUME
// capability MUST support creating a volume from another volume.
string volume_id = 1;
} }
oneof type { oneof type {
SnapshotSource snapshot = 1; SnapshotSource snapshot = 1;
VolumeSource volume = 2;
} }
} }
@@ -334,7 +358,7 @@ message CapacityRange {
int64 limit_bytes = 2; int64 limit_bytes = 2;
} }
// The information about a provisioned volume. // Information about a specific volume.
message Volume { message Volume {
// The capacity of the volume in bytes. This field is OPTIONAL. If not // The capacity of the volume in bytes. This field is OPTIONAL. If not
// set (value of 0), it indicates that the capacity of the volume is // set (value of 0), it indicates that the capacity of the volume is
@@ -342,20 +366,32 @@ message Volume {
// The value of this field MUST NOT be negative. // The value of this field MUST NOT be negative.
int64 capacity_bytes = 1; int64 capacity_bytes = 1;
// Contains identity information for the created volume. This field is // The identifier for this volume, generated by the plugin.
// REQUIRED. The identity information will be used by the CO in // This field is REQUIRED.
// subsequent calls to refer to the provisioned volume. // This field MUST contain enough information to uniquely identify
string id = 2; // this specific volume vs all other volumes supported by this plugin.
// This field SHALL be used by the CO in subsequent calls to refer to
// this volume.
// The SP is NOT responsible for global uniqueness of volume_id across
// multiple SPs.
string volume_id = 2;
// Attributes reflect static properties of a volume and MUST be passed // Opaque static properties of the volume. SP MAY use this field to
// to volume validation and publishing calls. // ensure subsequent volume validation and publishing calls have
// Attributes SHALL be opaque to a CO. Attributes SHALL NOT be mutable // contextual information.
// and SHALL be safe for the CO to cache. Attributes SHOULD NOT // The contents of this field SHALL be opaque to a CO.
// contain sensitive information. Attributes MAY NOT uniquely identify // The contents of this field SHALL NOT be mutable.
// a volume. A volume uniquely identified by `id` SHALL always report // The contents of this field SHALL be safe for the CO to cache.
// the same attributes. This field is OPTIONAL and when present MUST // The contents of this field SHOULD NOT contain sensitive
// be passed to volume validation and publishing calls. // information.
map<string, string> attributes = 3; // The contents of this field SHOULD NOT be used for uniquely
// identifying a volume. The `volume_id` alone SHOULD be sufficient to
// identify the volume.
// A volume uniquely identified by `volume_id` SHALL always report the
// same volume_context.
// This field is OPTIONAL and when present MUST be passed to volume
// validation and publishing calls.
map<string, string> volume_context = 3;
// If specified, indicates that the volume is not empty and is // If specified, indicates that the volume is not empty and is
// pre-populated with data from the specified source. // pre-populated with data from the specified source.
@@ -365,7 +401,7 @@ message Volume {
// Specifies where (regions, zones, racks, etc.) the provisioned // Specifies where (regions, zones, racks, etc.) the provisioned
// volume is accessible from. // volume is accessible from.
// A plugin that returns this field MUST also set the // A plugin that returns this field MUST also set the
// ACCESSIBILITY_CONSTRAINTS plugin capability. // VOLUME_ACCESSIBILITY_CONSTRAINTS plugin capability.
// An SP MAY specify multiple topologies to indicate the volume is // An SP MAY specify multiple topologies to indicate the volume is
// accessible from multiple locations. // accessible from multiple locations.
// COs MAY use this information along with the topology information // COs MAY use this information along with the topology information
@@ -373,7 +409,7 @@ message Volume {
// from a given node when scheduling workloads. // from a given node when scheduling workloads.
// This field is OPTIONAL. If it is not specified, the CO MAY assume // This field is OPTIONAL. If it is not specified, the CO MAY assume
// the volume is equally accessible from all nodes in the cluster and // the volume is equally accessible from all nodes in the cluster and
// may schedule workloads referencing the volume on any available // MAY schedule workloads referencing the volume on any available
// node. // node.
// //
// Example 1: // Example 1:
@@ -527,15 +563,18 @@ message TopologyRequirement {
// A topological segment is a specific instance of a topological domain, // A topological segment is a specific instance of a topological domain,
// like "zone3", "rack3", etc. // like "zone3", "rack3", etc.
// For example {"com.company/zone": "Z1", "com.company/rack": "R3"} // For example {"com.company/zone": "Z1", "com.company/rack": "R3"}
// Valid keys have two segments: an optional prefix and name, separated // Valid keys have two segments: an OPTIONAL prefix and name, separated
// by a slash (/), for example: "com.company.example/zone". // by a slash (/), for example: "com.company.example/zone".
// The key name segment is required. The prefix is optional. // The key name segment is REQUIRED. The prefix is OPTIONAL.
// Both the key name and the prefix MUST each be 63 characters or less, // The key name MUST be 63 characters or less, begin and end with an
// begin and end with an alphanumeric character ([a-z0-9A-Z]) and // alphanumeric character ([a-z0-9A-Z]), and contain only dashes (-),
// contain only dashes (-), underscores (_), dots (.), or alphanumerics // underscores (_), dots (.), or alphanumerics in between, for example
// in between, for example "zone". // "zone".
// The key prefix MUST follow reverse domain name notation format // The key prefix MUST be 63 characters or less, begin and end with a
// (https://en.wikipedia.org/wiki/Reverse_domain_name_notation). // lower-case alphanumeric character ([a-z0-9]), contain only
// dashes (-), dots (.), or lower-case alphanumerics in between, and
// follow domain name notation format
// (https://tools.ietf.org/html/rfc1035#section-2.3.1).
// The key prefix SHOULD include the plugin's host company name and/or // The key prefix SHOULD include the plugin's host company name and/or
// the plugin name, to minimize the possibility of collisions with keys // the plugin name, to minimize the possibility of collisions with keys
// from other plugins. // from other plugins.
@@ -558,7 +597,7 @@ message DeleteVolumeRequest {
// Secrets required by plugin to complete volume deletion request. // Secrets required by plugin to complete volume deletion request.
// This field is OPTIONAL. Refer to the `Secrets Requirements` // This field is OPTIONAL. Refer to the `Secrets Requirements`
// section on how to use this field. // section on how to use this field.
map<string, string> controller_delete_secrets = 2; map<string, string> secrets = 2 [(csi_secret) = true];
} }
message DeleteVolumeResponse { message DeleteVolumeResponse {
@@ -573,31 +612,44 @@ message ControllerPublishVolumeRequest {
// field to match the node ID returned by `NodeGetInfo`. // field to match the node ID returned by `NodeGetInfo`.
string node_id = 2; string node_id = 2;
// The capability of the volume the CO expects the volume to have. // Volume capability describing how the CO intends to use this volume.
// SP MUST ensure the CO can use the published volume as described.
// Otherwise SP MUST return the appropriate gRPC error code.
// This is a REQUIRED field. // This is a REQUIRED field.
VolumeCapability volume_capability = 3; VolumeCapability volume_capability = 3;
// Whether to publish the volume in readonly mode. This field is // Indicates SP MUST publish the volume in readonly mode.
// REQUIRED. // CO MUST set this field to false if SP does not have the
// PUBLISH_READONLY controller capability.
// This is a REQUIRED field.
bool readonly = 4; bool readonly = 4;
// Secrets required by plugin to complete controller publish volume // Secrets required by plugin to complete controller publish volume
// request. This field is OPTIONAL. Refer to the // request. This field is OPTIONAL. Refer to the
// `Secrets Requirements` section on how to use this field. // `Secrets Requirements` section on how to use this field.
map<string, string> controller_publish_secrets = 5; map<string, string> secrets = 5 [(csi_secret) = true];
// Attributes of the volume to be used on a node. This field is // Volume context as returned by CO in CreateVolumeRequest. This field
// OPTIONAL and MUST match the attributes of the Volume identified // is OPTIONAL and MUST match the volume_context of the volume
// by `volume_id`. // identified by `volume_id`.
map<string, string> volume_attributes = 6; map<string, string> volume_context = 6;
} }
message ControllerPublishVolumeResponse { message ControllerPublishVolumeResponse {
// The SP specific information that will be passed to the Plugin in // Opaque static publish properties of the volume. SP MAY use this
// the subsequent `NodeStageVolume` or `NodePublishVolume` calls // field to ensure subsequent `NodeStageVolume` or `NodePublishVolume`
// for the given volume. // calls calls have contextual information.
// This information is opaque to the CO. This field is OPTIONAL. // The contents of this field SHALL be opaque to a CO.
map<string, string> publish_info = 1; // The contents of this field SHALL NOT be mutable.
// The contents of this field SHALL be safe for the CO to cache.
// The contents of this field SHOULD NOT contain sensitive
// information.
// The contents of this field SHOULD NOT be used for uniquely
// identifying a volume. The `volume_id` alone SHOULD be sufficient to
// identify the volume.
// This field is OPTIONAL and when present MUST be passed to
// subsequent `NodeStageVolume` or `NodePublishVolume` calls
map<string, string> publish_context = 1;
} }
message ControllerUnpublishVolumeRequest { message ControllerUnpublishVolumeRequest {
// The ID of the volume. This field is REQUIRED. // The ID of the volume. This field is REQUIRED.
@@ -615,7 +667,7 @@ message ControllerUnpublishVolumeRequest {
// ControllerPublishVolume call for the specified volume. // ControllerPublishVolume call for the specified volume.
// This field is OPTIONAL. Refer to the `Secrets Requirements` // This field is OPTIONAL. Refer to the `Secrets Requirements`
// section on how to use this field. // section on how to use this field.
map<string, string> controller_unpublish_secrets = 3; map<string, string> secrets = 3 [(csi_secret) = true];
} }
message ControllerUnpublishVolumeResponse { message ControllerUnpublishVolumeResponse {
@@ -625,30 +677,52 @@ message ValidateVolumeCapabilitiesRequest {
// The ID of the volume to check. This field is REQUIRED. // The ID of the volume to check. This field is REQUIRED.
string volume_id = 1; string volume_id = 1;
// Volume context as returned by CO in CreateVolumeRequest. This field
// is OPTIONAL and MUST match the volume_context of the volume
// identified by `volume_id`.
map<string, string> volume_context = 2;
// The capabilities that the CO wants to check for the volume. This // The capabilities that the CO wants to check for the volume. This
// call SHALL return "supported" only if all the volume capabilities // call SHALL return "confirmed" only if all the volume capabilities
// specified below are supported. This field is REQUIRED. // specified below are supported. This field is REQUIRED.
repeated VolumeCapability volume_capabilities = 2; repeated VolumeCapability volume_capabilities = 3;
// Attributes of the volume to check. This field is OPTIONAL and MUST // See CreateVolumeRequest.parameters.
// match the attributes of the Volume identified by `volume_id`. // This field is OPTIONAL.
map<string, string> volume_attributes = 3; map<string, string> parameters = 4;
// Specifies where (regions, zones, racks, etc.) the caller believes // Secrets required by plugin to complete volume validation request.
// the volume is accessible from. // This field is OPTIONAL. Refer to the `Secrets Requirements`
// A caller MAY specify multiple topologies to indicate they believe // section on how to use this field.
// the volume to be accessible from multiple locations. map<string, string> secrets = 5 [(csi_secret) = true];
// This field is OPTIONAL. This field SHALL NOT be set unless the
// plugin advertises the ACCESSIBILITY_CONSTRAINTS capability.
repeated Topology accessible_topology = 4;
} }
message ValidateVolumeCapabilitiesResponse { message ValidateVolumeCapabilitiesResponse {
// True if the Plugin supports the specified capabilities for the message Confirmed {
// given volume. This field is REQUIRED. // Volume context validated by the plugin.
bool supported = 1; // This field is OPTIONAL.
map<string, string> volume_context = 1;
// Message to the CO if `supported` above is false. This field is // Volume capabilities supported by the plugin.
// This field is REQUIRED.
repeated VolumeCapability volume_capabilities = 2;
// The volume creation parameters validated by the plugin.
// This field is OPTIONAL.
map<string, string> parameters = 3;
}
// Confirmed indicates to the CO the set of capabilities that the
// plugin has validated. This field SHALL only be set to a non-empty
// value for successful validation responses.
// For successful validation responses, the CO SHALL compare the
// fields of this message to the originally requested capabilities in
// order to guard against an older plugin reporting "valid" for newer
// capability fields that it does not yet understand.
// This field is OPTIONAL.
Confirmed confirmed = 1;
// Message to the CO if `confirmed` above is empty. This field is
// OPTIONAL. // OPTIONAL.
// An empty string is equal to an unspecified field value. // An empty string is equal to an unspecified field value.
string message = 2; string message = 2;
@@ -705,7 +779,7 @@ message GetCapacityRequest {
// `accessible_topology`. This is the same as the // `accessible_topology`. This is the same as the
// `accessible_topology` the CO returns in a `CreateVolumeResponse`. // `accessible_topology` the CO returns in a `CreateVolumeResponse`.
// This field is OPTIONAL. This field SHALL NOT be set unless the // This field is OPTIONAL. This field SHALL NOT be set unless the
// plugin advertises the ACCESSIBILITY_CONSTRAINTS capability. // plugin advertises the VOLUME_ACCESSIBILITY_CONSTRAINTS capability.
Topology accessible_topology = 3; Topology accessible_topology = 3;
} }
@@ -725,7 +799,7 @@ message ControllerGetCapabilitiesRequest {
message ControllerGetCapabilitiesResponse { message ControllerGetCapabilitiesResponse {
// All the capabilities that the controller service supports. This // All the capabilities that the controller service supports. This
// field is OPTIONAL. // field is OPTIONAL.
repeated ControllerServiceCapability capabilities = 2; repeated ControllerServiceCapability capabilities = 1;
} }
// Specifies a capability of the controller service. // Specifies a capability of the controller service.
@@ -742,11 +816,15 @@ message ControllerServiceCapability {
// CREATE_DELETE_SNAPSHOT MUST support creating volume from // CREATE_DELETE_SNAPSHOT MUST support creating volume from
// snapshot. // snapshot.
CREATE_DELETE_SNAPSHOT = 5; CREATE_DELETE_SNAPSHOT = 5;
// LIST_SNAPSHOTS is NOT REQUIRED. For plugins that need to upload
// a snapshot after it is being cut, LIST_SNAPSHOTS COULD be used
// with the snapshot_id as the filter to query whether the
// uploading process is complete or not.
LIST_SNAPSHOTS = 6; LIST_SNAPSHOTS = 6;
// Plugins supporting volume cloning at the storage level MAY
// report this capability. The source volume MUST be managed by
// the same plugin. Not all volume sources and parameters
// combinations MAY work.
CLONE_VOLUME = 7;
// Indicates the SP supports ControllerPublishVolume.readonly
// field.
PUBLISH_READONLY = 8;
} }
Type type = 1; Type type = 1;
@@ -764,12 +842,16 @@ message CreateSnapshotRequest {
// The suggested name for the snapshot. This field is REQUIRED for // The suggested name for the snapshot. This field is REQUIRED for
// idempotency. // idempotency.
// Any Unicode string that conforms to the length limit is allowed
// except those containing the following banned characters:
// U+0000-U+0008, U+000B, U+000C, U+000E-U+001F, U+007F-U+009F.
// (These are control characters other than commonly used whitespace.)
string name = 2; string name = 2;
// Secrets required by plugin to complete snapshot creation request. // Secrets required by plugin to complete snapshot creation request.
// This field is OPTIONAL. Refer to the `Secrets Requirements` // This field is OPTIONAL. Refer to the `Secrets Requirements`
// section on how to use this field. // section on how to use this field.
map<string, string> create_snapshot_secrets = 3; map<string, string> secrets = 3 [(csi_secret) = true];
// Plugin specific parameters passed in as opaque key-value pairs. // Plugin specific parameters passed in as opaque key-value pairs.
// This field is OPTIONAL. The Plugin is responsible for parsing and // This field is OPTIONAL. The Plugin is responsible for parsing and
@@ -791,7 +873,7 @@ message CreateSnapshotResponse {
Snapshot snapshot = 1; Snapshot snapshot = 1;
} }
// The information about a provisioned snapshot. // Information about a specific snapshot.
message Snapshot { message Snapshot {
// This is the complete size of the snapshot in bytes. The purpose of // This is the complete size of the snapshot in bytes. The purpose of
// this field is to give CO guidance on how much space is needed to // this field is to give CO guidance on how much space is needed to
@@ -802,11 +884,16 @@ message Snapshot {
// zero means it is unspecified. // zero means it is unspecified.
int64 size_bytes = 1; int64 size_bytes = 1;
// Uniquely identifies a snapshot and is generated by the plugin. It // The identifier for this snapshot, generated by the plugin.
// will not change over time. This field is REQUIRED. The identity // This field is REQUIRED.
// information will be used by the CO in subsequent calls to refer to // This field MUST contain enough information to uniquely identify
// the provisioned snapshot. // this specific snapshot vs all other snapshots supported by this
string id = 2; // plugin.
// This field SHALL be used by the CO in subsequent calls to refer to
// this snapshot.
// The SP is NOT responsible for global uniqueness of snapshot_id
// across multiple SPs.
string snapshot_id = 2;
// Identity information for the source volume. Note that creating a // Identity information for the source volume. Note that creating a
// snapshot from a snapshot is not supported here so the source has to // snapshot from a snapshot is not supported here so the source has to
@@ -814,43 +901,13 @@ message Snapshot {
string source_volume_id = 3; string source_volume_id = 3;
// Timestamp when the point-in-time snapshot is taken on the storage // Timestamp when the point-in-time snapshot is taken on the storage
// system. The format of this field should be a Unix nanoseconds time // system. This field is REQUIRED.
// encoded as an int64. On Unix, the command `date +%s%N` returns the .google.protobuf.Timestamp creation_time = 4;
// current time in nanoseconds since 1970-01-01 00:00:00 UTC. This
// field is REQUIRED.
int64 created_at = 4;
// The status of a snapshot. // Indicates if a snapshot is ready to use as a
SnapshotStatus status = 5; // `volume_content_source` in a `CreateVolumeRequest`. The default
} // value is false. This field is REQUIRED.
bool ready_to_use = 5;
// The status of a snapshot.
message SnapshotStatus {
enum Type {
UNKNOWN = 0;
// A snapshot is ready for use.
READY = 1;
// A snapshot is cut and is now being uploaded.
// Some cloud providers and storage systems uploads the snapshot
// to the cloud after the snapshot is cut. During this phase,
// `thaw` can be done so the application can be running again if
// `freeze` was done before taking the snapshot.
UPLOADING = 2;
// An error occurred during the snapshot uploading process.
// This error status is specific for uploading because
// `CreateSnaphot` is a blocking call before the snapshot is
// cut and therefore it SHOULD NOT come back with an error
// status when an error occurs. Instead a gRPC error code SHALL
// be returned by `CreateSnapshot` when an error occurs before
// a snapshot is cut.
ERROR_UPLOADING = 3;
}
// This field is REQUIRED.
Type type = 1;
// Additional information to describe why a snapshot ended up in the
// `ERROR_UPLOADING` status. This field is OPTIONAL.
string details = 2;
} }
message DeleteSnapshotRequest { message DeleteSnapshotRequest {
// The ID of the snapshot to be deleted. // The ID of the snapshot to be deleted.
@@ -860,7 +917,7 @@ message DeleteSnapshotRequest {
// Secrets required by plugin to complete snapshot deletion request. // Secrets required by plugin to complete snapshot deletion request.
// This field is OPTIONAL. Refer to the `Secrets Requirements` // This field is OPTIONAL. Refer to the `Secrets Requirements`
// section on how to use this field. // section on how to use this field.
map<string, string> delete_snapshot_secrets = 2; map<string, string> secrets = 2 [(csi_secret) = true];
} }
message DeleteSnapshotResponse {} message DeleteSnapshotResponse {}
@@ -890,7 +947,8 @@ message ListSnapshotsRequest {
// Identity information for a specific snapshot. This field is // Identity information for a specific snapshot. This field is
// OPTIONAL. It can be used to list only a specific snapshot. // OPTIONAL. It can be used to list only a specific snapshot.
// ListSnapshots will return with current snapshot information // ListSnapshots will return with current snapshot information
// and will not block if the snapshot is being uploaded. // and will not block if the snapshot is being processed after
// it is cut.
string snapshot_id = 4; string snapshot_id = 4;
} }
@@ -918,28 +976,33 @@ message NodeStageVolumeRequest {
// has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be // has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be
// left unset if the corresponding Controller Plugin does not have // left unset if the corresponding Controller Plugin does not have
// this capability. This is an OPTIONAL field. // this capability. This is an OPTIONAL field.
map<string, string> publish_info = 2; map<string, string> publish_context = 2;
// The path to which the volume will be published. It MUST be an // The path to which the volume MAY be staged. It MUST be an
// absolute path in the root filesystem of the process serving this // absolute path in the root filesystem of the process serving this
// request. The CO SHALL ensure that there is only one // request. The CO SHALL ensure that there is only one
// staging_target_path per volume. // `staging_target_path` per volume. The CO SHALL ensure that the
// process serving the request has `read` and `write` permission to
// the path, and is able to create files or directories at the path
// if it does not exist.
// This is a REQUIRED field. // This is a REQUIRED field.
string staging_target_path = 3; string staging_target_path = 3;
// The capability of the volume the CO expects the volume to have. // Volume capability describing how the CO intends to use this volume.
// SP MUST ensure the CO can use the staged volume as described.
// Otherwise SP MUST return the appropriate gRPC error code.
// This is a REQUIRED field. // This is a REQUIRED field.
VolumeCapability volume_capability = 4; VolumeCapability volume_capability = 4;
// Secrets required by plugin to complete node stage volume request. // Secrets required by plugin to complete node stage volume request.
// This field is OPTIONAL. Refer to the `Secrets Requirements` // This field is OPTIONAL. Refer to the `Secrets Requirements`
// section on how to use this field. // section on how to use this field.
map<string, string> node_stage_secrets = 5; map<string, string> secrets = 5 [(csi_secret) = true];
// Attributes of the volume to publish. This field is OPTIONAL and // Volume context as returned by CO in CreateVolumeRequest. This field
// MUST match the attributes of the `Volume` identified by // is OPTIONAL and MUST match the volume_context of the volume
// `volume_id`. // identified by `volume_id`.
map<string, string> volume_attributes = 6; map<string, string> volume_context = 6;
} }
message NodeStageVolumeResponse { message NodeStageVolumeResponse {
@@ -949,7 +1012,7 @@ message NodeUnstageVolumeRequest {
// The ID of the volume. This field is REQUIRED. // The ID of the volume. This field is REQUIRED.
string volume_id = 1; string volume_id = 1;
// The path at which the volume was published. It MUST be an absolute // The path at which the volume was staged. It MUST be an absolute
// path in the root filesystem of the process serving this request. // path in the root filesystem of the process serving this request.
// This is a REQUIRED field. // This is a REQUIRED field.
string staging_target_path = 2; string staging_target_path = 2;
@@ -967,9 +1030,9 @@ message NodePublishVolumeRequest {
// has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be // has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be
// left unset if the corresponding Controller Plugin does not have // left unset if the corresponding Controller Plugin does not have
// this capability. This is an OPTIONAL field. // this capability. This is an OPTIONAL field.
map<string, string> publish_info = 2; map<string, string> publish_context = 2;
// The path to which the device was mounted by `NodeStageVolume`. // The path to which the volume was staged by `NodeStageVolume`.
// It MUST be an absolute path in the root filesystem of the process // It MUST be an absolute path in the root filesystem of the process
// serving this request. // serving this request.
// It MUST be set if the Node Plugin implements the // It MUST be set if the Node Plugin implements the
@@ -980,28 +1043,31 @@ message NodePublishVolumeRequest {
// The path to which the volume will be published. It MUST be an // The path to which the volume will be published. It MUST be an
// absolute path in the root filesystem of the process serving this // absolute path in the root filesystem of the process serving this
// request. The CO SHALL ensure uniqueness of target_path per volume. // request. The CO SHALL ensure uniqueness of target_path per volume.
// The CO SHALL ensure that the path exists, and that the process // The CO SHALL ensure that the process serving the request has
// serving the request has `read` and `write` permissions to the path. // `read` and `write` permissions to the path, and is able to create
// files or directories at the path if it does not exist.
// This is a REQUIRED field. // This is a REQUIRED field.
string target_path = 4; string target_path = 4;
// The capability of the volume the CO expects the volume to have. // Volume capability describing how the CO intends to use this volume.
// SP MUST ensure the CO can use the published volume as described.
// Otherwise SP MUST return the appropriate gRPC error code.
// This is a REQUIRED field. // This is a REQUIRED field.
VolumeCapability volume_capability = 5; VolumeCapability volume_capability = 5;
// Whether to publish the volume in readonly mode. This field is // Indicates SP MUST publish the volume in readonly mode.
// REQUIRED. // This field is REQUIRED.
bool readonly = 6; bool readonly = 6;
// Secrets required by plugin to complete node publish volume request. // Secrets required by plugin to complete node publish volume request.
// This field is OPTIONAL. Refer to the `Secrets Requirements` // This field is OPTIONAL. Refer to the `Secrets Requirements`
// section on how to use this field. // section on how to use this field.
map<string, string> node_publish_secrets = 7; map<string, string> secrets = 7 [(csi_secret) = true];
// Attributes of the volume to publish. This field is OPTIONAL and // Volume context as returned by CO in CreateVolumeRequest. This field
// MUST match the attributes of the Volume identified by // is OPTIONAL and MUST match the volume_context of the volume
// `volume_id`. // identified by `volume_id`.
map<string, string> volume_attributes = 8; map<string, string> volume_context = 8;
} }
message NodePublishVolumeResponse { message NodePublishVolumeResponse {
@@ -1020,15 +1086,43 @@ message NodeUnpublishVolumeRequest {
message NodeUnpublishVolumeResponse { message NodeUnpublishVolumeResponse {
// Intentionally empty. // Intentionally empty.
} }
message NodeGetIdRequest { message NodeGetVolumeStatsRequest {
// Intentionally empty. // The ID of the volume. This field is REQUIRED.
string volume_id = 1;
// It can be any valid path where volume was previously
// staged or published.
// It MUST be an absolute path in the root filesystem of
// the process serving this request.
// This is a REQUIRED field.
string volume_path = 2;
} }
message NodeGetIdResponse { message NodeGetVolumeStatsResponse {
// The ID of the node as understood by the SP which SHALL be used by // This field is OPTIONAL.
// CO in subsequent `ControllerPublishVolume`. repeated VolumeUsage usage = 1;
// This is a REQUIRED field. }
string node_id = 1;
message VolumeUsage {
enum Unit {
UNKNOWN = 0;
BYTES = 1;
INODES = 2;
}
// The available capacity in specified Unit. This field is OPTIONAL.
// The value of this field MUST NOT be negative.
int64 available = 1;
// The total capacity in specified Unit. This field is REQUIRED.
// The value of this field MUST NOT be negative.
int64 total = 2;
// The used capacity in specified Unit. This field is OPTIONAL.
// The value of this field MUST NOT be negative.
int64 used = 3;
// Units by which values are measured. This field is REQUIRED.
Unit unit = 4;
} }
message NodeGetCapabilitiesRequest { message NodeGetCapabilitiesRequest {
// Intentionally empty. // Intentionally empty.
@@ -1046,6 +1140,10 @@ message NodeServiceCapability {
enum Type { enum Type {
UNKNOWN = 0; UNKNOWN = 0;
STAGE_UNSTAGE_VOLUME = 1; STAGE_UNSTAGE_VOLUME = 1;
// If Plugin implements GET_VOLUME_STATS capability
// then it MUST implement NodeGetVolumeStats RPC
// call for fetching volume statistics.
GET_VOLUME_STATS = 2;
} }
Type type = 1; Type type = 1;
@@ -1060,9 +1158,14 @@ message NodeGetInfoRequest {
} }
message NodeGetInfoResponse { message NodeGetInfoResponse {
// The ID of the node as understood by the SP which SHALL be used by // The identifier of the node as understood by the SP.
// CO in subsequent calls to `ControllerPublishVolume`. // This field is REQUIRED.
// This is a REQUIRED field. // This field MUST contain enough information to uniquely identify
// this specific node vs all other nodes supported by this plugin.
// This field SHALL be used by the CO in subsequent calls, including
// `ControllerPublishVolume`, to refer to this node.
// The SP is NOT responsible for global uniqueness of node_id across
// multiple SPs.
string node_id = 1; string node_id = 1;
// Maximum number of volumes that controller can publish to the node. // Maximum number of volumes that controller can publish to the node.
@@ -1075,7 +1178,7 @@ message NodeGetInfoResponse {
// Specifies where (regions, zones, racks, etc.) the node is // Specifies where (regions, zones, racks, etc.) the node is
// accessible from. // accessible from.
// A plugin that returns this field MUST also set the // A plugin that returns this field MUST also set the
// ACCESSIBILITY_CONSTRAINTS plugin capability. // VOLUME_ACCESSIBILITY_CONSTRAINTS plugin capability.
// COs MAY use this information along with the topology information // COs MAY use this information along with the topology information
// returned in CreateVolumeResponse to ensure that a given volume is // returned in CreateVolumeResponse to ensure that a given volume is
// accessible from a given node when scheduling workloads. // accessible from a given node when scheduling workloads.

View File

@@ -58,14 +58,14 @@ $(PROTOC):
PROTOC_GEN_GO_PKG := github.com/golang/protobuf/protoc-gen-go PROTOC_GEN_GO_PKG := github.com/golang/protobuf/protoc-gen-go
PROTOC_GEN_GO := protoc-gen-go PROTOC_GEN_GO := protoc-gen-go
$(PROTOC_GEN_GO): PROTOBUF_PKG := $(dir $(PROTOC_GEN_GO_PKG)) $(PROTOC_GEN_GO): PROTOBUF_PKG := $(dir $(PROTOC_GEN_GO_PKG))
$(PROTOC_GEN_GO): PROTOBUF_VERSION := v1.1.0 $(PROTOC_GEN_GO): PROTOBUF_VERSION := v1.2.0
$(PROTOC_GEN_GO): $(PROTOC_GEN_GO):
mkdir -p $(dir $(GOPATH)/src/$(PROTOBUF_PKG)) mkdir -p $(dir $(GOPATH)/src/$(PROTOBUF_PKG))
test -d $(GOPATH)/src/$(PROTOBUF_PKG)/.git || git clone https://$(PROTOBUF_PKG) $(GOPATH)/src/$(PROTOBUF_PKG) test -d $(GOPATH)/src/$(PROTOBUF_PKG)/.git || git clone https://$(PROTOBUF_PKG) $(GOPATH)/src/$(PROTOBUF_PKG)
(cd $(GOPATH)/src/$(PROTOBUF_PKG) && \ (cd $(GOPATH)/src/$(PROTOBUF_PKG) && \
(test "$$(git describe --tags | head -1)" = "$(PROTOBUF_VERSION)" || \ (test "$$(git describe --tags | head -1)" = "$(PROTOBUF_VERSION)" || \
(git fetch && git checkout tags/$(PROTOBUF_VERSION)))) (git fetch && git checkout tags/$(PROTOBUF_VERSION))))
(cd $(GOPATH)/src/$(PROTOBUF_PKG) && go get -v -d ./...) && \ (cd $(GOPATH)/src/$(PROTOBUF_PKG) && go get -v -d $$(go list -f '{{ .ImportPath }}' ./...)) && \
go build -o "$@" $(PROTOC_GEN_GO_PKG) go build -o "$@" $(PROTOC_GEN_GO_PKG)
@@ -83,18 +83,25 @@ export PATH := $(shell pwd):$(PATH)
## BUILD ## ## BUILD ##
######################################################################## ########################################################################
CSI_PROTO := ../../csi.proto CSI_PROTO := ../../csi.proto
CSI_PKG := $(shell cat $(CSI_PROTO) | sed -n -e 's/^package.\([^;]*\);$$/\1/p'|tr '.' '/') CSI_PKG_ROOT := github.com/container-storage-interface/spec
CSI_GO := $(CSI_PKG)/csi.pb.go CSI_PKG_SUB := $(shell cat $(CSI_PROTO) | sed -n -e 's/^package.\([^;]*\).v[0-9]\+;$$/\1/p'|tr '.' '/')
CSI_BUILD := $(CSI_PKG_SUB)/.build
CSI_GO := $(CSI_PKG_SUB)/csi.pb.go
CSI_A := csi.a CSI_A := csi.a
CSI_GO_TMP := $(CSI_PKG)/.build/csi.pb.go CSI_GO_TMP := $(CSI_BUILD)/$(CSI_PKG_ROOT)/csi.pb.go
# This recipe generates the go language bindings to a temp area. # This recipe generates the go language bindings to a temp area.
$(CSI_GO_TMP): HERE := $(shell pwd)
$(CSI_GO_TMP): PTYPES_PKG := github.com/golang/protobuf/ptypes
$(CSI_GO_TMP): GO_OUT := plugins=grpc $(CSI_GO_TMP): GO_OUT := plugins=grpc
$(CSI_GO_TMP): GO_OUT := $(GO_OUT),Mgoogle/protobuf/wrappers.proto=github.com/golang/protobuf/ptypes/wrappers $(CSI_GO_TMP): GO_OUT := $(GO_OUT),Mgoogle/protobuf/descriptor.proto=github.com/golang/protobuf/protoc-gen-go/descriptor
$(CSI_GO_TMP): INCLUDE = -I$(PROTOC_TMP_DIR)/include $(CSI_GO_TMP): GO_OUT := $(GO_OUT),Mgoogle/protobuf/wrappers.proto=$(PTYPES_PKG)/wrappers
$(CSI_GO_TMP): GO_OUT := $(GO_OUT):"$(HERE)/$(CSI_BUILD)"
$(CSI_GO_TMP): INCLUDE := -I$(GOPATH)/src -I$(HERE)/$(PROTOC_TMP_DIR)/include
$(CSI_GO_TMP): $(CSI_PROTO) | $(PROTOC) $(PROTOC_GEN_GO) $(CSI_GO_TMP): $(CSI_PROTO) | $(PROTOC) $(PROTOC_GEN_GO)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(PROTOC) -I "$(<D)" $(INCLUDE) --go_out=$(GO_OUT):"$(@D)" "$<" (cd "$(GOPATH)/src" && \
$(HERE)/$(PROTOC) $(INCLUDE) --go_out=$(GO_OUT) "$(CSI_PKG_ROOT)/$(<F)")
# The temp language bindings are compared to the ones that are # The temp language bindings are compared to the ones that are
# versioned. If they are different then it means the language # versioned. If they are different then it means the language
@@ -114,16 +121,16 @@ endif
# 3. Build the archive file. # 3. Build the archive file.
$(CSI_A): $(CSI_GO) $(CSI_A): $(CSI_GO)
go get -v -d ./... go get -v -d ./...
go install ./$(CSI_PKG) go install ./$(CSI_PKG_SUB)
go build -o "$@" ./$(CSI_PKG) go build -o "$@" ./$(CSI_PKG_SUB)
build: $(CSI_A) build: $(CSI_A)
clean: clean:
go clean -i ./... go clean -i ./...
rm -f "$(CSI_A)" rm -rf "$(CSI_A)" "$(CSI_GO)" "$(CSI_BUILD)"
clobber: clean clobber: clean
rm -fr "$(PROTOC)" "$(PROTOC_GEN_GO)" "$(CSI_PKG)" rm -fr "$(PROTOC)" "$(PROTOC_GEN_GO)" "$(CSI_PKG_SUB)"
.PHONY: clean clobber .PHONY: clean clobber

File diff suppressed because it is too large Load Diff

View File

@@ -11,3 +11,9 @@
*.out *.out
bin/mock bin/mock
cmd/csi-sanity/csi-sanity cmd/csi-sanity/csi-sanity
# JetBrains GoLand
.idea
# Vim
*.swp

View File

@@ -1,4 +1,7 @@
language: go language: go
sudo: required
services:
- docker
matrix: matrix:
include: include:
- go: 1.10.3 - go: 1.10.3
@@ -6,6 +9,7 @@ script:
- make test - make test
after_success: after_success:
- if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then - if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then
make container
docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" quay.io; docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" quay.io;
make push; make push;
fi fi

View File

@@ -0,0 +1,22 @@
# Contributing Guidelines
Welcome to Kubernetes. We are excited about the prospect of you joining our [community](https://github.com/kubernetes/community)! The Kubernetes community abides by the CNCF [code of conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). Here is an excerpt:
_As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities._
## Getting Started
We have full documentation on how to get started contributing here:
- [Contributor License Agreement](https://git.k8s.io/community/CLA.md) Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests
- [Kubernetes Contributor Guide](http://git.k8s.io/community/contributors/guide) - Main contributor documentation, or you can just jump directly to the [contributing section](http://git.k8s.io/community/contributors/guide#contributing)
- [Contributor Cheat Sheet](https://git.k8s.io/community/contributors/guide/contributor-cheatsheet.md) - Common resources for existing developers
## Mentorship
- [Mentoring Initiatives](https://git.k8s.io/community/mentoring) - We have a diverse set of mentorship programs available that are always looking for volunteers!
## Contact Information
- [Slack channel](https://kubernetes.slack.com/messages/sig-storage)
- [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-storage)

View File

@@ -2,18 +2,23 @@
[[projects]] [[projects]]
digest = "1:26ee2356254e58b9872ba736f66aff1c54a26f08c7d16afbf49695131a87d454"
name = "github.com/container-storage-interface/spec" name = "github.com/container-storage-interface/spec"
packages = ["lib/go/csi/v0"] packages = ["lib/go/csi"]
revision = "2178fdeea87f1150a17a63252eee28d4d8141f72" pruneopts = "UT"
version = "v0.3.0" revision = "8efcc85c45550571fba8134182013ed7dc34038a"
version = "v1.0.0-rc2"
[[projects]] [[projects]]
digest = "1:bc38c7c481812e178d85160472e231c5e1c9a7f5845d67e23ee4e706933c10d8"
name = "github.com/golang/mock" name = "github.com/golang/mock"
packages = ["gomock"] packages = ["gomock"]
pruneopts = "UT"
revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" revision = "c34cdb4725f4c3844d095133c6e40e448b86589b"
version = "v1.1.1" version = "v1.1.1"
[[projects]] [[projects]]
digest = "1:588beb9f80d2b0afddf05663b32d01c867da419458b560471d81cca0286e76b8"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
packages = [ packages = [
"proto", "proto",
@@ -22,12 +27,14 @@
"ptypes/any", "ptypes/any",
"ptypes/duration", "ptypes/duration",
"ptypes/timestamp", "ptypes/timestamp",
"ptypes/wrappers" "ptypes/wrappers",
] ]
revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" pruneopts = "UT"
version = "v1.1.0" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:72f35d3e412bc67b121e15ea4c88a3b3da8bcbc2264339e7ffa4a1865799840c"
name = "github.com/onsi/ginkgo" name = "github.com/onsi/ginkgo"
packages = [ packages = [
".", ".",
@@ -47,12 +54,14 @@
"reporters/stenographer", "reporters/stenographer",
"reporters/stenographer/support/go-colorable", "reporters/stenographer/support/go-colorable",
"reporters/stenographer/support/go-isatty", "reporters/stenographer/support/go-isatty",
"types" "types",
] ]
pruneopts = "UT"
revision = "fa5fabab2a1bfbd924faf4c067d07ae414e2aedf" revision = "fa5fabab2a1bfbd924faf4c067d07ae414e2aedf"
version = "v1.5.0" version = "v1.5.0"
[[projects]] [[projects]]
digest = "1:d0c2c4e2d0006cd28c220a549cda1de8e67abc65ed4c572421492bbf0492ceaf"
name = "github.com/onsi/gomega" name = "github.com/onsi/gomega"
packages = [ packages = [
".", ".",
@@ -66,25 +75,31 @@
"matchers/support/goraph/edge", "matchers/support/goraph/edge",
"matchers/support/goraph/node", "matchers/support/goraph/node",
"matchers/support/goraph/util", "matchers/support/goraph/util",
"types" "types",
] ]
pruneopts = "UT"
revision = "62bff4df71bdbc266561a0caee19f0594b17c240" revision = "62bff4df71bdbc266561a0caee19f0594b17c240"
version = "v1.4.0" version = "v1.4.0"
[[projects]] [[projects]]
digest = "1:9e9193aa51197513b3abcb108970d831fbcf40ef96aa845c4f03276e1fa316d2"
name = "github.com/sirupsen/logrus" name = "github.com/sirupsen/logrus"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5" version = "v1.0.5"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = ["ssh/terminal"] packages = ["ssh/terminal"]
pruneopts = "UT"
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9" revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:0bb2e6ef036484991ed446a6c698698b8901766981d4d22cc8e53fedb09709ac"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"context", "context",
@@ -96,20 +111,24 @@
"http2/hpack", "http2/hpack",
"idna", "idna",
"internal/timeseries", "internal/timeseries",
"trace" "trace",
] ]
pruneopts = "UT"
revision = "1e491301e022f8f977054da4c2d852decd59571f" revision = "1e491301e022f8f977054da4c2d852decd59571f"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:8fbfc6ea1a8a078697633be97f07dd83a83d32a96959d42195464c13c25be374"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = [ packages = [
"unix", "unix",
"windows" "windows",
] ]
pruneopts = "UT"
revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb" revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb"
[[projects]] [[projects]]
digest = "1:436b24586f8fee329e0dd65fd67c817681420cda1d7f934345c13fe78c212a73"
name = "golang.org/x/text" name = "golang.org/x/text"
packages = [ packages = [
"collate", "collate",
@@ -137,18 +156,22 @@
"unicode/bidi", "unicode/bidi",
"unicode/cldr", "unicode/cldr",
"unicode/norm", "unicode/norm",
"unicode/rangetable" "unicode/rangetable",
] ]
pruneopts = "UT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0" version = "v0.3.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:601e63e7d4577f907118bec825902505291918859d223bce015539e79f1160e3"
name = "google.golang.org/genproto" name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"] packages = ["googleapis/rpc/status"]
pruneopts = "UT"
revision = "32ee49c4dd805befd833990acba36cb75042378c" revision = "32ee49c4dd805befd833990acba36cb75042378c"
[[projects]] [[projects]]
digest = "1:7a977fdcd5abff03e94f92e7b374ef37e91c7c389581e5c4348fa98616e6c6be"
name = "google.golang.org/grpc" name = "google.golang.org/grpc"
packages = [ packages = [
".", ".",
@@ -176,20 +199,39 @@
"stats", "stats",
"status", "status",
"tap", "tap",
"transport" "transport",
] ]
pruneopts = "UT"
revision = "7a6a684ca69eb4cae85ad0a484f2e531598c047b" revision = "7a6a684ca69eb4cae85ad0a484f2e531598c047b"
version = "v1.12.2" version = "v1.12.2"
[[projects]] [[projects]]
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
name = "gopkg.in/yaml.v2" name = "gopkg.in/yaml.v2"
packages = ["."] packages = ["."]
pruneopts = "UT"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1" version = "v2.2.1"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "5dd480018adbb94025564b74bad8dd269cc516183b7b428317f6dd04b07726f4" input-imports = [
"github.com/container-storage-interface/spec/lib/go/csi",
"github.com/golang/mock/gomock",
"github.com/golang/protobuf/proto",
"github.com/golang/protobuf/ptypes",
"github.com/golang/protobuf/ptypes/wrappers",
"github.com/onsi/ginkgo",
"github.com/onsi/gomega",
"github.com/sirupsen/logrus",
"golang.org/x/net/context",
"google.golang.org/grpc",
"google.golang.org/grpc/codes",
"google.golang.org/grpc/connectivity",
"google.golang.org/grpc/reflection",
"google.golang.org/grpc/status",
"gopkg.in/yaml.v2",
]
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -27,7 +27,7 @@
[[constraint]] [[constraint]]
name = "github.com/container-storage-interface/spec" name = "github.com/container-storage-interface/spec"
version = "~0.3.0" version = "v1.0.0-rc2"
[[constraint]] [[constraint]]
name = "github.com/golang/mock" name = "github.com/golang/mock"
@@ -35,7 +35,7 @@
[[constraint]] [[constraint]]
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
version = "v1.1.0" version = "v1.2.0"
[[constraint]] [[constraint]]
name = "github.com/onsi/ginkgo" name = "github.com/onsi/ginkgo"

View File

@@ -38,7 +38,7 @@ container: $(APP)
push: container push: container
docker push $(IMAGE_NAME):$(IMAGE_VERSION) docker push $(IMAGE_NAME):$(IMAGE_VERSION)
test: test: $(APP)
files=$$(find ./ -name '*.go' | grep -v '^./vendor' ); \ files=$$(find ./ -name '*.go' | grep -v '^./vendor' ); \
if [ $$(gofmt -d $$files | wc -l) -ne 0 ]; then \ if [ $$(gofmt -d $$files | wc -l) -ne 0 ]; then \
echo "formatting errors:"; \ echo "formatting errors:"; \

View File

@@ -27,3 +27,16 @@ CSI driver.
* Master is for CSI v0.4.0. Please see the branches for other CSI releases. * 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) * Only Golang 1.9+ supported. See [gRPC issue](https://github.com/grpc/grpc-go/issues/711#issuecomment-326626790)
## Community, discussion, contribution, and support
Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/).
You can reach the maintainers of this project at:
- [Slack channel](https://kubernetes.slack.com/messages/sig-storage)
- [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-storage)
### Code of conduct
Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md).

View File

@@ -41,6 +41,7 @@ func init() {
flag.StringVar(&config.StagingPath, prefix+"stagingdir", os.TempDir()+"/csi", "Mount point for NodeStage if staging is supported") 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.StringVar(&config.SecretsFile, prefix+"secrets", "", "CSI secrets file")
flag.Int64Var(&config.TestVolumeSize, prefix+"testvolumesize", sanity.DefTestVolumeSize, "Base volume size used for provisioned volumes") flag.Int64Var(&config.TestVolumeSize, prefix+"testvolumesize", sanity.DefTestVolumeSize, "Base volume size used for provisioned volumes")
flag.StringVar(&config.TestVolumeParametersFile, prefix+"testvolumeparameters", "", "YAML file of volume parameters for provisioned volumes")
flag.Parse() flag.Parse()
} }

View File

@@ -14,20 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License. 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 //go:generate mockgen -package=driver -destination=driver.mock.go github.com/container-storage-interface/spec/lib/go/csi IdentityServer,ControllerServer,NodeServer
package driver package driver
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"fmt"
"net" "net"
"sync" "sync"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
) )
@@ -102,7 +104,7 @@ func (c *CSIDriver) Start(l net.Listener) error {
// Create a new grpc server // Create a new grpc server
c.server = grpc.NewServer( c.server = grpc.NewServer(
grpc.UnaryInterceptor(c.authInterceptor), grpc.UnaryInterceptor(c.callInterceptor),
) )
// Register Mock servers // Register Mock servers
@@ -162,22 +164,49 @@ func (c *CSIDriver) SetDefaultCreds() {
} }
} }
func (c *CSIDriver) authInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { func (c *CSIDriver) callInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
err := c.authInterceptor(req)
if err != nil {
logGRPC(info.FullMethod, req, nil, err)
return nil, err
}
rsp, err := handler(ctx, req)
logGRPC(info.FullMethod, req, rsp, err)
return rsp, err
}
func (c *CSIDriver) authInterceptor(req interface{}) error {
if c.creds != nil { if c.creds != nil {
authenticated, authErr := isAuthenticated(req, c.creds) authenticated, authErr := isAuthenticated(req, c.creds)
if !authenticated { if !authenticated {
if authErr == ErrNoCredentials { if authErr == ErrNoCredentials {
return nil, status.Error(codes.InvalidArgument, authErr.Error()) return status.Error(codes.InvalidArgument, authErr.Error())
} }
if authErr == ErrAuthFailed { if authErr == ErrAuthFailed {
return nil, status.Error(codes.Unauthenticated, authErr.Error()) return status.Error(codes.Unauthenticated, authErr.Error())
} }
} }
} }
return nil
}
h, err := handler(ctx, req) func logGRPC(method string, request, reply interface{}, err error) {
// Log JSON with the request and response for easier parsing
return h, err logMessage := struct {
Method string
Request interface{}
Response interface{}
Error string
}{
Method: method,
Request: request,
Response: reply,
}
if err != nil {
logMessage.Error = err.Error()
}
msg, _ := json.Marshal(logMessage)
fmt.Printf("gRPCCall: %s\n", msg)
} }
func isAuthenticated(req interface{}, creds *CSICreds) (bool, error) { func isAuthenticated(req interface{}, creds *CSICreds) (bool, error) {
@@ -204,35 +233,35 @@ func isAuthenticated(req interface{}, creds *CSICreds) (bool, error) {
} }
func authenticateCreateVolume(req *csi.CreateVolumeRequest, creds *CSICreds) (bool, error) { func authenticateCreateVolume(req *csi.CreateVolumeRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetControllerCreateSecrets(), creds.CreateVolumeSecret) return credsCheck(req.GetSecrets(), creds.CreateVolumeSecret)
} }
func authenticateDeleteVolume(req *csi.DeleteVolumeRequest, creds *CSICreds) (bool, error) { func authenticateDeleteVolume(req *csi.DeleteVolumeRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetControllerDeleteSecrets(), creds.DeleteVolumeSecret) return credsCheck(req.GetSecrets(), creds.DeleteVolumeSecret)
} }
func authenticateControllerPublishVolume(req *csi.ControllerPublishVolumeRequest, creds *CSICreds) (bool, error) { func authenticateControllerPublishVolume(req *csi.ControllerPublishVolumeRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetControllerPublishSecrets(), creds.ControllerPublishVolumeSecret) return credsCheck(req.GetSecrets(), creds.ControllerPublishVolumeSecret)
} }
func authenticateControllerUnpublishVolume(req *csi.ControllerUnpublishVolumeRequest, creds *CSICreds) (bool, error) { func authenticateControllerUnpublishVolume(req *csi.ControllerUnpublishVolumeRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetControllerUnpublishSecrets(), creds.ControllerUnpublishVolumeSecret) return credsCheck(req.GetSecrets(), creds.ControllerUnpublishVolumeSecret)
} }
func authenticateNodeStageVolume(req *csi.NodeStageVolumeRequest, creds *CSICreds) (bool, error) { func authenticateNodeStageVolume(req *csi.NodeStageVolumeRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetNodeStageSecrets(), creds.NodeStageVolumeSecret) return credsCheck(req.GetSecrets(), creds.NodeStageVolumeSecret)
} }
func authenticateNodePublishVolume(req *csi.NodePublishVolumeRequest, creds *CSICreds) (bool, error) { func authenticateNodePublishVolume(req *csi.NodePublishVolumeRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetNodePublishSecrets(), creds.NodePublishVolumeSecret) return credsCheck(req.GetSecrets(), creds.NodePublishVolumeSecret)
} }
func authenticateCreateSnapshot(req *csi.CreateSnapshotRequest, creds *CSICreds) (bool, error) { func authenticateCreateSnapshot(req *csi.CreateSnapshotRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetCreateSnapshotSecrets(), creds.CreateSnapshotSecret) return credsCheck(req.GetSecrets(), creds.CreateSnapshotSecret)
} }
func authenticateDeleteSnapshot(req *csi.DeleteSnapshotRequest, creds *CSICreds) (bool, error) { func authenticateDeleteSnapshot(req *csi.DeleteSnapshotRequest, creds *CSICreds) (bool, error) {
return credsCheck(req.GetDeleteSnapshotSecrets(), creds.DeleteSnapshotSecret) return credsCheck(req.GetSecrets(), creds.DeleteSnapshotSecret)
} }
func credsCheck(secrets map[string]string, secretVal string) (bool, error) { func credsCheck(secrets map[string]string, secretVal string) (bool, error) {

View File

@@ -1,12 +1,12 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/container-storage-interface/spec/lib/go/csi/v0 (interfaces: IdentityServer,ControllerServer,NodeServer) // Source: github.com/container-storage-interface/spec/lib/go/csi (interfaces: IdentityServer,ControllerServer,NodeServer)
// Package driver is a generated GoMock package. // Package driver is a generated GoMock package.
package driver package driver
import ( import (
context "context" context "context"
v0 "github.com/container-storage-interface/spec/lib/go/csi/v0" csi "github.com/container-storage-interface/spec/lib/go/csi"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
reflect "reflect" reflect "reflect"
) )
@@ -35,9 +35,9 @@ func (m *MockIdentityServer) EXPECT() *MockIdentityServerMockRecorder {
} }
// GetPluginCapabilities mocks base method // GetPluginCapabilities mocks base method
func (m *MockIdentityServer) GetPluginCapabilities(arg0 context.Context, arg1 *v0.GetPluginCapabilitiesRequest) (*v0.GetPluginCapabilitiesResponse, error) { func (m *MockIdentityServer) GetPluginCapabilities(arg0 context.Context, arg1 *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) {
ret := m.ctrl.Call(m, "GetPluginCapabilities", arg0, arg1) ret := m.ctrl.Call(m, "GetPluginCapabilities", arg0, arg1)
ret0, _ := ret[0].(*v0.GetPluginCapabilitiesResponse) ret0, _ := ret[0].(*csi.GetPluginCapabilitiesResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -48,9 +48,9 @@ func (mr *MockIdentityServerMockRecorder) GetPluginCapabilities(arg0, arg1 inter
} }
// GetPluginInfo mocks base method // GetPluginInfo mocks base method
func (m *MockIdentityServer) GetPluginInfo(arg0 context.Context, arg1 *v0.GetPluginInfoRequest) (*v0.GetPluginInfoResponse, error) { func (m *MockIdentityServer) GetPluginInfo(arg0 context.Context, arg1 *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) {
ret := m.ctrl.Call(m, "GetPluginInfo", arg0, arg1) ret := m.ctrl.Call(m, "GetPluginInfo", arg0, arg1)
ret0, _ := ret[0].(*v0.GetPluginInfoResponse) ret0, _ := ret[0].(*csi.GetPluginInfoResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -61,9 +61,9 @@ func (mr *MockIdentityServerMockRecorder) GetPluginInfo(arg0, arg1 interface{})
} }
// Probe mocks base method // Probe mocks base method
func (m *MockIdentityServer) Probe(arg0 context.Context, arg1 *v0.ProbeRequest) (*v0.ProbeResponse, error) { func (m *MockIdentityServer) Probe(arg0 context.Context, arg1 *csi.ProbeRequest) (*csi.ProbeResponse, error) {
ret := m.ctrl.Call(m, "Probe", arg0, arg1) ret := m.ctrl.Call(m, "Probe", arg0, arg1)
ret0, _ := ret[0].(*v0.ProbeResponse) ret0, _ := ret[0].(*csi.ProbeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -97,9 +97,9 @@ func (m *MockControllerServer) EXPECT() *MockControllerServerMockRecorder {
} }
// ControllerGetCapabilities mocks base method // ControllerGetCapabilities mocks base method
func (m *MockControllerServer) ControllerGetCapabilities(arg0 context.Context, arg1 *v0.ControllerGetCapabilitiesRequest) (*v0.ControllerGetCapabilitiesResponse, error) { func (m *MockControllerServer) ControllerGetCapabilities(arg0 context.Context, arg1 *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) {
ret := m.ctrl.Call(m, "ControllerGetCapabilities", arg0, arg1) ret := m.ctrl.Call(m, "ControllerGetCapabilities", arg0, arg1)
ret0, _ := ret[0].(*v0.ControllerGetCapabilitiesResponse) ret0, _ := ret[0].(*csi.ControllerGetCapabilitiesResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -110,9 +110,9 @@ func (mr *MockControllerServerMockRecorder) ControllerGetCapabilities(arg0, arg1
} }
// ControllerPublishVolume mocks base method // ControllerPublishVolume mocks base method
func (m *MockControllerServer) ControllerPublishVolume(arg0 context.Context, arg1 *v0.ControllerPublishVolumeRequest) (*v0.ControllerPublishVolumeResponse, error) { func (m *MockControllerServer) ControllerPublishVolume(arg0 context.Context, arg1 *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) {
ret := m.ctrl.Call(m, "ControllerPublishVolume", arg0, arg1) ret := m.ctrl.Call(m, "ControllerPublishVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.ControllerPublishVolumeResponse) ret0, _ := ret[0].(*csi.ControllerPublishVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -123,9 +123,9 @@ func (mr *MockControllerServerMockRecorder) ControllerPublishVolume(arg0, arg1 i
} }
// ControllerUnpublishVolume mocks base method // ControllerUnpublishVolume mocks base method
func (m *MockControllerServer) ControllerUnpublishVolume(arg0 context.Context, arg1 *v0.ControllerUnpublishVolumeRequest) (*v0.ControllerUnpublishVolumeResponse, error) { func (m *MockControllerServer) ControllerUnpublishVolume(arg0 context.Context, arg1 *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) {
ret := m.ctrl.Call(m, "ControllerUnpublishVolume", arg0, arg1) ret := m.ctrl.Call(m, "ControllerUnpublishVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.ControllerUnpublishVolumeResponse) ret0, _ := ret[0].(*csi.ControllerUnpublishVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -136,9 +136,9 @@ func (mr *MockControllerServerMockRecorder) ControllerUnpublishVolume(arg0, arg1
} }
// CreateSnapshot mocks base method // CreateSnapshot mocks base method
func (m *MockControllerServer) CreateSnapshot(arg0 context.Context, arg1 *v0.CreateSnapshotRequest) (*v0.CreateSnapshotResponse, error) { func (m *MockControllerServer) CreateSnapshot(arg0 context.Context, arg1 *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
ret := m.ctrl.Call(m, "CreateSnapshot", arg0, arg1) ret := m.ctrl.Call(m, "CreateSnapshot", arg0, arg1)
ret0, _ := ret[0].(*v0.CreateSnapshotResponse) ret0, _ := ret[0].(*csi.CreateSnapshotResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -149,9 +149,9 @@ func (mr *MockControllerServerMockRecorder) CreateSnapshot(arg0, arg1 interface{
} }
// CreateVolume mocks base method // CreateVolume mocks base method
func (m *MockControllerServer) CreateVolume(arg0 context.Context, arg1 *v0.CreateVolumeRequest) (*v0.CreateVolumeResponse, error) { func (m *MockControllerServer) CreateVolume(arg0 context.Context, arg1 *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) {
ret := m.ctrl.Call(m, "CreateVolume", arg0, arg1) ret := m.ctrl.Call(m, "CreateVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.CreateVolumeResponse) ret0, _ := ret[0].(*csi.CreateVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -162,9 +162,9 @@ func (mr *MockControllerServerMockRecorder) CreateVolume(arg0, arg1 interface{})
} }
// DeleteSnapshot mocks base method // DeleteSnapshot mocks base method
func (m *MockControllerServer) DeleteSnapshot(arg0 context.Context, arg1 *v0.DeleteSnapshotRequest) (*v0.DeleteSnapshotResponse, error) { func (m *MockControllerServer) DeleteSnapshot(arg0 context.Context, arg1 *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
ret := m.ctrl.Call(m, "DeleteSnapshot", arg0, arg1) ret := m.ctrl.Call(m, "DeleteSnapshot", arg0, arg1)
ret0, _ := ret[0].(*v0.DeleteSnapshotResponse) ret0, _ := ret[0].(*csi.DeleteSnapshotResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -175,9 +175,9 @@ func (mr *MockControllerServerMockRecorder) DeleteSnapshot(arg0, arg1 interface{
} }
// DeleteVolume mocks base method // DeleteVolume mocks base method
func (m *MockControllerServer) DeleteVolume(arg0 context.Context, arg1 *v0.DeleteVolumeRequest) (*v0.DeleteVolumeResponse, error) { func (m *MockControllerServer) DeleteVolume(arg0 context.Context, arg1 *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) {
ret := m.ctrl.Call(m, "DeleteVolume", arg0, arg1) ret := m.ctrl.Call(m, "DeleteVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.DeleteVolumeResponse) ret0, _ := ret[0].(*csi.DeleteVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -188,9 +188,9 @@ func (mr *MockControllerServerMockRecorder) DeleteVolume(arg0, arg1 interface{})
} }
// GetCapacity mocks base method // GetCapacity mocks base method
func (m *MockControllerServer) GetCapacity(arg0 context.Context, arg1 *v0.GetCapacityRequest) (*v0.GetCapacityResponse, error) { func (m *MockControllerServer) GetCapacity(arg0 context.Context, arg1 *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) {
ret := m.ctrl.Call(m, "GetCapacity", arg0, arg1) ret := m.ctrl.Call(m, "GetCapacity", arg0, arg1)
ret0, _ := ret[0].(*v0.GetCapacityResponse) ret0, _ := ret[0].(*csi.GetCapacityResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -201,9 +201,9 @@ func (mr *MockControllerServerMockRecorder) GetCapacity(arg0, arg1 interface{})
} }
// ListSnapshots mocks base method // ListSnapshots mocks base method
func (m *MockControllerServer) ListSnapshots(arg0 context.Context, arg1 *v0.ListSnapshotsRequest) (*v0.ListSnapshotsResponse, error) { func (m *MockControllerServer) ListSnapshots(arg0 context.Context, arg1 *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) {
ret := m.ctrl.Call(m, "ListSnapshots", arg0, arg1) ret := m.ctrl.Call(m, "ListSnapshots", arg0, arg1)
ret0, _ := ret[0].(*v0.ListSnapshotsResponse) ret0, _ := ret[0].(*csi.ListSnapshotsResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -214,9 +214,9 @@ func (mr *MockControllerServerMockRecorder) ListSnapshots(arg0, arg1 interface{}
} }
// ListVolumes mocks base method // ListVolumes mocks base method
func (m *MockControllerServer) ListVolumes(arg0 context.Context, arg1 *v0.ListVolumesRequest) (*v0.ListVolumesResponse, error) { func (m *MockControllerServer) ListVolumes(arg0 context.Context, arg1 *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) {
ret := m.ctrl.Call(m, "ListVolumes", arg0, arg1) ret := m.ctrl.Call(m, "ListVolumes", arg0, arg1)
ret0, _ := ret[0].(*v0.ListVolumesResponse) ret0, _ := ret[0].(*csi.ListVolumesResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -227,9 +227,9 @@ func (mr *MockControllerServerMockRecorder) ListVolumes(arg0, arg1 interface{})
} }
// ValidateVolumeCapabilities mocks base method // ValidateVolumeCapabilities mocks base method
func (m *MockControllerServer) ValidateVolumeCapabilities(arg0 context.Context, arg1 *v0.ValidateVolumeCapabilitiesRequest) (*v0.ValidateVolumeCapabilitiesResponse, error) { func (m *MockControllerServer) ValidateVolumeCapabilities(arg0 context.Context, arg1 *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) {
ret := m.ctrl.Call(m, "ValidateVolumeCapabilities", arg0, arg1) ret := m.ctrl.Call(m, "ValidateVolumeCapabilities", arg0, arg1)
ret0, _ := ret[0].(*v0.ValidateVolumeCapabilitiesResponse) ret0, _ := ret[0].(*csi.ValidateVolumeCapabilitiesResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -263,9 +263,9 @@ func (m *MockNodeServer) EXPECT() *MockNodeServerMockRecorder {
} }
// NodeGetCapabilities mocks base method // NodeGetCapabilities mocks base method
func (m *MockNodeServer) NodeGetCapabilities(arg0 context.Context, arg1 *v0.NodeGetCapabilitiesRequest) (*v0.NodeGetCapabilitiesResponse, error) { func (m *MockNodeServer) NodeGetCapabilities(arg0 context.Context, arg1 *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) {
ret := m.ctrl.Call(m, "NodeGetCapabilities", arg0, arg1) ret := m.ctrl.Call(m, "NodeGetCapabilities", arg0, arg1)
ret0, _ := ret[0].(*v0.NodeGetCapabilitiesResponse) ret0, _ := ret[0].(*csi.NodeGetCapabilitiesResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -275,23 +275,10 @@ func (mr *MockNodeServerMockRecorder) NodeGetCapabilities(arg0, arg1 interface{}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetCapabilities", reflect.TypeOf((*MockNodeServer)(nil).NodeGetCapabilities), arg0, arg1) 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 // NodeGetInfo mocks base method
func (m *MockNodeServer) NodeGetInfo(arg0 context.Context, arg1 *v0.NodeGetInfoRequest) (*v0.NodeGetInfoResponse, error) { func (m *MockNodeServer) NodeGetInfo(arg0 context.Context, arg1 *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
ret := m.ctrl.Call(m, "NodeGetInfo", arg0, arg1) ret := m.ctrl.Call(m, "NodeGetInfo", arg0, arg1)
ret0, _ := ret[0].(*v0.NodeGetInfoResponse) ret0, _ := ret[0].(*csi.NodeGetInfoResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -301,10 +288,23 @@ func (mr *MockNodeServerMockRecorder) NodeGetInfo(arg0, arg1 interface{}) *gomoc
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetInfo", reflect.TypeOf((*MockNodeServer)(nil).NodeGetInfo), arg0, arg1) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetInfo", reflect.TypeOf((*MockNodeServer)(nil).NodeGetInfo), arg0, arg1)
} }
// NodeGetVolumeStats mocks base method
func (m *MockNodeServer) NodeGetVolumeStats(arg0 context.Context, arg1 *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
ret := m.ctrl.Call(m, "NodeGetVolumeStats", arg0, arg1)
ret0, _ := ret[0].(*csi.NodeGetVolumeStatsResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// NodeGetVolumeStats indicates an expected call of NodeGetVolumeStats
func (mr *MockNodeServerMockRecorder) NodeGetVolumeStats(arg0, arg1 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetVolumeStats", reflect.TypeOf((*MockNodeServer)(nil).NodeGetVolumeStats), arg0, arg1)
}
// NodePublishVolume mocks base method // NodePublishVolume mocks base method
func (m *MockNodeServer) NodePublishVolume(arg0 context.Context, arg1 *v0.NodePublishVolumeRequest) (*v0.NodePublishVolumeResponse, error) { func (m *MockNodeServer) NodePublishVolume(arg0 context.Context, arg1 *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
ret := m.ctrl.Call(m, "NodePublishVolume", arg0, arg1) ret := m.ctrl.Call(m, "NodePublishVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.NodePublishVolumeResponse) ret0, _ := ret[0].(*csi.NodePublishVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -315,9 +315,9 @@ func (mr *MockNodeServerMockRecorder) NodePublishVolume(arg0, arg1 interface{})
} }
// NodeStageVolume mocks base method // NodeStageVolume mocks base method
func (m *MockNodeServer) NodeStageVolume(arg0 context.Context, arg1 *v0.NodeStageVolumeRequest) (*v0.NodeStageVolumeResponse, error) { func (m *MockNodeServer) NodeStageVolume(arg0 context.Context, arg1 *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
ret := m.ctrl.Call(m, "NodeStageVolume", arg0, arg1) ret := m.ctrl.Call(m, "NodeStageVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.NodeStageVolumeResponse) ret0, _ := ret[0].(*csi.NodeStageVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -328,9 +328,9 @@ func (mr *MockNodeServerMockRecorder) NodeStageVolume(arg0, arg1 interface{}) *g
} }
// NodeUnpublishVolume mocks base method // NodeUnpublishVolume mocks base method
func (m *MockNodeServer) NodeUnpublishVolume(arg0 context.Context, arg1 *v0.NodeUnpublishVolumeRequest) (*v0.NodeUnpublishVolumeResponse, error) { func (m *MockNodeServer) NodeUnpublishVolume(arg0 context.Context, arg1 *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) {
ret := m.ctrl.Call(m, "NodeUnpublishVolume", arg0, arg1) ret := m.ctrl.Call(m, "NodeUnpublishVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.NodeUnpublishVolumeResponse) ret0, _ := ret[0].(*csi.NodeUnpublishVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
@@ -341,9 +341,9 @@ func (mr *MockNodeServerMockRecorder) NodeUnpublishVolume(arg0, arg1 interface{}
} }
// NodeUnstageVolume mocks base method // NodeUnstageVolume mocks base method
func (m *MockNodeServer) NodeUnstageVolume(arg0 context.Context, arg1 *v0.NodeUnstageVolumeRequest) (*v0.NodeUnstageVolumeResponse, error) { func (m *MockNodeServer) NodeUnstageVolume(arg0 context.Context, arg1 *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
ret := m.ctrl.Call(m, "NodeUnstageVolume", arg0, arg1) ret := m.ctrl.Call(m, "NodeUnstageVolume", arg0, arg1)
ret0, _ := ret[0].(*v0.NodeUnstageVolumeResponse) ret0, _ := ret[0].(*csi.NodeUnstageVolumeResponse)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }

View File

@@ -0,0 +1,18 @@
package apitest
import (
"os"
"testing"
"github.com/kubernetes-csi/csi-test/pkg/sanity"
)
func TestMyDriver(t *testing.T) {
config := &sanity.Config{
TargetPath: os.TempDir() + "/csi",
StagingPath: os.TempDir() + "/csi",
Address: "/tmp/e2e-csi-sanity.sock",
}
sanity.Test(t, config)
}

View File

@@ -0,0 +1,42 @@
package embedded
import (
"os"
"testing"
"github.com/kubernetes-csi/csi-test/pkg/sanity"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestMyDriverGinkgo(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "CSI Sanity Test Suite")
}
// The test suite into which the sanity tests get embedded may already
// have before/after suite functions. There can only be one such
// function. Here we define empty ones because then Ginkgo
// will start complaining at runtime when invoking the embedded case
// in hack/e2e.sh if a PR adds back such functions in the sanity test
// code.
var _ = BeforeSuite(func() {})
var _ = AfterSuite(func() {})
var _ = Describe("MyCSIDriver", func() {
Context("Config A", func() {
config := &sanity.Config{
TargetPath: os.TempDir() + "/csi",
StagingPath: os.TempDir() + "/csi",
Address: "/tmp/e2e-csi-sanity.sock",
}
BeforeEach(func() {})
AfterEach(func() {})
Describe("CSI Driver Test Suite", func() {
sanity.GinkgoTest(config)
})
})
})

View File

@@ -35,7 +35,26 @@ runTestWithCreds()
fi fi
} }
go build -o bin/mock ./mock || exit 1 runTestAPI()
{
CSI_ENDPOINT=$1 ./bin/mock &
local pid=$!
GOCACHE=off go test -v ./hack/_apitest/api_test.go; ret=$?
if [ $ret -ne 0 ] ; then
exit $ret
fi
GOCACHE=off go test -v ./hack/_embedded/embedded_test.go; ret=$?
kill -9 $pid
if [ $ret -ne 0 ] ; then
exit $ret
fi
}
make
cd cmd/csi-sanity cd cmd/csi-sanity
make clean install || exit 1 make clean install || exit 1
@@ -47,4 +66,7 @@ rm -f $UDS
runTestWithCreds "${UDS}" "${UDS}" runTestWithCreds "${UDS}" "${UDS}"
rm -f $UDS rm -f $UDS
runTestAPI "${UDS}"
rm -f $UDS
exit 0 exit 0

View File

@@ -1,2 +1,22 @@
# Mock CSI Driver # Mock CSI Driver
Extremely simple mock driver used to test `csi-sanity` based on `rexray/gocsi/mock` Extremely simple mock driver used to test `csi-sanity` based on `rexray/gocsi/mock`.
It can be used for testing of Container Orchestrators that implement client side
of CSI interface.
```
Usage of mock:
-disable-attach
Disables RPC_PUBLISH_UNPUBLISH_VOLUME capability.
-name string
CSI driver name. (default "io.kubernetes.storage.mock")
```
It prints all received CSI messages to stdout encoded as json, so a test can check that
CO sent the right CSI message.
Example of such output:
```
gRPCCall: {"Method":"/csi.v0.Controller/ControllerGetCapabilities","Request":{},"Response":{"capabilities":[{"Type":{"Rpc":{"type":1}}},{"Type":{"Rpc":{"type":3}}},{"Type":{"Rpc":{"type":4}}},{"Type":{"Rpc":{"type":6}}},{"Type":{"Rpc":{"type":5}}},{"Type":{"Rpc":{"type":2}}}]},"Error":""}
gRPCCall: {"Method":"/csi.v0.Controller/ControllerPublishVolume","Request":{"volume_id":"12","node_id":"some-fake-node-id","volume_capability":{"AccessType":{"Mount":{}},"access_mode":{"mode":1}}},"Response":null,"Error":"rpc error: code = NotFound desc = Not matching Node ID some-fake-node-id to Mock Node ID io.kubernetes.storage.mock"}
```

View File

@@ -4,7 +4,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
) )
type SnapshotCache interface { type SnapshotCache interface {
@@ -12,7 +12,7 @@ type SnapshotCache interface {
Delete(i int) Delete(i int)
List(status csi.SnapshotStatus_Type) []csi.Snapshot List(ready bool) []csi.Snapshot
FindSnapshot(k, v string) (int, Snapshot) FindSnapshot(k, v string) (int, Snapshot)
} }
@@ -49,13 +49,13 @@ func (snap *snapshotCache) Delete(i int) {
snap.snapshots = snap.snapshots[:len(snap.snapshots)-1] snap.snapshots = snap.snapshots[:len(snap.snapshots)-1]
} }
func (snap *snapshotCache) List(status csi.SnapshotStatus_Type) []csi.Snapshot { func (snap *snapshotCache) List(ready bool) []csi.Snapshot {
snap.snapshotsRWL.RLock() snap.snapshotsRWL.RLock()
defer snap.snapshotsRWL.RUnlock() defer snap.snapshotsRWL.RUnlock()
snapshots := make([]csi.Snapshot, 0) snapshots := make([]csi.Snapshot, 0)
for _, v := range snap.snapshots { for _, v := range snap.snapshots {
if v.SnapshotCSI.GetStatus() != nil && v.SnapshotCSI.GetStatus().Type == status { if v.SnapshotCSI.GetReadyToUse() {
snapshots = append(snapshots, v.SnapshotCSI) snapshots = append(snapshots, v.SnapshotCSI)
} }
} }
@@ -71,7 +71,7 @@ func (snap *snapshotCache) FindSnapshot(k, v string) (int, Snapshot) {
for i, vi := range snap.snapshots { for i, vi := range snap.snapshots {
switch k { switch k {
case "id": case "id":
if strings.EqualFold(v, vi.SnapshotCSI.Id) { if strings.EqualFold(v, vi.SnapshotCSI.GetSnapshotId()) {
return i, vi return i, vi
} }
case "sourceVolumeId": case "sourceVolumeId":

View File

@@ -16,6 +16,7 @@ limitations under the License.
package main package main
import ( import (
"flag"
"fmt" "fmt"
"net" "net"
"os" "os"
@@ -28,6 +29,12 @@ import (
) )
func main() { func main() {
var config service.Config
flag.BoolVar(&config.DisableAttach, "disable-attach", false, "Disables RPC_PUBLISH_UNPUBLISH_VOLUME capability.")
flag.StringVar(&config.DriverName, "name", service.Name, "CSI driver name.")
flag.Int64Var(&config.AttachLimit, "attach-limit", 0, "number of attachable volumes on a node")
flag.Parse()
endpoint := os.Getenv("CSI_ENDPOINT") endpoint := os.Getenv("CSI_ENDPOINT")
if len(endpoint) == 0 { if len(endpoint) == 0 {
fmt.Println("CSI_ENDPOINT must be defined and must be a path") fmt.Println("CSI_ENDPOINT must be defined and must be a path")
@@ -39,7 +46,7 @@ func main() {
} }
// Create mock driver // Create mock driver
s := service.New() s := service.New(config)
servers := &driver.CSIDriverServers{ servers := &driver.CSIDriverServers{
Controller: s, Controller: s,
Identity: s, Identity: s,

View File

@@ -12,7 +12,7 @@ import (
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
) )
const ( const (
@@ -62,7 +62,7 @@ func (s *service) CreateVolume(
s.volsRWL.Lock() s.volsRWL.Lock()
defer s.volsRWL.Unlock() defer s.volsRWL.Unlock()
s.vols = append(s.vols, v) s.vols = append(s.vols, v)
MockVolumes[v.Id] = Volume{ MockVolumes[v.GetVolumeId()] = Volume{
VolumeCSI: v, VolumeCSI: v,
NodeID: "", NodeID: "",
ISStaged: false, ISStaged: false,
@@ -108,6 +108,10 @@ func (s *service) ControllerPublishVolume(
req *csi.ControllerPublishVolumeRequest) ( req *csi.ControllerPublishVolumeRequest) (
*csi.ControllerPublishVolumeResponse, error) { *csi.ControllerPublishVolumeResponse, error) {
if s.config.DisableAttach {
return nil, status.Error(codes.Unimplemented, "ControllerPublish is not supported")
}
if len(req.VolumeId) == 0 { if len(req.VolumeId) == 0 {
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
} }
@@ -136,10 +140,10 @@ func (s *service) ControllerPublishVolume(
devPathKey := path.Join(req.NodeId, "dev") devPathKey := path.Join(req.NodeId, "dev")
// Check to see if the volume is already published. // Check to see if the volume is already published.
if device := v.Attributes[devPathKey]; device != "" { if device := v.VolumeContext[devPathKey]; device != "" {
var volRo bool var volRo bool
var roVal string var roVal string
if ro, ok := v.Attributes[ReadOnlyKey]; ok { if ro, ok := v.VolumeContext[ReadOnlyKey]; ok {
roVal = ro roVal = ro
} }
@@ -155,7 +159,7 @@ func (s *service) ControllerPublishVolume(
} }
return &csi.ControllerPublishVolumeResponse{ return &csi.ControllerPublishVolumeResponse{
PublishInfo: map[string]string{ PublishContext: map[string]string{
"device": device, "device": device,
"readonly": roVal, "readonly": roVal,
}, },
@@ -171,12 +175,12 @@ func (s *service) ControllerPublishVolume(
// Publish the volume. // Publish the volume.
device := "/dev/mock" device := "/dev/mock"
v.Attributes[devPathKey] = device v.VolumeContext[devPathKey] = device
v.Attributes[ReadOnlyKey] = roVal v.VolumeContext[ReadOnlyKey] = roVal
s.vols[i] = v s.vols[i] = v
return &csi.ControllerPublishVolumeResponse{ return &csi.ControllerPublishVolumeResponse{
PublishInfo: map[string]string{ PublishContext: map[string]string{
"device": device, "device": device,
"readonly": roVal, "readonly": roVal,
}, },
@@ -188,6 +192,10 @@ func (s *service) ControllerUnpublishVolume(
req *csi.ControllerUnpublishVolumeRequest) ( req *csi.ControllerUnpublishVolumeRequest) (
*csi.ControllerUnpublishVolumeResponse, error) { *csi.ControllerUnpublishVolumeResponse, error) {
if s.config.DisableAttach {
return nil, status.Error(codes.Unimplemented, "ControllerPublish is not supported")
}
if len(req.VolumeId) == 0 { if len(req.VolumeId) == 0 {
return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty")
} }
@@ -215,13 +223,13 @@ func (s *service) ControllerUnpublishVolume(
devPathKey := path.Join(nodeID, "dev") devPathKey := path.Join(nodeID, "dev")
// Check to see if the volume is already unpublished. // Check to see if the volume is already unpublished.
if v.Attributes[devPathKey] == "" { if v.VolumeContext[devPathKey] == "" {
return &csi.ControllerUnpublishVolumeResponse{}, nil return &csi.ControllerUnpublishVolumeResponse{}, nil
} }
// Unpublish the volume. // Unpublish the volume.
delete(v.Attributes, devPathKey) delete(v.VolumeContext, devPathKey)
delete(v.Attributes, ReadOnlyKey) delete(v.VolumeContext, ReadOnlyKey)
s.vols[i] = v s.vols[i] = v
return &csi.ControllerUnpublishVolumeResponse{}, nil return &csi.ControllerUnpublishVolumeResponse{}, nil
@@ -244,7 +252,11 @@ func (s *service) ValidateVolumeCapabilities(
} }
return &csi.ValidateVolumeCapabilitiesResponse{ return &csi.ValidateVolumeCapabilitiesResponse{
Supported: true, Confirmed: &csi.ValidateVolumeCapabilitiesResponse_Confirmed{
VolumeContext: req.GetVolumeContext(),
VolumeCapabilities: req.GetVolumeCapabilities(),
Parameters: req.GetParameters(),
},
}, nil }, nil
} }
@@ -338,51 +350,56 @@ func (s *service) ControllerGetCapabilities(
req *csi.ControllerGetCapabilitiesRequest) ( req *csi.ControllerGetCapabilitiesRequest) (
*csi.ControllerGetCapabilitiesResponse, error) { *csi.ControllerGetCapabilitiesResponse, error) {
return &csi.ControllerGetCapabilitiesResponse{ caps := []*csi.ControllerServiceCapability{
Capabilities: []*csi.ControllerServiceCapability{ {
{ Type: &csi.ControllerServiceCapability_Rpc{
Type: &csi.ControllerServiceCapability_Rpc{ Rpc: &csi.ControllerServiceCapability_RPC{
Rpc: &csi.ControllerServiceCapability_RPC{ Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
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,
},
}, },
}, },
}, },
{
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,
},
},
},
}
if !s.config.DisableAttach {
caps = append(caps, &csi.ControllerServiceCapability{
Type: &csi.ControllerServiceCapability_Rpc{
Rpc: &csi.ControllerServiceCapability_RPC{
Type: csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME,
},
},
})
}
return &csi.ControllerGetCapabilitiesResponse{
Capabilities: caps,
}, nil }, nil
} }
@@ -497,7 +514,8 @@ func getAllSnapshots(s *service, req *csi.ListSnapshotsRequest) (*csi.ListSnapsh
// Copy the mock snapshots into a new slice in order to avoid // Copy the mock snapshots into a new slice in order to avoid
// locking the service's snapshot slice for the duration of the // locking the service's snapshot slice for the duration of the
// ListSnapshots RPC. // ListSnapshots RPC.
snapshots := s.snapshots.List(csi.SnapshotStatus_READY) readyToUse := true
snapshots := s.snapshots.List(readyToUse)
var ( var (
ulenSnapshots = int32(len(snapshots)) ulenSnapshots = int32(len(snapshots))

View File

@@ -3,7 +3,7 @@ package service
import ( import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/protobuf/ptypes/wrappers" "github.com/golang/protobuf/ptypes/wrappers"
) )
@@ -13,7 +13,7 @@ func (s *service) GetPluginInfo(
*csi.GetPluginInfoResponse, error) { *csi.GetPluginInfoResponse, error) {
return &csi.GetPluginInfoResponse{ return &csi.GetPluginInfoResponse{
Name: Name, Name: s.config.DriverName,
VendorVersion: VendorVersion, VendorVersion: VendorVersion,
Manifest: Manifest, Manifest: Manifest,
}, nil }, nil

View File

@@ -8,7 +8,7 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
) )
func (s *service) NodeStageVolume( func (s *service) NodeStageVolume(
@@ -16,11 +16,15 @@ func (s *service) NodeStageVolume(
req *csi.NodeStageVolumeRequest) ( req *csi.NodeStageVolumeRequest) (
*csi.NodeStageVolumeResponse, error) { *csi.NodeStageVolumeResponse, error) {
device, ok := req.PublishInfo["device"] device, ok := req.PublishContext["device"]
if !ok { if !ok {
return nil, status.Error( if s.config.DisableAttach {
codes.InvalidArgument, device = "mock device"
"stage volume info 'device' key required") } else {
return nil, status.Error(
codes.InvalidArgument,
"stage volume info 'device' key required")
}
} }
if len(req.GetVolumeId()) == 0 { if len(req.GetVolumeId()) == 0 {
@@ -48,14 +52,14 @@ func (s *service) NodeStageVolume(
nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath) nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath)
// Check to see if the volume has already been staged. // Check to see if the volume has already been staged.
if v.Attributes[nodeStgPathKey] != "" { if v.VolumeContext[nodeStgPathKey] != "" {
// TODO: Check for the capabilities to be equal. Return "ALREADY_EXISTS" // TODO: Check for the capabilities to be equal. Return "ALREADY_EXISTS"
// if the capabilities don't match. // if the capabilities don't match.
return &csi.NodeStageVolumeResponse{}, nil return &csi.NodeStageVolumeResponse{}, nil
} }
// Stage the volume. // Stage the volume.
v.Attributes[nodeStgPathKey] = device v.VolumeContext[nodeStgPathKey] = device
s.vols[i] = v s.vols[i] = v
return &csi.NodeStageVolumeResponse{}, nil return &csi.NodeStageVolumeResponse{}, nil
@@ -87,12 +91,12 @@ func (s *service) NodeUnstageVolume(
nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath) nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath)
// Check to see if the volume has already been unstaged. // Check to see if the volume has already been unstaged.
if v.Attributes[nodeStgPathKey] == "" { if v.VolumeContext[nodeStgPathKey] == "" {
return &csi.NodeUnstageVolumeResponse{}, nil return &csi.NodeUnstageVolumeResponse{}, nil
} }
// Unpublish the volume. // Unpublish the volume.
delete(v.Attributes, nodeStgPathKey) delete(v.VolumeContext, nodeStgPathKey)
s.vols[i] = v s.vols[i] = v
return &csi.NodeUnstageVolumeResponse{}, nil return &csi.NodeUnstageVolumeResponse{}, nil
@@ -103,11 +107,15 @@ func (s *service) NodePublishVolume(
req *csi.NodePublishVolumeRequest) ( req *csi.NodePublishVolumeRequest) (
*csi.NodePublishVolumeResponse, error) { *csi.NodePublishVolumeResponse, error) {
device, ok := req.PublishInfo["device"] device, ok := req.PublishContext["device"]
if !ok { if !ok {
return nil, status.Error( if s.config.DisableAttach {
codes.InvalidArgument, device = "mock device"
"publish volume info 'device' key required") } else {
return nil, status.Error(
codes.InvalidArgument,
"stage volume info 'device' key required")
}
} }
if len(req.GetVolumeId()) == 0 { if len(req.GetVolumeId()) == 0 {
@@ -135,7 +143,7 @@ func (s *service) NodePublishVolume(
nodeMntPathKey := path.Join(s.nodeID, req.TargetPath) nodeMntPathKey := path.Join(s.nodeID, req.TargetPath)
// Check to see if the volume has already been published. // Check to see if the volume has already been published.
if v.Attributes[nodeMntPathKey] != "" { if v.VolumeContext[nodeMntPathKey] != "" {
// Requests marked Readonly fail due to volumes published by // Requests marked Readonly fail due to volumes published by
// the Mock driver supporting only RW mode. // the Mock driver supporting only RW mode.
@@ -148,9 +156,9 @@ func (s *service) NodePublishVolume(
// Publish the volume. // Publish the volume.
if req.GetStagingTargetPath() != "" { if req.GetStagingTargetPath() != "" {
v.Attributes[nodeMntPathKey] = req.GetStagingTargetPath() v.VolumeContext[nodeMntPathKey] = req.GetStagingTargetPath()
} else { } else {
v.Attributes[nodeMntPathKey] = device v.VolumeContext[nodeMntPathKey] = device
} }
s.vols[i] = v s.vols[i] = v
@@ -182,27 +190,17 @@ func (s *service) NodeUnpublishVolume(
nodeMntPathKey := path.Join(s.nodeID, req.TargetPath) nodeMntPathKey := path.Join(s.nodeID, req.TargetPath)
// Check to see if the volume has already been unpublished. // Check to see if the volume has already been unpublished.
if v.Attributes[nodeMntPathKey] == "" { if v.VolumeContext[nodeMntPathKey] == "" {
return &csi.NodeUnpublishVolumeResponse{}, nil return &csi.NodeUnpublishVolumeResponse{}, nil
} }
// Unpublish the volume. // Unpublish the volume.
delete(v.Attributes, nodeMntPathKey) delete(v.VolumeContext, nodeMntPathKey)
s.vols[i] = v s.vols[i] = v
return &csi.NodeUnpublishVolumeResponse{}, nil 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( func (s *service) NodeGetCapabilities(
ctx context.Context, ctx context.Context,
req *csi.NodeGetCapabilitiesRequest) ( req *csi.NodeGetCapabilitiesRequest) (
@@ -230,7 +228,17 @@ func (s *service) NodeGetCapabilities(
func (s *service) NodeGetInfo(ctx context.Context, func (s *service) NodeGetInfo(ctx context.Context,
req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
return &csi.NodeGetInfoResponse{ csiNodeResponse := &csi.NodeGetInfoResponse{
NodeId: s.nodeID, NodeId: s.nodeID,
}, nil }
if s.config.AttachLimit > 0 {
csiNodeResponse.MaxVolumesPerNode = s.config.AttachLimit
}
return csiNodeResponse, nil
}
func (s *service) NodeGetVolumeStats(ctx context.Context,
req *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
return &csi.NodeGetVolumeStatsResponse{}, nil
} }

View File

@@ -5,11 +5,12 @@ import (
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
"github.com/kubernetes-csi/csi-test/mock/cache" "github.com/kubernetes-csi/csi-test/mock/cache"
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/golang/protobuf/ptypes"
) )
const ( const (
@@ -25,6 +26,12 @@ var Manifest = map[string]string{
"url": "https://github.com/kubernetes-csi/csi-test/mock", "url": "https://github.com/kubernetes-csi/csi-test/mock",
} }
type Config struct {
DisableAttach bool
DriverName string
AttachLimit int64
}
// Service is the CSI Mock service provider. // Service is the CSI Mock service provider.
type Service interface { type Service interface {
csi.ControllerServer csi.ControllerServer
@@ -40,6 +47,7 @@ type service struct {
volsNID uint64 volsNID uint64
snapshots cache.SnapshotCache snapshots cache.SnapshotCache
snapshotsNID uint64 snapshotsNID uint64
config Config
} }
type Volume struct { type Volume struct {
@@ -55,8 +63,11 @@ type Volume struct {
var MockVolumes map[string]Volume var MockVolumes map[string]Volume
// New returns a new Service. // New returns a new Service.
func New() Service { func New(config Config) Service {
s := &service{nodeID: Name} s := &service{
nodeID: config.DriverName,
config: config,
}
s.snapshots = cache.NewSnapshotCache() s.snapshots = cache.NewSnapshotCache()
s.vols = []csi.Volume{ s.vols = []csi.Volume{
s.newVolume("Mock Volume 1", gib100), s.newVolume("Mock Volume 1", gib100),
@@ -83,8 +94,8 @@ const (
func (s *service) newVolume(name string, capcity int64) csi.Volume { func (s *service) newVolume(name string, capcity int64) csi.Volume {
return csi.Volume{ return csi.Volume{
Id: fmt.Sprintf("%d", atomic.AddUint64(&s.volsNID, 1)), VolumeId: fmt.Sprintf("%d", atomic.AddUint64(&s.volsNID, 1)),
Attributes: map[string]string{"name": name}, VolumeContext: map[string]string{"name": name},
CapacityBytes: capcity, CapacityBytes: capcity,
} }
} }
@@ -101,11 +112,11 @@ func (s *service) findVolNoLock(k, v string) (volIdx int, volInfo csi.Volume) {
for i, vi := range s.vols { for i, vi := range s.vols {
switch k { switch k {
case "id": case "id":
if strings.EqualFold(v, vi.Id) { if strings.EqualFold(v, vi.GetVolumeId()) {
return i, vi return i, vi
} }
case "name": case "name":
if n, ok := vi.Attributes["name"]; ok && strings.EqualFold(v, n) { if n, ok := vi.VolumeContext["name"]; ok && strings.EqualFold(v, n) {
return i, vi return i, vi
} }
} }
@@ -121,17 +132,16 @@ func (s *service) findVolByName(
} }
func (s *service) newSnapshot(name, sourceVolumeId string, parameters map[string]string) cache.Snapshot { func (s *service) newSnapshot(name, sourceVolumeId string, parameters map[string]string) cache.Snapshot {
ptime := ptypes.TimestampNow()
return cache.Snapshot{ return cache.Snapshot{
Name: name, Name: name,
Parameters: parameters, Parameters: parameters,
SnapshotCSI: csi.Snapshot{ SnapshotCSI: csi.Snapshot{
Id: fmt.Sprintf("%d", atomic.AddUint64(&s.snapshotsNID, 1)), SnapshotId: fmt.Sprintf("%d", atomic.AddUint64(&s.snapshotsNID, 1)),
CreatedAt: time.Now().UnixNano(), CreationTime: ptime,
SourceVolumeId: sourceVolumeId, SourceVolumeId: sourceVolumeId,
Status: &csi.SnapshotStatus{ ReadyToUse: true,
Type: csi.SnapshotStatus_READY,
Details: "snapshot ready",
},
}, },
} }
} }

View File

@@ -39,13 +39,13 @@ var _ = Describe("MyCSIDriver", func () {
Context("Config A", func () { Context("Config A", func () {
var config &sanity.Config var config &sanity.Config
BeforeEach() { BeforeEach(func() {
... setup driver and config... //... setup driver and config...
} })
AfterEach() { AfterEach(func() {
...tear down driver... //...tear down driver...
} })
Describe("CSI sanity", func() { Describe("CSI sanity", func() {
sanity.GinkgoTest(config) sanity.GinkgoTest(config)
@@ -53,7 +53,7 @@ var _ = Describe("MyCSIDriver", func () {
}) })
Context("Config B", func () { Context("Config B", func () {
... // other configs
}) })
}) })
``` ```

View File

@@ -20,7 +20,7 @@ import (
"context" "context"
"log" "log"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
) )
@@ -61,8 +61,8 @@ func (cl *Cleanup) RegisterVolume(name string, info VolumeInfo) {
// MaybeRegisterVolume adds or updates an entry for the volume with // MaybeRegisterVolume adds or updates an entry for the volume with
// the given name if CreateVolume was successful. // the given name if CreateVolume was successful.
func (cl *Cleanup) MaybeRegisterVolume(name string, vol *csi.CreateVolumeResponse, err error) { func (cl *Cleanup) MaybeRegisterVolume(name string, vol *csi.CreateVolumeResponse, err error) {
if err == nil && vol.GetVolume().GetId() != "" { if err == nil && vol.GetVolume().GetVolumeId() != "" {
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
} }
} }
@@ -112,7 +112,7 @@ func (cl *Cleanup) DeleteVolumes() {
&csi.ControllerUnpublishVolumeRequest{ &csi.ControllerUnpublishVolumeRequest{
VolumeId: info.VolumeID, VolumeId: info.VolumeID,
NodeId: info.NodeID, NodeId: info.NodeID,
ControllerUnpublishSecrets: cl.Context.Secrets.ControllerUnpublishVolumeSecret, Secrets: cl.Context.Secrets.ControllerUnpublishVolumeSecret,
}, },
); err != nil { ); err != nil {
logger.Printf("warning: ControllerUnpublishVolume: %s", err) logger.Printf("warning: ControllerUnpublishVolume: %s", err)
@@ -122,8 +122,8 @@ func (cl *Cleanup) DeleteVolumes() {
if _, err := cl.ControllerClient.DeleteVolume( if _, err := cl.ControllerClient.DeleteVolume(
ctx, ctx,
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: info.VolumeID, VolumeId: info.VolumeID,
ControllerDeleteSecrets: cl.Context.Secrets.DeleteVolumeSecret, Secrets: cl.Context.Secrets.DeleteVolumeSecret,
}, },
); err != nil { ); err != nil {
logger.Printf("error: DeleteVolume: %s", err) logger.Printf("error: DeleteVolume: %s", err)

View File

@@ -23,11 +23,12 @@ import (
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
"strconv"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"strconv"
) )
const ( const (
@@ -35,6 +36,8 @@ const (
// provisioned volumes. 10GB by default, can be overridden by // provisioned volumes. 10GB by default, can be overridden by
// setting Config.TestVolumeSize. // setting Config.TestVolumeSize.
DefTestVolumeSize int64 = 10 * 1024 * 1024 * 1024 DefTestVolumeSize int64 = 10 * 1024 * 1024 * 1024
MaxNameLength int = 128
) )
func TestVolumeSize(sc *SanityContext) int64 { func TestVolumeSize(sc *SanityContext) int64 {
@@ -46,14 +49,14 @@ func TestVolumeSize(sc *SanityContext) int64 {
func verifyVolumeInfo(v *csi.Volume) { func verifyVolumeInfo(v *csi.Volume) {
Expect(v).NotTo(BeNil()) Expect(v).NotTo(BeNil())
Expect(v.GetId()).NotTo(BeEmpty()) Expect(v.GetVolumeId()).NotTo(BeEmpty())
} }
func verifySnapshotInfo(snapshot *csi.Snapshot) { func verifySnapshotInfo(snapshot *csi.Snapshot) {
Expect(snapshot).NotTo(BeNil()) Expect(snapshot).NotTo(BeNil())
Expect(snapshot.GetId()).NotTo(BeEmpty()) Expect(snapshot.GetSnapshotId()).NotTo(BeEmpty())
Expect(snapshot.GetSourceVolumeId()).NotTo(BeEmpty()) Expect(snapshot.GetSourceVolumeId()).NotTo(BeEmpty())
Expect(snapshot.GetCreatedAt()).NotTo(BeZero()) Expect(snapshot.GetCreationTime()).NotTo(BeZero())
} }
func isControllerCapabilitySupported( func isControllerCapabilitySupported(
@@ -182,7 +185,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
vol, err := c.CreateVolume( vol, err := c.CreateVolume(
context.Background(), context.Background(),
&csi.CreateVolumeRequest{ &csi.CreateVolumeRequest{
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
cl.MaybeRegisterVolume("", vol, err) cl.MaybeRegisterVolume("", vol, err)
@@ -198,8 +202,9 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
vol, err := c.CreateVolume( vol, err := c.CreateVolume(
context.Background(), context.Background(),
&csi.CreateVolumeRequest{ &csi.CreateVolumeRequest{
Name: name, Name: name,
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
cl.MaybeRegisterVolume(name, vol, err) cl.MaybeRegisterVolume(name, vol, err)
@@ -229,22 +234,23 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -273,7 +279,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
CapacityRange: &csi.CapacityRange{ CapacityRange: &csi.CapacityRange{
RequiredBytes: TestVolumeSize(sc), RequiredBytes: TestVolumeSize(sc),
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
if serverError, ok := status.FromError(err); ok && if serverError, ok := status.FromError(err); ok &&
@@ -283,8 +290,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", TestVolumeSize(sc))) Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", TestVolumeSize(sc)))
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
@@ -292,14 +299,14 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name) cl.UnregisterVolume(name)
}) })
It("should not fail when requesting to create a volume with already exisiting name and same capacity.", func() { It("should not fail when requesting to create a volume with already existing name and same capacity.", func() {
By("creating a volume") By("creating a volume")
name := uniqueString("sanity-controller-create-twice") name := uniqueString("sanity-controller-create-twice")
@@ -322,14 +329,15 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
CapacityRange: &csi.CapacityRange{ CapacityRange: &csi.CapacityRange{
RequiredBytes: size, RequiredBytes: size,
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol1).NotTo(BeNil()) Expect(vol1).NotTo(BeNil())
Expect(vol1.GetVolume()).NotTo(BeNil()) Expect(vol1.GetVolume()).NotTo(BeNil())
Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol1.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetVolumeId()})
Expect(vol1.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size)) Expect(vol1.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size))
vol2, err := c.CreateVolume( vol2, err := c.CreateVolume(
@@ -349,29 +357,30 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
CapacityRange: &csi.CapacityRange{ CapacityRange: &csi.CapacityRange{
RequiredBytes: size, RequiredBytes: size,
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol2).NotTo(BeNil()) Expect(vol2).NotTo(BeNil())
Expect(vol2.GetVolume()).NotTo(BeNil()) Expect(vol2.GetVolume()).NotTo(BeNil())
Expect(vol2.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol2.GetVolume().GetVolumeId()).NotTo(BeEmpty())
Expect(vol2.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size)) Expect(vol2.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size))
Expect(vol1.GetVolume().GetId()).To(Equal(vol2.GetVolume().GetId())) Expect(vol1.GetVolume().GetVolumeId()).To(Equal(vol2.GetVolume().GetVolumeId()))
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol1.GetVolume().GetId(), VolumeId: vol1.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name) cl.UnregisterVolume(name)
}) })
It("should fail when requesting to create a volume with already exisiting name and different capacity.", func() { It("should fail when requesting to create a volume with already existing name and different capacity.", func() {
By("creating a volume") By("creating a volume")
name := uniqueString("sanity-controller-create-twice-different") name := uniqueString("sanity-controller-create-twice-different")
@@ -395,14 +404,15 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
RequiredBytes: size1, RequiredBytes: size1,
LimitBytes: size1, LimitBytes: size1,
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(vol1).NotTo(BeNil()) Expect(vol1).NotTo(BeNil())
Expect(vol1.GetVolume()).NotTo(BeNil()) Expect(vol1.GetVolume()).NotTo(BeNil())
Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol1.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetVolumeId()})
size2 := 2 * TestVolumeSize(sc) size2 := 2 * TestVolumeSize(sc)
_, err = c.CreateVolume( _, err = c.CreateVolume(
@@ -423,7 +433,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
RequiredBytes: size2, RequiredBytes: size2,
LimitBytes: size2, LimitBytes: size2,
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -436,8 +447,59 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol1.GetVolume().GetId(), VolumeId: vol1.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
},
)
Expect(err).NotTo(HaveOccurred())
cl.UnregisterVolume(name)
})
It("should not fail when creating volume with maximum-length name", func() {
nameBytes := make([]byte, MaxNameLength)
for i := 0; i < MaxNameLength; i++ {
nameBytes[i] = 'a'
}
name := string(nameBytes)
By("creating a volume")
size := TestVolumeSize(sc)
vol, err := c.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,
},
},
},
CapacityRange: &csi.CapacityRange{
RequiredBytes: size,
},
Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
},
)
Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size))
By("cleaning up deleting the volume")
_, err = c.DeleteVolume(
context.Background(),
&csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetVolumeId(),
Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -457,7 +519,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err := c.DeleteVolume( _, err := c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -472,8 +534,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err := c.DeleteVolume( _, err := c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: "reallyfakevolumeid", VolumeId: "reallyfakevolumeid",
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -499,14 +561,15 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
// Delete Volume // Delete Volume
By("deleting a volume") By("deleting a volume")
@@ -514,8 +577,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -570,21 +633,22 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
// ValidateVolumeCapabilities // ValidateVolumeCapabilities
By("validating volume capabilities") By("validating volume capabilities")
valivolcap, err := c.ValidateVolumeCapabilities( valivolcap, err := c.ValidateVolumeCapabilities(
context.Background(), context.Background(),
&csi.ValidateVolumeCapabilitiesRequest{ &csi.ValidateVolumeCapabilitiesRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
VolumeCapabilities: []*csi.VolumeCapability{ VolumeCapabilities: []*csi.VolumeCapability{
{ {
AccessType: &csi.VolumeCapability_Mount{ AccessType: &csi.VolumeCapability_Mount{
@@ -598,15 +662,20 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(valivolcap).NotTo(BeNil()) Expect(valivolcap).NotTo(BeNil())
Expect(valivolcap.GetSupported()).To(BeTrue())
// If confirmation is provided then it is REQUIRED to provide
// the volume capabilities
if valivolcap.GetConfirmed() != nil {
Expect(valivolcap.GetConfirmed().GetVolumeCapabilities()).NotTo(BeEmpty())
}
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -651,7 +720,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err := c.ControllerPublishVolume( _, err := c.ControllerPublishVolume(
context.Background(), context.Background(),
&csi.ControllerPublishVolumeRequest{ &csi.ControllerPublishVolumeRequest{
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -666,8 +735,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err := c.ControllerPublishVolume( _, err := c.ControllerPublishVolume(
context.Background(), context.Background(),
&csi.ControllerPublishVolumeRequest{ &csi.ControllerPublishVolumeRequest{
VolumeId: "id", VolumeId: "id",
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -684,7 +753,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
&csi.ControllerPublishVolumeRequest{ &csi.ControllerPublishVolumeRequest{
VolumeId: "id", VolumeId: "id",
NodeId: "fakenode", NodeId: "fakenode",
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -714,19 +783,20 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
By("getting a node id") By("getting a node id")
nid, err := n.NodeGetId( nid, err := n.NodeGetInfo(
context.Background(), context.Background(),
&csi.NodeGetIdRequest{}) &csi.NodeGetInfoRequest{})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(nid).NotTo(BeNil()) Expect(nid).NotTo(BeNil())
Expect(nid.GetNodeId()).NotTo(BeEmpty()) Expect(nid.GetNodeId()).NotTo(BeEmpty())
@@ -737,7 +807,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
conpubvol, err := c.ControllerPublishVolume( conpubvol, err := c.ControllerPublishVolume(
context.Background(), context.Background(),
&csi.ControllerPublishVolumeRequest{ &csi.ControllerPublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
VolumeCapability: &csi.VolumeCapability{ VolumeCapability: &csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{ AccessType: &csi.VolumeCapability_Mount{
@@ -747,12 +817,12 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
Readonly: false, Readonly: false,
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId(), NodeID: nid.GetNodeId()})
Expect(conpubvol).NotTo(BeNil()) Expect(conpubvol).NotTo(BeNil())
By("cleaning up unpublishing the volume") By("cleaning up unpublishing the volume")
@@ -760,10 +830,10 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
conunpubvol, err := c.ControllerUnpublishVolume( conunpubvol, err := c.ControllerUnpublishVolume(
context.Background(), context.Background(),
&csi.ControllerUnpublishVolumeRequest{ &csi.ControllerUnpublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
// NodeID is optional in ControllerUnpublishVolume // NodeID is optional in ControllerUnpublishVolume
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -774,8 +844,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -799,8 +869,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
Readonly: false, Readonly: false,
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -831,14 +901,15 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
// ControllerPublishVolume // ControllerPublishVolume
By("calling controllerpublish on that volume") By("calling controllerpublish on that volume")
@@ -846,7 +917,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
conpubvol, err := c.ControllerPublishVolume( conpubvol, err := c.ControllerPublishVolume(
context.Background(), context.Background(),
&csi.ControllerPublishVolumeRequest{ &csi.ControllerPublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
NodeId: "some-fake-node-id", NodeId: "some-fake-node-id",
VolumeCapability: &csi.VolumeCapability{ VolumeCapability: &csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{ AccessType: &csi.VolumeCapability_Mount{
@@ -856,8 +927,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
Readonly: false, Readonly: false,
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -872,8 +943,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -900,19 +971,20 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
By("getting a node id") By("getting a node id")
nid, err := n.NodeGetId( nid, err := n.NodeGetInfo(
context.Background(), context.Background(),
&csi.NodeGetIdRequest{}) &csi.NodeGetInfoRequest{})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(nid).NotTo(BeNil()) Expect(nid).NotTo(BeNil())
Expect(nid.GetNodeId()).NotTo(BeEmpty()) Expect(nid.GetNodeId()).NotTo(BeEmpty())
@@ -921,7 +993,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
By("calling controllerpublish on that volume") By("calling controllerpublish on that volume")
pubReq := &csi.ControllerPublishVolumeRequest{ pubReq := &csi.ControllerPublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
VolumeCapability: &csi.VolumeCapability{ VolumeCapability: &csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{ AccessType: &csi.VolumeCapability_Mount{
@@ -931,8 +1003,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
Readonly: false, Readonly: false,
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
} }
conpubvol, err := c.ControllerPublishVolume(context.Background(), pubReq) conpubvol, err := c.ControllerPublishVolume(context.Background(), pubReq)
@@ -955,10 +1027,10 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
conunpubvol, err := c.ControllerUnpublishVolume( conunpubvol, err := c.ControllerUnpublishVolume(
context.Background(), context.Background(),
&csi.ControllerUnpublishVolumeRequest{ &csi.ControllerUnpublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
// NodeID is optional in ControllerUnpublishVolume // NodeID is optional in ControllerUnpublishVolume
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
}, },
) )
@@ -970,8 +1042,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -991,7 +1063,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err := c.ControllerUnpublishVolume( _, err := c.ControllerUnpublishVolume(
context.Background(), context.Background(),
&csi.ControllerUnpublishVolumeRequest{ &csi.ControllerUnpublishVolumeRequest{
ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -1021,19 +1093,20 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
Parameters: sc.Config.TestVolumeParameters,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
By("getting a node id") By("getting a node id")
nid, err := n.NodeGetId( nid, err := n.NodeGetInfo(
context.Background(), context.Background(),
&csi.NodeGetIdRequest{}) &csi.NodeGetInfoRequest{})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(nid).NotTo(BeNil()) Expect(nid).NotTo(BeNil())
Expect(nid.GetNodeId()).NotTo(BeEmpty()) Expect(nid.GetNodeId()).NotTo(BeEmpty())
@@ -1044,7 +1117,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
conpubvol, err := c.ControllerPublishVolume( conpubvol, err := c.ControllerPublishVolume(
context.Background(), context.Background(),
&csi.ControllerPublishVolumeRequest{ &csi.ControllerPublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
VolumeCapability: &csi.VolumeCapability{ VolumeCapability: &csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{ AccessType: &csi.VolumeCapability_Mount{
@@ -1054,12 +1127,12 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
Readonly: false, Readonly: false,
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId(), NodeID: nid.GetNodeId()})
Expect(conpubvol).NotTo(BeNil()) Expect(conpubvol).NotTo(BeNil())
// ControllerUnpublishVolume // ControllerUnpublishVolume
@@ -1068,10 +1141,10 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
conunpubvol, err := c.ControllerUnpublishVolume( conunpubvol, err := c.ControllerUnpublishVolume(
context.Background(), context.Background(),
&csi.ControllerUnpublishVolumeRequest{ &csi.ControllerUnpublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
// NodeID is optional in ControllerUnpublishVolume // NodeID is optional in ControllerUnpublishVolume
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -1082,8 +1155,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) {
_, err = c.DeleteVolume( _, err = c.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -1125,28 +1198,28 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("creating a snapshot") By("creating a snapshot")
snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-1", volume.GetVolume().GetId(), nil) snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-1", volume.GetVolume().GetVolumeId(), nil)
snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq) snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
snapshots, err := c.ListSnapshots( snapshots, err := c.ListSnapshots(
context.Background(), context.Background(),
&csi.ListSnapshotsRequest{SnapshotId: snapshot.GetSnapshot().GetId()}) &csi.ListSnapshotsRequest{SnapshotId: snapshot.GetSnapshot().GetSnapshotId()})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(snapshots).NotTo(BeNil()) Expect(snapshots).NotTo(BeNil())
Expect(len(snapshots.GetEntries())).To(BeNumerically("==", 1)) Expect(len(snapshots.GetEntries())).To(BeNumerically("==", 1))
verifySnapshotInfo(snapshots.GetEntries()[0].GetSnapshot()) verifySnapshotInfo(snapshots.GetEntries()[0].GetSnapshot())
Expect(snapshots.GetEntries()[0].GetSnapshot().GetId()).To(Equal(snapshot.GetSnapshot().GetId())) Expect(snapshots.GetEntries()[0].GetSnapshot().GetSnapshotId()).To(Equal(snapshot.GetSnapshot().GetSnapshotId()))
By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId())
_, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the snapshot") By("cleaning up deleting the snapshot")
delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq) _, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred())
}) })
It("should return empty when the specify snapshot id is not exist", func() { It("should return empty when the specify snapshot id is not exist", func() {
@@ -1167,7 +1240,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("creating a snapshot") By("creating a snapshot")
snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-2", volume.GetVolume().GetId(), nil) snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-2", volume.GetVolume().GetVolumeId(), nil)
snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq) snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -1182,12 +1255,12 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
} }
By("cleaning up deleting the snapshot") By("cleaning up deleting the snapshot")
delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq) _, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq) _, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@@ -1202,46 +1275,6 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
Expect(snapshots.GetEntries()).To(BeEmpty()) Expect(snapshots.GetEntries()).To(BeEmpty())
}) })
It("should fail when an invalid starting_token is passed", func() {
vols, err := c.ListSnapshots(
context.Background(),
&csi.ListSnapshotsRequest{
StartingToken: "invalid-token",
},
)
Expect(err).To(HaveOccurred())
Expect(vols).To(BeNil())
serverError, ok := status.FromError(err)
Expect(ok).To(BeTrue())
Expect(serverError.Code()).To(Equal(codes.Aborted))
})
It("should fail when the starting_token is greater than total number of snapshots", func() {
// Get total number of snapshots.
snapshots, err := c.ListSnapshots(
context.Background(),
&csi.ListSnapshotsRequest{})
Expect(err).NotTo(HaveOccurred())
Expect(snapshots).NotTo(BeNil())
totalSnapshots := len(snapshots.GetEntries())
// Send starting_token that is greater than the total number of snapshots.
snapshots, err = c.ListSnapshots(
context.Background(),
&csi.ListSnapshotsRequest{
StartingToken: strconv.Itoa(totalSnapshots + 5),
},
)
Expect(err).To(HaveOccurred())
Expect(snapshots).To(BeNil())
serverError, ok := status.FromError(err)
Expect(ok).To(BeTrue())
Expect(serverError.Code()).To(Equal(codes.Aborted))
})
It("check the presence of new snapshots in the snapshot list", func() { It("check the presence of new snapshots in the snapshot list", func() {
// List Snapshots before creating new snapshots. // List Snapshots before creating new snapshots.
snapshots, err := c.ListSnapshots( snapshots, err := c.ListSnapshots(
@@ -1258,7 +1291,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("creating a snapshot") By("creating a snapshot")
snapReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-3", volume.GetVolume().GetId(), nil) snapReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-3", volume.GetVolume().GetVolumeId(), nil)
snapshot, err := c.CreateSnapshot(context.Background(), snapReq) snapshot, err := c.CreateSnapshot(context.Background(), snapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(snapshot).NotTo(BeNil()) Expect(snapshot).NotTo(BeNil())
@@ -1272,12 +1305,12 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
Expect(len(snapshots.GetEntries())).To(Equal(totalSnapshots + 1)) Expect(len(snapshots.GetEntries())).To(Equal(totalSnapshots + 1))
By("cleaning up deleting the snapshot") By("cleaning up deleting the snapshot")
delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq) _, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq) _, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -1326,7 +1359,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
Expect(volume).NotTo(BeNil()) Expect(volume).NotTo(BeNil())
createVols = append(createVols, volume.GetVolume()) createVols = append(createVols, volume.GetVolume())
snapReq := MakeCreateSnapshotReq(sc, "snapshot"+strconv.Itoa(i), volume.GetVolume().GetId(), nil) snapReq := MakeCreateSnapshotReq(sc, "snapshot"+strconv.Itoa(i), volume.GetVolume().GetVolumeId(), nil)
snapshot, err := c.CreateSnapshot(context.Background(), snapReq) snapshot, err := c.CreateSnapshot(context.Background(), snapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(snapshot).NotTo(BeNil()) Expect(snapshot).NotTo(BeNil())
@@ -1349,7 +1382,6 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
nextToken := snapshots.GetNextToken() nextToken := snapshots.GetNextToken()
Expect(nextToken).To(Equal(strconv.Itoa(maxEntries)))
Expect(len(snapshots.GetEntries())).To(Equal(maxEntries)) Expect(len(snapshots.GetEntries())).To(Equal(maxEntries))
// Request list snapshots with starting_token and no max entries. // Request list snapshots with starting_token and no max entries.
@@ -1369,7 +1401,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
By("cleaning up deleting the snapshots") By("cleaning up deleting the snapshots")
for _, snap := range createSnapshots { for _, snap := range createSnapshots {
delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetId()) delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq) _, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
@@ -1377,7 +1409,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte
By("cleaning up deleting the volumes") By("cleaning up deleting the volumes")
for _, vol := range createVols { for _, vol := range createVols {
delVolReq := MakeDeleteVolumeReq(sc, vol.GetId()) delVolReq := MakeDeleteVolumeReq(sc, vol.GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq) _, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }
@@ -1404,7 +1436,7 @@ var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *SanityCont
req := &csi.DeleteSnapshotRequest{} req := &csi.DeleteSnapshotRequest{}
if sc.Secrets != nil { if sc.Secrets != nil {
req.DeleteSnapshotSecrets = sc.Secrets.DeleteSnapshotSecret req.Secrets = sc.Secrets.DeleteSnapshotSecret
} }
_, err := c.DeleteSnapshot(context.Background(), req) _, err := c.DeleteSnapshot(context.Background(), req)
@@ -1431,19 +1463,19 @@ var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *SanityCont
// Create Snapshot First // Create Snapshot First
By("creating a snapshot") By("creating a snapshot")
snapshotReq := MakeCreateSnapshotReq(sc, "DeleteSnapshot-snapshot-1", volume.GetVolume().GetId(), nil) snapshotReq := MakeCreateSnapshotReq(sc, "DeleteSnapshot-snapshot-1", volume.GetVolume().GetVolumeId(), nil)
snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq) snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(snapshot).NotTo(BeNil()) Expect(snapshot).NotTo(BeNil())
verifySnapshotInfo(snapshot.GetSnapshot()) verifySnapshotInfo(snapshot.GetSnapshot())
By("cleaning up deleting the snapshot") By("cleaning up deleting the snapshot")
delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq) _, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq) _, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@@ -1469,7 +1501,7 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont
} }
if sc.Secrets != nil { if sc.Secrets != nil {
req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret req.Secrets = sc.Secrets.CreateSnapshotSecret
} }
_, err := c.CreateSnapshot(context.Background(), req) _, err := c.CreateSnapshot(context.Background(), req)
@@ -1486,7 +1518,7 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont
} }
if sc.Secrets != nil { if sc.Secrets != nil {
req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret req.Secrets = sc.Secrets.CreateSnapshotSecret
} }
_, err := c.CreateSnapshot(context.Background(), req) _, err := c.CreateSnapshot(context.Background(), req)
@@ -1504,7 +1536,7 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("creating a snapshot") By("creating a snapshot")
snapReq1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-1", volume.GetVolume().GetId(), nil) snapReq1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-1", volume.GetVolume().GetVolumeId(), nil)
snap1, err := c.CreateSnapshot(context.Background(), snapReq1) snap1, err := c.CreateSnapshot(context.Background(), snapReq1)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(snap1).NotTo(BeNil()) Expect(snap1).NotTo(BeNil())
@@ -1516,12 +1548,12 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont
verifySnapshotInfo(snap2.GetSnapshot()) verifySnapshotInfo(snap2.GetSnapshot())
By("cleaning up deleting the snapshot") By("cleaning up deleting the snapshot")
delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetId()) delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq) _, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq) _, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@@ -1533,14 +1565,17 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
By("creating a snapshot with the created volume source id") By("creating a snapshot with the created volume source id")
req1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume.GetVolume().GetId(), nil) req1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume.GetVolume().GetVolumeId(), nil)
snap1, err := c.CreateSnapshot(context.Background(), req1) snap1, err := c.CreateSnapshot(context.Background(), req1)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(snap1).NotTo(BeNil()) Expect(snap1).NotTo(BeNil())
verifySnapshotInfo(snap1.GetSnapshot()) verifySnapshotInfo(snap1.GetSnapshot())
volume2, err := c.CreateVolume(context.Background(), MakeCreateVolumeReq(sc, "CreateSnapshot-volume-3"))
Expect(err).ToNot(HaveOccurred())
By("creating a snapshot with the same name but different volume source id") By("creating a snapshot with the same name but different volume source id")
req2 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", "test001", nil) req2 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume2.GetVolume().GetVolumeId(), nil)
_, err = c.CreateSnapshot(context.Background(), req2) _, err = c.CreateSnapshot(context.Background(), req2)
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
serverError, ok := status.FromError(err) serverError, ok := status.FromError(err)
@@ -1548,12 +1583,48 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont
Expect(serverError.Code()).To(Equal(codes.AlreadyExists)) Expect(serverError.Code()).To(Equal(codes.AlreadyExists))
By("cleaning up deleting the snapshot") By("cleaning up deleting the snapshot")
delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetId()) delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq) _, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the volume") By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred())
})
It("should not fail when creating snapshot with maximum-length name", func() {
By("creating a volume")
volReq := MakeCreateVolumeReq(sc, "CreateSnapshot-volume-3")
volume, err := c.CreateVolume(context.Background(), volReq)
Expect(err).NotTo(HaveOccurred())
nameBytes := make([]byte, MaxNameLength)
for i := 0; i < MaxNameLength; i++ {
nameBytes[i] = 'a'
}
name := string(nameBytes)
By("creating a snapshot")
snapReq1 := MakeCreateSnapshotReq(sc, name, volume.GetVolume().GetVolumeId(), nil)
snap1, err := c.CreateSnapshot(context.Background(), snapReq1)
Expect(err).NotTo(HaveOccurred())
Expect(snap1).NotTo(BeNil())
verifySnapshotInfo(snap1.GetSnapshot())
snap2, err := c.CreateSnapshot(context.Background(), snapReq1)
Expect(err).NotTo(HaveOccurred())
Expect(snap2).NotTo(BeNil())
verifySnapshotInfo(snap2.GetSnapshot())
By("cleaning up deleting the snapshot")
delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetSnapshotId())
_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
Expect(err).NotTo(HaveOccurred())
By("cleaning up deleting the volume")
delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
_, err = c.DeleteVolume(context.Background(), delVolReq) _, err = c.DeleteVolume(context.Background(), delVolReq)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
@@ -1578,10 +1649,11 @@ func MakeCreateVolumeReq(sc *SanityContext, name string) *csi.CreateVolumeReques
RequiredBytes: size1, RequiredBytes: size1,
LimitBytes: size1, LimitBytes: size1,
}, },
Parameters: sc.Config.TestVolumeParameters,
} }
if sc.Secrets != nil { if sc.Secrets != nil {
req.ControllerCreateSecrets = sc.Secrets.CreateVolumeSecret req.Secrets = sc.Secrets.CreateVolumeSecret
} }
return req return req
@@ -1595,7 +1667,7 @@ func MakeCreateSnapshotReq(sc *SanityContext, name, sourceVolumeId string, param
} }
if sc.Secrets != nil { if sc.Secrets != nil {
req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret req.Secrets = sc.Secrets.CreateSnapshotSecret
} }
return req return req
@@ -1607,7 +1679,7 @@ func MakeDeleteSnapshotReq(sc *SanityContext, id string) *csi.DeleteSnapshotRequ
} }
if sc.Secrets != nil { if sc.Secrets != nil {
delSnapReq.DeleteSnapshotSecrets = sc.Secrets.DeleteSnapshotSecret delSnapReq.Secrets = sc.Secrets.DeleteSnapshotSecret
} }
return delSnapReq return delSnapReq
@@ -1619,7 +1691,7 @@ func MakeDeleteVolumeReq(sc *SanityContext, id string) *csi.DeleteVolumeRequest
} }
if sc.Secrets != nil { if sc.Secrets != nil {
delVolReq.ControllerDeleteSecrets = sc.Secrets.DeleteVolumeSecret delVolReq.Secrets = sc.Secrets.DeleteVolumeSecret
} }
return delVolReq return delVolReq

View File

@@ -24,7 +24,7 @@ import (
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@@ -51,7 +51,7 @@ var _ = DescribeSanity("Identity Service", func(sc *SanityContext) {
for _, cap := range res.GetCapabilities() { for _, cap := range res.GetCapabilities() {
switch cap.GetService().GetType() { switch cap.GetService().GetType() {
case csi.PluginCapability_Service_CONTROLLER_SERVICE: case csi.PluginCapability_Service_CONTROLLER_SERVICE:
case csi.PluginCapability_Service_ACCESSIBILITY_CONSTRAINTS: case csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS:
default: default:
Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetService().GetType())) Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetService().GetType()))
} }

View File

@@ -23,7 +23,7 @@ import (
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@@ -119,6 +119,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
switch cap.GetRpc().GetType() { switch cap.GetRpc().GetType() {
case csi.NodeServiceCapability_RPC_UNKNOWN: case csi.NodeServiceCapability_RPC_UNKNOWN:
case csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME: case csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME:
case csi.NodeServiceCapability_RPC_GET_VOLUME_STATS:
default: default:
Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType())) Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType()))
} }
@@ -126,18 +127,6 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
}) })
}) })
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() { Describe("NodeGetInfo", func() {
var ( var (
i csi.IdentityClient i csi.IdentityClient
@@ -146,7 +135,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
BeforeEach(func() { BeforeEach(func() {
i = csi.NewIdentityClient(sc.Conn) i = csi.NewIdentityClient(sc.Conn)
accessibilityConstraintSupported = isPluginCapabilitySupported(i, csi.PluginCapability_Service_ACCESSIBILITY_CONSTRAINTS) accessibilityConstraintSupported = isPluginCapabilitySupported(i, csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS)
}) })
It("should return approproate values", func() { It("should return approproate values", func() {
@@ -170,7 +159,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
_, err := c.NodePublishVolume( _, err := c.NodePublishVolume(
context.Background(), context.Background(),
&csi.NodePublishVolumeRequest{ &csi.NodePublishVolumeRequest{
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, Secrets: sc.Secrets.NodePublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -184,8 +173,8 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
_, err := c.NodePublishVolume( _, err := c.NodePublishVolume(
context.Background(), context.Background(),
&csi.NodePublishVolumeRequest{ &csi.NodePublishVolumeRequest{
VolumeId: "id", VolumeId: "id",
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, Secrets: sc.Secrets.NodePublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -199,9 +188,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
_, err := c.NodePublishVolume( _, err := c.NodePublishVolume(
context.Background(), context.Background(),
&csi.NodePublishVolumeRequest{ &csi.NodePublishVolumeRequest{
VolumeId: "id", VolumeId: "id",
TargetPath: sc.Config.TargetPath, TargetPath: sc.Config.TargetPath,
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, Secrets: sc.Secrets.NodePublishVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -266,10 +255,10 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
PublishInfo: map[string]string{ PublishContext: map[string]string{
"device": device, "device": device,
}, },
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, Secrets: sc.Secrets.NodeStageVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -292,10 +281,10 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
PublishInfo: map[string]string{ PublishContext: map[string]string{
"device": device, "device": device,
}, },
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, Secrets: sc.Secrets.NodeStageVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -311,10 +300,10 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
&csi.NodeStageVolumeRequest{ &csi.NodeStageVolumeRequest{
VolumeId: "id", VolumeId: "id",
StagingTargetPath: sc.Config.StagingPath, StagingTargetPath: sc.Config.StagingPath,
PublishInfo: map[string]string{ PublishContext: map[string]string{
"device": device, "device": device,
}, },
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, Secrets: sc.Secrets.NodeStageVolumeSecret,
}, },
) )
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
@@ -380,19 +369,19 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
}, },
}, },
}, },
ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, Secrets: sc.Secrets.CreateVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(vol).NotTo(BeNil()) Expect(vol).NotTo(BeNil())
Expect(vol.GetVolume()).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil())
Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
By("getting a node id") By("getting a node id")
nid, err := c.NodeGetId( nid, err := c.NodeGetInfo(
context.Background(), context.Background(),
&csi.NodeGetIdRequest{}) &csi.NodeGetInfoRequest{})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(nid).NotTo(BeNil()) Expect(nid).NotTo(BeNil())
Expect(nid.GetNodeId()).NotTo(BeEmpty()) Expect(nid.GetNodeId()).NotTo(BeEmpty())
@@ -404,7 +393,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
conpubvol, err = s.ControllerPublishVolume( conpubvol, err = s.ControllerPublishVolume(
context.Background(), context.Background(),
&csi.ControllerPublishVolumeRequest{ &csi.ControllerPublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
VolumeCapability: &csi.VolumeCapability{ VolumeCapability: &csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{ AccessType: &csi.VolumeCapability_Mount{
@@ -414,13 +403,13 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
VolumeAttributes: vol.GetVolume().GetAttributes(), VolumeContext: vol.GetVolume().GetVolumeContext(),
Readonly: false, Readonly: false,
ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, Secrets: sc.Secrets.ControllerPublishVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId(), NodeID: nid.GetNodeId()}) cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId(), NodeID: nid.GetNodeId()})
Expect(conpubvol).NotTo(BeNil()) Expect(conpubvol).NotTo(BeNil())
} }
// NodeStageVolume // NodeStageVolume
@@ -429,7 +418,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
nodestagevol, err := c.NodeStageVolume( nodestagevol, err := c.NodeStageVolume(
context.Background(), context.Background(),
&csi.NodeStageVolumeRequest{ &csi.NodeStageVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
VolumeCapability: &csi.VolumeCapability{ VolumeCapability: &csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{ AccessType: &csi.VolumeCapability_Mount{
Mount: &csi.VolumeCapability_MountVolume{}, Mount: &csi.VolumeCapability_MountVolume{},
@@ -439,9 +428,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
}, },
}, },
StagingTargetPath: sc.Config.StagingPath, StagingTargetPath: sc.Config.StagingPath,
VolumeAttributes: vol.GetVolume().GetAttributes(), VolumeContext: vol.GetVolume().GetVolumeContext(),
PublishInfo: conpubvol.GetPublishInfo(), PublishContext: conpubvol.GetPublishContext(),
NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, Secrets: sc.Secrets.NodeStageVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -456,7 +445,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
nodepubvol, err := c.NodePublishVolume( nodepubvol, err := c.NodePublishVolume(
context.Background(), context.Background(),
&csi.NodePublishVolumeRequest{ &csi.NodePublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
TargetPath: sc.Config.TargetPath, TargetPath: sc.Config.TargetPath,
StagingTargetPath: stagingPath, StagingTargetPath: stagingPath,
VolumeCapability: &csi.VolumeCapability{ VolumeCapability: &csi.VolumeCapability{
@@ -467,9 +456,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
}, },
}, },
VolumeAttributes: vol.GetVolume().GetAttributes(), VolumeContext: vol.GetVolume().GetVolumeContext(),
PublishInfo: conpubvol.GetPublishInfo(), PublishContext: conpubvol.GetPublishContext(),
NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, Secrets: sc.Secrets.NodePublishVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -480,7 +469,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
nodeunpubvol, err := c.NodeUnpublishVolume( nodeunpubvol, err := c.NodeUnpublishVolume(
context.Background(), context.Background(),
&csi.NodeUnpublishVolumeRequest{ &csi.NodeUnpublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
TargetPath: sc.Config.TargetPath, TargetPath: sc.Config.TargetPath,
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -491,7 +480,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
nodeunstagevol, err := c.NodeUnstageVolume( nodeunstagevol, err := c.NodeUnstageVolume(
context.Background(), context.Background(),
&csi.NodeUnstageVolumeRequest{ &csi.NodeUnstageVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
StagingTargetPath: sc.Config.StagingPath, StagingTargetPath: sc.Config.StagingPath,
}, },
) )
@@ -505,9 +494,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
controllerunpubvol, err := s.ControllerUnpublishVolume( controllerunpubvol, err := s.ControllerUnpublishVolume(
context.Background(), context.Background(),
&csi.ControllerUnpublishVolumeRequest{ &csi.ControllerUnpublishVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
NodeId: nid.GetNodeId(), NodeId: nid.GetNodeId(),
ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
@@ -519,8 +508,8 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) {
_, err = s.DeleteVolume( _, err = s.DeleteVolume(
context.Background(), context.Background(),
&csi.DeleteVolumeRequest{ &csi.DeleteVolumeRequest{
VolumeId: vol.GetVolume().GetId(), VolumeId: vol.GetVolume().GetVolumeId(),
ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, Secrets: sc.Secrets.DeleteVolumeSecret,
}, },
) )
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())

View File

@@ -47,11 +47,14 @@ type CSISecrets struct {
// Config provides the configuration for the sanity tests. It // Config provides the configuration for the sanity tests. It
// needs to be initialized by the user of the sanity package. // needs to be initialized by the user of the sanity package.
type Config struct { type Config struct {
TargetPath string TargetPath string
StagingPath string StagingPath string
Address string Address string
SecretsFile string SecretsFile string
TestVolumeSize int64
TestVolumeSize int64
TestVolumeParametersFile string
TestVolumeParameters map[string]string
} }
// SanityContext holds the variables that each test can depend on. It // SanityContext holds the variables that each test can depend on. It
@@ -60,11 +63,25 @@ type SanityContext struct {
Config *Config Config *Config
Conn *grpc.ClientConn Conn *grpc.ClientConn
Secrets *CSISecrets Secrets *CSISecrets
connAddress string
} }
// Test will test the CSI driver at the specified address by // Test will test the CSI driver at the specified address by
// setting up a Ginkgo suite and running it. // setting up a Ginkgo suite and running it.
func Test(t *testing.T, reqConfig *Config) { func Test(t *testing.T, reqConfig *Config) {
path := reqConfig.TestVolumeParametersFile
if len(path) != 0 {
yamlFile, err := ioutil.ReadFile(path)
if err != nil {
panic(fmt.Sprintf("failed to read file %q: %v", path, err))
}
err = yaml.Unmarshal(yamlFile, &reqConfig.TestVolumeParameters)
if err != nil {
panic(fmt.Sprintf("error unmarshaling yaml: %v", err))
}
}
sc := &SanityContext{ sc := &SanityContext{
Config: reqConfig, Config: reqConfig,
} }
@@ -92,9 +109,17 @@ func (sc *SanityContext) setup() {
sc.Secrets = &CSISecrets{} sc.Secrets = &CSISecrets{}
} }
By("connecting to CSI driver") // It is possible that a test sets sc.Config.Address
sc.Conn, err = utils.Connect(sc.Config.Address) // dynamically (and differently!) in a BeforeEach, so only
Expect(err).NotTo(HaveOccurred()) // reuse the connection if the address is still the same.
if sc.Conn == nil || sc.connAddress != sc.Config.Address {
By("connecting to CSI driver")
sc.Conn, err = utils.Connect(sc.Config.Address)
Expect(err).NotTo(HaveOccurred())
sc.connAddress = sc.Config.Address
} else {
By(fmt.Sprintf("reusing connection to CSI driver at %s", sc.connAddress))
}
By("creating mount and staging directories") By("creating mount and staging directories")
err = createMountTargetLocation(sc.Config.TargetPath) err = createMountTargetLocation(sc.Config.TargetPath)
@@ -106,10 +131,16 @@ func (sc *SanityContext) setup() {
} }
func (sc *SanityContext) teardown() { func (sc *SanityContext) teardown() {
if sc.Conn != nil { // We intentionally do not close the connection to the CSI
sc.Conn.Close() // driver here because the large amount of connection attempts
sc.Conn = nil // caused test failures
} // (https://github.com/kubernetes-csi/csi-test/issues/101). We
// could fix this with retries
// (https://github.com/kubernetes-csi/csi-test/pull/97) but
// that requires more discussion, so instead we just connect
// once per process instead of once per test case. This was
// also said to be faster
// (https://github.com/kubernetes-csi/csi-test/pull/98).
} }
func createMountTargetLocation(targetPath string) error { func createMountTargetLocation(targetPath string) error {

View File

@@ -21,7 +21,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
mock_driver "github.com/kubernetes-csi/csi-test/driver" mock_driver "github.com/kubernetes-csi/csi-test/driver"
@@ -157,7 +157,7 @@ func TestGRPCAttach(t *testing.T) {
// Setup mock outout // Setup mock outout
out := &csi.ControllerPublishVolumeResponse{ out := &csi.ControllerPublishVolumeResponse{
PublishInfo: publishVolumeInfo, PublishContext: publishVolumeInfo,
} }
// Setup expectation // Setup expectation
@@ -181,7 +181,7 @@ func TestGRPCAttach(t *testing.T) {
t.Errorf("Error: %s", err.Error()) t.Errorf("Error: %s", err.Error())
} }
info := r.GetPublishInfo() info := r.GetPublishContext()
if !reflect.DeepEqual(info, publishVolumeInfo) { if !reflect.DeepEqual(info, publishVolumeInfo) {
t.Errorf("Invalid publish info: %v", info) t.Errorf("Invalid publish info: %v", info)
} }

View File

@@ -21,7 +21,7 @@ import (
"sync" "sync"
"testing" "testing"
"github.com/container-storage-interface/spec/lib/go/csi/v0" "github.com/container-storage-interface/spec/lib/go/csi"
"github.com/kubernetes-csi/csi-test/utils" "github.com/kubernetes-csi/csi-test/utils"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"

View File

@@ -29,7 +29,7 @@ type SafeGoroutineTester struct{}
// Errorf prints the error to the screen then panics // Errorf prints the error to the screen then panics
func (s *SafeGoroutineTester) Errorf(format string, args ...interface{}) { func (s *SafeGoroutineTester) Errorf(format string, args ...interface{}) {
fmt.Printf(format, args) fmt.Printf(format, args...)
panic("MOCK TEST ERROR") panic("MOCK TEST ERROR")
} }