Skip to content

Commit 778a50d

Browse files
Introduce ObjectConvertor for conversion to known API versions
Will allow clients to transform internal objects to a version suitable for external output.
1 parent 2d54dfe commit 778a50d

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

pkg/conversion/scheme.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,46 @@ func (s *Scheme) Convert(in, out interface{}) error {
211211
return s.converter.Convert(in, out, 0, s.generateConvertMeta(inVersion, outVersion))
212212
}
213213

214+
// ConvertToVersion attempts to convert an input object to its matching Kind in another
215+
// version within this scheme. Will return an error if the provided version does not
216+
// contain the inKind (or a mapping by name defined with AddKnownTypeWithName).
217+
func (s *Scheme) ConvertToVersion(in interface{}, outVersion string) (interface{}, error) {
218+
t := reflect.TypeOf(in)
219+
if t.Kind() != reflect.Ptr {
220+
return nil, fmt.Errorf("only pointer types may be converted: %v", t)
221+
}
222+
t = t.Elem()
223+
if t.Kind() != reflect.Struct {
224+
return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
225+
}
226+
227+
kinds, ok := s.typeToKind[t]
228+
if !ok {
229+
return nil, fmt.Errorf("%v cannot be converted into version %q", t, outVersion)
230+
}
231+
outKind := kinds[0]
232+
233+
inVersion, _, err := s.ObjectVersionAndKind(in)
234+
if err != nil {
235+
return nil, err
236+
}
237+
238+
out, err := s.NewObject(outVersion, outKind)
239+
if err != nil {
240+
return nil, err
241+
}
242+
243+
if err := s.converter.Convert(in, out, 0, s.generateConvertMeta(inVersion, outVersion)); err != nil {
244+
return nil, err
245+
}
246+
247+
if err := s.SetVersionAndKind(outVersion, outKind, out); err != nil {
248+
return nil, err
249+
}
250+
251+
return out, nil
252+
}
253+
214254
// generateConvertMeta constructs the meta value we pass to Convert.
215255
func (s *Scheme) generateConvertMeta(srcVersion, destVersion string) *Meta {
216256
return &Meta{

pkg/conversion/scheme_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,45 @@ func TestMultipleNames(t *testing.T) {
240240
}
241241
}
242242

243+
func TestKnownTypes(t *testing.T) {
244+
s := GetTestScheme()
245+
if len(s.KnownTypes("v2")) != 0 {
246+
t.Errorf("should have no known types for v2")
247+
}
248+
249+
types := s.KnownTypes("v1")
250+
for _, s := range []string{"TestType1", "TestType2", "TestType3", "ExternalInternalSame"} {
251+
if _, ok := types[s]; !ok {
252+
t.Errorf("missing type %q", s)
253+
}
254+
}
255+
}
256+
257+
func TestConvertToVersion(t *testing.T) {
258+
s := GetTestScheme()
259+
tt := &TestType1{A: "I'm not a pointer object"}
260+
other, err := s.ConvertToVersion(tt, "v1")
261+
if err != nil {
262+
t.Fatalf("Failure: %v", err)
263+
}
264+
converted, ok := other.(*ExternalTestType1)
265+
if !ok {
266+
t.Fatalf("Got wrong type")
267+
}
268+
if tt.A != converted.A {
269+
t.Fatalf("Failed to convert object correctly: %#v", converted)
270+
}
271+
}
272+
273+
func TestConvertToVersionErr(t *testing.T) {
274+
s := GetTestScheme()
275+
tt := TestType1{A: "I'm not a pointer object"}
276+
_, err := s.ConvertToVersion(tt, "v1")
277+
if err == nil {
278+
t.Fatalf("unexpected non-error")
279+
}
280+
}
281+
243282
func TestEncode_NonPtr(t *testing.T) {
244283
s := GetTestScheme()
245284
tt := TestType1{A: "I'm not a pointer object"}

pkg/runtime/interfaces.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ type Codec interface {
3333
Encoder
3434
}
3535

36+
// ObjectConvertor converts an object to a different version.
37+
type ObjectConvertor interface {
38+
ConvertToVersion(in Object, outVersion string) (out Object, err error)
39+
}
40+
3641
// ObjectTyper contains methods for extracting the APIVersion and Kind
3742
// of objects.
3843
type ObjectTyper interface {

pkg/runtime/scheme.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package runtime
1818

1919
import (
20+
"fmt"
2021
"reflect"
2122

2223
"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
@@ -223,6 +224,23 @@ func (s *Scheme) Convert(in, out interface{}) error {
223224
return s.raw.Convert(in, out)
224225
}
225226

227+
// ConvertToVersion attempts to convert an input object to its matching Kind in another
228+
// version within this scheme. Will return an error if the provided version does not
229+
// contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
230+
// return an error if the conversion does not result in a valid Object being
231+
// returned.
232+
func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error) {
233+
unknown, err := s.raw.ConvertToVersion(in, outVersion)
234+
if err != nil {
235+
return nil, err
236+
}
237+
obj, ok := unknown.(Object)
238+
if !ok {
239+
return nil, fmt.Errorf("the provided object cannot be converted to a runtime.Object: %#v", unknown)
240+
}
241+
return obj, nil
242+
}
243+
226244
// EncodeToVersion turns the given api object into an appropriate JSON string.
227245
// Will return an error if the object doesn't have an embedded TypeMeta.
228246
// Obj may be a pointer to a struct, or a struct. If a struct, a copy

0 commit comments

Comments
 (0)