feat: implements Storage Version Migration API in-tree

Signed-off-by: Nilekh Chaudhari <1626598+nilekhc@users.noreply.github.com>
This commit is contained in:
Nilekh Chaudhari
2023-10-10 20:23:08 +00:00
parent 7ea3d0245a
commit 91a7708cdc
97 changed files with 10227 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
/*
Copyright 2024 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
// +groupName=storagemigration.k8s.io
package storagemigration // import "k8s.io/kubernetes/pkg/apis/storagemigration"

View File

@@ -0,0 +1,37 @@
/*
Copyright 2024 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 install
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/storagemigration"
"k8s.io/kubernetes/pkg/apis/storagemigration/v1alpha1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
func init() {
Install(legacyscheme.Scheme)
}
// Install registers the API group and adds types to a scheme
func Install(scheme *runtime.Scheme) {
utilruntime.Must(storagemigration.AddToScheme(scheme))
utilruntime.Must(v1alpha1.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(v1alpha1.SchemeGroupVersion))
}

View File

@@ -0,0 +1,51 @@
/*
Copyright 2024 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 storagemigration
import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "storagemigration.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
// Kind takes an unqualified kind and returns a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
return SchemeGroupVersion.WithKind(kind).GroupKind()
}
// 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
)
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&StorageVersionMigration{},
&StorageVersionMigrationList{},
)
return nil
}

View File

@@ -0,0 +1,131 @@
/*
Copyright 2024 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 storagemigration
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.30
// StorageVersionMigration represents a migration of stored data to the latest
// storage version.
type StorageVersionMigration struct {
metav1.TypeMeta
// Standard object metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ObjectMeta
// Specification of the migration.
// +optional
Spec StorageVersionMigrationSpec
// Status of the migration.
// +optional
Status StorageVersionMigrationStatus
}
// Spec of the storage version migration.
type StorageVersionMigrationSpec struct {
// The resource that is being migrated. The migrator sends requests to
// the endpoint serving the resource.
// Immutable.
Resource GroupVersionResource
// The token used in the list options to get the next chunk of objects
// to migrate. When the .status.conditions indicates the migration is
// "Running", users can use this token to check the progress of the
// migration.
// +optional
ContinueToken string
// TODO: consider recording the storage version hash when the migration
// is created. It can avoid races.
}
// The names of the group, the version, and the resource.
type GroupVersionResource struct {
// The name of the group.
Group string
// The name of the version.
Version string
// The name of the resource.
Resource string
}
type MigrationConditionType string
const (
// Indicates that the migration is running.
MigrationRunning MigrationConditionType = "Running"
// Indicates that the migration has completed successfully.
MigrationSucceeded MigrationConditionType = "Succeeded"
// Indicates that the migration has failed.
MigrationFailed MigrationConditionType = "Failed"
)
// Describes the state of a migration at a certain point.
type MigrationCondition struct {
// Type of the condition.
Type MigrationConditionType
// Status of the condition, one of True, False, Unknown.
Status corev1.ConditionStatus
// The last time this condition was updated.
// +optional
LastUpdateTime metav1.Time
// The reason for the condition's last transition.
// +optional
Reason string
// A human readable message indicating details about the transition.
// +optional
Message string
}
// Status of the storage version migration.
type StorageVersionMigrationStatus struct {
// The latest available observations of the migration's current state.
// +patchMergeKey=type
// +patchStrategy=merge
// +listType=map
// +listMapKey=type
// +optional
Conditions []MigrationCondition
// ResourceVersion to compare with the GC cache for performing the migration.
// This is the current resource version of given group, version and resource when
// kube-controller-manager first observes this StorageVersionMigration resource.
ResourceVersion string
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.30
// StorageVersionMigrationList is a collection of storage version migrations.
type StorageVersionMigrationList struct {
metav1.TypeMeta
// Standard list metadata
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ListMeta
// Items is the list of StorageVersionMigration
// +patchMergeKey=type
// +patchStrategy=merge
// +listType=map
// +listMapKey=type
Items []StorageVersionMigration
}

View File

@@ -0,0 +1,23 @@
/*
Copyright 2024 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:conversion-gen=k8s.io/kubernetes/pkg/apis/storagemigration
// +k8s:conversion-gen-external-types=k8s.io/api/storagemigration/v1alpha1
// +groupName=storagemigration.k8s.io
// +k8s:defaulter-gen=TypeMeta
// +k8s:defaulter-gen-input=k8s.io/api/storagemigration/v1alpha1
package v1alpha1 // import "k8s.io/kubernetes/pkg/apis/storagemigration/v1alpha1"

View File

@@ -0,0 +1,39 @@
/*
Copyright 2024 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 v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
svmv1alpha1 "k8s.io/api/storagemigration/v1alpha1"
)
// GroupName is the group name use in this package
const GroupName = "storagemigration.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
localSchemeBuilder = &svmv1alpha1.SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)

View File

@@ -0,0 +1,256 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
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 conversion-gen. DO NOT EDIT.
package v1alpha1
import (
unsafe "unsafe"
v1 "k8s.io/api/core/v1"
v1alpha1 "k8s.io/api/storagemigration/v1alpha1"
conversion "k8s.io/apimachinery/pkg/conversion"
runtime "k8s.io/apimachinery/pkg/runtime"
storagemigration "k8s.io/kubernetes/pkg/apis/storagemigration"
)
func init() {
localSchemeBuilder.Register(RegisterConversions)
}
// RegisterConversions adds conversion functions to the given scheme.
// Public to allow building arbitrary schemes.
func RegisterConversions(s *runtime.Scheme) error {
if err := s.AddGeneratedConversionFunc((*v1alpha1.GroupVersionResource)(nil), (*storagemigration.GroupVersionResource)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_GroupVersionResource_To_storagemigration_GroupVersionResource(a.(*v1alpha1.GroupVersionResource), b.(*storagemigration.GroupVersionResource), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*storagemigration.GroupVersionResource)(nil), (*v1alpha1.GroupVersionResource)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_storagemigration_GroupVersionResource_To_v1alpha1_GroupVersionResource(a.(*storagemigration.GroupVersionResource), b.(*v1alpha1.GroupVersionResource), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha1.MigrationCondition)(nil), (*storagemigration.MigrationCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_MigrationCondition_To_storagemigration_MigrationCondition(a.(*v1alpha1.MigrationCondition), b.(*storagemigration.MigrationCondition), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*storagemigration.MigrationCondition)(nil), (*v1alpha1.MigrationCondition)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_storagemigration_MigrationCondition_To_v1alpha1_MigrationCondition(a.(*storagemigration.MigrationCondition), b.(*v1alpha1.MigrationCondition), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha1.StorageVersionMigration)(nil), (*storagemigration.StorageVersionMigration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_StorageVersionMigration_To_storagemigration_StorageVersionMigration(a.(*v1alpha1.StorageVersionMigration), b.(*storagemigration.StorageVersionMigration), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*storagemigration.StorageVersionMigration)(nil), (*v1alpha1.StorageVersionMigration)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_storagemigration_StorageVersionMigration_To_v1alpha1_StorageVersionMigration(a.(*storagemigration.StorageVersionMigration), b.(*v1alpha1.StorageVersionMigration), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha1.StorageVersionMigrationList)(nil), (*storagemigration.StorageVersionMigrationList)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_StorageVersionMigrationList_To_storagemigration_StorageVersionMigrationList(a.(*v1alpha1.StorageVersionMigrationList), b.(*storagemigration.StorageVersionMigrationList), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*storagemigration.StorageVersionMigrationList)(nil), (*v1alpha1.StorageVersionMigrationList)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_storagemigration_StorageVersionMigrationList_To_v1alpha1_StorageVersionMigrationList(a.(*storagemigration.StorageVersionMigrationList), b.(*v1alpha1.StorageVersionMigrationList), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha1.StorageVersionMigrationSpec)(nil), (*storagemigration.StorageVersionMigrationSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_StorageVersionMigrationSpec_To_storagemigration_StorageVersionMigrationSpec(a.(*v1alpha1.StorageVersionMigrationSpec), b.(*storagemigration.StorageVersionMigrationSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*storagemigration.StorageVersionMigrationSpec)(nil), (*v1alpha1.StorageVersionMigrationSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_storagemigration_StorageVersionMigrationSpec_To_v1alpha1_StorageVersionMigrationSpec(a.(*storagemigration.StorageVersionMigrationSpec), b.(*v1alpha1.StorageVersionMigrationSpec), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*v1alpha1.StorageVersionMigrationStatus)(nil), (*storagemigration.StorageVersionMigrationStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_v1alpha1_StorageVersionMigrationStatus_To_storagemigration_StorageVersionMigrationStatus(a.(*v1alpha1.StorageVersionMigrationStatus), b.(*storagemigration.StorageVersionMigrationStatus), scope)
}); err != nil {
return err
}
if err := s.AddGeneratedConversionFunc((*storagemigration.StorageVersionMigrationStatus)(nil), (*v1alpha1.StorageVersionMigrationStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
return Convert_storagemigration_StorageVersionMigrationStatus_To_v1alpha1_StorageVersionMigrationStatus(a.(*storagemigration.StorageVersionMigrationStatus), b.(*v1alpha1.StorageVersionMigrationStatus), scope)
}); err != nil {
return err
}
return nil
}
func autoConvert_v1alpha1_GroupVersionResource_To_storagemigration_GroupVersionResource(in *v1alpha1.GroupVersionResource, out *storagemigration.GroupVersionResource, s conversion.Scope) error {
out.Group = in.Group
out.Version = in.Version
out.Resource = in.Resource
return nil
}
// Convert_v1alpha1_GroupVersionResource_To_storagemigration_GroupVersionResource is an autogenerated conversion function.
func Convert_v1alpha1_GroupVersionResource_To_storagemigration_GroupVersionResource(in *v1alpha1.GroupVersionResource, out *storagemigration.GroupVersionResource, s conversion.Scope) error {
return autoConvert_v1alpha1_GroupVersionResource_To_storagemigration_GroupVersionResource(in, out, s)
}
func autoConvert_storagemigration_GroupVersionResource_To_v1alpha1_GroupVersionResource(in *storagemigration.GroupVersionResource, out *v1alpha1.GroupVersionResource, s conversion.Scope) error {
out.Group = in.Group
out.Version = in.Version
out.Resource = in.Resource
return nil
}
// Convert_storagemigration_GroupVersionResource_To_v1alpha1_GroupVersionResource is an autogenerated conversion function.
func Convert_storagemigration_GroupVersionResource_To_v1alpha1_GroupVersionResource(in *storagemigration.GroupVersionResource, out *v1alpha1.GroupVersionResource, s conversion.Scope) error {
return autoConvert_storagemigration_GroupVersionResource_To_v1alpha1_GroupVersionResource(in, out, s)
}
func autoConvert_v1alpha1_MigrationCondition_To_storagemigration_MigrationCondition(in *v1alpha1.MigrationCondition, out *storagemigration.MigrationCondition, s conversion.Scope) error {
out.Type = storagemigration.MigrationConditionType(in.Type)
out.Status = v1.ConditionStatus(in.Status)
out.LastUpdateTime = in.LastUpdateTime
out.Reason = in.Reason
out.Message = in.Message
return nil
}
// Convert_v1alpha1_MigrationCondition_To_storagemigration_MigrationCondition is an autogenerated conversion function.
func Convert_v1alpha1_MigrationCondition_To_storagemigration_MigrationCondition(in *v1alpha1.MigrationCondition, out *storagemigration.MigrationCondition, s conversion.Scope) error {
return autoConvert_v1alpha1_MigrationCondition_To_storagemigration_MigrationCondition(in, out, s)
}
func autoConvert_storagemigration_MigrationCondition_To_v1alpha1_MigrationCondition(in *storagemigration.MigrationCondition, out *v1alpha1.MigrationCondition, s conversion.Scope) error {
out.Type = v1alpha1.MigrationConditionType(in.Type)
out.Status = v1.ConditionStatus(in.Status)
out.LastUpdateTime = in.LastUpdateTime
out.Reason = in.Reason
out.Message = in.Message
return nil
}
// Convert_storagemigration_MigrationCondition_To_v1alpha1_MigrationCondition is an autogenerated conversion function.
func Convert_storagemigration_MigrationCondition_To_v1alpha1_MigrationCondition(in *storagemigration.MigrationCondition, out *v1alpha1.MigrationCondition, s conversion.Scope) error {
return autoConvert_storagemigration_MigrationCondition_To_v1alpha1_MigrationCondition(in, out, s)
}
func autoConvert_v1alpha1_StorageVersionMigration_To_storagemigration_StorageVersionMigration(in *v1alpha1.StorageVersionMigration, out *storagemigration.StorageVersionMigration, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_v1alpha1_StorageVersionMigrationSpec_To_storagemigration_StorageVersionMigrationSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1alpha1_StorageVersionMigrationStatus_To_storagemigration_StorageVersionMigrationStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_v1alpha1_StorageVersionMigration_To_storagemigration_StorageVersionMigration is an autogenerated conversion function.
func Convert_v1alpha1_StorageVersionMigration_To_storagemigration_StorageVersionMigration(in *v1alpha1.StorageVersionMigration, out *storagemigration.StorageVersionMigration, s conversion.Scope) error {
return autoConvert_v1alpha1_StorageVersionMigration_To_storagemigration_StorageVersionMigration(in, out, s)
}
func autoConvert_storagemigration_StorageVersionMigration_To_v1alpha1_StorageVersionMigration(in *storagemigration.StorageVersionMigration, out *v1alpha1.StorageVersionMigration, s conversion.Scope) error {
out.ObjectMeta = in.ObjectMeta
if err := Convert_storagemigration_StorageVersionMigrationSpec_To_v1alpha1_StorageVersionMigrationSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_storagemigration_StorageVersionMigrationStatus_To_v1alpha1_StorageVersionMigrationStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
// Convert_storagemigration_StorageVersionMigration_To_v1alpha1_StorageVersionMigration is an autogenerated conversion function.
func Convert_storagemigration_StorageVersionMigration_To_v1alpha1_StorageVersionMigration(in *storagemigration.StorageVersionMigration, out *v1alpha1.StorageVersionMigration, s conversion.Scope) error {
return autoConvert_storagemigration_StorageVersionMigration_To_v1alpha1_StorageVersionMigration(in, out, s)
}
func autoConvert_v1alpha1_StorageVersionMigrationList_To_storagemigration_StorageVersionMigrationList(in *v1alpha1.StorageVersionMigrationList, out *storagemigration.StorageVersionMigrationList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]storagemigration.StorageVersionMigration)(unsafe.Pointer(&in.Items))
return nil
}
// Convert_v1alpha1_StorageVersionMigrationList_To_storagemigration_StorageVersionMigrationList is an autogenerated conversion function.
func Convert_v1alpha1_StorageVersionMigrationList_To_storagemigration_StorageVersionMigrationList(in *v1alpha1.StorageVersionMigrationList, out *storagemigration.StorageVersionMigrationList, s conversion.Scope) error {
return autoConvert_v1alpha1_StorageVersionMigrationList_To_storagemigration_StorageVersionMigrationList(in, out, s)
}
func autoConvert_storagemigration_StorageVersionMigrationList_To_v1alpha1_StorageVersionMigrationList(in *storagemigration.StorageVersionMigrationList, out *v1alpha1.StorageVersionMigrationList, s conversion.Scope) error {
out.ListMeta = in.ListMeta
out.Items = *(*[]v1alpha1.StorageVersionMigration)(unsafe.Pointer(&in.Items))
return nil
}
// Convert_storagemigration_StorageVersionMigrationList_To_v1alpha1_StorageVersionMigrationList is an autogenerated conversion function.
func Convert_storagemigration_StorageVersionMigrationList_To_v1alpha1_StorageVersionMigrationList(in *storagemigration.StorageVersionMigrationList, out *v1alpha1.StorageVersionMigrationList, s conversion.Scope) error {
return autoConvert_storagemigration_StorageVersionMigrationList_To_v1alpha1_StorageVersionMigrationList(in, out, s)
}
func autoConvert_v1alpha1_StorageVersionMigrationSpec_To_storagemigration_StorageVersionMigrationSpec(in *v1alpha1.StorageVersionMigrationSpec, out *storagemigration.StorageVersionMigrationSpec, s conversion.Scope) error {
if err := Convert_v1alpha1_GroupVersionResource_To_storagemigration_GroupVersionResource(&in.Resource, &out.Resource, s); err != nil {
return err
}
out.ContinueToken = in.ContinueToken
return nil
}
// Convert_v1alpha1_StorageVersionMigrationSpec_To_storagemigration_StorageVersionMigrationSpec is an autogenerated conversion function.
func Convert_v1alpha1_StorageVersionMigrationSpec_To_storagemigration_StorageVersionMigrationSpec(in *v1alpha1.StorageVersionMigrationSpec, out *storagemigration.StorageVersionMigrationSpec, s conversion.Scope) error {
return autoConvert_v1alpha1_StorageVersionMigrationSpec_To_storagemigration_StorageVersionMigrationSpec(in, out, s)
}
func autoConvert_storagemigration_StorageVersionMigrationSpec_To_v1alpha1_StorageVersionMigrationSpec(in *storagemigration.StorageVersionMigrationSpec, out *v1alpha1.StorageVersionMigrationSpec, s conversion.Scope) error {
if err := Convert_storagemigration_GroupVersionResource_To_v1alpha1_GroupVersionResource(&in.Resource, &out.Resource, s); err != nil {
return err
}
out.ContinueToken = in.ContinueToken
return nil
}
// Convert_storagemigration_StorageVersionMigrationSpec_To_v1alpha1_StorageVersionMigrationSpec is an autogenerated conversion function.
func Convert_storagemigration_StorageVersionMigrationSpec_To_v1alpha1_StorageVersionMigrationSpec(in *storagemigration.StorageVersionMigrationSpec, out *v1alpha1.StorageVersionMigrationSpec, s conversion.Scope) error {
return autoConvert_storagemigration_StorageVersionMigrationSpec_To_v1alpha1_StorageVersionMigrationSpec(in, out, s)
}
func autoConvert_v1alpha1_StorageVersionMigrationStatus_To_storagemigration_StorageVersionMigrationStatus(in *v1alpha1.StorageVersionMigrationStatus, out *storagemigration.StorageVersionMigrationStatus, s conversion.Scope) error {
out.Conditions = *(*[]storagemigration.MigrationCondition)(unsafe.Pointer(&in.Conditions))
out.ResourceVersion = in.ResourceVersion
return nil
}
// Convert_v1alpha1_StorageVersionMigrationStatus_To_storagemigration_StorageVersionMigrationStatus is an autogenerated conversion function.
func Convert_v1alpha1_StorageVersionMigrationStatus_To_storagemigration_StorageVersionMigrationStatus(in *v1alpha1.StorageVersionMigrationStatus, out *storagemigration.StorageVersionMigrationStatus, s conversion.Scope) error {
return autoConvert_v1alpha1_StorageVersionMigrationStatus_To_storagemigration_StorageVersionMigrationStatus(in, out, s)
}
func autoConvert_storagemigration_StorageVersionMigrationStatus_To_v1alpha1_StorageVersionMigrationStatus(in *storagemigration.StorageVersionMigrationStatus, out *v1alpha1.StorageVersionMigrationStatus, s conversion.Scope) error {
out.Conditions = *(*[]v1alpha1.MigrationCondition)(unsafe.Pointer(&in.Conditions))
out.ResourceVersion = in.ResourceVersion
return nil
}
// Convert_storagemigration_StorageVersionMigrationStatus_To_v1alpha1_StorageVersionMigrationStatus is an autogenerated conversion function.
func Convert_storagemigration_StorageVersionMigrationStatus_To_v1alpha1_StorageVersionMigrationStatus(in *storagemigration.StorageVersionMigrationStatus, out *v1alpha1.StorageVersionMigrationStatus, s conversion.Scope) error {
return autoConvert_storagemigration_StorageVersionMigrationStatus_To_v1alpha1_StorageVersionMigrationStatus(in, out, s)
}

View File

@@ -0,0 +1,33 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
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 defaulter-gen. DO NOT EDIT.
package v1alpha1
import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// RegisterDefaults adds defaulters functions to the given scheme.
// Public to allow building arbitrary schemes.
// All generated defaulters are covering - they call all nested defaulters.
func RegisterDefaults(scheme *runtime.Scheme) error {
return nil
}

View File

@@ -0,0 +1,227 @@
/*
Copyright 2024 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 validation
import (
"fmt"
"regexp"
"strconv"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/storagemigration"
corev1 "k8s.io/api/core/v1"
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
)
func ValidateStorageVersionMigration(svm *storagemigration.StorageVersionMigration) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&svm.ObjectMeta, false, apimachineryvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...)
allErrs = checkAndAppendError(allErrs, field.NewPath("spec", "resource", "resource"), svm.Spec.Resource.Resource, "resource is required")
allErrs = checkAndAppendError(allErrs, field.NewPath("spec", "resource", "version"), svm.Spec.Resource.Version, "version is required")
return allErrs
}
func ValidateStorageVersionMigrationUpdate(newSVMBundle, oldSVMBundle *storagemigration.StorageVersionMigration) field.ErrorList {
allErrs := ValidateStorageVersionMigration(newSVMBundle)
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&newSVMBundle.ObjectMeta, &oldSVMBundle.ObjectMeta, field.NewPath("metadata"))...)
// prevent changes to the group, version and resource
if newSVMBundle.Spec.Resource.Group != oldSVMBundle.Spec.Resource.Group {
allErrs = append(allErrs, field.Invalid(field.NewPath("group"), newSVMBundle.Spec.Resource.Group, "field is immutable"))
}
if newSVMBundle.Spec.Resource.Version != oldSVMBundle.Spec.Resource.Version {
allErrs = append(allErrs, field.Invalid(field.NewPath("version"), newSVMBundle.Spec.Resource.Version, "field is immutable"))
}
if newSVMBundle.Spec.Resource.Resource != oldSVMBundle.Spec.Resource.Resource {
allErrs = append(allErrs, field.Invalid(field.NewPath("resource"), newSVMBundle.Spec.Resource.Resource, "field is immutable"))
}
return allErrs
}
func ValidateStorageVersionMigrationStatusUpdate(newSVMBundle, oldSVMBundle *storagemigration.StorageVersionMigration) field.ErrorList {
allErrs := apivalidation.ValidateObjectMetaUpdate(&newSVMBundle.ObjectMeta, &oldSVMBundle.ObjectMeta, field.NewPath("metadata"))
fldPath := field.NewPath("status")
// resource version should be a non-negative integer
rvInt, err := convertResourceVersionToInt(newSVMBundle.Status.ResourceVersion)
if err != nil {
allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newSVMBundle.Status.ResourceVersion, err.Error()))
}
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(rvInt, fldPath.Child("resourceVersion"))...)
// TODO: after switching to metav1.Conditions in beta replace this validation with metav1.ValidateConditions
allErrs = append(allErrs, validateConditions(newSVMBundle.Status.Conditions, fldPath.Child("conditions"))...)
// resource version should not change once it has been set
if len(oldSVMBundle.Status.ResourceVersion) != 0 && oldSVMBundle.Status.ResourceVersion != newSVMBundle.Status.ResourceVersion {
allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceVersion"), newSVMBundle.Status.ResourceVersion, "resourceVersion cannot be updated"))
}
// at most one of success or failed may be true
if isSuccessful(newSVMBundle) && isFailed(newSVMBundle) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), newSVMBundle.Status.Conditions, "Both success and failed conditions cannot be true at the same time"))
}
// running must be false when success is true or failed is true
if isSuccessful(newSVMBundle) && isRunning(newSVMBundle) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), newSVMBundle.Status.Conditions, "Running condition cannot be true when success condition is true"))
}
if isFailed(newSVMBundle) && isRunning(newSVMBundle) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), newSVMBundle.Status.Conditions, "Running condition cannot be true when failed condition is true"))
}
// success cannot be set to false once it is true
isOldSuccessful := isSuccessful(oldSVMBundle)
if isOldSuccessful && !isSuccessful(newSVMBundle) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), newSVMBundle.Status.Conditions, "Success condition cannot be set to false once it is true"))
}
isOldFailed := isFailed(oldSVMBundle)
if isOldFailed && !isFailed(newSVMBundle) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), newSVMBundle.Status.Conditions, "Failed condition cannot be set to false once it is true"))
}
return allErrs
}
func isSuccessful(svm *storagemigration.StorageVersionMigration) bool {
successCondition := getCondition(svm, storagemigration.MigrationSucceeded)
if successCondition != nil && successCondition.Status == corev1.ConditionTrue {
return true
}
return false
}
func isFailed(svm *storagemigration.StorageVersionMigration) bool {
failedCondition := getCondition(svm, storagemigration.MigrationFailed)
if failedCondition != nil && failedCondition.Status == corev1.ConditionTrue {
return true
}
return false
}
func isRunning(svm *storagemigration.StorageVersionMigration) bool {
runningCondition := getCondition(svm, storagemigration.MigrationRunning)
if runningCondition != nil && runningCondition.Status == corev1.ConditionTrue {
return true
}
return false
}
func getCondition(svm *storagemigration.StorageVersionMigration, conditionType storagemigration.MigrationConditionType) *storagemigration.MigrationCondition {
for _, c := range svm.Status.Conditions {
if c.Type == conditionType {
return &c
}
}
return nil
}
func validateConditions(conditions []storagemigration.MigrationCondition, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
conditionTypeToFirstIndex := map[string]int{}
for i, condition := range conditions {
if _, ok := conditionTypeToFirstIndex[string(condition.Type)]; ok {
allErrs = append(allErrs, field.Duplicate(fldPath.Index(i).Child("type"), condition.Type))
} else {
conditionTypeToFirstIndex[string(condition.Type)] = i
}
allErrs = append(allErrs, validateCondition(condition, fldPath.Index(i))...)
}
return allErrs
}
func validateCondition(condition storagemigration.MigrationCondition, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
var validConditionStatuses = sets.NewString(string(metav1.ConditionTrue), string(metav1.ConditionFalse), string(metav1.ConditionUnknown))
// type is set and is a valid format
allErrs = append(allErrs, metav1validation.ValidateLabelName(string(condition.Type), fldPath.Child("type"))...)
// status is set and is an accepted value
if !validConditionStatuses.Has(string(condition.Status)) {
allErrs = append(allErrs, field.NotSupported(fldPath.Child("status"), condition.Status, validConditionStatuses.List()))
}
if condition.LastUpdateTime.IsZero() {
allErrs = append(allErrs, field.Required(fldPath.Child("lastTransitionTime"), "must be set"))
}
if len(condition.Reason) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("reason"), "must be set"))
} else {
for _, currErr := range isValidConditionReason(condition.Reason) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("reason"), condition.Reason, currErr))
}
const maxReasonLen int = 1 * 1024 // 1024
if len(condition.Reason) > maxReasonLen {
allErrs = append(allErrs, field.TooLong(fldPath.Child("reason"), condition.Reason, maxReasonLen))
}
}
const maxMessageLen int = 32 * 1024 // 32768
if len(condition.Message) > maxMessageLen {
allErrs = append(allErrs, field.TooLong(fldPath.Child("message"), condition.Message, maxMessageLen))
}
return allErrs
}
func isValidConditionReason(value string) []string {
const conditionReasonFmt string = "[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?"
const conditionReasonErrMsg string = "a condition reason must start with alphabetic character, optionally followed by a string of alphanumeric characters or '_,:', and must end with an alphanumeric character or '_'"
var conditionReasonRegexp = regexp.MustCompile("^" + conditionReasonFmt + "$")
if !conditionReasonRegexp.MatchString(value) {
return []string{validation.RegexError(conditionReasonErrMsg, conditionReasonFmt, "my_name", "MY_NAME", "MyName", "ReasonA,ReasonB", "ReasonA:ReasonB")}
}
return nil
}
func checkAndAppendError(allErrs field.ErrorList, fieldPath *field.Path, value string, message string) field.ErrorList {
if len(value) == 0 {
allErrs = append(allErrs, field.Required(fieldPath, message))
}
return allErrs
}
func convertResourceVersionToInt(rv string) (int64, error) {
// initial value of RV is expected to be empty, which means the resource version is not set
if len(rv) == 0 {
return 0, nil
}
resourceVersion, err := strconv.ParseInt(rv, 10, 64)
if err != nil {
return 0, fmt.Errorf("failed to parse resource version %q: %w", rv, err)
}
return resourceVersion, nil
}

View File

@@ -0,0 +1,116 @@
/*
Copyright 2024 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 validation
import (
"testing"
"k8s.io/kubernetes/pkg/apis/storagemigration"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// TestValidateStorageVersionMigration tests the ValidateStorageVersionMigration function
func TestValidateStorageVersionMigration(t *testing.T) {
tests := []struct {
name string
svm *storagemigration.StorageVersionMigration
errorString string
}{
{
name: "when all fields are non-empty",
svm: &storagemigration.StorageVersionMigration{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svm",
},
Spec: storagemigration.StorageVersionMigrationSpec{
Resource: storagemigration.GroupVersionResource{
Group: "non-empty",
Version: "non-empty",
Resource: "non-empty",
},
},
},
errorString: "",
},
{
name: "when all fields are empty",
svm: &storagemigration.StorageVersionMigration{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svm",
},
Spec: storagemigration.StorageVersionMigrationSpec{
Resource: storagemigration.GroupVersionResource{
Group: "",
Version: "",
Resource: "",
},
},
},
errorString: "[spec.resource.resource: Required value: resource is required, spec.resource.version: Required value: version is required]",
},
{
name: "when resource is empty",
svm: &storagemigration.StorageVersionMigration{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svm",
},
Spec: storagemigration.StorageVersionMigrationSpec{
Resource: storagemigration.GroupVersionResource{
Group: "non-empty",
Version: "non-empty",
Resource: "",
},
},
},
errorString: "spec.resource.resource: Required value: resource is required",
},
{
name: "when version is empty",
svm: &storagemigration.StorageVersionMigration{
ObjectMeta: metav1.ObjectMeta{
Name: "test-svm",
},
Spec: storagemigration.StorageVersionMigrationSpec{
Resource: storagemigration.GroupVersionResource{
Group: "non-empty",
Version: "",
Resource: "non-empty",
},
},
},
errorString: "spec.resource.version: Required value: version is required",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
errors := ValidateStorageVersionMigration(test.svm)
errorString := ""
if len(errors) == 0 {
errorString = ""
} else {
errorString = errors.ToAggregate().Error()
}
if errorString != test.errorString {
t.Errorf("Expected error string %s, got %s", test.errorString, errorString)
}
})
}
}

View File

@@ -0,0 +1,160 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
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 deepcopy-gen. DO NOT EDIT.
package storagemigration
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 *GroupVersionResource) DeepCopyInto(out *GroupVersionResource) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupVersionResource.
func (in *GroupVersionResource) DeepCopy() *GroupVersionResource {
if in == nil {
return nil
}
out := new(GroupVersionResource)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MigrationCondition) DeepCopyInto(out *MigrationCondition) {
*out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MigrationCondition.
func (in *MigrationCondition) DeepCopy() *MigrationCondition {
if in == nil {
return nil
}
out := new(MigrationCondition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StorageVersionMigration) DeepCopyInto(out *StorageVersionMigration) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageVersionMigration.
func (in *StorageVersionMigration) DeepCopy() *StorageVersionMigration {
if in == nil {
return nil
}
out := new(StorageVersionMigration)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *StorageVersionMigration) 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 *StorageVersionMigrationList) DeepCopyInto(out *StorageVersionMigrationList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]StorageVersionMigration, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageVersionMigrationList.
func (in *StorageVersionMigrationList) DeepCopy() *StorageVersionMigrationList {
if in == nil {
return nil
}
out := new(StorageVersionMigrationList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *StorageVersionMigrationList) 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 *StorageVersionMigrationSpec) DeepCopyInto(out *StorageVersionMigrationSpec) {
*out = *in
out.Resource = in.Resource
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageVersionMigrationSpec.
func (in *StorageVersionMigrationSpec) DeepCopy() *StorageVersionMigrationSpec {
if in == nil {
return nil
}
out := new(StorageVersionMigrationSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StorageVersionMigrationStatus) DeepCopyInto(out *StorageVersionMigrationStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]MigrationCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageVersionMigrationStatus.
func (in *StorageVersionMigrationStatus) DeepCopy() *StorageVersionMigrationStatus {
if in == nil {
return nil
}
out := new(StorageVersionMigrationStatus)
in.DeepCopyInto(out)
return out
}

View File

@@ -41,4 +41,5 @@ import (
_ "k8s.io/kubernetes/pkg/apis/resource/install"
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
_ "k8s.io/kubernetes/pkg/apis/storage/install"
_ "k8s.io/kubernetes/pkg/apis/storagemigration/install"
)

View File

@@ -53,6 +53,7 @@ import (
storageapiv1 "k8s.io/api/storage/v1"
storageapiv1alpha1 "k8s.io/api/storage/v1alpha1"
storageapiv1beta1 "k8s.io/api/storage/v1beta1"
svmv1alpha1 "k8s.io/api/storagemigration/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
utilnet "k8s.io/apimachinery/pkg/util/net"
@@ -115,6 +116,7 @@ import (
resourcerest "k8s.io/kubernetes/pkg/registry/resource/rest"
schedulingrest "k8s.io/kubernetes/pkg/registry/scheduling/rest"
storagerest "k8s.io/kubernetes/pkg/registry/storage/rest"
svmrest "k8s.io/kubernetes/pkg/registry/storagemigration/rest"
)
const (
@@ -471,6 +473,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer},
schedulingrest.RESTStorageProvider{},
storagerest.RESTStorageProvider{},
svmrest.RESTStorageProvider{},
flowcontrolrest.RESTStorageProvider{InformerFactory: c.GenericConfig.SharedInformerFactory},
// keep apps after extensions so legacy clients resolve the extensions versions of shared resource names.
// See https://github.com/kubernetes/kubernetes/issues/42392
@@ -781,6 +784,7 @@ var (
certificatesv1alpha1.SchemeGroupVersion,
networkingapiv1alpha1.SchemeGroupVersion,
storageapiv1alpha1.SchemeGroupVersion,
svmv1alpha1.SchemeGroupVersion,
}
)

View File

@@ -815,6 +815,13 @@ const (
// Enables a StatefulSet to start from an arbitrary non zero ordinal
StatefulSetStartOrdinal featuregate.Feature = "StatefulSetStartOrdinal"
// owner: @nilekhc
// kep: https://kep.k8s.io/4192
// alpha: v1.30
// Enables support for the StorageVersionMigrator controller.
StorageVersionMigrator featuregate.Feature = "StorageVersionMigrator"
// owner: @robscott
// kep: https://kep.k8s.io/2433
// alpha: v1.21
@@ -1196,6 +1203,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
StatefulSetStartOrdinal: {Default: true, PreRelease: featuregate.Beta},
StorageVersionMigrator: {Default: false, PreRelease: featuregate.Alpha},
TopologyAwareHints: {Default: true, PreRelease: featuregate.Beta},
TopologyManagerPolicyAlphaOptions: {Default: false, PreRelease: featuregate.Alpha},

View File

@@ -967,6 +967,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"k8s.io/api/storage/v1beta1.VolumeAttachmentStatus": schema_k8sio_api_storage_v1beta1_VolumeAttachmentStatus(ref),
"k8s.io/api/storage/v1beta1.VolumeError": schema_k8sio_api_storage_v1beta1_VolumeError(ref),
"k8s.io/api/storage/v1beta1.VolumeNodeResources": schema_k8sio_api_storage_v1beta1_VolumeNodeResources(ref),
"k8s.io/api/storagemigration/v1alpha1.GroupVersionResource": schema_k8sio_api_storagemigration_v1alpha1_GroupVersionResource(ref),
"k8s.io/api/storagemigration/v1alpha1.MigrationCondition": schema_k8sio_api_storagemigration_v1alpha1_MigrationCondition(ref),
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigration": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigration(ref),
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationList": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationList(ref),
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationSpec": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationSpec(ref),
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationStatus": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationStatus(ref),
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionRequest": schema_pkg_apis_apiextensions_v1_ConversionRequest(ref),
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionResponse": schema_pkg_apis_apiextensions_v1_ConversionResponse(ref),
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionReview": schema_pkg_apis_apiextensions_v1_ConversionReview(ref),
@@ -49389,6 +49395,279 @@ func schema_k8sio_api_storage_v1beta1_VolumeNodeResources(ref common.ReferenceCa
}
}
func schema_k8sio_api_storagemigration_v1alpha1_GroupVersionResource(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "The names of the group, the version, and the resource.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"group": {
SchemaProps: spec.SchemaProps{
Description: "The name of the group.",
Type: []string{"string"},
Format: "",
},
},
"version": {
SchemaProps: spec.SchemaProps{
Description: "The name of the version.",
Type: []string{"string"},
Format: "",
},
},
"resource": {
SchemaProps: spec.SchemaProps{
Description: "The name of the resource.",
Type: []string{"string"},
Format: "",
},
},
},
},
},
}
}
func schema_k8sio_api_storagemigration_v1alpha1_MigrationCondition(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "Describes the state of a migration at a certain point.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
Description: "Type of the condition.",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status of the condition, one of True, False, Unknown.",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"lastUpdateTime": {
SchemaProps: spec.SchemaProps{
Description: "The last time this condition was updated.",
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
},
},
"reason": {
SchemaProps: spec.SchemaProps{
Description: "The reason for the condition's last transition.",
Type: []string{"string"},
Format: "",
},
},
"message": {
SchemaProps: spec.SchemaProps{
Description: "A human readable message indicating details about the transition.",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"type", "status"},
},
},
Dependencies: []string{
"k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
}
}
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigration(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "StorageVersionMigration represents a migration of stored data to the latest storage version.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
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/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
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/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Description: "Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
"spec": {
SchemaProps: spec.SchemaProps{
Description: "Specification of the migration.",
Default: map[string]interface{}{},
Ref: ref("k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status of the migration.",
Default: map[string]interface{}{},
Ref: ref("k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationStatus"),
},
},
},
},
},
Dependencies: []string{
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationSpec", "k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "StorageVersionMigrationList is a collection of storage version migrations.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
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/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
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/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Description: "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
Default: map[string]interface{}{},
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-list-map-keys": []interface{}{
"type",
},
"x-kubernetes-list-type": "map",
"x-kubernetes-patch-merge-key": "type",
"x-kubernetes-patch-strategy": "merge",
},
},
SchemaProps: spec.SchemaProps{
Description: "Items is the list of StorageVersionMigration",
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/api/storagemigration/v1alpha1.StorageVersionMigration"),
},
},
},
},
},
},
Required: []string{"items"},
},
},
Dependencies: []string{
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigration", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "Spec of the storage version migration.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"resource": {
SchemaProps: spec.SchemaProps{
Description: "The resource that is being migrated. The migrator sends requests to the endpoint serving the resource. Immutable.",
Default: map[string]interface{}{},
Ref: ref("k8s.io/api/storagemigration/v1alpha1.GroupVersionResource"),
},
},
"continueToken": {
SchemaProps: spec.SchemaProps{
Description: "The token used in the list options to get the next chunk of objects to migrate. When the .status.conditions indicates the migration is \"Running\", users can use this token to check the progress of the migration.",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"resource"},
},
},
Dependencies: []string{
"k8s.io/api/storagemigration/v1alpha1.GroupVersionResource"},
}
}
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "Status of the storage version migration.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"conditions": {
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-list-map-keys": []interface{}{
"type",
},
"x-kubernetes-list-type": "map",
"x-kubernetes-patch-merge-key": "type",
"x-kubernetes-patch-strategy": "merge",
},
},
SchemaProps: spec.SchemaProps{
Description: "The latest available observations of the migration's current state.",
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Default: map[string]interface{}{},
Ref: ref("k8s.io/api/storagemigration/v1alpha1.MigrationCondition"),
},
},
},
},
},
"resourceVersion": {
SchemaProps: spec.SchemaProps{
Description: "ResourceVersion to compare with the GC cache for performing the migration. This is the current resource version of given group, version and resource when kube-controller-manager first observes this StorageVersionMigration resource.",
Type: []string{"string"},
Format: "",
},
},
},
},
},
Dependencies: []string{
"k8s.io/api/storagemigration/v1alpha1.MigrationCondition"},
}
}
func schema_pkg_apis_apiextensions_v1_ConversionRequest(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{

View File

@@ -35,6 +35,7 @@ import (
"k8s.io/kubernetes/pkg/apis/networking"
"k8s.io/kubernetes/pkg/apis/policy"
"k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/apis/storagemigration"
)
// SpecialDefaultResourcePrefixes are prefixes compiled into Kubernetes.
@@ -76,6 +77,7 @@ func NewStorageFactoryConfig() *StorageFactoryConfig {
networking.Resource("servicecidrs").WithVersion("v1alpha1"),
certificates.Resource("clustertrustbundles").WithVersion("v1alpha1"),
storage.Resource("volumeattributesclasses").WithVersion("v1alpha1"),
storagemigration.Resource("storagemigrations").WithVersion("v1alpha1"),
}
return &StorageFactoryConfig{

View File

@@ -41,6 +41,7 @@ import (
_ "k8s.io/kubernetes/pkg/apis/resource/install"
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
_ "k8s.io/kubernetes/pkg/apis/storage/install"
_ "k8s.io/kubernetes/pkg/apis/storagemigration/install"
// Put the deprecated apis last to ensure that the latest apis can be used first.
// Related issue: https://github.com/kubernetes/kubernetes/issues/112682

View File

@@ -71,6 +71,7 @@ import (
"k8s.io/kubernetes/pkg/apis/scheduling"
"k8s.io/kubernetes/pkg/apis/storage"
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
svmv1alpha1 "k8s.io/kubernetes/pkg/apis/storagemigration"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/util/node"
)
@@ -697,6 +698,13 @@ func AddHandlers(h printers.PrintHandler) {
_ = h.TableHandler(ipAddressColumnDefinitions, printIPAddress)
_ = h.TableHandler(ipAddressColumnDefinitions, printIPAddressList)
storageVersionMigrationColumnDefinitions := []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
{Name: "Resource", Type: "string", Description: "Fully qualified resource to migrate"},
}
_ = h.TableHandler(storageVersionMigrationColumnDefinitions, printStorageVersionMigration)
_ = h.TableHandler(storageVersionMigrationColumnDefinitions, printStorageVersionMigrationList)
}
// Pass ports=nil for all ports.
@@ -3142,6 +3150,31 @@ func printResourceSliceList(list *resource.ResourceSliceList, options printers.G
return rows, nil
}
func printStorageVersionMigration(obj *svmv1alpha1.StorageVersionMigration, options printers.GenerateOptions) ([]metav1.TableRow, error) {
row := metav1.TableRow{
Object: runtime.RawExtension{Object: obj},
}
migrationGVR := obj.Spec.Resource.Resource + "." + obj.Spec.Resource.Version + "." + obj.Spec.Resource.Group
row.Cells = append(row.Cells, obj.Name, migrationGVR)
//ToDo: add migration condition 'status' and 'type' (migration successful | failed)
return []metav1.TableRow{row}, nil
}
func printStorageVersionMigrationList(list *svmv1alpha1.StorageVersionMigrationList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
rows := make([]metav1.TableRow, 0, len(list.Items))
for i := range list.Items {
r, err := printStorageVersionMigration(&list.Items[i], options)
if err != nil {
return nil, err
}
rows = append(rows, r...)
}
return rows, nil
}
func printBoolPtr(value *bool) string {
if value != nil {
return printBool(*value)

View File

@@ -47,6 +47,7 @@ import (
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/apis/scheduling"
"k8s.io/kubernetes/pkg/apis/storage"
"k8s.io/kubernetes/pkg/apis/storagemigration"
"k8s.io/kubernetes/pkg/printers"
utilpointer "k8s.io/utils/pointer"
)
@@ -6841,3 +6842,92 @@ func TestPrintServiceCIDRList(t *testing.T) {
}
}
}
func TestPrintStorageVersionMigration(t *testing.T) {
storageVersionMigration := storagemigration.StorageVersionMigration{
TypeMeta: metav1.TypeMeta{
Kind: "StorageVersionMigration",
APIVersion: "storagemigration.k8s.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "print-test",
},
Spec: storagemigration.StorageVersionMigrationSpec{
Resource: storagemigration.GroupVersionResource{
Group: "test-group",
Version: "test-version",
Resource: "test-resource",
},
},
}
// Columns: Name, GVRTOMIGRATE
expected := []metav1.TableRow{{Cells: []interface{}{"print-test", "test-resource.test-version.test-group"}}}
rows, err := printStorageVersionMigration(&storageVersionMigration, printers.GenerateOptions{})
if err != nil {
t.Fatalf("Error generating table rows for StorageVersionMigration: %#v", err)
}
rows[0].Object.Object = nil
if !reflect.DeepEqual(expected, rows) {
t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
}
}
func TestPrintStorageVersionMigrationList(t *testing.T) {
storageVersionMigrationList := storagemigration.StorageVersionMigrationList{
Items: []storagemigration.StorageVersionMigration{
{
TypeMeta: metav1.TypeMeta{
Kind: "StorageVersionMigration",
APIVersion: "storagemigration.k8s.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "print-test",
},
Spec: storagemigration.StorageVersionMigrationSpec{
Resource: storagemigration.GroupVersionResource{
Group: "test-group",
Version: "test-version",
Resource: "test-resource",
},
},
},
{
TypeMeta: metav1.TypeMeta{
Kind: "StorageVersionMigration",
APIVersion: "storagemigration.k8s.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "print-test2",
},
Spec: storagemigration.StorageVersionMigrationSpec{
Resource: storagemigration.GroupVersionResource{
Group: "test-group2",
Version: "test-version2",
Resource: "test-resource2",
},
},
},
},
}
// Columns: Name, GVRTOMIGRATE
expected := []metav1.TableRow{
{Cells: []interface{}{"print-test", "test-resource.test-version.test-group"}},
{Cells: []interface{}{"print-test2", "test-resource2.test-version2.test-group2"}},
}
rows, err := printStorageVersionMigrationList(&storageVersionMigrationList, printers.GenerateOptions{})
if err != nil {
t.Fatalf("Error generating table rows for StorageVersionMigration: %#v", err)
}
for i := range rows {
rows[i].Object.Object = nil
}
if !reflect.DeepEqual(expected, rows) {
t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
}
}

View File

@@ -0,0 +1,69 @@
/*
Copyright 2024 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 rest
import (
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/klog/v2"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/storagemigration"
"k8s.io/kubernetes/pkg/features"
svmv1alpha1 "k8s.io/api/storagemigration/v1alpha1"
genericapiserver "k8s.io/apiserver/pkg/server"
serverstorage "k8s.io/apiserver/pkg/server/storage"
utilfeature "k8s.io/apiserver/pkg/util/feature"
storagemigrationstore "k8s.io/kubernetes/pkg/registry/storagemigration/storagemigration/storage"
)
type RESTStorageProvider struct{}
func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(storagemigration.GroupName, legacyscheme.Scheme, legacyscheme.ParameterCodec, legacyscheme.Codecs)
if storageMap, err := p.v1alpha1Storage(apiResourceConfigSource, restOptionsGetter); err != nil {
return genericapiserver.APIGroupInfo{}, err
} else if len(storageMap) > 0 {
apiGroupInfo.VersionedResourcesStorageMap[svmv1alpha1.SchemeGroupVersion.Version] = storageMap
}
return apiGroupInfo, nil
}
func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
storage := map[string]rest.Storage{}
if resource := "storageversionmigrations"; apiResourceConfigSource.ResourceEnabled(svmv1alpha1.SchemeGroupVersion.WithResource(resource)) {
if utilfeature.DefaultFeatureGate.Enabled(features.StorageVersionMigrator) {
svm, svmStatus, err := storagemigrationstore.NewREST(restOptionsGetter)
if err != nil {
return nil, err
}
storage[resource] = svm
storage[resource+"/status"] = svmStatus
} else {
klog.Warning("StorageVersionMigrator storage is disabled because the StorageVersionMigrator feature gate is disabled")
}
}
return storage, nil
}
func (p RESTStorageProvider) GroupName() string {
return storagemigration.GroupName
}

View File

@@ -0,0 +1,111 @@
/*
Copyright 2024 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 (
"context"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/kubernetes/pkg/printers"
"k8s.io/kubernetes/pkg/registry/storagemigration/storagemigration"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
svmapi "k8s.io/kubernetes/pkg/apis/storagemigration"
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
)
// REST is a RESTStorage for ClusterTrustBundle.
type REST struct {
*genericregistry.Store
}
type StatusREST struct {
store *genericregistry.Store
}
var _ rest.StandardStorage = &REST{}
var _ rest.TableConvertor = &REST{}
var _ genericregistry.GenericStore = &REST{}
// NewREST returns a RESTStorage object for ClusterTrustBundle objects.
func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
store := &genericregistry.Store{
NewFunc: func() runtime.Object { return &svmapi.StorageVersionMigration{} },
NewListFunc: func() runtime.Object { return &svmapi.StorageVersionMigrationList{} },
ObjectNameFunc: func(obj runtime.Object) (string, error) {
return obj.(*svmapi.StorageVersionMigration).Name, nil
},
DefaultQualifiedResource: svmapi.Resource("storageversionmigrations"),
SingularQualifiedResource: svmapi.Resource("storageversionmigration"),
CreateStrategy: storagemigration.Strategy,
UpdateStrategy: storagemigration.Strategy,
DeleteStrategy: storagemigration.Strategy,
ResetFieldsStrategy: storagemigration.Strategy,
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
}
options := &generic.StoreOptions{
RESTOptions: optsGetter,
}
if err := store.CompleteWithOptions(options); err != nil {
return nil, nil, err
}
statusStore := *store
statusStore.UpdateStrategy = storagemigration.StatusStrategy
statusStore.ResetFieldsStrategy = storagemigration.StatusStrategy
return &REST{store}, &StatusREST{store: &statusStore}, nil
}
// New creates a new StorageVersion object.
func (r *StatusREST) New() runtime.Object {
return &svmapi.StorageVersionMigration{}
}
// Destroy cleans up resources on shutdown.
func (r *StatusREST) Destroy() {
// Given that underlying store is shared with REST,
// we don't destroy it here explicitly.
}
// Get retrieves the object from the storage. It is required to support Patch.
func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
return r.store.Get(ctx, name, options)
}
// Update alters the status subset of an object.
func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
// subresources should never allow create on update.
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
}
// GetResetFields implements rest.ResetFieldsStrategy
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
return r.store.GetResetFields()
}
func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
return r.store.ConvertToTable(ctx, object, tableOptions)
}

View File

@@ -0,0 +1,143 @@
/*
Copyright 2024 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 storagemigration provides Registry interface and its RESTStorage
// implementation for storing StorageVersionMigration objects.
package storagemigration // import "k8s.io/kubernetes/pkg/registry/storagemigration/storagemigration"
import (
"context"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/storage/names"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/storagemigration"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
svmvalidation "k8s.io/kubernetes/pkg/apis/storagemigration/validation"
)
// strategy implements behavior for ClusterTrustBundles.
type strategy struct {
runtime.ObjectTyper
names.NameGenerator
}
// Strategy is the create, update, and delete strategy for ClusterTrustBundles.
var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator}
var _ rest.RESTCreateStrategy = Strategy
var _ rest.RESTUpdateStrategy = Strategy
var _ rest.RESTDeleteStrategy = Strategy
func (strategy) NamespaceScoped() bool {
return false
}
// GetResetFields returns the set of fields that get reset by the strategy
// and should not be modified by the user.
func (strategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
fields := map[fieldpath.APIVersion]*fieldpath.Set{
"storagemigration.k8s.io/v1alpha1": fieldpath.NewSet(
fieldpath.MakePathOrDie("status"),
),
}
return fields
}
// PrepareForCreate clears the status of an StorageVersion before creation.
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
svm := obj.(*storagemigration.StorageVersionMigration)
svm.Status = storagemigration.StorageVersionMigrationStatus{}
}
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (s strategy) PrepareForUpdate(ctx context.Context, new, old runtime.Object) {
svm := new.(*storagemigration.StorageVersionMigration)
svm.Status = old.(*storagemigration.StorageVersionMigration).Status
}
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
bundle := obj.(*storagemigration.StorageVersionMigration)
return svmvalidation.ValidateStorageVersionMigration(bundle)
}
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
return nil
}
func (strategy) Canonicalize(obj runtime.Object) {}
func (strategy) AllowCreateOnUpdate() bool {
return false
}
func (s strategy) ValidateUpdate(ctx context.Context, new, old runtime.Object) field.ErrorList {
newBundle := new.(*storagemigration.StorageVersionMigration)
oldBundle := old.(*storagemigration.StorageVersionMigration)
return svmvalidation.ValidateStorageVersionMigrationUpdate(newBundle, oldBundle)
}
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
return nil
}
func (strategy) AllowUnconditionalUpdate() bool {
return false
}
type statusStrategy struct {
strategy
}
var StatusStrategy = statusStrategy{Strategy}
// GetResetFields returns the set of fields that get reset by the strategy
// and should not be modified by the user.
func (statusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
fields := map[fieldpath.APIVersion]*fieldpath.Set{
"storagemigration.k8s.io/v1alpha1": fieldpath.NewSet(
fieldpath.MakePathOrDie("metadata"),
fieldpath.MakePathOrDie("spec"),
),
}
return fields
}
func (statusStrategy) PrepareForUpdate(ctx context.Context, new, old runtime.Object) {
newBundle := new.(*storagemigration.StorageVersionMigration)
oldBundle := old.(*storagemigration.StorageVersionMigration)
newBundle.Spec = oldBundle.Spec
metav1.ResetObjectMetaForStatus(&newBundle.ObjectMeta, &oldBundle.ObjectMeta)
}
func (s statusStrategy) ValidateUpdate(ctx context.Context, new, old runtime.Object) field.ErrorList {
newSVM := new.(*storagemigration.StorageVersionMigration)
oldSVM := old.(*storagemigration.StorageVersionMigration)
return svmvalidation.ValidateStorageVersionMigrationStatusUpdate(newSVM, oldSVM)
}
// WarningsOnUpdate returns warnings for the given update.
func (statusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
return nil
}