mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 18:28:13 +00:00 
			
		
		
		
	Merge pull request #53164 from enisoc/rc-rs-conversion
Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Fix RC/RS conversion This fixes some round-trip information loss when representing an RC as an RS. I want to use these conversions in #49429 to eliminate the maintenance burden of duplicated RC code. @kubernetes/sig-apps-pr-reviews
This commit is contained in:
		| @@ -541,7 +541,6 @@ staging/src/k8s.io/apimachinery/pkg/apimachinery/announced | |||||||
| staging/src/k8s.io/apimachinery/pkg/apimachinery/registered | staging/src/k8s.io/apimachinery/pkg/apimachinery/registered | ||||||
| staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer | staging/src/k8s.io/apimachinery/pkg/apis/meta/fuzzer | ||||||
| staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion | staging/src/k8s.io/apimachinery/pkg/apis/meta/internalversion | ||||||
| staging/src/k8s.io/apimachinery/pkg/apis/meta/v1 |  | ||||||
| staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured | staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured | ||||||
| staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation | staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/validation | ||||||
| staging/src/k8s.io/apimachinery/pkg/apis/meta/v1alpha1 | staging/src/k8s.io/apimachinery/pkg/apis/meta/v1alpha1 | ||||||
|   | |||||||
| @@ -46,9 +46,14 @@ go_test( | |||||||
|         "//pkg/api:go_default_library", |         "//pkg/api:go_default_library", | ||||||
|         "//pkg/api/legacyscheme:go_default_library", |         "//pkg/api/legacyscheme:go_default_library", | ||||||
|         "//pkg/api/testapi:go_default_library", |         "//pkg/api/testapi:go_default_library", | ||||||
|  |         "//pkg/api/testing:go_default_library", | ||||||
|  |         "//pkg/apis/extensions:go_default_library", | ||||||
|  |         "//pkg/util/pointer:go_default_library", | ||||||
|         "//vendor/k8s.io/api/core/v1:go_default_library", |         "//vendor/k8s.io/api/core/v1:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", | ||||||
|  |         "//vendor/k8s.io/apimachinery/pkg/api/testing/fuzzer:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library", | ||||||
|   | |||||||
| @@ -235,7 +235,9 @@ func Convert_v1_ReplicationController_to_extensions_ReplicaSet(in *v1.Replicatio | |||||||
|  |  | ||||||
| func Convert_v1_ReplicationControllerSpec_to_extensions_ReplicaSetSpec(in *v1.ReplicationControllerSpec, out *extensions.ReplicaSetSpec, s conversion.Scope) error { | func Convert_v1_ReplicationControllerSpec_to_extensions_ReplicaSetSpec(in *v1.ReplicationControllerSpec, out *extensions.ReplicaSetSpec, s conversion.Scope) error { | ||||||
| 	out.Replicas = *in.Replicas | 	out.Replicas = *in.Replicas | ||||||
|  | 	out.MinReadySeconds = in.MinReadySeconds | ||||||
| 	if in.Selector != nil { | 	if in.Selector != nil { | ||||||
|  | 		out.Selector = new(metav1.LabelSelector) | ||||||
| 		metav1.Convert_map_to_unversioned_LabelSelector(&in.Selector, out.Selector, s) | 		metav1.Convert_map_to_unversioned_LabelSelector(&in.Selector, out.Selector, s) | ||||||
| 	} | 	} | ||||||
| 	if in.Template != nil { | 	if in.Template != nil { | ||||||
| @@ -252,6 +254,15 @@ func Convert_v1_ReplicationControllerStatus_to_extensions_ReplicaSetStatus(in *v | |||||||
| 	out.ReadyReplicas = in.ReadyReplicas | 	out.ReadyReplicas = in.ReadyReplicas | ||||||
| 	out.AvailableReplicas = in.AvailableReplicas | 	out.AvailableReplicas = in.AvailableReplicas | ||||||
| 	out.ObservedGeneration = in.ObservedGeneration | 	out.ObservedGeneration = in.ObservedGeneration | ||||||
|  | 	for _, cond := range in.Conditions { | ||||||
|  | 		out.Conditions = append(out.Conditions, extensions.ReplicaSetCondition{ | ||||||
|  | 			Type:               extensions.ReplicaSetConditionType(cond.Type), | ||||||
|  | 			Status:             api.ConditionStatus(cond.Status), | ||||||
|  | 			LastTransitionTime: cond.LastTransitionTime, | ||||||
|  | 			Reason:             cond.Reason, | ||||||
|  | 			Message:            cond.Message, | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -294,6 +305,15 @@ func Convert_extensions_ReplicaSetStatus_to_v1_ReplicationControllerStatus(in *e | |||||||
| 	out.ReadyReplicas = in.ReadyReplicas | 	out.ReadyReplicas = in.ReadyReplicas | ||||||
| 	out.AvailableReplicas = in.AvailableReplicas | 	out.AvailableReplicas = in.AvailableReplicas | ||||||
| 	out.ObservedGeneration = in.ObservedGeneration | 	out.ObservedGeneration = in.ObservedGeneration | ||||||
|  | 	for _, cond := range in.Conditions { | ||||||
|  | 		out.Conditions = append(out.Conditions, v1.ReplicationControllerCondition{ | ||||||
|  | 			Type:               v1.ReplicationControllerConditionType(cond.Type), | ||||||
|  | 			Status:             v1.ConditionStatus(cond.Status), | ||||||
|  | 			LastTransitionTime: cond.LastTransitionTime, | ||||||
|  | 			Reason:             cond.Reason, | ||||||
|  | 			Message:            cond.Message, | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,20 +17,27 @@ limitations under the License. | |||||||
| package v1_test | package v1_test | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"math/rand" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"k8s.io/api/core/v1" | 	"k8s.io/api/core/v1" | ||||||
|  | 	extensionsv1beta1 "k8s.io/api/extensions/v1beta1" | ||||||
| 	apiequality "k8s.io/apimachinery/pkg/api/equality" | 	apiequality "k8s.io/apimachinery/pkg/api/equality" | ||||||
| 	"k8s.io/apimachinery/pkg/api/resource" | 	"k8s.io/apimachinery/pkg/api/resource" | ||||||
|  | 	"k8s.io/apimachinery/pkg/api/testing/fuzzer" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/util/diff" | 	"k8s.io/apimachinery/pkg/util/diff" | ||||||
| 	"k8s.io/kubernetes/pkg/api" | 	"k8s.io/kubernetes/pkg/api" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" | 	"k8s.io/kubernetes/pkg/api/legacyscheme" | ||||||
|  | 	kapitesting "k8s.io/kubernetes/pkg/api/testing" | ||||||
| 	k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1" | 	k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1" | ||||||
|  | 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||||
|  | 	utilpointer "k8s.io/kubernetes/pkg/util/pointer" | ||||||
|  |  | ||||||
| 	// enforce that all types are installed | 	// enforce that all types are installed | ||||||
| 	_ "k8s.io/kubernetes/pkg/api/testapi" | 	_ "k8s.io/kubernetes/pkg/api/testapi" | ||||||
| @@ -226,3 +233,115 @@ func TestResourceListConversion(t *testing.T) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestReplicationControllerConversion(t *testing.T) { | ||||||
|  | 	// If we start with a RC, we should always have round-trip fidelity. | ||||||
|  | 	inputs := []*v1.ReplicationController{ | ||||||
|  | 		{ | ||||||
|  | 			ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 				Name:      "name", | ||||||
|  | 				Namespace: "namespace", | ||||||
|  | 			}, | ||||||
|  | 			Spec: v1.ReplicationControllerSpec{ | ||||||
|  | 				Replicas:        utilpointer.Int32Ptr(1), | ||||||
|  | 				MinReadySeconds: 32, | ||||||
|  | 				Selector:        map[string]string{"foo": "bar", "bar": "foo"}, | ||||||
|  | 				Template: &v1.PodTemplateSpec{ | ||||||
|  | 					ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 						Labels: map[string]string{"foo": "bar", "bar": "foo"}, | ||||||
|  | 					}, | ||||||
|  | 					Spec: v1.PodSpec{ | ||||||
|  | 						Containers: []v1.Container{ | ||||||
|  | 							{ | ||||||
|  | 								Name:  "container", | ||||||
|  | 								Image: "image", | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			Status: v1.ReplicationControllerStatus{ | ||||||
|  | 				Replicas:             1, | ||||||
|  | 				FullyLabeledReplicas: 2, | ||||||
|  | 				ReadyReplicas:        3, | ||||||
|  | 				AvailableReplicas:    4, | ||||||
|  | 				ObservedGeneration:   5, | ||||||
|  | 				Conditions: []v1.ReplicationControllerCondition{ | ||||||
|  | 					{ | ||||||
|  | 						Type:               v1.ReplicationControllerReplicaFailure, | ||||||
|  | 						Status:             v1.ConditionTrue, | ||||||
|  | 						LastTransitionTime: metav1.NewTime(time.Unix(123456789, 0)), | ||||||
|  | 						Reason:             "Reason", | ||||||
|  | 						Message:            "Message", | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Add some fuzzed RCs. | ||||||
|  | 	apiObjectFuzzer := fuzzer.FuzzerFor(kapitesting.FuzzerFuncs, rand.NewSource(152), legacyscheme.Codecs) | ||||||
|  | 	for i := 0; i < 100; i++ { | ||||||
|  | 		rc := &v1.ReplicationController{} | ||||||
|  | 		apiObjectFuzzer.Fuzz(rc) | ||||||
|  | 		// Sometimes the fuzzer decides to leave Spec.Template nil. | ||||||
|  | 		// We can't support that because Spec.Template is not a pointer in RS, | ||||||
|  | 		// so it will round-trip as non-nil but empty. | ||||||
|  | 		if rc.Spec.Template == nil { | ||||||
|  | 			rc.Spec.Template = &v1.PodTemplateSpec{} | ||||||
|  | 		} | ||||||
|  | 		// Sometimes the fuzzer decides to insert an empty label key. | ||||||
|  | 		// This doesn't round-trip properly because it's invalid. | ||||||
|  | 		if rc.Spec.Selector != nil { | ||||||
|  | 			delete(rc.Spec.Selector, "") | ||||||
|  | 		} | ||||||
|  | 		inputs = append(inputs, rc) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Round-trip the input RCs before converting to RS. | ||||||
|  | 	for i := range inputs { | ||||||
|  | 		inputs[i] = roundTrip(t, inputs[i]).(*v1.ReplicationController) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, in := range inputs { | ||||||
|  | 		rs := &extensions.ReplicaSet{} | ||||||
|  | 		// Use in.DeepCopy() to avoid sharing pointers with `in`. | ||||||
|  | 		if err := k8s_api_v1.Convert_v1_ReplicationController_to_extensions_ReplicaSet(in.DeepCopy(), rs, nil); err != nil { | ||||||
|  | 			t.Errorf("can't convert RC to RS: %v", err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		// Round-trip RS before converting back to RC. | ||||||
|  | 		rs = roundTripRS(t, rs) | ||||||
|  | 		out := &v1.ReplicationController{} | ||||||
|  | 		if err := k8s_api_v1.Convert_extensions_ReplicaSet_to_v1_ReplicationController(rs, out, nil); err != nil { | ||||||
|  | 			t.Errorf("can't convert RS to RC: %v", err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if !apiequality.Semantic.DeepEqual(in, out) { | ||||||
|  | 			instr, _ := json.MarshalIndent(in, "", "  ") | ||||||
|  | 			outstr, _ := json.MarshalIndent(out, "", "  ") | ||||||
|  | 			t.Errorf("RC-RS conversion round-trip failed:\nin:\n%s\nout:\n%s", instr, outstr) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func roundTripRS(t *testing.T, rs *extensions.ReplicaSet) *extensions.ReplicaSet { | ||||||
|  | 	codec := legacyscheme.Codecs.LegacyCodec(extensionsv1beta1.SchemeGroupVersion) | ||||||
|  | 	data, err := runtime.Encode(codec, rs) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("%v\n %#v", err, rs) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	obj2, err := runtime.Decode(codec, data) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("%v\nData: %s\nSource: %#v", err, string(data), rs) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	obj3 := &extensions.ReplicaSet{} | ||||||
|  | 	err = legacyscheme.Scheme.Convert(obj2, obj3, nil) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Errorf("%v\nSource: %#v", err, obj2) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return obj3 | ||||||
|  | } | ||||||
|   | |||||||
| @@ -93,3 +93,13 @@ filegroup( | |||||||
|     srcs = ["generated.proto"], |     srcs = ["generated.proto"], | ||||||
|     visibility = ["//visibility:public"], |     visibility = ["//visibility:public"], | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | go_test( | ||||||
|  |     name = "go_default_xtest", | ||||||
|  |     srcs = ["conversion_test.go"], | ||||||
|  |     importpath = "k8s.io/apimachinery/pkg/apis/meta/v1_test", | ||||||
|  |     deps = [ | ||||||
|  |         "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", | ||||||
|  |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
|  |     ], | ||||||
|  | ) | ||||||
|   | |||||||
| @@ -252,7 +252,6 @@ func Convert_map_to_unversioned_LabelSelector(in *map[string]string, out *LabelS | |||||||
| 	if in == nil { | 	if in == nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	out = new(LabelSelector) |  | ||||||
| 	for labelKey, labelValue := range *in { | 	for labelKey, labelValue := range *in { | ||||||
| 		AddLabelToSelector(out, labelKey, labelValue) | 		AddLabelToSelector(out, labelKey, labelValue) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -0,0 +1,49 @@ | |||||||
|  | /* | ||||||
|  | Copyright 2017 The Kubernetes Authors. | ||||||
|  |  | ||||||
|  | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | you may not use this file except in compliance with the License. | ||||||
|  | You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  |     http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  | Unless required by applicable law or agreed to in writing, software | ||||||
|  | distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | See the License for the specific language governing permissions and | ||||||
|  | limitations under the License. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | package v1_test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	apiequality "k8s.io/apimachinery/pkg/api/equality" | ||||||
|  | 	"k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestMapToLabelSelectorRoundTrip(t *testing.T) { | ||||||
|  | 	// We should be able to round-trip a map-only selector through LabelSelector. | ||||||
|  | 	inputs := []map[string]string{ | ||||||
|  | 		nil, | ||||||
|  | 		{}, | ||||||
|  | 		{"one": "foo"}, | ||||||
|  | 		{"one": "foo", "two": "bar"}, | ||||||
|  | 	} | ||||||
|  | 	for _, in := range inputs { | ||||||
|  | 		ls := &v1.LabelSelector{} | ||||||
|  | 		if err := v1.Convert_map_to_unversioned_LabelSelector(&in, ls, nil); err != nil { | ||||||
|  | 			t.Errorf("Convert_map_to_unversioned_LabelSelector(%#v): %v", in, err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		out := map[string]string{} | ||||||
|  | 		if err := v1.Convert_unversioned_LabelSelector_to_map(ls, &out, nil); err != nil { | ||||||
|  | 			t.Errorf("Convert_unversioned_LabelSelector_to_map(%#v): %v", ls, err) | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		if !apiequality.Semantic.DeepEqual(in, out) { | ||||||
|  | 			t.Errorf("map-selector conversion round-trip failed: got %v; want %v", out, in) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Submit Queue
					Kubernetes Submit Queue