|
|
@@ -1,16 +1,12 @@
|
|
|
package kubecost
|
|
|
|
|
|
import (
|
|
|
- "bytes"
|
|
|
"encoding"
|
|
|
"fmt"
|
|
|
- "reflect"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
"time"
|
|
|
|
|
|
- gojson "encoding/json" // gojson is default golang json, required for RawMessage decoding
|
|
|
-
|
|
|
"github.com/kubecost/cost-model/pkg/log"
|
|
|
"github.com/kubecost/cost-model/pkg/util/json"
|
|
|
)
|
|
|
@@ -603,82 +599,6 @@ func (a *Any) Equal(that Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements json.Marshaler
|
|
|
-func (a *Any) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncode(buffer, "properties", a.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", a.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", a.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", a.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", a.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", a.Minutes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "adjustment", a.Adjustment(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", a.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (a *Any) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = a.InterfaceToAny(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to Any, carrying over relevant fields
|
|
|
-func (a *Any) InterfaceToAny(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- a.properties = &properties
|
|
|
- a.labels = labels
|
|
|
- a.start = start
|
|
|
- a.end = end
|
|
|
- a.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
-
|
|
|
- if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
|
|
|
- a.adjustment = adjustment.(float64)
|
|
|
- }
|
|
|
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
|
|
|
- a.Cost = Cost.(float64) - a.adjustment
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (a *Any) String() string {
|
|
|
return toString(a)
|
|
|
@@ -906,87 +826,6 @@ func (ca *Cloud) Equal(a Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements json.Marshaler
|
|
|
-func (ca *Cloud) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncodeString(buffer, "type", ca.Type().String(), ",")
|
|
|
- jsonEncode(buffer, "properties", ca.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", ca.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", ca.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", ca.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", ca.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", ca.Minutes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "adjustment", ca.Adjustment(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "credit", ca.Credit, ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", ca.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (ca *Cloud) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = ca.InterfaceToCloud(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to Cloud, carrying over relevant fields
|
|
|
-func (ca *Cloud) InterfaceToCloud(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- ca.properties = &properties
|
|
|
- ca.labels = labels
|
|
|
- ca.start = start
|
|
|
- ca.end = end
|
|
|
- ca.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
-
|
|
|
- if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
|
|
|
- ca.adjustment = adjustment.(float64)
|
|
|
- }
|
|
|
- if Credit, err := getTypedVal(fmap["credit"]); err == nil {
|
|
|
- ca.Credit = Credit.(float64)
|
|
|
- }
|
|
|
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
|
|
|
- ca.Cost = Cost.(float64) - ca.adjustment - ca.Credit
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (ca *Cloud) String() string {
|
|
|
return toString(ca)
|
|
|
@@ -1170,77 +1009,6 @@ func (cm *ClusterManagement) Equal(a Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements json.Marshler
|
|
|
-func (cm *ClusterManagement) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncodeString(buffer, "type", cm.Type().String(), ",")
|
|
|
- jsonEncode(buffer, "properties", cm.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", cm.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", cm.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", cm.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", cm.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", cm.Minutes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", cm.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (cm *ClusterManagement) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = cm.InterfaceToClusterManagement(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to ClusterManagement, carrying over relevant fields
|
|
|
-func (cm *ClusterManagement) InterfaceToClusterManagement(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- cm.properties = &properties
|
|
|
- cm.labels = labels
|
|
|
- cm.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
-
|
|
|
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
|
|
|
- cm.Cost = Cost.(float64)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (cm *ClusterManagement) String() string {
|
|
|
return toString(cm)
|
|
|
@@ -1507,100 +1275,6 @@ func (d *Disk) Equal(a Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements the json.Marshaler interface
|
|
|
-func (d *Disk) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncodeString(buffer, "type", d.Type().String(), ",")
|
|
|
- jsonEncode(buffer, "properties", d.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", d.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", d.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", d.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", d.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", d.Minutes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "byteHours", d.ByteHours, ",")
|
|
|
- jsonEncodeFloat64(buffer, "bytes", d.Bytes(), ",")
|
|
|
- jsonEncode(buffer, "breakdown", d.Breakdown, ",")
|
|
|
- jsonEncodeFloat64(buffer, "adjustment", d.Adjustment(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", d.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (d *Disk) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = d.InterfaceToDisk(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to Disk, carrying over relevant fields
|
|
|
-func (d *Disk) InterfaceToDisk(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- fbreakdown := fmap["breakdown"].(map[string]interface{})
|
|
|
-
|
|
|
- breakdown := toBreakdown(fbreakdown)
|
|
|
-
|
|
|
- d.properties = &properties
|
|
|
- d.labels = labels
|
|
|
- d.start = start
|
|
|
- d.end = end
|
|
|
- d.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
- d.Breakdown = &breakdown
|
|
|
-
|
|
|
- if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
|
|
|
- d.adjustment = adjustment.(float64)
|
|
|
- }
|
|
|
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
|
|
|
- d.Cost = Cost.(float64) - d.adjustment
|
|
|
- }
|
|
|
- if ByteHours, err := getTypedVal(fmap["byteHours"]); err == nil {
|
|
|
- d.ByteHours = ByteHours.(float64)
|
|
|
- }
|
|
|
-
|
|
|
- // d.Local is not marhsaled, and cannot be calculated from marshaled values.
|
|
|
- // Currently, it is just ignored and not set in the resulting unmarshal to Disk
|
|
|
- // be aware that this means a resulting Disk from an unmarshal is therefore NOT
|
|
|
- // equal to the originally marshaled Disk.
|
|
|
-
|
|
|
- return nil
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (d *Disk) String() string {
|
|
|
return toString(d)
|
|
|
@@ -1899,84 +1573,6 @@ func (n *Network) Equal(a Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements json.Marshal interface
|
|
|
-func (n *Network) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncodeString(buffer, "type", n.Type().String(), ",")
|
|
|
- jsonEncode(buffer, "properties", n.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", n.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", n.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", n.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", n.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (n *Network) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = n.InterfaceToNetwork(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to Network, carrying over relevant fields
|
|
|
-func (n *Network) InterfaceToNetwork(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- n.properties = &properties
|
|
|
- n.labels = labels
|
|
|
- n.start = start
|
|
|
- n.end = end
|
|
|
- n.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
-
|
|
|
- if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
|
|
|
- n.adjustment = adjustment.(float64)
|
|
|
- }
|
|
|
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
|
|
|
- n.Cost = Cost.(float64) - n.adjustment
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (n *Network) String() string {
|
|
|
return toString(n)
|
|
|
@@ -2321,132 +1917,6 @@ func (n *Node) Equal(a Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements json.Marshal interface
|
|
|
-func (n *Node) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncodeString(buffer, "type", n.Type().String(), ",")
|
|
|
- jsonEncode(buffer, "properties", n.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", n.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", n.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", n.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", n.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
|
|
|
- jsonEncodeString(buffer, "nodeType", n.NodeType, ",")
|
|
|
- jsonEncodeFloat64(buffer, "cpuCores", n.CPUCores(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "ramBytes", n.RAMBytes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "cpuCoreHours", n.CPUCoreHours, ",")
|
|
|
- jsonEncodeFloat64(buffer, "ramByteHours", n.RAMByteHours, ",")
|
|
|
- jsonEncodeFloat64(buffer, "GPUHours", n.GPUHours, ",")
|
|
|
- jsonEncode(buffer, "cpuBreakdown", n.CPUBreakdown, ",")
|
|
|
- jsonEncode(buffer, "ramBreakdown", n.RAMBreakdown, ",")
|
|
|
- jsonEncodeFloat64(buffer, "preemptible", n.Preemptible, ",")
|
|
|
- jsonEncodeFloat64(buffer, "discount", n.Discount, ",")
|
|
|
- jsonEncodeFloat64(buffer, "cpuCost", n.CPUCost, ",")
|
|
|
- jsonEncodeFloat64(buffer, "gpuCost", n.GPUCost, ",")
|
|
|
- jsonEncodeFloat64(buffer, "gpuCount", n.GPUs(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "ramCost", n.RAMCost, ",")
|
|
|
- jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (n *Node) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = n.InterfaceToNode(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to Node, carrying over relevant fields
|
|
|
-func (n *Node) InterfaceToNode(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- fcpuBreakdown := fmap["cpuBreakdown"].(map[string]interface{})
|
|
|
- framBreakdown := fmap["ramBreakdown"].(map[string]interface{})
|
|
|
-
|
|
|
- cpuBreakdown := toBreakdown(fcpuBreakdown)
|
|
|
- ramBreakdown := toBreakdown(framBreakdown)
|
|
|
-
|
|
|
- n.properties = &properties
|
|
|
- n.labels = labels
|
|
|
- n.start = start
|
|
|
- n.end = end
|
|
|
- n.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
- n.CPUBreakdown = &cpuBreakdown
|
|
|
- n.RAMBreakdown = &ramBreakdown
|
|
|
-
|
|
|
- if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
|
|
|
- n.adjustment = adjustment.(float64)
|
|
|
- }
|
|
|
- if NodeType, err := getTypedVal(fmap["nodeType"]); err == nil {
|
|
|
- n.NodeType = NodeType.(string)
|
|
|
- }
|
|
|
- if CPUCoreHours, err := getTypedVal(fmap["cpuCoreHours"]); err == nil {
|
|
|
- n.CPUCoreHours = CPUCoreHours.(float64)
|
|
|
- }
|
|
|
- if RAMByteHours, err := getTypedVal(fmap["ramByteHours"]); err == nil {
|
|
|
- n.RAMByteHours = RAMByteHours.(float64)
|
|
|
- }
|
|
|
- if GPUHours, err := getTypedVal(fmap["GPUHours"]); err == nil {
|
|
|
- n.GPUHours = GPUHours.(float64)
|
|
|
- }
|
|
|
- if CPUCost, err := getTypedVal(fmap["cpuCost"]); err == nil {
|
|
|
- n.CPUCost = CPUCost.(float64)
|
|
|
- }
|
|
|
- if GPUCost, err := getTypedVal(fmap["gpuCost"]); err == nil {
|
|
|
- n.GPUCost = GPUCost.(float64)
|
|
|
- }
|
|
|
- if GPUCount, err := getTypedVal(fmap["gpuCount"]); err == nil {
|
|
|
- n.GPUCount = GPUCount.(float64)
|
|
|
- }
|
|
|
- if RAMCost, err := getTypedVal(fmap["ramCost"]); err == nil {
|
|
|
- n.RAMCost = RAMCost.(float64)
|
|
|
- }
|
|
|
- if Discount, err := getTypedVal(fmap["discount"]); err == nil {
|
|
|
- n.Discount = Discount.(float64)
|
|
|
- }
|
|
|
- if Preemptible, err := getTypedVal(fmap["preemptible"]); err == nil {
|
|
|
- n.Preemptible = Preemptible.(float64)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (n *Node) String() string {
|
|
|
return toString(n)
|
|
|
@@ -2723,84 +2193,6 @@ func (lb *LoadBalancer) Equal(a Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements json.Marshal
|
|
|
-func (lb *LoadBalancer) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncodeString(buffer, "type", lb.Type().String(), ",")
|
|
|
- jsonEncode(buffer, "properties", lb.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", lb.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", lb.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", lb.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", lb.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", lb.Minutes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "adjustment", lb.Adjustment(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", lb.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (lb *LoadBalancer) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = lb.InterfaceToLoadBalancer(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to LoadBalancer, carrying over relevant fields
|
|
|
-func (lb *LoadBalancer) InterfaceToLoadBalancer(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- lb.properties = &properties
|
|
|
- lb.labels = labels
|
|
|
- lb.start = start
|
|
|
- lb.end = end
|
|
|
- lb.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
-
|
|
|
- if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
|
|
|
- lb.adjustment = adjustment.(float64)
|
|
|
- }
|
|
|
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
|
|
|
- lb.Cost = Cost.(float64) - lb.adjustment
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (lb *LoadBalancer) String() string {
|
|
|
return toString(lb)
|
|
|
@@ -2994,80 +2386,6 @@ func (sa *SharedAsset) Equal(a Asset) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON implements json.Marshaler
|
|
|
-func (sa *SharedAsset) MarshalJSON() ([]byte, error) {
|
|
|
- buffer := bytes.NewBufferString("{")
|
|
|
- jsonEncodeString(buffer, "type", sa.Type().String(), ",")
|
|
|
- jsonEncode(buffer, "properties", sa.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", sa.Labels(), ",")
|
|
|
- jsonEncode(buffer, "properties", sa.Properties(), ",")
|
|
|
- jsonEncode(buffer, "labels", sa.Labels(), ",")
|
|
|
- jsonEncode(buffer, "window", sa.Window(), ",")
|
|
|
- jsonEncodeString(buffer, "start", sa.Start().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeString(buffer, "end", sa.End().Format(time.RFC3339), ",")
|
|
|
- jsonEncodeFloat64(buffer, "minutes", sa.Minutes(), ",")
|
|
|
- jsonEncodeFloat64(buffer, "totalCost", sa.TotalCost(), "")
|
|
|
- buffer.WriteString("}")
|
|
|
- return buffer.Bytes(), nil
|
|
|
-}
|
|
|
-
|
|
|
-func (sa *SharedAsset) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(b, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- err = sa.InterfaceToSharedAsset(f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// Converts interface{} to SharedAsset, carrying over relevant fields
|
|
|
-func (sa *SharedAsset) InterfaceToSharedAsset(itf interface{}) error {
|
|
|
-
|
|
|
- fmap := itf.(map[string]interface{})
|
|
|
-
|
|
|
- // parse properties map to AssetProperties
|
|
|
- fproperties := fmap["properties"].(map[string]interface{})
|
|
|
- properties := toAssetProp(fproperties)
|
|
|
-
|
|
|
- // parse labels map to AssetLabels
|
|
|
- labels := make(map[string]string)
|
|
|
- for k, v := range fmap["labels"].(map[string]interface{}) {
|
|
|
- labels[k] = v.(string)
|
|
|
- }
|
|
|
-
|
|
|
- // parse start and end strings to time.Time
|
|
|
- start, err := time.Parse(time.RFC3339, fmap["start"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- end, err := time.Parse(time.RFC3339, fmap["end"].(string))
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- sa.properties = &properties
|
|
|
- sa.labels = labels
|
|
|
- sa.window = Window{
|
|
|
- start: &start,
|
|
|
- end: &end,
|
|
|
- }
|
|
|
-
|
|
|
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
|
|
|
- sa.Cost = Cost.(float64)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
// String implements fmt.Stringer
|
|
|
func (sa *SharedAsset) String() string {
|
|
|
return toString(sa)
|
|
|
@@ -3080,129 +2398,6 @@ type AssetSetResponse struct {
|
|
|
assets map[string]Asset
|
|
|
}
|
|
|
|
|
|
-// Unmarshals a marshaled AssetSet json into AssetSetResponse
|
|
|
-func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
|
|
|
-
|
|
|
- // gojson used here, as jsonitter UnmarshalJSON won't work with RawMessage
|
|
|
- var assetMap map[string]*gojson.RawMessage
|
|
|
-
|
|
|
- // Partial unmarshal to map of json RawMessage
|
|
|
- err := gojson.Unmarshal(b, &assetMap)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap := make(map[string]Asset)
|
|
|
-
|
|
|
- // For each item in asset map, unmarshal to appropriate type
|
|
|
- for key, rawMessage := range assetMap {
|
|
|
-
|
|
|
- var f interface{}
|
|
|
-
|
|
|
- err := json.Unmarshal(*rawMessage, &f)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- fmap := f.(map[string]interface{})
|
|
|
-
|
|
|
- switch t := fmap["type"]; t {
|
|
|
- case "Cloud":
|
|
|
-
|
|
|
- var ca Cloud
|
|
|
- err := ca.InterfaceToCloud(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &ca
|
|
|
-
|
|
|
- case "ClusterManagement":
|
|
|
-
|
|
|
- var cm ClusterManagement
|
|
|
- err := cm.InterfaceToClusterManagement(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &cm
|
|
|
-
|
|
|
- case "Disk":
|
|
|
-
|
|
|
- var d Disk
|
|
|
- err := d.InterfaceToDisk(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &d
|
|
|
-
|
|
|
- case "Network":
|
|
|
-
|
|
|
- var nw Network
|
|
|
- err := nw.InterfaceToNetwork(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &nw
|
|
|
-
|
|
|
- case "Node":
|
|
|
-
|
|
|
- var n Node
|
|
|
- err := n.InterfaceToNode(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &n
|
|
|
-
|
|
|
- case "LoadBalancer":
|
|
|
-
|
|
|
- var lb LoadBalancer
|
|
|
- err := lb.InterfaceToLoadBalancer(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &lb
|
|
|
-
|
|
|
- case "Shared":
|
|
|
-
|
|
|
- var sa SharedAsset
|
|
|
- err := sa.InterfaceToSharedAsset(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &sa
|
|
|
-
|
|
|
- default:
|
|
|
-
|
|
|
- var a Any
|
|
|
- err := a.InterfaceToAny(f)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- newAssetMap[key] = &a
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- asr.assets = newAssetMap
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
// AssetSet stores a set of Assets, each with a unique name, that share
|
|
|
// a window. An AssetSet is mutable, so treat it like a threadsafe map.
|
|
|
type AssetSet struct {
|
|
|
@@ -3497,13 +2692,6 @@ func (as *AssetSet) Map() map[string]Asset {
|
|
|
return as.Clone().assets
|
|
|
}
|
|
|
|
|
|
-// MarshalJSON JSON-encodes the AssetSet
|
|
|
-func (as *AssetSet) MarshalJSON() ([]byte, error) {
|
|
|
- as.RLock()
|
|
|
- defer as.RUnlock()
|
|
|
- return json.Marshal(as.assets)
|
|
|
-}
|
|
|
-
|
|
|
func (as *AssetSet) Set(asset Asset, aggregateBy []string) error {
|
|
|
if as.IsEmpty() {
|
|
|
as.Lock()
|
|
|
@@ -3822,71 +3010,3 @@ func contains(slice []string, item string) bool {
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
-
|
|
|
-// Creates an AssetProperties directly from map[string]interface{}
|
|
|
-func toAssetProp(fproperties map[string]interface{}) AssetProperties {
|
|
|
- var properties AssetProperties
|
|
|
-
|
|
|
- if category, v := fproperties["category"].(string); v {
|
|
|
- properties.Category = category
|
|
|
- }
|
|
|
- if provider, v := fproperties["provider"].(string); v {
|
|
|
- properties.Provider = provider
|
|
|
- }
|
|
|
- if account, v := fproperties["account"].(string); v {
|
|
|
- properties.Account = account
|
|
|
- }
|
|
|
- if project, v := fproperties["project"].(string); v {
|
|
|
- properties.Project = project
|
|
|
- }
|
|
|
- if service, v := fproperties["service"].(string); v {
|
|
|
- properties.Service = service
|
|
|
- }
|
|
|
- if cluster, v := fproperties["cluster"].(string); v {
|
|
|
- properties.Cluster = cluster
|
|
|
- }
|
|
|
- if name, v := fproperties["name"].(string); v {
|
|
|
- properties.Name = name
|
|
|
- }
|
|
|
- if providerID, v := fproperties["providerID"].(string); v {
|
|
|
- properties.ProviderID = providerID
|
|
|
- }
|
|
|
-
|
|
|
- return properties
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-// Creates an Breakdown directly from map[string]interface{}
|
|
|
-func toBreakdown(fproperties map[string]interface{}) Breakdown {
|
|
|
- var breakdown Breakdown
|
|
|
-
|
|
|
- if idle, v := fproperties["idle"].(float64); v {
|
|
|
- breakdown.Idle = idle
|
|
|
- }
|
|
|
- if other, v := fproperties["other"].(float64); v {
|
|
|
- breakdown.Other = other
|
|
|
- }
|
|
|
- if system, v := fproperties["system"].(float64); v {
|
|
|
- breakdown.System = system
|
|
|
- }
|
|
|
- if user, v := fproperties["user"].(float64); v {
|
|
|
- breakdown.User = user
|
|
|
- }
|
|
|
-
|
|
|
- return breakdown
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-// Not strictly nessesary, but cleans up the code and is a secondary check
|
|
|
-// for correct types
|
|
|
-func getTypedVal(itf interface{}) (interface{}, error) {
|
|
|
- switch itf := itf.(type) {
|
|
|
- case float64:
|
|
|
- return float64(itf), nil
|
|
|
- case string:
|
|
|
- return string(itf), nil
|
|
|
- default:
|
|
|
- unktype := reflect.ValueOf(itf)
|
|
|
- return nil, fmt.Errorf("Type %v is an invalid type", unktype)
|
|
|
- }
|
|
|
-}
|