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
}