Explorar o código

Add logic/structs for unmarshaling directly from API response

Kaelan Patel %!s(int64=4) %!d(string=hai) anos
pai
achega
d0eb7dd79c

+ 18 - 1
pkg/kubecost/asset.go

@@ -2395,7 +2395,7 @@ func (sa *SharedAsset) String() string {
 // json, which makes it impossible to recreate an AssetSet struct. Thus,
 // json, which makes it impossible to recreate an AssetSet struct. Thus,
 // the type when unmarshaling a marshaled AssetSet,is AssetSetResponse
 // the type when unmarshaling a marshaled AssetSet,is AssetSetResponse
 type AssetSetResponse struct {
 type AssetSetResponse struct {
-	assets map[string]Asset
+	Assets map[string]Asset
 }
 }
 
 
 // AssetSet stores a set of Assets, each with a unique name, that share
 // AssetSet stores a set of Assets, each with a unique name, that share
@@ -2899,6 +2899,14 @@ func (asr *AssetSetRange) MarshalJSON() ([]byte, error) {
 	return json.Marshal(asr.assets)
 	return json.Marshal(asr.assets)
 }
 }
 
 
+// As with AssetSet, AssetSetRange does not serialize all its fields,
+// making it impossible to reconstruct the AssetSetRange from its json.
+// Therefore, the type a marshaled AssetSetRange unmarshals to is
+// AssetSetRangeResponse
+type AssetSetRangeResponse struct {
+	Assets []*AssetSetResponse
+}
+
 func (asr *AssetSetRange) UTCOffset() time.Duration {
 func (asr *AssetSetRange) UTCOffset() time.Duration {
 	if asr.Length() == 0 {
 	if asr.Length() == 0 {
 		return 0
 		return 0
@@ -2989,6 +2997,15 @@ func (asr *AssetSetRange) Minutes() float64 {
 	return duration.Minutes()
 	return duration.Minutes()
 }
 }
 
 
+// This is a helper type. The Asset API returns a json which cannot be natively
+// unmarshaled into any Asset struct. Therefore, this struct IN COMBINATION WITH
+// DESERIALIZATION LOGIC DEFINED IN asset_unmarshal.go can unmarshal a json directly
+// from an Assets API query
+type AssetAPIResponse struct {
+	Code int                   `json:"code"`
+	Data AssetSetRangeResponse `json:"data"`
+}
+
 // Returns true if string slices a and b contain all of the same strings, in any order.
 // Returns true if string slices a and b contain all of the same strings, in any order.
 func sameContents(a, b []string) bool {
 func sameContents(a, b []string) bool {
 	if len(a) != len(b) {
 	if len(a) != len(b) {

+ 41 - 1
pkg/kubecost/asset_unmarshal.go

@@ -731,6 +731,16 @@ func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
 		return err
 		return err
 	}
 	}
 
 
+	err = asr.RawMessageToAssetSetResponse(assetMap)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (asr *AssetSetResponse) RawMessageToAssetSetResponse(assetMap map[string]*gojson.RawMessage) error {
+
 	newAssetMap := make(map[string]Asset)
 	newAssetMap := make(map[string]Asset)
 
 
 	// For each item in asset map, unmarshal to appropriate type
 	// For each item in asset map, unmarshal to appropriate type
@@ -837,7 +847,37 @@ func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
 		}
 		}
 	}
 	}
 
 
-	asr.assets = newAssetMap
+	asr.Assets = newAssetMap
+
+	return nil
+}
+
+func (asrr *AssetSetRangeResponse) UnmarshalJSON(b []byte) error {
+
+	// gojson used here, as jsonitter UnmarshalJSON won't work with RawMessage
+	var assetMapList []map[string]*gojson.RawMessage
+
+	// Partial unmarshal to map of json RawMessage
+	err := gojson.Unmarshal(b, &assetMapList)
+	if err != nil {
+		return err
+	}
+
+	var assetSetList []*AssetSetResponse
+
+	for _, rawm := range assetMapList {
+
+		var asresp AssetSetResponse
+		err = asresp.RawMessageToAssetSetResponse(rawm)
+		if err != nil {
+			return err
+		}
+
+		assetSetList = append(assetSetList, &asresp)
+
+	}
+
+	asrr.Assets = assetSetList
 
 
 	return nil
 	return nil
 }
 }

+ 1 - 1
pkg/kubecost/asset_unmarshal_test.go

@@ -489,7 +489,7 @@ func TestAssetset_Unmarshal(t *testing.T) {
 	// For each asset in unmarshaled AssetSetResponse, check if it is equal to the corresponding AssetSet asset
 	// For each asset in unmarshaled AssetSetResponse, check if it is equal to the corresponding AssetSet asset
 	for key, asset := range assetset.assets {
 	for key, asset := range assetset.assets {
 
 
-		if unmarshaledAsset, exists := assetUnmarshalResponse.assets[key]; exists {
+		if unmarshaledAsset, exists := assetUnmarshalResponse.Assets[key]; exists {
 
 
 			// As Disk is not marshaled with all fields, the resultant Disk will be unequal. Test all fields we have instead.
 			// As Disk is not marshaled with all fields, the resultant Disk will be unequal. Test all fields we have instead.
 			if unmarshaledAsset.Type().String() == "Disk" {
 			if unmarshaledAsset.Type().String() == "Disk" {