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
|
||||
}
|
||||
@@ -41,4 +41,5 @@ import (
|
||||
_ "k8s.io/kubernetes/pkg/apis/resource/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/storagemigration/install"
|
||||
)
|
||||
|
||||
@@ -53,6 +53,7 @@ import (
|
||||
storageapiv1 "k8s.io/api/storage/v1"
|
||||
storageapiv1alpha1 "k8s.io/api/storage/v1alpha1"
|
||||
storageapiv1beta1 "k8s.io/api/storage/v1beta1"
|
||||
svmv1alpha1 "k8s.io/api/storagemigration/v1alpha1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
@@ -115,6 +116,7 @@ import (
|
||||
resourcerest "k8s.io/kubernetes/pkg/registry/resource/rest"
|
||||
schedulingrest "k8s.io/kubernetes/pkg/registry/scheduling/rest"
|
||||
storagerest "k8s.io/kubernetes/pkg/registry/storage/rest"
|
||||
svmrest "k8s.io/kubernetes/pkg/registry/storagemigration/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -471,6 +473,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
|
||||
rbacrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer},
|
||||
schedulingrest.RESTStorageProvider{},
|
||||
storagerest.RESTStorageProvider{},
|
||||
svmrest.RESTStorageProvider{},
|
||||
flowcontrolrest.RESTStorageProvider{InformerFactory: c.GenericConfig.SharedInformerFactory},
|
||||
// keep apps after extensions so legacy clients resolve the extensions versions of shared resource names.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/42392
|
||||
@@ -781,6 +784,7 @@ var (
|
||||
certificatesv1alpha1.SchemeGroupVersion,
|
||||
networkingapiv1alpha1.SchemeGroupVersion,
|
||||
storageapiv1alpha1.SchemeGroupVersion,
|
||||
svmv1alpha1.SchemeGroupVersion,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -815,6 +815,13 @@ const (
|
||||
// Enables a StatefulSet to start from an arbitrary non zero ordinal
|
||||
StatefulSetStartOrdinal featuregate.Feature = "StatefulSetStartOrdinal"
|
||||
|
||||
// owner: @nilekhc
|
||||
// kep: https://kep.k8s.io/4192
|
||||
// alpha: v1.30
|
||||
|
||||
// Enables support for the StorageVersionMigrator controller.
|
||||
StorageVersionMigrator featuregate.Feature = "StorageVersionMigrator"
|
||||
|
||||
// owner: @robscott
|
||||
// kep: https://kep.k8s.io/2433
|
||||
// alpha: v1.21
|
||||
@@ -1196,6 +1203,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
|
||||
StatefulSetStartOrdinal: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
||||
StorageVersionMigrator: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
TopologyAwareHints: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
||||
TopologyManagerPolicyAlphaOptions: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
279
pkg/generated/openapi/zz_generated.openapi.go
generated
279
pkg/generated/openapi/zz_generated.openapi.go
generated
@@ -967,6 +967,12 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"k8s.io/api/storage/v1beta1.VolumeAttachmentStatus": schema_k8sio_api_storage_v1beta1_VolumeAttachmentStatus(ref),
|
||||
"k8s.io/api/storage/v1beta1.VolumeError": schema_k8sio_api_storage_v1beta1_VolumeError(ref),
|
||||
"k8s.io/api/storage/v1beta1.VolumeNodeResources": schema_k8sio_api_storage_v1beta1_VolumeNodeResources(ref),
|
||||
"k8s.io/api/storagemigration/v1alpha1.GroupVersionResource": schema_k8sio_api_storagemigration_v1alpha1_GroupVersionResource(ref),
|
||||
"k8s.io/api/storagemigration/v1alpha1.MigrationCondition": schema_k8sio_api_storagemigration_v1alpha1_MigrationCondition(ref),
|
||||
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigration": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigration(ref),
|
||||
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationList": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationList(ref),
|
||||
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationSpec": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationSpec(ref),
|
||||
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationStatus": schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationStatus(ref),
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionRequest": schema_pkg_apis_apiextensions_v1_ConversionRequest(ref),
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionResponse": schema_pkg_apis_apiextensions_v1_ConversionResponse(ref),
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.ConversionReview": schema_pkg_apis_apiextensions_v1_ConversionReview(ref),
|
||||
@@ -49389,6 +49395,279 @@ func schema_k8sio_api_storage_v1beta1_VolumeNodeResources(ref common.ReferenceCa
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_storagemigration_v1alpha1_GroupVersionResource(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The names of the group, the version, and the resource.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"group": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The name of the group.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"version": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The name of the version.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"resource": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The name of the resource.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_storagemigration_v1alpha1_MigrationCondition(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Describes the state of a migration at a certain point.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"type": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Type of the condition.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Status of the condition, one of True, False, Unknown.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"lastUpdateTime": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The last time this condition was updated.",
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
|
||||
},
|
||||
},
|
||||
"reason": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The reason for the condition's last transition.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"message": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A human readable message indicating details about the transition.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"type", "status"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigration(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "StorageVersionMigration represents a migration of stored data to the latest storage version.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"apiVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Standard object metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
|
||||
},
|
||||
},
|
||||
"spec": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Specification of the migration.",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationSpec"),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Status of the migration.",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationStatus"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationSpec", "k8s.io/api/storagemigration/v1alpha1.StorageVersionMigrationStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationList(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "StorageVersionMigrationList is a collection of storage version migrations.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"kind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"apiVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Standard list metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
|
||||
},
|
||||
},
|
||||
"items": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-map-keys": []interface{}{
|
||||
"type",
|
||||
},
|
||||
"x-kubernetes-list-type": "map",
|
||||
"x-kubernetes-patch-merge-key": "type",
|
||||
"x-kubernetes-patch-strategy": "merge",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Items is the list of StorageVersionMigration",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/api/storagemigration/v1alpha1.StorageVersionMigration"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"items"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/storagemigration/v1alpha1.StorageVersionMigration", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Spec of the storage version migration.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"resource": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The resource that is being migrated. The migrator sends requests to the endpoint serving the resource. Immutable.",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/api/storagemigration/v1alpha1.GroupVersionResource"),
|
||||
},
|
||||
},
|
||||
"continueToken": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The token used in the list options to get the next chunk of objects to migrate. When the .status.conditions indicates the migration is \"Running\", users can use this token to check the progress of the migration.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"resource"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/storagemigration/v1alpha1.GroupVersionResource"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_storagemigration_v1alpha1_StorageVersionMigrationStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Status of the storage version migration.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"conditions": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-map-keys": []interface{}{
|
||||
"type",
|
||||
},
|
||||
"x-kubernetes-list-type": "map",
|
||||
"x-kubernetes-patch-merge-key": "type",
|
||||
"x-kubernetes-patch-strategy": "merge",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The latest available observations of the migration's current state.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref("k8s.io/api/storagemigration/v1alpha1.MigrationCondition"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"resourceVersion": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ResourceVersion to compare with the GC cache for performing the migration. This is the current resource version of given group, version and resource when kube-controller-manager first observes this StorageVersionMigration resource.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"k8s.io/api/storagemigration/v1alpha1.MigrationCondition"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_apiextensions_v1_ConversionRequest(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/networking"
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/apis/storagemigration"
|
||||
)
|
||||
|
||||
// SpecialDefaultResourcePrefixes are prefixes compiled into Kubernetes.
|
||||
@@ -76,6 +77,7 @@ func NewStorageFactoryConfig() *StorageFactoryConfig {
|
||||
networking.Resource("servicecidrs").WithVersion("v1alpha1"),
|
||||
certificates.Resource("clustertrustbundles").WithVersion("v1alpha1"),
|
||||
storage.Resource("volumeattributesclasses").WithVersion("v1alpha1"),
|
||||
storagemigration.Resource("storagemigrations").WithVersion("v1alpha1"),
|
||||
}
|
||||
|
||||
return &StorageFactoryConfig{
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
_ "k8s.io/kubernetes/pkg/apis/resource/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/scheduling/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/storage/install"
|
||||
_ "k8s.io/kubernetes/pkg/apis/storagemigration/install"
|
||||
|
||||
// Put the deprecated apis last to ensure that the latest apis can be used first.
|
||||
// Related issue: https://github.com/kubernetes/kubernetes/issues/112682
|
||||
|
||||
@@ -71,6 +71,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
storageutil "k8s.io/kubernetes/pkg/apis/storage/util"
|
||||
svmv1alpha1 "k8s.io/kubernetes/pkg/apis/storagemigration"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/node"
|
||||
)
|
||||
@@ -697,6 +698,13 @@ func AddHandlers(h printers.PrintHandler) {
|
||||
|
||||
_ = h.TableHandler(ipAddressColumnDefinitions, printIPAddress)
|
||||
_ = h.TableHandler(ipAddressColumnDefinitions, printIPAddressList)
|
||||
|
||||
storageVersionMigrationColumnDefinitions := []metav1.TableColumnDefinition{
|
||||
{Name: "Name", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
|
||||
{Name: "Resource", Type: "string", Description: "Fully qualified resource to migrate"},
|
||||
}
|
||||
_ = h.TableHandler(storageVersionMigrationColumnDefinitions, printStorageVersionMigration)
|
||||
_ = h.TableHandler(storageVersionMigrationColumnDefinitions, printStorageVersionMigrationList)
|
||||
}
|
||||
|
||||
// Pass ports=nil for all ports.
|
||||
@@ -3142,6 +3150,31 @@ func printResourceSliceList(list *resource.ResourceSliceList, options printers.G
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func printStorageVersionMigration(obj *svmv1alpha1.StorageVersionMigration, options printers.GenerateOptions) ([]metav1.TableRow, error) {
|
||||
row := metav1.TableRow{
|
||||
Object: runtime.RawExtension{Object: obj},
|
||||
}
|
||||
|
||||
migrationGVR := obj.Spec.Resource.Resource + "." + obj.Spec.Resource.Version + "." + obj.Spec.Resource.Group
|
||||
row.Cells = append(row.Cells, obj.Name, migrationGVR)
|
||||
//ToDo: add migration condition 'status' and 'type' (migration successful | failed)
|
||||
|
||||
return []metav1.TableRow{row}, nil
|
||||
}
|
||||
|
||||
func printStorageVersionMigrationList(list *svmv1alpha1.StorageVersionMigrationList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
|
||||
rows := make([]metav1.TableRow, 0, len(list.Items))
|
||||
|
||||
for i := range list.Items {
|
||||
r, err := printStorageVersionMigration(&list.Items[i], options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows = append(rows, r...)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func printBoolPtr(value *bool) string {
|
||||
if value != nil {
|
||||
return printBool(*value)
|
||||
|
||||
@@ -47,6 +47,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/apis/scheduling"
|
||||
"k8s.io/kubernetes/pkg/apis/storage"
|
||||
"k8s.io/kubernetes/pkg/apis/storagemigration"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
@@ -6841,3 +6842,92 @@ func TestPrintServiceCIDRList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintStorageVersionMigration(t *testing.T) {
|
||||
storageVersionMigration := storagemigration.StorageVersionMigration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "StorageVersionMigration",
|
||||
APIVersion: "storagemigration.k8s.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "print-test",
|
||||
},
|
||||
Spec: storagemigration.StorageVersionMigrationSpec{
|
||||
Resource: storagemigration.GroupVersionResource{
|
||||
Group: "test-group",
|
||||
Version: "test-version",
|
||||
Resource: "test-resource",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Columns: Name, GVRTOMIGRATE
|
||||
expected := []metav1.TableRow{{Cells: []interface{}{"print-test", "test-resource.test-version.test-group"}}}
|
||||
|
||||
rows, err := printStorageVersionMigration(&storageVersionMigration, printers.GenerateOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Error generating table rows for StorageVersionMigration: %#v", err)
|
||||
}
|
||||
rows[0].Object.Object = nil
|
||||
if !reflect.DeepEqual(expected, rows) {
|
||||
t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintStorageVersionMigrationList(t *testing.T) {
|
||||
storageVersionMigrationList := storagemigration.StorageVersionMigrationList{
|
||||
Items: []storagemigration.StorageVersionMigration{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "StorageVersionMigration",
|
||||
APIVersion: "storagemigration.k8s.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "print-test",
|
||||
},
|
||||
Spec: storagemigration.StorageVersionMigrationSpec{
|
||||
Resource: storagemigration.GroupVersionResource{
|
||||
Group: "test-group",
|
||||
Version: "test-version",
|
||||
Resource: "test-resource",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "StorageVersionMigration",
|
||||
APIVersion: "storagemigration.k8s.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "print-test2",
|
||||
},
|
||||
Spec: storagemigration.StorageVersionMigrationSpec{
|
||||
Resource: storagemigration.GroupVersionResource{
|
||||
Group: "test-group2",
|
||||
Version: "test-version2",
|
||||
Resource: "test-resource2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Columns: Name, GVRTOMIGRATE
|
||||
expected := []metav1.TableRow{
|
||||
{Cells: []interface{}{"print-test", "test-resource.test-version.test-group"}},
|
||||
{Cells: []interface{}{"print-test2", "test-resource2.test-version2.test-group2"}},
|
||||
}
|
||||
|
||||
rows, err := printStorageVersionMigrationList(&storageVersionMigrationList, printers.GenerateOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Error generating table rows for StorageVersionMigration: %#v", err)
|
||||
}
|
||||
|
||||
for i := range rows {
|
||||
rows[i].Object.Object = nil
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(expected, rows) {
|
||||
t.Errorf("mismatch: %s", cmp.Diff(expected, rows))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package rest
|
||||
|
||||
import (
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/storagemigration"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
|
||||
svmv1alpha1 "k8s.io/api/storagemigration/v1alpha1"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
serverstorage "k8s.io/apiserver/pkg/server/storage"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
storagemigrationstore "k8s.io/kubernetes/pkg/registry/storagemigration/storagemigration/storage"
|
||||
)
|
||||
|
||||
type RESTStorageProvider struct{}
|
||||
|
||||
func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, error) {
|
||||
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(storagemigration.GroupName, legacyscheme.Scheme, legacyscheme.ParameterCodec, legacyscheme.Codecs)
|
||||
|
||||
if storageMap, err := p.v1alpha1Storage(apiResourceConfigSource, restOptionsGetter); err != nil {
|
||||
return genericapiserver.APIGroupInfo{}, err
|
||||
} else if len(storageMap) > 0 {
|
||||
apiGroupInfo.VersionedResourcesStorageMap[svmv1alpha1.SchemeGroupVersion.Version] = storageMap
|
||||
}
|
||||
|
||||
return apiGroupInfo, nil
|
||||
}
|
||||
|
||||
func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
|
||||
storage := map[string]rest.Storage{}
|
||||
|
||||
if resource := "storageversionmigrations"; apiResourceConfigSource.ResourceEnabled(svmv1alpha1.SchemeGroupVersion.WithResource(resource)) {
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.StorageVersionMigrator) {
|
||||
svm, svmStatus, err := storagemigrationstore.NewREST(restOptionsGetter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storage[resource] = svm
|
||||
storage[resource+"/status"] = svmStatus
|
||||
} else {
|
||||
klog.Warning("StorageVersionMigrator storage is disabled because the StorageVersionMigrator feature gate is disabled")
|
||||
}
|
||||
}
|
||||
|
||||
return storage, nil
|
||||
}
|
||||
|
||||
func (p RESTStorageProvider) GroupName() string {
|
||||
return storagemigration.GroupName
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/registry/storagemigration/storagemigration"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
svmapi "k8s.io/kubernetes/pkg/apis/storagemigration"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||
)
|
||||
|
||||
// REST is a RESTStorage for ClusterTrustBundle.
|
||||
type REST struct {
|
||||
*genericregistry.Store
|
||||
}
|
||||
|
||||
type StatusREST struct {
|
||||
store *genericregistry.Store
|
||||
}
|
||||
|
||||
var _ rest.StandardStorage = &REST{}
|
||||
var _ rest.TableConvertor = &REST{}
|
||||
var _ genericregistry.GenericStore = &REST{}
|
||||
|
||||
// NewREST returns a RESTStorage object for ClusterTrustBundle objects.
|
||||
func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: func() runtime.Object { return &svmapi.StorageVersionMigration{} },
|
||||
NewListFunc: func() runtime.Object { return &svmapi.StorageVersionMigrationList{} },
|
||||
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
||||
return obj.(*svmapi.StorageVersionMigration).Name, nil
|
||||
},
|
||||
DefaultQualifiedResource: svmapi.Resource("storageversionmigrations"),
|
||||
SingularQualifiedResource: svmapi.Resource("storageversionmigration"),
|
||||
|
||||
CreateStrategy: storagemigration.Strategy,
|
||||
UpdateStrategy: storagemigration.Strategy,
|
||||
DeleteStrategy: storagemigration.Strategy,
|
||||
ResetFieldsStrategy: storagemigration.Strategy,
|
||||
|
||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||
}
|
||||
options := &generic.StoreOptions{
|
||||
RESTOptions: optsGetter,
|
||||
}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = storagemigration.StatusStrategy
|
||||
statusStore.ResetFieldsStrategy = storagemigration.StatusStrategy
|
||||
|
||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||
}
|
||||
|
||||
// New creates a new StorageVersion object.
|
||||
func (r *StatusREST) New() runtime.Object {
|
||||
return &svmapi.StorageVersionMigration{}
|
||||
}
|
||||
|
||||
// Destroy cleans up resources on shutdown.
|
||||
func (r *StatusREST) Destroy() {
|
||||
// Given that underlying store is shared with REST,
|
||||
// we don't destroy it here explicitly.
|
||||
}
|
||||
|
||||
// Get retrieves the object from the storage. It is required to support Patch.
|
||||
func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return r.store.Get(ctx, name, options)
|
||||
}
|
||||
|
||||
// Update alters the status subset of an object.
|
||||
func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
||||
// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
|
||||
// subresources should never allow create on update.
|
||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||
}
|
||||
|
||||
// GetResetFields implements rest.ResetFieldsStrategy
|
||||
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return r.store.GetResetFields()
|
||||
}
|
||||
|
||||
func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
|
||||
return r.store.ConvertToTable(ctx, object, tableOptions)
|
||||
}
|
||||
143
pkg/registry/storagemigration/storagemigration/strategy.go
Normal file
143
pkg/registry/storagemigration/storagemigration/strategy.go
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package storagemigration provides Registry interface and its RESTStorage
|
||||
// implementation for storing StorageVersionMigration objects.
|
||||
package storagemigration // import "k8s.io/kubernetes/pkg/registry/storagemigration/storagemigration"
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/storagemigration"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
svmvalidation "k8s.io/kubernetes/pkg/apis/storagemigration/validation"
|
||||
)
|
||||
|
||||
// strategy implements behavior for ClusterTrustBundles.
|
||||
type strategy struct {
|
||||
runtime.ObjectTyper
|
||||
names.NameGenerator
|
||||
}
|
||||
|
||||
// Strategy is the create, update, and delete strategy for ClusterTrustBundles.
|
||||
var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator}
|
||||
|
||||
var _ rest.RESTCreateStrategy = Strategy
|
||||
var _ rest.RESTUpdateStrategy = Strategy
|
||||
var _ rest.RESTDeleteStrategy = Strategy
|
||||
|
||||
func (strategy) NamespaceScoped() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (strategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"storagemigration.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("status"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// PrepareForCreate clears the status of an StorageVersion before creation.
|
||||
func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
svm := obj.(*storagemigration.StorageVersionMigration)
|
||||
svm.Status = storagemigration.StorageVersionMigrationStatus{}
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||
func (s strategy) PrepareForUpdate(ctx context.Context, new, old runtime.Object) {
|
||||
svm := new.(*storagemigration.StorageVersionMigration)
|
||||
svm.Status = old.(*storagemigration.StorageVersionMigration).Status
|
||||
}
|
||||
|
||||
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
bundle := obj.(*storagemigration.StorageVersionMigration)
|
||||
return svmvalidation.ValidateStorageVersionMigration(bundle)
|
||||
}
|
||||
|
||||
func (strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (strategy) Canonicalize(obj runtime.Object) {}
|
||||
|
||||
func (strategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s strategy) ValidateUpdate(ctx context.Context, new, old runtime.Object) field.ErrorList {
|
||||
newBundle := new.(*storagemigration.StorageVersionMigration)
|
||||
oldBundle := old.(*storagemigration.StorageVersionMigration)
|
||||
return svmvalidation.ValidateStorageVersionMigrationUpdate(newBundle, oldBundle)
|
||||
}
|
||||
|
||||
func (strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (strategy) AllowUnconditionalUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type statusStrategy struct {
|
||||
strategy
|
||||
}
|
||||
|
||||
var StatusStrategy = statusStrategy{Strategy}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy
|
||||
// and should not be modified by the user.
|
||||
func (statusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"storagemigration.k8s.io/v1alpha1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func (statusStrategy) PrepareForUpdate(ctx context.Context, new, old runtime.Object) {
|
||||
newBundle := new.(*storagemigration.StorageVersionMigration)
|
||||
oldBundle := old.(*storagemigration.StorageVersionMigration)
|
||||
|
||||
newBundle.Spec = oldBundle.Spec
|
||||
metav1.ResetObjectMetaForStatus(&newBundle.ObjectMeta, &oldBundle.ObjectMeta)
|
||||
}
|
||||
|
||||
func (s statusStrategy) ValidateUpdate(ctx context.Context, new, old runtime.Object) field.ErrorList {
|
||||
newSVM := new.(*storagemigration.StorageVersionMigration)
|
||||
oldSVM := old.(*storagemigration.StorageVersionMigration)
|
||||
|
||||
return svmvalidation.ValidateStorageVersionMigrationStatusUpdate(newSVM, oldSVM)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (statusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user