diff --git a/pkg/registry/extensions/thirdpartyresourcedata/BUILD b/pkg/registry/extensions/thirdpartyresourcedata/BUILD index 020b4dd0b0..5a5a67d096 100644 --- a/pkg/registry/extensions/thirdpartyresourcedata/BUILD +++ b/pkg/registry/extensions/thirdpartyresourcedata/BUILD @@ -32,6 +32,7 @@ go_library( "//vendor:k8s.io/apimachinery/pkg/labels", "//vendor:k8s.io/apimachinery/pkg/runtime", "//vendor:k8s.io/apimachinery/pkg/runtime/schema", + "//vendor:k8s.io/apimachinery/pkg/util/json", "//vendor:k8s.io/apimachinery/pkg/util/validation/field", "//vendor:k8s.io/apimachinery/pkg/util/yaml", "//vendor:k8s.io/apimachinery/pkg/watch", diff --git a/pkg/registry/extensions/thirdpartyresourcedata/codec.go b/pkg/registry/extensions/thirdpartyresourcedata/codec.go index e78ddb58d5..1ac82fd050 100644 --- a/pkg/registry/extensions/thirdpartyresourcedata/codec.go +++ b/pkg/registry/extensions/thirdpartyresourcedata/codec.go @@ -18,7 +18,7 @@ package thirdpartyresourcedata import ( "bytes" - "encoding/json" + gojson "encoding/json" "fmt" "io" "net/url" @@ -28,6 +28,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/kubernetes/pkg/api" apiutil "k8s.io/kubernetes/pkg/api/util" @@ -233,14 +234,11 @@ func NewDecoder(delegate runtime.Decoder, kind string) runtime.Decoder { var _ runtime.Decoder = &thirdPartyResourceDataDecoder{} func parseObject(data []byte) (map[string]interface{}, error) { - var obj interface{} - if err := json.Unmarshal(data, &obj); err != nil { + var mapObj map[string]interface{} + if err := json.Unmarshal(data, &mapObj); err != nil { return nil, err } - mapObj, ok := obj.(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("unexpected object: %#v", obj) - } + return mapObj, nil } @@ -297,6 +295,7 @@ func (t *thirdPartyResourceDataDecoder) populateResource(objIn *extensions.Third if err := json.Unmarshal(metadataData, &objIn.ObjectMeta); err != nil { return err } + // Override API Version with the ThirdPartyResourceData value // TODO: fix this hard code objIn.APIVersion = v1beta1.SchemeGroupVersion.String() @@ -372,15 +371,11 @@ func (t *thirdPartyResourceDataDecoder) Decode(data []byte, gvk *schema.GroupVer } thirdParty := into.(*extensions.ThirdPartyResourceData) - var dataObj interface{} - if err := json.Unmarshal(data, &dataObj); err != nil { + var mapObj map[string]interface{} + if err := json.Unmarshal(data, &mapObj); err != nil { return nil, nil, err } - mapObj, ok := dataObj.(map[string]interface{}) - if !ok { - return nil, nil, fmt.Errorf("unexpected object: %#v", dataObj) - } /*if gvk.Kind != "ThirdPartyResourceData" { return nil, nil, fmt.Errorf("unexpected kind: %s", gvk.Kind) }*/ @@ -466,14 +461,10 @@ func NewEncoder(delegate runtime.Encoder, gvk schema.GroupVersionKind) runtime.E var _ runtime.Encoder = &thirdPartyResourceDataEncoder{} func encodeToJSON(obj *extensions.ThirdPartyResourceData, stream io.Writer) error { - var objOut interface{} - if err := json.Unmarshal(obj.Data, &objOut); err != nil { + var objMap map[string]interface{} + if err := json.Unmarshal(obj.Data, &objMap); err != nil { return err } - objMap, ok := objOut.(map[string]interface{}) - if !ok { - return fmt.Errorf("unexpected type: %v", objOut) - } objMap["metadata"] = &obj.ObjectMeta encoder := json.NewEncoder(stream) @@ -486,7 +477,7 @@ func (t *thirdPartyResourceDataEncoder) Encode(obj runtime.Object, stream io.Wri return encodeToJSON(obj, stream) case *extensions.ThirdPartyResourceDataList: // TODO: There are likely still better ways to do this... - listItems := make([]json.RawMessage, len(obj.Items)) + listItems := make([]gojson.RawMessage, len(obj.Items)) for ix := range obj.Items { buff := &bytes.Buffer{} @@ -494,7 +485,7 @@ func (t *thirdPartyResourceDataEncoder) Encode(obj runtime.Object, stream io.Wri if err != nil { return err } - listItems[ix] = json.RawMessage(buff.Bytes()) + listItems[ix] = gojson.RawMessage(buff.Bytes()) } if t.gvk.Empty() { @@ -503,8 +494,8 @@ func (t *thirdPartyResourceDataEncoder) Encode(obj runtime.Object, stream io.Wri encMap := struct { // +optional - Kind string `json:"kind,omitempty"` - Items []json.RawMessage `json:"items"` + Kind string `json:"kind,omitempty"` + Items []gojson.RawMessage `json:"items"` // +optional Metadata metav1.ListMeta `json:"metadata,omitempty"` // +optional diff --git a/pkg/registry/extensions/thirdpartyresourcedata/codec_test.go b/pkg/registry/extensions/thirdpartyresourcedata/codec_test.go index 742f8a0bcb..e5b354cd31 100644 --- a/pkg/registry/extensions/thirdpartyresourcedata/codec_test.go +++ b/pkg/registry/extensions/thirdpartyresourcedata/codec_test.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/json" "reflect" + "strings" "testing" "time" @@ -289,5 +290,40 @@ func TestThirdPartyResourceDataListEncoding(t *testing.T) { if targetOutput.APIVersion != gv.String() { t.Errorf("apiversion mismatch %v != %v", targetOutput.APIVersion, gv.String()) } - +} + +func TestDecodeNumbers(t *testing.T) { + gv := schema.GroupVersion{Group: "stable.foo.faz", Version: "v1"} + gvk := gv.WithKind("Foo") + e := &thirdPartyResourceDataEncoder{delegate: testapi.Extensions.Codec(), gvk: gvk} + d := &thirdPartyResourceDataDecoder{kind: "Foo", delegate: testapi.Extensions.Codec()} + + // Use highest int64 number and 1000000. + subject := &extensions.ThirdPartyResourceDataList{ + Items: []extensions.ThirdPartyResourceData{ + { + Data: []byte(`{"num1": 9223372036854775807, "num2": 1000000}`), + }, + }, + } + + // Encode to get original JSON. + originalJSON := bytes.NewBuffer([]byte{}) + err := e.Encode(subject, originalJSON) + if err != nil { + t.Errorf("encoding unexpected error: %v", err) + } + + // Decode original JSON. + var into runtime.Object + into, _, err = d.Decode(originalJSON.Bytes(), &gvk, into) + if err != nil { + t.Errorf("decoding unexpected error: %v", err) + } + + // Check if int is preserved. + decodedJSON := into.(*extensions.ThirdPartyResourceDataList).Items[0].Data + if !strings.Contains(string(decodedJSON), `"num1":9223372036854775807,"num2":1000000`) { + t.Errorf("Expected %s, got %s", `"num1":9223372036854775807,"num2":1000000`, string(decodedJSON)) + } }