feat: implements Storage Version Migration API in-tree
Signed-off-by: Nilekh Chaudhari <1626598+nilekhc@users.noreply.github.com>
This commit is contained in:
20
pkg/apis/storagemigration/doc.go
Normal file
20
pkg/apis/storagemigration/doc.go
Normal 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"
|
37
pkg/apis/storagemigration/install/install.go
Normal file
37
pkg/apis/storagemigration/install/install.go
Normal 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))
|
||||
}
|
51
pkg/apis/storagemigration/register.go
Normal file
51
pkg/apis/storagemigration/register.go
Normal 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
|
||||
}
|
131
pkg/apis/storagemigration/types.go
Normal file
131
pkg/apis/storagemigration/types.go
Normal 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
|
||||
}
|
23
pkg/apis/storagemigration/v1alpha1/doc.go
Normal file
23
pkg/apis/storagemigration/v1alpha1/doc.go
Normal 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"
|
39
pkg/apis/storagemigration/v1alpha1/register.go
Normal file
39
pkg/apis/storagemigration/v1alpha1/register.go
Normal 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
|
||||
)
|
256
pkg/apis/storagemigration/v1alpha1/zz_generated.conversion.go
generated
Normal file
256
pkg/apis/storagemigration/v1alpha1/zz_generated.conversion.go
generated
Normal 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)
|
||||
}
|
33
pkg/apis/storagemigration/v1alpha1/zz_generated.defaults.go
generated
Normal file
33
pkg/apis/storagemigration/v1alpha1/zz_generated.defaults.go
generated
Normal 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
|
||||
}
|
227
pkg/apis/storagemigration/validation/validation.go
Normal file
227
pkg/apis/storagemigration/validation/validation.go
Normal 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
|
||||
}
|
116
pkg/apis/storagemigration/validation/validation_test.go
Normal file
116
pkg/apis/storagemigration/validation/validation_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
160
pkg/apis/storagemigration/zz_generated.deepcopy.go
generated
Normal file
160
pkg/apis/storagemigration/zz_generated.deepcopy.go
generated
Normal 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
|
||||
}
|
Reference in New Issue
Block a user