diff --git a/Gopkg.lock b/Gopkg.lock index de9a2c79..cbd68e0f 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,24 +2,31 @@ [[projects]] + digest = "1:44982bd5390cb16b8a4dc65976503f907a9ffd07879fbddd3c06a9ef7e5b05c3" name = "github.com/container-storage-interface/spec" - packages = ["lib/go/csi/v0"] - revision = "2178fdeea87f1150a17a63252eee28d4d8141f72" - version = "v0.3.0" + packages = ["lib/go/csi"] + pruneopts = "" + revision = "8efcc85c45550571fba8134182013ed7dc34038a" + version = "v1.0.0-rc2" [[projects]] branch = "master" + digest = "1:107b233e45174dbab5b1324201d092ea9448e58243ab9f039e4c0f332e121e3a" name = "github.com/golang/glog" packages = ["."] + pruneopts = "" revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" [[projects]] + digest = "1:73a7106c799f98af4f3da7552906efc6a2570329f4cd2d2f5fb8f9d6c053ff2f" name = "github.com/golang/mock" packages = ["gomock"] + pruneopts = "" revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" version = "v1.1.1" [[projects]] + digest = "1:f958a1c137db276e52f0b50efee41a1a389dcdded59a69711f3e872757dab34b" name = "github.com/golang/protobuf" packages = [ "proto", @@ -28,22 +35,26 @@ "ptypes/any", "ptypes/duration", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] + pruneopts = "" revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" version = "v1.1.0" [[projects]] branch = "master" + digest = "1:79848f850d0d15b2413a7285441a7fd13ed8a901ebe57d59f1e49759c103b930" name = "github.com/kubernetes-csi/csi-test" packages = [ "driver", - "utils" + "utils", ] - revision = "e11d328ecca7fe91939284a8e878ebe77df8756d" + pruneopts = "" + revision = "619da6853e10bef67ddcc8f1c2b68b73154bf11d" [[projects]] branch = "master" + digest = "1:98219b20d296a0031fdb434d30ca6e109623a09530a76cf57e41c94bd1e391a0" name = "golang.org/x/net" packages = [ "context", @@ -52,17 +63,21 @@ "http2/hpack", "idna", "internal/timeseries", - "trace" + "trace", ] + pruneopts = "" revision = "c39426892332e1bb5ec0a434a079bf82f5d30c54" [[projects]] branch = "master" + digest = "1:b779cc85de245422bf70d8a21e6afcf3c0591eca64dc507feb9f054f64b21ab9" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "" revision = "4e1fef5609515ec7a2cee7b5de30ba6d9b438cbf" [[projects]] + digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4" name = "golang.org/x/text" packages = [ "collate", @@ -78,18 +93,22 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:3970150423e3f47a6d354b2868f7db632b665463755194aac1a30c4fb341be57" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] + pruneopts = "" revision = "383e8b2c3b9e36c4076b235b32537292176bae20" [[projects]] + digest = "1:ca75b3775a5d4e5d1fb48f57ef0865b4aaa8b3f00e6b52be68db991c4594e0a7" name = "google.golang.org/grpc" packages = [ ".", @@ -119,14 +138,22 @@ "resolver/passthrough", "stats", "status", - "tap" + "tap", ] + pruneopts = "" revision = "32fb0ac620c32ba40a4626ddf94d90d12cce3455" version = "v1.14.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "2f6e76998bb9d9f92c42332508edd9511082dc4b2a5bac1f3eba207120dd1b25" + input-imports = [ + "github.com/container-storage-interface/spec/lib/go/csi", + "github.com/golang/glog", + "github.com/golang/mock/gomock", + "github.com/kubernetes-csi/csi-test/driver", + "google.golang.org/grpc", + "google.golang.org/grpc/connectivity", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 182d704c..0544e7d6 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -23,7 +23,7 @@ [[constraint]] name = "github.com/container-storage-interface/spec" - version = "~0.3.0" + version = "1.0.0-rc2" [[constraint]] branch = "master" diff --git a/cmd/livenessprobe_test.go b/cmd/livenessprobe_test.go index bc17e898..12e2e190 100644 --- a/cmd/livenessprobe_test.go +++ b/cmd/livenessprobe_test.go @@ -21,7 +21,7 @@ import ( "testing" "time" - csi "github.com/container-storage-interface/spec/lib/go/csi/v0" + csi "github.com/container-storage-interface/spec/lib/go/csi" "github.com/golang/mock/gomock" "github.com/kubernetes-csi/csi-test/driver" "github.com/kubernetes-csi/livenessprobe/pkg/connection" diff --git a/pkg/connection/connection.go b/pkg/connection/connection.go index 3f2b5216..d1512ecc 100644 --- a/pkg/connection/connection.go +++ b/pkg/connection/connection.go @@ -23,7 +23,7 @@ import ( "strings" "time" - "github.com/container-storage-interface/spec/lib/go/csi/v0" + "github.com/container-storage-interface/spec/lib/go/csi" "github.com/golang/glog" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" diff --git a/vendor/github.com/container-storage-interface/spec/.gitignore b/vendor/github.com/container-storage-interface/spec/.gitignore index 4f7ede45..443a2c83 100644 --- a/vendor/github.com/container-storage-interface/spec/.gitignore +++ b/vendor/github.com/container-storage-interface/spec/.gitignore @@ -1,3 +1,4 @@ *.tmp .DS_Store .build +*.swp diff --git a/vendor/github.com/container-storage-interface/spec/.travis.yml b/vendor/github.com/container-storage-interface/spec/.travis.yml index 15b11d3a..65d1a6ab 100644 --- a/vendor/github.com/container-storage-interface/spec/.travis.yml +++ b/vendor/github.com/container-storage-interface/spec/.travis.yml @@ -29,7 +29,7 @@ jobs: # Lang stage: Go - stage: lang language: go - go: 1.9.5 + go: 1.10.4 go_import_path: github.com/container-storage-interface/spec install: - make -C lib/go protoc diff --git a/vendor/github.com/container-storage-interface/spec/CCLA.pdf b/vendor/github.com/container-storage-interface/spec/CCLA.pdf new file mode 100644 index 00000000..08a9f2a5 Binary files /dev/null and b/vendor/github.com/container-storage-interface/spec/CCLA.pdf differ diff --git a/vendor/github.com/container-storage-interface/spec/CONTRIBUTING.md b/vendor/github.com/container-storage-interface/spec/CONTRIBUTING.md index 8f33951f..e96ebc79 100644 --- a/vendor/github.com/container-storage-interface/spec/CONTRIBUTING.md +++ b/vendor/github.com/container-storage-interface/spec/CONTRIBUTING.md @@ -1,6 +1,9 @@ # How to Contribute 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. ## Markdown style diff --git a/vendor/github.com/container-storage-interface/spec/OWNERS b/vendor/github.com/container-storage-interface/spec/OWNERS index b11f9191..7225bd01 100644 --- a/vendor/github.com/container-storage-interface/spec/OWNERS +++ b/vendor/github.com/container-storage-interface/spec/OWNERS @@ -3,8 +3,8 @@ approvers: - thockin # Representing Kubernetes - jieyu # Representing Mesos - jdef # Representing Mesos - - cpuguy83 # Representing Docker - - mycure # Representing Docker - - julian-hj # Representing Cloud Foundry - - paulcwarren # Representing Cloud Foundry + - anusha-ragunathan # Representing Docker + - ddebroy # Representing Docker + - julian-hj # Representing Cloud Foundry + - paulcwarren # Representing Cloud Foundry reviewers: diff --git a/vendor/github.com/container-storage-interface/spec/README.md b/vendor/github.com/container-storage-interface/spec/README.md index d270cedd..c686e423 100644 --- a/vendor/github.com/container-storage-interface/spec/README.md +++ b/vendor/github.com/container-storage-interface/spec/README.md @@ -8,6 +8,6 @@ This project contains the CSI [specification](spec.md) and [protobuf](csi.proto) ### 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/) * [Mesos](http://mesos.apache.org/documentation/latest/csi/) diff --git a/vendor/github.com/container-storage-interface/spec/VERSION b/vendor/github.com/container-storage-interface/spec/VERSION index 0d91a54c..3eefcb9d 100644 --- a/vendor/github.com/container-storage-interface/spec/VERSION +++ b/vendor/github.com/container-storage-interface/spec/VERSION @@ -1 +1 @@ -0.3.0 +1.0.0 diff --git a/vendor/github.com/container-storage-interface/spec/csi.proto b/vendor/github.com/container-storage-interface/spec/csi.proto index 22cff40c..d240b668 100644 --- a/vendor/github.com/container-storage-interface/spec/csi.proto +++ b/vendor/github.com/container-storage-interface/spec/csi.proto @@ -1,10 +1,18 @@ // Code generated by make; DO NOT EDIT. syntax = "proto3"; -package csi.v0; +package csi.v1; +import "google/protobuf/descriptor.proto"; +import "google/protobuf/timestamp.proto"; import "google/protobuf/wrappers.proto"; 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 { rpc GetPluginInfo(GetPluginInfoRequest) returns (GetPluginInfoResponse) {} @@ -64,20 +72,12 @@ service Node { rpc NodeUnpublishVolume (NodeUnpublishVolumeRequest) returns (NodeUnpublishVolumeResponse) {} - // NodeGetId is being deprecated in favor of NodeGetInfo and will be - // removed in CSI 1.0. Existing drivers, however, may depend on this - // 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 NodeGetVolumeStats (NodeGetVolumeStatsRequest) + returns (NodeGetVolumeStatsResponse) {} rpc NodeGetCapabilities (NodeGetCapabilitiesRequest) returns (NodeGetCapabilitiesResponse) {} - // Prior to CSI 1.0 - CSI plugins MUST implement both NodeGetId and - // NodeGetInfo RPC calls. rpc NodeGetInfo (NodeGetInfoRequest) returns (NodeGetInfoResponse) {} } @@ -86,13 +86,13 @@ message GetPluginInfoRequest { } message GetPluginInfoResponse { - // The name MUST follow reverse domain name notation format - // (https://en.wikipedia.org/wiki/Reverse_domain_name_notation). - // It SHOULD include the plugin's host company name and the plugin - // name, to minimize the possibility of collisions. It MUST be 63 + // The name MUST follow domain name notation format + // (https://tools.ietf.org/html/rfc1035#section-2.3.1). It SHOULD + // include the plugin's host company name and the plugin name, + // to minimize the possibility of collisions. It MUST be 63 // characters or less, beginning and ending with an alphanumeric - // character ([a-z0-9A-Z]) with dashes (-), underscores (_), - // dots (.), and alphanumerics between. This field is REQUIRED. + // character ([a-z0-9A-Z]) with dashes (-), dots (.), and + // alphanumerics between. This field is REQUIRED. string name = 1; // This field is REQUIRED. Value of this field is opaque to the CO. @@ -108,7 +108,7 @@ message GetPluginCapabilitiesRequest { message GetPluginCapabilitiesResponse { // All the capabilities that the controller service supports. This // field is OPTIONAL. - repeated PluginCapability capabilities = 2; + repeated PluginCapability capabilities = 1; } // Specifies a capability of the plugin. @@ -119,7 +119,7 @@ message PluginCapability { // CONTROLLER_SERVICE indicates that the Plugin provides RPCs for // 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 // SHOULD NOT be the common case. // The presence of this capability determines whether the CO will @@ -127,13 +127,13 @@ message PluginCapability { // as specific RPCs as indicated by ControllerGetCapabilities. CONTROLLER_SERVICE = 1; - // ACCESSIBILITY_CONSTRAINTS indicates that the volumes for this - // plugin may not be equally accessible by all nodes in the + // VOLUME_ACCESSIBILITY_CONSTRAINTS indicates that the volumes for + // this plugin MAY NOT be equally accessible by all nodes in the // cluster. The CO MUST use the topology information returned by // CreateVolumeRequest along with the topology information // returned by NodeGetInfo to ensure that a given volume is // accessible from a given node when scheduling workloads. - ACCESSIBILITY_CONSTRAINTS = 2; + VOLUME_ACCESSIBILITY_CONSTRAINTS = 2; } Type type = 1; } @@ -174,37 +174,53 @@ message CreateVolumeRequest { // The suggested name for the storage space. This field is REQUIRED. // It serves two purposes: // 1) Idempotency - This name is generated by the CO to achieve - // idempotency. If `CreateVolume` fails, the volume may or may not - // be provisioned. In this case, the CO may call `CreateVolume` - // again, with the same name, to ensure the volume exists. The - // Plugin should ensure that multiple `CreateVolume` calls for the - // same name do not result in more than one piece of storage - // provisioned corresponding to that name. If a Plugin is unable to - // enforce idempotency, the CO's error recovery logic could result - // in multiple (unused) volumes being provisioned. + // idempotency. The Plugin SHOULD ensure that multiple + // `CreateVolume` calls for the same name do not result in more + // than one piece of storage provisioned corresponding to that + // name. If a Plugin is unable to enforce idempotency, the CO's + // error recovery logic could result in multiple (unused) volumes + // being provisioned. + // In the case of error, the CO MUST handle the gRPC error codes + // 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 // an identifier by which to refer to the newly provisioned // storage. If a storage system supports this, it can optionally // 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; // This field is OPTIONAL. This allows the CO to specify the capacity // requirement of the volume to be provisioned. If not specified, the // Plugin MAY choose an implementation-defined capacity range. If // 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. - CapacityRange capacity_range = 2; - // The capabilities that the provisioned volume MUST have: the Plugin - // MUST provision a volume that could satisfy ALL of the - // capabilities specified in this list. The Plugin MUST assume that - // the CO MAY use the provisioned volume later with ANY of the - // capabilities specified in this list. This also enables the CO to do - // early validation: if ANY of the specified volume capabilities are - // not supported by the Plugin, the call SHALL fail. This field is - // REQUIRED. + // The capabilities that the provisioned volume MUST have. SP MUST + // provision a volume that will satisfy ALL of the capabilities + // specified in this list. Otherwise SP MUST return the appropriate + // gRPC error code. + // The Plugin MUST assume that the CO MAY use the provisioned volume + // with ANY of the capabilities specified in this list. + // For example, a CO MAY specify two volume capabilities: one with + // 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; // 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. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map controller_create_secrets = 5; + map secrets = 5 [(csi_secret) = true]; // If specified, the new volume will be pre-populated with data from // this source. This field is OPTIONAL. @@ -228,10 +244,10 @@ message CreateVolumeRequest { // topological accessibility information supported by the SP. // This field is OPTIONAL. // 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 - // ACCESSIBILITY_CONSTRAINTS plugin capability, the SP MAY choose - // where the provisioned volume is accessible from. + // VOLUME_ACCESSIBILITY_CONSTRAINTS plugin capability, the SP MAY + // choose where the provisioned volume is accessible from. TopologyRequirement accessibility_requirements = 7; } @@ -243,11 +259,19 @@ message VolumeContentSource { // This field is REQUIRED. Plugin is REQUIRED to support creating // volume from snapshot if it supports the capability // 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 { SnapshotSource snapshot = 1; + VolumeSource volume = 2; } } @@ -334,7 +358,7 @@ message CapacityRange { int64 limit_bytes = 2; } -// The information about a provisioned volume. +// Information about a specific volume. message Volume { // 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 @@ -342,20 +366,32 @@ message Volume { // The value of this field MUST NOT be negative. int64 capacity_bytes = 1; - // Contains identity information for the created volume. This field is - // REQUIRED. The identity information will be used by the CO in - // subsequent calls to refer to the provisioned volume. - string id = 2; - - // Attributes reflect static properties of a volume and MUST be passed - // to volume validation and publishing calls. - // Attributes SHALL be opaque to a CO. Attributes SHALL NOT be mutable - // and SHALL be safe for the CO to cache. Attributes SHOULD NOT - // contain sensitive information. Attributes MAY NOT uniquely identify - // a volume. A volume uniquely identified by `id` SHALL always report - // the same attributes. This field is OPTIONAL and when present MUST - // be passed to volume validation and publishing calls. - map attributes = 3; + // The identifier for this volume, generated by the plugin. + // This field is REQUIRED. + // This field MUST contain enough information to uniquely identify + // 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; + + // Opaque static properties of the volume. SP MAY use this field to + // ensure subsequent volume validation and publishing calls have + // contextual information. + // The contents of this field SHALL be opaque to a CO. + // 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. + // 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 volume_context = 3; // If specified, indicates that the volume is not empty and is // pre-populated with data from the specified source. @@ -365,7 +401,7 @@ message Volume { // Specifies where (regions, zones, racks, etc.) the provisioned // volume is accessible from. // 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 // accessible from multiple locations. // COs MAY use this information along with the topology information @@ -373,7 +409,7 @@ message Volume { // from a given node when scheduling workloads. // 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 - // may schedule workloads referencing the volume on any available + // MAY schedule workloads referencing the volume on any available // node. // // Example 1: @@ -527,15 +563,18 @@ message TopologyRequirement { // A topological segment is a specific instance of a topological domain, // like "zone3", "rack3", etc. // 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". -// The key name segment is required. The prefix is optional. -// Both the key name and the prefix MUST each be 63 characters or less, -// begin and end with an alphanumeric character ([a-z0-9A-Z]) and -// contain only dashes (-), underscores (_), dots (.), or alphanumerics -// in between, for example "zone". -// The key prefix MUST follow reverse domain name notation format -// (https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +// The key name segment is REQUIRED. The prefix is OPTIONAL. +// The key name MUST be 63 characters or less, begin and end with an +// alphanumeric character ([a-z0-9A-Z]), and contain only dashes (-), +// underscores (_), dots (.), or alphanumerics in between, for example +// "zone". +// The key prefix MUST be 63 characters or less, begin and end with a +// 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 plugin name, to minimize the possibility of collisions with keys // from other plugins. @@ -558,7 +597,7 @@ message DeleteVolumeRequest { // Secrets required by plugin to complete volume deletion request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map controller_delete_secrets = 2; + map secrets = 2 [(csi_secret) = true]; } message DeleteVolumeResponse { @@ -573,31 +612,44 @@ message ControllerPublishVolumeRequest { // field to match the node ID returned by `NodeGetInfo`. 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. VolumeCapability volume_capability = 3; - // Whether to publish the volume in readonly mode. This field is - // REQUIRED. + // Indicates SP MUST publish the volume in readonly mode. + // 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; // Secrets required by plugin to complete controller publish volume // request. This field is OPTIONAL. Refer to the // `Secrets Requirements` section on how to use this field. - map controller_publish_secrets = 5; + map secrets = 5 [(csi_secret) = true]; - // Attributes of the volume to be used on a node. This field is - // OPTIONAL and MUST match the attributes of the Volume identified - // by `volume_id`. - map volume_attributes = 6; + // 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 volume_context = 6; } message ControllerPublishVolumeResponse { - // The SP specific information that will be passed to the Plugin in - // the subsequent `NodeStageVolume` or `NodePublishVolume` calls - // for the given volume. - // This information is opaque to the CO. This field is OPTIONAL. - map publish_info = 1; + // Opaque static publish properties of the volume. SP MAY use this + // field to ensure subsequent `NodeStageVolume` or `NodePublishVolume` + // calls calls have contextual information. + // The contents of this field SHALL be opaque to a CO. + // 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 publish_context = 1; } message ControllerUnpublishVolumeRequest { // The ID of the volume. This field is REQUIRED. @@ -615,7 +667,7 @@ message ControllerUnpublishVolumeRequest { // ControllerPublishVolume call for the specified volume. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map controller_unpublish_secrets = 3; + map secrets = 3 [(csi_secret) = true]; } message ControllerUnpublishVolumeResponse { @@ -625,30 +677,52 @@ message ValidateVolumeCapabilitiesRequest { // The ID of the volume to check. This field is REQUIRED. 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 volume_context = 2; + // 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. - repeated VolumeCapability volume_capabilities = 2; + repeated VolumeCapability volume_capabilities = 3; - // Attributes of the volume to check. This field is OPTIONAL and MUST - // match the attributes of the Volume identified by `volume_id`. - map volume_attributes = 3; + // See CreateVolumeRequest.parameters. + // This field is OPTIONAL. + map parameters = 4; - // Specifies where (regions, zones, racks, etc.) the caller believes - // the volume is accessible from. - // A caller MAY specify multiple topologies to indicate they believe - // the volume to be accessible from multiple locations. - // This field is OPTIONAL. This field SHALL NOT be set unless the - // plugin advertises the ACCESSIBILITY_CONSTRAINTS capability. - repeated Topology accessible_topology = 4; + // Secrets required by plugin to complete volume validation request. + // This field is OPTIONAL. Refer to the `Secrets Requirements` + // section on how to use this field. + map secrets = 5 [(csi_secret) = true]; } message ValidateVolumeCapabilitiesResponse { - // True if the Plugin supports the specified capabilities for the - // given volume. This field is REQUIRED. - bool supported = 1; + message Confirmed { + // Volume context validated by the plugin. + // This field is OPTIONAL. + map volume_context = 1; + + // 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 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 `supported` above is false. This field is + // Message to the CO if `confirmed` above is empty. This field is // OPTIONAL. // An empty string is equal to an unspecified field value. string message = 2; @@ -705,7 +779,7 @@ message GetCapacityRequest { // `accessible_topology`. This is the same as the // `accessible_topology` the CO returns in a `CreateVolumeResponse`. // 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; } @@ -725,7 +799,7 @@ message ControllerGetCapabilitiesRequest { message ControllerGetCapabilitiesResponse { // All the capabilities that the controller service supports. This // field is OPTIONAL. - repeated ControllerServiceCapability capabilities = 2; + repeated ControllerServiceCapability capabilities = 1; } // Specifies a capability of the controller service. @@ -742,11 +816,15 @@ message ControllerServiceCapability { // CREATE_DELETE_SNAPSHOT MUST support creating volume from // snapshot. 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; + // 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; @@ -764,12 +842,16 @@ message CreateSnapshotRequest { // The suggested name for the snapshot. This field is REQUIRED for // 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; // Secrets required by plugin to complete snapshot creation request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map create_snapshot_secrets = 3; + map secrets = 3 [(csi_secret) = true]; // Plugin specific parameters passed in as opaque key-value pairs. // This field is OPTIONAL. The Plugin is responsible for parsing and @@ -791,7 +873,7 @@ message CreateSnapshotResponse { Snapshot snapshot = 1; } -// The information about a provisioned snapshot. +// Information about a specific snapshot. message Snapshot { // 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 @@ -802,11 +884,16 @@ message Snapshot { // zero means it is unspecified. int64 size_bytes = 1; - // Uniquely identifies a snapshot and is generated by the plugin. It - // will not change over time. This field is REQUIRED. The identity - // information will be used by the CO in subsequent calls to refer to - // the provisioned snapshot. - string id = 2; + // The identifier for this snapshot, generated by the plugin. + // This field is REQUIRED. + // This field MUST contain enough information to uniquely identify + // this specific snapshot vs all other snapshots supported by this + // 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 // snapshot from a snapshot is not supported here so the source has to @@ -814,43 +901,13 @@ message Snapshot { string source_volume_id = 3; // Timestamp when the point-in-time snapshot is taken on the storage - // system. The format of this field should be a Unix nanoseconds time - // encoded as an int64. On Unix, the command `date +%s%N` returns the - // 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. - SnapshotStatus status = 5; -} + // system. This field is REQUIRED. + .google.protobuf.Timestamp creation_time = 4; -// 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; + // Indicates if a snapshot is ready to use as a + // `volume_content_source` in a `CreateVolumeRequest`. The default + // value is false. This field is REQUIRED. + bool ready_to_use = 5; } message DeleteSnapshotRequest { // The ID of the snapshot to be deleted. @@ -860,7 +917,7 @@ message DeleteSnapshotRequest { // Secrets required by plugin to complete snapshot deletion request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map delete_snapshot_secrets = 2; + map secrets = 2 [(csi_secret) = true]; } message DeleteSnapshotResponse {} @@ -890,7 +947,8 @@ message ListSnapshotsRequest { // Identity information for a specific snapshot. This field is // OPTIONAL. It can be used to list only a specific snapshot. // 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; } @@ -918,28 +976,33 @@ message NodeStageVolumeRequest { // has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be // left unset if the corresponding Controller Plugin does not have // this capability. This is an OPTIONAL field. - map publish_info = 2; + map 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 // 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. 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. VolumeCapability volume_capability = 4; // Secrets required by plugin to complete node stage volume request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map node_stage_secrets = 5; + map secrets = 5 [(csi_secret) = true]; - // Attributes of the volume to publish. This field is OPTIONAL and - // MUST match the attributes of the `Volume` identified by - // `volume_id`. - map volume_attributes = 6; + // 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 volume_context = 6; } message NodeStageVolumeResponse { @@ -949,7 +1012,7 @@ message NodeUnstageVolumeRequest { // The ID of the volume. This field is REQUIRED. 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. // This is a REQUIRED field. string staging_target_path = 2; @@ -967,9 +1030,9 @@ message NodePublishVolumeRequest { // has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be // left unset if the corresponding Controller Plugin does not have // this capability. This is an OPTIONAL field. - map publish_info = 2; + map 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 // serving this request. // 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 // absolute path in the root filesystem of the process serving this // request. The CO SHALL ensure uniqueness of target_path per volume. - // The CO SHALL ensure that the path exists, and that the process - // serving the request has `read` and `write` permissions to the path. + // The CO SHALL ensure that the process serving the request has + // `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. 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. VolumeCapability volume_capability = 5; - // Whether to publish the volume in readonly mode. This field is - // REQUIRED. + // Indicates SP MUST publish the volume in readonly mode. + // This field is REQUIRED. bool readonly = 6; // Secrets required by plugin to complete node publish volume request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map node_publish_secrets = 7; + map secrets = 7 [(csi_secret) = true]; - // Attributes of the volume to publish. This field is OPTIONAL and - // MUST match the attributes of the Volume identified by - // `volume_id`. - map volume_attributes = 8; + // 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 volume_context = 8; } message NodePublishVolumeResponse { @@ -1020,15 +1086,43 @@ message NodeUnpublishVolumeRequest { message NodeUnpublishVolumeResponse { // Intentionally empty. } -message NodeGetIdRequest { - // Intentionally empty. -} +message NodeGetVolumeStatsRequest { + // The ID of the volume. This field is REQUIRED. + string volume_id = 1; -message NodeGetIdResponse { - // The ID of the node as understood by the SP which SHALL be used by - // CO in subsequent `ControllerPublishVolume`. + // 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 node_id = 1; + string volume_path = 2; +} + +message NodeGetVolumeStatsResponse { + // This field is OPTIONAL. + repeated VolumeUsage usage = 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 { // Intentionally empty. @@ -1046,6 +1140,10 @@ message NodeServiceCapability { enum Type { UNKNOWN = 0; 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; @@ -1060,9 +1158,14 @@ message NodeGetInfoRequest { } message NodeGetInfoResponse { - // The ID of the node as understood by the SP which SHALL be used by - // CO in subsequent calls to `ControllerPublishVolume`. - // This is a REQUIRED field. + // The identifier of the node as understood by the SP. + // This field is REQUIRED. + // 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; // 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 // accessible from. // 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 // returned in CreateVolumeResponse to ensure that a given volume is // accessible from a given node when scheduling workloads. diff --git a/vendor/github.com/container-storage-interface/spec/lib/go/Makefile b/vendor/github.com/container-storage-interface/spec/lib/go/Makefile index a7443eae..3b1c5eab 100644 --- a/vendor/github.com/container-storage-interface/spec/lib/go/Makefile +++ b/vendor/github.com/container-storage-interface/spec/lib/go/Makefile @@ -58,14 +58,14 @@ $(PROTOC): PROTOC_GEN_GO_PKG := github.com/golang/protobuf/protoc-gen-go PROTOC_GEN_GO := protoc-gen-go $(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): mkdir -p $(dir $(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) && \ (test "$$(git describe --tags | head -1)" = "$(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) @@ -83,18 +83,25 @@ export PATH := $(shell pwd):$(PATH) ## BUILD ## ######################################################################## CSI_PROTO := ../../csi.proto -CSI_PKG := $(shell cat $(CSI_PROTO) | sed -n -e 's/^package.\([^;]*\);$$/\1/p'|tr '.' '/') -CSI_GO := $(CSI_PKG)/csi.pb.go +CSI_PKG_ROOT := github.com/container-storage-interface/spec +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_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. +$(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 := $(GO_OUT),Mgoogle/protobuf/wrappers.proto=github.com/golang/protobuf/ptypes/wrappers -$(CSI_GO_TMP): INCLUDE = -I$(PROTOC_TMP_DIR)/include +$(CSI_GO_TMP): GO_OUT := $(GO_OUT),Mgoogle/protobuf/descriptor.proto=github.com/golang/protobuf/protoc-gen-go/descriptor +$(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) @mkdir -p "$(@D)" - $(PROTOC) -I "$( controller_create_secrets = 5; + map secrets = 5 [(csi_secret) = true]; // If specified, the new volume will be pre-populated with data from // this source. This field is OPTIONAL. @@ -669,10 +708,10 @@ message CreateVolumeRequest { // topological accessibility information supported by the SP. // This field is OPTIONAL. // 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 - // ACCESSIBILITY_CONSTRAINTS plugin capability, the SP MAY choose - // where the provisioned volume is accessible from. + // VOLUME_ACCESSIBILITY_CONSTRAINTS plugin capability, the SP MAY + // choose where the provisioned volume is accessible from. TopologyRequirement accessibility_requirements = 7; } @@ -684,11 +723,19 @@ message VolumeContentSource { // This field is REQUIRED. Plugin is REQUIRED to support creating // volume from snapshot if it supports the capability // 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 { SnapshotSource snapshot = 1; + VolumeSource volume = 2; } } @@ -775,7 +822,7 @@ message CapacityRange { int64 limit_bytes = 2; } -// The information about a provisioned volume. +// Information about a specific volume. message Volume { // 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 @@ -783,20 +830,32 @@ message Volume { // The value of this field MUST NOT be negative. int64 capacity_bytes = 1; - // Contains identity information for the created volume. This field is - // REQUIRED. The identity information will be used by the CO in - // subsequent calls to refer to the provisioned volume. - string id = 2; - - // Attributes reflect static properties of a volume and MUST be passed - // to volume validation and publishing calls. - // Attributes SHALL be opaque to a CO. Attributes SHALL NOT be mutable - // and SHALL be safe for the CO to cache. Attributes SHOULD NOT - // contain sensitive information. Attributes MAY NOT uniquely identify - // a volume. A volume uniquely identified by `id` SHALL always report - // the same attributes. This field is OPTIONAL and when present MUST - // be passed to volume validation and publishing calls. - map attributes = 3; + // The identifier for this volume, generated by the plugin. + // This field is REQUIRED. + // This field MUST contain enough information to uniquely identify + // 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; + + // Opaque static properties of the volume. SP MAY use this field to + // ensure subsequent volume validation and publishing calls have + // contextual information. + // The contents of this field SHALL be opaque to a CO. + // 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. + // 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 volume_context = 3; // If specified, indicates that the volume is not empty and is // pre-populated with data from the specified source. @@ -806,7 +865,7 @@ message Volume { // Specifies where (regions, zones, racks, etc.) the provisioned // volume is accessible from. // 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 // accessible from multiple locations. // COs MAY use this information along with the topology information @@ -814,7 +873,7 @@ message Volume { // from a given node when scheduling workloads. // 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 - // may schedule workloads referencing the volume on any available + // MAY schedule workloads referencing the volume on any available // node. // // Example 1: @@ -968,15 +1027,18 @@ message TopologyRequirement { // A topological segment is a specific instance of a topological domain, // like "zone3", "rack3", etc. // 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". -// The key name segment is required. The prefix is optional. -// Both the key name and the prefix MUST each be 63 characters or less, -// begin and end with an alphanumeric character ([a-z0-9A-Z]) and -// contain only dashes (-), underscores (_), dots (.), or alphanumerics -// in between, for example "zone". -// The key prefix MUST follow reverse domain name notation format -// (https://en.wikipedia.org/wiki/Reverse_domain_name_notation). +// The key name segment is REQUIRED. The prefix is OPTIONAL. +// The key name MUST be 63 characters or less, begin and end with an +// alphanumeric character ([a-z0-9A-Z]), and contain only dashes (-), +// underscores (_), dots (.), or alphanumerics in between, for example +// "zone". +// The key prefix MUST be 63 characters or less, begin and end with a +// 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 plugin name, to minimize the possibility of collisions with keys // from other plugins. @@ -1001,18 +1063,17 @@ The CO MUST implement the specified error recovery behavior when it encounters t | Condition | gRPC Code | Description | Recovery Behavior | |-----------|-----------|-------------|-------------------| +| Source incompatible or not supported | 3 INVALID_ARGUMENT | Besides the general cases, this code MUST also be used to indicate when plugin supporting CREATE_DELETE_VOLUME cannot create a volume from the requested source (`SnapshotSource` or `VolumeSource`). Failure MAY be caused by not supporting the source (CO SHOULD NOT have provided that source) or incompatibility between `parameters` from the source and the ones requested for the new volume. More human-readable information SHOULD be provided in the gRPC `status.message` field if the problem is the source. | On source related issues, caller MUST use different parameters, a different source, or no source at all. | +| Source does not exist | 5 NOT_FOUND | Indicates that the specified source does not exist. | Caller MUST verify that the `volume_content_source` is correct, the source is accessible, and has not been deleted before retrying with exponential back off. | | Volume already exists but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified volume `name` already exists but is incompatible with the specified `capacity_range`, `volume_capabilities` or `parameters`. | Caller MUST fix the arguments or use a different `name` before retrying. | | Unable to provision in `accessible_topology` | 8 RESOURCE_EXHAUSTED | Indicates that although the `accessible_topology` field is valid, a new volume can not be provisioned with the specified topology constraints. More human-readable information MAY be provided in the gRPC `status.message` field. | Caller MUST ensure that whatever is preventing volumes from being provisioned in the specified location (e.g. quota issues) is addressed before retrying with exponential backoff. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | | Unsupported `capacity_range` | 11 OUT_OF_RANGE | Indicates that the capacity range is not allowed by the Plugin, for example when trying to create a volume smaller than the source snapshot. More human-readable information MAY be provided in the gRPC `status.message` field. | Caller MUST fix the capacity range before retrying. | -| Call not implemented | 12 UNIMPLEMENTED | CreateVolume call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` or `NodeGetCapabilities` to discover Plugin capabilities. | #### `DeleteVolume` A Controller Plugin MUST implement this RPC call if it has `CREATE_DELETE_VOLUME` capability. This RPC will be called by the CO to deprovision a volume. -If successful, the storage space associated with the volume MUST be released and all the data in the volume SHALL NOT be accessible anymore. This operation MUST be idempotent. If a volume corresponding to the specified `volume_id` does not exist or the artifacts associated with the volume do not exist anymore, the Plugin MUST reply `0 OK`. @@ -1026,7 +1087,7 @@ message DeleteVolumeRequest { // Secrets required by plugin to complete volume deletion request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map controller_delete_secrets = 2; + map secrets = 2 [(csi_secret) = true]; } message DeleteVolumeResponse { @@ -1043,8 +1104,6 @@ The CO MUST implement the specified error recovery behavior when it encounters t | Condition | gRPC Code | Description | Recovery Behavior | |-----------|-----------|-------------|-------------------| | Volume in use | 9 FAILED_PRECONDITION | Indicates that the volume corresponding to the specified `volume_id` could not be deleted because it is in use by another resource. | Caller SHOULD ensure that there are no other resources using the volume, and then retry with exponential back off. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | -| Call not implemented | 12 UNIMPLEMENTED | DeleteVolume call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` or `NodeGetCapabilities` to discover Plugin capabilities. | #### `ControllerPublishVolume` @@ -1071,31 +1130,44 @@ message ControllerPublishVolumeRequest { // field to match the node ID returned by `NodeGetInfo`. 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. VolumeCapability volume_capability = 3; - // Whether to publish the volume in readonly mode. This field is - // REQUIRED. + // Indicates SP MUST publish the volume in readonly mode. + // 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; // Secrets required by plugin to complete controller publish volume // request. This field is OPTIONAL. Refer to the // `Secrets Requirements` section on how to use this field. - map controller_publish_secrets = 5; + map secrets = 5 [(csi_secret) = true]; - // Attributes of the volume to be used on a node. This field is - // OPTIONAL and MUST match the attributes of the Volume identified - // by `volume_id`. - map volume_attributes = 6; + // 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 volume_context = 6; } message ControllerPublishVolumeResponse { - // The SP specific information that will be passed to the Plugin in - // the subsequent `NodeStageVolume` or `NodePublishVolume` calls - // for the given volume. - // This information is opaque to the CO. This field is OPTIONAL. - map publish_info = 1; + // Opaque static publish properties of the volume. SP MAY use this + // field to ensure subsequent `NodeStageVolume` or `NodePublishVolume` + // calls calls have contextual information. + // The contents of this field SHALL be opaque to a CO. + // 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 publish_context = 1; } ``` @@ -1112,8 +1184,6 @@ The CO MUST implement the specified error recovery behavior when it encounters t | Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the node corresponding to the specified `volume_id` but is incompatible with the specified `volume_capability` or `readonly` flag . | Caller MUST fix the arguments before retying. | | Volume published to another node | 9 FAILED_PRECONDITION | Indicates that a volume corresponding to the specified `volume_id` has already been published at another node and does not have MULTI_NODE volume capability. If this error code is returned, the Plugin SHOULD specify the `node_id` of the node at which the volume is published as part of the gRPC `status.message`. | Caller SHOULD ensure the specified volume is not published at any other node before retrying with exponential back off. | | Max volumes attached | 8 RESOURCE_EXHAUSTED | Indicates that the maximum supported number of volumes that can be attached to the specified node are already attached. Therefore, this operation will fail until at least one of the existing attached volumes is detached from the node. | Caller MUST ensure that the number of volumes already attached to the node is less then the maximum supported number of volumes before retrying with exponential backoff. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | -| Call not implemented | 12 UNIMPLEMENTED | ControllerPublishVolume call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` or `NodeGetCapabilities` to discover Plugin capabilities. | #### `ControllerUnpublishVolume` @@ -1146,7 +1216,7 @@ message ControllerUnpublishVolumeRequest { // ControllerPublishVolume call for the specified volume. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map controller_unpublish_secrets = 3; + map secrets = 3 [(csi_secret) = true]; } message ControllerUnpublishVolumeResponse { @@ -1164,46 +1234,69 @@ The CO MUST implement the specified error recovery behavior when it encounters t |-----------|-----------|-------------|-------------------| | Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. | | Node does not exist | 5 NOT_FOUND | Indicates that a node corresponding to the specified `node_id` does not exist. | Caller MUST verify that the `node_id` is correct and that the node is available and has not been terminated or deleted before retrying with exponential backoff. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | -| Call not implemented | 12 UNIMPLEMENTED | ControllerUnpublishVolume call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` or `NodeGetCapabilities` to discover Plugin capabilities. | #### `ValidateVolumeCapabilities` A Controller Plugin MUST implement this RPC call. This RPC will be called by the CO to check if a pre-provisioned volume has all the capabilities that the CO wants. -This RPC call SHALL return `supported` only if all the volume capabilities specified in the request are supported. +This RPC call SHALL return `confirmed` only if all the volume capabilities specified in the request are supported (see caveat below). This operation MUST be idempotent. +NOTE: Older plugins will parse but likely not "process" newer fields that MAY be present in capability-validation messages (and sub-messages) sent by a CO that is communicating using a newer, backwards-compatible version of the CSI protobufs. +Therefore, the CO SHALL reconcile successful capability-validation responses by comparing the validated capabilities with those that it had originally requested. + ```protobuf message ValidateVolumeCapabilitiesRequest { // The ID of the volume to check. This field is REQUIRED. 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 volume_context = 2; + // 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. - repeated VolumeCapability volume_capabilities = 2; + repeated VolumeCapability volume_capabilities = 3; - // Attributes of the volume to check. This field is OPTIONAL and MUST - // match the attributes of the Volume identified by `volume_id`. - map volume_attributes = 3; + // See CreateVolumeRequest.parameters. + // This field is OPTIONAL. + map parameters = 4; - // Specifies where (regions, zones, racks, etc.) the caller believes - // the volume is accessible from. - // A caller MAY specify multiple topologies to indicate they believe - // the volume to be accessible from multiple locations. - // This field is OPTIONAL. This field SHALL NOT be set unless the - // plugin advertises the ACCESSIBILITY_CONSTRAINTS capability. - repeated Topology accessible_topology = 4; + // Secrets required by plugin to complete volume validation request. + // This field is OPTIONAL. Refer to the `Secrets Requirements` + // section on how to use this field. + map secrets = 5 [(csi_secret) = true]; } message ValidateVolumeCapabilitiesResponse { - // True if the Plugin supports the specified capabilities for the - // given volume. This field is REQUIRED. - bool supported = 1; + message Confirmed { + // Volume context validated by the plugin. + // This field is OPTIONAL. + map 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 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. // An empty string is equal to an unspecified field value. string message = 2; @@ -1225,6 +1318,8 @@ The CO MUST implement the specified error recovery behavior when it encounters t A Controller Plugin MUST implement this RPC call if it has `LIST_VOLUMES` capability. The Plugin SHALL return the information about all the volumes that it knows about. +If volumes are created and/or deleted while the CO is concurrently paging through `ListVolumes` results then it is possible that the CO MAY either witness duplicate volumes in the list, not witness existing volumes, or both. +The CO SHALL NOT expect a consistent "view" of all volumes when paging through the volume list via multiple calls to `ListVolumes`. ```protobuf message ListVolumesRequest { @@ -1298,7 +1393,7 @@ message GetCapacityRequest { // `accessible_topology`. This is the same as the // `accessible_topology` the CO returns in a `CreateVolumeResponse`. // 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; } @@ -1329,7 +1424,7 @@ message ControllerGetCapabilitiesRequest { message ControllerGetCapabilitiesResponse { // All the capabilities that the controller service supports. This // field is OPTIONAL. - repeated ControllerServiceCapability capabilities = 2; + repeated ControllerServiceCapability capabilities = 1; } // Specifies a capability of the controller service. @@ -1346,11 +1441,15 @@ message ControllerServiceCapability { // CREATE_DELETE_SNAPSHOT MUST support creating volume from // snapshot. 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; + // 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; @@ -1373,17 +1472,43 @@ A Controller Plugin MUST implement this RPC call if it has `CREATE_DELETE_SNAPSH This RPC will be called by the CO to create a new snapshot from a source volume on behalf of a user. This operation MUST be idempotent. -If a snapshot corresponding to the specified snapshot `name` is already successfully cut and uploaded (if upload is part of the process) and is compatible with the specified `source_volume_id` and `parameters` in the `CreateSnapshotRequest`, the Plugin MUST reply `0 OK` with the corresponding `CreateSnapshotResponse`. +If a snapshot corresponding to the specified snapshot `name` is successfully cut and ready to use (meaning it MAY be specified as a `volume_content_source` in a `CreateVolumeRequest`), the Plugin MUST reply `0 OK` with the corresponding `CreateSnapshotResponse`. If an error occurs before a snapshot is cut, `CreateSnapshot` SHOULD return a corresponding gRPC error code that reflects the error condition. -For plugins that implement snapshot uploads, `CreateSnapshot` SHOULD return `10 ABORTED`, a gRPC code that indicates the operation is pending for snapshot, during the snapshot uploading processs. -If an error occurs during the uploading process, `CreateSnapshot` SHOULD return a corresponding gRPC error code that reflects the error condition. +For plugins that supports snapshot post processing such as uploading, `CreateSnapshot` SHOULD return `0 OK` and `ready_to_use` SHOULD be set to `false` after the snapshot is cut but still being processed. +CO SHOULD then reissue the same `CreateSnapshotRequest` periodically until boolean `ready_to_use` flips to `true` indicating the snapshot has been "processed" and is ready to use to create new volumes. +If an error occurs during the process, `CreateSnapshot` SHOULD return a corresponding gRPC error code that reflects the error condition. A snapshot MAY be used as the source to provision a new volume. -A CreateVolumeRequest message may specify an OPTIONAL source snapshot parameter. +A CreateVolumeRequest message MAY specify an OPTIONAL source snapshot parameter. Reverting a snapshot, where data in the original volume is erased and replaced with data in the snapshot, is an advanced functionality not every storage system can support and therefore is currently out of scope. +##### The ready_to_use Parameter + +Some SPs MAY "process" the snapshot after the snapshot is cut, for example, maybe uploading the snapshot somewhere after the snapshot is cut. +The post-cut process MAY be a long process that could take hours. +The CO MAY freeze the application using the source volume before taking the snapshot. +The purpose of `freeze` is to ensure the application data is in consistent state. +When `freeze` is performed, the container is paused and the application is also paused. +When `thaw` is performed, the container and the application start running again. +During the snapshot processing phase, since the snapshot is already cut, a `thaw` operation can be performed so application can start running without waiting for the process to complete. +The `ready_to_use` parameter of the snapshot will become `true` after the process is complete. + +For SPs that do not do additional processing after cut, the `ready_to_use` parameter SHOULD be `true` after the snapshot is cut. +`thaw` can be done when the `ready_to_use` parameter is `true` in this case. + +The `ready_to_use` parameter provides guidance to the CO on when it can "thaw" the application in the process of snapshotting. +If the cloud provider or storage system needs to process the snapshot after the snapshot is cut, the `ready_to_use` parameter returned by CreateSnapshot SHALL be `false`. +CO MAY continue to call CreateSnapshot while waiting for the process to complete until `ready_to_use` becomes `true`. +Note that CreateSnapshot no longer blocks after the snapshot is cut. + +A gRPC error code SHALL be returned if an error occurs during any stage of the snapshotting process. +A CO SHOULD explicitly delete snapshots when an error occurs. + +Based on this information, CO can issue repeated (idemponent) calls to CreateSnapshot, monitor the response, and make decisions. +Note that CreateSnapshot is a synchronous call and it MUST block until the snapshot is cut. + ```protobuf message CreateSnapshotRequest { // The ID of the source volume to be snapshotted. @@ -1392,12 +1517,16 @@ message CreateSnapshotRequest { // The suggested name for the snapshot. This field is REQUIRED for // 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; // Secrets required by plugin to complete snapshot creation request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map create_snapshot_secrets = 3; + map secrets = 3 [(csi_secret) = true]; // Plugin specific parameters passed in as opaque key-value pairs. // This field is OPTIONAL. The Plugin is responsible for parsing and @@ -1419,7 +1548,7 @@ message CreateSnapshotResponse { Snapshot snapshot = 1; } -// The information about a provisioned snapshot. +// Information about a specific snapshot. message Snapshot { // 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 @@ -1430,11 +1559,16 @@ message Snapshot { // zero means it is unspecified. int64 size_bytes = 1; - // Uniquely identifies a snapshot and is generated by the plugin. It - // will not change over time. This field is REQUIRED. The identity - // information will be used by the CO in subsequent calls to refer to - // the provisioned snapshot. - string id = 2; + // The identifier for this snapshot, generated by the plugin. + // This field is REQUIRED. + // This field MUST contain enough information to uniquely identify + // this specific snapshot vs all other snapshots supported by this + // 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 // snapshot from a snapshot is not supported here so the source has to @@ -1442,43 +1576,13 @@ message Snapshot { string source_volume_id = 3; // Timestamp when the point-in-time snapshot is taken on the storage - // system. The format of this field should be a Unix nanoseconds time - // encoded as an int64. On Unix, the command `date +%s%N` returns the - // 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. - SnapshotStatus status = 5; -} + // system. This field is REQUIRED. + .google.protobuf.Timestamp creation_time = 4; -// 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; + // Indicates if a snapshot is ready to use as a + // `volume_content_source` in a `CreateVolumeRequest`. The default + // value is false. This field is REQUIRED. + bool ready_to_use = 5; } ``` @@ -1491,16 +1595,14 @@ The CO MUST implement the specified error recovery behavior when it encounters t | Condition | gRPC Code | Description | Recovery Behavior | |-----------|-----------|-------------|-------------------| | Snapshot already exists but is incompatible | 6 ALREADY_EXISTS | Indicates that a snapshot corresponding to the specified snapshot `name` already exists but is incompatible with the specified `volume_id`. | Caller MUST fix the arguments or use a different `name` before retrying. | -| Operation pending for snapshot | 10 ABORTED | Indicates that there is a already an operation pending for the specified snapshot. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per snapshot at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same snapshot. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified snapshot, and then retry with exponential back off. | -| Call not implemented | 12 UNIMPLEMENTED | CreateSnapshot call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` to discover Plugin capabilities. | -| Not enough space to create snapshot | 13 RESOURCE_EXHAUSTED | There is not enough space on the storage system to handle the create snapshot request. | Caller should fail this request. Future calls to CreateSnapshot may succeed if space is freed up. | +| Operation pending for snapshot | 10 ABORTED | Indicates that there is already an operation pending for the specified snapshot. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per snapshot at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same snapshot. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified snapshot, and then retry with exponential back off. | +| Not enough space to create snapshot | 13 RESOURCE_EXHAUSTED | There is not enough space on the storage system to handle the create snapshot request. | Caller SHOULD fail this request. Future calls to CreateSnapshot MAY succeed if space is freed up. | #### `DeleteSnapshot` A Controller Plugin MUST implement this RPC call if it has `CREATE_DELETE_SNAPSHOT` capability. This RPC will be called by the CO to delete a snapshot. -If successful, the storage space associated with the snapshot MUST be released and all the data in the snapshot SHALL NOT be accessible anymore. This operation MUST be idempotent. If a snapshot corresponding to the specified `snapshot_id` does not exist or the artifacts associated with the snapshot do not exist anymore, the Plugin MUST reply `0 OK`. @@ -1514,7 +1616,7 @@ message DeleteSnapshotRequest { // Secrets required by plugin to complete snapshot deletion request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map delete_snapshot_secrets = 2; + map secrets = 2 [(csi_secret) = true]; } message DeleteSnapshotResponse {} @@ -1530,7 +1632,6 @@ The CO MUST implement the specified error recovery behavior when it encounters t |-----------|-----------|-------------|-------------------| | Snapshot in use | 9 FAILED_PRECONDITION | Indicates that the snapshot corresponding to the specified `snapshot_id` could not be deleted because it is in use by another resource. | Caller SHOULD ensure that there are no other resources using the snapshot, and then retry with exponential back off. | | Operation pending for snapshot | 10 ABORTED | Indicates that there is already an operation pending for the specified snapshot. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per snapshot at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same snapshot. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified snapshot, and then retry with exponential back off. | -| Call not implemented | 12 UNIMPLEMENTED | DeleteSnapshot call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` to discover Plugin capabilities. | #### `ListSnapshots` @@ -1538,6 +1639,8 @@ The CO MUST implement the specified error recovery behavior when it encounters t A Controller Plugin MUST implement this RPC call if it has `LIST_SNAPSHOTS` capability. The Plugin SHALL return the information about all snapshots on the storage system within the given parameters regardless of how they were created. `ListSnapshots` SHALL NOT list a snapshot that is being created but has not been cut successfully yet. +If snapshots are created and/or deleted while the CO is concurrently paging through `ListSnapshots` results then it is possible that the CO MAY either witness duplicate snapshots in the list, not witness existing snapshots, or both. +The CO SHALL NOT expect a consistent "view" of all snapshots when paging through the snapshot list via multiple calls to `ListSnapshots`. ```protobuf // List all snapshots on the storage system regardless of how they were @@ -1566,7 +1669,8 @@ message ListSnapshotsRequest { // Identity information for a specific snapshot. This field is // OPTIONAL. It can be used to list only a specific snapshot. // 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; } @@ -1621,40 +1725,10 @@ If a `CreateSnapshot` operation times out before the snapshot is cut, leaving th 2. The CO takes no further action regarding the timed out RPC, a snapshot is possibly leaked and the operator/user is expected to clean up. It is NOT REQUIRED for a controller plugin to implement the `LIST_SNAPSHOTS` capability if it supports the `CREATE_DELETE_SNAPSHOT` capability: the onus is upon the CO to take into consideration the full range of plugin capabilities before deciding how to proceed in the above scenario. -A controller plugin COULD implement the `LIST_SNAPSHOTS` capability and call it repeatedly with the `snapshot_id` as a filter to query whether the uploading process is complete or not if it needs to upload a snapshot after it is being cut. -##### Snapshot Statuses - -A snapshot could have the following statusus: UPLOADING, READY, and ERROR. - -Some cloud providers will upload the snapshot to a location in the cloud (i.e., an object store) after the snapshot is cut. -Uploading may be a long process that could take hours. -If a `freeze` operation was done on the application before taking the snapshot, it could be a long time before the application can be running again if we wait until the upload is complete to `thaw` the application. -The purpose of `freeze` is to ensure the application data is in consistent state. -When `freeze` is performed, the container is paused and the application is also paused. -When `thaw` is performed, the container and the application start running again. -During the snapshot uploading phase, since the snapshot is already cut, a `thaw` operation can be performed so application can start running without waiting for the upload to complete. -The status of the snapshot will become `READY` after the upload is complete. - -For cloud providers and storage systems that don't have the uploading process, the status should be `READY` after the snapshot is cut. -`thaw` can be done when the status is `READY` in this case. - -A `CREATING` status is not included here because CreateSnapshot is synchronous and will block until the snapshot is cut. - -`ERROR` is a terminal snapshot status. -A CO SHOULD explicitly delete snapshots in this status. - -The SnapshotStatus parameter provides guidance to the CO on what action can be taken in the process of snapshotting. -Based on this information, CO can issue repeated (idemponent) calls to CreateSnapshot, monitor the response, and make decisions. -Note that CreateSnapshot is a synchronous call and it must block until the snapshot is cut. -If the cloud provider or storage system does not need to upload the snapshot after it is cut, the status returned by CreateSnapshot SHALL be `READY`. -If the cloud provider or storage system needs to upload the snapshot after the snapshot is cut, the status returned by CreateSnapshot SHALL be `UPLOADING`. -CO MAY continue to call CreateSnapshot while waiting for the upload to complete until the status becomes `READY`. -Note that CreateSnapshot no longer blocks after the snapshot is cut. - -Alternatively, ListSnapshots can be called repeatedly with snapshot_id as filtering to wait for the upload to complete. ListSnapshots SHALL return with current information regarding the snapshots on the storage system. -When upload is complete, the status of the snapshot from ListSnapshots SHALL become `READY`. +When processing is complete, the `ready_to_use` parameter of the snapshot from ListSnapshots SHALL become `true`. +The downside of calling ListSnapshots is that ListSnapshots will not return a gRPC error code if an error occurs during the processing. So calling CreateSnapshot repeatedly is the preferred way to check if the processing is complete. ### Node Service RPC @@ -1684,28 +1758,33 @@ message NodeStageVolumeRequest { // has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be // left unset if the corresponding Controller Plugin does not have // this capability. This is an OPTIONAL field. - map publish_info = 2; + map 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 // 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. 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. VolumeCapability volume_capability = 4; // Secrets required by plugin to complete node stage volume request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map node_stage_secrets = 5; + map secrets = 5 [(csi_secret) = true]; - // Attributes of the volume to publish. This field is OPTIONAL and - // MUST match the attributes of the `Volume` identified by - // `volume_id`. - map volume_attributes = 6; + // 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 volume_context = 6; } message NodeStageVolumeResponse { @@ -1723,7 +1802,6 @@ The CO MUST implement the specified error recovery behavior when it encounters t |-----------|-----------|-------------|-------------------| | Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. | | Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the specified `staging_target_path` but is incompatible with the specified `volume_capability` flag. | Caller MUST fix the arguments before retying. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | | Exceeds capabilities | 9 FAILED_PRECONDITION | Indicates that the CO has exceeded the volume's capabilities because the volume does not have MULTI_NODE capability. | Caller MAY choose to call `ValidateVolumeCapabilities` to validate the volume capabilities, or wait for the volume to be unpublished on the node. | #### `NodeUnstageVolume` @@ -1751,7 +1829,7 @@ message NodeUnstageVolumeRequest { // The ID of the volume. This field is REQUIRED. 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. // This is a REQUIRED field. string staging_target_path = 2; @@ -1771,7 +1849,6 @@ The CO MUST implement the specified error recovery behavior when it encounters t | Condition | gRPC Code | Description | Recovery Behavior | |-----------|-----------|-------------|-------------------| | Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | #### RPC Interactions and Reference Counting `NodeStageVolume`, `NodeUnstageVolume`, `NodePublishVolume`, `NodeUnpublishVolume` @@ -1802,7 +1879,7 @@ The following table shows what the Plugin SHOULD return when receiving a second | MULTI_NODE | OK (idempotent) | ALREADY_EXISTS | OK | OK | | Non MULTI_NODE | OK (idempotent) | ALREADY_EXISTS | FAILED_PRECONDITION | FAILED_PRECONDITION| -(`Tn`: target path of the n-th `NodePublishVolume`, `Pn`: other arguments of the n-th `NodePublishVolume` except `node_publish_secrets`) +(`Tn`: target path of the n-th `NodePublishVolume`, `Pn`: other arguments of the n-th `NodePublishVolume` except `secrets`) ```protobuf message NodePublishVolumeRequest { @@ -1814,9 +1891,9 @@ message NodePublishVolumeRequest { // has `PUBLISH_UNPUBLISH_VOLUME` controller capability, and SHALL be // left unset if the corresponding Controller Plugin does not have // this capability. This is an OPTIONAL field. - map publish_info = 2; + map 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 // serving this request. // It MUST be set if the Node Plugin implements the @@ -1827,28 +1904,31 @@ message NodePublishVolumeRequest { // The path to which the volume will be published. It MUST be an // absolute path in the root filesystem of the process serving this // request. The CO SHALL ensure uniqueness of target_path per volume. - // The CO SHALL ensure that the path exists, and that the process - // serving the request has `read` and `write` permissions to the path. + // The CO SHALL ensure that the process serving the request has + // `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. 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. VolumeCapability volume_capability = 5; - // Whether to publish the volume in readonly mode. This field is - // REQUIRED. + // Indicates SP MUST publish the volume in readonly mode. + // This field is REQUIRED. bool readonly = 6; // Secrets required by plugin to complete node publish volume request. // This field is OPTIONAL. Refer to the `Secrets Requirements` // section on how to use this field. - map node_publish_secrets = 7; + map secrets = 7 [(csi_secret) = true]; - // Attributes of the volume to publish. This field is OPTIONAL and - // MUST match the attributes of the Volume identified by - // `volume_id`. - map volume_attributes = 8; + // 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 volume_context = 8; } message NodePublishVolumeResponse { @@ -1866,7 +1946,6 @@ The CO MUST implement the specified error recovery behavior when it encounters t |-----------|-----------|-------------|-------------------| | Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. | | Volume published but is incompatible | 6 ALREADY_EXISTS | Indicates that a volume corresponding to the specified `volume_id` has already been published at the specified `target_path` but is incompatible with the specified `volume_capability` or `readonly` flag. | Caller MUST fix the arguments before retying. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | | Exceeds capabilities | 9 FAILED_PRECONDITION | Indicates that the CO has exceeded the volume's capabilities because the volume does not have MULTI_NODE capability. | Caller MAY choose to call `ValidateVolumeCapabilities` to validate the volume capabilities, or wait for the volume to be unpublished on the node. | | Staging target path not set | 9 FAILED_PRECONDITION | Indicates that `STAGE_UNSTAGE_VOLUME` capability is set but no `staging_target_path` was set. | Caller MUST make sure call to `NodeStageVolume` is made and returns success before retrying with valid `staging_target_path`. | @@ -1910,41 +1989,68 @@ The CO MUST implement the specified error recovery behavior when it encounters t | Condition | gRPC Code | Description | Recovery Behavior | |-----------|-----------|-------------|-------------------| | Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible and has not been deleted before retrying with exponential back off. | -| Operation pending for volume | 10 ABORTED | Indicates that there is a already an operation pending for the specified volume. In general the Cluster Orchestrator (CO) is responsible for ensuring that there is no more than one call "in-flight" per volume at a given time. However, in some circumstances, the CO MAY lose state (for example when the CO crashes and restarts), and MAY issue multiple calls simultaneously for the same volume. The Plugin, SHOULD handle this as gracefully as possible, and MAY return this error code to reject secondary calls. | Caller SHOULD ensure that there are no other calls pending for the specified volume, and then retry with exponential back off. | -#### `NodeGetId` +#### `NodeGetVolumeStats` -`NodeGetId` RPC call is deprecated. -Users of this RPC call SHOULD use `NodeGetInfo`. +A Node plugin MUST implement this RPC call if it has GET_VOLUME_STATS node capability. +`NodeGetVolumeStats` RPC call returns the volume capacity statistics available for the volume. + +If the volume is being used in `BlockVolume` mode then `used` and `available` MAY be omitted from `usage` field of `NodeGetVolumeStatsResponse`. +Similarly, inode information MAY be omitted from `NodeGetVolumeStatsResponse` when unavailable. -A Node Plugin MUST implement this RPC call if the plugin has `PUBLISH_UNPUBLISH_VOLUME` controller capability. -The Plugin SHALL assume that this RPC will be executed on the node where the volume will be used. -The CO SHOULD call this RPC for the node at which it wants to place the workload. -The result of this call will be used by CO in `ControllerPublishVolume`. ```protobuf -message NodeGetIdRequest { - // Intentionally empty. -} +message NodeGetVolumeStatsRequest { + // The ID of the volume. This field is REQUIRED. + string volume_id = 1; -message NodeGetIdResponse { - // The ID of the node as understood by the SP which SHALL be used by - // CO in subsequent `ControllerPublishVolume`. + // 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 node_id = 1; + string volume_path = 2; +} + +message NodeGetVolumeStatsResponse { + // This field is OPTIONAL. + repeated VolumeUsage usage = 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; } ``` -##### NodeGetId Errors +##### NodeGetVolumeStats Errors -If the plugin is unable to complete the NodeGetId call successfully, it MUST return a non-ok gRPC code in the gRPC status. +If the plugin is unable to complete the `NodeGetVolumeStats` call successfully, it MUST return a non-ok gRPC code in the gRPC status. If the conditions defined below are encountered, the plugin MUST return the specified gRPC error code. The CO MUST implement the specified error recovery behavior when it encounters the gRPC error code. -Condition | gRPC Code | Description | Recovery Behavior -| --- | --- | --- | --- | -| Call not implemented | 12 UNIMPLEMENTED | NodeGetId call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` or `NodeGetCapabilities` to discover Plugin capabilities. | + +| Condition | gRPC Code | Description | Recovery Behavior | +|-----------|-----------|-------------|-------------------| +| Volume does not exist | 5 NOT_FOUND | Indicates that a volume corresponding to the specified `volume_id` does not exist on specified `volume_path`. | Caller MUST verify that the `volume_id` is correct and that the volume is accessible on specified `volume_path` and has not been deleted before retrying with exponential back off. | #### `NodeGetCapabilities` @@ -1968,6 +2074,10 @@ message NodeServiceCapability { enum Type { UNKNOWN = 0; 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; @@ -1990,6 +2100,8 @@ If the plugin is unable to complete the NodeGetCapabilities call successfully, i A Node Plugin MUST implement this RPC call if the plugin has `PUBLISH_UNPUBLISH_VOLUME` controller capability. The Plugin SHALL assume that this RPC will be executed on the node where the volume will be used. The CO SHOULD call this RPC for the node at which it wants to place the workload. +The CO MAY call this RPC more than once for a given node. +The SP SHALL NOT expect the CO to call this RPC more than once. The result of this call will be used by CO in `ControllerPublishVolume`. ```protobuf @@ -1997,9 +2109,14 @@ message NodeGetInfoRequest { } message NodeGetInfoResponse { - // The ID of the node as understood by the SP which SHALL be used by - // CO in subsequent calls to `ControllerPublishVolume`. - // This is a REQUIRED field. + // The identifier of the node as understood by the SP. + // This field is REQUIRED. + // 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; // Maximum number of volumes that controller can publish to the node. @@ -2012,7 +2129,7 @@ message NodeGetInfoResponse { // Specifies where (regions, zones, racks, etc.) the node is // accessible from. // 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 // returned in CreateVolumeResponse to ensure that a given volume is // accessible from a given node when scheduling workloads. @@ -2033,14 +2150,8 @@ message NodeGetInfoResponse { ##### NodeGetInfo Errors If the plugin is unable to complete the NodeGetInfo call successfully, it MUST return a non-ok gRPC code in the gRPC status. -If the conditions defined below are encountered, the plugin MUST return the specified gRPC error code. The CO MUST implement the specified error recovery behavior when it encounters the gRPC error code. -Condition | gRPC Code | Description | Recovery Behavior -| --- | --- | --- | --- | -| Call not implemented | 12 UNIMPLEMENTED | NodeGetInfo call is not implemented by the plugin or disabled in the Plugin's current mode of operation. | Caller MUST NOT retry. Caller MAY call `ControllerGetCapabilities` or `NodeGetCapabilities` to discover Plugin capabilities. | - - ## Protocol ### Connectivity @@ -2051,7 +2162,7 @@ Condition | gRPC Code | Description | Recovery Behavior Support for OPTIONAL RPCs is reported by the `ControllerGetCapabilities` and `NodeGetCapabilities` RPC calls. * The CO SHALL provide the listen-address for the Plugin by way of the `CSI_ENDPOINT` environment variable. Plugin components SHALL create, bind, and listen for RPCs on the specified listen address. - * Only UNIX Domain Sockets may be used as endpoints. + * Only UNIX Domain Sockets MAY be used as endpoints. This will likely change in a future version of this specification to support non-UNIX platforms. * All supported RPC services MUST be available at the listen address of the Plugin. @@ -2060,7 +2171,7 @@ Condition | gRPC Code | Description | Recovery Behavior * The CO operator and Plugin Supervisor SHOULD take steps to ensure that any and all communication between the CO and Plugin Service are secured according to best practices. * Communication between a CO and a Plugin SHALL be transported over UNIX Domain Sockets. * gRPC is compatible with UNIX Domain Sockets; it is the responsibility of the CO operator and Plugin Supervisor to properly secure access to the Domain Socket using OS filesystem ACLs and/or other OS-specific security context tooling. - * SP’s supplying stand-alone Plugin controller appliances, or other remote components that are incompatible with UNIX Domain Sockets must provide a software component that proxies communication between a UNIX Domain Socket and the remote component(s). + * SP’s supplying stand-alone Plugin controller appliances, or other remote components that are incompatible with UNIX Domain Sockets MUST provide a software component that proxies communication between a UNIX Domain Socket and the remote component(s). Proxy components transporting communication over IP networks SHALL be responsible for securing communications over such networks. * Both the CO and Plugin SHOULD avoid accidental leakage of sensitive information (such as redacting such information from log files). @@ -2105,8 +2216,8 @@ Condition | gRPC Code | Description | Recovery Behavior * Variables defined by this specification SHALL be identifiable by their `CSI_` name prefix. * Configuration properties not defined by the CSI specification SHALL NOT use the same `CSI_` name prefix; this prefix is reserved for common configuration properties defined by the CSI specification. -* The Plugin Supervisor SHOULD supply all recommended CSI environment variables to a Plugin. -* The Plugin Supervisor SHALL supply all required CSI environment variables to a Plugin. +* The Plugin Supervisor SHOULD supply all RECOMMENDED CSI environment variables to a Plugin. +* The Plugin Supervisor SHALL supply all REQUIRED CSI environment variables to a Plugin. ##### `CSI_ENDPOINT` @@ -2141,8 +2252,8 @@ Supervised plugins MAY be isolated and/or resource-bounded. ##### Available Services * Plugin Packages MAY support all or a subset of CSI services; service combinations MAY be configurable at runtime by the Plugin Supervisor. - * A plugin must know the "mode" in which it is operating (e.g. node, controller, or both). - * This specification does not dictate the mechanism by which mode of operation must be discovered, and instead places that burden upon the SP. + * A plugin MUST know the "mode" in which it is operating (e.g. node, controller, or both). + * This specification does not dictate the mechanism by which mode of operation MUST be discovered, and instead places that burden upon the SP. * Misconfigured plugin software SHOULD fail-fast with an OS-appropriate error code. ##### Linux Capabilities @@ -2158,7 +2269,7 @@ Supervised plugins MAY be isolated and/or resource-bounded. ##### Cgroup Isolation * A Plugin MAY be constrained by cgroups. -* An operator or Plugin Supervisor MAY configure the devices cgroup subsystem to ensure that a Plugin may access requisite devices. +* An operator or Plugin Supervisor MAY configure the devices cgroup subsystem to ensure that a Plugin MAY access requisite devices. * A Plugin Supervisor MAY define resource limits for a Plugin. ##### Resource Requirements diff --git a/vendor/github.com/kubernetes-csi/csi-test/.gitignore b/vendor/github.com/kubernetes-csi/csi-test/.gitignore index 984ec0fb..81c985c4 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/.gitignore +++ b/vendor/github.com/kubernetes-csi/csi-test/.gitignore @@ -11,3 +11,9 @@ *.out bin/mock cmd/csi-sanity/csi-sanity + +# JetBrains GoLand +.idea + +# Vim +*.swp diff --git a/vendor/github.com/kubernetes-csi/csi-test/.travis.yml b/vendor/github.com/kubernetes-csi/csi-test/.travis.yml index 261662d3..7a817191 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/.travis.yml +++ b/vendor/github.com/kubernetes-csi/csi-test/.travis.yml @@ -1,4 +1,7 @@ language: go +sudo: required +services: + - docker matrix: include: - go: 1.10.3 @@ -6,6 +9,7 @@ script: - make test after_success: - if [ "${TRAVIS_BRANCH}" == "master" ] && [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then + make container docker login -u "${DOCKER_USERNAME}" -p "${DOCKER_PASSWORD}" quay.io; make push; fi diff --git a/vendor/github.com/kubernetes-csi/csi-test/CONTRIBUTING.md b/vendor/github.com/kubernetes-csi/csi-test/CONTRIBUTING.md new file mode 100644 index 00000000..41b73b76 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/CONTRIBUTING.md @@ -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) diff --git a/vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock index 2737ba71..443ad970 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock +++ b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.lock @@ -2,18 +2,23 @@ [[projects]] + digest = "1:26ee2356254e58b9872ba736f66aff1c54a26f08c7d16afbf49695131a87d454" name = "github.com/container-storage-interface/spec" - packages = ["lib/go/csi/v0"] - revision = "2178fdeea87f1150a17a63252eee28d4d8141f72" - version = "v0.3.0" + packages = ["lib/go/csi"] + pruneopts = "UT" + revision = "8efcc85c45550571fba8134182013ed7dc34038a" + version = "v1.0.0-rc2" [[projects]] + digest = "1:bc38c7c481812e178d85160472e231c5e1c9a7f5845d67e23ee4e706933c10d8" name = "github.com/golang/mock" packages = ["gomock"] + pruneopts = "UT" revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" version = "v1.1.1" [[projects]] + digest = "1:588beb9f80d2b0afddf05663b32d01c867da419458b560471d81cca0286e76b8" name = "github.com/golang/protobuf" packages = [ "proto", @@ -22,12 +27,14 @@ "ptypes/any", "ptypes/duration", "ptypes/timestamp", - "ptypes/wrappers" + "ptypes/wrappers", ] - revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" - version = "v1.1.0" + pruneopts = "UT" + revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" + version = "v1.2.0" [[projects]] + digest = "1:72f35d3e412bc67b121e15ea4c88a3b3da8bcbc2264339e7ffa4a1865799840c" name = "github.com/onsi/ginkgo" packages = [ ".", @@ -47,12 +54,14 @@ "reporters/stenographer", "reporters/stenographer/support/go-colorable", "reporters/stenographer/support/go-isatty", - "types" + "types", ] + pruneopts = "UT" revision = "fa5fabab2a1bfbd924faf4c067d07ae414e2aedf" version = "v1.5.0" [[projects]] + digest = "1:d0c2c4e2d0006cd28c220a549cda1de8e67abc65ed4c572421492bbf0492ceaf" name = "github.com/onsi/gomega" packages = [ ".", @@ -66,25 +75,31 @@ "matchers/support/goraph/edge", "matchers/support/goraph/node", "matchers/support/goraph/util", - "types" + "types", ] + pruneopts = "UT" revision = "62bff4df71bdbc266561a0caee19f0594b17c240" version = "v1.4.0" [[projects]] + digest = "1:9e9193aa51197513b3abcb108970d831fbcf40ef96aa845c4f03276e1fa316d2" name = "github.com/sirupsen/logrus" packages = ["."] + pruneopts = "UT" revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc" version = "v1.0.5" [[projects]] branch = "master" + digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" name = "golang.org/x/crypto" packages = ["ssh/terminal"] + pruneopts = "UT" revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9" [[projects]] branch = "master" + digest = "1:0bb2e6ef036484991ed446a6c698698b8901766981d4d22cc8e53fedb09709ac" name = "golang.org/x/net" packages = [ "context", @@ -96,20 +111,24 @@ "http2/hpack", "idna", "internal/timeseries", - "trace" + "trace", ] + pruneopts = "UT" revision = "1e491301e022f8f977054da4c2d852decd59571f" [[projects]] branch = "master" + digest = "1:8fbfc6ea1a8a078697633be97f07dd83a83d32a96959d42195464c13c25be374" name = "golang.org/x/sys" packages = [ "unix", - "windows" + "windows", ] + pruneopts = "UT" revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb" [[projects]] + digest = "1:436b24586f8fee329e0dd65fd67c817681420cda1d7f934345c13fe78c212a73" name = "golang.org/x/text" packages = [ "collate", @@ -137,18 +156,22 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:601e63e7d4577f907118bec825902505291918859d223bce015539e79f1160e3" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] + pruneopts = "UT" revision = "32ee49c4dd805befd833990acba36cb75042378c" [[projects]] + digest = "1:7a977fdcd5abff03e94f92e7b374ef37e91c7c389581e5c4348fa98616e6c6be" name = "google.golang.org/grpc" packages = [ ".", @@ -176,20 +199,39 @@ "stats", "status", "tap", - "transport" + "transport", ] + pruneopts = "UT" revision = "7a6a684ca69eb4cae85ad0a484f2e531598c047b" version = "v1.12.2" [[projects]] + digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "UT" revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" version = "v2.2.1" [solve-meta] analyzer-name = "dep" 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-version = 1 diff --git a/vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml index e7312785..4e0836d0 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml +++ b/vendor/github.com/kubernetes-csi/csi-test/Gopkg.toml @@ -27,7 +27,7 @@ [[constraint]] name = "github.com/container-storage-interface/spec" - version = "~0.3.0" + version = "v1.0.0-rc2" [[constraint]] name = "github.com/golang/mock" @@ -35,7 +35,7 @@ [[constraint]] name = "github.com/golang/protobuf" - version = "v1.1.0" + version = "v1.2.0" [[constraint]] name = "github.com/onsi/ginkgo" diff --git a/vendor/github.com/kubernetes-csi/csi-test/Makefile b/vendor/github.com/kubernetes-csi/csi-test/Makefile index 621cec71..7fb42c87 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/Makefile +++ b/vendor/github.com/kubernetes-csi/csi-test/Makefile @@ -38,7 +38,7 @@ container: $(APP) push: container docker push $(IMAGE_NAME):$(IMAGE_VERSION) -test: +test: $(APP) files=$$(find ./ -name '*.go' | grep -v '^./vendor' ); \ if [ $$(gofmt -d $$files | wc -l) -ne 0 ]; then \ echo "formatting errors:"; \ diff --git a/vendor/github.com/kubernetes-csi/csi-test/README.md b/vendor/github.com/kubernetes-csi/csi-test/README.md index 61daecc0..36dce60b 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/README.md +++ b/vendor/github.com/kubernetes-csi/csi-test/README.md @@ -27,3 +27,16 @@ CSI driver. * 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) + +## 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). diff --git a/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go index a4f4707a..4b2d352c 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go +++ b/vendor/github.com/kubernetes-csi/csi-test/cmd/csi-sanity/sanity_test.go @@ -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.SecretsFile, prefix+"secrets", "", "CSI secrets file") 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() } diff --git a/vendor/github.com/kubernetes-csi/csi-test/driver/driver.go b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.go index a8cd796f..01224a3a 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/driver/driver.go +++ b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.go @@ -14,20 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ -//go:generate mockgen -package=driver -destination=driver.mock.go github.com/container-storage-interface/spec/lib/go/csi/v0 IdentityServer,ControllerServer,NodeServer +//go:generate mockgen -package=driver -destination=driver.mock.go github.com/container-storage-interface/spec/lib/go/csi IdentityServer,ControllerServer,NodeServer package driver import ( "context" + "encoding/json" "errors" + "fmt" "net" "sync" "google.golang.org/grpc/codes" "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/reflection" ) @@ -102,7 +104,7 @@ func (c *CSIDriver) Start(l net.Listener) error { // Create a new grpc server c.server = grpc.NewServer( - grpc.UnaryInterceptor(c.authInterceptor), + grpc.UnaryInterceptor(c.callInterceptor), ) // 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 { authenticated, authErr := isAuthenticated(req, c.creds) if !authenticated { if authErr == ErrNoCredentials { - return nil, status.Error(codes.InvalidArgument, authErr.Error()) + return status.Error(codes.InvalidArgument, authErr.Error()) } 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) - - return h, err +func logGRPC(method string, request, reply interface{}, err error) { + // Log JSON with the request and response for easier parsing + 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) { @@ -204,35 +233,35 @@ func isAuthenticated(req interface{}, 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) { - return credsCheck(req.GetControllerDeleteSecrets(), creds.DeleteVolumeSecret) + return credsCheck(req.GetSecrets(), creds.DeleteVolumeSecret) } 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) { - return credsCheck(req.GetControllerUnpublishSecrets(), creds.ControllerUnpublishVolumeSecret) + return credsCheck(req.GetSecrets(), creds.ControllerUnpublishVolumeSecret) } 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) { - return credsCheck(req.GetNodePublishSecrets(), creds.NodePublishVolumeSecret) + return credsCheck(req.GetSecrets(), creds.NodePublishVolumeSecret) } 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) { - return credsCheck(req.GetDeleteSnapshotSecrets(), creds.DeleteSnapshotSecret) + return credsCheck(req.GetSecrets(), creds.DeleteSnapshotSecret) } func credsCheck(secrets map[string]string, secretVal string) (bool, error) { diff --git a/vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go index f6d2b135..c54acaad 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go +++ b/vendor/github.com/kubernetes-csi/csi-test/driver/driver.mock.go @@ -1,12 +1,12 @@ // 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 import ( 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" reflect "reflect" ) @@ -35,9 +35,9 @@ func (m *MockIdentityServer) EXPECT() *MockIdentityServerMockRecorder { } // 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) - ret0, _ := ret[0].(*v0.GetPluginCapabilitiesResponse) + ret0, _ := ret[0].(*csi.GetPluginCapabilitiesResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -48,9 +48,9 @@ func (mr *MockIdentityServerMockRecorder) GetPluginCapabilities(arg0, arg1 inter } // 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) - ret0, _ := ret[0].(*v0.GetPluginInfoResponse) + ret0, _ := ret[0].(*csi.GetPluginInfoResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -61,9 +61,9 @@ func (mr *MockIdentityServerMockRecorder) GetPluginInfo(arg0, arg1 interface{}) } // 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) - ret0, _ := ret[0].(*v0.ProbeResponse) + ret0, _ := ret[0].(*csi.ProbeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -97,9 +97,9 @@ func (m *MockControllerServer) EXPECT() *MockControllerServerMockRecorder { } // 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) - ret0, _ := ret[0].(*v0.ControllerGetCapabilitiesResponse) + ret0, _ := ret[0].(*csi.ControllerGetCapabilitiesResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -110,9 +110,9 @@ func (mr *MockControllerServerMockRecorder) ControllerGetCapabilities(arg0, arg1 } // 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) - ret0, _ := ret[0].(*v0.ControllerPublishVolumeResponse) + ret0, _ := ret[0].(*csi.ControllerPublishVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -123,9 +123,9 @@ func (mr *MockControllerServerMockRecorder) ControllerPublishVolume(arg0, arg1 i } // 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) - ret0, _ := ret[0].(*v0.ControllerUnpublishVolumeResponse) + ret0, _ := ret[0].(*csi.ControllerUnpublishVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -136,9 +136,9 @@ func (mr *MockControllerServerMockRecorder) ControllerUnpublishVolume(arg0, arg1 } // 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) - ret0, _ := ret[0].(*v0.CreateSnapshotResponse) + ret0, _ := ret[0].(*csi.CreateSnapshotResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -149,9 +149,9 @@ func (mr *MockControllerServerMockRecorder) CreateSnapshot(arg0, arg1 interface{ } // 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) - ret0, _ := ret[0].(*v0.CreateVolumeResponse) + ret0, _ := ret[0].(*csi.CreateVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -162,9 +162,9 @@ func (mr *MockControllerServerMockRecorder) CreateVolume(arg0, arg1 interface{}) } // 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) - ret0, _ := ret[0].(*v0.DeleteSnapshotResponse) + ret0, _ := ret[0].(*csi.DeleteSnapshotResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -175,9 +175,9 @@ func (mr *MockControllerServerMockRecorder) DeleteSnapshot(arg0, arg1 interface{ } // 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) - ret0, _ := ret[0].(*v0.DeleteVolumeResponse) + ret0, _ := ret[0].(*csi.DeleteVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -188,9 +188,9 @@ func (mr *MockControllerServerMockRecorder) DeleteVolume(arg0, arg1 interface{}) } // 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) - ret0, _ := ret[0].(*v0.GetCapacityResponse) + ret0, _ := ret[0].(*csi.GetCapacityResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -201,9 +201,9 @@ func (mr *MockControllerServerMockRecorder) GetCapacity(arg0, arg1 interface{}) } // 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) - ret0, _ := ret[0].(*v0.ListSnapshotsResponse) + ret0, _ := ret[0].(*csi.ListSnapshotsResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -214,9 +214,9 @@ func (mr *MockControllerServerMockRecorder) ListSnapshots(arg0, arg1 interface{} } // 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) - ret0, _ := ret[0].(*v0.ListVolumesResponse) + ret0, _ := ret[0].(*csi.ListVolumesResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -227,9 +227,9 @@ func (mr *MockControllerServerMockRecorder) ListVolumes(arg0, arg1 interface{}) } // 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) - ret0, _ := ret[0].(*v0.ValidateVolumeCapabilitiesResponse) + ret0, _ := ret[0].(*csi.ValidateVolumeCapabilitiesResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -263,9 +263,9 @@ func (m *MockNodeServer) EXPECT() *MockNodeServerMockRecorder { } // 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) - ret0, _ := ret[0].(*v0.NodeGetCapabilitiesResponse) + ret0, _ := ret[0].(*csi.NodeGetCapabilitiesResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -275,36 +275,36 @@ func (mr *MockNodeServerMockRecorder) NodeGetCapabilities(arg0, arg1 interface{} 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) +// NodeGetInfo mocks base method +func (m *MockNodeServer) NodeGetInfo(arg0 context.Context, arg1 *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { + ret := m.ctrl.Call(m, "NodeGetInfo", arg0, arg1) + ret0, _ := ret[0].(*csi.NodeGetInfoResponse) 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 indicates an expected call of NodeGetInfo +func (mr *MockNodeServerMockRecorder) NodeGetInfo(arg0, arg1 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetInfo", reflect.TypeOf((*MockNodeServer)(nil).NodeGetInfo), arg0, arg1) } -// NodeGetInfo mocks base method -func (m *MockNodeServer) NodeGetInfo(arg0 context.Context, arg1 *v0.NodeGetInfoRequest) (*v0.NodeGetInfoResponse, error) { - ret := m.ctrl.Call(m, "NodeGetInfo", arg0, arg1) - ret0, _ := ret[0].(*v0.NodeGetInfoResponse) +// 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 } -// NodeGetInfo indicates an expected call of NodeGetInfo -func (mr *MockNodeServerMockRecorder) NodeGetInfo(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NodeGetInfo", reflect.TypeOf((*MockNodeServer)(nil).NodeGetInfo), arg0, arg1) +// 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 -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) - ret0, _ := ret[0].(*v0.NodePublishVolumeResponse) + ret0, _ := ret[0].(*csi.NodePublishVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -315,9 +315,9 @@ func (mr *MockNodeServerMockRecorder) NodePublishVolume(arg0, arg1 interface{}) } // 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) - ret0, _ := ret[0].(*v0.NodeStageVolumeResponse) + ret0, _ := ret[0].(*csi.NodeStageVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -328,9 +328,9 @@ func (mr *MockNodeServerMockRecorder) NodeStageVolume(arg0, arg1 interface{}) *g } // 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) - ret0, _ := ret[0].(*v0.NodeUnpublishVolumeResponse) + ret0, _ := ret[0].(*csi.NodeUnpublishVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -341,9 +341,9 @@ func (mr *MockNodeServerMockRecorder) NodeUnpublishVolume(arg0, arg1 interface{} } // 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) - ret0, _ := ret[0].(*v0.NodeUnstageVolumeResponse) + ret0, _ := ret[0].(*csi.NodeUnstageVolumeResponse) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/vendor/github.com/kubernetes-csi/csi-test/hack/_apitest/api_test.go b/vendor/github.com/kubernetes-csi/csi-test/hack/_apitest/api_test.go new file mode 100644 index 00000000..10ea5f35 --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/hack/_apitest/api_test.go @@ -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) +} diff --git a/vendor/github.com/kubernetes-csi/csi-test/hack/_embedded/embedded_test.go b/vendor/github.com/kubernetes-csi/csi-test/hack/_embedded/embedded_test.go new file mode 100644 index 00000000..bca267cb --- /dev/null +++ b/vendor/github.com/kubernetes-csi/csi-test/hack/_embedded/embedded_test.go @@ -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) + }) + }) +}) diff --git a/vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh b/vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh index 777250eb..baf4c304 100755 --- a/vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh +++ b/vendor/github.com/kubernetes-csi/csi-test/hack/e2e.sh @@ -35,7 +35,26 @@ runTestWithCreds() 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 make clean install || exit 1 @@ -47,4 +66,7 @@ rm -f $UDS runTestWithCreds "${UDS}" "${UDS}" rm -f $UDS +runTestAPI "${UDS}" +rm -f $UDS + exit 0 diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/README.md b/vendor/github.com/kubernetes-csi/csi-test/mock/README.md index d35e2d26..8274aa2c 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/mock/README.md +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/README.md @@ -1,2 +1,22 @@ # 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"} +``` diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go b/vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go index 14343d04..89835e11 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/cache/SnapshotCache.go @@ -4,7 +4,7 @@ import ( "strings" "sync" - "github.com/container-storage-interface/spec/lib/go/csi/v0" + "github.com/container-storage-interface/spec/lib/go/csi" ) type SnapshotCache interface { @@ -12,7 +12,7 @@ type SnapshotCache interface { Delete(i int) - List(status csi.SnapshotStatus_Type) []csi.Snapshot + List(ready bool) []csi.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] } -func (snap *snapshotCache) List(status csi.SnapshotStatus_Type) []csi.Snapshot { +func (snap *snapshotCache) List(ready bool) []csi.Snapshot { snap.snapshotsRWL.RLock() defer snap.snapshotsRWL.RUnlock() snapshots := make([]csi.Snapshot, 0) for _, v := range snap.snapshots { - if v.SnapshotCSI.GetStatus() != nil && v.SnapshotCSI.GetStatus().Type == status { + if v.SnapshotCSI.GetReadyToUse() { snapshots = append(snapshots, v.SnapshotCSI) } } @@ -71,7 +71,7 @@ func (snap *snapshotCache) FindSnapshot(k, v string) (int, Snapshot) { for i, vi := range snap.snapshots { switch k { case "id": - if strings.EqualFold(v, vi.SnapshotCSI.Id) { + if strings.EqualFold(v, vi.SnapshotCSI.GetSnapshotId()) { return i, vi } case "sourceVolumeId": diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/main.go b/vendor/github.com/kubernetes-csi/csi-test/mock/main.go index d66d1881..486d383b 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/mock/main.go +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/main.go @@ -16,6 +16,7 @@ limitations under the License. package main import ( + "flag" "fmt" "net" "os" @@ -28,6 +29,12 @@ import ( ) 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") if len(endpoint) == 0 { fmt.Println("CSI_ENDPOINT must be defined and must be a path") @@ -39,7 +46,7 @@ func main() { } // Create mock driver - s := service.New() + s := service.New(config) servers := &driver.CSIDriverServers{ Controller: s, Identity: s, diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go index 39176bdd..eace79f8 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/controller.go @@ -12,7 +12,7 @@ import ( "google.golang.org/grpc/codes" "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 ( @@ -62,7 +62,7 @@ func (s *service) CreateVolume( s.volsRWL.Lock() defer s.volsRWL.Unlock() s.vols = append(s.vols, v) - MockVolumes[v.Id] = Volume{ + MockVolumes[v.GetVolumeId()] = Volume{ VolumeCSI: v, NodeID: "", ISStaged: false, @@ -108,6 +108,10 @@ func (s *service) ControllerPublishVolume( req *csi.ControllerPublishVolumeRequest) ( *csi.ControllerPublishVolumeResponse, error) { + if s.config.DisableAttach { + return nil, status.Error(codes.Unimplemented, "ControllerPublish is not supported") + } + if len(req.VolumeId) == 0 { 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") // 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 roVal string - if ro, ok := v.Attributes[ReadOnlyKey]; ok { + if ro, ok := v.VolumeContext[ReadOnlyKey]; ok { roVal = ro } @@ -155,7 +159,7 @@ func (s *service) ControllerPublishVolume( } return &csi.ControllerPublishVolumeResponse{ - PublishInfo: map[string]string{ + PublishContext: map[string]string{ "device": device, "readonly": roVal, }, @@ -171,12 +175,12 @@ func (s *service) ControllerPublishVolume( // Publish the volume. device := "/dev/mock" - v.Attributes[devPathKey] = device - v.Attributes[ReadOnlyKey] = roVal + v.VolumeContext[devPathKey] = device + v.VolumeContext[ReadOnlyKey] = roVal s.vols[i] = v return &csi.ControllerPublishVolumeResponse{ - PublishInfo: map[string]string{ + PublishContext: map[string]string{ "device": device, "readonly": roVal, }, @@ -188,6 +192,10 @@ func (s *service) ControllerUnpublishVolume( req *csi.ControllerUnpublishVolumeRequest) ( *csi.ControllerUnpublishVolumeResponse, error) { + if s.config.DisableAttach { + return nil, status.Error(codes.Unimplemented, "ControllerPublish is not supported") + } + if len(req.VolumeId) == 0 { return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") } @@ -215,13 +223,13 @@ func (s *service) ControllerUnpublishVolume( devPathKey := path.Join(nodeID, "dev") // Check to see if the volume is already unpublished. - if v.Attributes[devPathKey] == "" { + if v.VolumeContext[devPathKey] == "" { return &csi.ControllerUnpublishVolumeResponse{}, nil } // Unpublish the volume. - delete(v.Attributes, devPathKey) - delete(v.Attributes, ReadOnlyKey) + delete(v.VolumeContext, devPathKey) + delete(v.VolumeContext, ReadOnlyKey) s.vols[i] = v return &csi.ControllerUnpublishVolumeResponse{}, nil @@ -244,7 +252,11 @@ func (s *service) ValidateVolumeCapabilities( } return &csi.ValidateVolumeCapabilitiesResponse{ - Supported: true, + Confirmed: &csi.ValidateVolumeCapabilitiesResponse_Confirmed{ + VolumeContext: req.GetVolumeContext(), + VolumeCapabilities: req.GetVolumeCapabilities(), + Parameters: req.GetParameters(), + }, }, nil } @@ -338,51 +350,56 @@ func (s *service) ControllerGetCapabilities( req *csi.ControllerGetCapabilitiesRequest) ( *csi.ControllerGetCapabilitiesResponse, error) { - return &csi.ControllerGetCapabilitiesResponse{ - Capabilities: []*csi.ControllerServiceCapability{ - { - Type: &csi.ControllerServiceCapability_Rpc{ - Rpc: &csi.ControllerServiceCapability_RPC{ - Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME, - }, + caps := []*csi.ControllerServiceCapability{ + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME, }, }, - { - Type: &csi.ControllerServiceCapability_Rpc{ - Rpc: &csi.ControllerServiceCapability_RPC{ - Type: csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME, - }, + }, + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_LIST_VOLUMES, }, }, - { - Type: &csi.ControllerServiceCapability_Rpc{ - Rpc: &csi.ControllerServiceCapability_RPC{ - Type: csi.ControllerServiceCapability_RPC_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_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_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_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 } @@ -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 // locking the service's snapshot slice for the duration of the // ListSnapshots RPC. - snapshots := s.snapshots.List(csi.SnapshotStatus_READY) + readyToUse := true + snapshots := s.snapshots.List(readyToUse) var ( ulenSnapshots = int32(len(snapshots)) diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go index c66d3b62..7e8735a9 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/identity.go @@ -3,7 +3,7 @@ package service import ( "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" ) @@ -13,7 +13,7 @@ func (s *service) GetPluginInfo( *csi.GetPluginInfoResponse, error) { return &csi.GetPluginInfoResponse{ - Name: Name, + Name: s.config.DriverName, VendorVersion: VendorVersion, Manifest: Manifest, }, nil diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go index 0321c740..886a219a 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/node.go @@ -8,7 +8,7 @@ import ( "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( @@ -16,11 +16,15 @@ func (s *service) NodeStageVolume( req *csi.NodeStageVolumeRequest) ( *csi.NodeStageVolumeResponse, error) { - device, ok := req.PublishInfo["device"] + device, ok := req.PublishContext["device"] if !ok { - return nil, status.Error( - codes.InvalidArgument, - "stage volume info 'device' key required") + if s.config.DisableAttach { + device = "mock device" + } else { + return nil, status.Error( + codes.InvalidArgument, + "stage volume info 'device' key required") + } } if len(req.GetVolumeId()) == 0 { @@ -48,14 +52,14 @@ func (s *service) NodeStageVolume( nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath) // 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" // if the capabilities don't match. return &csi.NodeStageVolumeResponse{}, nil } // Stage the volume. - v.Attributes[nodeStgPathKey] = device + v.VolumeContext[nodeStgPathKey] = device s.vols[i] = v return &csi.NodeStageVolumeResponse{}, nil @@ -87,12 +91,12 @@ func (s *service) NodeUnstageVolume( nodeStgPathKey := path.Join(s.nodeID, req.StagingTargetPath) // Check to see if the volume has already been unstaged. - if v.Attributes[nodeStgPathKey] == "" { + if v.VolumeContext[nodeStgPathKey] == "" { return &csi.NodeUnstageVolumeResponse{}, nil } // Unpublish the volume. - delete(v.Attributes, nodeStgPathKey) + delete(v.VolumeContext, nodeStgPathKey) s.vols[i] = v return &csi.NodeUnstageVolumeResponse{}, nil @@ -103,11 +107,15 @@ func (s *service) NodePublishVolume( req *csi.NodePublishVolumeRequest) ( *csi.NodePublishVolumeResponse, error) { - device, ok := req.PublishInfo["device"] + device, ok := req.PublishContext["device"] if !ok { - return nil, status.Error( - codes.InvalidArgument, - "publish volume info 'device' key required") + if s.config.DisableAttach { + device = "mock device" + } else { + return nil, status.Error( + codes.InvalidArgument, + "stage volume info 'device' key required") + } } if len(req.GetVolumeId()) == 0 { @@ -135,7 +143,7 @@ func (s *service) NodePublishVolume( nodeMntPathKey := path.Join(s.nodeID, req.TargetPath) // 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 // the Mock driver supporting only RW mode. @@ -148,9 +156,9 @@ func (s *service) NodePublishVolume( // Publish the volume. if req.GetStagingTargetPath() != "" { - v.Attributes[nodeMntPathKey] = req.GetStagingTargetPath() + v.VolumeContext[nodeMntPathKey] = req.GetStagingTargetPath() } else { - v.Attributes[nodeMntPathKey] = device + v.VolumeContext[nodeMntPathKey] = device } s.vols[i] = v @@ -182,27 +190,17 @@ func (s *service) NodeUnpublishVolume( nodeMntPathKey := path.Join(s.nodeID, req.TargetPath) // Check to see if the volume has already been unpublished. - if v.Attributes[nodeMntPathKey] == "" { + if v.VolumeContext[nodeMntPathKey] == "" { return &csi.NodeUnpublishVolumeResponse{}, nil } // Unpublish the volume. - delete(v.Attributes, nodeMntPathKey) + delete(v.VolumeContext, nodeMntPathKey) s.vols[i] = v return &csi.NodeUnpublishVolumeResponse{}, nil } -func (s *service) NodeGetId( - ctx context.Context, - req *csi.NodeGetIdRequest) ( - *csi.NodeGetIdResponse, error) { - - return &csi.NodeGetIdResponse{ - NodeId: s.nodeID, - }, nil -} - func (s *service) NodeGetCapabilities( ctx context.Context, req *csi.NodeGetCapabilitiesRequest) ( @@ -230,7 +228,17 @@ func (s *service) NodeGetCapabilities( func (s *service) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { - return &csi.NodeGetInfoResponse{ + csiNodeResponse := &csi.NodeGetInfoResponse{ 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 + } diff --git a/vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go b/vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go index c9f4f7b2..2254ccb8 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go +++ b/vendor/github.com/kubernetes-csi/csi-test/mock/service/service.go @@ -5,11 +5,12 @@ import ( "strings" "sync" "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" "golang.org/x/net/context" + + "github.com/golang/protobuf/ptypes" ) const ( @@ -25,6 +26,12 @@ var Manifest = map[string]string{ "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. type Service interface { csi.ControllerServer @@ -40,6 +47,7 @@ type service struct { volsNID uint64 snapshots cache.SnapshotCache snapshotsNID uint64 + config Config } type Volume struct { @@ -55,8 +63,11 @@ type Volume struct { var MockVolumes map[string]Volume // New returns a new Service. -func New() Service { - s := &service{nodeID: Name} +func New(config Config) Service { + s := &service{ + nodeID: config.DriverName, + config: config, + } s.snapshots = cache.NewSnapshotCache() s.vols = []csi.Volume{ s.newVolume("Mock Volume 1", gib100), @@ -83,8 +94,8 @@ const ( func (s *service) newVolume(name string, capcity int64) csi.Volume { return csi.Volume{ - Id: fmt.Sprintf("%d", atomic.AddUint64(&s.volsNID, 1)), - Attributes: map[string]string{"name": name}, + VolumeId: fmt.Sprintf("%d", atomic.AddUint64(&s.volsNID, 1)), + VolumeContext: map[string]string{"name": name}, CapacityBytes: capcity, } } @@ -101,11 +112,11 @@ func (s *service) findVolNoLock(k, v string) (volIdx int, volInfo csi.Volume) { for i, vi := range s.vols { switch k { case "id": - if strings.EqualFold(v, vi.Id) { + if strings.EqualFold(v, vi.GetVolumeId()) { return i, vi } 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 } } @@ -121,17 +132,16 @@ func (s *service) findVolByName( } func (s *service) newSnapshot(name, sourceVolumeId string, parameters map[string]string) cache.Snapshot { + + ptime := ptypes.TimestampNow() return cache.Snapshot{ Name: name, Parameters: parameters, SnapshotCSI: csi.Snapshot{ - Id: fmt.Sprintf("%d", atomic.AddUint64(&s.snapshotsNID, 1)), - CreatedAt: time.Now().UnixNano(), + SnapshotId: fmt.Sprintf("%d", atomic.AddUint64(&s.snapshotsNID, 1)), + CreationTime: ptime, SourceVolumeId: sourceVolumeId, - Status: &csi.SnapshotStatus{ - Type: csi.SnapshotStatus_READY, - Details: "snapshot ready", - }, + ReadyToUse: true, }, } } diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md index de4ae501..fd30f192 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/README.md @@ -39,13 +39,13 @@ var _ = Describe("MyCSIDriver", func () { Context("Config A", func () { var config &sanity.Config - BeforeEach() { - ... setup driver and config... - } + BeforeEach(func() { + //... setup driver and config... + }) - AfterEach() { - ...tear down driver... - } + AfterEach(func() { + //...tear down driver... + }) Describe("CSI sanity", func() { sanity.GinkgoTest(config) @@ -53,7 +53,7 @@ var _ = Describe("MyCSIDriver", func () { }) Context("Config B", func () { - ... + // other configs }) }) ``` diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go index 699efe7b..65a30334 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/cleanup.go @@ -20,7 +20,7 @@ import ( "context" "log" - "github.com/container-storage-interface/spec/lib/go/csi/v0" + "github.com/container-storage-interface/spec/lib/go/csi" . "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 // the given name if CreateVolume was successful. func (cl *Cleanup) MaybeRegisterVolume(name string, vol *csi.CreateVolumeResponse, err error) { - if err == nil && vol.GetVolume().GetId() != "" { - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + if err == nil && vol.GetVolume().GetVolumeId() != "" { + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) } } @@ -112,7 +112,7 @@ func (cl *Cleanup) DeleteVolumes() { &csi.ControllerUnpublishVolumeRequest{ VolumeId: info.VolumeID, NodeId: info.NodeID, - ControllerUnpublishSecrets: cl.Context.Secrets.ControllerUnpublishVolumeSecret, + Secrets: cl.Context.Secrets.ControllerUnpublishVolumeSecret, }, ); err != nil { logger.Printf("warning: ControllerUnpublishVolume: %s", err) @@ -122,8 +122,8 @@ func (cl *Cleanup) DeleteVolumes() { if _, err := cl.ControllerClient.DeleteVolume( ctx, &csi.DeleteVolumeRequest{ - VolumeId: info.VolumeID, - ControllerDeleteSecrets: cl.Context.Secrets.DeleteVolumeSecret, + VolumeId: info.VolumeID, + Secrets: cl.Context.Secrets.DeleteVolumeSecret, }, ); err != nil { logger.Printf("error: DeleteVolume: %s", err) diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go index 294a1e0d..022e1e6d 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go @@ -23,11 +23,12 @@ import ( "google.golang.org/grpc/codes" "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/gomega" - "strconv" ) const ( @@ -35,6 +36,8 @@ const ( // provisioned volumes. 10GB by default, can be overridden by // setting Config.TestVolumeSize. DefTestVolumeSize int64 = 10 * 1024 * 1024 * 1024 + + MaxNameLength int = 128 ) func TestVolumeSize(sc *SanityContext) int64 { @@ -46,14 +49,14 @@ func TestVolumeSize(sc *SanityContext) int64 { func verifyVolumeInfo(v *csi.Volume) { Expect(v).NotTo(BeNil()) - Expect(v.GetId()).NotTo(BeEmpty()) + Expect(v.GetVolumeId()).NotTo(BeEmpty()) } func verifySnapshotInfo(snapshot *csi.Snapshot) { Expect(snapshot).NotTo(BeNil()) - Expect(snapshot.GetId()).NotTo(BeEmpty()) + Expect(snapshot.GetSnapshotId()).NotTo(BeEmpty()) Expect(snapshot.GetSourceVolumeId()).NotTo(BeEmpty()) - Expect(snapshot.GetCreatedAt()).NotTo(BeZero()) + Expect(snapshot.GetCreationTime()).NotTo(BeZero()) } func isControllerCapabilitySupported( @@ -121,6 +124,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { case csi.ControllerServiceCapability_RPC_GET_CAPACITY: case csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT: case csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS: + case csi.ControllerServiceCapability_RPC_PUBLISH_READONLY: default: Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType())) } @@ -182,7 +186,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { vol, err := c.CreateVolume( context.Background(), &csi.CreateVolumeRequest{ - ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + Secrets: sc.Secrets.CreateVolumeSecret, + Parameters: sc.Config.TestVolumeParameters, }, ) cl.MaybeRegisterVolume("", vol, err) @@ -198,8 +203,9 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { vol, err := c.CreateVolume( context.Background(), &csi.CreateVolumeRequest{ - Name: name, - ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + Name: name, + Secrets: sc.Secrets.CreateVolumeSecret, + Parameters: sc.Config.TestVolumeParameters, }, ) cl.MaybeRegisterVolume(name, vol, err) @@ -229,22 +235,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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) By("cleaning up deleting the volume") _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -273,7 +280,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { CapacityRange: &csi.CapacityRange{ RequiredBytes: TestVolumeSize(sc), }, - ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + Secrets: sc.Secrets.CreateVolumeSecret, + Parameters: sc.Config.TestVolumeParameters, }, ) if serverError, ok := status.FromError(err); ok && @@ -283,8 +291,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { Expect(err).NotTo(HaveOccurred()) Expect(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", TestVolumeSize(sc))) By("cleaning up deleting the volume") @@ -292,14 +300,14 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) 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") name := uniqueString("sanity-controller-create-twice") @@ -322,14 +330,15 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { CapacityRange: &csi.CapacityRange{ RequiredBytes: size, }, - ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + Secrets: sc.Secrets.CreateVolumeSecret, + Parameters: sc.Config.TestVolumeParameters, }, ) Expect(err).NotTo(HaveOccurred()) Expect(vol1).NotTo(BeNil()) Expect(vol1.GetVolume()).NotTo(BeNil()) - Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()}) + Expect(vol1.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetVolumeId()}) Expect(vol1.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size)) vol2, err := c.CreateVolume( @@ -349,29 +358,30 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { CapacityRange: &csi.CapacityRange{ RequiredBytes: size, }, - ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + Secrets: sc.Secrets.CreateVolumeSecret, + Parameters: sc.Config.TestVolumeParameters, }, ) Expect(err).NotTo(HaveOccurred()) Expect(vol2).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(vol1.GetVolume().GetId()).To(Equal(vol2.GetVolume().GetId())) + Expect(vol1.GetVolume().GetVolumeId()).To(Equal(vol2.GetVolume().GetVolumeId())) By("cleaning up deleting the volume") _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol1.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol1.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) 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") name := uniqueString("sanity-controller-create-twice-different") @@ -395,14 +405,15 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { RequiredBytes: size1, LimitBytes: size1, }, - ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + Secrets: sc.Secrets.CreateVolumeSecret, + Parameters: sc.Config.TestVolumeParameters, }, ) Expect(err).ToNot(HaveOccurred()) Expect(vol1).NotTo(BeNil()) Expect(vol1.GetVolume()).NotTo(BeNil()) - Expect(vol1.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetId()}) + Expect(vol1.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetVolumeId()}) size2 := 2 * TestVolumeSize(sc) _, err = c.CreateVolume( @@ -423,7 +434,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { RequiredBytes: size2, LimitBytes: size2, }, - ControllerCreateSecrets: sc.Secrets.CreateVolumeSecret, + Secrets: sc.Secrets.CreateVolumeSecret, + Parameters: sc.Config.TestVolumeParameters, }, ) Expect(err).To(HaveOccurred()) @@ -436,8 +448,59 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol1.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol1.GetVolume().GetVolumeId(), + 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()) @@ -457,7 +520,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err := c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -472,8 +535,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err := c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: "reallyfakevolumeid", - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: "reallyfakevolumeid", + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -499,14 +562,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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) // Delete Volume By("deleting a volume") @@ -514,8 +578,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -570,21 +634,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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) // ValidateVolumeCapabilities By("validating volume capabilities") valivolcap, err := c.ValidateVolumeCapabilities( context.Background(), &csi.ValidateVolumeCapabilitiesRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), VolumeCapabilities: []*csi.VolumeCapability{ { AccessType: &csi.VolumeCapability_Mount{ @@ -598,15 +663,20 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { }) Expect(err).NotTo(HaveOccurred()) 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") _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -651,7 +721,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err := c.ControllerPublishVolume( context.Background(), &csi.ControllerPublishVolumeRequest{ - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -666,8 +736,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err := c.ControllerPublishVolume( context.Background(), &csi.ControllerPublishVolumeRequest{ - VolumeId: "id", - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + VolumeId: "id", + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -684,7 +754,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { &csi.ControllerPublishVolumeRequest{ VolumeId: "id", NodeId: "fakenode", - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -714,19 +784,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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) By("getting a node id") - nid, err := n.NodeGetId( + nid, err := n.NodeGetInfo( context.Background(), - &csi.NodeGetIdRequest{}) + &csi.NodeGetInfoRequest{}) Expect(err).NotTo(HaveOccurred()) Expect(nid).NotTo(BeNil()) Expect(nid.GetNodeId()).NotTo(BeEmpty()) @@ -737,7 +808,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { conpubvol, err := c.ControllerPublishVolume( context.Background(), &csi.ControllerPublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), NodeId: nid.GetNodeId(), VolumeCapability: &csi.VolumeCapability{ AccessType: &csi.VolumeCapability_Mount{ @@ -747,12 +818,12 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - Readonly: false, - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + Readonly: false, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) 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()) By("cleaning up unpublishing the volume") @@ -760,10 +831,10 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { conunpubvol, err := c.ControllerUnpublishVolume( context.Background(), &csi.ControllerUnpublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), // NodeID is optional in ControllerUnpublishVolume - NodeId: nid.GetNodeId(), - ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + NodeId: nid.GetNodeId(), + Secrets: sc.Secrets.ControllerUnpublishVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -774,8 +845,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -799,8 +870,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - Readonly: false, - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + Readonly: false, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -831,14 +902,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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) // ControllerPublishVolume By("calling controllerpublish on that volume") @@ -846,7 +918,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { conpubvol, err := c.ControllerPublishVolume( context.Background(), &csi.ControllerPublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), NodeId: "some-fake-node-id", VolumeCapability: &csi.VolumeCapability{ AccessType: &csi.VolumeCapability_Mount{ @@ -856,8 +928,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - Readonly: false, - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + Readonly: false, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -872,8 +944,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -900,19 +972,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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) By("getting a node id") - nid, err := n.NodeGetId( + nid, err := n.NodeGetInfo( context.Background(), - &csi.NodeGetIdRequest{}) + &csi.NodeGetInfoRequest{}) Expect(err).NotTo(HaveOccurred()) Expect(nid).NotTo(BeNil()) Expect(nid.GetNodeId()).NotTo(BeEmpty()) @@ -921,7 +994,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { By("calling controllerpublish on that volume") pubReq := &csi.ControllerPublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), NodeId: nid.GetNodeId(), VolumeCapability: &csi.VolumeCapability{ AccessType: &csi.VolumeCapability_Mount{ @@ -931,8 +1004,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - Readonly: false, - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + Readonly: false, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, } conpubvol, err := c.ControllerPublishVolume(context.Background(), pubReq) @@ -955,10 +1028,10 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { conunpubvol, err := c.ControllerUnpublishVolume( context.Background(), &csi.ControllerUnpublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), // NodeID is optional in ControllerUnpublishVolume - NodeId: nid.GetNodeId(), - ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + NodeId: nid.GetNodeId(), + Secrets: sc.Secrets.ControllerUnpublishVolumeSecret, }, ) @@ -970,8 +1043,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -991,7 +1064,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err := c.ControllerUnpublishVolume( context.Background(), &csi.ControllerUnpublishVolumeRequest{ - ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + Secrets: sc.Secrets.ControllerUnpublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -1021,19 +1094,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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) By("getting a node id") - nid, err := n.NodeGetId( + nid, err := n.NodeGetInfo( context.Background(), - &csi.NodeGetIdRequest{}) + &csi.NodeGetInfoRequest{}) Expect(err).NotTo(HaveOccurred()) Expect(nid).NotTo(BeNil()) Expect(nid.GetNodeId()).NotTo(BeEmpty()) @@ -1044,7 +1118,7 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { conpubvol, err := c.ControllerPublishVolume( context.Background(), &csi.ControllerPublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), NodeId: nid.GetNodeId(), VolumeCapability: &csi.VolumeCapability{ AccessType: &csi.VolumeCapability_Mount{ @@ -1054,12 +1128,12 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - Readonly: false, - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + Readonly: false, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) 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()) // ControllerUnpublishVolume @@ -1068,10 +1142,10 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { conunpubvol, err := c.ControllerUnpublishVolume( context.Background(), &csi.ControllerUnpublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), // NodeID is optional in ControllerUnpublishVolume - NodeId: nid.GetNodeId(), - ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + NodeId: nid.GetNodeId(), + Secrets: sc.Secrets.ControllerUnpublishVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -1082,8 +1156,8 @@ var _ = DescribeSanity("Controller Service", func(sc *SanityContext) { _, err = c.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -1125,28 +1199,28 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte Expect(err).NotTo(HaveOccurred()) 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) Expect(err).NotTo(HaveOccurred()) snapshots, err := c.ListSnapshots( context.Background(), - &csi.ListSnapshotsRequest{SnapshotId: snapshot.GetSnapshot().GetId()}) + &csi.ListSnapshotsRequest{SnapshotId: snapshot.GetSnapshot().GetSnapshotId()}) Expect(err).NotTo(HaveOccurred()) Expect(snapshots).NotTo(BeNil()) Expect(len(snapshots.GetEntries())).To(BeNumerically("==", 1)) verifySnapshotInfo(snapshots.GetEntries()[0].GetSnapshot()) - Expect(snapshots.GetEntries()[0].GetSnapshot().GetId()).To(Equal(snapshot.GetSnapshot().GetId())) - - By("cleaning up deleting the volume") - delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetId()) - _, err = c.DeleteVolume(context.Background(), delVolReq) - Expect(err).NotTo(HaveOccurred()) + Expect(snapshots.GetEntries()[0].GetSnapshot().GetSnapshotId()).To(Equal(snapshot.GetSnapshot().GetSnapshotId())) By("cleaning up deleting the snapshot") - delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.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) + Expect(err).NotTo(HaveOccurred()) }) It("should return empty when the specify snapshot id is not exist", func() { @@ -1167,7 +1241,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte Expect(err).NotTo(HaveOccurred()) 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) Expect(err).NotTo(HaveOccurred()) @@ -1182,12 +1256,12 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte } By("cleaning up deleting the snapshot") - delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId()) _, err = c.DeleteSnapshot(context.Background(), delSnapReq) Expect(err).NotTo(HaveOccurred()) 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()) }) @@ -1202,46 +1276,6 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte 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() { // List Snapshots before creating new snapshots. snapshots, err := c.ListSnapshots( @@ -1258,7 +1292,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte Expect(err).NotTo(HaveOccurred()) 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) Expect(err).NotTo(HaveOccurred()) Expect(snapshot).NotTo(BeNil()) @@ -1272,12 +1306,12 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte Expect(len(snapshots.GetEntries())).To(Equal(totalSnapshots + 1)) By("cleaning up deleting the snapshot") - delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId()) _, err = c.DeleteSnapshot(context.Background(), delSnapReq) Expect(err).NotTo(HaveOccurred()) 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()) @@ -1326,7 +1360,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte Expect(volume).NotTo(BeNil()) 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) Expect(err).NotTo(HaveOccurred()) Expect(snapshot).NotTo(BeNil()) @@ -1349,7 +1383,6 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte nextToken := snapshots.GetNextToken() - Expect(nextToken).To(Equal(strconv.Itoa(maxEntries))) Expect(len(snapshots.GetEntries())).To(Equal(maxEntries)) // Request list snapshots with starting_token and no max entries. @@ -1369,7 +1402,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte By("cleaning up deleting the snapshots") for _, snap := range createSnapshots { - delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetId()) + delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetSnapshotId()) _, err = c.DeleteSnapshot(context.Background(), delSnapReq) Expect(err).NotTo(HaveOccurred()) } @@ -1377,7 +1410,7 @@ var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *SanityConte By("cleaning up deleting the volumes") for _, vol := range createVols { - delVolReq := MakeDeleteVolumeReq(sc, vol.GetId()) + delVolReq := MakeDeleteVolumeReq(sc, vol.GetVolumeId()) _, err = c.DeleteVolume(context.Background(), delVolReq) Expect(err).NotTo(HaveOccurred()) } @@ -1404,7 +1437,7 @@ var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *SanityCont req := &csi.DeleteSnapshotRequest{} if sc.Secrets != nil { - req.DeleteSnapshotSecrets = sc.Secrets.DeleteSnapshotSecret + req.Secrets = sc.Secrets.DeleteSnapshotSecret } _, err := c.DeleteSnapshot(context.Background(), req) @@ -1431,19 +1464,19 @@ var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *SanityCont // Create Snapshot First 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) Expect(err).NotTo(HaveOccurred()) Expect(snapshot).NotTo(BeNil()) verifySnapshotInfo(snapshot.GetSnapshot()) By("cleaning up deleting the snapshot") - delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetId()) + delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId()) _, err = c.DeleteSnapshot(context.Background(), delSnapReq) Expect(err).NotTo(HaveOccurred()) 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()) }) @@ -1469,7 +1502,7 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont } if sc.Secrets != nil { - req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret + req.Secrets = sc.Secrets.CreateSnapshotSecret } _, err := c.CreateSnapshot(context.Background(), req) @@ -1486,7 +1519,7 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont } if sc.Secrets != nil { - req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret + req.Secrets = sc.Secrets.CreateSnapshotSecret } _, err := c.CreateSnapshot(context.Background(), req) @@ -1504,7 +1537,7 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont Expect(err).NotTo(HaveOccurred()) 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) Expect(err).NotTo(HaveOccurred()) Expect(snap1).NotTo(BeNil()) @@ -1516,12 +1549,12 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont verifySnapshotInfo(snap2.GetSnapshot()) By("cleaning up deleting the snapshot") - delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetId()) + 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().GetId()) + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId()) _, err = c.DeleteVolume(context.Background(), delVolReq) Expect(err).NotTo(HaveOccurred()) }) @@ -1533,14 +1566,17 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont Expect(err).ToNot(HaveOccurred()) 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) Expect(err).NotTo(HaveOccurred()) Expect(snap1).NotTo(BeNil()) 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") - req2 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", "test001", nil) + req2 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume2.GetVolume().GetVolumeId(), nil) _, err = c.CreateSnapshot(context.Background(), req2) Expect(err).To(HaveOccurred()) serverError, ok := status.FromError(err) @@ -1548,12 +1584,48 @@ var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *SanityCont Expect(serverError.Code()).To(Equal(codes.AlreadyExists)) By("cleaning up deleting the snapshot") - delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetId()) + 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) + 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().GetId()) + delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId()) _, err = c.DeleteVolume(context.Background(), delVolReq) Expect(err).NotTo(HaveOccurred()) }) @@ -1578,10 +1650,11 @@ func MakeCreateVolumeReq(sc *SanityContext, name string) *csi.CreateVolumeReques RequiredBytes: size1, LimitBytes: size1, }, + Parameters: sc.Config.TestVolumeParameters, } if sc.Secrets != nil { - req.ControllerCreateSecrets = sc.Secrets.CreateVolumeSecret + req.Secrets = sc.Secrets.CreateVolumeSecret } return req @@ -1595,7 +1668,7 @@ func MakeCreateSnapshotReq(sc *SanityContext, name, sourceVolumeId string, param } if sc.Secrets != nil { - req.CreateSnapshotSecrets = sc.Secrets.CreateSnapshotSecret + req.Secrets = sc.Secrets.CreateSnapshotSecret } return req @@ -1607,7 +1680,7 @@ func MakeDeleteSnapshotReq(sc *SanityContext, id string) *csi.DeleteSnapshotRequ } if sc.Secrets != nil { - delSnapReq.DeleteSnapshotSecrets = sc.Secrets.DeleteSnapshotSecret + delSnapReq.Secrets = sc.Secrets.DeleteSnapshotSecret } return delSnapReq @@ -1619,7 +1692,7 @@ func MakeDeleteVolumeReq(sc *SanityContext, id string) *csi.DeleteVolumeRequest } if sc.Secrets != nil { - delVolReq.ControllerDeleteSecrets = sc.Secrets.DeleteVolumeSecret + delVolReq.Secrets = sc.Secrets.DeleteVolumeSecret } return delVolReq diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go index e60439b3..c1a5eb7e 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/identity.go @@ -24,7 +24,7 @@ import ( "google.golang.org/grpc/codes" "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/gomega" @@ -51,7 +51,7 @@ var _ = DescribeSanity("Identity Service", func(sc *SanityContext) { for _, cap := range res.GetCapabilities() { switch cap.GetService().GetType() { case csi.PluginCapability_Service_CONTROLLER_SERVICE: - case csi.PluginCapability_Service_ACCESSIBILITY_CONSTRAINTS: + case csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS: default: Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetService().GetType())) } diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go index a98f5151..9bd9194b 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/node.go @@ -23,7 +23,7 @@ import ( "google.golang.org/grpc/codes" "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/gomega" @@ -119,6 +119,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { switch cap.GetRpc().GetType() { case csi.NodeServiceCapability_RPC_UNKNOWN: case csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME: + case csi.NodeServiceCapability_RPC_GET_VOLUME_STATS: default: 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() { var ( i csi.IdentityClient @@ -146,7 +135,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { BeforeEach(func() { 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() { @@ -170,7 +159,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { _, err := c.NodePublishVolume( context.Background(), &csi.NodePublishVolumeRequest{ - NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + Secrets: sc.Secrets.NodePublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -184,8 +173,8 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { _, err := c.NodePublishVolume( context.Background(), &csi.NodePublishVolumeRequest{ - VolumeId: "id", - NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + VolumeId: "id", + Secrets: sc.Secrets.NodePublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -199,9 +188,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { _, err := c.NodePublishVolume( context.Background(), &csi.NodePublishVolumeRequest{ - VolumeId: "id", - TargetPath: sc.Config.TargetPath, - NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + VolumeId: "id", + TargetPath: sc.Config.TargetPath, + Secrets: sc.Secrets.NodePublishVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -266,10 +255,10 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - PublishInfo: map[string]string{ + PublishContext: map[string]string{ "device": device, }, - NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + Secrets: sc.Secrets.NodeStageVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -292,10 +281,10 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - PublishInfo: map[string]string{ + PublishContext: map[string]string{ "device": device, }, - NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + Secrets: sc.Secrets.NodeStageVolumeSecret, }, ) Expect(err).To(HaveOccurred()) @@ -311,10 +300,10 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { &csi.NodeStageVolumeRequest{ VolumeId: "id", StagingTargetPath: sc.Config.StagingPath, - PublishInfo: map[string]string{ + PublishContext: map[string]string{ "device": device, }, - NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + Secrets: sc.Secrets.NodeStageVolumeSecret, }, ) 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(vol).NotTo(BeNil()) Expect(vol.GetVolume()).NotTo(BeNil()) - Expect(vol.GetVolume().GetId()).NotTo(BeEmpty()) - cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetId()}) + Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty()) + cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()}) By("getting a node id") - nid, err := c.NodeGetId( + nid, err := c.NodeGetInfo( context.Background(), - &csi.NodeGetIdRequest{}) + &csi.NodeGetInfoRequest{}) Expect(err).NotTo(HaveOccurred()) Expect(nid).NotTo(BeNil()) Expect(nid.GetNodeId()).NotTo(BeEmpty()) @@ -404,7 +393,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { conpubvol, err = s.ControllerPublishVolume( context.Background(), &csi.ControllerPublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), NodeId: nid.GetNodeId(), VolumeCapability: &csi.VolumeCapability{ AccessType: &csi.VolumeCapability_Mount{ @@ -414,13 +403,13 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - VolumeAttributes: vol.GetVolume().GetAttributes(), - Readonly: false, - ControllerPublishSecrets: sc.Secrets.ControllerPublishVolumeSecret, + VolumeContext: vol.GetVolume().GetVolumeContext(), + Readonly: false, + Secrets: sc.Secrets.ControllerPublishVolumeSecret, }, ) 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()) } // NodeStageVolume @@ -429,7 +418,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { nodestagevol, err := c.NodeStageVolume( context.Background(), &csi.NodeStageVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), VolumeCapability: &csi.VolumeCapability{ AccessType: &csi.VolumeCapability_Mount{ Mount: &csi.VolumeCapability_MountVolume{}, @@ -439,9 +428,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { }, }, StagingTargetPath: sc.Config.StagingPath, - VolumeAttributes: vol.GetVolume().GetAttributes(), - PublishInfo: conpubvol.GetPublishInfo(), - NodeStageSecrets: sc.Secrets.NodeStageVolumeSecret, + VolumeContext: vol.GetVolume().GetVolumeContext(), + PublishContext: conpubvol.GetPublishContext(), + Secrets: sc.Secrets.NodeStageVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -456,7 +445,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { nodepubvol, err := c.NodePublishVolume( context.Background(), &csi.NodePublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), TargetPath: sc.Config.TargetPath, StagingTargetPath: stagingPath, VolumeCapability: &csi.VolumeCapability{ @@ -467,9 +456,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER, }, }, - VolumeAttributes: vol.GetVolume().GetAttributes(), - PublishInfo: conpubvol.GetPublishInfo(), - NodePublishSecrets: sc.Secrets.NodePublishVolumeSecret, + VolumeContext: vol.GetVolume().GetVolumeContext(), + PublishContext: conpubvol.GetPublishContext(), + Secrets: sc.Secrets.NodePublishVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -480,7 +469,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { nodeunpubvol, err := c.NodeUnpublishVolume( context.Background(), &csi.NodeUnpublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), TargetPath: sc.Config.TargetPath, }) Expect(err).NotTo(HaveOccurred()) @@ -491,7 +480,7 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { nodeunstagevol, err := c.NodeUnstageVolume( context.Background(), &csi.NodeUnstageVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), StagingTargetPath: sc.Config.StagingPath, }, ) @@ -505,9 +494,9 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { controllerunpubvol, err := s.ControllerUnpublishVolume( context.Background(), &csi.ControllerUnpublishVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), + VolumeId: vol.GetVolume().GetVolumeId(), NodeId: nid.GetNodeId(), - ControllerUnpublishSecrets: sc.Secrets.ControllerUnpublishVolumeSecret, + Secrets: sc.Secrets.ControllerUnpublishVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) @@ -519,8 +508,8 @@ var _ = DescribeSanity("Node Service", func(sc *SanityContext) { _, err = s.DeleteVolume( context.Background(), &csi.DeleteVolumeRequest{ - VolumeId: vol.GetVolume().GetId(), - ControllerDeleteSecrets: sc.Secrets.DeleteVolumeSecret, + VolumeId: vol.GetVolume().GetVolumeId(), + Secrets: sc.Secrets.DeleteVolumeSecret, }, ) Expect(err).NotTo(HaveOccurred()) diff --git a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go index 9a4de8be..e3c1684e 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go +++ b/vendor/github.com/kubernetes-csi/csi-test/pkg/sanity/sanity.go @@ -47,11 +47,14 @@ type CSISecrets struct { // Config provides the configuration for the sanity tests. It // needs to be initialized by the user of the sanity package. type Config struct { - TargetPath string - StagingPath string - Address string - SecretsFile string - TestVolumeSize int64 + TargetPath string + StagingPath string + Address string + SecretsFile string + + TestVolumeSize int64 + TestVolumeParametersFile string + TestVolumeParameters map[string]string } // SanityContext holds the variables that each test can depend on. It @@ -60,11 +63,25 @@ type SanityContext struct { Config *Config Conn *grpc.ClientConn Secrets *CSISecrets + + connAddress string } // Test will test the CSI driver at the specified address by // setting up a Ginkgo suite and running it. func Test(t *testing.T, reqConfig *Config) { + 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{ Config: reqConfig, } @@ -92,9 +109,17 @@ func (sc *SanityContext) setup() { sc.Secrets = &CSISecrets{} } - By("connecting to CSI driver") - sc.Conn, err = utils.Connect(sc.Config.Address) - Expect(err).NotTo(HaveOccurred()) + // It is possible that a test sets sc.Config.Address + // dynamically (and differently!) in a BeforeEach, so only + // 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") err = createMountTargetLocation(sc.Config.TargetPath) @@ -106,10 +131,16 @@ func (sc *SanityContext) setup() { } func (sc *SanityContext) teardown() { - if sc.Conn != nil { - sc.Conn.Close() - sc.Conn = nil - } + // We intentionally do not close the connection to the CSI + // driver here because the large amount of connection attempts + // 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 { diff --git a/vendor/github.com/kubernetes-csi/csi-test/test/co_test.go b/vendor/github.com/kubernetes-csi/csi-test/test/co_test.go index 5a2bbe27..03b0f052 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/test/co_test.go +++ b/vendor/github.com/kubernetes-csi/csi-test/test/co_test.go @@ -21,7 +21,7 @@ import ( "reflect" "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/protobuf/proto" mock_driver "github.com/kubernetes-csi/csi-test/driver" @@ -157,7 +157,7 @@ func TestGRPCAttach(t *testing.T) { // Setup mock outout out := &csi.ControllerPublishVolumeResponse{ - PublishInfo: publishVolumeInfo, + PublishContext: publishVolumeInfo, } // Setup expectation @@ -181,7 +181,7 @@ func TestGRPCAttach(t *testing.T) { t.Errorf("Error: %s", err.Error()) } - info := r.GetPublishInfo() + info := r.GetPublishContext() if !reflect.DeepEqual(info, publishVolumeInfo) { t.Errorf("Invalid publish info: %v", info) } diff --git a/vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go b/vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go index 82080eb3..ae8c3367 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go +++ b/vendor/github.com/kubernetes-csi/csi-test/test/driver_test.go @@ -21,7 +21,7 @@ import ( "sync" "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" "google.golang.org/grpc" "google.golang.org/grpc/reflection" diff --git a/vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go b/vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go index c89a5cf1..3baf9672 100644 --- a/vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go +++ b/vendor/github.com/kubernetes-csi/csi-test/utils/safegoroutinetester.go @@ -29,7 +29,7 @@ type SafeGoroutineTester struct{} // Errorf prints the error to the screen then panics func (s *SafeGoroutineTester) Errorf(format string, args ...interface{}) { - fmt.Printf(format, args) + fmt.Printf(format, args...) panic("MOCK TEST ERROR") }