From d45a41807e99777f0fbbcfb36e1a8c9c6b8588cd Mon Sep 17 00:00:00 2001 From: NickrenREN Date: Thu, 18 Jan 2018 12:13:09 +0800 Subject: [PATCH] Add Beta VolumeAttachment API --- cmd/kube-apiserver/app/server.go | 2 +- pkg/registry/storage/rest/storage_storage.go | 4 + .../storage/volumeattachment/storage/BUILD | 1 + .../volumeattachment/storage/storage_test.go | 31 +++-- .../k8s.io/api/storage/v1beta1/register.go | 3 + .../src/k8s.io/api/storage/v1beta1/types.go | 107 ++++++++++++++++++ .../etcd/etcd_storage_path_test.go | 7 ++ 7 files changed, 142 insertions(+), 13 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index eb30d96f067..10ed13387b5 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -586,7 +586,7 @@ func BuildStorageFactory(s *options.ServerRunOptions, apiResourceConfig *servers // FIXME (soltysh): this GroupVersionResource override should be configurable []schema.GroupVersionResource{ batch.Resource("cronjobs").WithVersion("v1beta1"), - storage.Resource("volumeattachments").WithVersion("v1alpha1"), + storage.Resource("volumeattachments").WithVersion("v1beta1"), admissionregistration.Resource("initializerconfigurations").WithVersion("v1alpha1"), }, apiResourceConfig) diff --git a/pkg/registry/storage/rest/storage_storage.go b/pkg/registry/storage/rest/storage_storage.go index f8eaf24b6d6..3b581c113c2 100644 --- a/pkg/registry/storage/rest/storage_storage.go +++ b/pkg/registry/storage/rest/storage_storage.go @@ -69,6 +69,10 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag storageClassStorage := storageclassstore.NewREST(restOptionsGetter) storage["storageclasses"] = storageClassStorage + // volumeattachments + volumeAttachmentStorage := volumeattachmentstore.NewREST(restOptionsGetter) + storage["volumeattachments"] = volumeAttachmentStorage + return storage } diff --git a/pkg/registry/storage/volumeattachment/storage/BUILD b/pkg/registry/storage/volumeattachment/storage/BUILD index 1442fae44e6..f6bf4f44455 100644 --- a/pkg/registry/storage/volumeattachment/storage/BUILD +++ b/pkg/registry/storage/volumeattachment/storage/BUILD @@ -24,6 +24,7 @@ go_test( "//pkg/apis/storage:go_default_library", "//pkg/registry/registrytest:go_default_library", "//vendor/k8s.io/api/storage/v1alpha1:go_default_library", + "//vendor/k8s.io/api/storage/v1beta1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", diff --git a/pkg/registry/storage/volumeattachment/storage/storage_test.go b/pkg/registry/storage/volumeattachment/storage/storage_test.go index 540255de895..7e2d389af6a 100644 --- a/pkg/registry/storage/volumeattachment/storage/storage_test.go +++ b/pkg/registry/storage/volumeattachment/storage/storage_test.go @@ -20,6 +20,7 @@ import ( "testing" storageapiv1alpha1 "k8s.io/api/storage/v1alpha1" + storageapiv1beta1 "k8s.io/api/storage/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" @@ -61,8 +62,9 @@ func validNewVolumeAttachment(name string) *storageapi.VolumeAttachment { } func TestCreate(t *testing.T) { - if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion { - // skip the test for all versions exception v1alpha1 + if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion && + *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1alpha1 and v1beta1 return } @@ -91,8 +93,9 @@ func TestCreate(t *testing.T) { } func TestUpdate(t *testing.T) { - if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion { - // skip the test for all versions except v1alpha1 + if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion && + *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1alpha1 and v1beta1 return } @@ -119,8 +122,9 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion { - // skip the test for all versions except v1alpha1 + if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion && + *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1alpha1 and v1beta1 return } @@ -132,8 +136,9 @@ func TestDelete(t *testing.T) { } func TestGet(t *testing.T) { - if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion { - // skip the test for all versions except v1alpha1 + if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion && + *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1alpha1 and v1beta1 return } @@ -145,8 +150,9 @@ func TestGet(t *testing.T) { } func TestList(t *testing.T) { - if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion { - // skip the test for all versions except v1alpha1 + if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion && + *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1alpha1 and v1beta1 return } @@ -158,8 +164,9 @@ func TestList(t *testing.T) { } func TestWatch(t *testing.T) { - if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion { - // skip the test for all versions except v1alpha1 + if *testapi.Storage.GroupVersion() != storageapiv1alpha1.SchemeGroupVersion && + *testapi.Storage.GroupVersion() != storageapiv1beta1.SchemeGroupVersion { + // skip the test for all versions exception v1alpha1 and v1beta1 return } diff --git a/staging/src/k8s.io/api/storage/v1beta1/register.go b/staging/src/k8s.io/api/storage/v1beta1/register.go index 7f1f0c8e835..06b0f3d5299 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/register.go +++ b/staging/src/k8s.io/api/storage/v1beta1/register.go @@ -46,6 +46,9 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &StorageClass{}, &StorageClassList{}, + + &VolumeAttachment{}, + &VolumeAttachmentList{}, ) 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 7fb9ad98077..99c9e4594d8 100644 --- a/staging/src/k8s.io/api/storage/v1beta1/types.go +++ b/staging/src/k8s.io/api/storage/v1beta1/types.go @@ -96,3 +96,110 @@ const ( // binding will occur during Pod scheduing. VolumeBindingWaitForFirstConsumer VolumeBindingMode = "WaitForFirstConsumer" ) + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeAttachment captures the intent to attach or detach the specified volume +// to/from the specified node. +// +// VolumeAttachment objects are non-namespaced. +type VolumeAttachment struct { + metav1.TypeMeta `json:",inline"` + + // Standard object metadata. + // More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Specification of the desired attach/detach volume behavior. + // Populated by the Kubernetes system. + Spec VolumeAttachmentSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"` + + // Status of the VolumeAttachment request. + // Populated by the entity completing the attach or detach + // operation, i.e. the external-attacher. + // +optional + Status VolumeAttachmentStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeAttachmentList is a collection of VolumeAttachment objects. +type VolumeAttachmentList 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 VolumeAttachments + Items []VolumeAttachment `json:"items" protobuf:"bytes,2,rep,name=items"` +} + +// VolumeAttachmentSpec is the specification of a VolumeAttachment request. +type VolumeAttachmentSpec struct { + // Attacher indicates the name of the volume driver that MUST handle this + // request. This is the name returned by GetPluginName(). + Attacher string `json:"attacher" protobuf:"bytes,1,opt,name=attacher"` + + // Source represents the volume that should be attached. + Source VolumeAttachmentSource `json:"source" protobuf:"bytes,2,opt,name=source"` + + // The node that the volume should be attached to. + NodeName string `json:"nodeName" protobuf:"bytes,3,opt,name=nodeName"` +} + +// VolumeAttachmentSource represents a volume that should be attached. +// Right now only PersistenVolumes can be attached via external attacher, +// in future we may allow also inline volumes in pods. +// Exactly one member can be set. +type VolumeAttachmentSource struct { + // Name of the persistent volume to attach. + // +optional + PersistentVolumeName *string `json:"persistentVolumeName,omitempty" protobuf:"bytes,1,opt,name=persistentVolumeName"` + + // Placeholder for *VolumeSource to accommodate inline volumes in pods. +} + +// VolumeAttachmentStatus is the status of a VolumeAttachment request. +type VolumeAttachmentStatus struct { + // Indicates the volume is successfully attached. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + Attached bool `json:"attached" protobuf:"varint,1,opt,name=attached"` + + // Upon successful attach, this field is populated with any + // information returned by the attach operation that must be passed + // into subsequent WaitForAttach or Mount calls. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + // +optional + AttachmentMetadata map[string]string `json:"attachmentMetadata,omitempty" protobuf:"bytes,2,rep,name=attachmentMetadata"` + + // The last error encountered during attach operation, if any. + // This field must only be set by the entity completing the attach + // operation, i.e. the external-attacher. + // +optional + AttachError *VolumeError `json:"attachError,omitempty" protobuf:"bytes,3,opt,name=attachError,casttype=VolumeError"` + + // The last error encountered during detach operation, if any. + // This field must only be set by the entity completing the detach + // operation, i.e. the external-attacher. + // +optional + DetachError *VolumeError `json:"detachError,omitempty" protobuf:"bytes,4,opt,name=detachError,casttype=VolumeError"` +} + +// VolumeError captures an error encountered during a volume operation. +type VolumeError struct { + // Time the error was encountered. + // +optional + Time metav1.Time `json:"time,omitempty" protobuf:"bytes,1,opt,name=time"` + + // String detailing the error encountered during Attach or Detach operation. + // This string maybe logged, so it should not contain sensitive + // information. + // +optional + Message string `json:"message,omitempty" protobuf:"bytes,2,opt,name=message"` +} diff --git a/test/integration/etcd/etcd_storage_path_test.go b/test/integration/etcd/etcd_storage_path_test.go index 6a5b6998008..480cbfd8483 100644 --- a/test/integration/etcd/etcd_storage_path_test.go +++ b/test/integration/etcd/etcd_storage_path_test.go @@ -301,6 +301,13 @@ var etcdStorageData = map[schema.GroupVersionResource]struct { }, // -- + // k8s.io/kubernetes/pkg/apis/storage/v1beta1 + gvr("storage.k8s.io", "v1beta1", "volumeattachments"): { + stub: `{"metadata": {"name": "va2"}, "spec": {"attacher": "gce", "nodeName": "localhost", "source": {"persistentVolumeName": "pv2"}}}`, + expectedEtcdPath: "/registry/volumeattachments/va2", + }, + // -- + // k8s.io/kubernetes/pkg/apis/storage/v1beta1 gvr("storage.k8s.io", "v1beta1", "storageclasses"): { stub: `{"metadata": {"name": "sc1"}, "provisioner": "aws"}`,