asset_unmarshal.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. package kubecost
  2. import (
  3. "bytes"
  4. "fmt"
  5. "reflect"
  6. "time"
  7. // gojson is default golang json, required for RawMessage decoding
  8. gojson "encoding/json"
  9. "github.com/kubecost/cost-model/pkg/util/json"
  10. )
  11. // Encoding and decoding logic for Asset types
  12. // Any marshal and unmarshal
  13. // MarshalJSON implements json.Marshaler
  14. func (a *Any) MarshalJSON() ([]byte, error) {
  15. buffer := bytes.NewBufferString("{")
  16. jsonEncode(buffer, "properties", a.Properties(), ",")
  17. jsonEncode(buffer, "labels", a.Labels(), ",")
  18. jsonEncode(buffer, "window", a.Window(), ",")
  19. jsonEncodeString(buffer, "start", a.Start().Format(time.RFC3339), ",")
  20. jsonEncodeString(buffer, "end", a.End().Format(time.RFC3339), ",")
  21. jsonEncodeFloat64(buffer, "minutes", a.Minutes(), ",")
  22. jsonEncodeFloat64(buffer, "adjustment", a.Adjustment(), ",")
  23. jsonEncodeFloat64(buffer, "totalCost", a.TotalCost(), "")
  24. buffer.WriteString("}")
  25. return buffer.Bytes(), nil
  26. }
  27. func (a *Any) UnmarshalJSON(b []byte) error {
  28. var f interface{}
  29. err := json.Unmarshal(b, &f)
  30. if err != nil {
  31. return err
  32. }
  33. err = a.InterfaceToAny(f)
  34. if err != nil {
  35. return err
  36. }
  37. return nil
  38. }
  39. // Converts interface{} to Any, carrying over relevant fields
  40. func (a *Any) InterfaceToAny(itf interface{}) error {
  41. fmap := itf.(map[string]interface{})
  42. // parse properties map to AssetProperties
  43. fproperties := fmap["properties"].(map[string]interface{})
  44. properties := toAssetProp(fproperties)
  45. // parse labels map to AssetLabels
  46. labels := make(map[string]string)
  47. for k, v := range fmap["labels"].(map[string]interface{}) {
  48. labels[k] = v.(string)
  49. }
  50. // parse start and end strings to time.Time
  51. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  52. if err != nil {
  53. return err
  54. }
  55. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  56. if err != nil {
  57. return err
  58. }
  59. a.properties = &properties
  60. a.labels = labels
  61. a.start = start
  62. a.end = end
  63. a.window = Window{
  64. start: &start,
  65. end: &end,
  66. }
  67. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  68. a.adjustment = adjustment.(float64)
  69. }
  70. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  71. a.Cost = Cost.(float64) - a.adjustment
  72. }
  73. return nil
  74. }
  75. // Cloud marshal and unmarshal
  76. // MarshalJSON implements json.Marshaler
  77. func (ca *Cloud) MarshalJSON() ([]byte, error) {
  78. buffer := bytes.NewBufferString("{")
  79. jsonEncodeString(buffer, "type", ca.Type().String(), ",")
  80. jsonEncode(buffer, "properties", ca.Properties(), ",")
  81. jsonEncode(buffer, "labels", ca.Labels(), ",")
  82. jsonEncode(buffer, "window", ca.Window(), ",")
  83. jsonEncodeString(buffer, "start", ca.Start().Format(time.RFC3339), ",")
  84. jsonEncodeString(buffer, "end", ca.End().Format(time.RFC3339), ",")
  85. jsonEncodeFloat64(buffer, "minutes", ca.Minutes(), ",")
  86. jsonEncodeFloat64(buffer, "adjustment", ca.Adjustment(), ",")
  87. jsonEncodeFloat64(buffer, "credit", ca.Credit, ",")
  88. jsonEncodeFloat64(buffer, "totalCost", ca.TotalCost(), "")
  89. buffer.WriteString("}")
  90. return buffer.Bytes(), nil
  91. }
  92. func (ca *Cloud) UnmarshalJSON(b []byte) error {
  93. var f interface{}
  94. err := json.Unmarshal(b, &f)
  95. if err != nil {
  96. return err
  97. }
  98. err = ca.InterfaceToCloud(f)
  99. if err != nil {
  100. return err
  101. }
  102. return nil
  103. }
  104. // Converts interface{} to Cloud, carrying over relevant fields
  105. func (ca *Cloud) InterfaceToCloud(itf interface{}) error {
  106. fmap := itf.(map[string]interface{})
  107. // parse properties map to AssetProperties
  108. fproperties := fmap["properties"].(map[string]interface{})
  109. properties := toAssetProp(fproperties)
  110. // parse labels map to AssetLabels
  111. labels := make(map[string]string)
  112. for k, v := range fmap["labels"].(map[string]interface{}) {
  113. labels[k] = v.(string)
  114. }
  115. // parse start and end strings to time.Time
  116. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  117. if err != nil {
  118. return err
  119. }
  120. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  121. if err != nil {
  122. return err
  123. }
  124. ca.properties = &properties
  125. ca.labels = labels
  126. ca.start = start
  127. ca.end = end
  128. ca.window = Window{
  129. start: &start,
  130. end: &end,
  131. }
  132. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  133. ca.adjustment = adjustment.(float64)
  134. }
  135. if Credit, err := getTypedVal(fmap["credit"]); err == nil {
  136. ca.Credit = Credit.(float64)
  137. }
  138. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  139. ca.Cost = Cost.(float64) - ca.adjustment - ca.Credit
  140. }
  141. return nil
  142. }
  143. // ClusterManagement marshal and unmarshal
  144. // MarshalJSON implements json.Marshler
  145. func (cm *ClusterManagement) MarshalJSON() ([]byte, error) {
  146. buffer := bytes.NewBufferString("{")
  147. jsonEncodeString(buffer, "type", cm.Type().String(), ",")
  148. jsonEncode(buffer, "properties", cm.Properties(), ",")
  149. jsonEncode(buffer, "labels", cm.Labels(), ",")
  150. jsonEncode(buffer, "window", cm.Window(), ",")
  151. jsonEncodeString(buffer, "start", cm.Start().Format(time.RFC3339), ",")
  152. jsonEncodeString(buffer, "end", cm.End().Format(time.RFC3339), ",")
  153. jsonEncodeFloat64(buffer, "minutes", cm.Minutes(), ",")
  154. jsonEncodeFloat64(buffer, "totalCost", cm.TotalCost(), "")
  155. buffer.WriteString("}")
  156. return buffer.Bytes(), nil
  157. }
  158. func (cm *ClusterManagement) UnmarshalJSON(b []byte) error {
  159. var f interface{}
  160. err := json.Unmarshal(b, &f)
  161. if err != nil {
  162. return err
  163. }
  164. err = cm.InterfaceToClusterManagement(f)
  165. if err != nil {
  166. return err
  167. }
  168. return nil
  169. }
  170. // Converts interface{} to ClusterManagement, carrying over relevant fields
  171. func (cm *ClusterManagement) InterfaceToClusterManagement(itf interface{}) error {
  172. fmap := itf.(map[string]interface{})
  173. // parse properties map to AssetProperties
  174. fproperties := fmap["properties"].(map[string]interface{})
  175. properties := toAssetProp(fproperties)
  176. // parse labels map to AssetLabels
  177. labels := make(map[string]string)
  178. for k, v := range fmap["labels"].(map[string]interface{}) {
  179. labels[k] = v.(string)
  180. }
  181. // parse start and end strings to time.Time
  182. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  183. if err != nil {
  184. return err
  185. }
  186. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  187. if err != nil {
  188. return err
  189. }
  190. cm.properties = &properties
  191. cm.labels = labels
  192. cm.window = Window{
  193. start: &start,
  194. end: &end,
  195. }
  196. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  197. cm.Cost = Cost.(float64)
  198. }
  199. return nil
  200. }
  201. // Disk marshal and unmarshal
  202. // MarshalJSON implements the json.Marshaler interface
  203. func (d *Disk) MarshalJSON() ([]byte, error) {
  204. buffer := bytes.NewBufferString("{")
  205. jsonEncodeString(buffer, "type", d.Type().String(), ",")
  206. jsonEncode(buffer, "properties", d.Properties(), ",")
  207. jsonEncode(buffer, "labels", d.Labels(), ",")
  208. jsonEncode(buffer, "window", d.Window(), ",")
  209. jsonEncodeString(buffer, "start", d.Start().Format(time.RFC3339), ",")
  210. jsonEncodeString(buffer, "end", d.End().Format(time.RFC3339), ",")
  211. jsonEncodeFloat64(buffer, "minutes", d.Minutes(), ",")
  212. jsonEncodeFloat64(buffer, "byteHours", d.ByteHours, ",")
  213. jsonEncodeFloat64(buffer, "bytes", d.Bytes(), ",")
  214. jsonEncode(buffer, "breakdown", d.Breakdown, ",")
  215. jsonEncodeFloat64(buffer, "adjustment", d.Adjustment(), ",")
  216. jsonEncodeFloat64(buffer, "totalCost", d.TotalCost(), "")
  217. buffer.WriteString("}")
  218. return buffer.Bytes(), nil
  219. }
  220. func (d *Disk) UnmarshalJSON(b []byte) error {
  221. var f interface{}
  222. err := json.Unmarshal(b, &f)
  223. if err != nil {
  224. return err
  225. }
  226. err = d.InterfaceToDisk(f)
  227. if err != nil {
  228. return err
  229. }
  230. return nil
  231. }
  232. // Converts interface{} to Disk, carrying over relevant fields
  233. func (d *Disk) InterfaceToDisk(itf interface{}) error {
  234. fmap := itf.(map[string]interface{})
  235. // parse properties map to AssetProperties
  236. fproperties := fmap["properties"].(map[string]interface{})
  237. properties := toAssetProp(fproperties)
  238. // parse labels map to AssetLabels
  239. labels := make(map[string]string)
  240. for k, v := range fmap["labels"].(map[string]interface{}) {
  241. labels[k] = v.(string)
  242. }
  243. // parse start and end strings to time.Time
  244. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  245. if err != nil {
  246. return err
  247. }
  248. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  249. if err != nil {
  250. return err
  251. }
  252. fbreakdown := fmap["breakdown"].(map[string]interface{})
  253. breakdown := toBreakdown(fbreakdown)
  254. d.properties = &properties
  255. d.labels = labels
  256. d.start = start
  257. d.end = end
  258. d.window = Window{
  259. start: &start,
  260. end: &end,
  261. }
  262. d.Breakdown = &breakdown
  263. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  264. d.adjustment = adjustment.(float64)
  265. }
  266. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  267. d.Cost = Cost.(float64) - d.adjustment
  268. }
  269. if ByteHours, err := getTypedVal(fmap["byteHours"]); err == nil {
  270. d.ByteHours = ByteHours.(float64)
  271. }
  272. // d.Local is not marhsaled, and cannot be calculated from marshaled values.
  273. // Currently, it is just ignored and not set in the resulting unmarshal to Disk
  274. // be aware that this means a resulting Disk from an unmarshal is therefore NOT
  275. // equal to the originally marshaled Disk.
  276. return nil
  277. }
  278. // Network marshal and unmarshal
  279. // MarshalJSON implements json.Marshal interface
  280. func (n *Network) MarshalJSON() ([]byte, error) {
  281. buffer := bytes.NewBufferString("{")
  282. jsonEncodeString(buffer, "type", n.Type().String(), ",")
  283. jsonEncode(buffer, "properties", n.Properties(), ",")
  284. jsonEncode(buffer, "labels", n.Labels(), ",")
  285. jsonEncode(buffer, "window", n.Window(), ",")
  286. jsonEncodeString(buffer, "start", n.Start().Format(time.RFC3339), ",")
  287. jsonEncodeString(buffer, "end", n.End().Format(time.RFC3339), ",")
  288. jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
  289. jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
  290. jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
  291. buffer.WriteString("}")
  292. return buffer.Bytes(), nil
  293. }
  294. func (n *Network) UnmarshalJSON(b []byte) error {
  295. var f interface{}
  296. err := json.Unmarshal(b, &f)
  297. if err != nil {
  298. return err
  299. }
  300. err = n.InterfaceToNetwork(f)
  301. if err != nil {
  302. return err
  303. }
  304. return nil
  305. }
  306. // Converts interface{} to Network, carrying over relevant fields
  307. func (n *Network) InterfaceToNetwork(itf interface{}) error {
  308. fmap := itf.(map[string]interface{})
  309. // parse properties map to AssetProperties
  310. fproperties := fmap["properties"].(map[string]interface{})
  311. properties := toAssetProp(fproperties)
  312. // parse labels map to AssetLabels
  313. labels := make(map[string]string)
  314. for k, v := range fmap["labels"].(map[string]interface{}) {
  315. labels[k] = v.(string)
  316. }
  317. // parse start and end strings to time.Time
  318. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  319. if err != nil {
  320. return err
  321. }
  322. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  323. if err != nil {
  324. return err
  325. }
  326. n.properties = &properties
  327. n.labels = labels
  328. n.start = start
  329. n.end = end
  330. n.window = Window{
  331. start: &start,
  332. end: &end,
  333. }
  334. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  335. n.adjustment = adjustment.(float64)
  336. }
  337. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  338. n.Cost = Cost.(float64) - n.adjustment
  339. }
  340. return nil
  341. }
  342. // Node marshal and unmarshal
  343. // MarshalJSON implements json.Marshal interface
  344. func (n *Node) MarshalJSON() ([]byte, error) {
  345. buffer := bytes.NewBufferString("{")
  346. jsonEncodeString(buffer, "type", n.Type().String(), ",")
  347. jsonEncode(buffer, "properties", n.Properties(), ",")
  348. jsonEncode(buffer, "labels", n.Labels(), ",")
  349. jsonEncode(buffer, "window", n.Window(), ",")
  350. jsonEncodeString(buffer, "start", n.Start().Format(time.RFC3339), ",")
  351. jsonEncodeString(buffer, "end", n.End().Format(time.RFC3339), ",")
  352. jsonEncodeFloat64(buffer, "minutes", n.Minutes(), ",")
  353. jsonEncodeString(buffer, "nodeType", n.NodeType, ",")
  354. jsonEncodeFloat64(buffer, "cpuCores", n.CPUCores(), ",")
  355. jsonEncodeFloat64(buffer, "ramBytes", n.RAMBytes(), ",")
  356. jsonEncodeFloat64(buffer, "cpuCoreHours", n.CPUCoreHours, ",")
  357. jsonEncodeFloat64(buffer, "ramByteHours", n.RAMByteHours, ",")
  358. jsonEncodeFloat64(buffer, "GPUHours", n.GPUHours, ",")
  359. jsonEncode(buffer, "cpuBreakdown", n.CPUBreakdown, ",")
  360. jsonEncode(buffer, "ramBreakdown", n.RAMBreakdown, ",")
  361. jsonEncodeFloat64(buffer, "preemptible", n.Preemptible, ",")
  362. jsonEncodeFloat64(buffer, "discount", n.Discount, ",")
  363. jsonEncodeFloat64(buffer, "cpuCost", n.CPUCost, ",")
  364. jsonEncodeFloat64(buffer, "gpuCost", n.GPUCost, ",")
  365. jsonEncodeFloat64(buffer, "gpuCount", n.GPUs(), ",")
  366. jsonEncodeFloat64(buffer, "ramCost", n.RAMCost, ",")
  367. jsonEncodeFloat64(buffer, "adjustment", n.Adjustment(), ",")
  368. jsonEncodeFloat64(buffer, "totalCost", n.TotalCost(), "")
  369. buffer.WriteString("}")
  370. return buffer.Bytes(), nil
  371. }
  372. func (n *Node) UnmarshalJSON(b []byte) error {
  373. var f interface{}
  374. err := json.Unmarshal(b, &f)
  375. if err != nil {
  376. return err
  377. }
  378. err = n.InterfaceToNode(f)
  379. if err != nil {
  380. return err
  381. }
  382. return nil
  383. }
  384. // Converts interface{} to Node, carrying over relevant fields
  385. func (n *Node) InterfaceToNode(itf interface{}) error {
  386. fmap := itf.(map[string]interface{})
  387. // parse properties map to AssetProperties
  388. fproperties := fmap["properties"].(map[string]interface{})
  389. properties := toAssetProp(fproperties)
  390. // parse labels map to AssetLabels
  391. labels := make(map[string]string)
  392. for k, v := range fmap["labels"].(map[string]interface{}) {
  393. labels[k] = v.(string)
  394. }
  395. // parse start and end strings to time.Time
  396. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  397. if err != nil {
  398. return err
  399. }
  400. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  401. if err != nil {
  402. return err
  403. }
  404. fcpuBreakdown := fmap["cpuBreakdown"].(map[string]interface{})
  405. framBreakdown := fmap["ramBreakdown"].(map[string]interface{})
  406. cpuBreakdown := toBreakdown(fcpuBreakdown)
  407. ramBreakdown := toBreakdown(framBreakdown)
  408. n.properties = &properties
  409. n.labels = labels
  410. n.start = start
  411. n.end = end
  412. n.window = Window{
  413. start: &start,
  414. end: &end,
  415. }
  416. n.CPUBreakdown = &cpuBreakdown
  417. n.RAMBreakdown = &ramBreakdown
  418. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  419. n.adjustment = adjustment.(float64)
  420. }
  421. if NodeType, err := getTypedVal(fmap["nodeType"]); err == nil {
  422. n.NodeType = NodeType.(string)
  423. }
  424. if CPUCoreHours, err := getTypedVal(fmap["cpuCoreHours"]); err == nil {
  425. n.CPUCoreHours = CPUCoreHours.(float64)
  426. }
  427. if RAMByteHours, err := getTypedVal(fmap["ramByteHours"]); err == nil {
  428. n.RAMByteHours = RAMByteHours.(float64)
  429. }
  430. if GPUHours, err := getTypedVal(fmap["GPUHours"]); err == nil {
  431. n.GPUHours = GPUHours.(float64)
  432. }
  433. if CPUCost, err := getTypedVal(fmap["cpuCost"]); err == nil {
  434. n.CPUCost = CPUCost.(float64)
  435. }
  436. if GPUCost, err := getTypedVal(fmap["gpuCost"]); err == nil {
  437. n.GPUCost = GPUCost.(float64)
  438. }
  439. if GPUCount, err := getTypedVal(fmap["gpuCount"]); err == nil {
  440. n.GPUCount = GPUCount.(float64)
  441. }
  442. if RAMCost, err := getTypedVal(fmap["ramCost"]); err == nil {
  443. n.RAMCost = RAMCost.(float64)
  444. }
  445. if Discount, err := getTypedVal(fmap["discount"]); err == nil {
  446. n.Discount = Discount.(float64)
  447. }
  448. if Preemptible, err := getTypedVal(fmap["preemptible"]); err == nil {
  449. n.Preemptible = Preemptible.(float64)
  450. }
  451. return nil
  452. }
  453. // Loadbalancer marshal and unmarshal
  454. // MarshalJSON implements json.Marshal
  455. func (lb *LoadBalancer) MarshalJSON() ([]byte, error) {
  456. buffer := bytes.NewBufferString("{")
  457. jsonEncodeString(buffer, "type", lb.Type().String(), ",")
  458. jsonEncode(buffer, "properties", lb.Properties(), ",")
  459. jsonEncode(buffer, "labels", lb.Labels(), ",")
  460. jsonEncode(buffer, "window", lb.Window(), ",")
  461. jsonEncodeString(buffer, "start", lb.Start().Format(time.RFC3339), ",")
  462. jsonEncodeString(buffer, "end", lb.End().Format(time.RFC3339), ",")
  463. jsonEncodeFloat64(buffer, "minutes", lb.Minutes(), ",")
  464. jsonEncodeFloat64(buffer, "adjustment", lb.Adjustment(), ",")
  465. jsonEncodeFloat64(buffer, "totalCost", lb.TotalCost(), "")
  466. buffer.WriteString("}")
  467. return buffer.Bytes(), nil
  468. }
  469. func (lb *LoadBalancer) UnmarshalJSON(b []byte) error {
  470. var f interface{}
  471. err := json.Unmarshal(b, &f)
  472. if err != nil {
  473. return err
  474. }
  475. err = lb.InterfaceToLoadBalancer(f)
  476. if err != nil {
  477. return err
  478. }
  479. return nil
  480. }
  481. // Converts interface{} to LoadBalancer, carrying over relevant fields
  482. func (lb *LoadBalancer) InterfaceToLoadBalancer(itf interface{}) error {
  483. fmap := itf.(map[string]interface{})
  484. // parse properties map to AssetProperties
  485. fproperties := fmap["properties"].(map[string]interface{})
  486. properties := toAssetProp(fproperties)
  487. // parse labels map to AssetLabels
  488. labels := make(map[string]string)
  489. for k, v := range fmap["labels"].(map[string]interface{}) {
  490. labels[k] = v.(string)
  491. }
  492. // parse start and end strings to time.Time
  493. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  494. if err != nil {
  495. return err
  496. }
  497. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  498. if err != nil {
  499. return err
  500. }
  501. lb.properties = &properties
  502. lb.labels = labels
  503. lb.start = start
  504. lb.end = end
  505. lb.window = Window{
  506. start: &start,
  507. end: &end,
  508. }
  509. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  510. lb.adjustment = adjustment.(float64)
  511. }
  512. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  513. lb.Cost = Cost.(float64) - lb.adjustment
  514. }
  515. return nil
  516. }
  517. // SharedAsset marshal and unmarshal
  518. // MarshalJSON implements json.Marshaler
  519. func (sa *SharedAsset) MarshalJSON() ([]byte, error) {
  520. buffer := bytes.NewBufferString("{")
  521. jsonEncodeString(buffer, "type", sa.Type().String(), ",")
  522. jsonEncode(buffer, "properties", sa.Properties(), ",")
  523. jsonEncode(buffer, "labels", sa.Labels(), ",")
  524. jsonEncode(buffer, "properties", sa.Properties(), ",")
  525. jsonEncode(buffer, "labels", sa.Labels(), ",")
  526. jsonEncode(buffer, "window", sa.Window(), ",")
  527. jsonEncodeString(buffer, "start", sa.Start().Format(time.RFC3339), ",")
  528. jsonEncodeString(buffer, "end", sa.End().Format(time.RFC3339), ",")
  529. jsonEncodeFloat64(buffer, "minutes", sa.Minutes(), ",")
  530. jsonEncodeFloat64(buffer, "totalCost", sa.TotalCost(), "")
  531. buffer.WriteString("}")
  532. return buffer.Bytes(), nil
  533. }
  534. func (sa *SharedAsset) UnmarshalJSON(b []byte) error {
  535. var f interface{}
  536. err := json.Unmarshal(b, &f)
  537. if err != nil {
  538. return err
  539. }
  540. err = sa.InterfaceToSharedAsset(f)
  541. if err != nil {
  542. return err
  543. }
  544. return nil
  545. }
  546. // Converts interface{} to SharedAsset, carrying over relevant fields
  547. func (sa *SharedAsset) InterfaceToSharedAsset(itf interface{}) error {
  548. fmap := itf.(map[string]interface{})
  549. // parse properties map to AssetProperties
  550. fproperties := fmap["properties"].(map[string]interface{})
  551. properties := toAssetProp(fproperties)
  552. // parse labels map to AssetLabels
  553. labels := make(map[string]string)
  554. for k, v := range fmap["labels"].(map[string]interface{}) {
  555. labels[k] = v.(string)
  556. }
  557. // parse start and end strings to time.Time
  558. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  559. if err != nil {
  560. return err
  561. }
  562. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  563. if err != nil {
  564. return err
  565. }
  566. sa.properties = &properties
  567. sa.labels = labels
  568. sa.window = Window{
  569. start: &start,
  570. end: &end,
  571. }
  572. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  573. sa.Cost = Cost.(float64)
  574. }
  575. return nil
  576. }
  577. // AssetSet marshal
  578. // MarshalJSON JSON-encodes the AssetSet
  579. func (as *AssetSet) MarshalJSON() ([]byte, error) {
  580. as.RLock()
  581. defer as.RUnlock()
  582. return json.Marshal(as.assets)
  583. }
  584. // AssetSetResponse for unmarshaling of AssetSet.assets into AssetSet
  585. // Unmarshals a marshaled AssetSet json into AssetSetResponse
  586. func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
  587. // gojson used here, as jsonitter UnmarshalJSON won't work with RawMessage
  588. var assetMap map[string]*gojson.RawMessage
  589. // Partial unmarshal to map of json RawMessage
  590. err := gojson.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]*gojson.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. // gojson used here, as jsonitter UnmarshalJSON won't work with RawMessage
  674. var assetMapList []map[string]*gojson.RawMessage
  675. // Partial unmarshal to map of json RawMessage
  676. err := gojson.Unmarshal(b, &assetMapList)
  677. if err != nil {
  678. return err
  679. }
  680. var assetSetList []*AssetSetResponse
  681. for _, rawm := range assetMapList {
  682. var asresp AssetSetResponse
  683. err = asresp.RawMessageToAssetSetResponse(rawm)
  684. if err != nil {
  685. return err
  686. }
  687. assetSetList = append(assetSetList, &asresp)
  688. }
  689. asrr.Assets = assetSetList
  690. return nil
  691. }
  692. // Extra decoding util functions, for clarity
  693. // Creates an AssetProperties directly from map[string]interface{}
  694. func toAssetProp(fproperties map[string]interface{}) AssetProperties {
  695. var properties AssetProperties
  696. if category, v := fproperties["category"].(string); v {
  697. properties.Category = category
  698. }
  699. if provider, v := fproperties["provider"].(string); v {
  700. properties.Provider = provider
  701. }
  702. if account, v := fproperties["account"].(string); v {
  703. properties.Account = account
  704. }
  705. if project, v := fproperties["project"].(string); v {
  706. properties.Project = project
  707. }
  708. if service, v := fproperties["service"].(string); v {
  709. properties.Service = service
  710. }
  711. if cluster, v := fproperties["cluster"].(string); v {
  712. properties.Cluster = cluster
  713. }
  714. if name, v := fproperties["name"].(string); v {
  715. properties.Name = name
  716. }
  717. if providerID, v := fproperties["providerID"].(string); v {
  718. properties.ProviderID = providerID
  719. }
  720. return properties
  721. }
  722. // Creates an Breakdown directly from map[string]interface{}
  723. func toBreakdown(fproperties map[string]interface{}) Breakdown {
  724. var breakdown Breakdown
  725. if idle, v := fproperties["idle"].(float64); v {
  726. breakdown.Idle = idle
  727. }
  728. if other, v := fproperties["other"].(float64); v {
  729. breakdown.Other = other
  730. }
  731. if system, v := fproperties["system"].(float64); v {
  732. breakdown.System = system
  733. }
  734. if user, v := fproperties["user"].(float64); v {
  735. breakdown.User = user
  736. }
  737. return breakdown
  738. }
  739. // Not strictly nessesary, but cleans up the code and is a secondary check
  740. // for correct types
  741. func getTypedVal(itf interface{}) (interface{}, error) {
  742. switch itf := itf.(type) {
  743. case float64:
  744. return float64(itf), nil
  745. case string:
  746. return string(itf), nil
  747. default:
  748. unktype := reflect.ValueOf(itf)
  749. return nil, fmt.Errorf("Type %v is an invalid type", unktype)
  750. }
  751. }