| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012 |
- package opencost
- import (
- "bytes"
- "fmt"
- "reflect"
- "time"
- "github.com/opencost/opencost/core/pkg/log"
- "github.com/opencost/opencost/core/pkg/util/json"
- )
- // Encoding and decoding logic for Asset types
- // Any marshal and unmarshal
- // 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
- if _, found := fmap["window"]; found {
- a.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- 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
- }
- // Cloud marshal and unmarshal
- // 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
- if _, found := fmap["window"]; found {
- ca.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- 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
- }
- // ClusterManagement marshal and unmarshal
- // 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.GetStart().Format(time.RFC3339), ",")
- jsonEncodeString(buffer, "end", cm.GetEnd().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)
- }
- cm.Properties = &properties
- cm.Labels = labels
- if _, found := fmap["window"]; found {
- cm.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
- cm.Cost = Cost.(float64)
- }
- return nil
- }
- // Disk marshal and unmarshal
- // 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(), ",")
- if d.ByteHoursUsed == nil {
- jsonEncode(buffer, "byteHoursUsed", nil, ",")
- } else {
- jsonEncodeFloat64(buffer, "byteHoursUsed", *d.ByteHoursUsed, ",")
- }
- if d.ByteUsageMax == nil {
- jsonEncode(buffer, "byteUsageMax", nil, ",")
- } else {
- jsonEncodeFloat64(buffer, "byteUsageMax", *d.ByteUsageMax, ",")
- }
- jsonEncode(buffer, "breakdown", d.Breakdown, ",")
- jsonEncodeFloat64(buffer, "adjustment", d.Adjustment, ",")
- jsonEncodeFloat64(buffer, "totalCost", d.TotalCost(), ",")
- jsonEncodeString(buffer, "storageClass", d.StorageClass, ",")
- jsonEncodeString(buffer, "volumeName", d.VolumeName, ",")
- jsonEncodeString(buffer, "claimName", d.ClaimName, ",")
- jsonEncodeFloat64(buffer, "local", d.Local, ",")
- jsonEncodeString(buffer, "claimNamespace", d.ClaimNamespace, "")
- 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
- if _, found := fmap["window"]; found {
- d.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- 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)
- }
- if ByteHoursUsed, err := getTypedVal(fmap["byteHoursUsed"]); err == nil {
- if ByteHoursUsed == nil {
- d.ByteHoursUsed = nil
- } else {
- byteHours := ByteHoursUsed.(float64)
- d.ByteHoursUsed = &byteHours
- }
- }
- if ByteUsageMax, err := getTypedVal(fmap["byteUsageMax"]); err == nil {
- if ByteUsageMax == nil {
- d.ByteUsageMax = nil
- } else {
- max := ByteUsageMax.(float64)
- d.ByteUsageMax = &max
- }
- }
- if StorageClass, err := getTypedVal(fmap["storageClass"]); err == nil {
- d.StorageClass = StorageClass.(string)
- }
- if VolumeName, err := getTypedVal(fmap["volumeName"]); err == nil {
- d.VolumeName = VolumeName.(string)
- }
- if ClaimName, err := getTypedVal(fmap["claimName"]); err == nil {
- d.ClaimName = ClaimName.(string)
- }
- if ClaimNamespace, err := getTypedVal(fmap["claimNamespace"]); err == nil {
- d.ClaimNamespace = ClaimNamespace.(string)
- }
- if local, err := getTypedVal(fmap["local"]); err == nil {
- d.Local = local.(float64)
- }
- return nil
- }
- // Network marshal and unmarshal
- // 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
- if _, found := fmap["window"]; found {
- n.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- 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
- }
- // Node marshal and unmarshal
- // 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, ",")
- if poolName := GetNodePoolName(n.Properties.Provider, n.Labels); poolName != "" {
- jsonEncodeString(buffer, "pool", poolName, ",")
- }
- 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, ",")
- if n.Overhead != nil {
- jsonEncode(buffer, "overhead", n.Overhead, ",")
- }
- 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)
- if labelsInterface, ok := fmap["labels"].(map[string]interface{}); ok {
- for k, v := range labelsInterface {
- if strValue, ok := v.(string); ok {
- labels[k] = strValue
- }
- }
- }
- // 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
- if _, found := fmap["window"]; found {
- n.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- 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
- }
- // Loadbalancer marshal and unmarshal
- // 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(), ",")
- jsonEncode(buffer, "private", lb.Private, ",")
- jsonEncodeString(buffer, "ip", lb.Ip, "")
- 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
- if _, found := fmap["window"]; found {
- lb.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- 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
- }
- if private, err := getTypedVal(fmap["private"]); err == nil {
- lb.Private = private.(bool)
- }
- if ip, err := getTypedVal(fmap["ip"]); err == nil {
- lb.Ip = ip.(string)
- }
- return nil
- }
- // SharedAsset marshal and unmarshal
- // 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, "window", sa.Window, ",")
- jsonEncodeString(buffer, "start", sa.GetStart().Format(time.RFC3339), ",")
- jsonEncodeString(buffer, "end", sa.GetEnd().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)
- }
- sa.Properties = &properties
- sa.Labels = labels
- if _, found := fmap["window"]; found {
- sa.Window = toWindow(fmap["window"].(map[string]interface{}))
- }
- if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
- sa.Cost = Cost.(float64)
- }
- return nil
- }
- // AssetSet marshal
- // MarshalJSON JSON-encodes the AssetSet
- func (as *AssetSet) MarshalJSON() ([]byte, error) {
- if as == nil {
- return json.Marshal(map[string]Asset{})
- }
- return json.Marshal(as.Assets)
- }
- // AssetSetResponse for unmarshaling of AssetSet.assets into AssetSet
- // Unmarshals a marshaled AssetSet json into AssetSetResponse
- func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
- var assetMap map[string]*json.RawMessage
- // Partial unmarshal to map of json RawMessage
- err := json.Unmarshal(b, &assetMap)
- if err != nil {
- return err
- }
- err = asr.RawMessageToAssetSetResponse(assetMap)
- if err != nil {
- return err
- }
- return nil
- }
- func (asr *AssetSetResponse) RawMessageToAssetSetResponse(assetMap map[string]*json.RawMessage) error {
- 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
- }
- func (asrr *AssetSetRangeResponse) UnmarshalJSON(b []byte) error {
- var assetMapList []map[string]*json.RawMessage
- // Partial unmarshal to map of json RawMessage
- err := json.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
- }
- // Extra decoding util functions, for clarity
- // 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
- }
- func toWindow(fproperties map[string]interface{}) Window {
- var start, end time.Time
- var err error
- if startStr, v := fproperties["start"].(string); v {
- start, err = time.Parse(time.RFC3339, startStr)
- if err != nil {
- log.Errorf("error parsing window start from string %s, setting as 0 time", startStr)
- start = time.Time{}
- }
- }
- if endStr, v := fproperties["end"].(string); v {
- end, err = time.Parse(time.RFC3339, endStr)
- if err != nil {
- log.Errorf("error parsing window end from string %s, setting as 0 time", endStr)
- end = time.Time{}
- }
- }
- return NewClosedWindow(start, end)
- }
- // 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)
- }
- }
|