mirror of https://github.com/k3s-io/k3s
Preserve int data when unmarshalling for TPR
The Go json package converts all numbers to float64. This exposes many of the int64 fields to corruption when marshalled back to json. The json package provided by kubernetes also provides a way to defer conversion of numbers (https://golang.org/pkg/encoding/json/#Decoder.UseNumber) and does the conversions to int or float. This is also implemented in the custom json package. See: (https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/json/json.go) Fixes #30213 Update bazel build and add one more test case Fix for gofmt errorpull/6/head
parent
0f10d6ccf2
commit
eb88c4bce4
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue