diff --git a/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go b/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go index 51414fbdbc2..b0ffbf4f91a 100644 --- a/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go +++ b/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go @@ -87,6 +87,7 @@ func New() *Generator { `k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1`, `k8s.io/kubernetes/pkg/apis/settings/v1alpha1`, `k8s.io/kubernetes/pkg/apis/storage/v1beta1`, + `k8s.io/kubernetes/pkg/apis/storage/v1`, }, ","), DropEmbeddedFields: "k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta", } diff --git a/hack/lib/init.sh b/hack/lib/init.sh index 812c8682b03..a07f6f2e123 100644 --- a/hack/lib/init.sh +++ b/hack/lib/init.sh @@ -70,6 +70,7 @@ rbac.authorization.k8s.io/v1beta1 \ rbac.authorization.k8s.io/v1alpha1 \ settings.k8s.io/v1alpha1 \ storage.k8s.io/v1beta1 \ +storage.k8s.io/v1\ }" # not all group versions are exposed by the server. This list contains those diff --git a/hack/make-rules/test-cmd-util.sh b/hack/make-rules/test-cmd-util.sh index e1b8c78ab66..e7cb8407d9f 100644 --- a/hack/make-rules/test-cmd-util.sh +++ b/hack/make-rules/test-cmd-util.sh @@ -3282,7 +3282,7 @@ runTests() { kubectl create -f - "${kube_flags[@]}" << __EOF__ { "kind": "StorageClass", - "apiVersion": "storage.k8s.io/v1beta1", + "apiVersion": "storage.k8s.io/v1", "metadata": { "name": "storage-class-name" }, diff --git a/pkg/apis/storage/install/install.go b/pkg/apis/storage/install/install.go index 955c7e79dbf..8ba3050dcf9 100644 --- a/pkg/apis/storage/install/install.go +++ b/pkg/apis/storage/install/install.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/storage" + "k8s.io/kubernetes/pkg/apis/storage/v1" "k8s.io/kubernetes/pkg/apis/storage/v1beta1" ) @@ -36,13 +37,15 @@ func init() { func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) { if err := announced.NewGroupMetaFactory( &announced.GroupMetaFactoryArgs{ - GroupName: storage.GroupName, - VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version}, + GroupName: storage.GroupName, + // TODO: change the order when GKE supports v1 + VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version, v1.SchemeGroupVersion.Version}, ImportPrefix: "k8s.io/kubernetes/pkg/apis/storage", RootScopedKinds: sets.NewString("StorageClass"), AddInternalObjectsToScheme: storage.AddToScheme, }, announced.VersionToSchemeFunc{ + v1.SchemeGroupVersion.Version: v1.AddToScheme, v1beta1.SchemeGroupVersion.Version: v1beta1.AddToScheme, }, ).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil { diff --git a/pkg/apis/storage/v1/doc.go b/pkg/apis/storage/v1/doc.go new file mode 100644 index 00000000000..32f99daea9a --- /dev/null +++ b/pkg/apis/storage/v1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2017 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. +*/ + +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/storage +// +groupName=storage.k8s.io +// +k8s:openapi-gen=true +// +k8s:defaulter-gen=TypeMeta +package v1 diff --git a/pkg/apis/storage/v1/register.go b/pkg/apis/storage/v1/register.go new file mode 100644 index 00000000000..24d6bfa7d3b --- /dev/null +++ b/pkg/apis/storage/v1/register.go @@ -0,0 +1,50 @@ +/* +Copyright 2017 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "storage.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &StorageClass{}, + &StorageClassList{}, + ) + + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/storage/v1/types.go b/pkg/apis/storage/v1/types.go new file mode 100644 index 00000000000..25b283b81fc --- /dev/null +++ b/pkg/apis/storage/v1/types.go @@ -0,0 +1,57 @@ +/* +Copyright 2017 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient=true +// +nonNamespaced=true + +// StorageClass describes the parameters for a class of storage for +// which PersistentVolumes can be dynamically provisioned. +// +// StorageClasses are non-namespaced; the name of the storage class +// according to etcd is in ObjectMeta.Name. +type StorageClass struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Provisioner indicates the type of the provisioner. + Provisioner string `json:"provisioner"` + + // Parameters holds the parameters for the provisioner that should + // create volumes of this storage class. + // +optional + Parameters map[string]string `json:"parameters,omitempty"` +} + +// StorageClassList is a collection of storage classes. +type StorageClassList struct { + metav1.TypeMeta `json:",inline"` + // Standard list metadata + // More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + // Items is the list of StorageClasses + Items []StorageClass `json:"items"` +} diff --git a/pkg/apis/storage/v1/util/helpers.go b/pkg/apis/storage/v1/util/helpers.go new file mode 100644 index 00000000000..39c4f6f3ed5 --- /dev/null +++ b/pkg/apis/storage/v1/util/helpers.go @@ -0,0 +1,137 @@ +/* +Copyright 2016 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 util + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubernetes/pkg/api/v1" +) + +// IsDefaultStorageClassAnnotation represents a StorageClass annotation that +// marks a class as the default StorageClass +//TODO: Update IsDefaultStorageClassannotation and remove Beta when no longer used +const IsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class" +const BetaIsDefaultStorageClassAnnotation = "storageclass.beta.kubernetes.io/is-default-class" + +// AlphaStorageClassAnnotation represents the previous alpha storage class +// annotation. it's no longer used and held here for posterity. +const AlphaStorageClassAnnotation = "volume.alpha.kubernetes.io/storage-class" + +// BetaStorageClassAnnotation represents the beta/previous StorageClass annotation. +// It's currently still used and will be held for backwards compatibility +const BetaStorageClassAnnotation = "volume.beta.kubernetes.io/storage-class" + +// StorageClassAnnotation represents the storage class associated with a resource. +// It currently matches the Beta value and can change when official is set. +// - in PersistentVolumeClaim it represents required class to match. +// Only PersistentVolumes with the same class (i.e. annotation with the same +// value) can be bound to the claim. In case no such volume exists, the +// controller will provision a new one using StorageClass instance with +// the same name as the annotation value. +// - in PersistentVolume it represents storage class to which the persistent +// volume belongs. +//TODO: Update this to final annotation value as it matches BetaStorageClassAnnotation for now +const StorageClassAnnotation = "volume.beta.kubernetes.io/storage-class" + +// GetVolumeStorageClass returns value of StorageClassAnnotation or empty string in case +// the annotation does not exist. +// TODO: change to PersistentVolume.Spec.Class value when this attribute is +// introduced. +func GetVolumeStorageClass(volume *v1.PersistentVolume) string { + if class, found := volume.Annotations[StorageClassAnnotation]; found { + return class + } + + // 'nil' is interpreted as "", i.e. the volume does not belong to any class. + return "" +} + +// GetClaimStorageClass returns name of class that is requested by given claim. +// Request for `nil` class is interpreted as request for class "", +// i.e. for a classless PV. +// TODO: change to PersistentVolumeClaim.Spec.Class value when this +// attribute is introduced. +func GetClaimStorageClass(claim *v1.PersistentVolumeClaim) string { + if class, found := claim.Annotations[StorageClassAnnotation]; found { + return class + } + + return "" +} + +// GetStorageClassAnnotation returns the StorageClass value +// if the annotation is set, empty string if not +// TODO: remove Alpha and Beta when no longer used or needed +func GetStorageClassAnnotation(obj metav1.ObjectMeta) string { + if class, ok := obj.Annotations[StorageClassAnnotation]; ok { + return class + } + if class, ok := obj.Annotations[BetaStorageClassAnnotation]; ok { + return class + } + if class, ok := obj.Annotations[AlphaStorageClassAnnotation]; ok { + return class + } + + return "" +} + +// HasStorageClassAnnotation returns a boolean +// if the annotation is set +// TODO: remove Alpha and Beta when no longer used or needed +func HasStorageClassAnnotation(obj metav1.ObjectMeta) bool { + if _, found := obj.Annotations[StorageClassAnnotation]; found { + return found + } + if _, found := obj.Annotations[BetaStorageClassAnnotation]; found { + return found + } + if _, found := obj.Annotations[AlphaStorageClassAnnotation]; found { + return found + } + + return false + +} + +// IsDefaultAnnotationText returns a pretty Yes/No String if +// the annotation is set +// TODO: remove Beta when no longer needed +func IsDefaultAnnotationText(obj metav1.ObjectMeta) string { + if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" { + return "Yes" + } + if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" { + return "Yes" + } + + return "No" +} + +// IsDefaultAnnotation returns a boolean if +// the annotation is set +// TODO: remove Beta when no longer needed +func IsDefaultAnnotation(obj metav1.ObjectMeta) bool { + if obj.Annotations[IsDefaultStorageClassAnnotation] == "true" { + return true + } + if obj.Annotations[BetaIsDefaultStorageClassAnnotation] == "true" { + return true + } + + return false +} diff --git a/pkg/master/master.go b/pkg/master/master.go index c50b5224ec5..ea0f87232b3 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -46,6 +46,7 @@ import ( rbacapi "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" settingsapi "k8s.io/kubernetes/pkg/apis/settings/v1alpha1" + storageapiv1 "k8s.io/kubernetes/pkg/apis/storage/v1" storageapiv1beta1 "k8s.io/kubernetes/pkg/apis/storage/v1beta1" corev1client "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" @@ -375,6 +376,7 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig { rbacv1beta1.SchemeGroupVersion, rbacapi.SchemeGroupVersion, settingsapi.SchemeGroupVersion, + storageapiv1.SchemeGroupVersion, storageapiv1beta1.SchemeGroupVersion, certificatesapiv1beta1.SchemeGroupVersion, authorizationapiv1.SchemeGroupVersion, diff --git a/pkg/registry/storage/rest/storage_storage.go b/pkg/registry/storage/rest/storage_storage.go index 31239b00213..c12f8038243 100644 --- a/pkg/registry/storage/rest/storage_storage.go +++ b/pkg/registry/storage/rest/storage_storage.go @@ -23,6 +23,7 @@ import ( serverstorage "k8s.io/apiserver/pkg/server/storage" "k8s.io/kubernetes/pkg/api" storageapi "k8s.io/kubernetes/pkg/apis/storage" + storageapiv1 "k8s.io/kubernetes/pkg/apis/storage/v1" storageapiv1beta1 "k8s.io/kubernetes/pkg/apis/storage/v1beta1" storageclassstore "k8s.io/kubernetes/pkg/registry/storage/storageclass/storage" ) @@ -37,6 +38,10 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorag apiGroupInfo.VersionedResourcesStorageMap[storageapiv1beta1.SchemeGroupVersion.Version] = p.v1beta1Storage(apiResourceConfigSource, restOptionsGetter) apiGroupInfo.GroupMeta.GroupVersion = storageapiv1beta1.SchemeGroupVersion } + if apiResourceConfigSource.AnyResourcesForVersionEnabled(storageapiv1.SchemeGroupVersion) { + apiGroupInfo.VersionedResourcesStorageMap[storageapiv1.SchemeGroupVersion.Version] = p.v1Storage(apiResourceConfigSource, restOptionsGetter) + apiGroupInfo.GroupMeta.GroupVersion = storageapiv1.SchemeGroupVersion + } return apiGroupInfo, true } @@ -54,6 +59,19 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag return storage } +func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage { + version := storageapiv1.SchemeGroupVersion + + storage := map[string]rest.Storage{} + + if apiResourceConfigSource.ResourceEnabled(version.WithResource("storageclasses")) { + storageClassStorage := storageclassstore.NewREST(restOptionsGetter) + storage["storageclasses"] = storageClassStorage + } + + return storage +} + func (p RESTStorageProvider) GroupName() string { return storageapi.GroupName }