diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 85fd8f142d..b4573fc7c3 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -15534,6 +15534,197 @@ }, "type": "object" }, + "io.k8s.api.storage.v1beta1.CSIDriver": { + "description": "CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. CSI drivers do not need to create the CSIDriver object directly. Instead they may use the cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically creates a CSIDriver object representing the driver. Kubernetes attach detach controller uses this object to determine whether attach is required. Kubelet uses this object to determine whether pod information needs to be passed on mount. CSIDriver objects are non-namespaced.", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", + "description": "Standard object metadata. metadata.Name indicates the name of the CSI driver that this object refers to; it MUST be the same name returned by the CSI GetPluginName() call for that driver. The driver name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata" + }, + "spec": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriverSpec", + "description": "Specification of the CSI Driver." + } + }, + "required": [ + "spec" + ], + "type": "object", + "x-kubernetes-group-version-kind": [ + { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + ] + }, + "io.k8s.api.storage.v1beta1.CSIDriverList": { + "description": "CSIDriverList is a collection of CSIDriver objects.", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type": "string" + }, + "items": { + "description": "items is the list of CSIDriver", + "items": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + }, + "type": "array" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta", + "description": "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata" + } + }, + "required": [ + "items" + ], + "type": "object", + "x-kubernetes-group-version-kind": [ + { + "group": "storage.k8s.io", + "kind": "CSIDriverList", + "version": "v1beta1" + } + ] + }, + "io.k8s.api.storage.v1beta1.CSIDriverSpec": { + "description": "CSIDriverSpec is the specification of a CSIDriver.", + "properties": { + "attachRequired": { + "description": "attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called.", + "type": "boolean" + }, + "podInfoOnMount": { + "description": "If set to true, podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations. If set to false, pod information will not be passed on mount. Default is false. The CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext. The following VolumeConext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID)", + "type": "boolean" + } + }, + "type": "object" + }, + "io.k8s.api.storage.v1beta1.CSINode": { + "description": "CSINode holds information about all CSI drivers installed on a node. CSI drivers do not need to create the CSINode object directly. As long as they use the node-driver-registrar sidecar container, the kubelet will automatically populate the CSINode object for the CSI driver as part of kubelet plugin registration. CSINode has the same name as a node. If the object is missing, it means either there are no CSI Drivers available on the node, or the Kubelet version is low enough that it doesn't create this object. CSINode has an OwnerReference that points to the corresponding node object.", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type": "string" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta", + "description": "metadata.name must be the Kubernetes node name." + }, + "spec": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINodeSpec", + "description": "spec is the specification of CSINode" + } + }, + "required": [ + "spec" + ], + "type": "object", + "x-kubernetes-group-version-kind": [ + { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + ] + }, + "io.k8s.api.storage.v1beta1.CSINodeDriver": { + "description": "CSINodeDriver holds information about the specification of one CSI driver installed on a node", + "properties": { + "name": { + "description": "This is the name of the CSI driver that this object refers to. This MUST be the same name returned by the CSI GetPluginName() call for that driver.", + "type": "string" + }, + "nodeID": { + "description": "nodeID of the node from the driver point of view. This field enables Kubernetes to communicate with storage systems that do not share the same nomenclature for nodes. For example, Kubernetes may refer to a given node as \"node1\", but the storage system may refer to the same node as \"nodeA\". When Kubernetes issues a command to the storage system to attach a volume to a specific node, it can use this field to refer to the node name using the ID that the storage system will understand, e.g. \"nodeA\" instead of \"node1\". This field is required.", + "type": "string" + }, + "topologyKeys": { + "description": "topologyKeys is the list of keys supported by the driver. When a driver is initialized on a cluster, it provides a set of topology keys that it understands (e.g. \"company.com/zone\", \"company.com/region\"). When a driver is initialized on a node, it provides the same topology keys along with values. Kubelet will expose these topology keys as labels on its own node object. When Kubernetes does topology aware provisioning, it can use this list to determine which labels it should retrieve from the node object and pass back to the driver. It is possible for different nodes to use different topology keys. This can be empty if driver does not support topology.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "nodeID" + ], + "type": "object" + }, + "io.k8s.api.storage.v1beta1.CSINodeList": { + "description": "CSINodeList is a collection of CSINode objects.", + "properties": { + "apiVersion": { + "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources", + "type": "string" + }, + "items": { + "description": "items is the list of CSINode", + "items": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + }, + "type": "array" + }, + "kind": { + "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds", + "type": "string" + }, + "metadata": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ListMeta", + "description": "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata" + } + }, + "required": [ + "items" + ], + "type": "object", + "x-kubernetes-group-version-kind": [ + { + "group": "storage.k8s.io", + "kind": "CSINodeList", + "version": "v1beta1" + } + ] + }, + "io.k8s.api.storage.v1beta1.CSINodeSpec": { + "description": "CSINodeSpec holds information about the specification of all CSI drivers installed on a node", + "properties": { + "drivers": { + "description": "drivers is a list of information of all CSI Drivers existing on a node. If all drivers in the list are uninstalled, this can become empty.", + "items": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINodeDriver" + }, + "type": "array", + "x-kubernetes-patch-merge-key": "name", + "x-kubernetes-patch-strategy": "merge" + } + }, + "required": [ + "drivers" + ], + "type": "object" + }, "io.k8s.api.storage.v1beta1.StorageClass": { "description": "StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned.\n\nStorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name.", "properties": { @@ -94856,6 +95047,1038 @@ ] } }, + "/apis/storage.k8s.io/v1beta1/csidrivers": { + "delete": { + "consumes": [ + "*/*" + ], + "description": "delete collection of CSIDriver", + "operationId": "deleteStorageV1beta1CollectionCSIDriver", + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "deletecollection", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + }, + "get": { + "consumes": [ + "*/*" + ], + "description": "list or watch objects of kind CSIDriver", + "operationId": "listStorageV1beta1CSIDriver", + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriverList" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "list", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + } + ], + "post": { + "consumes": [ + "*/*" + ], + "description": "create a CSIDriver", + "operationId": "createStorageV1beta1CSIDriver", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "post", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + } + }, + "/apis/storage.k8s.io/v1beta1/csidrivers/{name}": { + "delete": { + "consumes": [ + "*/*" + ], + "description": "delete a CSIDriver", + "operationId": "deleteStorageV1beta1CSIDriver", + "parameters": [ + { + "in": "body", + "name": "body", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + }, + { + "description": "The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately.", + "in": "query", + "name": "gracePeriodSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the \"orphan\" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both.", + "in": "query", + "name": "orphanDependents", + "type": "boolean", + "uniqueItems": true + }, + { + "description": "Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground.", + "in": "query", + "name": "propagationPolicy", + "type": "string", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "delete", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + }, + "get": { + "consumes": [ + "*/*" + ], + "description": "read the specified CSIDriver", + "operationId": "readStorageV1beta1CSIDriver", + "parameters": [ + { + "description": "Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'. Deprecated. Planned for removal in 1.18.", + "in": "query", + "name": "exact", + "type": "boolean", + "uniqueItems": true + }, + { + "description": "Should this value be exported. Export strips fields that a user can not specify. Deprecated. Planned for removal in 1.18.", + "in": "query", + "name": "export", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "name of the CSIDriver", + "in": "path", + "name": "name", + "required": true, + "type": "string", + "uniqueItems": true + }, + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + } + ], + "patch": { + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "description": "partially update the specified CSIDriver", + "operationId": "patchStorageV1beta1CSIDriver", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + }, + { + "description": "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.", + "in": "query", + "name": "force", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "patch", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + }, + "put": { + "consumes": [ + "*/*" + ], + "description": "replace the specified CSIDriver", + "operationId": "replaceStorageV1beta1CSIDriver", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSIDriver" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "put", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + } + }, + "/apis/storage.k8s.io/v1beta1/csinodes": { + "delete": { + "consumes": [ + "*/*" + ], + "description": "delete collection of CSINode", + "operationId": "deleteStorageV1beta1CollectionCSINode", + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "deletecollection", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + }, + "get": { + "consumes": [ + "*/*" + ], + "description": "list or watch objects of kind CSINode", + "operationId": "listStorageV1beta1CSINode", + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINodeList" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "list", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + } + ], + "post": { + "consumes": [ + "*/*" + ], + "description": "create a CSINode", + "operationId": "createStorageV1beta1CSINode", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "post", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + } + }, + "/apis/storage.k8s.io/v1beta1/csinodes/{name}": { + "delete": { + "consumes": [ + "*/*" + ], + "description": "delete a CSINode", + "operationId": "deleteStorageV1beta1CSINode", + "parameters": [ + { + "in": "body", + "name": "body", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + }, + { + "description": "The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately.", + "in": "query", + "name": "gracePeriodSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the \"orphan\" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both.", + "in": "query", + "name": "orphanDependents", + "type": "boolean", + "uniqueItems": true + }, + { + "description": "Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground.", + "in": "query", + "name": "propagationPolicy", + "type": "string", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "202": { + "description": "Accepted", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Status" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "delete", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + }, + "get": { + "consumes": [ + "*/*" + ], + "description": "read the specified CSINode", + "operationId": "readStorageV1beta1CSINode", + "parameters": [ + { + "description": "Should the export be exact. Exact export maintains cluster-specific fields like 'Namespace'. Deprecated. Planned for removal in 1.18.", + "in": "query", + "name": "exact", + "type": "boolean", + "uniqueItems": true + }, + { + "description": "Should this value be exported. Export strips fields that a user can not specify. Deprecated. Planned for removal in 1.18.", + "in": "query", + "name": "export", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "get", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "name of the CSINode", + "in": "path", + "name": "name", + "required": true, + "type": "string", + "uniqueItems": true + }, + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + } + ], + "patch": { + "consumes": [ + "application/json-patch+json", + "application/merge-patch+json", + "application/strategic-merge-patch+json" + ], + "description": "partially update the specified CSINode", + "operationId": "patchStorageV1beta1CSINode", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Patch" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + }, + { + "description": "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.", + "in": "query", + "name": "force", + "type": "boolean", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "patch", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + }, + "put": { + "consumes": [ + "*/*" + ], + "description": "replace the specified CSINode", + "operationId": "replaceStorageV1beta1CSINode", + "parameters": [ + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + { + "description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + "in": "query", + "name": "dryRun", + "type": "string", + "uniqueItems": true + } + ], + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/io.k8s.api.storage.v1beta1.CSINode" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "put", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + } + }, "/apis/storage.k8s.io/v1beta1/storageclasses": { "delete": { "consumes": [ @@ -95888,6 +97111,410 @@ } } }, + "/apis/storage.k8s.io/v1beta1/watch/csidrivers": { + "get": { + "consumes": [ + "*/*" + ], + "description": "watch individual changes to a list of CSIDriver. deprecated: use the 'watch' parameter with a list operation instead.", + "operationId": "watchStorageV1beta1CSIDriverList", + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.WatchEvent" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "watchlist", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ] + }, + "/apis/storage.k8s.io/v1beta1/watch/csidrivers/{name}": { + "get": { + "consumes": [ + "*/*" + ], + "description": "watch changes to an object of kind CSIDriver. deprecated: use the 'watch' parameter with a list operation instead, filtered to a single item with the 'fieldSelector' parameter.", + "operationId": "watchStorageV1beta1CSIDriver", + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.WatchEvent" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "watch", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSIDriver", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "name of the CSIDriver", + "in": "path", + "name": "name", + "required": true, + "type": "string", + "uniqueItems": true + }, + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ] + }, + "/apis/storage.k8s.io/v1beta1/watch/csinodes": { + "get": { + "consumes": [ + "*/*" + ], + "description": "watch individual changes to a list of CSINode. deprecated: use the 'watch' parameter with a list operation instead.", + "operationId": "watchStorageV1beta1CSINodeList", + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.WatchEvent" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "watchlist", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ] + }, + "/apis/storage.k8s.io/v1beta1/watch/csinodes/{name}": { + "get": { + "consumes": [ + "*/*" + ], + "description": "watch changes to an object of kind CSINode. deprecated: use the 'watch' parameter with a list operation instead, filtered to a single item with the 'fieldSelector' parameter.", + "operationId": "watchStorageV1beta1CSINode", + "produces": [ + "application/json", + "application/yaml", + "application/vnd.kubernetes.protobuf", + "application/json;stream=watch", + "application/vnd.kubernetes.protobuf;stream=watch" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.WatchEvent" + } + }, + "401": { + "description": "Unauthorized" + } + }, + "schemes": [ + "https" + ], + "tags": [ + "storage_v1beta1" + ], + "x-kubernetes-action": "watch", + "x-kubernetes-group-version-kind": { + "group": "storage.k8s.io", + "kind": "CSINode", + "version": "v1beta1" + } + }, + "parameters": [ + { + "description": "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + "in": "query", + "name": "continue", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + "in": "query", + "name": "fieldSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + "in": "query", + "name": "labelSelector", + "type": "string", + "uniqueItems": true + }, + { + "description": "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + "in": "query", + "name": "limit", + "type": "integer", + "uniqueItems": true + }, + { + "description": "name of the CSINode", + "in": "path", + "name": "name", + "required": true, + "type": "string", + "uniqueItems": true + }, + { + "description": "If 'true', then the output is pretty printed.", + "in": "query", + "name": "pretty", + "type": "string", + "uniqueItems": true + }, + { + "description": "When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it's 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv.", + "in": "query", + "name": "resourceVersion", + "type": "string", + "uniqueItems": true + }, + { + "description": "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + "in": "query", + "name": "timeoutSeconds", + "type": "integer", + "uniqueItems": true + }, + { + "description": "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + "in": "query", + "name": "watch", + "type": "boolean", + "uniqueItems": true + } + ] + }, "/apis/storage.k8s.io/v1beta1/watch/storageclasses": { "get": { "consumes": [ diff --git a/cmd/kube-controller-manager/app/BUILD b/cmd/kube-controller-manager/app/BUILD index c5e48fc813..21f09ff99a 100644 --- a/cmd/kube-controller-manager/app/BUILD +++ b/cmd/kube-controller-manager/app/BUILD @@ -134,7 +134,6 @@ go_library( "//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/component-base/cli/flag:go_default_library", "//staging/src/k8s.io/component-base/cli/globalflag:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/custom_metrics:go_default_library", "//staging/src/k8s.io/metrics/pkg/client/external_metrics:go_default_library", diff --git a/cmd/kube-controller-manager/app/core.go b/cmd/kube-controller-manager/app/core.go index 7f39d085ec..9ee77f5367 100644 --- a/cmd/kube-controller-manager/app/core.go +++ b/cmd/kube-controller-manager/app/core.go @@ -37,7 +37,6 @@ import ( "k8s.io/client-go/dynamic" clientset "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/kubernetes/pkg/controller" cloudcontroller "k8s.io/kubernetes/pkg/controller/cloud" endpointcontroller "k8s.io/kubernetes/pkg/controller/endpoint" @@ -216,14 +215,10 @@ func startAttachDetachController(ctx ControllerContext) (http.Handler, bool, err if ctx.ComponentConfig.AttachDetachController.ReconcilerSyncLoopPeriod.Duration < time.Second { return nil, true, fmt.Errorf("duration time must be greater than one second as set via command line option reconcile-sync-loop-period") } - csiClientConfig := ctx.ClientBuilder.ConfigOrDie("attachdetach-controller") - // csiClient works with CRDs that support json only - csiClientConfig.ContentType = "application/json" attachDetachController, attachDetachControllerErr := attachdetach.NewAttachDetachController( ctx.ClientBuilder.ClientOrDie("attachdetach-controller"), - csiclientset.NewForConfigOrDie(csiClientConfig), ctx.InformerFactory.Core().V1().Pods(), ctx.InformerFactory.Core().V1().Nodes(), ctx.InformerFactory.Core().V1().PersistentVolumeClaims(), diff --git a/cmd/kubelet/app/BUILD b/cmd/kubelet/app/BUILD index c19b88a80c..4ead906244 100644 --- a/cmd/kubelet/app/BUILD +++ b/cmd/kubelet/app/BUILD @@ -136,7 +136,6 @@ go_library( "//staging/src/k8s.io/client-go/util/keyutil:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/component-base/cli/flag:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//staging/src/k8s.io/kubelet/config/v1beta1:go_default_library", "//staging/src/k8s.io/node-api/pkg/client/clientset/versioned:go_default_library", "//vendor/github.com/coreos/go-systemd/daemon:go_default_library", diff --git a/cmd/kubelet/app/server.go b/cmd/kubelet/app/server.go index b7004673d0..d22eb21cb4 100644 --- a/cmd/kubelet/app/server.go +++ b/cmd/kubelet/app/server.go @@ -57,7 +57,6 @@ import ( "k8s.io/client-go/util/keyutil" cloudprovider "k8s.io/cloud-provider" cliflag "k8s.io/component-base/cli/flag" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1" "k8s.io/kubernetes/cmd/kubelet/app/options" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -400,7 +399,6 @@ func UnsecuredDependencies(s *options.KubeletServer) (*kubelet.Dependencies, err DockerClientConfig: dockerClientConfig, KubeClient: nil, HeartbeatClient: nil, - CSIClient: nil, EventClient: nil, Mounter: mounter, Subpather: subpather, @@ -598,10 +596,6 @@ func run(s *options.KubeletServer, kubeDeps *kubelet.Dependencies, stopCh <-chan // CRDs are JSON only, and client renegotiation for streaming is not correct as per #67803 crdClientConfig := restclient.CopyConfig(clientConfig) crdClientConfig.ContentType = "application/json" - kubeDeps.CSIClient, err = csiclientset.NewForConfig(crdClientConfig) - if err != nil { - return fmt.Errorf("failed to initialize kubelet storage client: %v", err) - } kubeDeps.NodeAPIClient, err = nodeapiclientset.NewForConfig(crdClientConfig) if err != nil { diff --git a/hack/test-update-storage-objects.sh b/hack/test-update-storage-objects.sh index f2e53edc61..9f5a533165 100755 --- a/hack/test-update-storage-objects.sh +++ b/hack/test-update-storage-objects.sh @@ -107,9 +107,9 @@ test/e2e/testing-manifests/rbd-storage-class.yaml,storageclasses,,slow,v1beta1,v ) KUBE_OLD_API_VERSION="networking.k8s.io/v1,storage.k8s.io/v1beta1,extensions/v1beta1" -KUBE_NEW_API_VERSION="networking.k8s.io/v1,storage.k8s.io/v1,extensions/v1beta1,policy/v1beta1" +KUBE_NEW_API_VERSION="networking.k8s.io/v1,storage.k8s.io/v1beta1,storage.k8s.io/v1,extensions/v1beta1,policy/v1beta1" KUBE_OLD_STORAGE_VERSIONS="storage.k8s.io/v1beta1" -KUBE_NEW_STORAGE_VERSIONS="storage.k8s.io/v1" +KUBE_NEW_STORAGE_VERSIONS="storage.k8s.io/v1beta1,storage.k8s.io/v1" ### END TEST DEFINITION CUSTOMIZATION ### diff --git a/pkg/api/testing/defaulting_test.go b/pkg/api/testing/defaulting_test.go index 5045357727..32995e4bab 100644 --- a/pkg/api/testing/defaulting_test.go +++ b/pkg/api/testing/defaulting_test.go @@ -142,6 +142,8 @@ func TestDefaulting(t *testing.T) { {Group: "networking.k8s.io", Version: "v1", Kind: "NetworkPolicyList"}: {}, {Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClass"}: {}, {Group: "storage.k8s.io", Version: "v1beta1", Kind: "StorageClassList"}: {}, + {Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriver"}: {}, + {Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriverList"}: {}, {Group: "storage.k8s.io", Version: "v1", Kind: "StorageClass"}: {}, {Group: "storage.k8s.io", Version: "v1", Kind: "StorageClassList"}: {}, {Group: "authentication.k8s.io", Version: "v1", Kind: "TokenRequest"}: {}, diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index f7ba935ff8..76fc962097 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -61,8 +61,6 @@ const isInvalidQuotaResource string = `must be a standard resource for quota` const fieldImmutableErrorMsg string = apimachineryvalidation.FieldImmutableErrorMsg const isNotIntegerErrorMsg string = `must be an integer` const isNotPositiveErrorMsg string = `must be greater than zero` -const csiDriverNameRexpErrMsg string = "must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character" -const csiDriverNameRexpFmt string = `^[a-zA-Z0-9][-a-zA-Z0-9_.]{0,61}[a-zA-Z-0-9]$` var pdPartitionErrorMsg string = validation.InclusiveRangeError(1, 255) var fileModeErrorMsg string = "must be a number between 0 and 0777 (octal), both inclusive" @@ -74,8 +72,6 @@ var iscsiInitiatorIqnRegex = regexp.MustCompile(`iqn\.\d{4}-\d{2}\.([[:alnum:]-. var iscsiInitiatorEuiRegex = regexp.MustCompile(`^eui.[[:alnum:]]{16}$`) var iscsiInitiatorNaaRegex = regexp.MustCompile(`^naa.[[:alnum:]]{32}$`) -var csiDriverNameRexp = regexp.MustCompile(csiDriverNameRexpFmt) - // ValidateHasLabel requires that metav1.ObjectMeta has a Label with key and expectedValue func ValidateHasLabel(meta metav1.ObjectMeta, fldPath *field.Path, key, expectedValue string) field.ErrorList { allErrs := field.ErrorList{} @@ -1446,9 +1442,10 @@ func ValidateCSIDriverName(driverName string, fldPath *field.Path) field.ErrorLi allErrs = append(allErrs, field.TooLong(fldPath, driverName, 63)) } - if !csiDriverNameRexp.MatchString(driverName) { - allErrs = append(allErrs, field.Invalid(fldPath, driverName, validation.RegexError(csiDriverNameRexpErrMsg, csiDriverNameRexpFmt, "csi-hostpath"))) + for _, msg := range validation.IsDNS1123Subdomain(strings.ToLower(driverName)) { + allErrs = append(allErrs, field.Invalid(fldPath, driverName, msg)) } + return allErrs } diff --git a/pkg/apis/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go index 45ec2c359c..ddb21670b9 100644 --- a/pkg/apis/core/validation/validation_test.go +++ b/pkg/apis/core/validation/validation_test.go @@ -1775,24 +1775,30 @@ func TestValidateCSIVolumeSource(t *testing.T) { csi: &core.CSIPersistentVolumeSource{Driver: "io-kubernetes-storage-csi-flex", VolumeHandle: "test-123"}, }, { - name: "driver name: ok underscore only", - csi: &core.CSIPersistentVolumeSource{Driver: "io_kubernetes_storage_csi_flex", VolumeHandle: "test-123"}, + name: "driver name: invalid underscore", + csi: &core.CSIPersistentVolumeSource{Driver: "io_kubernetes_storage_csi_flex", VolumeHandle: "test-123"}, + errtype: field.ErrorTypeInvalid, + errfield: "driver", }, { - name: "driver name: ok dot underscores", - csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage_csi.flex", VolumeHandle: "test-123"}, + name: "driver name: invalid dot underscores", + csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage_csi.flex", VolumeHandle: "test-123"}, + errtype: field.ErrorTypeInvalid, + errfield: "driver", }, { name: "driver name: ok beginnin with number", - csi: &core.CSIPersistentVolumeSource{Driver: "2io.kubernetes.storage_csi.flex", VolumeHandle: "test-123"}, + csi: &core.CSIPersistentVolumeSource{Driver: "2io.kubernetes.storage-csi.flex", VolumeHandle: "test-123"}, }, { name: "driver name: ok ending with number", - csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage_csi.flex2", VolumeHandle: "test-123"}, + csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes.storage-csi.flex2", VolumeHandle: "test-123"}, }, { - name: "driver name: ok dot dash underscores", - csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes-storage.csi_flex", VolumeHandle: "test-123"}, + name: "driver name: invalid dot dash underscores", + csi: &core.CSIPersistentVolumeSource{Driver: "io.kubernetes-storage.csi_flex", VolumeHandle: "test-123"}, + errtype: field.ErrorTypeInvalid, + errfield: "driver", }, { name: "driver name: invalid length 0", @@ -1801,10 +1807,8 @@ func TestValidateCSIVolumeSource(t *testing.T) { errfield: "driver", }, { - name: "driver name: invalid length 1", - csi: &core.CSIPersistentVolumeSource{Driver: "a", VolumeHandle: "test-123"}, - errtype: field.ErrorTypeInvalid, - errfield: "driver", + name: "driver name: ok length 1", + csi: &core.CSIPersistentVolumeSource{Driver: "a", VolumeHandle: "test-123"}, }, { name: "driver name: invalid length > 63", diff --git a/pkg/apis/storage/fuzzer/fuzzer.go b/pkg/apis/storage/fuzzer/fuzzer.go index e39f4e91e1..2081ffe846 100644 --- a/pkg/apis/storage/fuzzer/fuzzer.go +++ b/pkg/apis/storage/fuzzer/fuzzer.go @@ -34,5 +34,18 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { bindingModes := []storage.VolumeBindingMode{storage.VolumeBindingImmediate, storage.VolumeBindingWaitForFirstConsumer} obj.VolumeBindingMode = &bindingModes[c.Rand.Intn(len(bindingModes))] }, + func(obj *storage.CSIDriver, c fuzz.Continue) { + c.FuzzNoCustom(obj) // fuzz self without calling this function again + + // match defaulting + if obj.Spec.AttachRequired == nil { + obj.Spec.AttachRequired = new(bool) + *(obj.Spec.AttachRequired) = true + } + if obj.Spec.PodInfoOnMount == nil { + obj.Spec.PodInfoOnMount = new(bool) + *(obj.Spec.PodInfoOnMount) = false + } + }, } } diff --git a/pkg/apis/storage/register.go b/pkg/apis/storage/register.go index 7ae2f3efe1..fffba5fc5a 100644 --- a/pkg/apis/storage/register.go +++ b/pkg/apis/storage/register.go @@ -48,6 +48,10 @@ func addKnownTypes(scheme *runtime.Scheme) error { &StorageClassList{}, &VolumeAttachment{}, &VolumeAttachmentList{}, + &CSINode{}, + &CSINodeList{}, + &CSIDriver{}, + &CSIDriverList{}, ) return nil } diff --git a/pkg/apis/storage/types.go b/pkg/apis/storage/types.go index f8c16a7450..daf23d6113 100644 --- a/pkg/apis/storage/types.go +++ b/pkg/apis/storage/types.go @@ -215,3 +215,160 @@ const ( // binding will occur during Pod scheduing. VolumeBindingWaitForFirstConsumer VolumeBindingMode = "WaitForFirstConsumer" ) + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSIDriver captures information about a Container Storage Interface (CSI) +// volume driver deployed on the cluster. +// CSI drivers do not need to create the CSIDriver object directly. Instead they may use the +// cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically +// creates a CSIDriver object representing the driver. +// Kubernetes attach detach controller uses this object to determine whether attach is required. +// Kubelet uses this object to determine whether pod information needs to be passed on mount. +// CSIDriver objects are non-namespaced. +type CSIDriver struct { + metav1.TypeMeta + + // Standard object metadata. + // metadata.Name indicates the name of the CSI driver that this object + // refers to; it MUST be the same name returned by the CSI GetPluginName() + // call for that driver. + // The driver name must be 63 characters or less, beginning and ending with + // an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and + // alphanumerics between. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + metav1.ObjectMeta + + // Specification of the CSI Driver. + Spec CSIDriverSpec +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSIDriverList is a collection of CSIDriver objects. +type CSIDriverList struct { + metav1.TypeMeta + + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + metav1.ListMeta + + // items is the list of CSIDriver + Items []CSIDriver +} + +// CSIDriverSpec is the specification of a CSIDriver. +type CSIDriverSpec struct { + // attachRequired indicates this CSI volume driver requires an attach + // operation (because it implements the CSI ControllerPublishVolume() + // method), and that the Kubernetes attach detach controller should call + // the attach volume interface which checks the volumeattachment status + // and waits until the volume is attached before proceeding to mounting. + // The CSI external-attacher coordinates with CSI volume driver and updates + // the volumeattachment status when the attach operation is complete. + // If the CSIDriverRegistry feature gate is enabled and the value is + // specified to false, the attach operation will be skipped. + // Otherwise the attach operation will be called. + // +optional + AttachRequired *bool + + // If set to true, podInfoOnMount indicates this CSI volume driver + // requires additional pod information (like podName, podUID, etc.) during + // mount operations. + // If set to false, pod information will not be passed on mount. + // Default is false. + // The CSI driver specifies podInfoOnMount as part of driver deployment. + // If true, Kubelet will pass pod information as VolumeContext in the CSI + // NodePublishVolume() calls. + // The CSI driver is responsible for parsing and validating the information + // passed in as VolumeContext. + // The following VolumeConext will be passed if podInfoOnMount is set to true. + // This list might grow, but the prefix will be used. + // "csi.storage.k8s.io/pod.name": pod.Name + // "csi.storage.k8s.io/pod.namespace": pod.Namespace + // "csi.storage.k8s.io/pod.uid": string(pod.UID) + // +optional + PodInfoOnMount *bool +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSINode holds information about all CSI drivers installed on a node. +// CSI drivers do not need to create the CSINode object directly. As long as +// they use the node-driver-registrar sidecar container, the kubelet will +// automatically populate the CSINode object for the CSI driver as part of +// kubelet plugin registration. +// CSINode has the same name as a node. If the object is missing, it means either +// there are no CSI Drivers available on the node, or the Kubelet version is low +// enough that it doesn't create this object. +// CSINode has an OwnerReference that points to the corresponding node object. +type CSINode struct { + metav1.TypeMeta + + // metadata.name must be the Kubernetes node name. + metav1.ObjectMeta + + // spec is the specification of CSINode + Spec CSINodeSpec +} + +// CSINodeSpec holds information about the specification of all CSI drivers installed on a node +type CSINodeSpec struct { + // drivers is a list of information of all CSI Drivers existing on a node. + // If all drivers in the list are uninstalled, this can become empty. + // +patchMergeKey=name + // +patchStrategy=merge + Drivers []CSINodeDriver +} + +// CSINodeDriver holds information about the specification of one CSI driver installed on a node +type CSINodeDriver struct { + // This is the name of the CSI driver that this object refers to. + // This MUST be the same name returned by the CSI GetPluginName() call for + // that driver. + Name string + + // nodeID of the node from the driver point of view. + // This field enables Kubernetes to communicate with storage systems that do + // not share the same nomenclature for nodes. For example, Kubernetes may + // refer to a given node as "node1", but the storage system may refer to + // the same node as "nodeA". When Kubernetes issues a command to the storage + // system to attach a volume to a specific node, it can use this field to + // refer to the node name using the ID that the storage system will + // understand, e.g. "nodeA" instead of "node1". This field is required. + NodeID string + + // topologyKeys is the list of keys supported by the driver. + // When a driver is initialized on a cluster, it provides a set of topology + // keys that it understands (e.g. "company.com/zone", "company.com/region"). + // When a driver is initialized on a node, it provides the same topology keys + // along with values. Kubelet will expose these topology keys as labels + // on its own node object. + // When Kubernetes does topology aware provisioning, it can use this list to + // determine which labels it should retrieve from the node object and pass + // back to the driver. + // It is possible for different nodes to use different topology keys. + // This can be empty if driver does not support topology. + // +optional + TopologyKeys []string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSINodeList is a collection of CSINode objects. +type CSINodeList struct { + metav1.TypeMeta + + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + metav1.ListMeta + + // items is the list of CSINode + Items []CSINode +} diff --git a/pkg/apis/storage/v1beta1/defaults.go b/pkg/apis/storage/v1beta1/defaults.go index f2db7d84bf..3080328165 100644 --- a/pkg/apis/storage/v1beta1/defaults.go +++ b/pkg/apis/storage/v1beta1/defaults.go @@ -37,3 +37,14 @@ func SetDefaults_StorageClass(obj *storagev1beta1.StorageClass) { *obj.VolumeBindingMode = storagev1beta1.VolumeBindingImmediate } } + +func SetDefaults_CSIDriver(obj *storagev1beta1.CSIDriver) { + if obj.Spec.AttachRequired == nil { + obj.Spec.AttachRequired = new(bool) + *(obj.Spec.AttachRequired) = true + } + if obj.Spec.PodInfoOnMount == nil { + obj.Spec.PodInfoOnMount = new(bool) + *(obj.Spec.PodInfoOnMount) = false + } +} diff --git a/pkg/apis/storage/v1beta1/defaults_test.go b/pkg/apis/storage/v1beta1/defaults_test.go index d920c5c7f9..d1cebcf7b9 100644 --- a/pkg/apis/storage/v1beta1/defaults_test.go +++ b/pkg/apis/storage/v1beta1/defaults_test.go @@ -60,3 +60,24 @@ func TestSetDefaultVolumeBindingMode(t *testing.T) { t.Errorf("Expected VolumeBindingMode to be defaulted to: %+v, got: %+v", defaultMode, outMode) } } + +func TestSetDefaultAttachRequired(t *testing.T) { + driver := &storagev1beta1.CSIDriver{} + + // field should be defaulted + defaultAttach := true + defaultPodInfo := false + output := roundTrip(t, runtime.Object(driver)).(*storagev1beta1.CSIDriver) + outAttach := output.Spec.AttachRequired + if outAttach == nil { + t.Errorf("Expected AttachRequired to be defaulted to: %+v, got: nil", defaultAttach) + } else if *outAttach != defaultAttach { + t.Errorf("Expected AttachRequired to be defaulted to: %+v, got: %+v", defaultAttach, outAttach) + } + outPodInfo := output.Spec.PodInfoOnMount + if outPodInfo == nil { + t.Errorf("Expected PodInfoOnMount to be defaulted to: %+v, got: nil", defaultPodInfo) + } else if *outPodInfo != defaultPodInfo { + t.Errorf("Expected PodInfoOnMount to be defaulted to: %+v, got: %+v", defaultPodInfo, outPodInfo) + } +} diff --git a/pkg/apis/storage/v1beta1/zz_generated.conversion.go b/pkg/apis/storage/v1beta1/zz_generated.conversion.go index be21c4e184..e8d4471fb8 100644 --- a/pkg/apis/storage/v1beta1/zz_generated.conversion.go +++ b/pkg/apis/storage/v1beta1/zz_generated.conversion.go @@ -38,6 +38,76 @@ func init() { // RegisterConversions adds conversion functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*v1beta1.CSIDriver)(nil), (*storage.CSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CSIDriver_To_storage_CSIDriver(a.(*v1beta1.CSIDriver), b.(*storage.CSIDriver), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.CSIDriver)(nil), (*v1beta1.CSIDriver)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_CSIDriver_To_v1beta1_CSIDriver(a.(*storage.CSIDriver), b.(*v1beta1.CSIDriver), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.CSIDriverList)(nil), (*storage.CSIDriverList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CSIDriverList_To_storage_CSIDriverList(a.(*v1beta1.CSIDriverList), b.(*storage.CSIDriverList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.CSIDriverList)(nil), (*v1beta1.CSIDriverList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_CSIDriverList_To_v1beta1_CSIDriverList(a.(*storage.CSIDriverList), b.(*v1beta1.CSIDriverList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.CSIDriverSpec)(nil), (*storage.CSIDriverSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(a.(*v1beta1.CSIDriverSpec), b.(*storage.CSIDriverSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.CSIDriverSpec)(nil), (*v1beta1.CSIDriverSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(a.(*storage.CSIDriverSpec), b.(*v1beta1.CSIDriverSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.CSINode)(nil), (*storage.CSINode)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CSINode_To_storage_CSINode(a.(*v1beta1.CSINode), b.(*storage.CSINode), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.CSINode)(nil), (*v1beta1.CSINode)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_CSINode_To_v1beta1_CSINode(a.(*storage.CSINode), b.(*v1beta1.CSINode), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.CSINodeDriver)(nil), (*storage.CSINodeDriver)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(a.(*v1beta1.CSINodeDriver), b.(*storage.CSINodeDriver), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.CSINodeDriver)(nil), (*v1beta1.CSINodeDriver)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(a.(*storage.CSINodeDriver), b.(*v1beta1.CSINodeDriver), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.CSINodeList)(nil), (*storage.CSINodeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CSINodeList_To_storage_CSINodeList(a.(*v1beta1.CSINodeList), b.(*storage.CSINodeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.CSINodeList)(nil), (*v1beta1.CSINodeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_CSINodeList_To_v1beta1_CSINodeList(a.(*storage.CSINodeList), b.(*v1beta1.CSINodeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1beta1.CSINodeSpec)(nil), (*storage.CSINodeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(a.(*v1beta1.CSINodeSpec), b.(*storage.CSINodeSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*storage.CSINodeSpec)(nil), (*v1beta1.CSINodeSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(a.(*storage.CSINodeSpec), b.(*v1beta1.CSINodeSpec), scope) + }); err != nil { + return err + } if err := s.AddGeneratedConversionFunc((*v1beta1.StorageClass)(nil), (*storage.StorageClass)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1beta1_StorageClass_To_storage_StorageClass(a.(*v1beta1.StorageClass), b.(*storage.StorageClass), scope) }); err != nil { @@ -121,6 +191,168 @@ func RegisterConversions(s *runtime.Scheme) error { return nil } +func autoConvert_v1beta1_CSIDriver_To_storage_CSIDriver(in *v1beta1.CSIDriver, out *storage.CSIDriver, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta1_CSIDriver_To_storage_CSIDriver is an autogenerated conversion function. +func Convert_v1beta1_CSIDriver_To_storage_CSIDriver(in *v1beta1.CSIDriver, out *storage.CSIDriver, s conversion.Scope) error { + return autoConvert_v1beta1_CSIDriver_To_storage_CSIDriver(in, out, s) +} + +func autoConvert_storage_CSIDriver_To_v1beta1_CSIDriver(in *storage.CSIDriver, out *v1beta1.CSIDriver, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_storage_CSIDriver_To_v1beta1_CSIDriver is an autogenerated conversion function. +func Convert_storage_CSIDriver_To_v1beta1_CSIDriver(in *storage.CSIDriver, out *v1beta1.CSIDriver, s conversion.Scope) error { + return autoConvert_storage_CSIDriver_To_v1beta1_CSIDriver(in, out, s) +} + +func autoConvert_v1beta1_CSIDriverList_To_storage_CSIDriverList(in *v1beta1.CSIDriverList, out *storage.CSIDriverList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]storage.CSIDriver)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1beta1_CSIDriverList_To_storage_CSIDriverList is an autogenerated conversion function. +func Convert_v1beta1_CSIDriverList_To_storage_CSIDriverList(in *v1beta1.CSIDriverList, out *storage.CSIDriverList, s conversion.Scope) error { + return autoConvert_v1beta1_CSIDriverList_To_storage_CSIDriverList(in, out, s) +} + +func autoConvert_storage_CSIDriverList_To_v1beta1_CSIDriverList(in *storage.CSIDriverList, out *v1beta1.CSIDriverList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1beta1.CSIDriver)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_storage_CSIDriverList_To_v1beta1_CSIDriverList is an autogenerated conversion function. +func Convert_storage_CSIDriverList_To_v1beta1_CSIDriverList(in *storage.CSIDriverList, out *v1beta1.CSIDriverList, s conversion.Scope) error { + return autoConvert_storage_CSIDriverList_To_v1beta1_CSIDriverList(in, out, s) +} + +func autoConvert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in *v1beta1.CSIDriverSpec, out *storage.CSIDriverSpec, s conversion.Scope) error { + out.AttachRequired = (*bool)(unsafe.Pointer(in.AttachRequired)) + out.PodInfoOnMount = (*bool)(unsafe.Pointer(in.PodInfoOnMount)) + return nil +} + +// Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec is an autogenerated conversion function. +func Convert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in *v1beta1.CSIDriverSpec, out *storage.CSIDriverSpec, s conversion.Scope) error { + return autoConvert_v1beta1_CSIDriverSpec_To_storage_CSIDriverSpec(in, out, s) +} + +func autoConvert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in *storage.CSIDriverSpec, out *v1beta1.CSIDriverSpec, s conversion.Scope) error { + out.AttachRequired = (*bool)(unsafe.Pointer(in.AttachRequired)) + out.PodInfoOnMount = (*bool)(unsafe.Pointer(in.PodInfoOnMount)) + return nil +} + +// Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec is an autogenerated conversion function. +func Convert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in *storage.CSIDriverSpec, out *v1beta1.CSIDriverSpec, s conversion.Scope) error { + return autoConvert_storage_CSIDriverSpec_To_v1beta1_CSIDriverSpec(in, out, s) +} + +func autoConvert_v1beta1_CSINode_To_storage_CSINode(in *v1beta1.CSINode, out *storage.CSINode, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_v1beta1_CSINode_To_storage_CSINode is an autogenerated conversion function. +func Convert_v1beta1_CSINode_To_storage_CSINode(in *v1beta1.CSINode, out *storage.CSINode, s conversion.Scope) error { + return autoConvert_v1beta1_CSINode_To_storage_CSINode(in, out, s) +} + +func autoConvert_storage_CSINode_To_v1beta1_CSINode(in *storage.CSINode, out *v1beta1.CSINode, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + return nil +} + +// Convert_storage_CSINode_To_v1beta1_CSINode is an autogenerated conversion function. +func Convert_storage_CSINode_To_v1beta1_CSINode(in *storage.CSINode, out *v1beta1.CSINode, s conversion.Scope) error { + return autoConvert_storage_CSINode_To_v1beta1_CSINode(in, out, s) +} + +func autoConvert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(in *v1beta1.CSINodeDriver, out *storage.CSINodeDriver, s conversion.Scope) error { + out.Name = in.Name + out.NodeID = in.NodeID + out.TopologyKeys = *(*[]string)(unsafe.Pointer(&in.TopologyKeys)) + return nil +} + +// Convert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver is an autogenerated conversion function. +func Convert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(in *v1beta1.CSINodeDriver, out *storage.CSINodeDriver, s conversion.Scope) error { + return autoConvert_v1beta1_CSINodeDriver_To_storage_CSINodeDriver(in, out, s) +} + +func autoConvert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(in *storage.CSINodeDriver, out *v1beta1.CSINodeDriver, s conversion.Scope) error { + out.Name = in.Name + out.NodeID = in.NodeID + out.TopologyKeys = *(*[]string)(unsafe.Pointer(&in.TopologyKeys)) + return nil +} + +// Convert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver is an autogenerated conversion function. +func Convert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(in *storage.CSINodeDriver, out *v1beta1.CSINodeDriver, s conversion.Scope) error { + return autoConvert_storage_CSINodeDriver_To_v1beta1_CSINodeDriver(in, out, s) +} + +func autoConvert_v1beta1_CSINodeList_To_storage_CSINodeList(in *v1beta1.CSINodeList, out *storage.CSINodeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]storage.CSINode)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1beta1_CSINodeList_To_storage_CSINodeList is an autogenerated conversion function. +func Convert_v1beta1_CSINodeList_To_storage_CSINodeList(in *v1beta1.CSINodeList, out *storage.CSINodeList, s conversion.Scope) error { + return autoConvert_v1beta1_CSINodeList_To_storage_CSINodeList(in, out, s) +} + +func autoConvert_storage_CSINodeList_To_v1beta1_CSINodeList(in *storage.CSINodeList, out *v1beta1.CSINodeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]v1beta1.CSINode)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_storage_CSINodeList_To_v1beta1_CSINodeList is an autogenerated conversion function. +func Convert_storage_CSINodeList_To_v1beta1_CSINodeList(in *storage.CSINodeList, out *v1beta1.CSINodeList, s conversion.Scope) error { + return autoConvert_storage_CSINodeList_To_v1beta1_CSINodeList(in, out, s) +} + +func autoConvert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(in *v1beta1.CSINodeSpec, out *storage.CSINodeSpec, s conversion.Scope) error { + out.Drivers = *(*[]storage.CSINodeDriver)(unsafe.Pointer(&in.Drivers)) + return nil +} + +// Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec is an autogenerated conversion function. +func Convert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(in *v1beta1.CSINodeSpec, out *storage.CSINodeSpec, s conversion.Scope) error { + return autoConvert_v1beta1_CSINodeSpec_To_storage_CSINodeSpec(in, out, s) +} + +func autoConvert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(in *storage.CSINodeSpec, out *v1beta1.CSINodeSpec, s conversion.Scope) error { + out.Drivers = *(*[]v1beta1.CSINodeDriver)(unsafe.Pointer(&in.Drivers)) + return nil +} + +// Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec is an autogenerated conversion function. +func Convert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(in *storage.CSINodeSpec, out *v1beta1.CSINodeSpec, s conversion.Scope) error { + return autoConvert_storage_CSINodeSpec_To_v1beta1_CSINodeSpec(in, out, s) +} + func autoConvert_v1beta1_StorageClass_To_storage_StorageClass(in *v1beta1.StorageClass, out *storage.StorageClass, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta out.Provisioner = in.Provisioner diff --git a/pkg/apis/storage/v1beta1/zz_generated.defaults.go b/pkg/apis/storage/v1beta1/zz_generated.defaults.go index 80830c4db2..5b674dbc7f 100644 --- a/pkg/apis/storage/v1beta1/zz_generated.defaults.go +++ b/pkg/apis/storage/v1beta1/zz_generated.defaults.go @@ -29,11 +29,24 @@ import ( // Public to allow building arbitrary schemes. // All generated defaulters are covering - they call all nested defaulters. func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&v1beta1.CSIDriver{}, func(obj interface{}) { SetObjectDefaults_CSIDriver(obj.(*v1beta1.CSIDriver)) }) + scheme.AddTypeDefaultingFunc(&v1beta1.CSIDriverList{}, func(obj interface{}) { SetObjectDefaults_CSIDriverList(obj.(*v1beta1.CSIDriverList)) }) scheme.AddTypeDefaultingFunc(&v1beta1.StorageClass{}, func(obj interface{}) { SetObjectDefaults_StorageClass(obj.(*v1beta1.StorageClass)) }) scheme.AddTypeDefaultingFunc(&v1beta1.StorageClassList{}, func(obj interface{}) { SetObjectDefaults_StorageClassList(obj.(*v1beta1.StorageClassList)) }) return nil } +func SetObjectDefaults_CSIDriver(in *v1beta1.CSIDriver) { + SetDefaults_CSIDriver(in) +} + +func SetObjectDefaults_CSIDriverList(in *v1beta1.CSIDriverList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_CSIDriver(a) + } +} + func SetObjectDefaults_StorageClass(in *v1beta1.StorageClass) { SetDefaults_StorageClass(in) } diff --git a/pkg/apis/storage/validation/validation.go b/pkg/apis/storage/validation/validation.go index db97493954..518e04a9de 100644 --- a/pkg/apis/storage/validation/validation.go +++ b/pkg/apis/storage/validation/validation.go @@ -17,6 +17,7 @@ limitations under the License. package validation import ( + "fmt" "reflect" "strings" @@ -36,6 +37,8 @@ const ( maxAttachedVolumeMetadataSize = 256 * (1 << 10) // 256 kB maxVolumeErrorMessageSize = 1024 + + csiNodeIDMaxLength = 128 ) // ValidateStorageClass validates a StorageClass. @@ -266,3 +269,144 @@ func validateAllowedTopologies(topologies []api.TopologySelectorTerm, fldPath *f return allErrs } + +// ValidateCSINode validates a CSINode. +func ValidateCSINode(csiNode *storage.CSINode) field.ErrorList { + allErrs := apivalidation.ValidateObjectMeta(&csiNode.ObjectMeta, false, apivalidation.ValidateNodeName, field.NewPath("metadata")) + allErrs = append(allErrs, validateCSINodeSpec(&csiNode.Spec, field.NewPath("spec"))...) + return allErrs +} + +// ValidateCSINodeUpdate validates a CSINode. +func ValidateCSINodeUpdate(new, old *storage.CSINode) field.ErrorList { + allErrs := ValidateCSINode(new) + + // Validate modifying fields inside an existing CSINodeDriver entry is not allowed + for _, oldDriver := range old.Spec.Drivers { + for _, newDriver := range new.Spec.Drivers { + if oldDriver.Name == newDriver.Name { + if !apiequality.Semantic.DeepEqual(oldDriver, newDriver) { + allErrs = append(allErrs, field.Invalid(field.NewPath("CSINodeDriver"), newDriver, "field is immutable")) + } + } + } + } + + return allErrs +} + +// ValidateCSINodeSpec tests that the specified CSINodeSpec has valid data. +func validateCSINodeSpec( + spec *storage.CSINodeSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, validateCSINodeDrivers(spec.Drivers, fldPath.Child("drivers"))...) + return allErrs +} + +// ValidateCSINodeDrivers tests that the specified CSINodeDrivers have valid data. +func validateCSINodeDrivers(drivers []storage.CSINodeDriver, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + driverNamesInSpecs := make(sets.String) + for i, driver := range drivers { + idxPath := fldPath.Index(i) + allErrs = append(allErrs, validateCSINodeDriver(driver, driverNamesInSpecs, idxPath)...) + } + + return allErrs +} + +// validateCSINodeDriverNodeID tests if Name in CSINodeDriver is a valid node id. +func validateCSINodeDriverNodeID(nodeID string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + // nodeID is always required + if len(nodeID) == 0 { + allErrs = append(allErrs, field.Required(fldPath, nodeID)) + } + if len(nodeID) > csiNodeIDMaxLength { + allErrs = append(allErrs, field.Invalid(fldPath, nodeID, fmt.Sprintf("must be %d characters or less", csiNodeIDMaxLength))) + } + return allErrs +} + +// validateCSINodeDriver tests if CSINodeDriver has valid entries +func validateCSINodeDriver(driver storage.CSINodeDriver, driverNamesInSpecs sets.String, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + allErrs = append(allErrs, apivalidation.ValidateCSIDriverName(driver.Name, fldPath.Child("name"))...) + allErrs = append(allErrs, validateCSINodeDriverNodeID(driver.NodeID, fldPath.Child("nodeID"))...) + + // check for duplicate entries for the same driver in specs + if driverNamesInSpecs.Has(driver.Name) { + allErrs = append(allErrs, field.Duplicate(fldPath.Child("name"), driver.Name)) + } + driverNamesInSpecs.Insert(driver.Name) + topoKeys := make(sets.String) + for _, key := range driver.TopologyKeys { + if len(key) == 0 { + allErrs = append(allErrs, field.Required(fldPath, key)) + } + + if topoKeys.Has(key) { + allErrs = append(allErrs, field.Duplicate(fldPath, key)) + } + topoKeys.Insert(key) + + for _, msg := range validation.IsQualifiedName(key) { + allErrs = append(allErrs, field.Invalid(fldPath, driver.TopologyKeys, msg)) + } + } + + return allErrs +} + +// ValidateCSIDriver validates a CSIDriver. +func ValidateCSIDriver(csiDriver *storage.CSIDriver) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, apivalidation.ValidateCSIDriverName(csiDriver.Name, field.NewPath("name"))...) + + allErrs = append(allErrs, validateCSIDriverSpec(&csiDriver.Spec, field.NewPath("spec"))...) + return allErrs +} + +// ValidateCSIDriverUpdate validates a CSIDriver. +func ValidateCSIDriverUpdate(new, old *storage.CSIDriver) field.ErrorList { + allErrs := ValidateCSIDriver(new) + + // Spec is read-only + // If this ever relaxes in the future, make sure to increment the Generation number in PrepareForUpdate + if !apiequality.Semantic.DeepEqual(old.Spec, new.Spec) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), new.Spec, "field is immutable")) + } + return allErrs +} + +// ValidateCSIDriverSpec tests that the specified CSIDriverSpec +// has valid data. +func validateCSIDriverSpec( + spec *storage.CSIDriverSpec, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + allErrs = append(allErrs, validateAttachRequired(spec.AttachRequired, fldPath.Child("attachedRequired"))...) + allErrs = append(allErrs, validatePodInfoOnMount(spec.PodInfoOnMount, fldPath.Child("podInfoOnMount"))...) + return allErrs +} + +// validateAttachRequired tests if attachRequired is set for CSIDriver. +func validateAttachRequired(attachRequired *bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if attachRequired == nil { + allErrs = append(allErrs, field.Required(fldPath, "")) + } + + return allErrs +} + +// validatePodInfoOnMount tests if podInfoOnMount is set for CSIDriver. +func validatePodInfoOnMount(podInfoOnMount *bool, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + if podInfoOnMount == nil { + allErrs = append(allErrs, field.Required(fldPath, "")) + } + + return allErrs +} diff --git a/pkg/apis/storage/validation/validation_test.go b/pkg/apis/storage/validation/validation_test.go index f5b2004131..8c9c4c2688 100644 --- a/pkg/apis/storage/validation/validation_test.go +++ b/pkg/apis/storage/validation/validation_test.go @@ -870,3 +870,628 @@ func TestValidateAllowedTopologies(t *testing.T) { } } } + +func TestCSINodeValidation(t *testing.T) { + driverName := "driver-name" + driverName2 := "1io.kubernetes-storage-2-csi-driver3" + longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver" + nodeID := "nodeA" + successCases := []storage.CSINode{ + { + // driver name: dot only + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // driver name: dash only + ObjectMeta: metav1.ObjectMeta{Name: "foo2"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io-kubernetes-storage-csi-driver", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // driver name: numbers + ObjectMeta: metav1.ObjectMeta{Name: "foo3"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "1io-kubernetes-storage-2-csi-driver3", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // driver name: dot, dash + ObjectMeta: metav1.ObjectMeta{Name: "foo4"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage-csi-driver", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // driver name: dot, dash, and numbers + ObjectMeta: metav1.ObjectMeta{Name: "foo5"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: driverName2, + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // Driver name length 1 + ObjectMeta: metav1.ObjectMeta{Name: "foo2"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "a", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // multiple drivers with different node IDs, topology keys + ObjectMeta: metav1.ObjectMeta{Name: "foo6"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "driver1", + NodeID: "node1", + TopologyKeys: []string{"key1", "key2"}, + }, + { + Name: "driverB", + NodeID: "nodeA", + TopologyKeys: []string{"keyA", "keyB"}, + }, + }, + }, + }, + { + // multiple drivers with same node IDs, topology keys + ObjectMeta: metav1.ObjectMeta{Name: "foo7"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "driver1", + NodeID: "node1", + TopologyKeys: []string{"key1"}, + }, + { + Name: "driver2", + NodeID: "node1", + TopologyKeys: []string{"key1"}, + }, + }, + }, + }, + { + // topology key names with -, _, and dot . + ObjectMeta: metav1.ObjectMeta{Name: "foo8"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "driver1", + NodeID: "node1", + TopologyKeys: []string{"zone_1", "zone.2"}, + }, + { + Name: "driver2", + NodeID: "node1", + TopologyKeys: []string{"zone-3", "zone.4"}, + }, + }, + }, + }, + { + // topology prefix with - and dot. + ObjectMeta: metav1.ObjectMeta{Name: "foo9"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "driver1", + NodeID: "node1", + TopologyKeys: []string{"company-com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // No topology keys + ObjectMeta: metav1.ObjectMeta{Name: "foo10"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: driverName, + NodeID: nodeID, + }, + }, + }, + }, + } + + for _, csiNode := range successCases { + if errs := ValidateCSINode(&csiNode); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + errorCases := []storage.CSINode{ + { + // Empty driver name + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // Invalid start char in driver name + ObjectMeta: metav1.ObjectMeta{Name: "foo3"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "_io.kubernetes.storage.csi.driver", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // Invalid end char in driver name + ObjectMeta: metav1.ObjectMeta{Name: "foo4"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver/", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // Invalid separators in driver name + ObjectMeta: metav1.ObjectMeta{Name: "foo5"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io/kubernetes/storage/csi~driver", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // driver name: underscore only + ObjectMeta: metav1.ObjectMeta{Name: "foo6"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io_kubernetes_storage_csi_driver", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // Driver name length > 63 + ObjectMeta: metav1.ObjectMeta{Name: "foo7"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: longName, + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // No driver name + ObjectMeta: metav1.ObjectMeta{Name: "foo8"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // Empty individual topology key + ObjectMeta: metav1.ObjectMeta{Name: "foo9"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: driverName, + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", ""}, + }, + }, + }, + }, + { + // duplicate drivers in driver specs + ObjectMeta: metav1.ObjectMeta{Name: "foo10"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "driver1", + NodeID: "node1", + TopologyKeys: []string{"key1", "key2"}, + }, + { + Name: "driver1", + NodeID: "nodeX", + TopologyKeys: []string{"keyA", "keyB"}, + }, + }, + }, + }, + { + // single driver with duplicate topology keys in driver specs + ObjectMeta: metav1.ObjectMeta{Name: "foo11"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "driver1", + NodeID: "node1", + TopologyKeys: []string{"key1", "key1"}, + }, + }, + }, + }, + { + // multiple drivers with one set of duplicate topology keys in driver specs + ObjectMeta: metav1.ObjectMeta{Name: "foo12"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "driver1", + NodeID: "node1", + TopologyKeys: []string{"key1"}, + }, + { + Name: "driver2", + NodeID: "nodeX", + TopologyKeys: []string{"keyA", "keyA"}, + }, + }, + }, + }, + { + // Empty NodeID + ObjectMeta: metav1.ObjectMeta{Name: "foo13"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: driverName, + NodeID: "", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // topology prefix should be lower case + ObjectMeta: metav1.ObjectMeta{Name: "foo14"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: driverName, + NodeID: "node1", + TopologyKeys: []string{"Company.Com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + } + + for _, csiNode := range errorCases { + if errs := ValidateCSINode(&csiNode); len(errs) == 0 { + t.Errorf("Expected failure for test: %v", csiNode) + } + } +} + +func TestCSINodeUpdateValidation(t *testing.T) { + //driverName := "driver-name" + //driverName2 := "1io.kubernetes-storage-2-csi-driver3" + //longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver" + nodeID := "nodeA" + + old := storage.CSINode{ + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver-1", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + { + Name: "io.kubernetes.storage.csi.driver-2", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + } + + successCases := []storage.CSINode{ + { + // no change + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver-1", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + { + Name: "io.kubernetes.storage.csi.driver-2", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // remove a driver + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver-1", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // add a driver + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver-1", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + { + Name: "io.kubernetes.storage.csi.driver-2", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + { + Name: "io.kubernetes.storage.csi.driver-3", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // remove a driver and add a driver + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver-1", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + { + Name: "io.kubernetes.storage.csi.new-driver", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + } + + for _, csiNode := range successCases { + if errs := ValidateCSINodeUpdate(&csiNode, &old); len(errs) != 0 { + t.Errorf("expected success: %+v", errs) + } + } + + errorCases := []storage.CSINode{ + { + // invalid change node id + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver-1", + NodeID: "nodeB", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + { + Name: "io.kubernetes.storage.csi.driver-2", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + { + // invalid change topology keys + ObjectMeta: metav1.ObjectMeta{Name: "foo1"}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "io.kubernetes.storage.csi.driver-1", + NodeID: "nodeB", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + { + Name: "io.kubernetes.storage.csi.driver-2", + NodeID: nodeID, + TopologyKeys: []string{"company.com/zone2"}, + }, + }, + }, + }, + } + + for _, csiNode := range errorCases { + if errs := ValidateCSINodeUpdate(&csiNode, &old); len(errs) == 0 { + t.Errorf("Expected failure for test: %+v", csiNode) + } + } +} + +func TestCSIDriverValidation(t *testing.T) { + driverName := "test-driver" + longName := "my-a-b-c-d-c-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-ABCDEFGHIJKLMNOPQRSTUVWXYZ-driver" + invalidName := "-invalid-@#$%^&*()-" + attachRequired := true + attachNotRequired := false + podInfoOnMount := true + notPodInfoOnMount := false + successCases := []storage.CSIDriver{ + { + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + { + // driver name: dot only + ObjectMeta: metav1.ObjectMeta{Name: "io.kubernetes.storage.csi.driver"}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + { + // driver name: dash only + ObjectMeta: metav1.ObjectMeta{Name: "io-kubernetes-storage-csi-driver"}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: ¬PodInfoOnMount, + }, + }, + { + // driver name: numbers + ObjectMeta: metav1.ObjectMeta{Name: "1csi2driver3"}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + { + // driver name: dot and dash + ObjectMeta: metav1.ObjectMeta{Name: "io.kubernetes.storage.csi-driver"}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: ¬PodInfoOnMount, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + }, + }, + } + + for _, csiDriver := range successCases { + if errs := ValidateCSIDriver(&csiDriver); len(errs) != 0 { + t.Errorf("expected success: %v", errs) + } + } + errorCases := []storage.CSIDriver{ + { + ObjectMeta: metav1.ObjectMeta{Name: invalidName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{Name: longName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + }, + }, + { + // AttachRequired not set + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: nil, + PodInfoOnMount: &podInfoOnMount, + }, + }, + { + // AttachRequired not set + ObjectMeta: metav1.ObjectMeta{Name: driverName}, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachNotRequired, + PodInfoOnMount: nil, + }, + }, + } + + for _, csiDriver := range errorCases { + if errs := ValidateCSIDriver(&csiDriver); len(errs) == 0 { + t.Errorf("Expected failure for test: %v", csiDriver) + } + } +} diff --git a/pkg/apis/storage/zz_generated.deepcopy.go b/pkg/apis/storage/zz_generated.deepcopy.go index f1391c98a2..69d40d6eb2 100644 --- a/pkg/apis/storage/zz_generated.deepcopy.go +++ b/pkg/apis/storage/zz_generated.deepcopy.go @@ -25,6 +25,196 @@ import ( core "k8s.io/kubernetes/pkg/apis/core" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIDriver) DeepCopyInto(out *CSIDriver) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriver. +func (in *CSIDriver) DeepCopy() *CSIDriver { + if in == nil { + return nil + } + out := new(CSIDriver) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSIDriver) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIDriverList) DeepCopyInto(out *CSIDriverList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CSIDriver, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverList. +func (in *CSIDriverList) DeepCopy() *CSIDriverList { + if in == nil { + return nil + } + out := new(CSIDriverList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSIDriverList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) { + *out = *in + if in.AttachRequired != nil { + in, out := &in.AttachRequired, &out.AttachRequired + *out = new(bool) + **out = **in + } + if in.PodInfoOnMount != nil { + in, out := &in.PodInfoOnMount, &out.PodInfoOnMount + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverSpec. +func (in *CSIDriverSpec) DeepCopy() *CSIDriverSpec { + if in == nil { + return nil + } + out := new(CSIDriverSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINode) DeepCopyInto(out *CSINode) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINode. +func (in *CSINode) DeepCopy() *CSINode { + if in == nil { + return nil + } + out := new(CSINode) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSINode) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINodeDriver) DeepCopyInto(out *CSINodeDriver) { + *out = *in + if in.TopologyKeys != nil { + in, out := &in.TopologyKeys, &out.TopologyKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeDriver. +func (in *CSINodeDriver) DeepCopy() *CSINodeDriver { + if in == nil { + return nil + } + out := new(CSINodeDriver) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINodeList) DeepCopyInto(out *CSINodeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CSINode, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeList. +func (in *CSINodeList) DeepCopy() *CSINodeList { + if in == nil { + return nil + } + out := new(CSINodeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSINodeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINodeSpec) DeepCopyInto(out *CSINodeSpec) { + *out = *in + if in.Drivers != nil { + in, out := &in.Drivers, &out.Drivers + *out = make([]CSINodeDriver, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeSpec. +func (in *CSINodeSpec) DeepCopy() *CSINodeSpec { + if in == nil { + return nil + } + out := new(CSINodeSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StorageClass) DeepCopyInto(out *StorageClass) { *out = *in diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/BUILD b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/BUILD index 240a6baa84..56402f0e3d 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/BUILD +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/BUILD @@ -8,6 +8,8 @@ load( go_library( name = "go_default_library", srcs = [ + "csidriver.go", + "csinode.go", "doc.go", "generated_expansion.go", "storage_client.go", diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/csidriver.go b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/csidriver.go new file mode 100644 index 0000000000..438969207f --- /dev/null +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/csidriver.go @@ -0,0 +1,164 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + storage "k8s.io/kubernetes/pkg/apis/storage" + scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme" +) + +// CSIDriversGetter has a method to return a CSIDriverInterface. +// A group's client should implement this interface. +type CSIDriversGetter interface { + CSIDrivers() CSIDriverInterface +} + +// CSIDriverInterface has methods to work with CSIDriver resources. +type CSIDriverInterface interface { + Create(*storage.CSIDriver) (*storage.CSIDriver, error) + Update(*storage.CSIDriver) (*storage.CSIDriver, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*storage.CSIDriver, error) + List(opts v1.ListOptions) (*storage.CSIDriverList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSIDriver, err error) + CSIDriverExpansion +} + +// cSIDrivers implements CSIDriverInterface +type cSIDrivers struct { + client rest.Interface +} + +// newCSIDrivers returns a CSIDrivers +func newCSIDrivers(c *StorageClient) *cSIDrivers { + return &cSIDrivers{ + client: c.RESTClient(), + } +} + +// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any. +func (c *cSIDrivers) Get(name string, options v1.GetOptions) (result *storage.CSIDriver, err error) { + result = &storage.CSIDriver{} + err = c.client.Get(). + Resource("csidrivers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors. +func (c *cSIDrivers) List(opts v1.ListOptions) (result *storage.CSIDriverList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &storage.CSIDriverList{} + err = c.client.Get(). + Resource("csidrivers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested cSIDrivers. +func (c *cSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("csidrivers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *cSIDrivers) Create(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) { + result = &storage.CSIDriver{} + err = c.client.Post(). + Resource("csidrivers"). + Body(cSIDriver). + Do(). + Into(result) + return +} + +// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *cSIDrivers) Update(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) { + result = &storage.CSIDriver{} + err = c.client.Put(). + Resource("csidrivers"). + Name(cSIDriver.Name). + Body(cSIDriver). + Do(). + Into(result) + return +} + +// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs. +func (c *cSIDrivers) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("csidrivers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *cSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("csidrivers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched cSIDriver. +func (c *cSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSIDriver, err error) { + result = &storage.CSIDriver{} + err = c.client.Patch(pt). + Resource("csidrivers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/csinode.go b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/csinode.go new file mode 100644 index 0000000000..b1d926fcdf --- /dev/null +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/csinode.go @@ -0,0 +1,164 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package internalversion + +import ( + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + storage "k8s.io/kubernetes/pkg/apis/storage" + scheme "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/scheme" +) + +// CSINodesGetter has a method to return a CSINodeInterface. +// A group's client should implement this interface. +type CSINodesGetter interface { + CSINodes() CSINodeInterface +} + +// CSINodeInterface has methods to work with CSINode resources. +type CSINodeInterface interface { + Create(*storage.CSINode) (*storage.CSINode, error) + Update(*storage.CSINode) (*storage.CSINode, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*storage.CSINode, error) + List(opts v1.ListOptions) (*storage.CSINodeList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSINode, err error) + CSINodeExpansion +} + +// cSINodes implements CSINodeInterface +type cSINodes struct { + client rest.Interface +} + +// newCSINodes returns a CSINodes +func newCSINodes(c *StorageClient) *cSINodes { + return &cSINodes{ + client: c.RESTClient(), + } +} + +// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any. +func (c *cSINodes) Get(name string, options v1.GetOptions) (result *storage.CSINode, err error) { + result = &storage.CSINode{} + err = c.client.Get(). + Resource("csinodes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CSINodes that match those selectors. +func (c *cSINodes) List(opts v1.ListOptions) (result *storage.CSINodeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &storage.CSINodeList{} + err = c.client.Get(). + Resource("csinodes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested cSINodes. +func (c *cSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("csinodes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *cSINodes) Create(cSINode *storage.CSINode) (result *storage.CSINode, err error) { + result = &storage.CSINode{} + err = c.client.Post(). + Resource("csinodes"). + Body(cSINode). + Do(). + Into(result) + return +} + +// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *cSINodes) Update(cSINode *storage.CSINode) (result *storage.CSINode, err error) { + result = &storage.CSINode{} + err = c.client.Put(). + Resource("csinodes"). + Name(cSINode.Name). + Body(cSINode). + Do(). + Into(result) + return +} + +// Delete takes name of the cSINode and deletes it. Returns an error if one occurs. +func (c *cSINodes) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("csinodes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *cSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("csinodes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched cSINode. +func (c *cSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSINode, err error) { + result = &storage.CSINode{} + err = c.client.Patch(pt). + Resource("csinodes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/BUILD b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/BUILD index 2af047d157..335907eb4d 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/BUILD +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/BUILD @@ -9,6 +9,8 @@ go_library( name = "go_default_library", srcs = [ "doc.go", + "fake_csidriver.go", + "fake_csinode.go", "fake_storage_client.go", "fake_storageclass.go", "fake_volumeattachment.go", diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_csidriver.go b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_csidriver.go new file mode 100644 index 0000000000..cf34374d09 --- /dev/null +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_csidriver.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + storage "k8s.io/kubernetes/pkg/apis/storage" +) + +// FakeCSIDrivers implements CSIDriverInterface +type FakeCSIDrivers struct { + Fake *FakeStorage +} + +var csidriversResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "", Resource: "csidrivers"} + +var csidriversKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "", Kind: "CSIDriver"} + +// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any. +func (c *FakeCSIDrivers) Get(name string, options v1.GetOptions) (result *storage.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csidriversResource, name), &storage.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSIDriver), err +} + +// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors. +func (c *FakeCSIDrivers) List(opts v1.ListOptions) (result *storage.CSIDriverList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csidriversResource, csidriversKind, opts), &storage.CSIDriverList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &storage.CSIDriverList{ListMeta: obj.(*storage.CSIDriverList).ListMeta} + for _, item := range obj.(*storage.CSIDriverList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSIDrivers. +func (c *FakeCSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csidriversResource, opts)) +} + +// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Create(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csidriversResource, cSIDriver), &storage.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSIDriver), err +} + +// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Update(cSIDriver *storage.CSIDriver) (result *storage.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csidriversResource, cSIDriver), &storage.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSIDriver), err +} + +// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs. +func (c *FakeCSIDrivers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(csidriversResource, name), &storage.CSIDriver{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csidriversResource, listOptions) + + _, err := c.Fake.Invokes(action, &storage.CSIDriverList{}) + return err +} + +// Patch applies the patch and returns the patched cSIDriver. +func (c *FakeCSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, name, pt, data, subresources...), &storage.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSIDriver), err +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_csinode.go b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_csinode.go new file mode 100644 index 0000000000..fc6df1b914 --- /dev/null +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_csinode.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + storage "k8s.io/kubernetes/pkg/apis/storage" +) + +// FakeCSINodes implements CSINodeInterface +type FakeCSINodes struct { + Fake *FakeStorage +} + +var csinodesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "", Resource: "csinodes"} + +var csinodesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "", Kind: "CSINode"} + +// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any. +func (c *FakeCSINodes) Get(name string, options v1.GetOptions) (result *storage.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csinodesResource, name), &storage.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSINode), err +} + +// List takes label and field selectors, and returns the list of CSINodes that match those selectors. +func (c *FakeCSINodes) List(opts v1.ListOptions) (result *storage.CSINodeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csinodesResource, csinodesKind, opts), &storage.CSINodeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &storage.CSINodeList{ListMeta: obj.(*storage.CSINodeList).ListMeta} + for _, item := range obj.(*storage.CSINodeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSINodes. +func (c *FakeCSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csinodesResource, opts)) +} + +// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Create(cSINode *storage.CSINode) (result *storage.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csinodesResource, cSINode), &storage.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSINode), err +} + +// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Update(cSINode *storage.CSINode) (result *storage.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csinodesResource, cSINode), &storage.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSINode), err +} + +// Delete takes name of the cSINode and deletes it. Returns an error if one occurs. +func (c *FakeCSINodes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(csinodesResource, name), &storage.CSINode{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csinodesResource, listOptions) + + _, err := c.Fake.Invokes(action, &storage.CSINodeList{}) + return err +} + +// Patch applies the patch and returns the patched cSINode. +func (c *FakeCSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *storage.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, name, pt, data, subresources...), &storage.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*storage.CSINode), err +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_storage_client.go b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_storage_client.go index 1935235eac..9b8cb5eb8e 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_storage_client.go +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/fake/fake_storage_client.go @@ -28,6 +28,14 @@ type FakeStorage struct { *testing.Fake } +func (c *FakeStorage) CSIDrivers() internalversion.CSIDriverInterface { + return &FakeCSIDrivers{c} +} + +func (c *FakeStorage) CSINodes() internalversion.CSINodeInterface { + return &FakeCSINodes{c} +} + func (c *FakeStorage) StorageClasses() internalversion.StorageClassInterface { return &FakeStorageClasses{c} } diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/generated_expansion.go b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/generated_expansion.go index d74dc56fe9..873439a3a2 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/generated_expansion.go +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/generated_expansion.go @@ -18,6 +18,10 @@ limitations under the License. package internalversion +type CSIDriverExpansion interface{} + +type CSINodeExpansion interface{} + type StorageClassExpansion interface{} type VolumeAttachmentExpansion interface{} diff --git a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/storage_client.go b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/storage_client.go index 9272e2b9c5..823bfe82fa 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/storage_client.go +++ b/pkg/client/clientset_generated/internalclientset/typed/storage/internalversion/storage_client.go @@ -25,6 +25,8 @@ import ( type StorageInterface interface { RESTClient() rest.Interface + CSIDriversGetter + CSINodesGetter StorageClassesGetter VolumeAttachmentsGetter } @@ -34,6 +36,14 @@ type StorageClient struct { restClient rest.Interface } +func (c *StorageClient) CSIDrivers() CSIDriverInterface { + return newCSIDrivers(c) +} + +func (c *StorageClient) CSINodes() CSINodeInterface { + return newCSINodes(c) +} + func (c *StorageClient) StorageClasses() StorageClassInterface { return newStorageClasses(c) } diff --git a/pkg/controller/volume/attachdetach/BUILD b/pkg/controller/volume/attachdetach/BUILD index 3128c2b342..d513330fef 100644 --- a/pkg/controller/volume/attachdetach/BUILD +++ b/pkg/controller/volume/attachdetach/BUILD @@ -40,7 +40,6 @@ go_library( "//staging/src/k8s.io/client-go/tools/record:go_default_library", "//staging/src/k8s.io/client-go/util/workqueue:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/pkg/controller/volume/attachdetach/attach_detach_controller.go b/pkg/controller/volume/attachdetach/attach_detach_controller.go index 66a4c6c66c..c67dd88f25 100644 --- a/pkg/controller/volume/attachdetach/attach_detach_controller.go +++ b/pkg/controller/volume/attachdetach/attach_detach_controller.go @@ -39,7 +39,6 @@ import ( "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" cloudprovider "k8s.io/cloud-provider" - csiclient "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/klog" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/volume/attachdetach/cache" @@ -98,7 +97,6 @@ type AttachDetachController interface { // NewAttachDetachController returns a new instance of AttachDetachController. func NewAttachDetachController( kubeClient clientset.Interface, - csiClient csiclient.Interface, podInformer coreinformers.PodInformer, nodeInformer coreinformers.NodeInformer, pvcInformer coreinformers.PersistentVolumeClaimInformer, @@ -125,7 +123,6 @@ func NewAttachDetachController( // deleted (probably can't do this with sharedInformer), etc. adc := &attachDetachController{ kubeClient: kubeClient, - csiClient: csiClient, pvcLister: pvcInformer.Lister(), pvcsSynced: pvcInformer.Informer().HasSynced, pvLister: pvInformer.Lister(), @@ -241,10 +238,6 @@ type attachDetachController struct { // the API server. kubeClient clientset.Interface - // csiClient is the csi.storage.k8s.io API client used by volumehost to communicate with - // the API server. - csiClient csiclient.Interface - // pvcLister is the shared PVC lister used to fetch and store PVC // objects from the API server. It is shared with other controllers and // therefore the PVC objects in its store should be treated as immutable. @@ -766,10 +759,6 @@ func (adc *attachDetachController) GetEventRecorder() record.EventRecorder { return adc.recorder } -func (adc *attachDetachController) GetCSIClient() csiclient.Interface { - return adc.csiClient -} - func (adc *attachDetachController) GetSubpather() subpath.Interface { // Subpaths not needed in attachdetach controller return nil diff --git a/pkg/controller/volume/attachdetach/attach_detach_controller_test.go b/pkg/controller/volume/attachdetach/attach_detach_controller_test.go index c197ae2dd8..2c5c2bc06b 100644 --- a/pkg/controller/volume/attachdetach/attach_detach_controller_test.go +++ b/pkg/controller/volume/attachdetach/attach_detach_controller_test.go @@ -40,7 +40,6 @@ func Test_NewAttachDetachController_Positive(t *testing.T) { // Act _, err := NewAttachDetachController( fakeKubeClient, - nil, /* csiClient */ informerFactory.Core().V1().Pods(), informerFactory.Core().V1().Nodes(), informerFactory.Core().V1().PersistentVolumeClaims(), @@ -215,7 +214,6 @@ func attachDetachRecoveryTestCase(t *testing.T, extraPods1 []*v1.Pod, extraPods2 // Create the controller adcObj, err := NewAttachDetachController( fakeKubeClient, - nil, /* csiClient */ informerFactory.Core().V1().Pods(), informerFactory.Core().V1().Nodes(), informerFactory.Core().V1().PersistentVolumeClaims(), diff --git a/pkg/controller/volume/expand/BUILD b/pkg/controller/volume/expand/BUILD index 63bca838cd..c8e3e62f27 100644 --- a/pkg/controller/volume/expand/BUILD +++ b/pkg/controller/volume/expand/BUILD @@ -36,7 +36,6 @@ go_library( "//staging/src/k8s.io/client-go/tools/cache:go_default_library", "//staging/src/k8s.io/client-go/tools/record:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/pkg/controller/volume/expand/expand_controller.go b/pkg/controller/volume/expand/expand_controller.go index 9eb82138a2..b6885f47f6 100644 --- a/pkg/controller/volume/expand/expand_controller.go +++ b/pkg/controller/volume/expand/expand_controller.go @@ -38,7 +38,6 @@ import ( kcache "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" cloudprovider "k8s.io/cloud-provider" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller/volume/events" "k8s.io/kubernetes/pkg/controller/volume/expand/cache" @@ -336,11 +335,6 @@ func (expc *expandController) GetEventRecorder() record.EventRecorder { return expc.recorder } -func (expc *expandController) GetCSIClient() csiclientset.Interface { - // No volume plugin in expand controller needs csi.storage.k8s.io - return nil -} - func (expc *expandController) GetSubpather() subpath.Interface { // not needed for expand controller return nil diff --git a/pkg/controller/volume/persistentvolume/BUILD b/pkg/controller/volume/persistentvolume/BUILD index 52b6df3aac..041545ddfc 100644 --- a/pkg/controller/volume/persistentvolume/BUILD +++ b/pkg/controller/volume/persistentvolume/BUILD @@ -61,7 +61,6 @@ go_library( "//staging/src/k8s.io/client-go/util/workqueue:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/cloud-provider/volume/errors:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//staging/src/k8s.io/csi-translation-lib:go_default_library", "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", "//vendor/k8s.io/klog:go_default_library", diff --git a/pkg/controller/volume/persistentvolume/volume_host.go b/pkg/controller/volume/persistentvolume/volume_host.go index 1baebc9de2..76f3de2ebc 100644 --- a/pkg/controller/volume/persistentvolume/volume_host.go +++ b/pkg/controller/volume/persistentvolume/volume_host.go @@ -26,7 +26,6 @@ import ( clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/record" cloudprovider "k8s.io/cloud-provider" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/klog" "k8s.io/kubernetes/pkg/util/mount" vol "k8s.io/kubernetes/pkg/volume" @@ -133,11 +132,6 @@ func (ctrl *PersistentVolumeController) GetEventRecorder() record.EventRecorder return ctrl.eventRecorder } -func (ctrl *PersistentVolumeController) GetCSIClient() csiclientset.Interface { - // No volume plugin needs csi.storage.k8s.io client in PV controller. - return nil -} - func (ctrl *PersistentVolumeController) GetSubpather() subpath.Interface { // No volume plugin needs Subpaths in PV controller. return nil diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 1eea44a582..ef934af25b 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -195,12 +195,14 @@ const ( // owner: @saad-ali // alpha: v1.12 - // Enable all logic related to the CSIDriver API object in csi.storage.k8s.io + // beta: v1.14 + // Enable all logic related to the CSIDriver API object in storage.k8s.io CSIDriverRegistry utilfeature.Feature = "CSIDriverRegistry" // owner: @verult // alpha: v1.12 - // Enable all logic related to the CSINodeInfo API object in csi.storage.k8s.io + // beta: v1.14 + // Enable all logic related to the CSINode API object in storage.k8s.io CSINodeInfo utilfeature.Feature = "CSINodeInfo" // owner @MrHohn @@ -448,8 +450,8 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS MountContainers: {Default: false, PreRelease: utilfeature.Alpha}, VolumeScheduling: {Default: true, PreRelease: utilfeature.GA, LockToDefault: true}, // remove in 1.16 CSIPersistentVolume: {Default: true, PreRelease: utilfeature.GA}, - CSIDriverRegistry: {Default: false, PreRelease: utilfeature.Alpha}, - CSINodeInfo: {Default: false, PreRelease: utilfeature.Alpha}, + CSIDriverRegistry: {Default: true, PreRelease: utilfeature.Beta}, + CSINodeInfo: {Default: true, PreRelease: utilfeature.Beta}, CustomPodDNS: {Default: true, PreRelease: utilfeature.GA, LockToDefault: true}, // remove in 1.16 BlockVolume: {Default: true, PreRelease: utilfeature.Beta}, StorageObjectInUseProtection: {Default: true, PreRelease: utilfeature.GA}, diff --git a/pkg/kubeapiserver/BUILD b/pkg/kubeapiserver/BUILD index 9b0ec00572..b66f74d9ae 100644 --- a/pkg/kubeapiserver/BUILD +++ b/pkg/kubeapiserver/BUILD @@ -21,6 +21,8 @@ go_library( "//pkg/apis/extensions:go_default_library", "//pkg/apis/networking:go_default_library", "//pkg/apis/policy:go_default_library", + "//pkg/apis/storage:go_default_library", + "//pkg/features:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library", @@ -28,6 +30,7 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/server/resourceconfig:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/storage:go_default_library", "//staging/src/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", ], ) diff --git a/pkg/kubeapiserver/default_storage_factory_builder.go b/pkg/kubeapiserver/default_storage_factory_builder.go index a3dbefc5a0..6a829e8a9f 100644 --- a/pkg/kubeapiserver/default_storage_factory_builder.go +++ b/pkg/kubeapiserver/default_storage_factory_builder.go @@ -26,6 +26,7 @@ import ( "k8s.io/apiserver/pkg/server/resourceconfig" serverstorage "k8s.io/apiserver/pkg/server/storage" "k8s.io/apiserver/pkg/storage/storagebackend" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/batch" @@ -34,6 +35,8 @@ import ( "k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/networking" "k8s.io/kubernetes/pkg/apis/policy" + apisstorage "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/features" ) // SpecialDefaultResourcePrefixes are prefixes compiled into Kubernetes. @@ -48,12 +51,23 @@ var SpecialDefaultResourcePrefixes = map[schema.GroupResource]string{ } func NewStorageFactoryConfig() *StorageFactoryConfig { + + resources := []schema.GroupVersionResource{ + batch.Resource("cronjobs").WithVersion("v1beta1"), + } + // add csinodes if CSINodeInfo feature gate is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { + resources = append(resources, apisstorage.Resource("csinodes").WithVersion("v1beta1")) + } + // add csidrivers if CSIDriverRegistry feature gate is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { + resources = append(resources, apisstorage.Resource("csidrivers").WithVersion("v1beta1")) + } + return &StorageFactoryConfig{ - Serializer: legacyscheme.Codecs, - DefaultResourceEncoding: serverstorage.NewDefaultResourceEncodingConfig(legacyscheme.Scheme), - ResourceEncodingOverrides: []schema.GroupVersionResource{ - batch.Resource("cronjobs").WithVersion("v1beta1"), - }, + Serializer: legacyscheme.Codecs, + DefaultResourceEncoding: serverstorage.NewDefaultResourceEncodingConfig(legacyscheme.Scheme), + ResourceEncodingOverrides: resources, } } diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index b824a8dbbb..5616e1c6e7 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -140,7 +140,6 @@ go_library( "//staging/src/k8s.io/client-go/util/certificate:go_default_library", "//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//staging/src/k8s.io/node-api/pkg/client/clientset/versioned:go_default_library", "//third_party/forked/golang/expansion:go_default_library", "//vendor/github.com/golang/groupcache/lru:go_default_library", diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index 9b63bcd484..edee172ef1 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -51,7 +51,6 @@ import ( "k8s.io/client-go/util/certificate" "k8s.io/client-go/util/flowcontrol" cloudprovider "k8s.io/cloud-provider" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/klog" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/features" @@ -249,7 +248,6 @@ type Dependencies struct { HeartbeatClient clientset.Interface OnHeartbeatFailure func() KubeClient clientset.Interface - CSIClient csiclientset.Interface NodeAPIClient nodeapiclientset.Interface Mounter mount.Interface OOMAdjuster *oom.OOMAdjuster @@ -493,7 +491,6 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, hostnameOverridden: len(hostnameOverride) > 0, nodeName: nodeName, kubeClient: kubeDeps.KubeClient, - csiClient: kubeDeps.CSIClient, heartbeatClient: kubeDeps.HeartbeatClient, onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure, rootDirectory: rootDirectory, @@ -898,7 +895,6 @@ type Kubelet struct { nodeName types.NodeName runtimeCache kubecontainer.RuntimeCache kubeClient clientset.Interface - csiClient csiclientset.Interface heartbeatClient clientset.Interface iptClient utilipt.Interface rootDirectory string diff --git a/pkg/kubelet/volume_host.go b/pkg/kubelet/volume_host.go index 78797d8958..e269c023b5 100644 --- a/pkg/kubelet/volume_host.go +++ b/pkg/kubelet/volume_host.go @@ -30,7 +30,6 @@ import ( clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/record" cloudprovider "k8s.io/cloud-provider" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/kubelet/configmap" "k8s.io/kubernetes/pkg/kubelet/container" @@ -123,10 +122,6 @@ func (kvh *kubeletVolumeHost) GetKubeClient() clientset.Interface { return kvh.kubelet.kubeClient } -func (kvh *kubeletVolumeHost) GetCSIClient() csiclientset.Interface { - return kvh.kubelet.csiClient -} - func (kvh *kubeletVolumeHost) GetSubpather() subpath.Interface { return kvh.kubelet.subpather } diff --git a/pkg/registry/BUILD b/pkg/registry/BUILD index acf2054ffb..5d432d0aa7 100644 --- a/pkg/registry/BUILD +++ b/pkg/registry/BUILD @@ -85,6 +85,8 @@ filegroup( "//pkg/registry/scheduling/rest:all-srcs", "//pkg/registry/settings/podpreset:all-srcs", "//pkg/registry/settings/rest:all-srcs", + "//pkg/registry/storage/csidriver:all-srcs", + "//pkg/registry/storage/csinode:all-srcs", "//pkg/registry/storage/rest:all-srcs", "//pkg/registry/storage/storageclass:all-srcs", "//pkg/registry/storage/volumeattachment:all-srcs", diff --git a/pkg/registry/storage/csidriver/BUILD b/pkg/registry/storage/csidriver/BUILD new file mode 100644 index 0000000000..41953486c8 --- /dev/null +++ b/pkg/registry/storage/csidriver/BUILD @@ -0,0 +1,48 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "strategy.go", + ], + importpath = "k8s.io/kubernetes/pkg/registry/storage/csidriver", + visibility = ["//visibility:public"], + deps = [ + "//pkg/api/legacyscheme:go_default_library", + "//pkg/apis/storage:go_default_library", + "//pkg/apis/storage/validation:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//pkg/registry/storage/csidriver/storage:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = ["strategy_test.go"], + embed = [":go_default_library"], + deps = [ + "//pkg/apis/storage:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", + ], +) diff --git a/pkg/registry/storage/csidriver/doc.go b/pkg/registry/storage/csidriver/doc.go new file mode 100644 index 0000000000..edb13124fc --- /dev/null +++ b/pkg/registry/storage/csidriver/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package csidriver provides Registry interface and its REST +// implementation for storing csidriver api objects. +package csidriver diff --git a/pkg/registry/storage/csidriver/storage/BUILD b/pkg/registry/storage/csidriver/storage/BUILD new file mode 100644 index 0000000000..bdbddb6134 --- /dev/null +++ b/pkg/registry/storage/csidriver/storage/BUILD @@ -0,0 +1,48 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["storage.go"], + importpath = "k8s.io/kubernetes/pkg/registry/storage/csidriver/storage", + visibility = ["//visibility:public"], + deps = [ + "//pkg/apis/storage:go_default_library", + "//pkg/registry/storage/csidriver:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = ["storage_test.go"], + embed = [":go_default_library"], + deps = [ + "//pkg/api/testapi:go_default_library", + "//pkg/apis/storage:go_default_library", + "//pkg/registry/registrytest:go_default_library", + "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", + ], +) diff --git a/pkg/registry/storage/csidriver/storage/storage.go b/pkg/registry/storage/csidriver/storage/storage.go new file mode 100644 index 0000000000..c22747d6f2 --- /dev/null +++ b/pkg/registry/storage/csidriver/storage/storage.go @@ -0,0 +1,57 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + storageapi "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/registry/storage/csidriver" +) + +// CSIDriverStorage includes storage for CSIDrivers and all subresources +type CSIDriverStorage struct { + CSIDriver *REST +} + +// REST object that will work for CSIDrivers +type REST struct { + *genericregistry.Store +} + +// NewStorage returns a RESTStorage object that will work against CSIDrivers +func NewStorage(optsGetter generic.RESTOptionsGetter) *CSIDriverStorage { + store := &genericregistry.Store{ + NewFunc: func() runtime.Object { return &storageapi.CSIDriver{} }, + NewListFunc: func() runtime.Object { return &storageapi.CSIDriverList{} }, + DefaultQualifiedResource: storageapi.Resource("csidrivers"), + + CreateStrategy: csidriver.Strategy, + UpdateStrategy: csidriver.Strategy, + DeleteStrategy: csidriver.Strategy, + ReturnDeletedObject: true, + } + options := &generic.StoreOptions{RESTOptions: optsGetter} + if err := store.CompleteWithOptions(options); err != nil { + panic(err) // TODO: Propagate error up + } + + return &CSIDriverStorage{ + CSIDriver: &REST{store}, + } +} diff --git a/pkg/registry/storage/csidriver/storage/storage_test.go b/pkg/registry/storage/csidriver/storage/storage_test.go new file mode 100644 index 0000000000..2cc848f6dc --- /dev/null +++ b/pkg/registry/storage/csidriver/storage/storage_test.go @@ -0,0 +1,179 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + "testing" + + storageapiv1beta1 "k8s.io/api/storage/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" + etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" + "k8s.io/kubernetes/pkg/api/testapi" + storageapi "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/registry/registrytest" +) + +func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) { + etcdStorage, server := registrytest.NewEtcdStorage(t, storageapi.GroupName) + restOptions := generic.RESTOptions{ + StorageConfig: etcdStorage, + Decorator: generic.UndecoratedStorage, + DeleteCollectionWorkers: 1, + ResourcePrefix: "csidrivers", + } + csiDriverStorage := NewStorage(restOptions) + return csiDriverStorage.CSIDriver, server +} + +func validNewCSIDriver(name string) *storageapi.CSIDriver { + attachRequired := true + podInfoOnMount := true + return &storageapi.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: storageapi.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + } +} + +func TestCreate(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + csiDriver := validNewCSIDriver("foo") + csiDriver.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"} + attachNotRequired := false + notPodInfoOnMount := false + test.TestCreate( + // valid + csiDriver, + // invalid + &storageapi.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"}, + Spec: storageapi.CSIDriverSpec{ + AttachRequired: &attachNotRequired, + PodInfoOnMount: ¬PodInfoOnMount, + }, + }, + ) +} + +func TestUpdate(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + notPodInfoOnMount := false + + test.TestUpdate( + // valid + validNewCSIDriver("foo"), + //invalid update + func(obj runtime.Object) runtime.Object { + object := obj.(*storageapi.CSIDriver) + object.Spec.PodInfoOnMount = ¬PodInfoOnMount + return object + }, + ) +} + +func TestDelete(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject() + test.TestDelete(validNewCSIDriver("foo")) +} + +func TestGet(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + test.TestGet(validNewCSIDriver("foo")) +} + +func TestList(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + test.TestList(validNewCSIDriver("foo")) +} + +func TestWatch(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + test.TestWatch( + validNewCSIDriver("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + }, + ) +} diff --git a/pkg/registry/storage/csidriver/strategy.go b/pkg/registry/storage/csidriver/strategy.go new file mode 100644 index 0000000000..1f534b2e76 --- /dev/null +++ b/pkg/registry/storage/csidriver/strategy.go @@ -0,0 +1,78 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package csidriver + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/apis/storage/validation" +) + +// csiDriverStrategy implements behavior for CSIDriver objects +type csiDriverStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// Strategy is the default logic that applies when creating and updating +// CSIDriver objects via the REST API. +var Strategy = csiDriverStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} + +func (csiDriverStrategy) NamespaceScoped() bool { + return false +} + +// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation. +func (csiDriverStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { +} + +func (csiDriverStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { + csiDriver := obj.(*storage.CSIDriver) + + errs := validation.ValidateCSIDriver(csiDriver) + errs = append(errs, validation.ValidateCSIDriver(csiDriver)...) + + return errs +} + +// Canonicalize normalizes the object after validation. +func (csiDriverStrategy) Canonicalize(obj runtime.Object) { +} + +func (csiDriverStrategy) AllowCreateOnUpdate() bool { + return false +} + +// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a CSIDriver +func (csiDriverStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { +} + +func (csiDriverStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + newCSIDriverObj := obj.(*storage.CSIDriver) + oldCSIDriverObj := old.(*storage.CSIDriver) + errorList := validation.ValidateCSIDriver(newCSIDriverObj) + return append(errorList, validation.ValidateCSIDriverUpdate(newCSIDriverObj, oldCSIDriverObj)...) +} + +func (csiDriverStrategy) AllowUnconditionalUpdate() bool { + return false +} diff --git a/pkg/registry/storage/csidriver/strategy_test.go b/pkg/registry/storage/csidriver/strategy_test.go new file mode 100644 index 0000000000..e5334fc1ed --- /dev/null +++ b/pkg/registry/storage/csidriver/strategy_test.go @@ -0,0 +1,155 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package csidriver + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/kubernetes/pkg/apis/storage" +) + +func getValidCSIDriver(name string) *storage.CSIDriver { + attachRequired := true + podInfoOnMount := true + return &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + } +} + +func TestCSIDriverStrategy(t *testing.T) { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{ + APIGroup: "storage.k8s.io", + APIVersion: "v1beta1", + Resource: "csidrivers", + }) + if Strategy.NamespaceScoped() { + t.Errorf("CSIDriver must not be namespace scoped") + } + if Strategy.AllowCreateOnUpdate() { + t.Errorf("CSIDriver should not allow create on update") + } + + csiDriver := getValidCSIDriver("valid-csidriver") + + Strategy.PrepareForCreate(ctx, csiDriver) + + errs := Strategy.Validate(ctx, csiDriver) + if len(errs) != 0 { + t.Errorf("unexpected error validating %v", errs) + } + + // Update of spec is disallowed + newCSIDriver := csiDriver.DeepCopy() + attachNotRequired := false + newCSIDriver.Spec.AttachRequired = &attachNotRequired + + Strategy.PrepareForUpdate(ctx, newCSIDriver, csiDriver) + + errs = Strategy.ValidateUpdate(ctx, newCSIDriver, csiDriver) + if len(errs) == 0 { + t.Errorf("Expected a validation error") + } +} + +func TestCSIDriverValidation(t *testing.T) { + attachRequired := true + notAttachRequired := false + podInfoOnMount := true + notPodInfoOnMount := false + + tests := []struct { + name string + csiDriver *storage.CSIDriver + expectError bool + }{ + { + "valid csidriver", + getValidCSIDriver("foo"), + false, + }, + { + "true PodInfoOnMount and AttachRequired", + &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + false, + }, + { + "false PodInfoOnMount and AttachRequired", + &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSIDriverSpec{ + AttachRequired: ¬AttachRequired, + PodInfoOnMount: ¬PodInfoOnMount, + }, + }, + false, + }, + { + "invalid driver name", + &storage.CSIDriver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "*foo#", + }, + Spec: storage.CSIDriverSpec{ + AttachRequired: &attachRequired, + PodInfoOnMount: &podInfoOnMount, + }, + }, + true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + testValidation := func(csiDriver *storage.CSIDriver, apiVersion string) field.ErrorList { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{ + APIGroup: "storage.k8s.io", + APIVersion: "v1beta1", + Resource: "csidrivers", + }) + return Strategy.Validate(ctx, csiDriver) + } + + betaErr := testValidation(test.csiDriver, "v1beta1") + if len(betaErr) > 0 && !test.expectError { + t.Errorf("Validation of v1beta1 object failed: %+v", betaErr) + } + if len(betaErr) == 0 && test.expectError { + t.Errorf("Validation of v1beta1 object unexpectedly succeeded") + } + }) + } +} diff --git a/pkg/registry/storage/csinode/BUILD b/pkg/registry/storage/csinode/BUILD new file mode 100644 index 0000000000..fdf1f063d0 --- /dev/null +++ b/pkg/registry/storage/csinode/BUILD @@ -0,0 +1,48 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "strategy.go", + ], + importpath = "k8s.io/kubernetes/pkg/registry/storage/csinode", + visibility = ["//visibility:public"], + deps = [ + "//pkg/api/legacyscheme:go_default_library", + "//pkg/apis/storage:go_default_library", + "//pkg/apis/storage/validation:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/storage/names:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//pkg/registry/storage/csinode/storage:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = ["strategy_test.go"], + embed = [":go_default_library"], + deps = [ + "//pkg/apis/storage:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/endpoints/request:go_default_library", + ], +) diff --git a/pkg/registry/storage/csinode/doc.go b/pkg/registry/storage/csinode/doc.go new file mode 100644 index 0000000000..cfbc7bc3a9 --- /dev/null +++ b/pkg/registry/storage/csinode/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package csinode provides Registry interface and its REST +// implementation for storing csinode api objects. +package csinode diff --git a/pkg/registry/storage/csinode/storage/BUILD b/pkg/registry/storage/csinode/storage/BUILD new file mode 100644 index 0000000000..a3daa50f0a --- /dev/null +++ b/pkg/registry/storage/csinode/storage/BUILD @@ -0,0 +1,48 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "go_default_library", + srcs = ["storage.go"], + importpath = "k8s.io/kubernetes/pkg/registry/storage/csinode/storage", + visibility = ["//visibility:public"], + deps = [ + "//pkg/apis/storage:go_default_library", + "//pkg/registry/storage/csinode:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic/registry:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) + +go_test( + name = "go_default_test", + srcs = ["storage_test.go"], + embed = [":go_default_library"], + deps = [ + "//pkg/api/testapi:go_default_library", + "//pkg/apis/storage:go_default_library", + "//pkg/registry/registrytest:go_default_library", + "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", + ], +) diff --git a/pkg/registry/storage/csinode/storage/storage.go b/pkg/registry/storage/csinode/storage/storage.go new file mode 100644 index 0000000000..ecdcb5a44b --- /dev/null +++ b/pkg/registry/storage/csinode/storage/storage.go @@ -0,0 +1,57 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + storageapi "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/registry/storage/csinode" +) + +// CSINodeStorage includes storage for CSINodes and all subresources +type CSINodeStorage struct { + CSINode *REST +} + +// REST object that will work for CSINodes +type REST struct { + *genericregistry.Store +} + +// NewStorage returns a RESTStorage object that will work against CSINodes +func NewStorage(optsGetter generic.RESTOptionsGetter) *CSINodeStorage { + store := &genericregistry.Store{ + NewFunc: func() runtime.Object { return &storageapi.CSINode{} }, + NewListFunc: func() runtime.Object { return &storageapi.CSINodeList{} }, + DefaultQualifiedResource: storageapi.Resource("csinodes"), + + CreateStrategy: csinode.Strategy, + UpdateStrategy: csinode.Strategy, + DeleteStrategy: csinode.Strategy, + ReturnDeletedObject: true, + } + options := &generic.StoreOptions{RESTOptions: optsGetter} + if err := store.CompleteWithOptions(options); err != nil { + panic(err) // TODO: Propagate error up + } + + return &CSINodeStorage{ + CSINode: &REST{store}, + } +} diff --git a/pkg/registry/storage/csinode/storage/storage_test.go b/pkg/registry/storage/csinode/storage/storage_test.go new file mode 100644 index 0000000000..5cfb5756d4 --- /dev/null +++ b/pkg/registry/storage/csinode/storage/storage_test.go @@ -0,0 +1,190 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package storage + +import ( + "testing" + + storageapiv1beta1 "k8s.io/api/storage/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing" + etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" + "k8s.io/kubernetes/pkg/api/testapi" + storageapi "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/registry/registrytest" +) + +func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) { + etcdStorage, server := registrytest.NewEtcdStorage(t, storageapi.GroupName) + restOptions := generic.RESTOptions{ + StorageConfig: etcdStorage, + Decorator: generic.UndecoratedStorage, + DeleteCollectionWorkers: 1, + ResourcePrefix: "csinodes", + } + csiNodeStorage := NewStorage(restOptions) + return csiNodeStorage.CSINode, server +} + +func validNewCSINode(name string) *storageapi.CSINode { + return &storageapi.CSINode{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: storageapi.CSINodeSpec{ + Drivers: []storageapi.CSINodeDriver{ + { + Name: "valid-driver-name", + NodeID: "valid-node", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + } +} + +func TestCreate(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + csiNode := validNewCSINode("foo") + csiNode.ObjectMeta = metav1.ObjectMeta{GenerateName: "foo"} + test.TestCreate( + // valid + csiNode, + // invalid + &storageapi.CSINode{ + ObjectMeta: metav1.ObjectMeta{Name: "*BadName!"}, + Spec: storageapi.CSINodeSpec{ + Drivers: []storageapi.CSINodeDriver{ + { + Name: "invalid-name-!@#$%^&*()", + NodeID: "invalid-node-!@#$%^&*()", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + ) +} + +func TestUpdate(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + + test.TestUpdate( + // valid + validNewCSINode("foo"), + // we allow status field to be set in v1beta1 + func(obj runtime.Object) runtime.Object { + object := obj.(*storageapi.CSINode) + //object.Status = *getCSINodeStatus() + return object + }, + //invalid update + func(obj runtime.Object) runtime.Object { + object := obj.(*storageapi.CSINode) + object.Spec.Drivers[0].Name = "invalid-name-!@#$%^&*()" + return object + }, + ) +} + +func TestDelete(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject() + test.TestDelete(validNewCSINode("foo")) +} + +func TestGet(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + test.TestGet(validNewCSINode("foo")) +} + +func TestList(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + test.TestList(validNewCSINode("foo")) +} + +func TestWatch(t *testing.T) { + if *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1beta1 + return + } + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.Store.DestroyFunc() + test := genericregistrytest.New(t, storage.Store).ClusterScope() + test.TestWatch( + validNewCSINode("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + }, + ) +} diff --git a/pkg/registry/storage/csinode/strategy.go b/pkg/registry/storage/csinode/strategy.go new file mode 100644 index 0000000000..f20e6e57b0 --- /dev/null +++ b/pkg/registry/storage/csinode/strategy.go @@ -0,0 +1,78 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package csinode + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/apis/storage/validation" +) + +// csiNodeStrategy implements behavior for CSINode objects +type csiNodeStrategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// Strategy is the default logic that applies when creating and updating +// CSINode objects via the REST API. +var Strategy = csiNodeStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} + +func (csiNodeStrategy) NamespaceScoped() bool { + return false +} + +// ResetBeforeCreate clears the Status field which is not allowed to be set by end users on creation. +func (csiNodeStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { +} + +func (csiNodeStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { + csiNode := obj.(*storage.CSINode) + + errs := validation.ValidateCSINode(csiNode) + errs = append(errs, validation.ValidateCSINode(csiNode)...) + + return errs +} + +// Canonicalize normalizes the object after validation. +func (csiNodeStrategy) Canonicalize(obj runtime.Object) { +} + +func (csiNodeStrategy) AllowCreateOnUpdate() bool { + return false +} + +// PrepareForUpdate sets the Status fields which is not allowed to be set by an end user updating a CSINode +func (csiNodeStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { +} + +func (csiNodeStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + newCSINodeObj := obj.(*storage.CSINode) + oldCSINodeObj := old.(*storage.CSINode) + errorList := validation.ValidateCSINode(newCSINodeObj) + return append(errorList, validation.ValidateCSINodeUpdate(newCSINodeObj, oldCSINodeObj)...) +} + +func (csiNodeStrategy) AllowUnconditionalUpdate() bool { + return false +} diff --git a/pkg/registry/storage/csinode/strategy_test.go b/pkg/registry/storage/csinode/strategy_test.go new file mode 100644 index 0000000000..14d04f6c15 --- /dev/null +++ b/pkg/registry/storage/csinode/strategy_test.go @@ -0,0 +1,167 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package csinode + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/kubernetes/pkg/apis/storage" +) + +func getValidCSINode(name string) *storage.CSINode { + return &storage.CSINode{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "valid-driver-name", + NodeID: "valid-node", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + } +} + +func TestCSINodeStrategy(t *testing.T) { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{ + APIGroup: "storage.k8s.io", + APIVersion: "v1beta1", + Resource: "csinodes", + }) + if Strategy.NamespaceScoped() { + t.Errorf("CSINode must not be namespace scoped") + } + if Strategy.AllowCreateOnUpdate() { + t.Errorf("CSINode should not allow create on update") + } + + csiNode := getValidCSINode("valid-csinode") + + Strategy.PrepareForCreate(ctx, csiNode) + + errs := Strategy.Validate(ctx, csiNode) + if len(errs) != 0 { + t.Errorf("unexpected error validating %v", errs) + } + + // Update of spec is allowed + newCSINode := csiNode.DeepCopy() + newCSINode.Spec.Drivers[0].NodeID = "valid-node-2" + + Strategy.PrepareForUpdate(ctx, newCSINode, csiNode) + + errs = Strategy.ValidateUpdate(ctx, newCSINode, csiNode) + if len(errs) == 0 { + t.Errorf("expected validation error") + } +} + +func TestCSINodeValidation(t *testing.T) { + tests := []struct { + name string + csiNode *storage.CSINode + expectError bool + }{ + { + "valid csinode", + getValidCSINode("foo"), + false, + }, + { + "invalid driver name", + &storage.CSINode{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "$csi-driver@", + NodeID: "valid-node", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + true, + }, + { + "empty node id", + &storage.CSINode{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "valid-driver-name", + NodeID: "", + TopologyKeys: []string{"company.com/zone1", "company.com/zone2"}, + }, + }, + }, + }, + true, + }, + { + "invalid topology keys", + &storage.CSINode{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ + { + Name: "valid-driver-name", + NodeID: "valid-node", + TopologyKeys: []string{"company.com/zone1", ""}, + }, + }, + }, + }, + true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + + testValidation := func(csiNode *storage.CSINode, apiVersion string) field.ErrorList { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{ + APIGroup: "storage.k8s.io", + APIVersion: "v1beta1", + Resource: "csinodes", + }) + return Strategy.Validate(ctx, csiNode) + } + + betaErr := testValidation(test.csiNode, "v1beta1") + if len(betaErr) > 0 && !test.expectError { + t.Errorf("Validation of v1beta1 object failed: %+v", betaErr) + } + if len(betaErr) == 0 && test.expectError { + t.Errorf("Validation of v1beta1 object unexpectedly succeeded") + } + }) + } +} diff --git a/pkg/registry/storage/rest/BUILD b/pkg/registry/storage/rest/BUILD index 60121512da..8c773060cf 100644 --- a/pkg/registry/storage/rest/BUILD +++ b/pkg/registry/storage/rest/BUILD @@ -12,6 +12,9 @@ go_library( deps = [ "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/storage:go_default_library", + "//pkg/features:go_default_library", + "//pkg/registry/storage/csidriver/storage:go_default_library", + "//pkg/registry/storage/csinode/storage:go_default_library", "//pkg/registry/storage/storageclass/storage:go_default_library", "//pkg/registry/storage/volumeattachment/storage:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", @@ -21,6 +24,7 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/storage:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", ], ) diff --git a/pkg/registry/storage/rest/storage_storage.go b/pkg/registry/storage/rest/storage_storage.go index f799226001..6cd0efbe88 100644 --- a/pkg/registry/storage/rest/storage_storage.go +++ b/pkg/registry/storage/rest/storage_storage.go @@ -24,8 +24,12 @@ import ( "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" serverstorage "k8s.io/apiserver/pkg/server/storage" + utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" storageapi "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/features" + csidriverstore "k8s.io/kubernetes/pkg/registry/storage/csidriver/storage" + csinodestore "k8s.io/kubernetes/pkg/registry/storage/csinode/storage" storageclassstore "k8s.io/kubernetes/pkg/registry/storage/storageclass/storage" volumeattachmentstore "k8s.io/kubernetes/pkg/registry/storage/volumeattachment/storage" ) @@ -70,6 +74,18 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag volumeAttachmentStorage := volumeattachmentstore.NewStorage(restOptionsGetter) storage["volumeattachments"] = volumeAttachmentStorage.VolumeAttachment + // register csinodes if CSINodeInfo feature gate is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { + csiNodeStorage := csinodestore.NewStorage(restOptionsGetter) + storage["csinodes"] = csiNodeStorage.CSINode + } + + // register csidrivers if CSIDriverRegistry feature gate is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { + csiDriverStorage := csidriverstore.NewStorage(restOptionsGetter) + storage["csidrivers"] = csiDriverStorage.CSIDriver + } + return storage } diff --git a/pkg/volume/BUILD b/pkg/volume/BUILD index 2e39a0c3d0..7d5c5d4658 100644 --- a/pkg/volume/BUILD +++ b/pkg/volume/BUILD @@ -32,7 +32,6 @@ go_library( "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/tools/record:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/pkg/volume/csi/BUILD b/pkg/volume/csi/BUILD index 4d042bc65b..ffcf3f7251 100644 --- a/pkg/volume/csi/BUILD +++ b/pkg/volume/csi/BUILD @@ -28,10 +28,10 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//staging/src/k8s.io/client-go/informers:go_default_library", + "//staging/src/k8s.io/client-go/informers/storage/v1beta1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/informers/externalversions:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/informers/externalversions/csi/v1alpha1:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/listers/csi/v1alpha1:go_default_library", + "//staging/src/k8s.io/client-go/listers/storage/v1beta1:go_default_library", "//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library", "//vendor/google.golang.org/grpc:go_default_library", "//vendor/k8s.io/klog:go_default_library", @@ -58,6 +58,7 @@ go_test( "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", + "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", @@ -71,8 +72,6 @@ go_test( "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/client-go/testing:go_default_library", "//staging/src/k8s.io/client-go/util/testing:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned/fake:go_default_library", "//vendor/github.com/container-storage-interface/spec/lib/go/csi:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], diff --git a/pkg/volume/csi/csi_attacher_test.go b/pkg/volume/csi/csi_attacher_test.go index 46c5b35a56..1ef325c996 100644 --- a/pkg/volume/csi/csi_attacher_test.go +++ b/pkg/volume/csi/csi_attacher_test.go @@ -37,7 +37,6 @@ import ( fakeclient "k8s.io/client-go/kubernetes/fake" core "k8s.io/client-go/testing" utiltesting "k8s.io/client-go/util/testing" - fakecsi "k8s.io/csi-api/pkg/client/clientset/versioned/fake" "k8s.io/klog" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" @@ -236,12 +235,12 @@ func TestAttacherWithCSIDriver(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - fakeCSIClient := fakecsi.NewSimpleClientset( + fakeClient := fakeclient.NewSimpleClientset( getCSIDriver("not-attachable", nil, &bFalse), getCSIDriver("attachable", nil, &bTrue), getCSIDriver("nil", nil, nil), ) - plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, fakeCSIClient) + plug, fakeWatcher, tmpDir, _ := newTestWatchPlugin(t, fakeClient) defer os.RemoveAll(tmpDir) attacher, err := plug.NewAttacher() @@ -274,10 +273,10 @@ func TestAttacherWithCSIDriver(t *testing.T) { t.Errorf("Attach() failed: %s", err) } if test.expectVolumeAttachment && attachID == "" { - t.Errorf("Epected attachID, got nothing") + t.Errorf("Expected attachID, got nothing") } if !test.expectVolumeAttachment && attachID != "" { - t.Errorf("Epected empty attachID, got %q", attachID) + t.Errorf("Expected empty attachID, got %q", attachID) } }) } @@ -318,12 +317,12 @@ func TestAttacherWaitForVolumeAttachmentWithCSIDriver(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - fakeCSIClient := fakecsi.NewSimpleClientset( + fakeClient := fakeclient.NewSimpleClientset( getCSIDriver("not-attachable", nil, &bFalse), getCSIDriver("attachable", nil, &bTrue), getCSIDriver("nil", nil, nil), ) - plug, tmpDir := newTestPlugin(t, nil, fakeCSIClient) + plug, tmpDir := newTestPlugin(t, fakeClient) defer os.RemoveAll(tmpDir) attacher, err := plug.NewAttacher() @@ -519,7 +518,7 @@ func TestAttacherWaitForVolumeAttachment(t *testing.T) { } func TestAttacherVolumesAreAttached(t *testing.T) { - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) attacher, err := plug.NewAttacher() @@ -981,23 +980,20 @@ func TestAttacherUnmountDevice(t *testing.T) { } // create a plugin mgr to load plugins and setup a fake client -func newTestWatchPlugin(t *testing.T, csiClient *fakecsi.Clientset) (*csiPlugin, *watch.RaceFreeFakeWatcher, string, *fakeclient.Clientset) { +func newTestWatchPlugin(t *testing.T, fakeClient *fakeclient.Clientset) (*csiPlugin, *watch.RaceFreeFakeWatcher, string, *fakeclient.Clientset) { tmpDir, err := utiltesting.MkTmpdir("csi-test") if err != nil { t.Fatalf("can't create temp dir: %v", err) } - fakeClient := fakeclient.NewSimpleClientset() - fakeWatcher := watch.NewRaceFreeFake() - fakeClient.Fake.PrependWatchReactor("*", core.DefaultWatchReactor(fakeWatcher, nil)) - fakeClient.Fake.WatchReactionChain = fakeClient.Fake.WatchReactionChain[:1] - if csiClient == nil { - csiClient = fakecsi.NewSimpleClientset() + if fakeClient == nil { + fakeClient = fakeclient.NewSimpleClientset() } + fakeWatcher := watch.NewRaceFreeFake() + fakeClient.Fake.AddWatchReactor("*", core.DefaultWatchReactor(fakeWatcher, nil)) host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, fakeClient, - csiClient, nil, "node", ) diff --git a/pkg/volume/csi/csi_block_test.go b/pkg/volume/csi/csi_block_test.go index 72d803621b..9bc2b8c63f 100644 --- a/pkg/volume/csi/csi_block_test.go +++ b/pkg/volume/csi/csi_block_test.go @@ -52,7 +52,7 @@ func prepareBlockMapperTest(plug *csiPlugin, specVolumeName string, t *testing.T func TestBlockMapperGetGlobalMapPath(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) // TODO (vladimirvivien) specName with slashes will not work @@ -93,7 +93,7 @@ func TestBlockMapperGetGlobalMapPath(t *testing.T) { func TestBlockMapperGetStagingPath(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) testCases := []struct { @@ -130,7 +130,7 @@ func TestBlockMapperGetStagingPath(t *testing.T) { func TestBlockMapperGetPublishPath(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) testCases := []struct { @@ -167,7 +167,7 @@ func TestBlockMapperGetPublishPath(t *testing.T) { func TestBlockMapperGetDeviceMapPath(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) testCases := []struct { @@ -208,14 +208,13 @@ func TestBlockMapperGetDeviceMapPath(t *testing.T) { func TestBlockMapperSetupDevice(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) fakeClient := fakeclient.NewSimpleClientset() host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, fakeClient, nil, - nil, "fakeNode", ) plug.host = host @@ -275,14 +274,13 @@ func TestBlockMapperSetupDevice(t *testing.T) { func TestBlockMapperMapDevice(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) fakeClient := fakeclient.NewSimpleClientset() host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, fakeClient, nil, - nil, "fakeNode", ) plug.host = host @@ -358,14 +356,13 @@ func TestBlockMapperMapDevice(t *testing.T) { func TestBlockMapperTearDownDevice(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) fakeClient := fakeclient.NewSimpleClientset() host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, fakeClient, nil, - nil, "fakeNode", ) plug.host = host diff --git a/pkg/volume/csi/csi_mounter.go b/pkg/volume/csi/csi_mounter.go index 4e0dbe59df..1630aa5076 100644 --- a/pkg/volume/csi/csi_mounter.go +++ b/pkg/volume/csi/csi_mounter.go @@ -50,7 +50,6 @@ var ( "nodeName", "attachmentID", } - currentPodInfoMountVersion = "v1" ) type csiMountMgr struct { @@ -247,8 +246,8 @@ func (c *csiMountMgr) podAttributes() (map[string]string, error) { return nil, err } - // if PodInfoOnMountVersion is not set or not v1 we do not set pod attributes - if csiDriver.Spec.PodInfoOnMountVersion == nil || *csiDriver.Spec.PodInfoOnMountVersion != currentPodInfoMountVersion { + // if PodInfoOnMount is not set or false we do not set pod attributes + if csiDriver.Spec.PodInfoOnMount == nil || *csiDriver.Spec.PodInfoOnMount == false { klog.V(4).Infof(log("CSIDriver %q does not require pod information", c.driverName)) return nil, nil } diff --git a/pkg/volume/csi/csi_mounter_test.go b/pkg/volume/csi/csi_mounter_test.go index 6301c1bdd7..2b02373482 100644 --- a/pkg/volume/csi/csi_mounter_test.go +++ b/pkg/volume/csi/csi_mounter_test.go @@ -29,14 +29,13 @@ import ( api "k8s.io/api/core/v1" storage "k8s.io/api/storage/v1" + storagev1beta1 "k8s.io/api/storage/v1beta1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" fakeclient "k8s.io/client-go/kubernetes/fake" - csiapi "k8s.io/csi-api/pkg/apis/csi/v1alpha1" - fakecsi "k8s.io/csi-api/pkg/client/clientset/versioned/fake" "k8s.io/klog" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" @@ -53,7 +52,7 @@ var ( ) func TestMounterGetPath(t *testing.T) { - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) // TODO (vladimirvivien) specName with slashes will not work @@ -142,17 +141,17 @@ func MounterSetUpTests(t *testing.T, podInfoEnabled bool) { }, } - emptyPodMountInfoVersion := "" + noPodMountInfo := false + currentPodInfoMount := true for _, test := range tests { t.Run(test.name, func(t *testing.T) { klog.Infof("Starting test %s", test.name) - fakeClient := fakeclient.NewSimpleClientset() - fakeCSIClient := fakecsi.NewSimpleClientset( - getCSIDriver("no-info", &emptyPodMountInfoVersion, nil), - getCSIDriver("info", ¤tPodInfoMountVersion, nil), + fakeClient := fakeclient.NewSimpleClientset( + getCSIDriver("no-info", &noPodMountInfo, nil), + getCSIDriver("info", ¤tPodInfoMount, nil), getCSIDriver("nil", nil, nil), ) - plug, tmpDir := newTestPlugin(t, fakeClient, fakeCSIClient) + plug, tmpDir := newTestPlugin(t, fakeClient) defer os.RemoveAll(tmpDir) if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { @@ -269,7 +268,7 @@ func TestMounterSetUp(t *testing.T) { } func TestMounterSetUpWithFSGroup(t *testing.T) { fakeClient := fakeclient.NewSimpleClientset() - plug, tmpDir := newTestPlugin(t, fakeClient, nil) + plug, tmpDir := newTestPlugin(t, fakeClient) defer os.RemoveAll(tmpDir) testCases := []struct { @@ -393,7 +392,7 @@ func TestMounterSetUpWithFSGroup(t *testing.T) { } func TestUnmounterTeardown(t *testing.T) { - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) pv := makeTestPV("test-pv", 10, testDriver, testVol) @@ -443,7 +442,7 @@ func TestUnmounterTeardown(t *testing.T) { } func TestSaveVolumeData(t *testing.T) { - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) testCases := []struct { name string @@ -490,14 +489,14 @@ func TestSaveVolumeData(t *testing.T) { } } -func getCSIDriver(name string, podInfoMountVersion *string, attachable *bool) *csiapi.CSIDriver { - return &csiapi.CSIDriver{ +func getCSIDriver(name string, podInfoMount *bool, attachable *bool) *storagev1beta1.CSIDriver { + return &storagev1beta1.CSIDriver{ ObjectMeta: meta.ObjectMeta{ Name: name, }, - Spec: csiapi.CSIDriverSpec{ - PodInfoOnMountVersion: podInfoMountVersion, - AttachRequired: attachable, + Spec: storagev1beta1.CSIDriverSpec{ + PodInfoOnMount: podInfoMount, + AttachRequired: attachable, }, } } diff --git a/pkg/volume/csi/csi_plugin.go b/pkg/volume/csi/csi_plugin.go index 81814e5a43..54bdc20ac0 100644 --- a/pkg/volume/csi/csi_plugin.go +++ b/pkg/volume/csi/csi_plugin.go @@ -36,10 +36,10 @@ import ( utilversion "k8s.io/apimachinery/pkg/util/version" "k8s.io/apimachinery/pkg/util/wait" utilfeature "k8s.io/apiserver/pkg/util/feature" + csiapiinformer "k8s.io/client-go/informers" + csiinformer "k8s.io/client-go/informers/storage/v1beta1" clientset "k8s.io/client-go/kubernetes" - csiapiinformer "k8s.io/csi-api/pkg/client/informers/externalversions" - csiinformer "k8s.io/csi-api/pkg/client/informers/externalversions/csi/v1alpha1" - csilister "k8s.io/csi-api/pkg/client/listers/csi/v1alpha1" + csilister "k8s.io/client-go/listers/storage/v1beta1" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/csi/nodeinfomanager" @@ -205,16 +205,15 @@ func (p *csiPlugin) Init(host volume.VolumeHost) error { p.host = host if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { - csiClient := host.GetCSIClient() + csiClient := host.GetKubeClient() if csiClient == nil { - klog.Warning("The client for CSI Custom Resources is not available, skipping informer initialization") - } else { - // Start informer for CSIDrivers. - factory := csiapiinformer.NewSharedInformerFactory(csiClient, csiResyncPeriod) - p.csiDriverInformer = factory.Csi().V1alpha1().CSIDrivers() - p.csiDriverLister = p.csiDriverInformer.Lister() - go factory.Start(wait.NeverStop) + return errors.New("unable to get Kubernetes client") } + // Start informer for CSIDrivers. + factory := csiapiinformer.NewSharedInformerFactory(csiClient, csiResyncPeriod) + p.csiDriverInformer = factory.Storage().V1beta1().CSIDrivers() + p.csiDriverLister = p.csiDriverInformer.Lister() + go factory.Start(wait.NeverStop) } // Initializing the label management channels diff --git a/pkg/volume/csi/csi_plugin_test.go b/pkg/volume/csi/csi_plugin_test.go index 48d77b10ef..7e957a0997 100644 --- a/pkg/volume/csi/csi_plugin_test.go +++ b/pkg/volume/csi/csi_plugin_test.go @@ -32,14 +32,13 @@ import ( utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" fakeclient "k8s.io/client-go/kubernetes/fake" utiltesting "k8s.io/client-go/util/testing" - fakecsi "k8s.io/csi-api/pkg/client/clientset/versioned/fake" "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/volume" volumetest "k8s.io/kubernetes/pkg/volume/testing" ) // create a plugin mgr to load plugins and setup a fake client -func newTestPlugin(t *testing.T, client *fakeclient.Clientset, csiClient *fakecsi.Clientset) (*csiPlugin, string) { +func newTestPlugin(t *testing.T, client *fakeclient.Clientset) (*csiPlugin, string) { tmpDir, err := utiltesting.MkTmpdir("csi-test") if err != nil { t.Fatalf("can't create temp dir: %v", err) @@ -48,13 +47,9 @@ func newTestPlugin(t *testing.T, client *fakeclient.Clientset, csiClient *fakecs if client == nil { client = fakeclient.NewSimpleClientset() } - if csiClient == nil { - csiClient = fakecsi.NewSimpleClientset() - } host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, client, - csiClient, nil, "fakeNode", ) @@ -120,7 +115,7 @@ func registerFakePlugin(pluginName, endpoint string, versions []string, t *testi func TestPluginGetPluginName(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) if plug.GetPluginName() != "kubernetes.io/csi" { t.Errorf("unexpected plugin name %v", plug.GetPluginName()) @@ -130,7 +125,7 @@ func TestPluginGetPluginName(t *testing.T) { func TestPluginGetVolumeName(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) testCases := []struct { name string @@ -162,7 +157,7 @@ func TestPluginGetVolumeName(t *testing.T) { func TestPluginCanSupport(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) @@ -177,7 +172,7 @@ func TestPluginCanSupport(t *testing.T) { func TestPluginConstructVolumeSpec(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) testCases := []struct { @@ -239,7 +234,7 @@ func TestPluginConstructVolumeSpec(t *testing.T) { func TestPluginNewMounter(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) registerFakePlugin(testDriver, "endpoint", []string{"1.2.0"}, t) @@ -290,7 +285,7 @@ func TestPluginNewMounter(t *testing.T) { func TestPluginNewUnmounter(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) @@ -338,7 +333,7 @@ func TestPluginNewUnmounter(t *testing.T) { func TestPluginNewAttacher(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) attacher, err := plug.NewAttacher() @@ -358,7 +353,7 @@ func TestPluginNewAttacher(t *testing.T) { func TestPluginNewDetacher(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) detacher, err := plug.NewDetacher() @@ -389,10 +384,8 @@ func TestPluginCanAttach(t *testing.T) { } for _, test := range tests { - csiDriver := getCSIDriver(test.driverName, nil, &test.canAttach) t.Run(test.name, func(t *testing.T) { - fakeCSIClient := fakecsi.NewSimpleClientset(csiDriver) - plug, tmpDir := newTestPlugin(t, nil, fakeCSIClient) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) spec := volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, test.driverName, "test-vol"), false) @@ -408,7 +401,7 @@ func TestPluginCanAttach(t *testing.T) { func TestPluginNewBlockMapper(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) @@ -456,7 +449,7 @@ func TestPluginNewBlockMapper(t *testing.T) { func TestPluginNewUnmapper(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) registerFakePlugin(testDriver, "endpoint", []string{"1.0.0"}, t) @@ -516,7 +509,7 @@ func TestPluginNewUnmapper(t *testing.T) { func TestPluginConstructBlockVolumeSpec(t *testing.T) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIBlockVolume, true)() - plug, tmpDir := newTestPlugin(t, nil, nil) + plug, tmpDir := newTestPlugin(t, nil) defer os.RemoveAll(tmpDir) testCases := []struct { diff --git a/pkg/volume/csi/nodeinfomanager/BUILD b/pkg/volume/csi/nodeinfomanager/BUILD index 6af576c422..f998f4e7a0 100644 --- a/pkg/volume/csi/nodeinfomanager/BUILD +++ b/pkg/volume/csi/nodeinfomanager/BUILD @@ -11,6 +11,7 @@ go_library( "//pkg/volume:go_default_library", "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", @@ -19,8 +20,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", + "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) @@ -50,6 +50,8 @@ go_test( "//pkg/volume/testing:go_default_library", "//pkg/volume/util:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", + "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", @@ -60,8 +62,6 @@ go_test( "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/client-go/testing:go_default_library", "//staging/src/k8s.io/client-go/util/testing:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned/fake:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library", ], ) diff --git a/pkg/volume/csi/nodeinfomanager/nodeinfomanager.go b/pkg/volume/csi/nodeinfomanager/nodeinfomanager.go index 099edaed2a..dfea45f51e 100644 --- a/pkg/volume/csi/nodeinfomanager/nodeinfomanager.go +++ b/pkg/volume/csi/nodeinfomanager/nodeinfomanager.go @@ -21,11 +21,11 @@ package nodeinfomanager // import "k8s.io/kubernetes/pkg/volume/csi/nodeinfomana import ( "encoding/json" "fmt" - "strings" "time" "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1beta1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -34,8 +34,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" utilfeature "k8s.io/apiserver/pkg/util/feature" - csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" + clientset "k8s.io/client-go/kubernetes" "k8s.io/klog" "k8s.io/kubernetes/pkg/features" nodeutil "k8s.io/kubernetes/pkg/util/node" @@ -59,7 +58,7 @@ var ( ) // nodeInfoManager contains necessary common dependencies to update node info on both -// the Node and CSINodeInfo objects. +// the Node and CSINode objects. type nodeInfoManager struct { nodeName types.NodeName volumeHost volume.VolumeHost @@ -70,7 +69,7 @@ type nodeUpdateFunc func(*v1.Node) (newNode *v1.Node, updated bool, err error) // Interface implements an interface for managing labels of a node type Interface interface { - CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error) + CreateCSINode() (*storage.CSINode, error) // Record in the cluster the given node information from the CSI driver with the given name. // Concurrent calls to InstallCSIDriver() is allowed, but they should not be intertwined with calls @@ -94,9 +93,9 @@ func NewNodeInfoManager( } // InstallCSIDriver updates the node ID annotation in the Node object and CSIDrivers field in the -// CSINodeInfo object. If the CSINodeInfo object doesn't yet exist, it will be created. +// CSINode object. If the CSINode object doesn't yet exist, it will be created. // If multiple calls to InstallCSIDriver() are made in parallel, some calls might receive Node or -// CSINodeInfo update conflicts, which causes the function to retry the corresponding update. +// CSINode update conflicts, which causes the function to retry the corresponding update. func (nim *nodeInfoManager) InstallCSIDriver(driverName string, driverNodeID string, maxAttachLimit int64, topology map[string]string) error { if driverNodeID == "" { return fmt.Errorf("error adding CSI driver node info: driverNodeID must not be empty") @@ -120,23 +119,23 @@ func (nim *nodeInfoManager) InstallCSIDriver(driverName string, driverNodeID str } if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { - err = nim.updateCSINodeInfo(driverName, driverNodeID, topology) + err = nim.updateCSINode(driverName, driverNodeID, topology) if err != nil { - return fmt.Errorf("error updating CSINodeInfo object with CSI driver node info: %v", err) + return fmt.Errorf("error updating CSINode object with CSI driver node info: %v", err) } } return nil } // UninstallCSIDriver removes the node ID annotation from the Node object and CSIDrivers field from the -// CSINodeInfo object. If the CSINOdeInfo object contains no CSIDrivers, it will be deleted. +// CSINode object. If the CSINOdeInfo object contains no CSIDrivers, it will be deleted. // If multiple calls to UninstallCSIDriver() are made in parallel, some calls might receive Node or -// CSINodeInfo update conflicts, which causes the function to retry the corresponding update. +// CSINode update conflicts, which causes the function to retry the corresponding update. func (nim *nodeInfoManager) UninstallCSIDriver(driverName string) error { if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { - err := nim.uninstallDriverFromCSINodeInfo(driverName) + err := nim.uninstallDriverFromCSINode(driverName) if err != nil { - return fmt.Errorf("error uninstalling CSI driver from CSINodeInfo object %v", err) + return fmt.Errorf("error uninstalling CSI driver from CSINode object %v", err) } } @@ -344,55 +343,55 @@ func updateTopologyLabels(topology map[string]string) nodeUpdateFunc { } } -func (nim *nodeInfoManager) updateCSINodeInfo( +func (nim *nodeInfoManager) updateCSINode( driverName string, driverNodeID string, topology map[string]string) error { - csiKubeClient := nim.volumeHost.GetCSIClient() + csiKubeClient := nim.volumeHost.GetKubeClient() if csiKubeClient == nil { return fmt.Errorf("error getting CSI client") } var updateErrs []error err := wait.ExponentialBackoff(updateBackoff, func() (bool, error) { - if err := nim.tryUpdateCSINodeInfo(csiKubeClient, driverName, driverNodeID, topology); err != nil { + if err := nim.tryUpdateCSINode(csiKubeClient, driverName, driverNodeID, topology); err != nil { updateErrs = append(updateErrs, err) return false, nil } return true, nil }) if err != nil { - return fmt.Errorf("error updating CSINodeInfo: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs)) + return fmt.Errorf("error updating CSINode: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs)) } return nil } -func (nim *nodeInfoManager) tryUpdateCSINodeInfo( - csiKubeClient csiclientset.Interface, +func (nim *nodeInfoManager) tryUpdateCSINode( + csiKubeClient clientset.Interface, driverName string, driverNodeID string, topology map[string]string) error { - nodeInfo, err := csiKubeClient.CsiV1alpha1().CSINodeInfos().Get(string(nim.nodeName), metav1.GetOptions{}) + nodeInfo, err := csiKubeClient.StorageV1beta1().CSINodes().Get(string(nim.nodeName), metav1.GetOptions{}) if nodeInfo == nil || errors.IsNotFound(err) { - nodeInfo, err = nim.CreateCSINodeInfo() + nodeInfo, err = nim.CreateCSINode() } if err != nil { return err } - return nim.installDriverToCSINodeInfo(nodeInfo, driverName, driverNodeID, topology) + return nim.installDriverToCSINode(nodeInfo, driverName, driverNodeID, topology) } -func (nim *nodeInfoManager) CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error) { +func (nim *nodeInfoManager) CreateCSINode() (*storage.CSINode, error) { kubeClient := nim.volumeHost.GetKubeClient() if kubeClient == nil { return nil, fmt.Errorf("error getting kube client") } - csiKubeClient := nim.volumeHost.GetCSIClient() + csiKubeClient := nim.volumeHost.GetKubeClient() if csiKubeClient == nil { return nil, fmt.Errorf("error getting CSI client") } @@ -402,7 +401,7 @@ func (nim *nodeInfoManager) CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error return nil, err } - nodeInfo := &csiv1alpha1.CSINodeInfo{ + nodeInfo := &storage.CSINode{ ObjectMeta: metav1.ObjectMeta{ Name: string(nim.nodeName), OwnerReferences: []metav1.OwnerReference{ @@ -414,24 +413,21 @@ func (nim *nodeInfoManager) CreateCSINodeInfo() (*csiv1alpha1.CSINodeInfo, error }, }, }, - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{}, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{}, + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{}, }, } - return csiKubeClient.CsiV1alpha1().CSINodeInfos().Create(nodeInfo) + return csiKubeClient.StorageV1beta1().CSINodes().Create(nodeInfo) } -func (nim *nodeInfoManager) installDriverToCSINodeInfo( - nodeInfo *csiv1alpha1.CSINodeInfo, +func (nim *nodeInfoManager) installDriverToCSINode( + nodeInfo *storage.CSINode, driverName string, driverNodeID string, topology map[string]string) error { - csiKubeClient := nim.volumeHost.GetCSIClient() + csiKubeClient := nim.volumeHost.GetKubeClient() if csiKubeClient == nil { return fmt.Errorf("error getting CSI client") } @@ -444,7 +440,7 @@ func (nim *nodeInfoManager) installDriverToCSINodeInfo( specModified := true statusModified := true // Clone driver list, omitting the driver that matches the given driverName - newDriverSpecs := []csiv1alpha1.CSIDriverInfoSpec{} + newDriverSpecs := []storage.CSINodeDriver{} for _, driverInfoSpec := range nodeInfo.Spec.Drivers { if driverInfoSpec.Name == driverName { if driverInfoSpec.NodeID == driverNodeID && @@ -456,106 +452,80 @@ func (nim *nodeInfoManager) installDriverToCSINodeInfo( newDriverSpecs = append(newDriverSpecs, driverInfoSpec) } } - newDriverStatuses := []csiv1alpha1.CSIDriverInfoStatus{} - for _, driverInfoStatus := range nodeInfo.Status.Drivers { - if driverInfoStatus.Name == driverName { - if driverInfoStatus.Available && - /* TODO(https://github.com/kubernetes/enhancements/issues/625): Add actual migration status */ - driverInfoStatus.VolumePluginMechanism == csiv1alpha1.VolumePluginMechanismInTree { - statusModified = false - } - } else { - // Omit driverInfoSpec matching given driverName - newDriverStatuses = append(newDriverStatuses, driverInfoStatus) - } - } if !specModified && !statusModified { return nil } // Append new driver - driverSpec := csiv1alpha1.CSIDriverInfoSpec{ + driverSpec := storage.CSINodeDriver{ Name: driverName, NodeID: driverNodeID, TopologyKeys: topologyKeys.List(), } - driverStatus := csiv1alpha1.CSIDriverInfoStatus{ - Name: driverName, - Available: true, - // TODO(https://github.com/kubernetes/enhancements/issues/625): Add actual migration status - VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree, - } newDriverSpecs = append(newDriverSpecs, driverSpec) - newDriverStatuses = append(newDriverStatuses, driverStatus) nodeInfo.Spec.Drivers = newDriverSpecs - nodeInfo.Status.Drivers = newDriverStatuses - err := validateCSINodeInfo(nodeInfo) - if err != nil { - return err - } - _, err = csiKubeClient.CsiV1alpha1().CSINodeInfos().Update(nodeInfo) + _, err := csiKubeClient.StorageV1beta1().CSINodes().Update(nodeInfo) return err } -func (nim *nodeInfoManager) uninstallDriverFromCSINodeInfo( +func (nim *nodeInfoManager) uninstallDriverFromCSINode( csiDriverName string) error { - csiKubeClient := nim.volumeHost.GetCSIClient() + csiKubeClient := nim.volumeHost.GetKubeClient() if csiKubeClient == nil { return fmt.Errorf("error getting CSI client") } var updateErrs []error err := wait.ExponentialBackoff(updateBackoff, func() (bool, error) { - if err := nim.tryUninstallDriverFromCSINodeInfo(csiKubeClient, csiDriverName); err != nil { + if err := nim.tryUninstallDriverFromCSINode(csiKubeClient, csiDriverName); err != nil { updateErrs = append(updateErrs, err) return false, nil } return true, nil }) if err != nil { - return fmt.Errorf("error updating CSINodeInfo: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs)) + return fmt.Errorf("error updating CSINode: %v; caused by: %v", err, utilerrors.NewAggregate(updateErrs)) } return nil } -func (nim *nodeInfoManager) tryUninstallDriverFromCSINodeInfo( - csiKubeClient csiclientset.Interface, +func (nim *nodeInfoManager) tryUninstallDriverFromCSINode( + csiKubeClient clientset.Interface, csiDriverName string) error { - nodeInfoClient := csiKubeClient.CsiV1alpha1().CSINodeInfos() + nodeInfoClient := csiKubeClient.StorageV1beta1().CSINodes() nodeInfo, err := nodeInfoClient.Get(string(nim.nodeName), metav1.GetOptions{}) - if err != nil { - return err // do not wrap error + if err != nil && errors.IsNotFound(err) { + return nil + } else if err != nil { + return err } hasModified := false - newDriverStatuses := []csiv1alpha1.CSIDriverInfoStatus{} - for _, driverStatus := range nodeInfo.Status.Drivers { - if driverStatus.Name == csiDriverName { - // Uninstall the driver if we find it - hasModified = driverStatus.Available - driverStatus.Available = false + // Uninstall CSINodeDriver with name csiDriverName + drivers := nodeInfo.Spec.Drivers[:0] + for _, driver := range nodeInfo.Spec.Drivers { + if driver.Name != csiDriverName { + drivers = append(drivers, driver) + } else { + // Found a driver with name csiDriverName + // Set hasModified to true because it will be removed + hasModified = true } - newDriverStatuses = append(newDriverStatuses, driverStatus) } - - nodeInfo.Status.Drivers = newDriverStatuses - if !hasModified { // No changes, don't update return nil } + nodeInfo.Spec.Drivers = drivers - err = validateCSINodeInfo(nodeInfo) - if err != nil { - return err - } - _, updateErr := nodeInfoClient.Update(nodeInfo) - return updateErr // do not wrap error + _, err = nodeInfoClient.Update(nodeInfo) + + return err // do not wrap error } @@ -611,50 +581,3 @@ func removeMaxAttachLimit(driverName string) nodeUpdateFunc { return node, true, nil } } - -// validateCSINodeInfo ensures members of CSINodeInfo object satisfies map and set semantics. -// Before calling CSINodeInfoInterface.Update(), validateCSINodeInfo() should be invoked to -// make sure the CSINodeInfo is compliant -func validateCSINodeInfo(nodeInfo *csiv1alpha1.CSINodeInfo) error { - if len(nodeInfo.Status.Drivers) < 1 { - return fmt.Errorf("at least one Driver entry is required in driver statuses") - } - if len(nodeInfo.Spec.Drivers) < 1 { - return fmt.Errorf("at least one Driver entry is required in driver specs") - } - if len(nodeInfo.Status.Drivers) != len(nodeInfo.Spec.Drivers) { - return fmt.Errorf("") - } - // check for duplicate entries for the same driver in statuses - var errors []string - driverNamesInStatuses := make(sets.String) - for _, driverInfo := range nodeInfo.Status.Drivers { - if driverNamesInStatuses.Has(driverInfo.Name) { - errors = append(errors, fmt.Sprintf("duplicate entries found for driver: %s in driver statuses", driverInfo.Name)) - } - driverNamesInStatuses.Insert(driverInfo.Name) - } - // check for duplicate entries for the same driver in specs - driverNamesInSpecs := make(sets.String) - for _, driverInfo := range nodeInfo.Spec.Drivers { - if driverNamesInSpecs.Has(driverInfo.Name) { - errors = append(errors, fmt.Sprintf("duplicate entries found for driver: %s in driver specs", driverInfo.Name)) - } - driverNamesInSpecs.Insert(driverInfo.Name) - topoKeys := make(sets.String) - for _, key := range driverInfo.TopologyKeys { - if topoKeys.Has(key) { - errors = append(errors, fmt.Sprintf("duplicate topology keys %s found for driver %s in driver specs", key, driverInfo.Name)) - } - topoKeys.Insert(key) - } - } - // check all entries in specs and status match - if !driverNamesInSpecs.Equal(driverNamesInStatuses) { - errors = append(errors, fmt.Sprintf("list of drivers in specs: %v does not match list of drivers in statuses: %v", driverNamesInSpecs.List(), driverNamesInStatuses.List())) - } - if len(errors) == 0 { - return nil - } - return fmt.Errorf(strings.Join(errors, ", ")) -} diff --git a/pkg/volume/csi/nodeinfomanager/nodeinfomanager_test.go b/pkg/volume/csi/nodeinfomanager/nodeinfomanager_test.go index d900acb6e6..6b5831e9f7 100644 --- a/pkg/volume/csi/nodeinfomanager/nodeinfomanager_test.go +++ b/pkg/volume/csi/nodeinfomanager/nodeinfomanager_test.go @@ -23,6 +23,8 @@ import ( "github.com/stretchr/testify/assert" "k8s.io/api/core/v1" + storage "k8s.io/api/storage/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -33,8 +35,6 @@ import ( "k8s.io/client-go/kubernetes/fake" clienttesting "k8s.io/client-go/testing" utiltesting "k8s.io/client-go/util/testing" - csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1" - csifake "k8s.io/csi-api/pkg/client/clientset/versioned/fake" "k8s.io/kubernetes/pkg/apis/core/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" "k8s.io/kubernetes/pkg/features" @@ -46,7 +46,7 @@ type testcase struct { name string driverName string existingNode *v1.Node - existingNodeInfo *csiv1alpha1.CSINodeInfo + existingCSINode *storage.CSINode inputNodeID string inputTopology map[string]string inputVolumeLimit int64 @@ -55,49 +55,50 @@ type testcase struct { expectedLabels map[string]string expectedVolumeLimit int64 expectFail bool + hasModified bool } type nodeIDMap map[string]string type topologyKeyMap map[string][]string type labelMap map[string]string -// TestInstallCSIDriver tests InstallCSIDriver with various existing Node and/or CSINodeInfo objects. -// The node IDs in all test cases below are the same between the Node annotation and CSINodeInfo. +// TestInstallCSIDriver tests InstallCSIDriver with various existing Node and/or CSINode objects. +// The node IDs in all test cases below are the same between the Node annotation and CSINode. func TestInstallCSIDriver(t *testing.T) { testcases := []testcase{ { name: "empty node", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode(nil /* nodeIDs */, nil /* labels */, nil /*capacity*/), inputNodeID: "com.example.csi/csi-node1", inputTopology: map[string]string{ "com.example.csi/zone": "zoneA", }, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": sets.NewString("com.example.csi/zone"), + "com.example.csi.driver1": sets.NewString("com.example.csi/zone"), }, expectedLabels: map[string]string{"com.example.csi/zone": "zoneA"}, }, { name: "pre-existing node info from the same driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, labelMap{ "com.example.csi/zone": "zoneA", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, topologyKeyMap{ - "com.example.csi/driver1": {"com.example.csi/zone"}, + "com.example.csi.driver1": {"com.example.csi/zone"}, }, ), inputNodeID: "com.example.csi/csi-node1", @@ -105,10 +106,10 @@ func TestInstallCSIDriver(t *testing.T) { "com.example.csi/zone": "zoneA", }, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": sets.NewString("com.example.csi/zone"), + "com.example.csi.driver1": sets.NewString("com.example.csi/zone"), }, expectedLabels: map[string]string{ "com.example.csi/zone": "zoneA", @@ -116,15 +117,15 @@ func TestInstallCSIDriver(t *testing.T) { }, { name: "pre-existing node info from the same driver, but without topology info", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, nil /* labels */, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, nil, /* topologyKeys */ ), @@ -133,10 +134,10 @@ func TestInstallCSIDriver(t *testing.T) { "com.example.csi/zone": "zoneA", }, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": sets.NewString("com.example.csi/zone"), + "com.example.csi.driver1": sets.NewString("com.example.csi/zone"), }, expectedLabels: map[string]string{ "com.example.csi/zone": "zoneA", @@ -144,20 +145,20 @@ func TestInstallCSIDriver(t *testing.T) { }, { name: "pre-existing node info from different driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/test-node", + "net.example.storage.other-driver": "net.example.storage/test-node", }, labelMap{ "net.example.storage/rack": "rack1", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/test-node", + "net.example.storage.other-driver": "net.example.storage/test-node", }, topologyKeyMap{ - "net.example.storage/other-driver": {"net.example.storage/rack"}, + "net.example.storage.other-driver": {"net.example.storage/rack"}, }, ), inputNodeID: "com.example.csi/csi-node1", @@ -165,12 +166,12 @@ func TestInstallCSIDriver(t *testing.T) { "com.example.csi/zone": "zoneA", }, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", - "net.example.storage/other-driver": "net.example.storage/test-node", + "com.example.csi.driver1": "com.example.csi/csi-node1", + "net.example.storage.other-driver": "net.example.storage/test-node", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": sets.NewString("com.example.csi/zone"), - "net.example.storage/other-driver": sets.NewString("net.example.storage/rack"), + "com.example.csi.driver1": sets.NewString("com.example.csi/zone"), + "net.example.storage.other-driver": sets.NewString("net.example.storage/rack"), }, expectedLabels: map[string]string{ "com.example.csi/zone": "zoneA", @@ -179,20 +180,20 @@ func TestInstallCSIDriver(t *testing.T) { }, { name: "pre-existing node info from the same driver, but different node ID and topology values; labels should conflict", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, labelMap{ "com.example.csi/zone": "zoneA", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, topologyKeyMap{ - "com.example.csi/driver1": {"com.example.csi/zone"}, + "com.example.csi.driver1": {"com.example.csi/zone"}, }, ), inputNodeID: "com.example.csi/csi-node1", @@ -203,20 +204,20 @@ func TestInstallCSIDriver(t *testing.T) { }, { name: "pre-existing node info from the same driver, but different node ID and topology keys; new labels should be added", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, labelMap{ "com.example.csi/zone": "zoneA", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, topologyKeyMap{ - "com.example.csi/driver1": {"com.example.csi/zone"}, + "com.example.csi.driver1": {"com.example.csi/zone"}, }, ), inputNodeID: "com.example.csi/other-node", @@ -224,10 +225,10 @@ func TestInstallCSIDriver(t *testing.T) { "com.example.csi/rack": "rack1", }, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/other-node", + "com.example.csi.driver1": "com.example.csi/other-node", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": sets.NewString("com.example.csi/rack"), + "com.example.csi.driver1": sets.NewString("com.example.csi/rack"), }, expectedLabels: map[string]string{ "com.example.csi/zone": "zoneA", @@ -236,43 +237,43 @@ func TestInstallCSIDriver(t *testing.T) { }, { name: "nil topology, empty node", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode(nil /* nodeIDs */, nil /* labels */, nil /*capacity*/), inputNodeID: "com.example.csi/csi-node1", inputTopology: nil, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": nil, + "com.example.csi.driver1": nil, }, expectedLabels: nil, }, { name: "nil topology, pre-existing node info from the same driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, labelMap{ "com.example.csi/zone": "zoneA", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, topologyKeyMap{ - "com.example.csi/driver1": {"com.example.csi/zone"}, + "com.example.csi.driver1": {"com.example.csi/zone"}, }, ), inputNodeID: "com.example.csi/csi-node1", inputTopology: nil, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": nil, + "com.example.csi.driver1": nil, }, expectedLabels: map[string]string{ "com.example.csi/zone": "zoneA", // old labels are not removed @@ -280,31 +281,31 @@ func TestInstallCSIDriver(t *testing.T) { }, { name: "nil topology, pre-existing node info from different driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/test-node", + "net.example.storage.other-driver": "net.example.storage/test-node", }, labelMap{ "net.example.storage/rack": "rack1", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/test-node", + "net.example.storage.other-driver": "net.example.storage/test-node", }, topologyKeyMap{ - "net.example.storage/other-driver": {"net.example.storage/rack"}, + "net.example.storage.other-driver": {"net.example.storage/rack"}, }, ), inputNodeID: "com.example.csi/csi-node1", inputTopology: nil, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", - "net.example.storage/other-driver": "net.example.storage/test-node", + "com.example.csi.driver1": "com.example.csi/csi-node1", + "net.example.storage.other-driver": "net.example.storage/test-node", }, expectedTopologyMap: map[string]sets.String{ - "net.example.storage/other-driver": sets.NewString("net.example.storage/rack"), - "com.example.csi/driver1": nil, + "net.example.storage.other-driver": sets.NewString("net.example.storage/rack"), + "com.example.csi.driver1": nil, }, expectedLabels: map[string]string{ "net.example.storage/rack": "rack1", @@ -312,30 +313,30 @@ func TestInstallCSIDriver(t *testing.T) { }, { name: "empty node ID", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode(nil /* nodeIDs */, nil /* labels */, nil /*capacity*/), inputNodeID: "", expectFail: true, }, { name: "new node with valid max limit", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode(nil /*nodeIDs*/, nil /*labels*/, nil /*capacity*/), inputVolumeLimit: 10, inputTopology: nil, inputNodeID: "com.example.csi/csi-node1", expectedVolumeLimit: 10, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": nil, + "com.example.csi.driver1": nil, }, expectedLabels: nil, }, { name: "node with existing valid max limit", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nil, /*nodeIDs*/ nil, /*labels*/ @@ -348,10 +349,10 @@ func TestInstallCSIDriver(t *testing.T) { inputNodeID: "com.example.csi/csi-node1", expectedVolumeLimit: 20, expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "com.example.csi/driver1": nil, + "com.example.csi.driver1": nil, }, expectedLabels: nil, }, @@ -362,42 +363,42 @@ func TestInstallCSIDriver(t *testing.T) { // TestInstallCSIDriver_CSINodeInfoDisabled tests InstallCSIDriver with various existing Node annotations // and CSINodeInfo feature gate disabled. -func TestInstallCSIDriver_CSINodeInfoDisabled(t *testing.T) { +func TestInstallCSIDriverCSINodeInfoDisabled(t *testing.T) { testcases := []testcase{ { name: "empty node", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode(nil /* nodeIDs */, nil /* labels */, nil /*capacity*/), inputNodeID: "com.example.csi/csi-node1", expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, }, { name: "pre-existing node info from the same driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, nil /* labels */, nil /*capacity*/), inputNodeID: "com.example.csi/csi-node1", expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, }, { name: "pre-existing node info from different driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/test-node", + "net.example.storage.other-driver": "net.example.storage/test-node", }, nil /* labels */, nil /*capacity*/), inputNodeID: "com.example.csi/csi-node1", expectedNodeIDMap: map[string]string{ - "com.example.csi/driver1": "com.example.csi/csi-node1", - "net.example.storage/other-driver": "net.example.storage/test-node", + "com.example.csi.driver1": "com.example.csi/csi-node1", + "net.example.storage.other-driver": "net.example.storage/test-node", }, }, } @@ -405,89 +406,91 @@ func TestInstallCSIDriver_CSINodeInfoDisabled(t *testing.T) { test(t, true /* addNodeInfo */, false /* csiNodeInfoEnabled */, testcases) } -// TestUninstallCSIDriver tests UninstallCSIDriver with various existing Node and/or CSINodeInfo objects. +// TestUninstallCSIDriver tests UninstallCSIDriver with various existing Node and/or CSINode objects. func TestUninstallCSIDriver(t *testing.T) { testcases := []testcase{ { - name: "empty node and empty CSINodeInfo", - driverName: "com.example.csi/driver1", + name: "empty node and empty CSINode", + driverName: "com.example.csi.driver1", existingNode: generateNode(nil /* nodeIDs */, nil /* labels */, nil /*capacity*/), expectedNodeIDMap: nil, expectedLabels: nil, }, { name: "pre-existing node info from the same driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, labelMap{ "com.example.csi/zone": "zoneA", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, topologyKeyMap{ - "com.example.csi/driver1": {"com.example.csi/zone"}, + "com.example.csi.driver1": {"com.example.csi/zone"}, }, ), expectedNodeIDMap: nil, expectedLabels: map[string]string{"com.example.csi/zone": "zoneA"}, + hasModified: true, }, { name: "pre-existing node info from different driver", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/csi-node1", + "net.example.storage.other-driver": "net.example.storage/csi-node1", }, labelMap{ "net.example.storage/zone": "zoneA", }, nil /*capacity*/), - existingNodeInfo: generateNodeInfo( + existingCSINode: generateCSINode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/csi-node1", + "net.example.storage.other-driver": "net.example.storage/csi-node1", }, topologyKeyMap{ - "net.example.storage/other-driver": {"net.example.storage/zone"}, + "net.example.storage.other-driver": {"net.example.storage/zone"}, }, ), expectedNodeIDMap: map[string]string{ - "net.example.storage/other-driver": "net.example.storage/csi-node1", + "net.example.storage.other-driver": "net.example.storage/csi-node1", }, expectedTopologyMap: map[string]sets.String{ - "net.example.storage/other-driver": sets.NewString("net.example.storage/zone"), + "net.example.storage.other-driver": sets.NewString("net.example.storage/zone"), }, expectedLabels: map[string]string{"net.example.storage/zone": "zoneA"}, + hasModified: false, }, { - name: "pre-existing info about the same driver in node, but empty CSINodeInfo", - driverName: "com.example.csi/driver1", + name: "pre-existing info about the same driver in node, but empty CSINode", + driverName: "com.example.csi.driver1", existingNode: generateNode( nodeIDMap{ - "com.example.csi/driver1": "com.example.csi/csi-node1", + "com.example.csi.driver1": "com.example.csi/csi-node1", }, nil /* labels */, nil /*capacity*/), expectedNodeIDMap: nil, expectedLabels: nil, }, { - name: "pre-existing info about a different driver in node, but empty CSINodeInfo", + name: "pre-existing info about a different driver in node, but empty CSINode", existingNode: generateNode( nodeIDMap{ - "net.example.storage/other-driver": "net.example.storage/csi-node1", + "net.example.storage.other-driver": "net.example.storage/csi-node1", }, nil /* labels */, nil /*capacity*/), expectedNodeIDMap: map[string]string{ - "net.example.storage/other-driver": "net.example.storage/csi-node1", + "net.example.storage.other-driver": "net.example.storage/csi-node1", }, expectedLabels: nil, }, { name: "new node with valid max limit", - driverName: "com.example.csi/driver1", + driverName: "com.example.csi.driver1", existingNode: generateNode( nil, /*nodeIDs*/ nil, /*labels*/ @@ -505,9 +508,9 @@ func TestUninstallCSIDriver(t *testing.T) { test(t, false /* addNodeInfo */, true /* csiNodeInfoEnabled */, testcases) } -// TestUninstallCSIDriver tests UninstallCSIDriver with various existing Node objects and CSINodeInfo +// TestUninstallCSIDriver tests UninstallCSIDriver with various existing Node objects and CSINode // feature disabled. -func TestUninstallCSIDriver_CSINodeInfoDisabled(t *testing.T) { +func TestUninstallCSIDriverCSINodeInfoDisabled(t *testing.T) { testcases := []testcase{ { name: "empty node", @@ -553,7 +556,7 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) { existingNode *v1.Node }{ { - name: "pre-existing info about the same driver in node, but empty CSINodeInfo", + name: "pre-existing info about the same driver in node, but empty CSINode", existingNode: generateNode( nodeIDMap{ "com.example.csi/driver1": "com.example.csi/csi-node1", @@ -561,7 +564,7 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) { nil /* labels */, nil /*capacity*/), }, { - name: "pre-existing info about a different driver in node, but empty CSINodeInfo", + name: "pre-existing info about a different driver in node, but empty CSINode", existingNode: generateNode( nodeIDMap{ "net.example.storage/other-driver": "net.example.storage/test-node", @@ -576,7 +579,6 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) { // Arrange nodeName := tc.existingNode.Name client := fake.NewSimpleClientset(tc.existingNode) - csiClient := csifake.NewSimpleClientset() tmpDir, err := utiltesting.MkTmpdir("nodeinfomanager-test") if err != nil { @@ -585,7 +587,6 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) { host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, client, - csiClient, nil, nodeName, ) @@ -593,7 +594,7 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) { nim := NewNodeInfoManager(types.NodeName(nodeName), host) // Act - _, err = nim.CreateCSINodeInfo() + _, err = nim.CreateCSINode() if err != nil { t.Errorf("expected no error from creating CSINodeinfo but got: %v", err) continue @@ -605,15 +606,9 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) { } // Assert - nodeInfo, err := csiClient.CsiV1alpha1().CSINodeInfos().Get(nodeName, metav1.GetOptions{}) + nodeInfo, err := client.StorageV1beta1().CSINodes().Get(nodeName, metav1.GetOptions{}) if err != nil { - t.Errorf("error getting CSINodeInfo: %v", err) - continue - } - - if len(nodeInfo.Spec.Drivers) != 1 || len(nodeInfo.Status.Drivers) != 1 { - t.Errorf("expected 1 CSIDriverInfoSpec and 1 CSIDriverInfoStatus entry but got: %d, %d", - len(nodeInfo.Spec.Drivers), len(nodeInfo.Status.Drivers)) + t.Errorf("error getting CSINode: %v", err) continue } @@ -624,296 +619,6 @@ func TestInstallCSIDriverExistingAnnotation(t *testing.T) { } } -func TestValidateCSINodeInfo(t *testing.T) { - testcases := []struct { - name string - nodeInfo *csiv1alpha1.CSINodeInfo - expectErr bool - }{ - { - name: "multiple drivers with different node IDs, topology keys and status", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1, key2"}, - }, - { - Name: "driverB", - NodeID: "nodeA", - TopologyKeys: []string{"keyA", "keyB"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "in-tree", - }, - { - Name: "driverB", - Available: false, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: false, - }, - { - name: "multiple drivers with same node IDs, topology keys and status", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1"}, - }, - { - Name: "driver2", - NodeID: "node1", - TopologyKeys: []string{"key1"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "csi", - }, - { - Name: "driver2", - Available: true, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: false, - }, - { - name: "duplicate drivers in driver specs", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1", "key2"}, - }, - { - Name: "driver1", - NodeID: "nodeX", - TopologyKeys: []string{"keyA", "keyB"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: true, - }, - { - name: "duplicate drivers in driver statuses", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1", "key2"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "in-tree", - }, - { - Name: "driver1", - Available: false, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: true, - }, - { - name: "single driver with duplicate topology keys in driver specs", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1", "key1"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: true, - }, - { - name: "multiple drivers with one set of duplicate topology keys in driver specs", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1"}, - }, - { - Name: "driver2", - NodeID: "nodeX", - TopologyKeys: []string{"keyA", "keyA"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "csi", - }, - { - Name: "driver2", - Available: true, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: true, - }, - { - name: "mismatch between drivers in specs and status (null intersection)", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1"}, - }, - { - Name: "driver2", - NodeID: "nodeX", - TopologyKeys: []string{"keyA", "keyA"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver3", - Available: true, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: true, - }, - { - name: "mismatch between drivers in specs and status (specs superset of status)", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1"}, - }, - { - Name: "driver2", - NodeID: "nodeX", - TopologyKeys: []string{"keyA", "keyA"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: true, - }, - { - name: "mismatch between drivers in specs and status (specs subset of status)", - nodeInfo: &csiv1alpha1.CSINodeInfo{ - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ - { - Name: "driver1", - NodeID: "node1", - TopologyKeys: []string{"key1"}, - }, - }, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "driver1", - Available: true, - VolumePluginMechanism: "csi", - }, - { - Name: "driver2", - Available: true, - VolumePluginMechanism: "csi", - }, - }, - }, - }, - expectErr: true, - }, - } - for _, tc := range testcases { - t.Logf("test case: %q", tc.name) - err := validateCSINodeInfo(tc.nodeInfo) - if err != nil && !tc.expectErr { - t.Errorf("expected no errors from validateCSINodeInfo but got error %v", err) - } - if err == nil && tc.expectErr { - t.Errorf("expected error from validateCSINodeInfo but got no errors") - } - } -} - func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []testcase) { defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSINodeInfo, csiNodeInfoEnabled)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AttachVolumeLimit, true)() @@ -923,12 +628,15 @@ func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []t //// Arrange nodeName := tc.existingNode.Name - client := fake.NewSimpleClientset(tc.existingNode) - var csiClient *csifake.Clientset - if tc.existingNodeInfo == nil { - csiClient = csifake.NewSimpleClientset() + var client *fake.Clientset + if tc.existingCSINode != nil && tc.existingNode != nil { + client = fake.NewSimpleClientset(tc.existingNode, tc.existingCSINode) + } else if tc.existingCSINode != nil && tc.existingNode == nil { + client = fake.NewSimpleClientset(tc.existingCSINode) + } else if tc.existingCSINode == nil && tc.existingNode != nil { + client = fake.NewSimpleClientset(tc.existingNode) } else { - csiClient = csifake.NewSimpleClientset(tc.existingNodeInfo) + client = fake.NewSimpleClientset() } tmpDir, err := utiltesting.MkTmpdir("nodeinfomanager-test") @@ -938,14 +646,13 @@ func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []t host := volumetest.NewFakeVolumeHostWithCSINodeName( tmpDir, client, - csiClient, nil, nodeName, ) nim := NewNodeInfoManager(types.NodeName(nodeName), host) //// Act - nim.CreateCSINodeInfo() + nim.CreateCSINode() if addNodeInfo { err = nim.InstallCSIDriver(tc.driverName, tc.inputNodeID, tc.inputVolumeLimit, tc.inputTopology) } else { @@ -1017,42 +724,44 @@ func test(t *testing.T, addNodeInfo bool, csiNodeInfoEnabled bool, testcases []t t.Errorf("expected topology labels to be %v; got: %v", tc.expectedLabels, node.Labels) } - /* CSINodeInfo validation */ - nodeInfo, err := csiClient.CsiV1alpha1().CSINodeInfos().Get(nodeName, metav1.GetOptions{}) + // CSINode validation + nodeInfo, err := client.StorageV1beta1().CSINodes().Get(nodeName, metav1.GetOptions{}) if err != nil { - t.Errorf("error getting CSINodeInfo: %v", err) + if !errors.IsNotFound(err) { + t.Errorf("error getting CSINode: %v", err) + } continue } // Extract node IDs and topology keys - availableDrivers := sets.String{} actualNodeIDs := make(map[string]string) actualTopologyKeys := make(map[string]sets.String) - for _, driver := range nodeInfo.Status.Drivers { - if driver.Available { - availableDrivers.Insert(driver.Name) - } - - } for _, driver := range nodeInfo.Spec.Drivers { - if availableDrivers.Has(driver.Name) { - actualNodeIDs[driver.Name] = driver.NodeID - actualTopologyKeys[driver.Name] = sets.NewString(driver.TopologyKeys...) - } + actualNodeIDs[driver.Name] = driver.NodeID + actualTopologyKeys[driver.Name] = sets.NewString(driver.TopologyKeys...) } // Node IDs - // No need to check if Node ID found in NodeInfo if it was present in the NodeID + // No need to check if Node ID found in Node if it was present in the NodeID if !foundInNode { if !helper.Semantic.DeepEqual(actualNodeIDs, tc.expectedNodeIDMap) { - t.Errorf("expected node IDs %v from CSINodeInfo; got: %v", tc.expectedNodeIDMap, actualNodeIDs) + t.Errorf("expected node IDs %v from CSINode; got: %v", tc.expectedNodeIDMap, actualNodeIDs) } } // Topology keys if !helper.Semantic.DeepEqual(actualTopologyKeys, tc.expectedTopologyMap) { - t.Errorf("expected topology keys %v from CSINodeInfo; got: %v", tc.expectedTopologyMap, actualTopologyKeys) + t.Errorf("expected topology keys %v from CSINode; got: %v", tc.expectedTopologyMap, actualTopologyKeys) + } + + if !addNodeInfo && tc.existingCSINode != nil && tc.existingNode != nil { + if tc.hasModified && helper.Semantic.DeepEqual(nodeInfo, tc.existingCSINode) { + t.Errorf("existing CSINode %v; got: %v", tc.existingCSINode, nodeInfo) + } + if !tc.hasModified && !helper.Semantic.DeepEqual(nodeInfo, tc.existingCSINode) { + t.Errorf("existing CSINode %v; got: %v", tc.existingCSINode, nodeInfo) + } } } } @@ -1092,34 +801,24 @@ func generateNode(nodeIDs, labels map[string]string, capacity map[v1.ResourceNam return node } -func generateNodeInfo(nodeIDs map[string]string, topologyKeys map[string][]string) *csiv1alpha1.CSINodeInfo { - driverInfoSpecs := []csiv1alpha1.CSIDriverInfoSpec{} - driverInfoStatuses := []csiv1alpha1.CSIDriverInfoStatus{} +func generateCSINode(nodeIDs map[string]string, topologyKeys map[string][]string) *storage.CSINode { + nodeDrivers := []storage.CSINodeDriver{} for k, nodeID := range nodeIDs { - dspec := csiv1alpha1.CSIDriverInfoSpec{ + dspec := storage.CSINodeDriver{ Name: k, NodeID: nodeID, } - dstatus := csiv1alpha1.CSIDriverInfoStatus{ - Name: k, - Available: true, - VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree, - } if top, exists := topologyKeys[k]; exists { dspec.TopologyKeys = top } - driverInfoSpecs = append(driverInfoSpecs, dspec) - driverInfoStatuses = append(driverInfoStatuses, dstatus) + nodeDrivers = append(nodeDrivers, dspec) } - return &csiv1alpha1.CSINodeInfo{ + return &storage.CSINode{ ObjectMeta: metav1.ObjectMeta{ Name: "node1", }, - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: driverInfoSpecs, - }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: driverInfoStatuses, + Spec: storage.CSINodeSpec{ + Drivers: nodeDrivers, }, } } diff --git a/pkg/volume/plugins.go b/pkg/volume/plugins.go index 0bbd69640c..84b3a5b785 100644 --- a/pkg/volume/plugins.go +++ b/pkg/volume/plugins.go @@ -32,7 +32,6 @@ import ( clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/record" cloudprovider "k8s.io/cloud-provider" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/klog" "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" @@ -318,9 +317,6 @@ type VolumeHost interface { // GetKubeClient returns a client interface GetKubeClient() clientset.Interface - // GetCSIClient returns a client interface to csi.storage.k8s.io - GetCSIClient() csiclientset.Interface - // NewWrapperMounter finds an appropriate plugin with which to handle // the provided spec. This is used to implement volume plugins which // "wrap" other plugins. For example, the "secret" volume is diff --git a/pkg/volume/testing/BUILD b/pkg/volume/testing/BUILD index 02f4efba7c..b454ee05f5 100644 --- a/pkg/volume/testing/BUILD +++ b/pkg/volume/testing/BUILD @@ -29,7 +29,6 @@ go_library( "//staging/src/k8s.io/client-go/tools/record:go_default_library", "//staging/src/k8s.io/client-go/util/testing:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//vendor/github.com/stretchr/testify/mock:go_default_library", "//vendor/k8s.io/utils/strings:go_default_library", ], diff --git a/pkg/volume/testing/testing.go b/pkg/volume/testing/testing.go index d41ea0d4f9..0d3a6f66ca 100644 --- a/pkg/volume/testing/testing.go +++ b/pkg/volume/testing/testing.go @@ -37,7 +37,6 @@ import ( "k8s.io/client-go/tools/record" utiltesting "k8s.io/client-go/util/testing" cloudprovider "k8s.io/cloud-provider" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/kubernetes/pkg/util/mount" . "k8s.io/kubernetes/pkg/volume" "k8s.io/kubernetes/pkg/volume/util" @@ -65,7 +64,6 @@ const ( type fakeVolumeHost struct { rootDir string kubeClient clientset.Interface - csiClient csiclientset.Interface pluginMgr VolumePluginMgr cloud cloudprovider.Interface mounter mount.Interface @@ -89,10 +87,9 @@ func NewFakeVolumeHostWithNodeLabels(rootDir string, kubeClient clientset.Interf return volHost } -func NewFakeVolumeHostWithCSINodeName(rootDir string, kubeClient clientset.Interface, csiClient csiclientset.Interface, plugins []VolumePlugin, nodeName string) *fakeVolumeHost { +func NewFakeVolumeHostWithCSINodeName(rootDir string, kubeClient clientset.Interface, plugins []VolumePlugin, nodeName string) *fakeVolumeHost { volHost := newFakeVolumeHost(rootDir, kubeClient, plugins, nil, nil) volHost.nodeName = nodeName - volHost.csiClient = csiClient return volHost } @@ -140,10 +137,6 @@ func (f *fakeVolumeHost) GetKubeClient() clientset.Interface { return f.kubeClient } -func (f *fakeVolumeHost) GetCSIClient() csiclientset.Interface { - return f.csiClient -} - func (f *fakeVolumeHost) GetCloudProvider() cloudprovider.Interface { return f.cloud } diff --git a/plugin/pkg/admission/noderestriction/BUILD b/plugin/pkg/admission/noderestriction/BUILD index 6a632ef272..bcc03b465d 100644 --- a/plugin/pkg/admission/noderestriction/BUILD +++ b/plugin/pkg/admission/noderestriction/BUILD @@ -16,6 +16,7 @@ go_library( "//pkg/apis/coordination:go_default_library", "//pkg/apis/core:go_default_library", "//pkg/apis/policy:go_default_library", + "//pkg/apis/storage:go_default_library", "//pkg/auth/nodeidentifier:go_default_library", "//pkg/features:go_default_library", "//pkg/kubelet/apis:go_default_library", @@ -30,7 +31,6 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/client-go/informers:go_default_library", "//staging/src/k8s.io/client-go/listers/core/v1:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], ) @@ -44,6 +44,7 @@ go_test( "//pkg/apis/coordination:go_default_library", "//pkg/apis/core:go_default_library", "//pkg/apis/policy:go_default_library", + "//pkg/apis/storage:go_default_library", "//pkg/auth/nodeidentifier:go_default_library", "//pkg/features:go_default_library", "//pkg/kubelet/apis:go_default_library", @@ -57,7 +58,6 @@ go_test( "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/client-go/listers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library", "//vendor/k8s.io/utils/pointer:go_default_library", ], ) diff --git a/plugin/pkg/admission/noderestriction/admission.go b/plugin/pkg/admission/noderestriction/admission.go index 305fdddad6..b83273e52b 100644 --- a/plugin/pkg/admission/noderestriction/admission.go +++ b/plugin/pkg/admission/noderestriction/admission.go @@ -32,13 +32,13 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/informers" corev1lister "k8s.io/client-go/listers/core/v1" - csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1" "k8s.io/klog" podutil "k8s.io/kubernetes/pkg/api/pod" authenticationapi "k8s.io/kubernetes/pkg/apis/authentication" coordapi "k8s.io/kubernetes/pkg/apis/coordination" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/policy" + storage "k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/auth/nodeidentifier" "k8s.io/kubernetes/pkg/features" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" @@ -94,12 +94,12 @@ func (p *nodePlugin) ValidateInitialization() error { } var ( - podResource = api.Resource("pods") - nodeResource = api.Resource("nodes") - pvcResource = api.Resource("persistentvolumeclaims") - svcacctResource = api.Resource("serviceaccounts") - leaseResource = coordapi.Resource("leases") - csiNodeInfoResource = csiv1alpha1.Resource("csinodeinfos") + podResource = api.Resource("pods") + nodeResource = api.Resource("nodes") + pvcResource = api.Resource("persistentvolumeclaims") + svcacctResource = api.Resource("serviceaccounts") + leaseResource = coordapi.Resource("leases") + csiNodeResource = storage.Resource("csinodes") ) func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) error { @@ -151,9 +151,9 @@ func (c *nodePlugin) Admit(a admission.Attributes, o admission.ObjectInterfaces) } return admission.NewForbidden(a, fmt.Errorf("disabled by feature gate %s", features.NodeLease)) - case csiNodeInfoResource: + case csiNodeResource: if c.features.Enabled(features.KubeletPluginsWatcher) && c.features.Enabled(features.CSINodeInfo) { - return c.admitCSINodeInfo(nodeName, a) + return c.admitCSINode(nodeName, a) } return admission.NewForbidden(a, fmt.Errorf("disabled by feature gates %s and %s", features.KubeletPluginsWatcher, features.CSINodeInfo)) @@ -530,8 +530,8 @@ func (r *nodePlugin) admitLease(nodeName string, a admission.Attributes) error { return nil } -func (c *nodePlugin) admitCSINodeInfo(nodeName string, a admission.Attributes) error { - // the request must come from a node with the same name as the CSINodeInfo object +func (c *nodePlugin) admitCSINode(nodeName string, a admission.Attributes) error { + // the request must come from a node with the same name as the CSINode object if a.GetOperation() == admission.Create { // a.GetName() won't return the name on create, so we drill down to the proposed object accessor, err := meta.Accessor(a.GetObject()) @@ -539,11 +539,11 @@ func (c *nodePlugin) admitCSINodeInfo(nodeName string, a admission.Attributes) e return admission.NewForbidden(a, fmt.Errorf("unable to access the object name")) } if accessor.GetName() != nodeName { - return admission.NewForbidden(a, fmt.Errorf("can only access CSINodeInfo with the same name as the requesting node")) + return admission.NewForbidden(a, fmt.Errorf("can only access CSINode with the same name as the requesting node")) } } else { if a.GetName() != nodeName { - return admission.NewForbidden(a, fmt.Errorf("can only access CSINodeInfo with the same name as the requesting node")) + return admission.NewForbidden(a, fmt.Errorf("can only access CSINode with the same name as the requesting node")) } } diff --git a/plugin/pkg/admission/noderestriction/admission_test.go b/plugin/pkg/admission/noderestriction/admission_test.go index a81d9fa7dd..b7d998f6ee 100644 --- a/plugin/pkg/admission/noderestriction/admission_test.go +++ b/plugin/pkg/admission/noderestriction/admission_test.go @@ -33,11 +33,11 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" corev1lister "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" - csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1" authenticationapi "k8s.io/kubernetes/pkg/apis/authentication" "k8s.io/kubernetes/pkg/apis/coordination" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/policy" + storage "k8s.io/kubernetes/pkg/apis/storage" "k8s.io/kubernetes/pkg/auth/nodeidentifier" "k8s.io/kubernetes/pkg/features" kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis" @@ -306,14 +306,14 @@ func Test_nodePlugin_Admit(t *testing.T) { }, } - csiNodeInfoResource = csiv1alpha1.Resource("csinodeinfos").WithVersion("v1alpha1") - csiNodeInfoKind = schema.GroupVersionKind{Group: "csi.storage.k8s.io", Version: "v1alpha1", Kind: "CSINodeInfo"} - nodeInfo = &csiv1alpha1.CSINodeInfo{ + csiNodeResource = storage.Resource("csinodes").WithVersion("v1beta1") + csiNodeKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSINode"} + nodeInfo = &storage.CSINode{ ObjectMeta: metav1.ObjectMeta{ Name: "mynode", }, - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ { Name: "com.example.csi/mydriver", NodeID: "com.example.csi/mynode", @@ -321,22 +321,13 @@ func Test_nodePlugin_Admit(t *testing.T) { }, }, }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "com.example.csi/mydriver", - Available: true, - VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree, - }, - }, - }, } - nodeInfoWrongName = &csiv1alpha1.CSINodeInfo{ + nodeInfoWrongName = &storage.CSINode{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ + Spec: storage.CSINodeSpec{ + Drivers: []storage.CSINodeDriver{ { Name: "com.example.csi/mydriver", NodeID: "com.example.csi/foo", @@ -344,15 +335,6 @@ func Test_nodePlugin_Admit(t *testing.T) { }, }, }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "com.example.csi/mydriver", - Available: true, - VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree, - }, - }, - }, } noExistingPodsIndex = cache.NewIndexer(cache.MetaNamespaceKeyFunc, nil) @@ -1183,46 +1165,46 @@ func Test_nodePlugin_Admit(t *testing.T) { features: leaseEnabledFeature, err: "", }, - // CSINodeInfo + // CSINode { - name: "disallowed create CSINodeInfo - feature disabled", - attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Create, false, mynode), + name: "disallowed create CSINode - feature disabled", + attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Create, false, mynode), features: csiNodeInfoDisabledFeature, err: fmt.Sprintf("forbidden: disabled by feature gates %s and %s", features.KubeletPluginsWatcher, features.CSINodeInfo), }, { - name: "disallowed create another node's CSINodeInfo - feature enabled", - attributes: admission.NewAttributesRecord(nodeInfoWrongName, nil, csiNodeInfoKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeInfoResource, "", admission.Create, false, mynode), + name: "disallowed create another node's CSINode - feature enabled", + attributes: admission.NewAttributesRecord(nodeInfoWrongName, nil, csiNodeKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeResource, "", admission.Create, false, mynode), features: csiNodeInfoEnabledFeature, err: "forbidden: ", }, { - name: "disallowed update another node's CSINodeInfo - feature enabled", - attributes: admission.NewAttributesRecord(nodeInfoWrongName, nodeInfoWrongName, csiNodeInfoKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeInfoResource, "", admission.Update, false, mynode), + name: "disallowed update another node's CSINode - feature enabled", + attributes: admission.NewAttributesRecord(nodeInfoWrongName, nodeInfoWrongName, csiNodeKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeResource, "", admission.Update, false, mynode), features: csiNodeInfoEnabledFeature, err: "forbidden: ", }, { - name: "disallowed delete another node's CSINodeInfo - feature enabled", - attributes: admission.NewAttributesRecord(nil, nil, csiNodeInfoKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeInfoResource, "", admission.Delete, false, mynode), + name: "disallowed delete another node's CSINode - feature enabled", + attributes: admission.NewAttributesRecord(nil, nil, csiNodeKind, nodeInfoWrongName.Namespace, nodeInfoWrongName.Name, csiNodeResource, "", admission.Delete, false, mynode), features: csiNodeInfoEnabledFeature, err: "forbidden: ", }, { - name: "allowed create node CSINodeInfo - feature enabled", - attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Create, false, mynode), + name: "allowed create node CSINode - feature enabled", + attributes: admission.NewAttributesRecord(nodeInfo, nil, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Create, false, mynode), features: csiNodeInfoEnabledFeature, err: "", }, { - name: "allowed update node CSINodeInfo - feature enabled", - attributes: admission.NewAttributesRecord(nodeInfo, nodeInfo, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Update, false, mynode), + name: "allowed update node CSINode - feature enabled", + attributes: admission.NewAttributesRecord(nodeInfo, nodeInfo, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Update, false, mynode), features: csiNodeInfoEnabledFeature, err: "", }, { - name: "allowed delete node CSINodeInfo - feature enabled", - attributes: admission.NewAttributesRecord(nil, nil, csiNodeInfoKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeInfoResource, "", admission.Delete, false, mynode), + name: "allowed delete node CSINode - feature enabled", + attributes: admission.NewAttributesRecord(nil, nil, csiNodeKind, nodeInfo.Namespace, nodeInfo.Name, csiNodeResource, "", admission.Delete, false, mynode), features: csiNodeInfoEnabledFeature, err: "", }, diff --git a/plugin/pkg/auth/authorizer/node/BUILD b/plugin/pkg/auth/authorizer/node/BUILD index 4e171b31a4..39ae2624b6 100644 --- a/plugin/pkg/auth/authorizer/node/BUILD +++ b/plugin/pkg/auth/authorizer/node/BUILD @@ -56,7 +56,6 @@ go_library( "//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library", "//third_party/forked/gonum/graph:go_default_library", "//third_party/forked/gonum/graph/simple:go_default_library", "//third_party/forked/gonum/graph/traverse:go_default_library", diff --git a/plugin/pkg/auth/authorizer/node/node_authorizer.go b/plugin/pkg/auth/authorizer/node/node_authorizer.go index 1e541ee22a..b0f49c12fa 100644 --- a/plugin/pkg/auth/authorizer/node/node_authorizer.go +++ b/plugin/pkg/auth/authorizer/node/node_authorizer.go @@ -25,7 +25,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/authorization/authorizer" utilfeature "k8s.io/apiserver/pkg/util/feature" - csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1" coordapi "k8s.io/kubernetes/pkg/apis/coordination" api "k8s.io/kubernetes/pkg/apis/core" storageapi "k8s.io/kubernetes/pkg/apis/storage" @@ -68,14 +67,14 @@ func NewAuthorizer(graph *Graph, identifier nodeidentifier.NodeIdentifier, rules } var ( - configMapResource = api.Resource("configmaps") - secretResource = api.Resource("secrets") - pvcResource = api.Resource("persistentvolumeclaims") - pvResource = api.Resource("persistentvolumes") - vaResource = storageapi.Resource("volumeattachments") - svcAcctResource = api.Resource("serviceaccounts") - leaseResource = coordapi.Resource("leases") - csiNodeInfoResource = csiv1alpha1.Resource("csinodeinfos") + configMapResource = api.Resource("configmaps") + secretResource = api.Resource("secrets") + pvcResource = api.Resource("persistentvolumeclaims") + pvResource = api.Resource("persistentvolumes") + vaResource = storageapi.Resource("volumeattachments") + svcAcctResource = api.Resource("serviceaccounts") + leaseResource = coordapi.Resource("leases") + csiNodeResource = storageapi.Resource("csinodes") ) func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (authorizer.Decision, string, error) { @@ -122,9 +121,9 @@ func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (authorizer.Deci return r.authorizeLease(nodeName, attrs) } return authorizer.DecisionNoOpinion, fmt.Sprintf("disabled by feature gate %s", features.NodeLease), nil - case csiNodeInfoResource: + case csiNodeResource: if r.features.Enabled(features.KubeletPluginsWatcher) && r.features.Enabled(features.CSINodeInfo) { - return r.authorizeCSINodeInfo(nodeName, attrs) + return r.authorizeCSINode(nodeName, attrs) } return authorizer.DecisionNoOpinion, fmt.Sprintf("disabled by feature gates %s and %s", features.KubeletPluginsWatcher, features.CSINodeInfo), nil } @@ -260,8 +259,8 @@ func (r *NodeAuthorizer) authorizeLease(nodeName string, attrs authorizer.Attrib return authorizer.DecisionAllow, "", nil } -// authorizeCSINodeInfo authorizes node requests to CSINodeInfo csi.storage.k8s.io/csinodeinfos -func (r *NodeAuthorizer) authorizeCSINodeInfo(nodeName string, attrs authorizer.Attributes) (authorizer.Decision, string, error) { +// authorizeCSINode authorizes node requests to CSINode storage.k8s.io/csinodes +func (r *NodeAuthorizer) authorizeCSINode(nodeName string, attrs authorizer.Attributes) (authorizer.Decision, string, error) { // allowed verbs: get, create, update, patch, delete verb := attrs.GetVerb() if verb != "get" && @@ -270,20 +269,20 @@ func (r *NodeAuthorizer) authorizeCSINodeInfo(nodeName string, attrs authorizer. verb != "patch" && verb != "delete" { klog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs) - return authorizer.DecisionNoOpinion, "can only get, create, update, patch, or delete a CSINodeInfo", nil + return authorizer.DecisionNoOpinion, "can only get, create, update, patch, or delete a CSINode", nil } if len(attrs.GetSubresource()) > 0 { klog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs) - return authorizer.DecisionNoOpinion, "cannot authorize CSINodeInfo subresources", nil + return authorizer.DecisionNoOpinion, "cannot authorize CSINode subresources", nil } - // the request must come from a node with the same name as the CSINodeInfo + // the request must come from a node with the same name as the CSINode // note we skip this check for create, since the authorizer doesn't know the name on create // the noderestriction admission plugin is capable of performing this check at create time if verb != "create" && attrs.GetName() != nodeName { klog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs) - return authorizer.DecisionNoOpinion, "can only access CSINodeInfo with the same name as the requesting node", nil + return authorizer.DecisionNoOpinion, "can only access CSINode with the same name as the requesting node", nil } return authorizer.DecisionAllow, "", nil diff --git a/plugin/pkg/auth/authorizer/node/node_authorizer_test.go b/plugin/pkg/auth/authorizer/node/node_authorizer_test.go index e7b318026d..afe1bdaf02 100644 --- a/plugin/pkg/auth/authorizer/node/node_authorizer_test.go +++ b/plugin/pkg/auth/authorizer/node/node_authorizer_test.go @@ -352,82 +352,82 @@ func TestAuthorizer(t *testing.T) { features: leaseEnabledFeature, expect: authorizer.DecisionAllow, }, - // CSINodeInfo + // CSINode { - name: "disallowed CSINodeInfo - feature disabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"}, + name: "disallowed CSINode - feature disabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"}, features: csiNodeInfoDisabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "disallowed CSINodeInfo with subresource - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", Subresource: "csiDrivers", APIGroup: "csi.storage.k8s.io", Name: "node0"}, + name: "disallowed CSINode with subresource - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", Subresource: "csiDrivers", APIGroup: "storage.k8s.io", Name: "node0"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "disallowed get another node's CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"}, + name: "disallowed get another node's CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "disallowed update another node's CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"}, + name: "disallowed update another node's CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "disallowed patch another node's CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"}, + name: "disallowed patch another node's CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "disallowed delete another node's CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node1"}, + name: "disallowed delete another node's CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node1"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "disallowed list CSINodeInfos - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "list", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io"}, + name: "disallowed list CSINodes - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "list", Resource: "csinodes", APIGroup: "storage.k8s.io"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "disallowed watch CSINodeInfos - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "watch", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io"}, + name: "disallowed watch CSINodes - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "watch", Resource: "csinodes", APIGroup: "storage.k8s.io"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionNoOpinion, }, { - name: "allowed get CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"}, + name: "allowed get CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionAllow, }, { - name: "allowed create CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"}, + name: "allowed create CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "create", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionAllow, }, { - name: "allowed update CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"}, + name: "allowed update CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "update", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionAllow, }, { - name: "allowed patch CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"}, + name: "allowed patch CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "patch", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionAllow, }, { - name: "allowed delete CSINodeInfo - feature enabled", - attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodeinfos", APIGroup: "csi.storage.k8s.io", Name: "node0"}, + name: "allowed delete CSINode - feature enabled", + attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "delete", Resource: "csinodes", APIGroup: "storage.k8s.io", Name: "node0"}, features: csiNodeInfoEnabledFeature, expect: authorizer.DecisionAllow, }, diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/controller_policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/controller_policy.go index 71485bc986..c409ae8fd9 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/controller_policy.go +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/controller_policy.go @@ -74,7 +74,7 @@ func buildControllerRoles() ([]rbacv1.ClusterRole, []rbacv1.ClusterRoleBinding) if utilfeature.DefaultFeatureGate.Enabled(features.CSIPersistentVolume) { role.Rules = append(role.Rules, rbacv1helpers.NewRule("get", "create", "delete", "list", "watch").Groups(storageGroup).Resources("volumeattachments").RuleOrDie()) if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { - role.Rules = append(role.Rules, rbacv1helpers.NewRule("get", "watch", "list").Groups("csi.storage.k8s.io").Resources("csidrivers").RuleOrDie()) + role.Rules = append(role.Rules, rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csidrivers").RuleOrDie()) } } diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go index 77b411c73e..f037181279 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go @@ -160,13 +160,13 @@ func NodeRules() []rbacv1.PolicyRule { volAttachRule := rbacv1helpers.NewRule("get").Groups(storageGroup).Resources("volumeattachments").RuleOrDie() nodePolicyRules = append(nodePolicyRules, volAttachRule) if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { - csiDriverRule := rbacv1helpers.NewRule("get", "watch", "list").Groups("csi.storage.k8s.io").Resources("csidrivers").RuleOrDie() + csiDriverRule := rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csidrivers").RuleOrDie() nodePolicyRules = append(nodePolicyRules, csiDriverRule) } } if utilfeature.DefaultFeatureGate.Enabled(features.KubeletPluginsWatcher) && utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { - csiNodeInfoRule := rbacv1helpers.NewRule("get", "create", "update", "patch", "delete").Groups("csi.storage.k8s.io").Resources("csinodeinfos").RuleOrDie() + csiNodeInfoRule := rbacv1helpers.NewRule("get", "create", "update", "patch", "delete").Groups("storage.k8s.io").Resources("csinodes").RuleOrDie() nodePolicyRules = append(nodePolicyRules, csiNodeInfoRule) } @@ -514,7 +514,7 @@ func ClusterRoles() []rbacv1.ClusterRole { rbacv1helpers.NewRule("get", "list", "watch").Groups(legacyGroup).Resources("nodes").RuleOrDie(), } if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { - externalProvisionerRules = append(externalProvisionerRules, rbacv1helpers.NewRule("get", "watch", "list").Groups("csi.storage.k8s.io").Resources("csinodeinfos").RuleOrDie()) + externalProvisionerRules = append(externalProvisionerRules, rbacv1helpers.NewRule("get", "watch", "list").Groups("storage.k8s.io").Resources("csinodes").RuleOrDie()) } roles = append(roles, rbacv1.ClusterRole{ // a role for the csi external provisioner diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml index f5c14a37fc..357546a8c0 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/cluster-roles.yaml @@ -534,6 +534,14 @@ items: - get - list - watch + - apiGroups: + - storage.k8s.io + resources: + - csinodes + verbs: + - get + - list + - watch - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -987,6 +995,24 @@ items: - volumeattachments verbs: - get + - apiGroups: + - storage.k8s.io + resources: + - csidrivers + verbs: + - get + - list + - watch + - apiGroups: + - storage.k8s.io + resources: + - csinodes + verbs: + - create + - delete + - get + - patch + - update - apiGroups: - coordination.k8s.io resources: diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml index 3344def7c2..2c64f63a96 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/controller-roles.yaml @@ -58,6 +58,14 @@ items: - get - list - watch + - apiGroups: + - storage.k8s.io + resources: + - csidrivers + verbs: + - get + - list + - watch - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: diff --git a/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go b/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go index 3e995f039f..0cde6ec087 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go +++ b/staging/src/k8s.io/api/storage/v1beta1/generated.pb.go @@ -24,6 +24,13 @@ limitations under the License. k8s.io/kubernetes/vendor/k8s.io/api/storage/v1beta1/generated.proto It has these top-level messages: + CSIDriver + CSIDriverList + CSIDriverSpec + CSINode + CSINodeDriver + CSINodeList + CSINodeSpec StorageClass StorageClassList VolumeAttachment @@ -59,39 +66,74 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package +func (m *CSIDriver) Reset() { *m = CSIDriver{} } +func (*CSIDriver) ProtoMessage() {} +func (*CSIDriver) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } + +func (m *CSIDriverList) Reset() { *m = CSIDriverList{} } +func (*CSIDriverList) ProtoMessage() {} +func (*CSIDriverList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } + +func (m *CSIDriverSpec) Reset() { *m = CSIDriverSpec{} } +func (*CSIDriverSpec) ProtoMessage() {} +func (*CSIDriverSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} } + +func (m *CSINode) Reset() { *m = CSINode{} } +func (*CSINode) ProtoMessage() {} +func (*CSINode) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} } + +func (m *CSINodeDriver) Reset() { *m = CSINodeDriver{} } +func (*CSINodeDriver) ProtoMessage() {} +func (*CSINodeDriver) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} } + +func (m *CSINodeList) Reset() { *m = CSINodeList{} } +func (*CSINodeList) ProtoMessage() {} +func (*CSINodeList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} } + +func (m *CSINodeSpec) Reset() { *m = CSINodeSpec{} } +func (*CSINodeSpec) ProtoMessage() {} +func (*CSINodeSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} } + func (m *StorageClass) Reset() { *m = StorageClass{} } func (*StorageClass) ProtoMessage() {} -func (*StorageClass) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{0} } +func (*StorageClass) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{7} } func (m *StorageClassList) Reset() { *m = StorageClassList{} } func (*StorageClassList) ProtoMessage() {} -func (*StorageClassList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{1} } +func (*StorageClassList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{8} } func (m *VolumeAttachment) Reset() { *m = VolumeAttachment{} } func (*VolumeAttachment) ProtoMessage() {} -func (*VolumeAttachment) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{2} } +func (*VolumeAttachment) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{9} } func (m *VolumeAttachmentList) Reset() { *m = VolumeAttachmentList{} } func (*VolumeAttachmentList) ProtoMessage() {} -func (*VolumeAttachmentList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{3} } +func (*VolumeAttachmentList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{10} } func (m *VolumeAttachmentSource) Reset() { *m = VolumeAttachmentSource{} } func (*VolumeAttachmentSource) ProtoMessage() {} -func (*VolumeAttachmentSource) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{4} } +func (*VolumeAttachmentSource) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{11} } func (m *VolumeAttachmentSpec) Reset() { *m = VolumeAttachmentSpec{} } func (*VolumeAttachmentSpec) ProtoMessage() {} -func (*VolumeAttachmentSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{5} } +func (*VolumeAttachmentSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{12} } func (m *VolumeAttachmentStatus) Reset() { *m = VolumeAttachmentStatus{} } func (*VolumeAttachmentStatus) ProtoMessage() {} -func (*VolumeAttachmentStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{6} } +func (*VolumeAttachmentStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{13} } func (m *VolumeError) Reset() { *m = VolumeError{} } func (*VolumeError) ProtoMessage() {} -func (*VolumeError) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{7} } +func (*VolumeError) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{14} } func init() { + proto.RegisterType((*CSIDriver)(nil), "k8s.io.api.storage.v1beta1.CSIDriver") + proto.RegisterType((*CSIDriverList)(nil), "k8s.io.api.storage.v1beta1.CSIDriverList") + proto.RegisterType((*CSIDriverSpec)(nil), "k8s.io.api.storage.v1beta1.CSIDriverSpec") + proto.RegisterType((*CSINode)(nil), "k8s.io.api.storage.v1beta1.CSINode") + proto.RegisterType((*CSINodeDriver)(nil), "k8s.io.api.storage.v1beta1.CSINodeDriver") + proto.RegisterType((*CSINodeList)(nil), "k8s.io.api.storage.v1beta1.CSINodeList") + proto.RegisterType((*CSINodeSpec)(nil), "k8s.io.api.storage.v1beta1.CSINodeSpec") proto.RegisterType((*StorageClass)(nil), "k8s.io.api.storage.v1beta1.StorageClass") proto.RegisterType((*StorageClassList)(nil), "k8s.io.api.storage.v1beta1.StorageClassList") proto.RegisterType((*VolumeAttachment)(nil), "k8s.io.api.storage.v1beta1.VolumeAttachment") @@ -101,6 +143,259 @@ func init() { proto.RegisterType((*VolumeAttachmentStatus)(nil), "k8s.io.api.storage.v1beta1.VolumeAttachmentStatus") proto.RegisterType((*VolumeError)(nil), "k8s.io.api.storage.v1beta1.VolumeError") } +func (m *CSIDriver) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CSIDriver) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n1, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.Spec.Size())) + n2, err := m.Spec.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n2 + return i, nil +} + +func (m *CSIDriverList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CSIDriverList) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n3, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n3 + if len(m.Items) > 0 { + for _, msg := range m.Items { + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + +func (m *CSIDriverSpec) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CSIDriverSpec) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.AttachRequired != nil { + dAtA[i] = 0x8 + i++ + if *m.AttachRequired { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.PodInfoOnMount != nil { + dAtA[i] = 0x10 + i++ + if *m.PodInfoOnMount { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + return i, nil +} + +func (m *CSINode) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CSINode) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) + n4, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n4 + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.Spec.Size())) + n5, err := m.Spec.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n5 + return i, nil +} + +func (m *CSINodeDriver) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CSINodeDriver) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.NodeID))) + i += copy(dAtA[i:], m.NodeID) + if len(m.TopologyKeys) > 0 { + for _, s := range m.TopologyKeys { + dAtA[i] = 0x1a + i++ + l = len(s) + for l >= 1<<7 { + dAtA[i] = uint8(uint64(l)&0x7f | 0x80) + l >>= 7 + i++ + } + dAtA[i] = uint8(l) + i++ + i += copy(dAtA[i:], s) + } + } + return i, nil +} + +func (m *CSINodeList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CSINodeList) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n6, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n6 + if len(m.Items) > 0 { + for _, msg := range m.Items { + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + +func (m *CSINodeSpec) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *CSINodeSpec) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Drivers) > 0 { + for _, msg := range m.Drivers { + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + func (m *StorageClass) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -119,11 +414,11 @@ func (m *StorageClass) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) - n1, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + n7, err := m.ObjectMeta.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n1 + i += n7 dAtA[i] = 0x12 i++ i = encodeVarintGenerated(dAtA, i, uint64(len(m.Provisioner))) @@ -220,11 +515,11 @@ func (m *StorageClassList) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) - n2, err := m.ListMeta.MarshalTo(dAtA[i:]) + n8, err := m.ListMeta.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n2 + i += n8 if len(m.Items) > 0 { for _, msg := range m.Items { dAtA[i] = 0x12 @@ -258,27 +553,27 @@ func (m *VolumeAttachment) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.ObjectMeta.Size())) - n3, err := m.ObjectMeta.MarshalTo(dAtA[i:]) + n9, err := m.ObjectMeta.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n3 + i += n9 dAtA[i] = 0x12 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Spec.Size())) - n4, err := m.Spec.MarshalTo(dAtA[i:]) + n10, err := m.Spec.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n4 + i += n10 dAtA[i] = 0x1a i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Status.Size())) - n5, err := m.Status.MarshalTo(dAtA[i:]) + n11, err := m.Status.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n5 + i += n11 return i, nil } @@ -300,11 +595,11 @@ func (m *VolumeAttachmentList) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) - n6, err := m.ListMeta.MarshalTo(dAtA[i:]) + n12, err := m.ListMeta.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n6 + i += n12 if len(m.Items) > 0 { for _, msg := range m.Items { dAtA[i] = 0x12 @@ -366,11 +661,11 @@ func (m *VolumeAttachmentSpec) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Source.Size())) - n7, err := m.Source.MarshalTo(dAtA[i:]) + n13, err := m.Source.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n7 + i += n13 dAtA[i] = 0x1a i++ i = encodeVarintGenerated(dAtA, i, uint64(len(m.NodeName))) @@ -427,21 +722,21 @@ func (m *VolumeAttachmentStatus) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintGenerated(dAtA, i, uint64(m.AttachError.Size())) - n8, err := m.AttachError.MarshalTo(dAtA[i:]) + n14, err := m.AttachError.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n8 + i += n14 } if m.DetachError != nil { dAtA[i] = 0x22 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.DetachError.Size())) - n9, err := m.DetachError.MarshalTo(dAtA[i:]) + n15, err := m.DetachError.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n9 + i += n15 } return i, nil } @@ -464,11 +759,11 @@ func (m *VolumeError) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Time.Size())) - n10, err := m.Time.MarshalTo(dAtA[i:]) + n16, err := m.Time.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n10 + i += n16 dAtA[i] = 0x12 i++ i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message))) @@ -485,6 +780,94 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return offset + 1 } +func (m *CSIDriver) Size() (n int) { + var l int + _ = l + l = m.ObjectMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Spec.Size() + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *CSIDriverList) Size() (n int) { + var l int + _ = l + l = m.ListMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Items) > 0 { + for _, e := range m.Items { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *CSIDriverSpec) Size() (n int) { + var l int + _ = l + if m.AttachRequired != nil { + n += 2 + } + if m.PodInfoOnMount != nil { + n += 2 + } + return n +} + +func (m *CSINode) Size() (n int) { + var l int + _ = l + l = m.ObjectMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Spec.Size() + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *CSINodeDriver) Size() (n int) { + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.NodeID) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.TopologyKeys) > 0 { + for _, s := range m.TopologyKeys { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *CSINodeList) Size() (n int) { + var l int + _ = l + l = m.ListMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Items) > 0 { + for _, e := range m.Items { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *CSINodeSpec) Size() (n int) { + var l int + _ = l + if len(m.Drivers) > 0 { + for _, e := range m.Drivers { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *StorageClass) Size() (n int) { var l int _ = l @@ -634,6 +1017,83 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *CSIDriver) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CSIDriver{`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "CSIDriverSpec", "CSIDriverSpec", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} +func (this *CSIDriverList) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CSIDriverList{`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "CSIDriver", "CSIDriver", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} +func (this *CSIDriverSpec) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CSIDriverSpec{`, + `AttachRequired:` + valueToStringGenerated(this.AttachRequired) + `,`, + `PodInfoOnMount:` + valueToStringGenerated(this.PodInfoOnMount) + `,`, + `}`, + }, "") + return s +} +func (this *CSINode) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CSINode{`, + `ObjectMeta:` + strings.Replace(strings.Replace(this.ObjectMeta.String(), "ObjectMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta", 1), `&`, ``, 1) + `,`, + `Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "CSINodeSpec", "CSINodeSpec", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} +func (this *CSINodeDriver) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CSINodeDriver{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `NodeID:` + fmt.Sprintf("%v", this.NodeID) + `,`, + `TopologyKeys:` + fmt.Sprintf("%v", this.TopologyKeys) + `,`, + `}`, + }, "") + return s +} +func (this *CSINodeList) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CSINodeList{`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "k8s_io_apimachinery_pkg_apis_meta_v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "CSINode", "CSINode", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} +func (this *CSINodeSpec) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&CSINodeSpec{`, + `Drivers:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Drivers), "CSINodeDriver", "CSINodeDriver", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} func (this *StorageClass) String() string { if this == nil { return "nil" @@ -759,6 +1219,758 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *CSIDriver) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CSIDriver: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CSIDriver: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CSIDriverList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CSIDriverList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CSIDriverList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, CSIDriver{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CSIDriverSpec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CSIDriverSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CSIDriverSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AttachRequired", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.AttachRequired = &b + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PodInfoOnMount", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.PodInfoOnMount = &b + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CSINode) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CSINode: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CSINode: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObjectMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ObjectMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Spec", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Spec.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CSINodeDriver) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CSINodeDriver: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CSINodeDriver: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NodeID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TopologyKeys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TopologyKeys = append(m.TopologyKeys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CSINodeList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CSINodeList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CSINodeList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, CSINode{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CSINodeSpec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CSINodeSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CSINodeSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Drivers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Drivers = append(m.Drivers, CSINodeDriver{}) + if err := m.Drivers[len(m.Drivers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *StorageClass) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -2180,67 +3392,81 @@ func init() { } var fileDescriptorGenerated = []byte{ - // 988 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4d, 0x6f, 0x1b, 0x45, - 0x18, 0xce, 0xc6, 0xf9, 0x70, 0xc6, 0x09, 0x4d, 0x86, 0x08, 0x8c, 0x0f, 0x76, 0xe4, 0x0b, 0xa6, - 0x6a, 0x77, 0x9b, 0xa8, 0xa0, 0x08, 0x89, 0x83, 0xb7, 0xe4, 0x00, 0x8a, 0xdb, 0x30, 0x89, 0x2a, - 0x54, 0x71, 0x60, 0xb2, 0xfb, 0x76, 0xb3, 0x78, 0x77, 0x67, 0x99, 0x19, 0x1b, 0x72, 0xe3, 0xc4, - 0x19, 0x71, 0xe0, 0x17, 0xf0, 0x3f, 0x38, 0x92, 0x13, 0xea, 0xb1, 0x27, 0x8b, 0x2c, 0xff, 0x22, - 0xe2, 0x80, 0x66, 0x76, 0x62, 0xaf, 0xbd, 0x0e, 0x6d, 0x7a, 0xe8, 0xcd, 0xef, 0xc7, 0xf3, 0xbc, - 0xdf, 0xb3, 0x46, 0x8f, 0xfa, 0xfb, 0xc2, 0x0e, 0x99, 0xd3, 0x1f, 0x9c, 0x02, 0x4f, 0x40, 0x82, - 0x70, 0x86, 0x90, 0xf8, 0x8c, 0x3b, 0xc6, 0x40, 0xd3, 0xd0, 0x11, 0x92, 0x71, 0x1a, 0x80, 0x33, - 0xdc, 0x3d, 0x05, 0x49, 0x77, 0x9d, 0x00, 0x12, 0xe0, 0x54, 0x82, 0x6f, 0xa7, 0x9c, 0x49, 0x86, - 0x1b, 0xb9, 0xaf, 0x4d, 0xd3, 0xd0, 0x36, 0xbe, 0xb6, 0xf1, 0x6d, 0xdc, 0x0f, 0x42, 0x79, 0x36, - 0x38, 0xb5, 0x3d, 0x16, 0x3b, 0x01, 0x0b, 0x98, 0xa3, 0x21, 0xa7, 0x83, 0xe7, 0x5a, 0xd2, 0x82, - 0xfe, 0x95, 0x53, 0x35, 0xda, 0x85, 0xb0, 0x1e, 0xe3, 0x2a, 0xe6, 0x6c, 0xb8, 0xc6, 0xc3, 0x89, - 0x4f, 0x4c, 0xbd, 0xb3, 0x30, 0x01, 0x7e, 0xee, 0xa4, 0xfd, 0x40, 0x29, 0x84, 0x13, 0x83, 0xa4, - 0xf3, 0x50, 0xce, 0x4d, 0x28, 0x3e, 0x48, 0x64, 0x18, 0x43, 0x09, 0xf0, 0xc9, 0xab, 0x00, 0xc2, - 0x3b, 0x83, 0x98, 0xce, 0xe2, 0xda, 0xbf, 0xae, 0xa0, 0xf5, 0xe3, 0xbc, 0x0b, 0x8f, 0x22, 0x2a, - 0x04, 0xfe, 0x16, 0x55, 0x55, 0x52, 0x3e, 0x95, 0xb4, 0x6e, 0xed, 0x58, 0x9d, 0xda, 0xde, 0x03, - 0x7b, 0xd2, 0xb1, 0x31, 0xb7, 0x9d, 0xf6, 0x03, 0xa5, 0x10, 0xb6, 0xf2, 0xb6, 0x87, 0xbb, 0xf6, - 0x93, 0xd3, 0xef, 0xc0, 0x93, 0x3d, 0x90, 0xd4, 0xc5, 0x17, 0xa3, 0xd6, 0x42, 0x36, 0x6a, 0xa1, - 0x89, 0x8e, 0x8c, 0x59, 0xf1, 0xc7, 0xa8, 0x96, 0x72, 0x36, 0x0c, 0x45, 0xc8, 0x12, 0xe0, 0xf5, - 0xc5, 0x1d, 0xab, 0xb3, 0xe6, 0xbe, 0x6b, 0x20, 0xb5, 0xa3, 0x89, 0x89, 0x14, 0xfd, 0x70, 0x84, - 0x50, 0x4a, 0x39, 0x8d, 0x41, 0x02, 0x17, 0xf5, 0xca, 0x4e, 0xa5, 0x53, 0xdb, 0xdb, 0xb7, 0x6f, - 0x1e, 0xa6, 0x5d, 0x2c, 0xcb, 0x3e, 0x1a, 0x43, 0x0f, 0x12, 0xc9, 0xcf, 0x27, 0x29, 0x4e, 0x0c, - 0xa4, 0xc0, 0x8f, 0xfb, 0x68, 0x83, 0x83, 0x17, 0xd1, 0x30, 0x3e, 0x62, 0x51, 0xe8, 0x9d, 0xd7, - 0x97, 0x74, 0x9a, 0x07, 0xd9, 0xa8, 0xb5, 0x41, 0x8a, 0x86, 0xab, 0x51, 0xeb, 0x41, 0x79, 0x0d, - 0xec, 0x23, 0xe0, 0x22, 0x14, 0x12, 0x12, 0xf9, 0x94, 0x45, 0x83, 0x18, 0xa6, 0x30, 0x64, 0x9a, - 0x1b, 0x3f, 0x44, 0xeb, 0x31, 0x1b, 0x24, 0xf2, 0x49, 0x2a, 0x43, 0x96, 0x88, 0xfa, 0xf2, 0x4e, - 0xa5, 0xb3, 0xe6, 0x6e, 0x66, 0xa3, 0xd6, 0x7a, 0xaf, 0xa0, 0x27, 0x53, 0x5e, 0xf8, 0x10, 0x6d, - 0xd3, 0x28, 0x62, 0x3f, 0xe4, 0x01, 0x0e, 0x7e, 0x4c, 0x69, 0xa2, 0x5a, 0x55, 0x5f, 0xd9, 0xb1, - 0x3a, 0x55, 0xb7, 0x9e, 0x8d, 0x5a, 0xdb, 0xdd, 0x39, 0x76, 0x32, 0x17, 0x85, 0xbf, 0x46, 0x5b, - 0x43, 0xad, 0x72, 0xc3, 0xc4, 0x0f, 0x93, 0xa0, 0xc7, 0x7c, 0xa8, 0xaf, 0xea, 0xa2, 0xef, 0x66, - 0xa3, 0xd6, 0xd6, 0xd3, 0x59, 0xe3, 0xd5, 0x3c, 0x25, 0x29, 0x93, 0xe0, 0xef, 0xd1, 0x96, 0x8e, - 0x08, 0xfe, 0x09, 0x4b, 0x59, 0xc4, 0x82, 0x10, 0x44, 0xbd, 0xaa, 0xe7, 0xd7, 0x29, 0xce, 0x4f, - 0xb5, 0x4e, 0x2d, 0x92, 0xf1, 0x3a, 0x3f, 0x86, 0x08, 0x3c, 0xc9, 0xf8, 0x09, 0xf0, 0xd8, 0xfd, - 0xc0, 0xcc, 0x6b, 0xab, 0x3b, 0x4b, 0x45, 0xca, 0xec, 0x8d, 0xcf, 0xd0, 0x9d, 0x99, 0x81, 0xe3, - 0x4d, 0x54, 0xe9, 0xc3, 0xb9, 0x5e, 0xe9, 0x35, 0xa2, 0x7e, 0xe2, 0x6d, 0xb4, 0x3c, 0xa4, 0xd1, - 0x00, 0xf2, 0x0d, 0x24, 0xb9, 0xf0, 0xe9, 0xe2, 0xbe, 0xd5, 0xfe, 0xc3, 0x42, 0x9b, 0xc5, 0xed, - 0x39, 0x0c, 0x85, 0xc4, 0xdf, 0x94, 0x0e, 0xc3, 0x7e, 0xbd, 0xc3, 0x50, 0x68, 0x7d, 0x16, 0x9b, - 0xa6, 0x86, 0xea, 0xb5, 0xa6, 0x70, 0x14, 0x3d, 0xb4, 0x1c, 0x4a, 0x88, 0x45, 0x7d, 0xb1, 0xdc, - 0x98, 0xff, 0x5b, 0x6c, 0x77, 0xc3, 0x90, 0x2e, 0x7f, 0xa1, 0xe0, 0x24, 0x67, 0x69, 0xff, 0xbe, - 0x88, 0x36, 0xf3, 0xe1, 0x74, 0xa5, 0xa4, 0xde, 0x59, 0x0c, 0x89, 0x7c, 0x0b, 0xa7, 0x4d, 0xd0, - 0x92, 0x48, 0xc1, 0xd3, 0x1d, 0x9d, 0x66, 0x2f, 0x15, 0x31, 0x9b, 0xdd, 0x71, 0x0a, 0x9e, 0xbb, - 0x6e, 0xd8, 0x97, 0x94, 0x44, 0x34, 0x17, 0x7e, 0x86, 0x56, 0x84, 0xa4, 0x72, 0xa0, 0x6e, 0x5e, - 0xb1, 0xee, 0xdd, 0x8a, 0x55, 0x23, 0xdd, 0x77, 0x0c, 0xef, 0x4a, 0x2e, 0x13, 0xc3, 0xd8, 0xfe, - 0xd3, 0x42, 0xdb, 0xb3, 0x90, 0xb7, 0x30, 0xec, 0xaf, 0xa6, 0x87, 0x7d, 0xef, 0x36, 0x15, 0xdd, - 0x30, 0xf0, 0xe7, 0xe8, 0xbd, 0x52, 0xed, 0x6c, 0xc0, 0x3d, 0x50, 0xcf, 0x44, 0x3a, 0xf3, 0x18, - 0x3d, 0xa6, 0x31, 0xe4, 0x97, 0x90, 0x3f, 0x13, 0x47, 0x73, 0xec, 0x64, 0x2e, 0xaa, 0xfd, 0xd7, - 0x9c, 0x8e, 0xa9, 0x61, 0xe1, 0x7b, 0xa8, 0x4a, 0xb5, 0x06, 0xb8, 0xa1, 0x1e, 0x77, 0xa0, 0x6b, - 0xf4, 0x64, 0xec, 0xa1, 0x87, 0xaa, 0xd3, 0x33, 0xab, 0x72, 0xbb, 0xa1, 0x6a, 0x64, 0x61, 0xa8, - 0x5a, 0x26, 0x86, 0x51, 0x65, 0x92, 0x30, 0x3f, 0x2f, 0xb2, 0x32, 0x9d, 0xc9, 0x63, 0xa3, 0x27, - 0x63, 0x8f, 0xf6, 0xbf, 0x95, 0x39, 0x9d, 0xd3, 0xdb, 0x51, 0x28, 0xc9, 0xd7, 0x25, 0x55, 0x4b, - 0x25, 0xf9, 0xe3, 0x92, 0x7c, 0xfc, 0x9b, 0x85, 0x30, 0x1d, 0x53, 0xf4, 0xae, 0xb7, 0x27, 0x1f, - 0xf1, 0x97, 0xb7, 0x5f, 0x5a, 0xbb, 0x5b, 0x22, 0xcb, 0x3f, 0x5d, 0x0d, 0x93, 0x04, 0x2e, 0x3b, - 0x90, 0x39, 0x19, 0xe0, 0x10, 0xd5, 0x72, 0xed, 0x01, 0xe7, 0x8c, 0x9b, 0x2b, 0xfa, 0xf0, 0xd5, - 0x09, 0x69, 0x77, 0xb7, 0xa9, 0x3e, 0xca, 0xdd, 0x09, 0xfe, 0x6a, 0xd4, 0xaa, 0x15, 0xec, 0xa4, - 0xc8, 0xad, 0x42, 0xf9, 0x30, 0x09, 0xb5, 0xf4, 0x06, 0xa1, 0x3e, 0x87, 0x9b, 0x43, 0x15, 0xb8, - 0x1b, 0x07, 0xe8, 0xfd, 0x1b, 0x1a, 0x74, 0xab, 0xa7, 0xfe, 0x67, 0x0b, 0x15, 0x63, 0xe0, 0x43, - 0xb4, 0xa4, 0xfe, 0x2e, 0x99, 0xa3, 0xbf, 0xfb, 0x7a, 0x47, 0x7f, 0x12, 0xc6, 0x30, 0x79, 0xbb, - 0x94, 0x44, 0x34, 0x0b, 0xfe, 0x08, 0xad, 0xc6, 0x20, 0x04, 0x0d, 0x4c, 0x64, 0xf7, 0x8e, 0x71, - 0x5a, 0xed, 0xe5, 0x6a, 0x72, 0x6d, 0x77, 0xef, 0x5f, 0x5c, 0x36, 0x17, 0x5e, 0x5c, 0x36, 0x17, - 0x5e, 0x5e, 0x36, 0x17, 0x7e, 0xca, 0x9a, 0xd6, 0x45, 0xd6, 0xb4, 0x5e, 0x64, 0x4d, 0xeb, 0x65, - 0xd6, 0xb4, 0xfe, 0xce, 0x9a, 0xd6, 0x2f, 0xff, 0x34, 0x17, 0x9e, 0xad, 0x9a, 0xbe, 0xfd, 0x17, - 0x00, 0x00, 0xff, 0xff, 0xb4, 0x63, 0x7e, 0xa7, 0x0b, 0x0b, 0x00, 0x00, + // 1216 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xc6, 0x4e, 0x9c, 0x8c, 0x93, 0x36, 0x59, 0x22, 0x30, 0x3e, 0xd8, 0x91, 0x11, 0x34, + 0xad, 0xda, 0x75, 0x1b, 0x15, 0x14, 0x55, 0xe2, 0x60, 0x27, 0x91, 0x70, 0x1b, 0x27, 0x66, 0x12, + 0x55, 0xa8, 0xe2, 0xc0, 0x64, 0xf7, 0xc5, 0x59, 0xec, 0xdd, 0xd9, 0xce, 0x8e, 0x0d, 0xbe, 0x71, + 0x82, 0x23, 0x88, 0x03, 0x9f, 0x80, 0xaf, 0x00, 0x12, 0x5c, 0x38, 0x92, 0x13, 0xea, 0xb1, 0x27, + 0x8b, 0x98, 0x6f, 0x11, 0x71, 0x40, 0x33, 0x3b, 0xf6, 0xee, 0xfa, 0x4f, 0xe3, 0x70, 0xf0, 0xcd, + 0xf3, 0xde, 0xfb, 0xfd, 0xde, 0xdf, 0x79, 0xb3, 0x46, 0xbb, 0x8d, 0x1d, 0xdf, 0xb0, 0x69, 0xb1, + 0xd1, 0x3a, 0x05, 0xe6, 0x02, 0x07, 0xbf, 0xd8, 0x06, 0xd7, 0xa2, 0xac, 0xa8, 0x14, 0xc4, 0xb3, + 0x8b, 0x3e, 0xa7, 0x8c, 0xd4, 0xa1, 0xd8, 0x7e, 0x74, 0x0a, 0x9c, 0x3c, 0x2a, 0xd6, 0xc1, 0x05, + 0x46, 0x38, 0x58, 0x86, 0xc7, 0x28, 0xa7, 0x7a, 0x36, 0xb0, 0x35, 0x88, 0x67, 0x1b, 0xca, 0xd6, + 0x50, 0xb6, 0xd9, 0x07, 0x75, 0x9b, 0x9f, 0xb7, 0x4e, 0x0d, 0x93, 0x3a, 0xc5, 0x3a, 0xad, 0xd3, + 0xa2, 0x84, 0x9c, 0xb6, 0xce, 0xe4, 0x49, 0x1e, 0xe4, 0xaf, 0x80, 0x2a, 0x5b, 0x88, 0xb8, 0x35, + 0x29, 0x13, 0x3e, 0x87, 0xdd, 0x65, 0x1f, 0x87, 0x36, 0x0e, 0x31, 0xcf, 0x6d, 0x17, 0x58, 0xa7, + 0xe8, 0x35, 0xea, 0x42, 0xe0, 0x17, 0x1d, 0xe0, 0x64, 0x1c, 0xaa, 0x38, 0x09, 0xc5, 0x5a, 0x2e, + 0xb7, 0x1d, 0x18, 0x01, 0x7c, 0x74, 0x1d, 0xc0, 0x37, 0xcf, 0xc1, 0x21, 0xc3, 0xb8, 0xc2, 0xef, + 0x1a, 0x5a, 0xde, 0x3d, 0xae, 0xec, 0x31, 0xbb, 0x0d, 0x4c, 0xff, 0x02, 0x2d, 0x89, 0x88, 0x2c, + 0xc2, 0x49, 0x46, 0xdb, 0xd4, 0xb6, 0xd2, 0xdb, 0x0f, 0x8d, 0xb0, 0x5c, 0x03, 0x62, 0xc3, 0x6b, + 0xd4, 0x85, 0xc0, 0x37, 0x84, 0xb5, 0xd1, 0x7e, 0x64, 0x1c, 0x9d, 0x7e, 0x09, 0x26, 0xaf, 0x02, + 0x27, 0x65, 0xfd, 0xa2, 0x9b, 0x9f, 0xeb, 0x75, 0xf3, 0x28, 0x94, 0xe1, 0x01, 0xab, 0xfe, 0x0c, + 0x25, 0x7d, 0x0f, 0xcc, 0xcc, 0xbc, 0x64, 0xbf, 0x6b, 0x4c, 0x6e, 0x86, 0x31, 0x08, 0xeb, 0xd8, + 0x03, 0xb3, 0xbc, 0xa2, 0x68, 0x93, 0xe2, 0x84, 0x25, 0x49, 0xe1, 0x37, 0x0d, 0xad, 0x0e, 0xac, + 0x0e, 0x6c, 0x9f, 0xeb, 0x9f, 0x8f, 0x24, 0x60, 0x4c, 0x97, 0x80, 0x40, 0xcb, 0xf0, 0xd7, 0x94, + 0x9f, 0xa5, 0xbe, 0x24, 0x12, 0xfc, 0x53, 0xb4, 0x60, 0x73, 0x70, 0xfc, 0xcc, 0xfc, 0x66, 0x62, + 0x2b, 0xbd, 0xfd, 0xfe, 0x54, 0xd1, 0x97, 0x57, 0x15, 0xe3, 0x42, 0x45, 0x60, 0x71, 0x40, 0x51, + 0xf8, 0x2e, 0x1a, 0xbb, 0xc8, 0x49, 0x7f, 0x82, 0x6e, 0x11, 0xce, 0x89, 0x79, 0x8e, 0xe1, 0x65, + 0xcb, 0x66, 0x60, 0xc9, 0x0c, 0x96, 0xca, 0x7a, 0xaf, 0x9b, 0xbf, 0x55, 0x8a, 0x69, 0xf0, 0x90, + 0xa5, 0xc0, 0x7a, 0xd4, 0xaa, 0xb8, 0x67, 0xf4, 0xc8, 0xad, 0xd2, 0x96, 0xcb, 0x65, 0x81, 0x15, + 0xb6, 0x16, 0xd3, 0xe0, 0x21, 0xcb, 0xc2, 0xaf, 0x1a, 0x4a, 0xed, 0x1e, 0x57, 0x0e, 0xa9, 0x05, + 0x33, 0x18, 0x80, 0x4a, 0x6c, 0x00, 0xee, 0x5c, 0x53, 0x42, 0x11, 0xd4, 0xc4, 0xf6, 0x7f, 0x1f, + 0x94, 0x50, 0xd8, 0xa8, 0xf9, 0xdd, 0x44, 0x49, 0x97, 0x38, 0x20, 0x43, 0x5f, 0x0e, 0x31, 0x87, + 0xc4, 0x01, 0x2c, 0x35, 0xfa, 0x07, 0x68, 0xd1, 0xa5, 0x16, 0x54, 0xf6, 0x64, 0x00, 0xcb, 0xe5, + 0x5b, 0xca, 0x66, 0xf1, 0x50, 0x4a, 0xb1, 0xd2, 0xea, 0x8f, 0xd1, 0x0a, 0xa7, 0x1e, 0x6d, 0xd2, + 0x7a, 0xe7, 0x19, 0x74, 0xfc, 0x4c, 0x62, 0x33, 0xb1, 0xb5, 0x5c, 0x5e, 0xeb, 0x75, 0xf3, 0x2b, + 0x27, 0x11, 0x39, 0x8e, 0x59, 0x15, 0x7e, 0xd1, 0x50, 0x5a, 0x45, 0x34, 0x83, 0x71, 0xfc, 0x24, + 0x3e, 0x8e, 0xef, 0x4d, 0x51, 0xcb, 0x09, 0xc3, 0x68, 0x0e, 0xc2, 0x96, 0x93, 0x78, 0x82, 0x52, + 0x96, 0x2c, 0xa8, 0x9f, 0xd1, 0x24, 0xf5, 0xdd, 0x29, 0xa8, 0xd5, 0xb4, 0xdf, 0x56, 0x0e, 0x52, + 0xc1, 0xd9, 0xc7, 0x7d, 0xaa, 0xc2, 0x8f, 0x8b, 0x68, 0xe5, 0x38, 0xc0, 0xee, 0x36, 0x89, 0xef, + 0xcf, 0x60, 0xd8, 0x3e, 0x44, 0x69, 0x8f, 0xd1, 0xb6, 0xed, 0xdb, 0xd4, 0x05, 0xa6, 0x5a, 0xfe, + 0x96, 0x82, 0xa4, 0x6b, 0xa1, 0x0a, 0x47, 0xed, 0xf4, 0x26, 0x42, 0x1e, 0x61, 0xc4, 0x01, 0x2e, + 0x4a, 0x90, 0x90, 0x25, 0xd8, 0x79, 0x53, 0x09, 0xa2, 0x69, 0x19, 0xb5, 0x01, 0x74, 0xdf, 0xe5, + 0xac, 0x13, 0x86, 0x18, 0x2a, 0x70, 0x84, 0x5f, 0x6f, 0xa0, 0x55, 0x06, 0x66, 0x93, 0xd8, 0x4e, + 0x8d, 0x36, 0x6d, 0xb3, 0x93, 0x49, 0xca, 0x30, 0xf7, 0x7b, 0xdd, 0xfc, 0x2a, 0x8e, 0x2a, 0xae, + 0xba, 0xf9, 0x87, 0xa3, 0x2f, 0x8e, 0x51, 0x03, 0xe6, 0xdb, 0x3e, 0x07, 0x97, 0x3f, 0xa7, 0xcd, + 0x96, 0x03, 0x31, 0x0c, 0x8e, 0x73, 0x8b, 0xb9, 0x76, 0xc4, 0xad, 0x3f, 0xf2, 0xb8, 0x4d, 0x5d, + 0x3f, 0xb3, 0x10, 0xce, 0x75, 0x35, 0x22, 0xc7, 0x31, 0x2b, 0xfd, 0x00, 0x6d, 0x90, 0x66, 0x93, + 0x7e, 0x15, 0x38, 0xd8, 0xff, 0xda, 0x23, 0xae, 0x28, 0x55, 0x66, 0x51, 0x2e, 0x99, 0x4c, 0xaf, + 0x9b, 0xdf, 0x28, 0x8d, 0xd1, 0xe3, 0xb1, 0x28, 0xfd, 0x33, 0xb4, 0xde, 0x96, 0xa2, 0xb2, 0xed, + 0x5a, 0xb6, 0x5b, 0xaf, 0x52, 0x0b, 0x32, 0x29, 0x99, 0xf4, 0xbd, 0x5e, 0x37, 0xbf, 0xfe, 0x7c, + 0x58, 0x79, 0x35, 0x4e, 0x88, 0x47, 0x49, 0xf4, 0x97, 0x68, 0x5d, 0x7a, 0x04, 0x4b, 0x5d, 0x52, + 0x1b, 0xfc, 0xcc, 0x92, 0xec, 0xdf, 0x56, 0xb4, 0x7f, 0xa2, 0x74, 0x62, 0x90, 0xfa, 0x57, 0xf9, + 0x18, 0x9a, 0x60, 0x72, 0xca, 0x4e, 0x80, 0x39, 0xe5, 0x77, 0x55, 0xbf, 0xd6, 0x4b, 0xc3, 0x54, + 0x78, 0x94, 0x3d, 0xfb, 0x31, 0xba, 0x3d, 0xd4, 0x70, 0x7d, 0x0d, 0x25, 0x1a, 0xd0, 0x09, 0x96, + 0x10, 0x16, 0x3f, 0xf5, 0x0d, 0xb4, 0xd0, 0x26, 0xcd, 0x16, 0x04, 0x13, 0x88, 0x83, 0xc3, 0x93, + 0xf9, 0x1d, 0xad, 0xf0, 0x87, 0x86, 0xd6, 0xa2, 0xd3, 0x33, 0x83, 0xb5, 0x51, 0x8d, 0xaf, 0x8d, + 0xad, 0x69, 0x07, 0x7b, 0xc2, 0xee, 0xf8, 0x79, 0x1e, 0xad, 0x05, 0xcd, 0x09, 0xde, 0x28, 0x07, + 0x5c, 0x3e, 0x83, 0xab, 0x8d, 0x63, 0xef, 0xc8, 0xc3, 0x37, 0x25, 0x31, 0x1c, 0xdd, 0xa4, 0x07, + 0x45, 0x7f, 0x81, 0x16, 0x7d, 0x4e, 0x78, 0x4b, 0xdc, 0x79, 0xc1, 0xba, 0x7d, 0x23, 0x56, 0x89, + 0x0c, 0x1f, 0x94, 0xe0, 0x8c, 0x15, 0x63, 0xe1, 0x4f, 0x0d, 0x6d, 0x0c, 0x43, 0x66, 0xd0, 0xec, + 0x4f, 0xe3, 0xcd, 0xbe, 0x7f, 0x93, 0x8c, 0x26, 0x34, 0xfc, 0x0c, 0xbd, 0x3d, 0x92, 0x3b, 0x6d, + 0x31, 0x13, 0xc4, 0x9a, 0xf0, 0x86, 0x96, 0xd1, 0x61, 0xf8, 0x1c, 0xcb, 0x35, 0x51, 0x1b, 0xa3, + 0xc7, 0x63, 0x51, 0x85, 0xbf, 0xc6, 0x54, 0x4c, 0x3e, 0x4f, 0xf7, 0xd1, 0x52, 0xf0, 0xf9, 0x03, + 0x4c, 0x51, 0x0f, 0x2a, 0x50, 0x52, 0x72, 0x3c, 0xb0, 0x90, 0x4d, 0x95, 0xe1, 0xa9, 0x51, 0xb9, + 0x59, 0x53, 0x25, 0x32, 0xd2, 0x54, 0x79, 0xc6, 0x8a, 0x51, 0x44, 0x22, 0xbe, 0x17, 0x64, 0x92, + 0x89, 0x78, 0x24, 0x87, 0x4a, 0x8e, 0x07, 0x16, 0x85, 0x7f, 0x13, 0x63, 0x2a, 0x27, 0xa7, 0x23, + 0x92, 0x52, 0xff, 0xab, 0x6f, 0x38, 0x25, 0x6b, 0x90, 0x92, 0xa5, 0xff, 0xa4, 0x21, 0x9d, 0x0c, + 0x28, 0xaa, 0xfd, 0xe9, 0x09, 0x5a, 0xfc, 0xf4, 0xe6, 0x43, 0x6b, 0x94, 0x46, 0xc8, 0x82, 0xa7, + 0x2b, 0xab, 0x82, 0xd0, 0x47, 0x0d, 0xf0, 0x98, 0x08, 0x74, 0x1b, 0xa5, 0x03, 0xe9, 0x3e, 0x63, + 0x94, 0xa9, 0x5b, 0x74, 0xe7, 0xfa, 0x80, 0xa4, 0x79, 0x39, 0x27, 0x1e, 0xe5, 0x52, 0x88, 0xbf, + 0xea, 0xe6, 0xd3, 0x11, 0x3d, 0x8e, 0x72, 0x0b, 0x57, 0x16, 0x84, 0xae, 0x92, 0xff, 0xc3, 0xd5, + 0x1e, 0x4c, 0x76, 0x15, 0xe1, 0xce, 0xee, 0xa3, 0x77, 0x26, 0x14, 0xe8, 0x46, 0xab, 0xfe, 0x5b, + 0x0d, 0x45, 0x7d, 0xe8, 0x07, 0x28, 0x29, 0xfe, 0x99, 0xa9, 0x4b, 0x7f, 0x6f, 0xba, 0x4b, 0x7f, + 0x62, 0x3b, 0x10, 0xee, 0x2e, 0x71, 0xc2, 0x92, 0x45, 0xbf, 0x8b, 0x52, 0x0e, 0xf8, 0x3e, 0xa9, + 0x2b, 0xcf, 0xe1, 0x87, 0x58, 0x35, 0x10, 0xe3, 0xbe, 0xbe, 0xfc, 0xe0, 0xe2, 0x32, 0x37, 0xf7, + 0xea, 0x32, 0x37, 0xf7, 0xfa, 0x32, 0x37, 0xf7, 0x4d, 0x2f, 0xa7, 0x5d, 0xf4, 0x72, 0xda, 0xab, + 0x5e, 0x4e, 0x7b, 0xdd, 0xcb, 0x69, 0x7f, 0xf7, 0x72, 0xda, 0x0f, 0xff, 0xe4, 0xe6, 0x5e, 0xa4, + 0x54, 0xdd, 0xfe, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x78, 0xdc, 0x5e, 0x79, 0x76, 0x0f, 0x00, 0x00, } diff --git a/staging/src/k8s.io/api/storage/v1beta1/generated.proto b/staging/src/k8s.io/api/storage/v1beta1/generated.proto index 4efe7d7fea..6d9fe90499 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/storage/v1beta1/generated.proto @@ -29,6 +29,143 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v1beta1"; +// CSIDriver captures information about a Container Storage Interface (CSI) +// volume driver deployed on the cluster. +// CSI drivers do not need to create the CSIDriver object directly. Instead they may use the +// cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically +// creates a CSIDriver object representing the driver. +// Kubernetes attach detach controller uses this object to determine whether attach is required. +// Kubelet uses this object to determine whether pod information needs to be passed on mount. +// CSIDriver objects are non-namespaced. +message CSIDriver { + // Standard object metadata. + // metadata.Name indicates the name of the CSI driver that this object + // refers to; it MUST be the same name returned by the CSI GetPluginName() + // call for that driver. + // The driver name must be 63 characters or less, beginning and ending with + // an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and + // alphanumerics between. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // Specification of the CSI Driver. + optional CSIDriverSpec spec = 2; +} + +// CSIDriverList is a collection of CSIDriver objects. +message CSIDriverList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of CSIDriver + repeated CSIDriver items = 2; +} + +// CSIDriverSpec is the specification of a CSIDriver. +message CSIDriverSpec { + // attachRequired indicates this CSI volume driver requires an attach + // operation (because it implements the CSI ControllerPublishVolume() + // method), and that the Kubernetes attach detach controller should call + // the attach volume interface which checks the volumeattachment status + // and waits until the volume is attached before proceeding to mounting. + // The CSI external-attacher coordinates with CSI volume driver and updates + // the volumeattachment status when the attach operation is complete. + // If the CSIDriverRegistry feature gate is enabled and the value is + // specified to false, the attach operation will be skipped. + // Otherwise the attach operation will be called. + // +optional + optional bool attachRequired = 1; + + // If set to true, podInfoOnMount indicates this CSI volume driver + // requires additional pod information (like podName, podUID, etc.) during + // mount operations. + // If set to false, pod information will not be passed on mount. + // Default is false. + // The CSI driver specifies podInfoOnMount as part of driver deployment. + // If true, Kubelet will pass pod information as VolumeContext in the CSI + // NodePublishVolume() calls. + // The CSI driver is responsible for parsing and validating the information + // passed in as VolumeContext. + // The following VolumeConext will be passed if podInfoOnMount is set to true. + // This list might grow, but the prefix will be used. + // "csi.storage.k8s.io/pod.name": pod.Name + // "csi.storage.k8s.io/pod.namespace": pod.Namespace + // "csi.storage.k8s.io/pod.uid": string(pod.UID) + // +optional + optional bool podInfoOnMount = 2; +} + +// CSINode holds information about all CSI drivers installed on a node. +// CSI drivers do not need to create the CSINode object directly. As long as +// they use the node-driver-registrar sidecar container, the kubelet will +// automatically populate the CSINode object for the CSI driver as part of +// kubelet plugin registration. +// CSINode has the same name as a node. If the object is missing, it means either +// there are no CSI Drivers available on the node, or the Kubelet version is low +// enough that it doesn't create this object. +// CSINode has an OwnerReference that points to the corresponding node object. +message CSINode { + // metadata.name must be the Kubernetes node name. + optional k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta metadata = 1; + + // spec is the specification of CSINode + optional CSINodeSpec spec = 2; +} + +// CSINodeDriver holds information about the specification of one CSI driver installed on a node +message CSINodeDriver { + // This is the name of the CSI driver that this object refers to. + // This MUST be the same name returned by the CSI GetPluginName() call for + // that driver. + optional string name = 1; + + // nodeID of the node from the driver point of view. + // This field enables Kubernetes to communicate with storage systems that do + // not share the same nomenclature for nodes. For example, Kubernetes may + // refer to a given node as "node1", but the storage system may refer to + // the same node as "nodeA". When Kubernetes issues a command to the storage + // system to attach a volume to a specific node, it can use this field to + // refer to the node name using the ID that the storage system will + // understand, e.g. "nodeA" instead of "node1". This field is required. + optional string nodeID = 2; + + // topologyKeys is the list of keys supported by the driver. + // When a driver is initialized on a cluster, it provides a set of topology + // keys that it understands (e.g. "company.com/zone", "company.com/region"). + // When a driver is initialized on a node, it provides the same topology keys + // along with values. Kubelet will expose these topology keys as labels + // on its own node object. + // When Kubernetes does topology aware provisioning, it can use this list to + // determine which labels it should retrieve from the node object and pass + // back to the driver. + // It is possible for different nodes to use different topology keys. + // This can be empty if driver does not support topology. + // +optional + repeated string topologyKeys = 3; +} + +// CSINodeList is a collection of CSINode objects. +message CSINodeList { + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // items is the list of CSINode + repeated CSINode items = 2; +} + +// CSINodeSpec holds information about the specification of all CSI drivers installed on a node +message CSINodeSpec { + // drivers is a list of information of all CSI Drivers existing on a node. + // If all drivers in the list are uninstalled, this can become empty. + // +patchMergeKey=name + // +patchStrategy=merge + repeated CSINodeDriver drivers = 1; +} + // StorageClass describes the parameters for a class of storage for // which PersistentVolumes can be dynamically provisioned. // diff --git a/staging/src/k8s.io/api/storage/v1beta1/register.go b/staging/src/k8s.io/api/storage/v1beta1/register.go index 06b0f3d529..c270ace57d 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/register.go +++ b/staging/src/k8s.io/api/storage/v1beta1/register.go @@ -49,6 +49,12 @@ func addKnownTypes(scheme *runtime.Scheme) error { &VolumeAttachment{}, &VolumeAttachmentList{}, + + &CSIDriver{}, + &CSIDriverList{}, + + &CSINode{}, + &CSINodeList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) diff --git a/staging/src/k8s.io/api/storage/v1beta1/types.go b/staging/src/k8s.io/api/storage/v1beta1/types.go index a955542256..4900579120 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/types.go +++ b/staging/src/k8s.io/api/storage/v1beta1/types.go @@ -209,3 +209,160 @@ type VolumeError struct { // +optional Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"` } + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSIDriver captures information about a Container Storage Interface (CSI) +// volume driver deployed on the cluster. +// CSI drivers do not need to create the CSIDriver object directly. Instead they may use the +// cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically +// creates a CSIDriver object representing the driver. +// Kubernetes attach detach controller uses this object to determine whether attach is required. +// Kubelet uses this object to determine whether pod information needs to be passed on mount. +// CSIDriver objects are non-namespaced. +type CSIDriver struct { + metav1.TypeMeta `json:",inline"` + + // Standard object metadata. + // metadata.Name indicates the name of the CSI driver that this object + // refers to; it MUST be the same name returned by the CSI GetPluginName() + // call for that driver. + // The driver name must be 63 characters or less, beginning and ending with + // an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and + // alphanumerics between. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Specification of the CSI Driver. + Spec CSIDriverSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSIDriverList is a collection of CSIDriver objects. +type CSIDriverList struct { + metav1.TypeMeta `json:",inline"` + + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // items is the list of CSIDriver + Items []CSIDriver `json:"items" protobuf:"bytes,2,rep,name=items"` +} + +// CSIDriverSpec is the specification of a CSIDriver. +type CSIDriverSpec struct { + // attachRequired indicates this CSI volume driver requires an attach + // operation (because it implements the CSI ControllerPublishVolume() + // method), and that the Kubernetes attach detach controller should call + // the attach volume interface which checks the volumeattachment status + // and waits until the volume is attached before proceeding to mounting. + // The CSI external-attacher coordinates with CSI volume driver and updates + // the volumeattachment status when the attach operation is complete. + // If the CSIDriverRegistry feature gate is enabled and the value is + // specified to false, the attach operation will be skipped. + // Otherwise the attach operation will be called. + // +optional + AttachRequired *bool `json:"attachRequired,omitempty" protobuf:"varint,1,opt,name=attachRequired"` + + // If set to true, podInfoOnMount indicates this CSI volume driver + // requires additional pod information (like podName, podUID, etc.) during + // mount operations. + // If set to false, pod information will not be passed on mount. + // Default is false. + // The CSI driver specifies podInfoOnMount as part of driver deployment. + // If true, Kubelet will pass pod information as VolumeContext in the CSI + // NodePublishVolume() calls. + // The CSI driver is responsible for parsing and validating the information + // passed in as VolumeContext. + // The following VolumeConext will be passed if podInfoOnMount is set to true. + // This list might grow, but the prefix will be used. + // "csi.storage.k8s.io/pod.name": pod.Name + // "csi.storage.k8s.io/pod.namespace": pod.Namespace + // "csi.storage.k8s.io/pod.uid": string(pod.UID) + // +optional + PodInfoOnMount *bool `json:"podInfoOnMount,omitempty" protobuf:"bytes,2,opt,name=podInfoOnMount"` +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSINode holds information about all CSI drivers installed on a node. +// CSI drivers do not need to create the CSINode object directly. As long as +// they use the node-driver-registrar sidecar container, the kubelet will +// automatically populate the CSINode object for the CSI driver as part of +// kubelet plugin registration. +// CSINode has the same name as a node. If the object is missing, it means either +// there are no CSI Drivers available on the node, or the Kubelet version is low +// enough that it doesn't create this object. +// CSINode has an OwnerReference that points to the corresponding node object. +type CSINode struct { + metav1.TypeMeta `json:",inline"` + + // metadata.name must be the Kubernetes node name. + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // spec is the specification of CSINode + Spec CSINodeSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"` +} + +// CSINodeSpec holds information about the specification of all CSI drivers installed on a node +type CSINodeSpec struct { + // drivers is a list of information of all CSI Drivers existing on a node. + // If all drivers in the list are uninstalled, this can become empty. + // +patchMergeKey=name + // +patchStrategy=merge + Drivers []CSINodeDriver `json:"drivers" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,1,rep,name=drivers"` +} + +// CSINodeDriver holds information about the specification of one CSI driver installed on a node +type CSINodeDriver struct { + // This is the name of the CSI driver that this object refers to. + // This MUST be the same name returned by the CSI GetPluginName() call for + // that driver. + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` + + // nodeID of the node from the driver point of view. + // This field enables Kubernetes to communicate with storage systems that do + // not share the same nomenclature for nodes. For example, Kubernetes may + // refer to a given node as "node1", but the storage system may refer to + // the same node as "nodeA". When Kubernetes issues a command to the storage + // system to attach a volume to a specific node, it can use this field to + // refer to the node name using the ID that the storage system will + // understand, e.g. "nodeA" instead of "node1". This field is required. + NodeID string `json:"nodeID" protobuf:"bytes,2,opt,name=nodeID"` + + // topologyKeys is the list of keys supported by the driver. + // When a driver is initialized on a cluster, it provides a set of topology + // keys that it understands (e.g. "company.com/zone", "company.com/region"). + // When a driver is initialized on a node, it provides the same topology keys + // along with values. Kubelet will expose these topology keys as labels + // on its own node object. + // When Kubernetes does topology aware provisioning, it can use this list to + // determine which labels it should retrieve from the node object and pass + // back to the driver. + // It is possible for different nodes to use different topology keys. + // This can be empty if driver does not support topology. + // +optional + TopologyKeys []string `json:"topologyKeys" protobuf:"bytes,3,rep,name=topologyKeys"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CSINodeList is a collection of CSINode objects. +type CSINodeList struct { + metav1.TypeMeta `json:",inline"` + + // Standard list metadata + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // items is the list of CSINode + Items []CSINode `json:"items" protobuf:"bytes,2,rep,name=items"` +} diff --git a/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go index e41197bd37..ec741ecf70 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/storage/v1beta1/types_swagger_doc_generated.go @@ -27,6 +27,76 @@ package v1beta1 // Those methods can be generated by using hack/update-generated-swagger-docs.sh // AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT. +var map_CSIDriver = map[string]string{ + "": "CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. CSI drivers do not need to create the CSIDriver object directly. Instead they may use the cluster-driver-registrar sidecar container. When deployed with a CSI driver it automatically creates a CSIDriver object representing the driver. Kubernetes attach detach controller uses this object to determine whether attach is required. Kubelet uses this object to determine whether pod information needs to be passed on mount. CSIDriver objects are non-namespaced.", + "metadata": "Standard object metadata. metadata.Name indicates the name of the CSI driver that this object refers to; it MUST be the same name returned by the CSI GetPluginName() call for that driver. The driver name must be 63 characters or less, beginning and ending with an alphanumeric character ([a-z0-9A-Z]) with dashes (-), dots (.), and alphanumerics between. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "spec": "Specification of the CSI Driver.", +} + +func (CSIDriver) SwaggerDoc() map[string]string { + return map_CSIDriver +} + +var map_CSIDriverList = map[string]string{ + "": "CSIDriverList is a collection of CSIDriver objects.", + "metadata": "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "items": "items is the list of CSIDriver", +} + +func (CSIDriverList) SwaggerDoc() map[string]string { + return map_CSIDriverList +} + +var map_CSIDriverSpec = map[string]string{ + "": "CSIDriverSpec is the specification of a CSIDriver.", + "attachRequired": "attachRequired indicates this CSI volume driver requires an attach operation (because it implements the CSI ControllerPublishVolume() method), and that the Kubernetes attach detach controller should call the attach volume interface which checks the volumeattachment status and waits until the volume is attached before proceeding to mounting. The CSI external-attacher coordinates with CSI volume driver and updates the volumeattachment status when the attach operation is complete. If the CSIDriverRegistry feature gate is enabled and the value is specified to false, the attach operation will be skipped. Otherwise the attach operation will be called.", + "podInfoOnMount": "If set to true, podInfoOnMount indicates this CSI volume driver requires additional pod information (like podName, podUID, etc.) during mount operations. If set to false, pod information will not be passed on mount. Default is false. The CSI driver specifies podInfoOnMount as part of driver deployment. If true, Kubelet will pass pod information as VolumeContext in the CSI NodePublishVolume() calls. The CSI driver is responsible for parsing and validating the information passed in as VolumeContext. The following VolumeConext will be passed if podInfoOnMount is set to true. This list might grow, but the prefix will be used. \"csi.storage.k8s.io/pod.name\": pod.Name \"csi.storage.k8s.io/pod.namespace\": pod.Namespace \"csi.storage.k8s.io/pod.uid\": string(pod.UID)", +} + +func (CSIDriverSpec) SwaggerDoc() map[string]string { + return map_CSIDriverSpec +} + +var map_CSINode = map[string]string{ + "": "CSINode holds information about all CSI drivers installed on a node. CSI drivers do not need to create the CSINode object directly. As long as they use the node-driver-registrar sidecar container, the kubelet will automatically populate the CSINode object for the CSI driver as part of kubelet plugin registration. CSINode has the same name as a node. If the object is missing, it means either there are no CSI Drivers available on the node, or the Kubelet version is low enough that it doesn't create this object. CSINode has an OwnerReference that points to the corresponding node object.", + "metadata": "metadata.name must be the Kubernetes node name.", + "spec": "spec is the specification of CSINode", +} + +func (CSINode) SwaggerDoc() map[string]string { + return map_CSINode +} + +var map_CSINodeDriver = map[string]string{ + "": "CSINodeDriver holds information about the specification of one CSI driver installed on a node", + "name": "This is the name of the CSI driver that this object refers to. This MUST be the same name returned by the CSI GetPluginName() call for that driver.", + "nodeID": "nodeID of the node from the driver point of view. This field enables Kubernetes to communicate with storage systems that do not share the same nomenclature for nodes. For example, Kubernetes may refer to a given node as \"node1\", but the storage system may refer to the same node as \"nodeA\". When Kubernetes issues a command to the storage system to attach a volume to a specific node, it can use this field to refer to the node name using the ID that the storage system will understand, e.g. \"nodeA\" instead of \"node1\". This field is required.", + "topologyKeys": "topologyKeys is the list of keys supported by the driver. When a driver is initialized on a cluster, it provides a set of topology keys that it understands (e.g. \"company.com/zone\", \"company.com/region\"). When a driver is initialized on a node, it provides the same topology keys along with values. Kubelet will expose these topology keys as labels on its own node object. When Kubernetes does topology aware provisioning, it can use this list to determine which labels it should retrieve from the node object and pass back to the driver. It is possible for different nodes to use different topology keys. This can be empty if driver does not support topology.", +} + +func (CSINodeDriver) SwaggerDoc() map[string]string { + return map_CSINodeDriver +} + +var map_CSINodeList = map[string]string{ + "": "CSINodeList is a collection of CSINode objects.", + "metadata": "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", + "items": "items is the list of CSINode", +} + +func (CSINodeList) SwaggerDoc() map[string]string { + return map_CSINodeList +} + +var map_CSINodeSpec = map[string]string{ + "": "CSINodeSpec holds information about the specification of all CSI drivers installed on a node", + "drivers": "drivers is a list of information of all CSI Drivers existing on a node. If all drivers in the list are uninstalled, this can become empty.", +} + +func (CSINodeSpec) SwaggerDoc() map[string]string { + return map_CSINodeSpec +} + var map_StorageClass = map[string]string{ "": "StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned.\n\nStorageClasses are non-namespaced; the name of the storage class according to etcd is in ObjectMeta.Name.", "metadata": "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata", diff --git a/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go index 8096dba9be..022815f183 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/storage/v1beta1/zz_generated.deepcopy.go @@ -25,6 +25,196 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIDriver) DeepCopyInto(out *CSIDriver) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriver. +func (in *CSIDriver) DeepCopy() *CSIDriver { + if in == nil { + return nil + } + out := new(CSIDriver) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSIDriver) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIDriverList) DeepCopyInto(out *CSIDriverList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CSIDriver, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverList. +func (in *CSIDriverList) DeepCopy() *CSIDriverList { + if in == nil { + return nil + } + out := new(CSIDriverList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSIDriverList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSIDriverSpec) DeepCopyInto(out *CSIDriverSpec) { + *out = *in + if in.AttachRequired != nil { + in, out := &in.AttachRequired, &out.AttachRequired + *out = new(bool) + **out = **in + } + if in.PodInfoOnMount != nil { + in, out := &in.PodInfoOnMount, &out.PodInfoOnMount + *out = new(bool) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIDriverSpec. +func (in *CSIDriverSpec) DeepCopy() *CSIDriverSpec { + if in == nil { + return nil + } + out := new(CSIDriverSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINode) DeepCopyInto(out *CSINode) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINode. +func (in *CSINode) DeepCopy() *CSINode { + if in == nil { + return nil + } + out := new(CSINode) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSINode) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINodeDriver) DeepCopyInto(out *CSINodeDriver) { + *out = *in + if in.TopologyKeys != nil { + in, out := &in.TopologyKeys, &out.TopologyKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeDriver. +func (in *CSINodeDriver) DeepCopy() *CSINodeDriver { + if in == nil { + return nil + } + out := new(CSINodeDriver) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINodeList) DeepCopyInto(out *CSINodeList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CSINode, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeList. +func (in *CSINodeList) DeepCopy() *CSINodeList { + if in == nil { + return nil + } + out := new(CSINodeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CSINodeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CSINodeSpec) DeepCopyInto(out *CSINodeSpec) { + *out = *in + if in.Drivers != nil { + in, out := &in.Drivers, &out.Drivers + *out = make([]CSINodeDriver, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSINodeSpec. +func (in *CSINodeSpec) DeepCopy() *CSINodeSpec { + if in == nil { + return nil + } + out := new(CSINodeSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StorageClass) DeepCopyInto(out *StorageClass) { *out = *in diff --git a/staging/src/k8s.io/client-go/informers/generic.go b/staging/src/k8s.io/client-go/informers/generic.go index bd0ba6d790..cf4e9ff0aa 100644 --- a/staging/src/k8s.io/client-go/informers/generic.go +++ b/staging/src/k8s.io/client-go/informers/generic.go @@ -280,6 +280,10 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1alpha1().VolumeAttachments().Informer()}, nil // Group=storage.k8s.io, Version=v1beta1 + case storagev1beta1.SchemeGroupVersion.WithResource("csidrivers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1beta1().CSIDrivers().Informer()}, nil + case storagev1beta1.SchemeGroupVersion.WithResource("csinodes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1beta1().CSINodes().Informer()}, nil case storagev1beta1.SchemeGroupVersion.WithResource("storageclasses"): return &genericInformer{resource: resource.GroupResource(), informer: f.Storage().V1beta1().StorageClasses().Informer()}, nil case storagev1beta1.SchemeGroupVersion.WithResource("volumeattachments"): diff --git a/staging/src/k8s.io/client-go/informers/storage/v1beta1/BUILD b/staging/src/k8s.io/client-go/informers/storage/v1beta1/BUILD index 72df059003..3a7f30cec2 100644 --- a/staging/src/k8s.io/client-go/informers/storage/v1beta1/BUILD +++ b/staging/src/k8s.io/client-go/informers/storage/v1beta1/BUILD @@ -8,6 +8,8 @@ load( go_library( name = "go_default_library", srcs = [ + "csidriver.go", + "csinode.go", "interface.go", "storageclass.go", "volumeattachment.go", diff --git a/staging/src/k8s.io/client-go/informers/storage/v1beta1/csidriver.go b/staging/src/k8s.io/client-go/informers/storage/v1beta1/csidriver.go new file mode 100644 index 0000000000..7f7cb216df --- /dev/null +++ b/staging/src/k8s.io/client-go/informers/storage/v1beta1/csidriver.go @@ -0,0 +1,88 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + time "time" + + storagev1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + internalinterfaces "k8s.io/client-go/informers/internalinterfaces" + kubernetes "k8s.io/client-go/kubernetes" + v1beta1 "k8s.io/client-go/listers/storage/v1beta1" + cache "k8s.io/client-go/tools/cache" +) + +// CSIDriverInformer provides access to a shared informer and lister for +// CSIDrivers. +type CSIDriverInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.CSIDriverLister +} + +type cSIDriverInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewCSIDriverInformer constructs a new informer for CSIDriver type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewCSIDriverInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredCSIDriverInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredCSIDriverInformer constructs a new informer for CSIDriver type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredCSIDriverInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.StorageV1beta1().CSIDrivers().List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.StorageV1beta1().CSIDrivers().Watch(options) + }, + }, + &storagev1beta1.CSIDriver{}, + resyncPeriod, + indexers, + ) +} + +func (f *cSIDriverInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredCSIDriverInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *cSIDriverInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&storagev1beta1.CSIDriver{}, f.defaultInformer) +} + +func (f *cSIDriverInformer) Lister() v1beta1.CSIDriverLister { + return v1beta1.NewCSIDriverLister(f.Informer().GetIndexer()) +} diff --git a/staging/src/k8s.io/client-go/informers/storage/v1beta1/csinode.go b/staging/src/k8s.io/client-go/informers/storage/v1beta1/csinode.go new file mode 100644 index 0000000000..218bb11831 --- /dev/null +++ b/staging/src/k8s.io/client-go/informers/storage/v1beta1/csinode.go @@ -0,0 +1,88 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1beta1 + +import ( + time "time" + + storagev1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + internalinterfaces "k8s.io/client-go/informers/internalinterfaces" + kubernetes "k8s.io/client-go/kubernetes" + v1beta1 "k8s.io/client-go/listers/storage/v1beta1" + cache "k8s.io/client-go/tools/cache" +) + +// CSINodeInformer provides access to a shared informer and lister for +// CSINodes. +type CSINodeInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1beta1.CSINodeLister +} + +type cSINodeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewCSINodeInformer constructs a new informer for CSINode type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewCSINodeInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredCSINodeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredCSINodeInformer constructs a new informer for CSINode type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredCSINodeInformer(client kubernetes.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.StorageV1beta1().CSINodes().List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.StorageV1beta1().CSINodes().Watch(options) + }, + }, + &storagev1beta1.CSINode{}, + resyncPeriod, + indexers, + ) +} + +func (f *cSINodeInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredCSINodeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *cSINodeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&storagev1beta1.CSINode{}, f.defaultInformer) +} + +func (f *cSINodeInformer) Lister() v1beta1.CSINodeLister { + return v1beta1.NewCSINodeLister(f.Informer().GetIndexer()) +} diff --git a/staging/src/k8s.io/client-go/informers/storage/v1beta1/interface.go b/staging/src/k8s.io/client-go/informers/storage/v1beta1/interface.go index aa11c2bb6d..af4ee2f74a 100644 --- a/staging/src/k8s.io/client-go/informers/storage/v1beta1/interface.go +++ b/staging/src/k8s.io/client-go/informers/storage/v1beta1/interface.go @@ -24,6 +24,10 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // CSIDrivers returns a CSIDriverInformer. + CSIDrivers() CSIDriverInformer + // CSINodes returns a CSINodeInformer. + CSINodes() CSINodeInformer // StorageClasses returns a StorageClassInformer. StorageClasses() StorageClassInformer // VolumeAttachments returns a VolumeAttachmentInformer. @@ -41,6 +45,16 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// CSIDrivers returns a CSIDriverInformer. +func (v *version) CSIDrivers() CSIDriverInformer { + return &cSIDriverInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// CSINodes returns a CSINodeInformer. +func (v *version) CSINodes() CSINodeInformer { + return &cSINodeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // StorageClasses returns a StorageClassInformer. func (v *version) StorageClasses() StorageClassInformer { return &storageClassInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/BUILD b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/BUILD index 425d2dc925..c46c64a003 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/BUILD +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/BUILD @@ -8,6 +8,8 @@ load( go_library( name = "go_default_library", srcs = [ + "csidriver.go", + "csinode.go", "doc.go", "generated_expansion.go", "storage_client.go", diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csidriver.go b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csidriver.go new file mode 100644 index 0000000000..86cf9bf180 --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csidriver.go @@ -0,0 +1,164 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "time" + + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + rest "k8s.io/client-go/rest" +) + +// CSIDriversGetter has a method to return a CSIDriverInterface. +// A group's client should implement this interface. +type CSIDriversGetter interface { + CSIDrivers() CSIDriverInterface +} + +// CSIDriverInterface has methods to work with CSIDriver resources. +type CSIDriverInterface interface { + Create(*v1beta1.CSIDriver) (*v1beta1.CSIDriver, error) + Update(*v1beta1.CSIDriver) (*v1beta1.CSIDriver, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.CSIDriver, error) + List(opts v1.ListOptions) (*v1beta1.CSIDriverList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSIDriver, err error) + CSIDriverExpansion +} + +// cSIDrivers implements CSIDriverInterface +type cSIDrivers struct { + client rest.Interface +} + +// newCSIDrivers returns a CSIDrivers +func newCSIDrivers(c *StorageV1beta1Client) *cSIDrivers { + return &cSIDrivers{ + client: c.RESTClient(), + } +} + +// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any. +func (c *cSIDrivers) Get(name string, options v1.GetOptions) (result *v1beta1.CSIDriver, err error) { + result = &v1beta1.CSIDriver{} + err = c.client.Get(). + Resource("csidrivers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors. +func (c *cSIDrivers) List(opts v1.ListOptions) (result *v1beta1.CSIDriverList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.CSIDriverList{} + err = c.client.Get(). + Resource("csidrivers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested cSIDrivers. +func (c *cSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("csidrivers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *cSIDrivers) Create(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) { + result = &v1beta1.CSIDriver{} + err = c.client.Post(). + Resource("csidrivers"). + Body(cSIDriver). + Do(). + Into(result) + return +} + +// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *cSIDrivers) Update(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) { + result = &v1beta1.CSIDriver{} + err = c.client.Put(). + Resource("csidrivers"). + Name(cSIDriver.Name). + Body(cSIDriver). + Do(). + Into(result) + return +} + +// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs. +func (c *cSIDrivers) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("csidrivers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *cSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("csidrivers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched cSIDriver. +func (c *cSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSIDriver, err error) { + result = &v1beta1.CSIDriver{} + err = c.client.Patch(pt). + Resource("csidrivers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csinode.go b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csinode.go new file mode 100644 index 0000000000..e5540c1287 --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/csinode.go @@ -0,0 +1,164 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1beta1 + +import ( + "time" + + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + rest "k8s.io/client-go/rest" +) + +// CSINodesGetter has a method to return a CSINodeInterface. +// A group's client should implement this interface. +type CSINodesGetter interface { + CSINodes() CSINodeInterface +} + +// CSINodeInterface has methods to work with CSINode resources. +type CSINodeInterface interface { + Create(*v1beta1.CSINode) (*v1beta1.CSINode, error) + Update(*v1beta1.CSINode) (*v1beta1.CSINode, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1beta1.CSINode, error) + List(opts v1.ListOptions) (*v1beta1.CSINodeList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSINode, err error) + CSINodeExpansion +} + +// cSINodes implements CSINodeInterface +type cSINodes struct { + client rest.Interface +} + +// newCSINodes returns a CSINodes +func newCSINodes(c *StorageV1beta1Client) *cSINodes { + return &cSINodes{ + client: c.RESTClient(), + } +} + +// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any. +func (c *cSINodes) Get(name string, options v1.GetOptions) (result *v1beta1.CSINode, err error) { + result = &v1beta1.CSINode{} + err = c.client.Get(). + Resource("csinodes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of CSINodes that match those selectors. +func (c *cSINodes) List(opts v1.ListOptions) (result *v1beta1.CSINodeList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1beta1.CSINodeList{} + err = c.client.Get(). + Resource("csinodes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested cSINodes. +func (c *cSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("csinodes"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *cSINodes) Create(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) { + result = &v1beta1.CSINode{} + err = c.client.Post(). + Resource("csinodes"). + Body(cSINode). + Do(). + Into(result) + return +} + +// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *cSINodes) Update(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) { + result = &v1beta1.CSINode{} + err = c.client.Put(). + Resource("csinodes"). + Name(cSINode.Name). + Body(cSINode). + Do(). + Into(result) + return +} + +// Delete takes name of the cSINode and deletes it. Returns an error if one occurs. +func (c *cSINodes) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Resource("csinodes"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *cSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("csinodes"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched cSINode. +func (c *cSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSINode, err error) { + result = &v1beta1.CSINode{} + err = c.client.Patch(pt). + Resource("csinodes"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/BUILD b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/BUILD index f687a4719f..7bcbe73990 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/BUILD +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/BUILD @@ -9,6 +9,8 @@ go_library( name = "go_default_library", srcs = [ "doc.go", + "fake_csidriver.go", + "fake_csinode.go", "fake_storage_client.go", "fake_storageclass.go", "fake_volumeattachment.go", diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csidriver.go b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csidriver.go new file mode 100644 index 0000000000..2446316b2d --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csidriver.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeCSIDrivers implements CSIDriverInterface +type FakeCSIDrivers struct { + Fake *FakeStorageV1beta1 +} + +var csidriversResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "csidrivers"} + +var csidriversKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSIDriver"} + +// Get takes name of the cSIDriver, and returns the corresponding cSIDriver object, and an error if there is any. +func (c *FakeCSIDrivers) Get(name string, options v1.GetOptions) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csidriversResource, name), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} + +// List takes label and field selectors, and returns the list of CSIDrivers that match those selectors. +func (c *FakeCSIDrivers) List(opts v1.ListOptions) (result *v1beta1.CSIDriverList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csidriversResource, csidriversKind, opts), &v1beta1.CSIDriverList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.CSIDriverList{ListMeta: obj.(*v1beta1.CSIDriverList).ListMeta} + for _, item := range obj.(*v1beta1.CSIDriverList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSIDrivers. +func (c *FakeCSIDrivers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csidriversResource, opts)) +} + +// Create takes the representation of a cSIDriver and creates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Create(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csidriversResource, cSIDriver), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} + +// Update takes the representation of a cSIDriver and updates it. Returns the server's representation of the cSIDriver, and an error, if there is any. +func (c *FakeCSIDrivers) Update(cSIDriver *v1beta1.CSIDriver) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csidriversResource, cSIDriver), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} + +// Delete takes name of the cSIDriver and deletes it. Returns an error if one occurs. +func (c *FakeCSIDrivers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(csidriversResource, name), &v1beta1.CSIDriver{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSIDrivers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csidriversResource, listOptions) + + _, err := c.Fake.Invokes(action, &v1beta1.CSIDriverList{}) + return err +} + +// Patch applies the patch and returns the patched cSIDriver. +func (c *FakeCSIDrivers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSIDriver, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csidriversResource, name, pt, data, subresources...), &v1beta1.CSIDriver{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSIDriver), err +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csinode.go b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csinode.go new file mode 100644 index 0000000000..0050f4743d --- /dev/null +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_csinode.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1beta1 "k8s.io/api/storage/v1beta1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeCSINodes implements CSINodeInterface +type FakeCSINodes struct { + Fake *FakeStorageV1beta1 +} + +var csinodesResource = schema.GroupVersionResource{Group: "storage.k8s.io", Version: "v1beta1", Resource: "csinodes"} + +var csinodesKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSINode"} + +// Get takes name of the cSINode, and returns the corresponding cSINode object, and an error if there is any. +func (c *FakeCSINodes) Get(name string, options v1.GetOptions) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(csinodesResource, name), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} + +// List takes label and field selectors, and returns the list of CSINodes that match those selectors. +func (c *FakeCSINodes) List(opts v1.ListOptions) (result *v1beta1.CSINodeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(csinodesResource, csinodesKind, opts), &v1beta1.CSINodeList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1beta1.CSINodeList{ListMeta: obj.(*v1beta1.CSINodeList).ListMeta} + for _, item := range obj.(*v1beta1.CSINodeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested cSINodes. +func (c *FakeCSINodes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(csinodesResource, opts)) +} + +// Create takes the representation of a cSINode and creates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Create(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(csinodesResource, cSINode), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} + +// Update takes the representation of a cSINode and updates it. Returns the server's representation of the cSINode, and an error, if there is any. +func (c *FakeCSINodes) Update(cSINode *v1beta1.CSINode) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(csinodesResource, cSINode), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} + +// Delete takes name of the cSINode and deletes it. Returns an error if one occurs. +func (c *FakeCSINodes) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(csinodesResource, name), &v1beta1.CSINode{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeCSINodes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(csinodesResource, listOptions) + + _, err := c.Fake.Invokes(action, &v1beta1.CSINodeList{}) + return err +} + +// Patch applies the patch and returns the patched cSINode. +func (c *FakeCSINodes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.CSINode, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(csinodesResource, name, pt, data, subresources...), &v1beta1.CSINode{}) + if obj == nil { + return nil, err + } + return obj.(*v1beta1.CSINode), err +} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go index e0e3f1d78b..7968c9003a 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake/fake_storage_client.go @@ -28,6 +28,14 @@ type FakeStorageV1beta1 struct { *testing.Fake } +func (c *FakeStorageV1beta1) CSIDrivers() v1beta1.CSIDriverInterface { + return &FakeCSIDrivers{c} +} + +func (c *FakeStorageV1beta1) CSINodes() v1beta1.CSINodeInterface { + return &FakeCSINodes{c} +} + func (c *FakeStorageV1beta1) StorageClasses() v1beta1.StorageClassInterface { return &FakeStorageClasses{c} } diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/generated_expansion.go b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/generated_expansion.go index 559f88f676..7ba93142bf 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/generated_expansion.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/generated_expansion.go @@ -18,6 +18,10 @@ limitations under the License. package v1beta1 +type CSIDriverExpansion interface{} + +type CSINodeExpansion interface{} + type StorageClassExpansion interface{} type VolumeAttachmentExpansion interface{} diff --git a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/storage_client.go b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/storage_client.go index 4bdebb8782..e9916bc0aa 100644 --- a/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/storage_client.go +++ b/staging/src/k8s.io/client-go/kubernetes/typed/storage/v1beta1/storage_client.go @@ -27,6 +27,8 @@ import ( type StorageV1beta1Interface interface { RESTClient() rest.Interface + CSIDriversGetter + CSINodesGetter StorageClassesGetter VolumeAttachmentsGetter } @@ -36,6 +38,14 @@ type StorageV1beta1Client struct { restClient rest.Interface } +func (c *StorageV1beta1Client) CSIDrivers() CSIDriverInterface { + return newCSIDrivers(c) +} + +func (c *StorageV1beta1Client) CSINodes() CSINodeInterface { + return newCSINodes(c) +} + func (c *StorageV1beta1Client) StorageClasses() StorageClassInterface { return newStorageClasses(c) } diff --git a/staging/src/k8s.io/client-go/listers/storage/v1beta1/BUILD b/staging/src/k8s.io/client-go/listers/storage/v1beta1/BUILD index e38902fa3b..8f22ec7939 100644 --- a/staging/src/k8s.io/client-go/listers/storage/v1beta1/BUILD +++ b/staging/src/k8s.io/client-go/listers/storage/v1beta1/BUILD @@ -8,6 +8,8 @@ load( go_library( name = "go_default_library", srcs = [ + "csidriver.go", + "csinode.go", "expansion_generated.go", "storageclass.go", "volumeattachment.go", diff --git a/staging/src/k8s.io/client-go/listers/storage/v1beta1/csidriver.go b/staging/src/k8s.io/client-go/listers/storage/v1beta1/csidriver.go new file mode 100644 index 0000000000..8a40137506 --- /dev/null +++ b/staging/src/k8s.io/client-go/listers/storage/v1beta1/csidriver.go @@ -0,0 +1,65 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1beta1 "k8s.io/api/storage/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// CSIDriverLister helps list CSIDrivers. +type CSIDriverLister interface { + // List lists all CSIDrivers in the indexer. + List(selector labels.Selector) (ret []*v1beta1.CSIDriver, err error) + // Get retrieves the CSIDriver from the index for a given name. + Get(name string) (*v1beta1.CSIDriver, error) + CSIDriverListerExpansion +} + +// cSIDriverLister implements the CSIDriverLister interface. +type cSIDriverLister struct { + indexer cache.Indexer +} + +// NewCSIDriverLister returns a new CSIDriverLister. +func NewCSIDriverLister(indexer cache.Indexer) CSIDriverLister { + return &cSIDriverLister{indexer: indexer} +} + +// List lists all CSIDrivers in the indexer. +func (s *cSIDriverLister) List(selector labels.Selector) (ret []*v1beta1.CSIDriver, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.CSIDriver)) + }) + return ret, err +} + +// Get retrieves the CSIDriver from the index for a given name. +func (s *cSIDriverLister) Get(name string) (*v1beta1.CSIDriver, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("csidriver"), name) + } + return obj.(*v1beta1.CSIDriver), nil +} diff --git a/staging/src/k8s.io/client-go/listers/storage/v1beta1/csinode.go b/staging/src/k8s.io/client-go/listers/storage/v1beta1/csinode.go new file mode 100644 index 0000000000..bb7a2b2b3b --- /dev/null +++ b/staging/src/k8s.io/client-go/listers/storage/v1beta1/csinode.go @@ -0,0 +1,65 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1beta1 + +import ( + v1beta1 "k8s.io/api/storage/v1beta1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// CSINodeLister helps list CSINodes. +type CSINodeLister interface { + // List lists all CSINodes in the indexer. + List(selector labels.Selector) (ret []*v1beta1.CSINode, err error) + // Get retrieves the CSINode from the index for a given name. + Get(name string) (*v1beta1.CSINode, error) + CSINodeListerExpansion +} + +// cSINodeLister implements the CSINodeLister interface. +type cSINodeLister struct { + indexer cache.Indexer +} + +// NewCSINodeLister returns a new CSINodeLister. +func NewCSINodeLister(indexer cache.Indexer) CSINodeLister { + return &cSINodeLister{indexer: indexer} +} + +// List lists all CSINodes in the indexer. +func (s *cSINodeLister) List(selector labels.Selector) (ret []*v1beta1.CSINode, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1beta1.CSINode)) + }) + return ret, err +} + +// Get retrieves the CSINode from the index for a given name. +func (s *cSINodeLister) Get(name string) (*v1beta1.CSINode, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1beta1.Resource("csinode"), name) + } + return obj.(*v1beta1.CSINode), nil +} diff --git a/staging/src/k8s.io/client-go/listers/storage/v1beta1/expansion_generated.go b/staging/src/k8s.io/client-go/listers/storage/v1beta1/expansion_generated.go index 21d95620c1..eeca4fdb40 100644 --- a/staging/src/k8s.io/client-go/listers/storage/v1beta1/expansion_generated.go +++ b/staging/src/k8s.io/client-go/listers/storage/v1beta1/expansion_generated.go @@ -18,6 +18,14 @@ limitations under the License. package v1beta1 +// CSIDriverListerExpansion allows custom methods to be added to +// CSIDriverLister. +type CSIDriverListerExpansion interface{} + +// CSINodeListerExpansion allows custom methods to be added to +// CSINodeLister. +type CSINodeListerExpansion interface{} + // StorageClassListerExpansion allows custom methods to be added to // StorageClassLister. type StorageClassListerExpansion interface{} diff --git a/test/e2e/framework/BUILD b/test/e2e/framework/BUILD index c3956b797f..0c769830a9 100644 --- a/test/e2e/framework/BUILD +++ b/test/e2e/framework/BUILD @@ -126,7 +126,6 @@ go_library( "//staging/src/k8s.io/client-go/tools/watch:go_default_library", "//staging/src/k8s.io/client-go/util/retry:go_default_library", "//staging/src/k8s.io/component-base/cli/flag:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//staging/src/k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset:go_default_library", "//staging/src/k8s.io/node-api/pkg/client/clientset/versioned:go_default_library", "//test/e2e/framework/ginkgowrapper:go_default_library", diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index 6630838a49..c53c1ae305 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -46,7 +46,6 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/restmapper" scaleclient "k8s.io/client-go/scale" - csi "k8s.io/csi-api/pkg/client/clientset/versioned" aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" @@ -78,7 +77,6 @@ type Framework struct { ClientSet clientset.Interface KubemarkExternalClusterClientSet clientset.Interface APIExtensionsClientSet apiextensionsclient.Interface - CSIClientSet csi.Interface NodeAPIClientSet nodeapiclient.Interface InternalClientset *internalclientset.Clientset @@ -194,12 +192,9 @@ func (f *Framework) BeforeEach() { ExpectNoError(err) f.DynamicClient, err = dynamic.NewForConfig(config) ExpectNoError(err) - // csi.storage.k8s.io is based on CRD, which is served only as JSON + // node.k8s.io is based on CRD, which is served only as JSON jsonConfig := config jsonConfig.ContentType = "application/json" - f.CSIClientSet, err = csi.NewForConfig(jsonConfig) - ExpectNoError(err) - // node.k8s.io is also based on CRD f.NodeAPIClientSet, err = nodeapiclient.NewForConfig(jsonConfig) ExpectNoError(err) diff --git a/test/e2e/storage/BUILD b/test/e2e/storage/BUILD index 13269e6748..3c85845af5 100644 --- a/test/e2e/storage/BUILD +++ b/test/e2e/storage/BUILD @@ -65,7 +65,6 @@ go_library( "//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//staging/src/k8s.io/cloud-provider/volume/helpers:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//test/e2e/framework:go_default_library", "//test/e2e/framework/metrics:go_default_library", "//test/e2e/framework/providers/gce:go_default_library", diff --git a/test/e2e/storage/csi_mock_volume.go b/test/e2e/storage/csi_mock_volume.go index 02dd0ea9d7..31ebd2830e 100644 --- a/test/e2e/storage/csi_mock_volume.go +++ b/test/e2e/storage/csi_mock_volume.go @@ -33,7 +33,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" clientset "k8s.io/client-go/kubernetes" - csiclient "k8s.io/csi-api/pkg/client/clientset/versioned" volumeutil "k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/storage/drivers" @@ -85,7 +84,7 @@ var _ = utils.SIGDescribe("CSI mock volume", func() { sc: make(map[string]*storage.StorageClass), tp: tp, } - csics := f.CSIClientSet + cs := f.ClientSet var err error m.driver = drivers.InitMockCSIDriver(tp.registerDriver, tp.attachable, tp.podInfoVersion, tp.attachLimit) @@ -102,10 +101,10 @@ var _ = utils.SIGDescribe("CSI mock volume", func() { } if tp.registerDriver { - err = waitForCSIDriver(csics, m.config.GetUniqueDriverName()) + err = waitForCSIDriver(cs, m.config.GetUniqueDriverName()) framework.ExpectNoError(err, "Failed to get CSIDriver : %v", err) m.testCleanups = append(m.testCleanups, func() { - destroyCSIDriver(csics, m.config.GetUniqueDriverName()) + destroyCSIDriver(cs, m.config.GetUniqueDriverName()) }) } } @@ -515,12 +514,12 @@ func checkPodInfo(cs clientset.Interface, namespace, driverPodName, driverContai } } -func waitForCSIDriver(csics csiclient.Interface, driverName string) error { +func waitForCSIDriver(cs clientset.Interface, driverName string) error { timeout := 2 * time.Minute framework.Logf("waiting up to %v for CSIDriver %q", timeout, driverName) for start := time.Now(); time.Since(start) < timeout; time.Sleep(framework.Poll) { - _, err := csics.CsiV1alpha1().CSIDrivers().Get(driverName, metav1.GetOptions{}) + _, err := cs.StorageV1beta1().CSIDrivers().Get(driverName, metav1.GetOptions{}) if !errors.IsNotFound(err) { return err } @@ -528,13 +527,13 @@ func waitForCSIDriver(csics csiclient.Interface, driverName string) error { return fmt.Errorf("gave up after waiting %v for CSIDriver %q.", timeout, driverName) } -func destroyCSIDriver(csics csiclient.Interface, driverName string) { - driverGet, err := csics.CsiV1alpha1().CSIDrivers().Get(driverName, metav1.GetOptions{}) +func destroyCSIDriver(cs clientset.Interface, driverName string) { + driverGet, err := cs.StorageV1beta1().CSIDrivers().Get(driverName, metav1.GetOptions{}) if err == nil { framework.Logf("deleting %s.%s: %s", driverGet.TypeMeta.APIVersion, driverGet.TypeMeta.Kind, driverGet.ObjectMeta.Name) // Uncomment the following line to get full dump of CSIDriver object // framework.Logf("%s", framework.PrettyPrint(driverGet)) - csics.CsiV1alpha1().CSIDrivers().Delete(driverName, nil) + cs.StorageV1beta1().CSIDrivers().Delete(driverName, nil) } } diff --git a/test/integration/apiserver/print_test.go b/test/integration/apiserver/print_test.go index b3cab84f09..40d1355f21 100644 --- a/test/integration/apiserver/print_test.go +++ b/test/integration/apiserver/print_test.go @@ -133,6 +133,8 @@ var missingHanlders = sets.NewString( "PriorityClass", "PodPreset", "AuditSink", + "CSINode", + "CSIDriver", ) func TestServerSidePrint(t *testing.T) { diff --git a/test/integration/auth/BUILD b/test/integration/auth/BUILD index 31405070a5..545af5ad2d 100644 --- a/test/integration/auth/BUILD +++ b/test/integration/auth/BUILD @@ -52,6 +52,7 @@ go_test( "//staging/src/k8s.io/api/authentication/v1beta1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library", + "//staging/src/k8s.io/api/storage/v1beta1:go_default_library", "//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library", "//staging/src/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", @@ -87,11 +88,8 @@ go_test( "//staging/src/k8s.io/client-go/transport:go_default_library", "//staging/src/k8s.io/client-go/util/keyutil:go_default_library", "//staging/src/k8s.io/cluster-bootstrap/token/api:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/apis/csi/v1alpha1:go_default_library", - "//staging/src/k8s.io/csi-api/pkg/client/clientset/versioned:go_default_library", "//test/e2e/lifecycle/bootstrap:go_default_library", "//test/integration:go_default_library", - "//test/integration/etcd:go_default_library", "//test/integration/framework:go_default_library", "//vendor/gopkg.in/square/go-jose.v2/jwt:go_default_library", "//vendor/k8s.io/klog:go_default_library", diff --git a/test/integration/auth/node_test.go b/test/integration/auth/node_test.go index 868418c3ad..bd652c38cf 100644 --- a/test/integration/auth/node_test.go +++ b/test/integration/auth/node_test.go @@ -24,6 +24,7 @@ import ( "time" storagev1 "k8s.io/api/storage/v1" + storagev1beta1 "k8s.io/api/storage/v1beta1" apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -34,8 +35,6 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" externalclientset "k8s.io/client-go/kubernetes" - csiv1alpha1 "k8s.io/csi-api/pkg/apis/csi/v1alpha1" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/coordination" @@ -44,7 +43,6 @@ import ( "k8s.io/kubernetes/pkg/apis/policy" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/features" - "k8s.io/kubernetes/test/integration/etcd" "k8s.io/kubernetes/test/integration/framework" "k8s.io/utils/pointer" ) @@ -67,7 +65,7 @@ func TestNodeAuthorizer(t *testing.T) { // Enable NodeLease feature so that nodes can create leases defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeLease, true)() - // Enable CSINodeInfo feature so that nodes can create CSINodeInfo objects. + // Enable CSINodeInfo feature so that nodes can create CSINode objects. defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSINodeInfo, true)() tokenFile, err := ioutil.TempFile("", "kubeconfig") @@ -95,7 +93,6 @@ func TestNodeAuthorizer(t *testing.T) { // Build client config and superuser clientset clientConfig := server.ClientConfig superuserClient, superuserClientExternal := clientsetForToken(tokenMaster, clientConfig) - superuserCRDClient := crdClientsetForToken(tokenMaster, clientConfig) // Wait for a healthy server for { @@ -158,13 +155,6 @@ func TestNodeAuthorizer(t *testing.T) { t.Fatal(err) } - csiNodeInfoCRD, err := crdFromManifest("../../../staging/src/k8s.io/csi-api/pkg/crd/manifests/csinodeinfo.yaml") - if err != nil { - t.Fatal(err) - } - - etcd.CreateTestCRDs(t, superuserCRDClient, false, csiNodeInfoCRD) - getSecret := func(client clientset.Interface) func() error { return func() error { _, err := client.Core().Secrets("ns").Get("mysecret", metav1.GetOptions{}) @@ -412,84 +402,68 @@ func TestNodeAuthorizer(t *testing.T) { } } - getNode1CSINodeInfo := func(client csiclientset.Interface) func() error { + getNode1CSINode := func(client externalclientset.Interface) func() error { return func() error { - _, err := client.CsiV1alpha1().CSINodeInfos().Get("node1", metav1.GetOptions{}) + _, err := client.StorageV1beta1().CSINodes().Get("node1", metav1.GetOptions{}) return err } } - createNode1CSINodeInfo := func(client csiclientset.Interface) func() error { + createNode1CSINode := func(client externalclientset.Interface) func() error { return func() error { - nodeInfo := &csiv1alpha1.CSINodeInfo{ + nodeInfo := &storagev1beta1.CSINode{ ObjectMeta: metav1.ObjectMeta{ Name: "node1", }, - Spec: csiv1alpha1.CSINodeInfoSpec{ - Drivers: []csiv1alpha1.CSIDriverInfoSpec{ + Spec: storagev1beta1.CSINodeSpec{ + Drivers: []storagev1beta1.CSINodeDriver{ { - Name: "com.example.csi/driver1", + Name: "com.example.csi.driver1", NodeID: "com.example.csi/node1", TopologyKeys: []string{"com.example.csi/zone"}, }, }, }, - Status: csiv1alpha1.CSINodeInfoStatus{ - Drivers: []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "com.example.csi/driver1", - Available: true, - VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree, - }, - }, - }, } - _, err := client.CsiV1alpha1().CSINodeInfos().Create(nodeInfo) + _, err := client.StorageV1beta1().CSINodes().Create(nodeInfo) return err } } - updateNode1CSINodeInfo := func(client csiclientset.Interface) func() error { + updateNode1CSINode := func(client externalclientset.Interface) func() error { return func() error { - nodeInfo, err := client.CsiV1alpha1().CSINodeInfos().Get("node1", metav1.GetOptions{}) + nodeInfo, err := client.StorageV1beta1().CSINodes().Get("node1", metav1.GetOptions{}) if err != nil { return err } - nodeInfo.Spec.Drivers = []csiv1alpha1.CSIDriverInfoSpec{ + nodeInfo.Spec.Drivers = []storagev1beta1.CSINodeDriver{ { - Name: "com.example.csi/driver1", + Name: "com.example.csi.driver2", NodeID: "com.example.csi/node1", TopologyKeys: []string{"com.example.csi/rack"}, }, } - nodeInfo.Status.Drivers = []csiv1alpha1.CSIDriverInfoStatus{ - { - Name: "com.example.csi/driver1", - Available: true, - VolumePluginMechanism: csiv1alpha1.VolumePluginMechanismInTree, - }, - } - _, err = client.CsiV1alpha1().CSINodeInfos().Update(nodeInfo) + _, err = client.StorageV1beta1().CSINodes().Update(nodeInfo) return err } } - patchNode1CSINodeInfo := func(client csiclientset.Interface) func() error { + patchNode1CSINode := func(client externalclientset.Interface) func() error { return func() error { - bs := []byte(fmt.Sprintf(`{"csiDrivers": [ { "driver": "net.example.storage/driver2", "nodeID": "net.example.storage/node1", "topologyKeys": [ "net.example.storage/region" ] } ] }`)) + bs := []byte(fmt.Sprintf(`{"csiDrivers": [ { "driver": "net.example.storage.driver2", "nodeID": "net.example.storage/node1", "topologyKeys": [ "net.example.storage/region" ] } ] }`)) // StrategicMergePatch is unsupported by CRs. Falling back to MergePatch - _, err := client.CsiV1alpha1().CSINodeInfos().Patch("node1", types.MergePatchType, bs) + _, err := client.StorageV1beta1().CSINodes().Patch("node1", types.MergePatchType, bs) return err } } - deleteNode1CSINodeInfo := func(client csiclientset.Interface) func() error { + deleteNode1CSINode := func(client externalclientset.Interface) func() error { return func() error { - return client.CsiV1alpha1().CSINodeInfos().Delete("node1", &metav1.DeleteOptions{}) + return client.StorageV1beta1().CSINodes().Delete("node1", &metav1.DeleteOptions{}) } } nodeanonClient, _ := clientsetForToken(tokenNodeUnknown, clientConfig) node1Client, node1ClientExternal := clientsetForToken(tokenNode1, clientConfig) node2Client, node2ClientExternal := clientsetForToken(tokenNode2, clientConfig) - csiNode1Client := csiClientsetForToken(tokenNode1, clientConfig) - csiNode2Client := csiClientsetForToken(tokenNode2, clientConfig) + _, csiNode1Client := clientsetForToken(tokenNode1, clientConfig) + _, csiNode2Client := clientsetForToken(tokenNode2, clientConfig) // all node requests from node1 and unknown node fail expectForbidden(t, getSecret(nodeanonClient)) @@ -645,18 +619,18 @@ func TestNodeAuthorizer(t *testing.T) { expectForbidden(t, patchNode1Lease(node2Client)) expectForbidden(t, deleteNode1Lease(node2Client)) - // node1 allowed to operate on its own CSINodeInfo - expectAllowed(t, createNode1CSINodeInfo(csiNode1Client)) - expectAllowed(t, getNode1CSINodeInfo(csiNode1Client)) - expectAllowed(t, updateNode1CSINodeInfo(csiNode1Client)) - expectAllowed(t, patchNode1CSINodeInfo(csiNode1Client)) - expectAllowed(t, deleteNode1CSINodeInfo(csiNode1Client)) - // node2 not allowed to operate on another node's CSINodeInfo - expectForbidden(t, createNode1CSINodeInfo(csiNode2Client)) - expectForbidden(t, getNode1CSINodeInfo(csiNode2Client)) - expectForbidden(t, updateNode1CSINodeInfo(csiNode2Client)) - expectForbidden(t, patchNode1CSINodeInfo(csiNode2Client)) - expectForbidden(t, deleteNode1CSINodeInfo(csiNode2Client)) + // node1 allowed to operate on its own CSINode + expectAllowed(t, createNode1CSINode(csiNode1Client)) + expectAllowed(t, getNode1CSINode(csiNode1Client)) + expectAllowed(t, updateNode1CSINode(csiNode1Client)) + expectAllowed(t, patchNode1CSINode(csiNode1Client)) + expectAllowed(t, deleteNode1CSINode(csiNode1Client)) + // node2 not allowed to operate on another node's CSINode + expectForbidden(t, createNode1CSINode(csiNode2Client)) + expectForbidden(t, getNode1CSINode(csiNode2Client)) + expectForbidden(t, updateNode1CSINode(csiNode2Client)) + expectForbidden(t, patchNode1CSINode(csiNode2Client)) + expectForbidden(t, deleteNode1CSINode(csiNode2Client)) } // expect executes a function a set number of times until it either returns the diff --git a/test/integration/auth/rbac_test.go b/test/integration/auth/rbac_test.go index e95e107f49..950b1e94e2 100644 --- a/test/integration/auth/rbac_test.go +++ b/test/integration/auth/rbac_test.go @@ -45,7 +45,6 @@ import ( restclient "k8s.io/client-go/rest" watchtools "k8s.io/client-go/tools/watch" "k8s.io/client-go/transport" - csiclientset "k8s.io/csi-api/pkg/client/clientset/versioned" "k8s.io/klog" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/testapi" @@ -86,13 +85,6 @@ func crdClientsetForToken(user string, config *restclient.Config) apiextensionsc return apiextensionsclient.NewForConfigOrDie(&configCopy) } -func csiClientsetForToken(user string, config *restclient.Config) csiclientset.Interface { - configCopy := *config - configCopy.BearerToken = user - configCopy.ContentType = "application/json" // // csi client works with CRDs that support json only - return csiclientset.NewForConfigOrDie(&configCopy) -} - type testRESTOptionsGetter struct { config *master.Config } diff --git a/test/integration/etcd/BUILD b/test/integration/etcd/BUILD index f29d37ba72..ecf1142563 100644 --- a/test/integration/etcd/BUILD +++ b/test/integration/etcd/BUILD @@ -55,6 +55,7 @@ go_library( deps = [ "//cmd/kube-apiserver/app:go_default_library", "//cmd/kube-apiserver/app/options:go_default_library", + "//pkg/features:go_default_library", "//pkg/master:go_default_library", "//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library", "//staging/src/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library", @@ -65,6 +66,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library", + "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/client-go/discovery/cached/memory:go_default_library", "//staging/src/k8s.io/client-go/dynamic:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library", diff --git a/test/integration/etcd/data.go b/test/integration/etcd/data.go index 30f5247fa5..f6d84a8d7c 100644 --- a/test/integration/etcd/data.go +++ b/test/integration/etcd/data.go @@ -20,13 +20,15 @@ import ( apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" ) // GetEtcdStorageData returns etcd data for all persisted objects. // It is exported so that it can be reused across multiple tests. // It returns a new map on every invocation to prevent different tests from mutating shared state. func GetEtcdStorageData() map[schema.GroupVersionResource]StorageData { - return map[schema.GroupVersionResource]StorageData{ + etcdStorageData := map[schema.GroupVersionResource]StorageData{ // k8s.io/kubernetes/pkg/api/v1 gvr("", "v1", "configmaps"): { Stub: `{"data": {"foo": "bar"}, "metadata": {"name": "cm1"}}`, @@ -484,6 +486,26 @@ func GetEtcdStorageData() map[schema.GroupVersionResource]StorageData { }, // -- } + + // k8s.io/kubernetes/pkg/apis/storage/v1beta1 + // add csinodes if CSINodeInfo feature gate is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { + etcdStorageData[gvr("storage.k8s.io", "v1beta1", "csinodes")] = StorageData{ + Stub: `{"metadata": {"name": "csini1"}, "spec": {"drivers": [{"name": "test-driver", "nodeID": "localhost", "topologyKeys": ["company.com/zone1", "company.com/zone2"]}]}}`, + ExpectedEtcdPath: "/registry/csinodes/csini1", + } + } + + // k8s.io/kubernetes/pkg/apis/storage/v1beta1 + // add csidrivers if CSIDriverRegistry feature gate is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { + etcdStorageData[gvr("storage.k8s.io", "v1beta1", "csidrivers")] = StorageData{ + Stub: `{"metadata": {"name": "csid1"}, "spec": {"attachRequired": true, "podInfoOnMount": true}}`, + ExpectedEtcdPath: "/registry/csidrivers/csid1", + } + } + + return etcdStorageData } // StorageData contains information required to create an object and verify its storage in etcd diff --git a/test/integration/framework/master_utils.go b/test/integration/framework/master_utils.go index 7c94935484..9b98835f2b 100644 --- a/test/integration/framework/master_utils.go +++ b/test/integration/framework/master_utils.go @@ -267,6 +267,8 @@ func NewMasterConfig() *master.Config { resourceEncoding.SetResourceEncoding(schema.GroupResource{Group: batch.GroupName, Resource: "cronjobs"}, schema.GroupVersion{Group: batch.GroupName, Version: "v1beta1"}, schema.GroupVersion{Group: batch.GroupName, Version: runtime.APIVersionInternal}) // we also need to set both for the storage group and for volumeattachments, separately resourceEncoding.SetResourceEncoding(schema.GroupResource{Group: storage.GroupName, Resource: "volumeattachments"}, schema.GroupVersion{Group: storage.GroupName, Version: "v1beta1"}, schema.GroupVersion{Group: storage.GroupName, Version: runtime.APIVersionInternal}) + resourceEncoding.SetResourceEncoding(schema.GroupResource{Group: storage.GroupName, Resource: "csinodes"}, schema.GroupVersion{Group: storage.GroupName, Version: "v1beta1"}, schema.GroupVersion{Group: storage.GroupName, Version: runtime.APIVersionInternal}) + resourceEncoding.SetResourceEncoding(schema.GroupResource{Group: storage.GroupName, Resource: "csidrivers"}, schema.GroupVersion{Group: storage.GroupName, Version: "v1beta1"}, schema.GroupVersion{Group: storage.GroupName, Version: runtime.APIVersionInternal}) storageFactory := serverstorage.NewDefaultStorageFactory(etcdOptions.StorageConfig, runtime.ContentTypeJSON, ns, resourceEncoding, master.DefaultAPIResourceConfigSource(), nil) storageFactory.SetSerializer( diff --git a/test/integration/volume/attach_detach_test.go b/test/integration/volume/attach_detach_test.go index 9b908ae21b..c6ac38141c 100644 --- a/test/integration/volume/attach_detach_test.go +++ b/test/integration/volume/attach_detach_test.go @@ -411,7 +411,6 @@ func createAdClients(ns *v1.Namespace, t *testing.T, server *httptest.Server, sy informers := informers.NewSharedInformerFactory(testClient, resyncPeriod) ctrl, err := attachdetach.NewAttachDetachController( testClient, - nil, /* csiClient */ informers.Core().V1().Pods(), informers.Core().V1().Nodes(), informers.Core().V1().PersistentVolumeClaims(),