Introduce ObjectConvertor for conversion to known API versions

Will allow clients to transform internal objects to a version
suitable for external output.
This commit is contained in:
Clayton Coleman 2014-11-01 18:38:02 -04:00
parent 2d54dfe249
commit 778a50d00b
4 changed files with 102 additions and 0 deletions

View File

@ -211,6 +211,46 @@ func (s *Scheme) Convert(in, out interface{}) error {
return s.converter.Convert(in, out, 0, s.generateConvertMeta(inVersion, outVersion))
}
// ConvertToVersion attempts to convert an input object to its matching Kind in another
// version within this scheme. Will return an error if the provided version does not
// contain the inKind (or a mapping by name defined with AddKnownTypeWithName).
func (s *Scheme) ConvertToVersion(in interface{}, outVersion string) (interface{}, error) {
t := reflect.TypeOf(in)
if t.Kind() != reflect.Ptr {
return nil, fmt.Errorf("only pointer types may be converted: %v", t)
}
t = t.Elem()
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
}
kinds, ok := s.typeToKind[t]
if !ok {
return nil, fmt.Errorf("%v cannot be converted into version %q", t, outVersion)
}
outKind := kinds[0]
inVersion, _, err := s.ObjectVersionAndKind(in)
if err != nil {
return nil, err
}
out, err := s.NewObject(outVersion, outKind)
if err != nil {
return nil, err
}
if err := s.converter.Convert(in, out, 0, s.generateConvertMeta(inVersion, outVersion)); err != nil {
return nil, err
}
if err := s.SetVersionAndKind(outVersion, outKind, out); err != nil {
return nil, err
}
return out, nil
}
// generateConvertMeta constructs the meta value we pass to Convert.
func (s *Scheme) generateConvertMeta(srcVersion, destVersion string) *Meta {
return &Meta{

View File

@ -240,6 +240,45 @@ func TestMultipleNames(t *testing.T) {
}
}
func TestKnownTypes(t *testing.T) {
s := GetTestScheme()
if len(s.KnownTypes("v2")) != 0 {
t.Errorf("should have no known types for v2")
}
types := s.KnownTypes("v1")
for _, s := range []string{"TestType1", "TestType2", "TestType3", "ExternalInternalSame"} {
if _, ok := types[s]; !ok {
t.Errorf("missing type %q", s)
}
}
}
func TestConvertToVersion(t *testing.T) {
s := GetTestScheme()
tt := &TestType1{A: "I'm not a pointer object"}
other, err := s.ConvertToVersion(tt, "v1")
if err != nil {
t.Fatalf("Failure: %v", err)
}
converted, ok := other.(*ExternalTestType1)
if !ok {
t.Fatalf("Got wrong type")
}
if tt.A != converted.A {
t.Fatalf("Failed to convert object correctly: %#v", converted)
}
}
func TestConvertToVersionErr(t *testing.T) {
s := GetTestScheme()
tt := TestType1{A: "I'm not a pointer object"}
_, err := s.ConvertToVersion(tt, "v1")
if err == nil {
t.Fatalf("unexpected non-error")
}
}
func TestEncode_NonPtr(t *testing.T) {
s := GetTestScheme()
tt := TestType1{A: "I'm not a pointer object"}

View File

@ -33,6 +33,11 @@ type Codec interface {
Encoder
}
// ObjectConvertor converts an object to a different version.
type ObjectConvertor interface {
ConvertToVersion(in Object, outVersion string) (out Object, err error)
}
// ObjectTyper contains methods for extracting the APIVersion and Kind
// of objects.
type ObjectTyper interface {

View File

@ -17,6 +17,7 @@ limitations under the License.
package runtime
import (
"fmt"
"reflect"
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
@ -223,6 +224,23 @@ func (s *Scheme) Convert(in, out interface{}) error {
return s.raw.Convert(in, out)
}
// ConvertToVersion attempts to convert an input object to its matching Kind in another
// version within this scheme. Will return an error if the provided version does not
// contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
// return an error if the conversion does not result in a valid Object being
// returned.
func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error) {
unknown, err := s.raw.ConvertToVersion(in, outVersion)
if err != nil {
return nil, err
}
obj, ok := unknown.(Object)
if !ok {
return nil, fmt.Errorf("the provided object cannot be converted to a runtime.Object: %#v", unknown)
}
return obj, nil
}
// EncodeToVersion turns the given api object into an appropriate JSON string.
// Will return an error if the object doesn't have an embedded TypeMeta.
// Obj may be a pointer to a struct, or a struct. If a struct, a copy