asset_json.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  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. jsonEncodeString(buffer, "claimNamespace", d.ClaimNamespace, "")
  229. buffer.WriteString("}")
  230. return buffer.Bytes(), nil
  231. }
  232. func (d *Disk) UnmarshalJSON(b []byte) error {
  233. var f interface{}
  234. err := json.Unmarshal(b, &f)
  235. if err != nil {
  236. return err
  237. }
  238. err = d.InterfaceToDisk(f)
  239. if err != nil {
  240. return err
  241. }
  242. return nil
  243. }
  244. // Converts interface{} to Disk, carrying over relevant fields
  245. func (d *Disk) InterfaceToDisk(itf interface{}) error {
  246. fmap := itf.(map[string]interface{})
  247. // parse properties map to AssetProperties
  248. fproperties := fmap["properties"].(map[string]interface{})
  249. properties := toAssetProp(fproperties)
  250. // parse labels map to AssetLabels
  251. labels := make(map[string]string)
  252. for k, v := range fmap["labels"].(map[string]interface{}) {
  253. labels[k] = v.(string)
  254. }
  255. // parse start and end strings to time.Time
  256. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  257. if err != nil {
  258. return err
  259. }
  260. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  261. if err != nil {
  262. return err
  263. }
  264. fbreakdown := fmap["breakdown"].(map[string]interface{})
  265. breakdown := toBreakdown(fbreakdown)
  266. d.Properties = &properties
  267. d.Labels = labels
  268. d.Start = start
  269. d.End = end
  270. d.Window = Window{
  271. start: &start,
  272. end: &end,
  273. }
  274. d.Breakdown = &breakdown
  275. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  276. d.Adjustment = adjustment.(float64)
  277. }
  278. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  279. d.Cost = Cost.(float64) - d.Adjustment
  280. }
  281. if ByteHours, err := getTypedVal(fmap["byteHours"]); err == nil {
  282. d.ByteHours = ByteHours.(float64)
  283. }
  284. if ByteHoursUsed, err := getTypedVal(fmap["byteHoursUsed"]); err == nil {
  285. if ByteHoursUsed == nil {
  286. d.ByteHoursUsed = nil
  287. } else {
  288. byteHours := ByteHoursUsed.(float64)
  289. d.ByteHoursUsed = &byteHours
  290. }
  291. }
  292. if ByteUsageMax, err := getTypedVal(fmap["byteUsageMax"]); err == nil {
  293. if ByteUsageMax == nil {
  294. d.ByteUsageMax = nil
  295. } else {
  296. max := ByteUsageMax.(float64)
  297. d.ByteUsageMax = &max
  298. }
  299. }
  300. if StorageClass, err := getTypedVal(fmap["storageClass"]); err == nil {
  301. d.StorageClass = StorageClass.(string)
  302. }
  303. if VolumeName, err := getTypedVal(fmap["volumeName"]); err == nil {
  304. d.VolumeName = VolumeName.(string)
  305. }
  306. if ClaimName, err := getTypedVal(fmap["claimName"]); err == nil {
  307. d.ClaimName = ClaimName.(string)
  308. }
  309. if ClaimNamespace, err := getTypedVal(fmap["claimNamespace"]); err == nil {
  310. d.ClaimNamespace = ClaimNamespace.(string)
  311. }
  312. // d.Local is not marhsaled, and cannot be calculated from marshaled values.
  313. // Currently, it is just ignored and not set in the resulting unmarshal to Disk
  314. // be aware that this means a resulting Disk from an unmarshal is therefore NOT
  315. // equal to the originally marshaled Disk.
  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. for k, v := range fmap["labels"].(map[string]interface{}) {
  439. labels[k] = v.(string)
  440. }
  441. // parse start and end strings to time.Time
  442. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  443. if err != nil {
  444. return err
  445. }
  446. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  447. if err != nil {
  448. return err
  449. }
  450. fcpuBreakdown := fmap["cpuBreakdown"].(map[string]interface{})
  451. framBreakdown := fmap["ramBreakdown"].(map[string]interface{})
  452. cpuBreakdown := toBreakdown(fcpuBreakdown)
  453. ramBreakdown := toBreakdown(framBreakdown)
  454. n.Properties = &properties
  455. n.Labels = labels
  456. n.Start = start
  457. n.End = end
  458. n.Window = Window{
  459. start: &start,
  460. end: &end,
  461. }
  462. n.CPUBreakdown = &cpuBreakdown
  463. n.RAMBreakdown = &ramBreakdown
  464. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  465. n.Adjustment = adjustment.(float64)
  466. }
  467. if NodeType, err := getTypedVal(fmap["nodeType"]); err == nil {
  468. n.NodeType = NodeType.(string)
  469. }
  470. if CPUCoreHours, err := getTypedVal(fmap["cpuCoreHours"]); err == nil {
  471. n.CPUCoreHours = CPUCoreHours.(float64)
  472. }
  473. if RAMByteHours, err := getTypedVal(fmap["ramByteHours"]); err == nil {
  474. n.RAMByteHours = RAMByteHours.(float64)
  475. }
  476. if GPUHours, err := getTypedVal(fmap["GPUHours"]); err == nil {
  477. n.GPUHours = GPUHours.(float64)
  478. }
  479. if CPUCost, err := getTypedVal(fmap["cpuCost"]); err == nil {
  480. n.CPUCost = CPUCost.(float64)
  481. }
  482. if GPUCost, err := getTypedVal(fmap["gpuCost"]); err == nil {
  483. n.GPUCost = GPUCost.(float64)
  484. }
  485. if GPUCount, err := getTypedVal(fmap["gpuCount"]); err == nil {
  486. n.GPUCount = GPUCount.(float64)
  487. }
  488. if RAMCost, err := getTypedVal(fmap["ramCost"]); err == nil {
  489. n.RAMCost = RAMCost.(float64)
  490. }
  491. if Discount, err := getTypedVal(fmap["discount"]); err == nil {
  492. n.Discount = Discount.(float64)
  493. }
  494. if Preemptible, err := getTypedVal(fmap["preemptible"]); err == nil {
  495. n.Preemptible = Preemptible.(float64)
  496. }
  497. return nil
  498. }
  499. // Loadbalancer marshal and unmarshal
  500. // MarshalJSON implements json.Marshal
  501. func (lb *LoadBalancer) MarshalJSON() ([]byte, error) {
  502. buffer := bytes.NewBufferString("{")
  503. jsonEncodeString(buffer, "type", lb.Type().String(), ",")
  504. jsonEncode(buffer, "properties", lb.Properties, ",")
  505. jsonEncode(buffer, "labels", lb.Labels, ",")
  506. jsonEncode(buffer, "window", lb.Window, ",")
  507. jsonEncodeString(buffer, "start", lb.Start.Format(time.RFC3339), ",")
  508. jsonEncodeString(buffer, "end", lb.End.Format(time.RFC3339), ",")
  509. jsonEncodeFloat64(buffer, "minutes", lb.Minutes(), ",")
  510. jsonEncodeFloat64(buffer, "adjustment", lb.Adjustment, ",")
  511. jsonEncodeFloat64(buffer, "totalCost", lb.TotalCost(), ",")
  512. jsonEncode(buffer, "private", lb.Private, ",")
  513. jsonEncodeString(buffer, "ip", lb.Ip, "")
  514. buffer.WriteString("}")
  515. return buffer.Bytes(), nil
  516. }
  517. func (lb *LoadBalancer) UnmarshalJSON(b []byte) error {
  518. var f interface{}
  519. err := json.Unmarshal(b, &f)
  520. if err != nil {
  521. return err
  522. }
  523. err = lb.InterfaceToLoadBalancer(f)
  524. if err != nil {
  525. return err
  526. }
  527. return nil
  528. }
  529. // Converts interface{} to LoadBalancer, carrying over relevant fields
  530. func (lb *LoadBalancer) InterfaceToLoadBalancer(itf interface{}) error {
  531. fmap := itf.(map[string]interface{})
  532. // parse properties map to AssetProperties
  533. fproperties := fmap["properties"].(map[string]interface{})
  534. properties := toAssetProp(fproperties)
  535. // parse labels map to AssetLabels
  536. labels := make(map[string]string)
  537. for k, v := range fmap["labels"].(map[string]interface{}) {
  538. labels[k] = v.(string)
  539. }
  540. // parse start and end strings to time.Time
  541. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  542. if err != nil {
  543. return err
  544. }
  545. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  546. if err != nil {
  547. return err
  548. }
  549. lb.Properties = &properties
  550. lb.Labels = labels
  551. lb.Start = start
  552. lb.End = end
  553. lb.Window = Window{
  554. start: &start,
  555. end: &end,
  556. }
  557. if adjustment, err := getTypedVal(fmap["adjustment"]); err == nil {
  558. lb.Adjustment = adjustment.(float64)
  559. }
  560. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  561. lb.Cost = Cost.(float64) - lb.Adjustment
  562. }
  563. if private, err := getTypedVal(fmap["private"]); err == nil {
  564. lb.Private = private.(bool)
  565. }
  566. if ip, err := getTypedVal(fmap["ip"]); err == nil {
  567. lb.Ip = ip.(string)
  568. }
  569. return nil
  570. }
  571. // SharedAsset marshal and unmarshal
  572. // MarshalJSON implements json.Marshaler
  573. func (sa *SharedAsset) MarshalJSON() ([]byte, error) {
  574. buffer := bytes.NewBufferString("{")
  575. jsonEncodeString(buffer, "type", sa.Type().String(), ",")
  576. jsonEncode(buffer, "properties", sa.Properties, ",")
  577. jsonEncode(buffer, "labels", sa.Labels, ",")
  578. jsonEncode(buffer, "window", sa.Window, ",")
  579. jsonEncodeString(buffer, "start", sa.GetStart().Format(time.RFC3339), ",")
  580. jsonEncodeString(buffer, "end", sa.GetEnd().Format(time.RFC3339), ",")
  581. jsonEncodeFloat64(buffer, "minutes", sa.Minutes(), ",")
  582. jsonEncodeFloat64(buffer, "totalCost", sa.TotalCost(), "")
  583. buffer.WriteString("}")
  584. return buffer.Bytes(), nil
  585. }
  586. func (sa *SharedAsset) UnmarshalJSON(b []byte) error {
  587. var f interface{}
  588. err := json.Unmarshal(b, &f)
  589. if err != nil {
  590. return err
  591. }
  592. err = sa.InterfaceToSharedAsset(f)
  593. if err != nil {
  594. return err
  595. }
  596. return nil
  597. }
  598. // Converts interface{} to SharedAsset, carrying over relevant fields
  599. func (sa *SharedAsset) InterfaceToSharedAsset(itf interface{}) error {
  600. fmap := itf.(map[string]interface{})
  601. // parse properties map to AssetProperties
  602. fproperties := fmap["properties"].(map[string]interface{})
  603. properties := toAssetProp(fproperties)
  604. // parse labels map to AssetLabels
  605. labels := make(map[string]string)
  606. for k, v := range fmap["labels"].(map[string]interface{}) {
  607. labels[k] = v.(string)
  608. }
  609. // parse start and end strings to time.Time
  610. start, err := time.Parse(time.RFC3339, fmap["start"].(string))
  611. if err != nil {
  612. return err
  613. }
  614. end, err := time.Parse(time.RFC3339, fmap["end"].(string))
  615. if err != nil {
  616. return err
  617. }
  618. sa.Properties = &properties
  619. sa.Labels = labels
  620. sa.Window = Window{
  621. start: &start,
  622. end: &end,
  623. }
  624. if Cost, err := getTypedVal(fmap["totalCost"]); err == nil {
  625. sa.Cost = Cost.(float64)
  626. }
  627. return nil
  628. }
  629. // AssetSet marshal
  630. // MarshalJSON JSON-encodes the AssetSet
  631. func (as *AssetSet) MarshalJSON() ([]byte, error) {
  632. if as == nil {
  633. return json.Marshal(map[string]Asset{})
  634. }
  635. return json.Marshal(as.Assets)
  636. }
  637. // AssetSetResponse for unmarshaling of AssetSet.assets into AssetSet
  638. // Unmarshals a marshaled AssetSet json into AssetSetResponse
  639. func (asr *AssetSetResponse) UnmarshalJSON(b []byte) error {
  640. var assetMap map[string]*json.RawMessage
  641. // Partial unmarshal to map of json RawMessage
  642. err := json.Unmarshal(b, &assetMap)
  643. if err != nil {
  644. return err
  645. }
  646. err = asr.RawMessageToAssetSetResponse(assetMap)
  647. if err != nil {
  648. return err
  649. }
  650. return nil
  651. }
  652. func (asr *AssetSetResponse) RawMessageToAssetSetResponse(assetMap map[string]*json.RawMessage) error {
  653. newAssetMap := make(map[string]Asset)
  654. // For each item in asset map, unmarshal to appropriate type
  655. for key, rawMessage := range assetMap {
  656. var f interface{}
  657. err := json.Unmarshal(*rawMessage, &f)
  658. if err != nil {
  659. return err
  660. }
  661. fmap := f.(map[string]interface{})
  662. switch t := fmap["type"]; t {
  663. case "Cloud":
  664. var ca Cloud
  665. err := ca.InterfaceToCloud(f)
  666. if err != nil {
  667. return err
  668. }
  669. newAssetMap[key] = &ca
  670. case "ClusterManagement":
  671. var cm ClusterManagement
  672. err := cm.InterfaceToClusterManagement(f)
  673. if err != nil {
  674. return err
  675. }
  676. newAssetMap[key] = &cm
  677. case "Disk":
  678. var d Disk
  679. err := d.InterfaceToDisk(f)
  680. if err != nil {
  681. return err
  682. }
  683. newAssetMap[key] = &d
  684. case "Network":
  685. var nw Network
  686. err := nw.InterfaceToNetwork(f)
  687. if err != nil {
  688. return err
  689. }
  690. newAssetMap[key] = &nw
  691. case "Node":
  692. var n Node
  693. err := n.InterfaceToNode(f)
  694. if err != nil {
  695. return err
  696. }
  697. newAssetMap[key] = &n
  698. case "LoadBalancer":
  699. var lb LoadBalancer
  700. err := lb.InterfaceToLoadBalancer(f)
  701. if err != nil {
  702. return err
  703. }
  704. newAssetMap[key] = &lb
  705. case "Shared":
  706. var sa SharedAsset
  707. err := sa.InterfaceToSharedAsset(f)
  708. if err != nil {
  709. return err
  710. }
  711. newAssetMap[key] = &sa
  712. default:
  713. var a Any
  714. err := a.InterfaceToAny(f)
  715. if err != nil {
  716. return err
  717. }
  718. newAssetMap[key] = &a
  719. }
  720. }
  721. asr.Assets = newAssetMap
  722. return nil
  723. }
  724. func (asrr *AssetSetRangeResponse) UnmarshalJSON(b []byte) error {
  725. var assetMapList []map[string]*json.RawMessage
  726. // Partial unmarshal to map of json RawMessage
  727. err := json.Unmarshal(b, &assetMapList)
  728. if err != nil {
  729. return err
  730. }
  731. var assetSetList []*AssetSetResponse
  732. for _, rawm := range assetMapList {
  733. var asresp AssetSetResponse
  734. err = asresp.RawMessageToAssetSetResponse(rawm)
  735. if err != nil {
  736. return err
  737. }
  738. assetSetList = append(assetSetList, &asresp)
  739. }
  740. asrr.Assets = assetSetList
  741. return nil
  742. }
  743. // Extra decoding util functions, for clarity
  744. // Creates an AssetProperties directly from map[string]interface{}
  745. func toAssetProp(fproperties map[string]interface{}) AssetProperties {
  746. var properties AssetProperties
  747. if category, v := fproperties["category"].(string); v {
  748. properties.Category = category
  749. }
  750. if provider, v := fproperties["provider"].(string); v {
  751. properties.Provider = provider
  752. }
  753. if account, v := fproperties["account"].(string); v {
  754. properties.Account = account
  755. }
  756. if project, v := fproperties["project"].(string); v {
  757. properties.Project = project
  758. }
  759. if service, v := fproperties["service"].(string); v {
  760. properties.Service = service
  761. }
  762. if cluster, v := fproperties["cluster"].(string); v {
  763. properties.Cluster = cluster
  764. }
  765. if name, v := fproperties["name"].(string); v {
  766. properties.Name = name
  767. }
  768. if providerID, v := fproperties["providerID"].(string); v {
  769. properties.ProviderID = providerID
  770. }
  771. return properties
  772. }
  773. // Creates an Breakdown directly from map[string]interface{}
  774. func toBreakdown(fproperties map[string]interface{}) Breakdown {
  775. var breakdown Breakdown
  776. if idle, v := fproperties["idle"].(float64); v {
  777. breakdown.Idle = idle
  778. }
  779. if other, v := fproperties["other"].(float64); v {
  780. breakdown.Other = other
  781. }
  782. if system, v := fproperties["system"].(float64); v {
  783. breakdown.System = system
  784. }
  785. if user, v := fproperties["user"].(float64); v {
  786. breakdown.User = user
  787. }
  788. return breakdown
  789. }
  790. // Not strictly nessesary, but cleans up the code and is a secondary check
  791. // for correct types
  792. func getTypedVal(itf interface{}) (interface{}, error) {
  793. switch itf := itf.(type) {
  794. case float64:
  795. return float64(itf), nil
  796. case string:
  797. return string(itf), nil
  798. default:
  799. unktype := reflect.ValueOf(itf)
  800. return nil, fmt.Errorf("Type %v is an invalid type", unktype)
  801. }
  802. }