asset_unmarshal.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. package kubecost
  2. import (
  3. "bytes"
  4. "fmt"
  5. "reflect"
  6. "time"
  7. "github.com/opencost/opencost/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.Start().Format(time.RFC3339), ",")
  150. jsonEncodeString(buffer, "end", cm.End().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. jsonEncode(buffer, "breakdown", d.Breakdown, ",")
  213. jsonEncodeFloat64(buffer, "adjustment", d.Adjustment(), ",")
  214. jsonEncodeFloat64(buffer, "totalCost", d.TotalCost(), "")
  215. buffer.WriteString("}")
  216. return buffer.Bytes(), nil
  217. }
  218. func (d *Disk) UnmarshalJSON(b []byte) error {
  219. var f interface{}
  220. err := json.Unmarshal(b, &f)
  221. if err != nil {
  222. return err
  223. }
  224. err = d.InterfaceToDisk(f)
  225. if err != nil {
  226. return err
  227. }
  228. return nil
  229. }
  230. // Converts interface{} to Disk, carrying over relevant fields
  231. func (d *Disk) InterfaceToDisk(itf interface{}) error {
  232. fmap := itf.(map[string]interface{})
  233. // parse properties map to AssetProperties
  234. fproperties := fmap["properties"].(map[string]interface{})
  235. properties := toAssetProp(fproperties)
  236. // parse labels map to AssetLabels
  237. labels := make(map[string]string)
  238. for k, v := range fmap["labels"].(map[string]interface{}) {
  239. labels[k] = v.(string)
  240. }
  241. // parse start and end strings to time.Time
  242. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  243. if err != nil {
  244. return err
  245. }
  246. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  247. if err != nil {
  248. return err
  249. }
  250. fbreakdown := fmap["breakdown"].(map[string]interface{})
  251. breakdown := toBreakdown(fbreakdown)
  252. d.properties = &properties
  253. d.labels = labels
  254. d.start = start
  255. d.end = end
  256. d.window = Window{
  257. start: &start,
  258. end: &end,
  259. }
  260. d.Breakdown = &breakdown
  261. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  262. d.adjustment = adjustment.(float64)
  263. }
  264. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  265. d.Cost = Cost.(float64) - d.adjustment
  266. }
  267. if ByteHours, err := getTypedVal(fmap["byteHours"]); err == nil {
  268. d.ByteHours = ByteHours.(float64)
  269. }
  270. // d.Local is not marhsaled, and cannot be calculated from marshaled values.
  271. // Currently, it is just ignored and not set in the resulting unmarshal to Disk
  272. // be aware that this means a resulting Disk from an unmarshal is therefore NOT
  273. // equal to the originally marshaled Disk.
  274. return nil
  275. }
  276. // Network marshal and unmarshal
  277. // MarshalJSON implements json.Marshal interface
  278. func (n *Network) MarshalJSON() ([]byte, error) {
  279. buffer := bytes.NewBufferString("{")
  280. jsonEncodeString(buffer, "type", n.Type().String(), ",")
  281. jsonEncode(buffer, "properties", n.Properties(), ",")
  282. jsonEncode(buffer, "labels", n.Labels(), ",")
  283. jsonEncode(buffer, "window", n.Window(), ",")
  284. jsonEncodeString(buffer, "start", n.Start().Format(time.RFC3339), ",")
  285. jsonEncodeString(buffer, "end", n.End().Format(time.RFC3339), ",")
  286. jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
  287. jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
  288. jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
  289. buffer.WriteString("}")
  290. return buffer.Bytes(), nil
  291. }
  292. func (n *Network) UnmarshalJSON(b []byte) error {
  293. var f interface{}
  294. err := json.Unmarshal(b, &f)
  295. if err != nil {
  296. return err
  297. }
  298. err = n.InterfaceToNetwork(f)
  299. if err != nil {
  300. return err
  301. }
  302. return nil
  303. }
  304. // Converts interface{} to Network, carrying over relevant fields
  305. func (n *Network) InterfaceToNetwork(itf interface{}) error {
  306. fmap := itf.(map[string]interface{})
  307. // parse properties map to AssetProperties
  308. fproperties := fmap["properties"].(map[string]interface{})
  309. properties := toAssetProp(fproperties)
  310. // parse labels map to AssetLabels
  311. labels := make(map[string]string)
  312. for k, v := range fmap["labels"].(map[string]interface{}) {
  313. labels[k] = v.(string)
  314. }
  315. // parse start and end strings to time.Time
  316. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  317. if err != nil {
  318. return err
  319. }
  320. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  321. if err != nil {
  322. return err
  323. }
  324. n.properties = &properties
  325. n.labels = labels
  326. n.start = start
  327. n.end = end
  328. n.window = Window{
  329. start: &start,
  330. end: &end,
  331. }
  332. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  333. n.adjustment = adjustment.(float64)
  334. }
  335. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  336. n.Cost = Cost.(float64) - n.adjustment
  337. }
  338. return nil
  339. }
  340. // Node marshal and unmarshal
  341. // MarshalJSON implements json.Marshal interface
  342. func (n *Node) MarshalJSON() ([]byte, error) {
  343. buffer := bytes.NewBufferString("{")
  344. jsonEncodeString(buffer, "type", n.Type().String(), ",")
  345. jsonEncode(buffer, "properties", n.Properties(), ",")
  346. jsonEncode(buffer, "labels", n.Labels(), ",")
  347. jsonEncode(buffer, "window", n.Window(), ",")
  348. jsonEncodeString(buffer, "start", n.Start().Format(time.RFC3339), ",")
  349. jsonEncodeString(buffer, "end", n.End().Format(time.RFC3339), ",")
  350. jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
  351. jsonEncodeString(buffer, "nodeType", n.NodeType, ",")
  352. jsonEncodeFloat64(buffer, "cpuCores", n.CPUCores(), ",")
  353. jsonEncodeFloat64(buffer, "ramBytes", n.RAMBytes(), ",")
  354. jsonEncodeFloat64(buffer, "cpuCoreHours", n.CPUCoreHours, ",")
  355. jsonEncodeFloat64(buffer, "ramByteHours", n.RAMByteHours, ",")
  356. jsonEncodeFloat64(buffer, "GPUHours", n.GPUHours, ",")
  357. jsonEncode(buffer, "cpuBreakdown", n.CPUBreakdown, ",")
  358. jsonEncode(buffer, "ramBreakdown", n.RAMBreakdown, ",")
  359. jsonEncodeFloat64(buffer, "preemptible", n.Preemptible, ",")
  360. jsonEncodeFloat64(buffer, "discount", n.Discount, ",")
  361. jsonEncodeFloat64(buffer, "cpuCost", n.CPUCost, ",")
  362. jsonEncodeFloat64(buffer, "gpuCost", n.GPUCost, ",")
  363. jsonEncodeFloat64(buffer, "gpuCount", n.GPUs(), ",")
  364. jsonEncodeFloat64(buffer, "ramCost", n.RAMCost, ",")
  365. jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
  366. jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
  367. buffer.WriteString("}")
  368. return buffer.Bytes(), nil
  369. }
  370. func (n *Node) UnmarshalJSON(b []byte) error {
  371. var f interface{}
  372. err := json.Unmarshal(b, &f)
  373. if err != nil {
  374. return err
  375. }
  376. err = n.InterfaceToNode(f)
  377. if err != nil {
  378. return err
  379. }
  380. return nil
  381. }
  382. // Converts interface{} to Node, carrying over relevant fields
  383. func (n *Node) InterfaceToNode(itf interface{}) error {
  384. fmap := itf.(map[string]interface{})
  385. // parse properties map to AssetProperties
  386. fproperties := fmap["properties"].(map[string]interface{})
  387. properties := toAssetProp(fproperties)
  388. // parse labels map to AssetLabels
  389. labels := make(map[string]string)
  390. for k, v := range fmap["labels"].(map[string]interface{}) {
  391. labels[k] = v.(string)
  392. }
  393. // parse start and end strings to time.Time
  394. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  395. if err != nil {
  396. return err
  397. }
  398. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  399. if err != nil {
  400. return err
  401. }
  402. fcpuBreakdown := fmap["cpuBreakdown"].(map[string]interface{})
  403. framBreakdown := fmap["ramBreakdown"].(map[string]interface{})
  404. cpuBreakdown := toBreakdown(fcpuBreakdown)
  405. ramBreakdown := toBreakdown(framBreakdown)
  406. n.properties = &properties
  407. n.labels = labels
  408. n.start = start
  409. n.end = end
  410. n.window = Window{
  411. start: &start,
  412. end: &end,
  413. }
  414. n.CPUBreakdown = &cpuBreakdown
  415. n.RAMBreakdown = &ramBreakdown
  416. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  417. n.adjustment = adjustment.(float64)
  418. }
  419. if NodeType, err := getTypedVal(fmap["nodeType"]); err == nil {
  420. n.NodeType = NodeType.(string)
  421. }
  422. if CPUCoreHours, err := getTypedVal(fmap["cpuCoreHours"]); err == nil {
  423. n.CPUCoreHours = CPUCoreHours.(float64)
  424. }
  425. if RAMByteHours, err := getTypedVal(fmap["ramByteHours"]); err == nil {
  426. n.RAMByteHours = RAMByteHours.(float64)
  427. }
  428. if GPUHours, err := getTypedVal(fmap["GPUHours"]); err == nil {
  429. n.GPUHours = GPUHours.(float64)
  430. }
  431. if CPUCost, err := getTypedVal(fmap["cpuCost"]); err == nil {
  432. n.CPUCost = CPUCost.(float64)
  433. }
  434. if GPUCost, err := getTypedVal(fmap["gpuCost"]); err == nil {
  435. n.GPUCost = GPUCost.(float64)
  436. }
  437. if GPUCount, err := getTypedVal(fmap["gpuCount"]); err == nil {
  438. n.GPUCount = GPUCount.(float64)
  439. }
  440. if RAMCost, err := getTypedVal(fmap["ramCost"]); err == nil {
  441. n.RAMCost = RAMCost.(float64)
  442. }
  443. if Discount, err := getTypedVal(fmap["discount"]); err == nil {
  444. n.Discount = Discount.(float64)
  445. }
  446. if Preemptible, err := getTypedVal(fmap["preemptible"]); err == nil {
  447. n.Preemptible = Preemptible.(float64)
  448. }
  449. return nil
  450. }
  451. // Loadbalancer marshal and unmarshal
  452. // MarshalJSON implements json.Marshal
  453. func (lb *LoadBalancer) MarshalJSON() ([]byte, error) {
  454. buffer := bytes.NewBufferString("{")
  455. jsonEncodeString(buffer, "type", lb.Type().String(), ",")
  456. jsonEncode(buffer, "properties", lb.Properties(), ",")
  457. jsonEncode(buffer, "labels", lb.Labels(), ",")
  458. jsonEncode(buffer, "window", lb.Window(), ",")
  459. jsonEncodeString(buffer, "start", lb.Start().Format(time.RFC3339), ",")
  460. jsonEncodeString(buffer, "end", lb.End().Format(time.RFC3339), ",")
  461. jsonEncodeFloat64(buffer, "minutes", lb.Minutes(), ",")
  462. jsonEncodeFloat64(buffer, "adjustment", lb.Adjustment(), ",")
  463. jsonEncodeFloat64(buffer, "totalCost", lb.TotalCost(), "")
  464. buffer.WriteString("}")
  465. return buffer.Bytes(), nil
  466. }
  467. func (lb *LoadBalancer) UnmarshalJSON(b []byte) error {
  468. var f interface{}
  469. err := json.Unmarshal(b, &f)
  470. if err != nil {
  471. return err
  472. }
  473. err = lb.InterfaceToLoadBalancer(f)
  474. if err != nil {
  475. return err
  476. }
  477. return nil
  478. }
  479. // Converts interface{} to LoadBalancer, carrying over relevant fields
  480. func (lb *LoadBalancer) InterfaceToLoadBalancer(itf interface{}) error {
  481. fmap := itf.(map[string]interface{})
  482. // parse properties map to AssetProperties
  483. fproperties := fmap["properties"].(map[string]interface{})
  484. properties := toAssetProp(fproperties)
  485. // parse labels map to AssetLabels
  486. labels := make(map[string]string)
  487. for k, v := range fmap["labels"].(map[string]interface{}) {
  488. labels[k] = v.(string)
  489. }
  490. // parse start and end strings to time.Time
  491. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  492. if err != nil {
  493. return err
  494. }
  495. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  496. if err != nil {
  497. return err
  498. }
  499. lb.properties = &properties
  500. lb.labels = labels
  501. lb.start = start
  502. lb.end = end
  503. lb.window = Window{
  504. start: &start,
  505. end: &end,
  506. }
  507. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  508. lb.adjustment = adjustment.(float64)
  509. }
  510. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  511. lb.Cost = Cost.(float64) - lb.adjustment
  512. }
  513. return nil
  514. }
  515. // SharedAsset marshal and unmarshal
  516. // MarshalJSON implements json.Marshaler
  517. func (sa *SharedAsset) MarshalJSON() ([]byte, error) {
  518. buffer := bytes.NewBufferString("{")
  519. jsonEncodeString(buffer, "type", sa.Type().String(), ",")
  520. jsonEncode(buffer, "properties", sa.Properties(), ",")
  521. jsonEncode(buffer, "labels", sa.Labels(), ",")
  522. jsonEncode(buffer, "properties", sa.Properties(), ",")
  523. jsonEncode(buffer, "labels", sa.Labels(), ",")
  524. jsonEncode(buffer, "window", sa.Window(), ",")
  525. jsonEncodeString(buffer, "start", sa.Start().Format(time.RFC3339), ",")
  526. jsonEncodeString(buffer, "end", sa.End().Format(time.RFC3339), ",")
  527. jsonEncodeFloat64(buffer, "minutes", sa.Minutes(), ",")
  528. jsonEncodeFloat64(buffer, "totalCost", sa.TotalCost(), "")
  529. buffer.WriteString("}")
  530. return buffer.Bytes(), nil
  531. }
  532. func (sa *SharedAsset) UnmarshalJSON(b []byte) error {
  533. var f interface{}
  534. err := json.Unmarshal(b, &f)
  535. if err != nil {
  536. return err
  537. }
  538. err = sa.InterfaceToSharedAsset(f)
  539. if err != nil {
  540. return err
  541. }
  542. return nil
  543. }
  544. // Converts interface{} to SharedAsset, carrying over relevant fields
  545. func (sa *SharedAsset) InterfaceToSharedAsset(itf interface{}) error {
  546. fmap := itf.(map[string]interface{})
  547. // parse properties map to AssetProperties
  548. fproperties := fmap["properties"].(map[string]interface{})
  549. properties := toAssetProp(fproperties)
  550. // parse labels map to AssetLabels
  551. labels := make(map[string]string)
  552. for k, v := range fmap["labels"].(map[string]interface{}) {
  553. labels[k] = v.(string)
  554. }
  555. // parse start and end strings to time.Time
  556. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  557. if err != nil {
  558. return err
  559. }
  560. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  561. if err != nil {
  562. return err
  563. }
  564. sa.properties = &properties
  565. sa.labels = labels
  566. sa.window = Window{
  567. start: &start,
  568. end: &end,
  569. }
  570. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  571. sa.Cost = Cost.(float64)
  572. }
  573. return nil
  574. }
  575. // AssetSet marshal
  576. // MarshalJSON JSON-encodes the AssetSet
  577. func (as *AssetSet) MarshalJSON() ([]byte, error) {
  578. if as == nil {
  579. return json.Marshal(map[string]Asset{})
  580. }
  581. as.RLock()
  582. defer as.RUnlock()
  583. return json.Marshal(as.assets)
  584. }
  585. // AssetSetResponse for unmarshaling of AssetSet.assets into AssetSet
  586. // Unmarshals a marshaled AssetSet json into AssetSetResponse
  587. func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
  588. var assetMap map[string]*json.RawMessage
  589. // Partial unmarshal to map of json RawMessage
  590. err := json.Unmarshal(b, &assetMap)
  591. if err != nil {
  592. return err
  593. }
  594. err = asr.RawMessageToAssetSetResponse(assetMap)
  595. if err != nil {
  596. return err
  597. }
  598. return nil
  599. }
  600. func (asr *AssetSetResponse) RawMessageToAssetSetResponse(assetMap map[string]*json.RawMessage) error {
  601. newAssetMap := make(map[string]Asset)
  602. // For each item in asset map, unmarshal to appropriate type
  603. for key, rawMessage := range assetMap {
  604. var f interface{}
  605. err := json.Unmarshal(*rawMessage, &f)
  606. if err != nil {
  607. return err
  608. }
  609. fmap := f.(map[string]interface{})
  610. switch t := fmap["type"]; t {
  611. case "Cloud":
  612. var ca Cloud
  613. err := ca.InterfaceToCloud(f)
  614. if err != nil {
  615. return err
  616. }
  617. newAssetMap[key] = &ca
  618. case "ClusterManagement":
  619. var cm ClusterManagement
  620. err := cm.InterfaceToClusterManagement(f)
  621. if err != nil {
  622. return err
  623. }
  624. newAssetMap[key] = &cm
  625. case "Disk":
  626. var d Disk
  627. err := d.InterfaceToDisk(f)
  628. if err != nil {
  629. return err
  630. }
  631. newAssetMap[key] = &d
  632. case "Network":
  633. var nw Network
  634. err := nw.InterfaceToNetwork(f)
  635. if err != nil {
  636. return err
  637. }
  638. newAssetMap[key] = &nw
  639. case "Node":
  640. var n Node
  641. err := n.InterfaceToNode(f)
  642. if err != nil {
  643. return err
  644. }
  645. newAssetMap[key] = &n
  646. case "LoadBalancer":
  647. var lb LoadBalancer
  648. err := lb.InterfaceToLoadBalancer(f)
  649. if err != nil {
  650. return err
  651. }
  652. newAssetMap[key] = &lb
  653. case "Shared":
  654. var sa SharedAsset
  655. err := sa.InterfaceToSharedAsset(f)
  656. if err != nil {
  657. return err
  658. }
  659. newAssetMap[key] = &sa
  660. default:
  661. var a Any
  662. err := a.InterfaceToAny(f)
  663. if err != nil {
  664. return err
  665. }
  666. newAssetMap[key] = &a
  667. }
  668. }
  669. asr.Assets = newAssetMap
  670. return nil
  671. }
  672. func (asrr *AssetSetRangeResponse) UnmarshalJSON(b []byte) error {
  673. var assetMapList []map[string]*json.RawMessage
  674. // Partial unmarshal to map of json RawMessage
  675. err := json.Unmarshal(b, &assetMapList)
  676. if err != nil {
  677. return err
  678. }
  679. var assetSetList []*AssetSetResponse
  680. for _, rawm := range assetMapList {
  681. var asresp AssetSetResponse
  682. err = asresp.RawMessageToAssetSetResponse(rawm)
  683. if err != nil {
  684. return err
  685. }
  686. assetSetList = append(assetSetList, &asresp)
  687. }
  688. asrr.Assets = assetSetList
  689. return nil
  690. }
  691. // Extra decoding util functions, for clarity
  692. // Creates an AssetProperties directly from map[string]interface{}
  693. func toAssetProp(fproperties map[string]interface{}) AssetProperties {
  694. var properties AssetProperties
  695. if category, v := fproperties["category"].(string); v {
  696. properties.Category = category
  697. }
  698. if provider, v := fproperties["provider"].(string); v {
  699. properties.Provider = provider
  700. }
  701. if account, v := fproperties["account"].(string); v {
  702. properties.Account = account
  703. }
  704. if project, v := fproperties["project"].(string); v {
  705. properties.Project = project
  706. }
  707. if service, v := fproperties["service"].(string); v {
  708. properties.Service = service
  709. }
  710. if cluster, v := fproperties["cluster"].(string); v {
  711. properties.Cluster = cluster
  712. }
  713. if name, v := fproperties["name"].(string); v {
  714. properties.Name = name
  715. }
  716. if providerID, v := fproperties["providerID"].(string); v {
  717. properties.ProviderID = providerID
  718. }
  719. return properties
  720. }
  721. // Creates an Breakdown directly from map[string]interface{}
  722. func toBreakdown(fproperties map[string]interface{}) Breakdown {
  723. var breakdown Breakdown
  724. if idle, v := fproperties["idle"].(float64); v {
  725. breakdown.Idle = idle
  726. }
  727. if other, v := fproperties["other"].(float64); v {
  728. breakdown.Other = other
  729. }
  730. if system, v := fproperties["system"].(float64); v {
  731. breakdown.System = system
  732. }
  733. if user, v := fproperties["user"].(float64); v {
  734. breakdown.User = user
  735. }
  736. return breakdown
  737. }
  738. // Not strictly nessesary, but cleans up the code and is a secondary check
  739. // for correct types
  740. func getTypedVal(itf interface{}) (interface{}, error) {
  741. switch itf := itf.(type) {
  742. case float64:
  743. return float64(itf), nil
  744. case string:
  745. return string(itf), nil
  746. default:
  747. unktype := reflect.ValueOf(itf)
  748. return nil, fmt.Errorf("Type %v is an invalid type", unktype)
  749. }
  750. }