asset_json.go 25 KB

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