Add CSINode to storage/v1

This commit is contained in:
Michelle Au 2019-10-02 18:47:48 -07:00
parent 2a1ac8bb8c
commit 603a2aa8a9
11 changed files with 127 additions and 17 deletions

View File

@ -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,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,VolumeMounts
API rule violation: list_type_missing,k8s.io/api/settings/v1alpha1,PodPresetSpec,Volumes 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,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,StorageClass,MountOptions
API rule violation: list_type_missing,k8s.io/api/storage/v1,StorageClassList,Items API rule violation: list_type_missing,k8s.io/api/storage/v1,StorageClassList,Items

View File

@ -405,7 +405,7 @@ type VolumeNodeResources struct {
// Maximum number of unique volumes managed by the CSI driver that can be used on a node. // 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. // 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. // 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 // +optional
Count *int32 Count *int32
} }

View File

@ -22,7 +22,6 @@ go_library(
"//pkg/apis/networking:go_default_library", "//pkg/apis/networking:go_default_library",
"//pkg/apis/policy:go_default_library", "//pkg/apis/policy:go_default_library",
"//pkg/apis/storage: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:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema: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", "//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/resourceconfig:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/server/storage: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/storage/storagebackend:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
], ],
) )

View File

@ -26,7 +26,6 @@ import (
"k8s.io/apiserver/pkg/server/resourceconfig" "k8s.io/apiserver/pkg/server/resourceconfig"
serverstorage "k8s.io/apiserver/pkg/server/storage" serverstorage "k8s.io/apiserver/pkg/server/storage"
"k8s.io/apiserver/pkg/storage/storagebackend" "k8s.io/apiserver/pkg/storage/storagebackend"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/batch"
@ -36,7 +35,6 @@ import (
"k8s.io/kubernetes/pkg/apis/networking" "k8s.io/kubernetes/pkg/apis/networking"
"k8s.io/kubernetes/pkg/apis/policy" "k8s.io/kubernetes/pkg/apis/policy"
apisstorage "k8s.io/kubernetes/pkg/apis/storage" apisstorage "k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/features"
) )
// SpecialDefaultResourcePrefixes are prefixes compiled into Kubernetes. // SpecialDefaultResourcePrefixes are prefixes compiled into Kubernetes.
@ -56,14 +54,9 @@ func NewStorageFactoryConfig() *StorageFactoryConfig {
resources := []schema.GroupVersionResource{ resources := []schema.GroupVersionResource{
batch.Resource("cronjobs").WithVersion("v1beta1"), batch.Resource("cronjobs").WithVersion("v1beta1"),
networking.Resource("ingresses").WithVersion("v1beta1"), networking.Resource("ingresses").WithVersion("v1beta1"),
} // TODO #83513 csinodes override can be removed in 1.18
// add csinodes if CSINodeInfo feature gate is enabled apisstorage.Resource("csinodes").WithVersion("v1beta1"),
if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { apisstorage.Resource("csidrivers").WithVersion("v1beta1"),
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{ return &StorageFactoryConfig{

View File

@ -81,6 +81,7 @@ var GVRToStorageVersionHash = map[string]string{
"rbac.authorization.k8s.io/v1beta1/roles": "7FuwZcIIItM=", "rbac.authorization.k8s.io/v1beta1/roles": "7FuwZcIIItM=",
"scheduling.k8s.io/v1beta1/priorityclasses": "1QwjyaZjj3Y=", "scheduling.k8s.io/v1beta1/priorityclasses": "1QwjyaZjj3Y=",
"scheduling.k8s.io/v1/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/storageclasses": "K+m6uJwbjGY=",
"storage.k8s.io/v1/volumeattachments": "vQAqD28V4AY=", "storage.k8s.io/v1/volumeattachments": "vQAqD28V4AY=",
"storage.k8s.io/v1beta1/csidrivers": "hL6j/rwBV5w=", "storage.k8s.io/v1beta1/csidrivers": "hL6j/rwBV5w=",

View File

@ -135,6 +135,15 @@ func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.API
"volumeattachments/status": volumeAttachmentStorage.Status, "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 return storage, nil
} }

View File

@ -315,8 +315,8 @@ func Test_nodePlugin_Admit(t *testing.T) {
}, },
} }
csiNodeResource = storage.Resource("csinodes").WithVersion("v1beta1") csiNodeResource = storage.Resource("csinodes").WithVersion("v1")
csiNodeKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1beta1", Kind: "CSINode"} csiNodeKind = schema.GroupVersionKind{Group: "storage.k8s.io", Version: "v1", Kind: "CSINode"}
nodeInfo = &storage.CSINode{ nodeInfo = &storage.CSINode{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: "mynode", Name: "mynode",

View File

@ -49,6 +49,9 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&VolumeAttachment{}, &VolumeAttachment{},
&VolumeAttachmentList{}, &VolumeAttachmentList{},
&CSINode{},
&CSINodeList{},
) )
metav1.AddToGroupVersion(scheme, SchemeGroupVersion) metav1.AddToGroupVersion(scheme, SchemeGroupVersion)

View File

@ -17,7 +17,7 @@ limitations under the License.
package v1 package v1
import ( import (
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@ -216,3 +216,97 @@ type VolumeError struct {
// +optional // +optional
Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"` 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"`
}

View File

@ -348,6 +348,8 @@ const (
// +genclient:nonNamespaced // +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +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. // 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 // 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 // they use the node-driver-registrar sidecar container, the kubelet will

View File

@ -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 // add csinodes if CSINodeInfo feature gate is enabled
if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) { if utilfeature.DefaultFeatureGate.Enabled(features.CSINodeInfo) {
// k8s.io/kubernetes/pkg/apis/storage/v1beta1
etcdStorageData[gvr("storage.k8s.io", "v1beta1", "csinodes")] = StorageData{ 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"]}]}}`, Stub: `{"metadata": {"name": "csini1"}, "spec": {"drivers": [{"name": "test-driver", "nodeID": "localhost", "topologyKeys": ["company.com/zone1", "company.com/zone2"]}]}}`,
ExpectedEtcdPath: "/registry/csinodes/csini1", 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 // k8s.io/kubernetes/pkg/apis/storage/v1beta1