diff --git a/api/api-rules/violation_exceptions.list b/api/api-rules/violation_exceptions.list index 4fbd6ac8146..5d653fe5d6c 100644 --- a/api/api-rules/violation_exceptions.list +++ b/api/api-rules/violation_exceptions.list @@ -339,6 +339,9 @@ API rule violation: list_type_missing,k8s.io/api/settings/v1alpha1,PodPresetSpec API rule violation: list_type_missing,k8s.io/api/settings/v1alpha1,PodPresetSpec,EnvFrom API rule violation: list_type_missing,k8s.io/api/settings/v1alpha1,PodPresetSpec,VolumeMounts API rule violation: list_type_missing,k8s.io/api/settings/v1alpha1,PodPresetSpec,Volumes +API rule violation: list_type_missing,k8s.io/api/storage/v1,CSINodeDriver,TopologyKeys +API rule violation: list_type_missing,k8s.io/api/storage/v1,CSINodeList,Items +API rule violation: list_type_missing,k8s.io/api/storage/v1,CSINodeSpec,Drivers API rule violation: list_type_missing,k8s.io/api/storage/v1,StorageClass,AllowedTopologies API rule violation: list_type_missing,k8s.io/api/storage/v1,StorageClass,MountOptions API rule violation: list_type_missing,k8s.io/api/storage/v1,StorageClassList,Items diff --git a/pkg/apis/storage/types.go b/pkg/apis/storage/types.go index 642759606b6..78185dfdbdb 100644 --- a/pkg/apis/storage/types.go +++ b/pkg/apis/storage/types.go @@ -405,7 +405,7 @@ type VolumeNodeResources struct { // Maximum number of unique volumes managed by the CSI driver that can be used on a node. // A volume that is both attached and mounted on a node is considered to be used once, not twice. // The same rule applies for a unique volume that is shared among multiple pods on the same node. - // If this field is nil, then the supported number of volumes on this node is unbounded. + // If this field is not specified, then the supported number of volumes on this node is unbounded. // +optional Count *int32 } diff --git a/pkg/kubeapiserver/BUILD b/pkg/kubeapiserver/BUILD index b66f74d9ae1..4a9c0ea5026 100644 --- a/pkg/kubeapiserver/BUILD +++ b/pkg/kubeapiserver/BUILD @@ -22,7 +22,6 @@ go_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", @@ -30,7 +29,6 @@ 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 42582858f7c..f05189d1c89 100644 --- a/pkg/kubeapiserver/default_storage_factory_builder.go +++ b/pkg/kubeapiserver/default_storage_factory_builder.go @@ -26,7 +26,6 @@ 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" @@ -36,7 +35,6 @@ import ( "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. @@ -56,14 +54,9 @@ func NewStorageFactoryConfig() *StorageFactoryConfig { resources := []schema.GroupVersionResource{ batch.Resource("cronjobs").WithVersion("v1beta1"), networking.Resource("ingresses").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")) + // TODO #83513 csinodes override can be removed in 1.18 + apisstorage.Resource("csinodes").WithVersion("v1beta1"), + apisstorage.Resource("csidrivers").WithVersion("v1beta1"), } return &StorageFactoryConfig{ diff --git a/pkg/master/storageversionhashdata/data.go b/pkg/master/storageversionhashdata/data.go index b1dd1c3ece7..a77a8d5639e 100644 --- a/pkg/master/storageversionhashdata/data.go +++ b/pkg/master/storageversionhashdata/data.go @@ -81,6 +81,7 @@ var GVRToStorageVersionHash = map[string]string{ "rbac.authorization.k8s.io/v1beta1/roles": "7FuwZcIIItM=", "scheduling.k8s.io/v1beta1/priorityclasses": "1QwjyaZjj3Y=", "scheduling.k8s.io/v1/priorityclasses": "1QwjyaZjj3Y=", + "storage.k8s.io/v1/csinodes": "Pe62DkZtjuo=", "storage.k8s.io/v1/storageclasses": "K+m6uJwbjGY=", "storage.k8s.io/v1/volumeattachments": "vQAqD28V4AY=", "storage.k8s.io/v1beta1/csidrivers": "hL6j/rwBV5w=", diff --git a/pkg/registry/storage/rest/storage_storage.go b/pkg/registry/storage/rest/storage_storage.go index 9f12063c0ab..1e1ee0059a2 100644 --- a/pkg/registry/storage/rest/storage_storage.go +++ b/pkg/registry/storage/rest/storage_storage.go @@ -135,6 +135,15 @@ func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.API "volumeattachments/status": volumeAttachmentStorage.Status, } + // register csinodes if CSINodeInfo feature gate is enabled + if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { + csiNodeStorage, err := csinodestore.NewStorage(restOptionsGetter) + if err != nil { + return nil, err + } + storage["csinodes"] = csiNodeStorage.CSINode + } + return storage, nil } diff --git a/plugin/pkg/admission/noderestriction/admission_test.go b/plugin/pkg/admission/noderestriction/admission_test.go index d312682c0bc..3e5170ccb41 100644 --- a/plugin/pkg/admission/noderestriction/admission_test.go +++ b/plugin/pkg/admission/noderestriction/admission_test.go @@ -315,8 +315,8 @@ func Test_nodePlugin_Admit(t *testing.T) { }, } - csiNodeResource = storage.Resource("csinodes").WithVersion("v1beta1") - csiNodeKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSINode"} + csiNodeResource = storage.Resource("csinodes").WithVersion("v1") + csiNodeKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "CSINode"} nodeInfo = &storage.CSINode{ ObjectMeta: metav1.ObjectMeta{ Name: "mynode", diff --git a/staging/src/k8s.io/api/storage/v1/register.go b/staging/src/k8s.io/api/storage/v1/register.go index 473c687278b..67493fd0fab 100644 --- a/staging/src/k8s.io/api/storage/v1/register.go +++ b/staging/src/k8s.io/api/storage/v1/register.go @@ -49,6 +49,9 @@ func addKnownTypes(scheme *runtime.Scheme) error { &VolumeAttachment{}, &VolumeAttachmentList{}, + + &CSINode{}, + &CSINodeList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) diff --git a/staging/src/k8s.io/api/storage/v1/types.go b/staging/src/k8s.io/api/storage/v1/types.go index e42ee5e9c59..86cb78b6401 100644 --- a/staging/src/k8s.io/api/storage/v1/types.go +++ b/staging/src/k8s.io/api/storage/v1/types.go @@ -17,7 +17,7 @@ limitations under the License. package v1 import ( - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -216,3 +216,97 @@ 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 + +// 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"` + + // allocatable represents the volume resources of a node that are available for scheduling. + // This field is beta. + // +optional + Allocatable *VolumeNodeResources `json:"allocatable,omitempty" protobuf:"bytes,4,opt,name=allocatable"` +} + +// VolumeNodeResources is a set of resource limits for scheduling of volumes. +type VolumeNodeResources struct { + // Maximum number of unique volumes managed by the CSI driver that can be used on a node. + // A volume that is both attached and mounted on a node is considered to be used once, not twice. + // The same rule applies for a unique volume that is shared among multiple pods on the same node. + // If this field is not specified, then the supported number of volumes on this node is unbounded. + // +optional + Count *int32 `json:"count,omitempty" protobuf:"varint,1,opt,name=count"` +} + +// +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/sig-architecture/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.go b/staging/src/k8s.io/api/storage/v1beta1/types.go index fa1bae1d8d5..a8faeb9d130 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/types.go +++ b/staging/src/k8s.io/api/storage/v1beta1/types.go @@ -348,6 +348,8 @@ const ( // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// DEPRECATED - This group version of CSINode is deprecated by storage/v1/CSINode. +// See the release notes for more information. // 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 diff --git a/test/integration/etcd/data.go b/test/integration/etcd/data.go index 617425e979b..12ed41195f8 100644 --- a/test/integration/etcd/data.go +++ b/test/integration/etcd/data.go @@ -544,13 +544,20 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes // -- } - // k8s.io/kubernetes/pkg/apis/storage/v1beta1 // add csinodes if CSINodeInfo feature gate is enabled if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { + // k8s.io/kubernetes/pkg/apis/storage/v1beta1 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/v1 + etcdStorageData[gvr("storage.k8s.io", "v1", "csinodes")] = StorageData{ + Stub: `{"metadata": {"name": "csini2"}, "spec": {"drivers": [{"name": "test-driver", "nodeID": "localhost", "topologyKeys": ["company.com/zone1", "company.com/zone2"]}]}}`, + ExpectedEtcdPath: "/registry/csinodes/csini2", + ExpectedGVK: gvkP("storage.k8s.io", "v1beta1", "CSINode"), + } } // k8s.io/kubernetes/pkg/apis/storage/v1beta1