Merge pull request #24733 from kargakis/rc-rs-conversions

Automatic merge from submit-queue

Custom conversions between RCs/RSs

Needed for building storages that still need to work with RCs but also want to facilitate RSs.

cc: @deads2k @smarterclayton @liggitt
This commit is contained in:
k8s-merge-robot 2016-07-17 04:49:16 -07:00 committed by GitHub
commit 01925c810b
5 changed files with 297 additions and 17 deletions

View File

@ -17,12 +17,16 @@ limitations under the License.
package api
import (
"fmt"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/intstr"
utillabels "k8s.io/kubernetes/pkg/util/labels"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func init() {
@ -69,6 +73,9 @@ func init() {
Convert_Pointer_float64_To_float64,
Convert_float64_To_Pointer_float64,
Convert_map_to_unversioned_LabelSelector,
Convert_unversioned_LabelSelector_to_map,
)
}
@ -195,6 +202,7 @@ func Convert_string_To_labels_Selector(in *string, out *labels.Selector, s conve
*out = selector
return nil
}
func Convert_string_To_fields_Selector(in *string, out *fields.Selector, s conversion.Scope) error {
selector, err := fields.ParseSelector(*in)
if err != nil {
@ -203,6 +211,7 @@ func Convert_string_To_fields_Selector(in *string, out *fields.Selector, s conve
*out = selector
return nil
}
func Convert_labels_Selector_To_string(in *labels.Selector, out *string, s conversion.Scope) error {
if *in == nil {
return nil
@ -210,6 +219,7 @@ func Convert_labels_Selector_To_string(in *labels.Selector, out *string, s conve
*out = (*in).String()
return nil
}
func Convert_fields_Selector_To_string(in *fields.Selector, out *string, s conversion.Scope) error {
if *in == nil {
return nil
@ -217,7 +227,25 @@ func Convert_fields_Selector_To_string(in *fields.Selector, out *string, s conve
*out = (*in).String()
return nil
}
func Convert_resource_Quantity_To_resource_Quantity(in *resource.Quantity, out *resource.Quantity, s conversion.Scope) error {
*out = *in
return nil
}
func Convert_map_to_unversioned_LabelSelector(in *map[string]string, out *unversioned.LabelSelector, s conversion.Scope) error {
out = new(unversioned.LabelSelector)
for labelKey, labelValue := range *in {
utillabels.AddLabelToSelector(out, labelKey, labelValue)
}
return nil
}
func Convert_unversioned_LabelSelector_to_map(in *unversioned.LabelSelector, out *map[string]string, s conversion.Scope) error {
var err error
*out, err = unversioned.LabelSelectorAsMap(in)
if err != nil {
err = field.Invalid(field.NewPath("labelSelector"), *in, fmt.Sprintf("cannot convert to old selector: %v", err))
}
return err
}

View File

@ -38,8 +38,12 @@ import (
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/serializer/streaming"
"k8s.io/kubernetes/pkg/runtime/serializer/versioning"
"k8s.io/kubernetes/pkg/util/diff"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/watch"
@ -144,6 +148,61 @@ func roundTripSame(t *testing.T, group testapi.TestGroup, item runtime.Object, e
}
}
func Convert_v1beta1_ReplicaSet_to_api_ReplicationController(in *v1beta1.ReplicaSet, out *api.ReplicationController, s conversion.Scope) error {
intermediate1 := &extensions.ReplicaSet{}
if err := v1beta1.Convert_v1beta1_ReplicaSet_To_extensions_ReplicaSet(in, intermediate1, s); err != nil {
return err
}
intermediate2 := &v1.ReplicationController{}
if err := v1.Convert_extensions_ReplicaSet_to_v1_ReplicationController(intermediate1, intermediate2, s); err != nil {
return err
}
return v1.Convert_v1_ReplicationController_To_api_ReplicationController(intermediate2, out, s)
}
func TestSetControllerConversion(t *testing.T) {
if err := api.Scheme.AddConversionFuncs(Convert_v1beta1_ReplicaSet_to_api_ReplicationController); err != nil {
t.Fatal(err)
}
rs := &extensions.ReplicaSet{}
rc := &api.ReplicationController{}
extGroup := testapi.Extensions
defaultGroup := testapi.Default
fuzzInternalObject(t, extGroup.InternalGroupVersion(), rs, rand.Int63())
t.Logf("rs._internal.extensions -> rs.v1beta1.extensions")
data, err := runtime.Encode(extGroup.Codec(), rs)
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
decoder := api.Codecs.UniversalDecoder(*extGroup.GroupVersion(), *defaultGroup.GroupVersion())
if err := versioning.EnableCrossGroupDecoding(decoder, extGroup.GroupVersion().Group, defaultGroup.GroupVersion().Group); err != nil {
t.Fatalf("unexpected error while enabling cross-group decoding: %v", err)
}
t.Logf("rs.v1beta1.extensions -> rc._internal")
if err := runtime.DecodeInto(decoder, data, rc); err != nil {
t.Fatalf("unexpected decoding error: %v", err)
}
t.Logf("rc._internal -> rc.v1")
data, err = runtime.Encode(defaultGroup.Codec(), rc)
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
t.Logf("rc.v1 -> rs._internal.extensions")
if err := runtime.DecodeInto(decoder, data, rs); err != nil {
t.Fatalf("unexpected decoding error: %v", err)
}
}
// For debugging problems
func TestSpecificKind(t *testing.T) {
kind := "DaemonSet"

View File

@ -64,6 +64,35 @@ func LabelSelectorAsSelector(ps *LabelSelector) (labels.Selector, error) {
return selector, nil
}
// LabelSelectorAsMap converts the LabelSelector api type into a map of strings, ie. the
// original structure of a label selector. Operators that cannot be converted into plain
// labels (Exists, DoesNotExist, NotIn, and In with more than one value) will result in
// an error.
func LabelSelectorAsMap(ps *LabelSelector) (map[string]string, error) {
if ps == nil {
return nil, nil
}
selector := map[string]string{}
for k, v := range ps.MatchLabels {
selector[k] = v
}
for _, expr := range ps.MatchExpressions {
switch expr.Operator {
case LabelSelectorOpIn:
if len(expr.Values) != 1 {
return selector, fmt.Errorf("operator %q without a single value cannot be converted into the old label selector format", expr.Operator)
}
// Should we do anything in case this will override a previous key-value pair?
selector[expr.Key] = expr.Values[0]
case LabelSelectorOpNotIn, LabelSelectorOpExists, LabelSelectorOpDoesNotExist:
return selector, fmt.Errorf("operator %q cannot be converted into the old label selector format", expr.Operator)
default:
return selector, fmt.Errorf("%q is not a valid selector operator", expr.Operator)
}
}
return selector, nil
}
// ParseToLabelSelector parses a string representing a selector into a LabelSelector object.
// Note: This function should be kept in sync with the parser in pkg/labels/selector.go
func ParseToLabelSelector(selector string) (*LabelSelector, error) {

View File

@ -18,6 +18,7 @@ package unversioned
import (
"reflect"
"strings"
"testing"
"k8s.io/kubernetes/pkg/labels"
@ -81,3 +82,73 @@ func TestLabelSelectorAsSelector(t *testing.T) {
}
}
}
func TestLabelSelectorAsMap(t *testing.T) {
matchLabels := map[string]string{"foo": "bar"}
matchExpressions := func(operator LabelSelectorOperator, values []string) []LabelSelectorRequirement {
return []LabelSelectorRequirement{{
Key: "baz",
Operator: operator,
Values: values,
}}
}
tests := []struct {
in *LabelSelector
out map[string]string
errString string
}{
{in: nil, out: nil},
{
in: &LabelSelector{MatchLabels: matchLabels},
out: map[string]string{"foo": "bar"},
},
{
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})},
out: map[string]string{"foo": "bar", "baz": "norf"},
},
{
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf"})},
out: map[string]string{"baz": "norf"},
},
{
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpIn, []string{"norf", "qux"})},
out: map[string]string{"foo": "bar"},
errString: "without a single value cannot be converted",
},
{
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpNotIn, []string{"norf", "qux"})},
out: map[string]string{},
errString: "cannot be converted",
},
{
in: &LabelSelector{MatchLabels: matchLabels, MatchExpressions: matchExpressions(LabelSelectorOpExists, []string{})},
out: map[string]string{"foo": "bar"},
errString: "cannot be converted",
},
{
in: &LabelSelector{MatchExpressions: matchExpressions(LabelSelectorOpDoesNotExist, []string{})},
out: map[string]string{},
errString: "cannot be converted",
},
}
for i, tc := range tests {
out, err := LabelSelectorAsMap(tc.in)
if err == nil && len(tc.errString) > 0 {
t.Errorf("[%v]expected error but got none.", i)
continue
}
if err != nil && len(tc.errString) == 0 {
t.Errorf("[%v]did not expect error but got: %v", i, err)
continue
}
if err != nil && len(tc.errString) > 0 && !strings.Contains(err.Error(), tc.errString) {
t.Errorf("[%v]expected error with %q but got: %v", i, tc.errString, err)
continue
}
if !reflect.DeepEqual(out, tc.out) {
t.Errorf("[%v]expected:\n\t%+v\nbut got:\n\t%+v", i, tc.out, out)
}
}
}

View File

@ -19,10 +19,13 @@ package v1
import (
"encoding/json"
"fmt"
"reflect"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/validation/field"
)
const (
@ -31,6 +34,9 @@ const (
// Value used to identify mirror pods from pre-v1.1 kubelet.
mirrorAnnotationValue_1_0 = "mirror"
// annotation key prefix used to identify non-convertible json paths.
NonConvertibleAnnotationPrefix = "kubernetes.io/non-convertible"
)
func addConversionFuncs(scheme *runtime.Scheme) {
@ -46,6 +52,12 @@ func addConversionFuncs(scheme *runtime.Scheme) {
Convert_v1_Secret_To_api_Secret,
Convert_v1_ServiceSpec_To_api_ServiceSpec,
Convert_v1_ResourceList_To_api_ResourceList,
Convert_v1_ReplicationController_to_extensions_ReplicaSet,
Convert_v1_ReplicationControllerSpec_to_extensions_ReplicaSetSpec,
Convert_v1_ReplicationControllerStatus_to_extensions_ReplicaSetStatus,
Convert_extensions_ReplicaSet_to_v1_ReplicationController,
Convert_extensions_ReplicaSetSpec_to_v1_ReplicationControllerSpec,
Convert_extensions_ReplicaSetStatus_to_v1_ReplicationControllerStatus,
)
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
@ -199,17 +211,107 @@ func addConversionFuncs(scheme *runtime.Scheme) {
}
}
func Convert_v1_ReplicationController_to_extensions_ReplicaSet(in *ReplicationController, out *extensions.ReplicaSet, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicationController))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_v1_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_v1_ReplicationControllerSpec_to_extensions_ReplicaSetSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1_ReplicationControllerStatus_to_extensions_ReplicaSetStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_v1_ReplicationControllerSpec_to_extensions_ReplicaSetSpec(in *ReplicationControllerSpec, out *extensions.ReplicaSetSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicationControllerSpec))(in)
}
out.Replicas = *in.Replicas
if in.Selector != nil {
api.Convert_map_to_unversioned_LabelSelector(&in.Selector, out.Selector, s)
}
if in.Template != nil {
if err := Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(in.Template, &out.Template, s); err != nil {
return err
}
}
return nil
}
func Convert_v1_ReplicationControllerStatus_to_extensions_ReplicaSetStatus(in *ReplicationControllerStatus, out *extensions.ReplicaSetStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ReplicationControllerStatus))(in)
}
out.Replicas = in.Replicas
out.FullyLabeledReplicas = in.FullyLabeledReplicas
out.ObservedGeneration = in.ObservedGeneration
return nil
}
func Convert_extensions_ReplicaSet_to_v1_ReplicationController(in *extensions.ReplicaSet, out *ReplicationController, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSet))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_api_ObjectMeta_To_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_extensions_ReplicaSetSpec_to_v1_ReplicationControllerSpec(&in.Spec, &out.Spec, s); err != nil {
fieldErr, ok := err.(*field.Error)
if !ok {
return err
}
if out.Annotations == nil {
out.Annotations = make(map[string]string)
}
out.Annotations[NonConvertibleAnnotationPrefix+"/"+fieldErr.Field] = reflect.ValueOf(fieldErr.BadValue).String()
}
if err := Convert_extensions_ReplicaSetStatus_to_v1_ReplicationControllerStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_extensions_ReplicaSetSpec_to_v1_ReplicationControllerSpec(in *extensions.ReplicaSetSpec, out *ReplicationControllerSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSetSpec))(in)
}
out.Replicas = new(int32)
*out.Replicas = in.Replicas
var invalidErr error
if in.Selector != nil {
invalidErr = api.Convert_unversioned_LabelSelector_to_map(in.Selector, &out.Selector, s)
}
out.Template = new(PodTemplateSpec)
if err := Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(&in.Template, out.Template, s); err != nil {
return err
}
return invalidErr
}
func Convert_extensions_ReplicaSetStatus_to_v1_ReplicationControllerStatus(in *extensions.ReplicaSetStatus, out *ReplicationControllerStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.ReplicaSetStatus))(in)
}
out.Replicas = in.Replicas
out.FullyLabeledReplicas = in.FullyLabeledReplicas
out.ObservedGeneration = in.ObservedGeneration
return nil
}
func Convert_api_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *api.ReplicationControllerSpec, out *ReplicationControllerSpec, s conversion.Scope) error {
out.Replicas = &in.Replicas
out.Selector = in.Selector
//if in.TemplateRef != nil {
// out.TemplateRef = new(ObjectReference)
// if err := Convert_api_ObjectReference_To_v1_ObjectReference(in.TemplateRef, out.TemplateRef, s); err != nil {
// return err
// }
//} else {
// out.TemplateRef = nil
//}
if in.Template != nil {
out.Template = new(PodTemplateSpec)
if err := Convert_api_PodTemplateSpec_To_v1_PodTemplateSpec(in.Template, out.Template, s); err != nil {
@ -224,15 +326,6 @@ func Convert_api_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *a
func Convert_v1_ReplicationControllerSpec_To_api_ReplicationControllerSpec(in *ReplicationControllerSpec, out *api.ReplicationControllerSpec, s conversion.Scope) error {
out.Replicas = *in.Replicas
out.Selector = in.Selector
//if in.TemplateRef != nil {
// out.TemplateRef = new(api.ObjectReference)
// if err := Convert_v1_ObjectReference_To_api_ObjectReference(in.TemplateRef, out.TemplateRef, s); err != nil {
// return err
// }
//} else {
// out.TemplateRef = nil
//}
if in.Template != nil {
out.Template = new(api.PodTemplateSpec)
if err := Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(in.Template, out.Template, s); err != nil {