asset_json.go 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  1. package opencost
  2. import (
  3. "bytes"
  4. "fmt"
  5. "reflect"
  6. "time"
  7. "github.com/opencost/opencost/core/pkg/log"
  8. "github.com/opencost/opencost/core/pkg/util/json"
  9. )
  10. // Encoding and decoding logic for Asset types
  11. // Any marshal and unmarshal
  12. // MarshalJSON implements json.Marshaler
  13. func (a *Any) MarshalJSON() ([]byte, error) {
  14. buffer := bytes.NewBufferString("{")
  15. jsonEncode(buffer, "properties", a.Properties, ",")
  16. jsonEncode(buffer, "labels", a.Labels, ",")
  17. jsonEncode(buffer, "window", a.Window, ",")
  18. jsonEncodeString(buffer, "start", a.Start.Format(time.RFC3339), ",")
  19. jsonEncodeString(buffer, "end", a.End.Format(time.RFC3339), ",")
  20. jsonEncodeFloat64(buffer, "minutes", a.Minutes(), ",")
  21. jsonEncodeFloat64(buffer, "adjustment", a.Adjustment, ",")
  22. jsonEncodeFloat64(buffer, "totalCost", a.TotalCost(), "")
  23. buffer.WriteString("}")
  24. return buffer.Bytes(), nil
  25. }
  26. func (a *Any) UnmarshalJSON(b []byte) error {
  27. var f interface{}
  28. err := json.Unmarshal(b, &f)
  29. if err != nil {
  30. return err
  31. }
  32. err = a.InterfaceToAny(f)
  33. if err != nil {
  34. return err
  35. }
  36. return nil
  37. }
  38. // Converts interface{} to Any, carrying over relevant fields
  39. func (a *Any) InterfaceToAny(itf interface{}) error {
  40. fmap := itf.(map[string]interface{})
  41. // parse properties map to AssetProperties
  42. fproperties := fmap["properties"].(map[string]interface{})
  43. properties := toAssetProp(fproperties)
  44. // parse labels map to AssetLabels
  45. labels := make(map[string]string)
  46. for k, v := range fmap["labels"].(map[string]interface{}) {
  47. labels[k] = v.(string)
  48. }
  49. // parse start and end strings to time.Time
  50. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  51. if err != nil {
  52. return err
  53. }
  54. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  55. if err != nil {
  56. return err
  57. }
  58. a.Properties = &properties
  59. a.Labels = labels
  60. a.Start = start
  61. a.End = end
  62. if _, found := fmap["window"]; found {
  63. a.Window = toWindow(fmap["window"].(map[string]interface{}))
  64. }
  65. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  66. a.Adjustment = adjustment.(float64)
  67. }
  68. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  69. a.Cost = Cost.(float64) - a.Adjustment
  70. }
  71. return nil
  72. }
  73. // Cloud marshal and unmarshal
  74. // MarshalJSON implements json.Marshaler
  75. func (ca *Cloud) MarshalJSON() ([]byte, error) {
  76. buffer := bytes.NewBufferString("{")
  77. jsonEncodeString(buffer, "type", ca.Type().String(), ",")
  78. jsonEncode(buffer, "properties", ca.Properties, ",")
  79. jsonEncode(buffer, "labels", ca.Labels, ",")
  80. jsonEncode(buffer, "window", ca.Window, ",")
  81. jsonEncodeString(buffer, "start", ca.Start.Format(time.RFC3339), ",")
  82. jsonEncodeString(buffer, "end", ca.End.Format(time.RFC3339), ",")
  83. jsonEncodeFloat64(buffer, "minutes", ca.Minutes(), ",")
  84. jsonEncodeFloat64(buffer, "adjustment", ca.Adjustment, ",")
  85. jsonEncodeFloat64(buffer, "credit", ca.Credit, ",")
  86. jsonEncodeFloat64(buffer, "totalCost", ca.TotalCost(), "")
  87. buffer.WriteString("}")
  88. return buffer.Bytes(), nil
  89. }
  90. func (ca *Cloud) UnmarshalJSON(b []byte) error {
  91. var f interface{}
  92. err := json.Unmarshal(b, &f)
  93. if err != nil {
  94. return err
  95. }
  96. err = ca.InterfaceToCloud(f)
  97. if err != nil {
  98. return err
  99. }
  100. return nil
  101. }
  102. // Converts interface{} to Cloud, carrying over relevant fields
  103. func (ca *Cloud) InterfaceToCloud(itf interface{}) error {
  104. fmap := itf.(map[string]interface{})
  105. // parse properties map to AssetProperties
  106. fproperties := fmap["properties"].(map[string]interface{})
  107. properties := toAssetProp(fproperties)
  108. // parse labels map to AssetLabels
  109. labels := make(map[string]string)
  110. for k, v := range fmap["labels"].(map[string]interface{}) {
  111. labels[k] = v.(string)
  112. }
  113. // parse start and end strings to time.Time
  114. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  115. if err != nil {
  116. return err
  117. }
  118. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  119. if err != nil {
  120. return err
  121. }
  122. ca.Properties = &properties
  123. ca.Labels = labels
  124. ca.Start = start
  125. ca.End = end
  126. if _, found := fmap["window"]; found {
  127. ca.Window = toWindow(fmap["window"].(map[string]interface{}))
  128. }
  129. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  130. ca.Adjustment = adjustment.(float64)
  131. }
  132. if Credit, err := getTypedVal(fmap["credit"]); err == nil {
  133. ca.Credit = Credit.(float64)
  134. }
  135. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  136. ca.Cost = Cost.(float64) - ca.Adjustment - ca.Credit
  137. }
  138. return nil
  139. }
  140. // ClusterManagement marshal and unmarshal
  141. // MarshalJSON implements json.Marshler
  142. func (cm *ClusterManagement) MarshalJSON() ([]byte, error) {
  143. buffer := bytes.NewBufferString("{")
  144. jsonEncodeString(buffer, "type", cm.Type().String(), ",")
  145. jsonEncode(buffer, "properties", cm.Properties, ",")
  146. jsonEncode(buffer, "labels", cm.Labels, ",")
  147. jsonEncode(buffer, "window", cm.Window, ",")
  148. jsonEncodeString(buffer, "start", cm.GetStart().Format(time.RFC3339), ",")
  149. jsonEncodeString(buffer, "end", cm.GetEnd().Format(time.RFC3339), ",")
  150. jsonEncodeFloat64(buffer, "minutes", cm.Minutes(), ",")
  151. jsonEncodeFloat64(buffer, "totalCost", cm.TotalCost(), "")
  152. buffer.WriteString("}")
  153. return buffer.Bytes(), nil
  154. }
  155. func (cm *ClusterManagement) UnmarshalJSON(b []byte) error {
  156. var f interface{}
  157. err := json.Unmarshal(b, &f)
  158. if err != nil {
  159. return err
  160. }
  161. err = cm.InterfaceToClusterManagement(f)
  162. if err != nil {
  163. return err
  164. }
  165. return nil
  166. }
  167. // Converts interface{} to ClusterManagement, carrying over relevant fields
  168. func (cm *ClusterManagement) InterfaceToClusterManagement(itf interface{}) error {
  169. fmap := itf.(map[string]interface{})
  170. // parse properties map to AssetProperties
  171. fproperties := fmap["properties"].(map[string]interface{})
  172. properties := toAssetProp(fproperties)
  173. // parse labels map to AssetLabels
  174. labels := make(map[string]string)
  175. for k, v := range fmap["labels"].(map[string]interface{}) {
  176. labels[k] = v.(string)
  177. }
  178. cm.Properties = &properties
  179. cm.Labels = labels
  180. if _, found := fmap["window"]; found {
  181. cm.Window = toWindow(fmap["window"].(map[string]interface{}))
  182. }
  183. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  184. cm.Cost = Cost.(float64)
  185. }
  186. return nil
  187. }
  188. // Disk marshal and unmarshal
  189. // MarshalJSON implements the json.Marshaler interface
  190. func (d *Disk) MarshalJSON() ([]byte, error) {
  191. buffer := bytes.NewBufferString("{")
  192. jsonEncodeString(buffer, "type", d.Type().String(), ",")
  193. jsonEncode(buffer, "properties", d.Properties, ",")
  194. jsonEncode(buffer, "labels", d.Labels, ",")
  195. jsonEncode(buffer, "window", d.Window, ",")
  196. jsonEncodeString(buffer, "start", d.Start.Format(time.RFC3339), ",")
  197. jsonEncodeString(buffer, "end", d.End.Format(time.RFC3339), ",")
  198. jsonEncodeFloat64(buffer, "minutes", d.Minutes(), ",")
  199. jsonEncodeFloat64(buffer, "byteHours", d.ByteHours, ",")
  200. jsonEncodeFloat64(buffer, "bytes", d.Bytes(), ",")
  201. if d.ByteHoursUsed == nil {
  202. jsonEncode(buffer, "byteHoursUsed", nil, ",")
  203. } else {
  204. jsonEncodeFloat64(buffer, "byteHoursUsed", *d.ByteHoursUsed, ",")
  205. }
  206. if d.ByteUsageMax == nil {
  207. jsonEncode(buffer, "byteUsageMax", nil, ",")
  208. } else {
  209. jsonEncodeFloat64(buffer, "byteUsageMax", *d.ByteUsageMax, ",")
  210. }
  211. jsonEncode(buffer, "breakdown", d.Breakdown, ",")
  212. jsonEncodeFloat64(buffer, "adjustment", d.Adjustment, ",")
  213. jsonEncodeFloat64(buffer, "totalCost", d.TotalCost(), ",")
  214. jsonEncodeString(buffer, "storageClass", d.StorageClass, ",")
  215. jsonEncodeString(buffer, "volumeName", d.VolumeName, ",")
  216. jsonEncodeString(buffer, "claimName", d.ClaimName, ",")
  217. jsonEncodeFloat64(buffer, "local", d.Local, ",")
  218. jsonEncodeString(buffer, "claimNamespace", d.ClaimNamespace, "")
  219. buffer.WriteString("}")
  220. return buffer.Bytes(), nil
  221. }
  222. func (d *Disk) UnmarshalJSON(b []byte) error {
  223. var f interface{}
  224. err := json.Unmarshal(b, &f)
  225. if err != nil {
  226. return err
  227. }
  228. err = d.InterfaceToDisk(f)
  229. if err != nil {
  230. return err
  231. }
  232. return nil
  233. }
  234. // Converts interface{} to Disk, carrying over relevant fields
  235. func (d *Disk) InterfaceToDisk(itf interface{}) error {
  236. fmap := itf.(map[string]interface{})
  237. // parse properties map to AssetProperties
  238. fproperties := fmap["properties"].(map[string]interface{})
  239. properties := toAssetProp(fproperties)
  240. // parse labels map to AssetLabels
  241. labels := make(map[string]string)
  242. for k, v := range fmap["labels"].(map[string]interface{}) {
  243. labels[k] = v.(string)
  244. }
  245. // parse start and end strings to time.Time
  246. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  247. if err != nil {
  248. return err
  249. }
  250. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  251. if err != nil {
  252. return err
  253. }
  254. fbreakdown := fmap["breakdown"].(map[string]interface{})
  255. breakdown := toBreakdown(fbreakdown)
  256. d.Properties = &properties
  257. d.Labels = labels
  258. d.Start = start
  259. d.End = end
  260. if _, found := fmap["window"]; found {
  261. d.Window = toWindow(fmap["window"].(map[string]interface{}))
  262. }
  263. d.Breakdown = &breakdown
  264. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  265. d.Adjustment = adjustment.(float64)
  266. }
  267. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  268. d.Cost = Cost.(float64) - d.Adjustment
  269. }
  270. if ByteHours, err := getTypedVal(fmap["byteHours"]); err == nil {
  271. d.ByteHours = ByteHours.(float64)
  272. }
  273. if ByteHoursUsed, err := getTypedVal(fmap["byteHoursUsed"]); err == nil {
  274. if ByteHoursUsed == nil {
  275. d.ByteHoursUsed = nil
  276. } else {
  277. byteHours := ByteHoursUsed.(float64)
  278. d.ByteHoursUsed = &byteHours
  279. }
  280. }
  281. if ByteUsageMax, err := getTypedVal(fmap["byteUsageMax"]); err == nil {
  282. if ByteUsageMax == nil {
  283. d.ByteUsageMax = nil
  284. } else {
  285. max := ByteUsageMax.(float64)
  286. d.ByteUsageMax = &max
  287. }
  288. }
  289. if StorageClass, err := getTypedVal(fmap["storageClass"]); err == nil {
  290. d.StorageClass = StorageClass.(string)
  291. }
  292. if VolumeName, err := getTypedVal(fmap["volumeName"]); err == nil {
  293. d.VolumeName = VolumeName.(string)
  294. }
  295. if ClaimName, err := getTypedVal(fmap["claimName"]); err == nil {
  296. d.ClaimName = ClaimName.(string)
  297. }
  298. if ClaimNamespace, err := getTypedVal(fmap["claimNamespace"]); err == nil {
  299. d.ClaimNamespace = ClaimNamespace.(string)
  300. }
  301. if local, err := getTypedVal(fmap["local"]); err == nil {
  302. d.Local = local.(float64)
  303. }
  304. return nil
  305. }
  306. // Network marshal and unmarshal
  307. // MarshalJSON implements json.Marshal interface
  308. func (n *Network) MarshalJSON() ([]byte, error) {
  309. buffer := bytes.NewBufferString("{")
  310. jsonEncodeString(buffer, "type", n.Type().String(), ",")
  311. jsonEncode(buffer, "properties", n.Properties, ",")
  312. jsonEncode(buffer, "labels", n.Labels, ",")
  313. jsonEncode(buffer, "window", n.Window, ",")
  314. jsonEncodeString(buffer, "start", n.Start.Format(time.RFC3339), ",")
  315. jsonEncodeString(buffer, "end", n.End.Format(time.RFC3339), ",")
  316. jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
  317. jsonEncodeFloat64(buffer, "adjustment", n.Adjustment, ",")
  318. jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
  319. buffer.WriteString("}")
  320. return buffer.Bytes(), nil
  321. }
  322. func (n *Network) UnmarshalJSON(b []byte) error {
  323. var f interface{}
  324. err := json.Unmarshal(b, &f)
  325. if err != nil {
  326. return err
  327. }
  328. err = n.InterfaceToNetwork(f)
  329. if err != nil {
  330. return err
  331. }
  332. return nil
  333. }
  334. // Converts interface{} to Network, carrying over relevant fields
  335. func (n *Network) InterfaceToNetwork(itf interface{}) error {
  336. fmap := itf.(map[string]interface{})
  337. // parse properties map to AssetProperties
  338. fproperties := fmap["properties"].(map[string]interface{})
  339. properties := toAssetProp(fproperties)
  340. // parse labels map to AssetLabels
  341. labels := make(map[string]string)
  342. for k, v := range fmap["labels"].(map[string]interface{}) {
  343. labels[k] = v.(string)
  344. }
  345. // parse start and end strings to time.Time
  346. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  347. if err != nil {
  348. return err
  349. }
  350. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  351. if err != nil {
  352. return err
  353. }
  354. n.Properties = &properties
  355. n.Labels = labels
  356. n.Start = start
  357. n.End = end
  358. if _, found := fmap["window"]; found {
  359. n.Window = toWindow(fmap["window"].(map[string]interface{}))
  360. }
  361. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  362. n.Adjustment = adjustment.(float64)
  363. }
  364. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  365. n.Cost = Cost.(float64) - n.Adjustment
  366. }
  367. return nil
  368. }
  369. // Node marshal and unmarshal
  370. // MarshalJSON implements json.Marshal interface
  371. func (n *Node) MarshalJSON() ([]byte, error) {
  372. buffer := bytes.NewBufferString("{")
  373. jsonEncodeString(buffer, "type", n.Type().String(), ",")
  374. jsonEncode(buffer, "properties", n.Properties, ",")
  375. jsonEncode(buffer, "labels", n.Labels, ",")
  376. jsonEncode(buffer, "window", n.Window, ",")
  377. jsonEncodeString(buffer, "start", n.Start.Format(time.RFC3339), ",")
  378. jsonEncodeString(buffer, "end", n.End.Format(time.RFC3339), ",")
  379. jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
  380. jsonEncodeString(buffer, "nodeType", n.NodeType, ",")
  381. if poolName := GetNodePoolName(n.Properties.Provider, n.Labels); poolName != "" {
  382. jsonEncodeString(buffer, "pool", poolName, ",")
  383. }
  384. jsonEncodeFloat64(buffer, "cpuCores", n.CPUCores(), ",")
  385. jsonEncodeFloat64(buffer, "ramBytes", n.RAMBytes(), ",")
  386. jsonEncodeFloat64(buffer, "cpuCoreHours", n.CPUCoreHours, ",")
  387. jsonEncodeFloat64(buffer, "ramByteHours", n.RAMByteHours, ",")
  388. jsonEncodeFloat64(buffer, "GPUHours", n.GPUHours, ",")
  389. jsonEncode(buffer, "cpuBreakdown", n.CPUBreakdown, ",")
  390. jsonEncode(buffer, "ramBreakdown", n.RAMBreakdown, ",")
  391. jsonEncodeFloat64(buffer, "preemptible", n.Preemptible, ",")
  392. jsonEncodeFloat64(buffer, "discount", n.Discount, ",")
  393. jsonEncodeFloat64(buffer, "cpuCost", n.CPUCost, ",")
  394. jsonEncodeFloat64(buffer, "gpuCost", n.GPUCost, ",")
  395. jsonEncodeFloat64(buffer, "gpuCount", n.GPUs(), ",")
  396. jsonEncodeFloat64(buffer, "ramCost", n.RAMCost, ",")
  397. jsonEncodeFloat64(buffer, "adjustment", n.Adjustment, ",")
  398. if n.Overhead != nil {
  399. jsonEncode(buffer, "overhead", n.Overhead, ",")
  400. }
  401. jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
  402. buffer.WriteString("}")
  403. return buffer.Bytes(), nil
  404. }
  405. func (n *Node) UnmarshalJSON(b []byte) error {
  406. var f interface{}
  407. err := json.Unmarshal(b, &f)
  408. if err != nil {
  409. return err
  410. }
  411. err = n.InterfaceToNode(f)
  412. if err != nil {
  413. return err
  414. }
  415. return nil
  416. }
  417. // Converts interface{} to Node, carrying over relevant fields
  418. func (n *Node) InterfaceToNode(itf interface{}) error {
  419. fmap := itf.(map[string]interface{})
  420. // parse properties map to AssetProperties
  421. fproperties := fmap["properties"].(map[string]interface{})
  422. properties := toAssetProp(fproperties)
  423. // parse labels map to AssetLabels
  424. labels := make(map[string]string)
  425. if labelsInterface, ok := fmap["labels"].(map[string]interface{}); ok {
  426. for k, v := range labelsInterface {
  427. if strValue, ok := v.(string); ok {
  428. labels[k] = strValue
  429. }
  430. }
  431. }
  432. // parse start and end strings to time.Time
  433. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  434. if err != nil {
  435. return err
  436. }
  437. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  438. if err != nil {
  439. return err
  440. }
  441. fcpuBreakdown := fmap["cpuBreakdown"].(map[string]interface{})
  442. framBreakdown := fmap["ramBreakdown"].(map[string]interface{})
  443. cpuBreakdown := toBreakdown(fcpuBreakdown)
  444. ramBreakdown := toBreakdown(framBreakdown)
  445. n.Properties = &properties
  446. n.Labels = labels
  447. n.Start = start
  448. n.End = end
  449. if _, found := fmap["window"]; found {
  450. n.Window = toWindow(fmap["window"].(map[string]interface{}))
  451. }
  452. n.CPUBreakdown = &cpuBreakdown
  453. n.RAMBreakdown = &ramBreakdown
  454. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  455. n.Adjustment = adjustment.(float64)
  456. }
  457. if NodeType, err := getTypedVal(fmap["nodeType"]); err == nil {
  458. n.NodeType = NodeType.(string)
  459. }
  460. if CPUCoreHours, err := getTypedVal(fmap["cpuCoreHours"]); err == nil {
  461. n.CPUCoreHours = CPUCoreHours.(float64)
  462. }
  463. if RAMByteHours, err := getTypedVal(fmap["ramByteHours"]); err == nil {
  464. n.RAMByteHours = RAMByteHours.(float64)
  465. }
  466. if GPUHours, err := getTypedVal(fmap["GPUHours"]); err == nil {
  467. n.GPUHours = GPUHours.(float64)
  468. }
  469. if CPUCost, err := getTypedVal(fmap["cpuCost"]); err == nil {
  470. n.CPUCost = CPUCost.(float64)
  471. }
  472. if GPUCost, err := getTypedVal(fmap["gpuCost"]); err == nil {
  473. n.GPUCost = GPUCost.(float64)
  474. }
  475. if GPUCount, err := getTypedVal(fmap["gpuCount"]); err == nil {
  476. n.GPUCount = GPUCount.(float64)
  477. }
  478. if RAMCost, err := getTypedVal(fmap["ramCost"]); err == nil {
  479. n.RAMCost = RAMCost.(float64)
  480. }
  481. if Discount, err := getTypedVal(fmap["discount"]); err == nil {
  482. n.Discount = Discount.(float64)
  483. }
  484. if Preemptible, err := getTypedVal(fmap["preemptible"]); err == nil {
  485. n.Preemptible = Preemptible.(float64)
  486. }
  487. return nil
  488. }
  489. // Loadbalancer marshal and unmarshal
  490. // MarshalJSON implements json.Marshal
  491. func (lb *LoadBalancer) MarshalJSON() ([]byte, error) {
  492. buffer := bytes.NewBufferString("{")
  493. jsonEncodeString(buffer, "type", lb.Type().String(), ",")
  494. jsonEncode(buffer, "properties", lb.Properties, ",")
  495. jsonEncode(buffer, "labels", lb.Labels, ",")
  496. jsonEncode(buffer, "window", lb.Window, ",")
  497. jsonEncodeString(buffer, "start", lb.Start.Format(time.RFC3339), ",")
  498. jsonEncodeString(buffer, "end", lb.End.Format(time.RFC3339), ",")
  499. jsonEncodeFloat64(buffer, "minutes", lb.Minutes(), ",")
  500. jsonEncodeFloat64(buffer, "adjustment", lb.Adjustment, ",")
  501. jsonEncodeFloat64(buffer, "totalCost", lb.TotalCost(), ",")
  502. jsonEncode(buffer, "private", lb.Private, ",")
  503. jsonEncodeString(buffer, "ip", lb.Ip, "")
  504. buffer.WriteString("}")
  505. return buffer.Bytes(), nil
  506. }
  507. func (lb *LoadBalancer) UnmarshalJSON(b []byte) error {
  508. var f interface{}
  509. err := json.Unmarshal(b, &f)
  510. if err != nil {
  511. return err
  512. }
  513. err = lb.InterfaceToLoadBalancer(f)
  514. if err != nil {
  515. return err
  516. }
  517. return nil
  518. }
  519. // Converts interface{} to LoadBalancer, carrying over relevant fields
  520. func (lb *LoadBalancer) InterfaceToLoadBalancer(itf interface{}) error {
  521. fmap := itf.(map[string]interface{})
  522. // parse properties map to AssetProperties
  523. fproperties := fmap["properties"].(map[string]interface{})
  524. properties := toAssetProp(fproperties)
  525. // parse labels map to AssetLabels
  526. labels := make(map[string]string)
  527. for k, v := range fmap["labels"].(map[string]interface{}) {
  528. labels[k] = v.(string)
  529. }
  530. // parse start and end strings to time.Time
  531. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  532. if err != nil {
  533. return err
  534. }
  535. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  536. if err != nil {
  537. return err
  538. }
  539. lb.Properties = &properties
  540. lb.Labels = labels
  541. lb.Start = start
  542. lb.End = end
  543. if _, found := fmap["window"]; found {
  544. lb.Window = toWindow(fmap["window"].(map[string]interface{}))
  545. }
  546. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  547. lb.Adjustment = adjustment.(float64)
  548. }
  549. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  550. lb.Cost = Cost.(float64) - lb.Adjustment
  551. }
  552. if private, err := getTypedVal(fmap["private"]); err == nil {
  553. lb.Private = private.(bool)
  554. }
  555. if ip, err := getTypedVal(fmap["ip"]); err == nil {
  556. lb.Ip = ip.(string)
  557. }
  558. return nil
  559. }
  560. // SharedAsset marshal and unmarshal
  561. // MarshalJSON implements json.Marshaler
  562. func (sa *SharedAsset) MarshalJSON() ([]byte, error) {
  563. buffer := bytes.NewBufferString("{")
  564. jsonEncodeString(buffer, "type", sa.Type().String(), ",")
  565. jsonEncode(buffer, "properties", sa.Properties, ",")
  566. jsonEncode(buffer, "labels", sa.Labels, ",")
  567. jsonEncode(buffer, "window", sa.Window, ",")
  568. jsonEncodeString(buffer, "start", sa.GetStart().Format(time.RFC3339), ",")
  569. jsonEncodeString(buffer, "end", sa.GetEnd().Format(time.RFC3339), ",")
  570. jsonEncodeFloat64(buffer, "minutes", sa.Minutes(), ",")
  571. jsonEncodeFloat64(buffer, "totalCost", sa.TotalCost(), "")
  572. buffer.WriteString("}")
  573. return buffer.Bytes(), nil
  574. }
  575. func (sa *SharedAsset) UnmarshalJSON(b []byte) error {
  576. var f interface{}
  577. err := json.Unmarshal(b, &f)
  578. if err != nil {
  579. return err
  580. }
  581. err = sa.InterfaceToSharedAsset(f)
  582. if err != nil {
  583. return err
  584. }
  585. return nil
  586. }
  587. // Converts interface{} to SharedAsset, carrying over relevant fields
  588. func (sa *SharedAsset) InterfaceToSharedAsset(itf interface{}) error {
  589. fmap := itf.(map[string]interface{})
  590. // parse properties map to AssetProperties
  591. fproperties := fmap["properties"].(map[string]interface{})
  592. properties := toAssetProp(fproperties)
  593. // parse labels map to AssetLabels
  594. labels := make(map[string]string)
  595. for k, v := range fmap["labels"].(map[string]interface{}) {
  596. labels[k] = v.(string)
  597. }
  598. sa.Properties = &properties
  599. sa.Labels = labels
  600. if _, found := fmap["window"]; found {
  601. sa.Window = toWindow(fmap["window"].(map[string]interface{}))
  602. }
  603. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  604. sa.Cost = Cost.(float64)
  605. }
  606. return nil
  607. }
  608. // AssetSet marshal
  609. // MarshalJSON JSON-encodes the AssetSet
  610. func (as *AssetSet) MarshalJSON() ([]byte, error) {
  611. if as == nil {
  612. return json.Marshal(map[string]Asset{})
  613. }
  614. return json.Marshal(as.Assets)
  615. }
  616. // AssetSetResponse for unmarshaling of AssetSet.assets into AssetSet
  617. // Unmarshals a marshaled AssetSet json into AssetSetResponse
  618. func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
  619. var assetMap map[string]*json.RawMessage
  620. // Partial unmarshal to map of json RawMessage
  621. err := json.Unmarshal(b, &assetMap)
  622. if err != nil {
  623. return err
  624. }
  625. err = asr.RawMessageToAssetSetResponse(assetMap)
  626. if err != nil {
  627. return err
  628. }
  629. return nil
  630. }
  631. func (asr *AssetSetResponse) RawMessageToAssetSetResponse(assetMap map[string]*json.RawMessage) error {
  632. newAssetMap := make(map[string]Asset)
  633. // For each item in asset map, unmarshal to appropriate type
  634. for key, rawMessage := range assetMap {
  635. var f interface{}
  636. err := json.Unmarshal(*rawMessage, &f)
  637. if err != nil {
  638. return err
  639. }
  640. fmap := f.(map[string]interface{})
  641. switch t := fmap["type"]; t {
  642. case "Cloud":
  643. var ca Cloud
  644. err := ca.InterfaceToCloud(f)
  645. if err != nil {
  646. return err
  647. }
  648. newAssetMap[key] = &ca
  649. case "ClusterManagement":
  650. var cm ClusterManagement
  651. err := cm.InterfaceToClusterManagement(f)
  652. if err != nil {
  653. return err
  654. }
  655. newAssetMap[key] = &cm
  656. case "Disk":
  657. var d Disk
  658. err := d.InterfaceToDisk(f)
  659. if err != nil {
  660. return err
  661. }
  662. newAssetMap[key] = &d
  663. case "Network":
  664. var nw Network
  665. err := nw.InterfaceToNetwork(f)
  666. if err != nil {
  667. return err
  668. }
  669. newAssetMap[key] = &nw
  670. case "Node":
  671. var n Node
  672. err := n.InterfaceToNode(f)
  673. if err != nil {
  674. return err
  675. }
  676. newAssetMap[key] = &n
  677. case "LoadBalancer":
  678. var lb LoadBalancer
  679. err := lb.InterfaceToLoadBalancer(f)
  680. if err != nil {
  681. return err
  682. }
  683. newAssetMap[key] = &lb
  684. case "Shared":
  685. var sa SharedAsset
  686. err := sa.InterfaceToSharedAsset(f)
  687. if err != nil {
  688. return err
  689. }
  690. newAssetMap[key] = &sa
  691. default:
  692. var a Any
  693. err := a.InterfaceToAny(f)
  694. if err != nil {
  695. return err
  696. }
  697. newAssetMap[key] = &a
  698. }
  699. }
  700. asr.Assets = newAssetMap
  701. return nil
  702. }
  703. func (asrr *AssetSetRangeResponse) UnmarshalJSON(b []byte) error {
  704. var assetMapList []map[string]*json.RawMessage
  705. // Partial unmarshal to map of json RawMessage
  706. err := json.Unmarshal(b, &assetMapList)
  707. if err != nil {
  708. return err
  709. }
  710. var assetSetList []*AssetSetResponse
  711. for _, rawm := range assetMapList {
  712. var asresp AssetSetResponse
  713. err = asresp.RawMessageToAssetSetResponse(rawm)
  714. if err != nil {
  715. return err
  716. }
  717. assetSetList = append(assetSetList, &asresp)
  718. }
  719. asrr.Assets = assetSetList
  720. return nil
  721. }
  722. // Extra decoding util functions, for clarity
  723. // Creates an AssetProperties directly from map[string]interface{}
  724. func toAssetProp(fproperties map[string]interface{}) AssetProperties {
  725. var properties AssetProperties
  726. if category, v := fproperties["category"].(string); v {
  727. properties.Category = category
  728. }
  729. if provider, v := fproperties["provider"].(string); v {
  730. properties.Provider = provider
  731. }
  732. if account, v := fproperties["account"].(string); v {
  733. properties.Account = account
  734. }
  735. if project, v := fproperties["project"].(string); v {
  736. properties.Project = project
  737. }
  738. if service, v := fproperties["service"].(string); v {
  739. properties.Service = service
  740. }
  741. if cluster, v := fproperties["cluster"].(string); v {
  742. properties.Cluster = cluster
  743. }
  744. if name, v := fproperties["name"].(string); v {
  745. properties.Name = name
  746. }
  747. if providerID, v := fproperties["providerID"].(string); v {
  748. properties.ProviderID = providerID
  749. }
  750. return properties
  751. }
  752. func toWindow(fproperties map[string]interface{}) Window {
  753. var start, end time.Time
  754. var err error
  755. if startStr, v := fproperties["start"].(string); v {
  756. start, err = time.Parse(time.RFC3339, startStr)
  757. if err != nil {
  758. log.Errorf("error parsing window start from string %s, setting as 0 time", startStr)
  759. start = time.Time{}
  760. }
  761. }
  762. if endStr, v := fproperties["end"].(string); v {
  763. end, err = time.Parse(time.RFC3339, endStr)
  764. if err != nil {
  765. log.Errorf("error parsing window end from string %s, setting as 0 time", endStr)
  766. end = time.Time{}
  767. }
  768. }
  769. return NewClosedWindow(start, end)
  770. }
  771. // Creates an Breakdown directly from map[string]interface{}
  772. func toBreakdown(fproperties map[string]interface{}) Breakdown {
  773. var breakdown Breakdown
  774. if idle, v := fproperties["idle"].(float64); v {
  775. breakdown.Idle = idle
  776. }
  777. if other, v := fproperties["other"].(float64); v {
  778. breakdown.Other = other
  779. }
  780. if system, v := fproperties["system"].(float64); v {
  781. breakdown.System = system
  782. }
  783. if user, v := fproperties["user"].(float64); v {
  784. breakdown.User = user
  785. }
  786. return breakdown
  787. }
  788. // Not strictly nessesary, but cleans up the code and is a secondary check
  789. // for correct types
  790. func getTypedVal(itf interface{}) (interface{}, error) {
  791. switch itf := itf.(type) {
  792. case float64:
  793. return float64(itf), nil
  794. case string:
  795. return string(itf), nil
  796. default:
  797. unktype := reflect.ValueOf(itf)
  798. return nil, fmt.Errorf("Type %v is an invalid type", unktype)
  799. }
  800. }