properties.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. package kubecost
  2. import (
  3. "fmt"
  4. "sort"
  5. "strings"
  6. util "github.com/kubecost/cost-model/pkg/util"
  7. )
  8. type Property string
  9. const (
  10. NilProp Property = ""
  11. ClusterProp Property = "cluster"
  12. NodeProp Property = "node"
  13. ContainerProp Property = "container"
  14. ControllerProp Property = "controller"
  15. ControllerKindProp Property = "controllerKind"
  16. LabelProp Property = "label"
  17. AnnotationProp Property = "annotation"
  18. NamespaceProp Property = "namespace"
  19. PodProp Property = "pod"
  20. ServiceProp Property = "service"
  21. )
  22. var availableProperties []Property = []Property{
  23. NilProp,
  24. ClusterProp,
  25. NodeProp,
  26. ContainerProp,
  27. ControllerProp,
  28. ControllerKindProp,
  29. LabelProp,
  30. AnnotationProp,
  31. NamespaceProp,
  32. PodProp,
  33. ServiceProp,
  34. }
  35. func ParseProperty(prop string) Property {
  36. for _, property := range availableProperties {
  37. if strings.ToLower(string(property)) == strings.ToLower(prop) {
  38. return property
  39. }
  40. }
  41. return NilProp
  42. }
  43. func (p Property) String() string {
  44. return string(p)
  45. }
  46. type PropertyValue struct {
  47. Property Property
  48. Value interface{}
  49. }
  50. // Properties describes a set of Kubernetes objects.
  51. type Properties map[Property]interface{}
  52. // TODO niko/etl make sure Services deep copy works correctly
  53. func (p *Properties) Clone() Properties {
  54. if p == nil {
  55. return nil
  56. }
  57. clone := make(Properties, len(*p))
  58. for k, v := range *p {
  59. clone[k] = v
  60. }
  61. return clone
  62. }
  63. func (p *Properties) Equal(that *Properties) bool {
  64. if p == nil || that == nil {
  65. return false
  66. }
  67. if p.Length() != that.Length() {
  68. return false
  69. }
  70. pCluster, _ := p.GetCluster()
  71. thatCluster, _ := that.GetCluster()
  72. if pCluster != thatCluster {
  73. return false
  74. }
  75. pNode, _ := p.GetNode()
  76. thatNode, _ := that.GetNode()
  77. if pNode != thatNode {
  78. return false
  79. }
  80. pContainer, _ := p.GetContainer()
  81. thatContainer, _ := that.GetContainer()
  82. if pContainer != thatContainer {
  83. return false
  84. }
  85. pController, _ := p.GetController()
  86. thatController, _ := that.GetController()
  87. if pController != thatController {
  88. return false
  89. }
  90. pControllerKind, _ := p.GetControllerKind()
  91. thatControllerKind, _ := that.GetControllerKind()
  92. if pControllerKind != thatControllerKind {
  93. return false
  94. }
  95. pNamespace, _ := p.GetNamespace()
  96. thatNamespace, _ := that.GetNamespace()
  97. if pNamespace != thatNamespace {
  98. return false
  99. }
  100. pPod, _ := p.GetPod()
  101. thatPod, _ := that.GetPod()
  102. if pPod != thatPod {
  103. return false
  104. }
  105. pLabels, _ := p.GetLabels()
  106. thatLabels, _ := that.GetLabels()
  107. if len(pLabels) != len(thatLabels) {
  108. for k, pv := range pLabels {
  109. tv, ok := thatLabels[k]
  110. if !ok || tv != pv {
  111. return false
  112. }
  113. }
  114. return false
  115. }
  116. pAnnotations, _ := p.GetAnnotations()
  117. thatAnnotations, _ := that.GetAnnotations()
  118. if len(pAnnotations) != len(thatAnnotations) {
  119. for k, pv := range pAnnotations {
  120. tv, ok := thatAnnotations[k]
  121. if !ok || tv != pv {
  122. return false
  123. }
  124. }
  125. return false
  126. }
  127. pServices, _ := p.GetServices()
  128. thatServices, _ := that.GetServices()
  129. if len(pServices) != len(thatServices) {
  130. sort.Strings(pServices)
  131. sort.Strings(thatServices)
  132. for i, pv := range pServices {
  133. tv := thatServices[i]
  134. if tv != pv {
  135. return false
  136. }
  137. }
  138. return false
  139. }
  140. return true
  141. }
  142. func (p *Properties) Intersection(that Properties) Properties {
  143. spec := &Properties{}
  144. sCluster, sErr := p.GetCluster()
  145. tCluster, tErr := that.GetCluster()
  146. if sErr == nil && tErr == nil && sCluster == tCluster {
  147. spec.SetCluster(sCluster)
  148. }
  149. sNode, sErr := p.GetNode()
  150. tNode, tErr := that.GetNode()
  151. if sErr == nil && tErr == nil && sNode == tNode {
  152. spec.SetNode(sNode)
  153. }
  154. sContainer, sErr := p.GetContainer()
  155. tContainer, tErr := that.GetContainer()
  156. if sErr == nil && tErr == nil && sContainer == tContainer {
  157. spec.SetContainer(sContainer)
  158. }
  159. sController, sErr := p.GetController()
  160. tController, tErr := that.GetController()
  161. if sErr == nil && tErr == nil && sController == tController {
  162. spec.SetController(sController)
  163. }
  164. sControllerKind, sErr := p.GetControllerKind()
  165. tControllerKind, tErr := that.GetControllerKind()
  166. if sErr == nil && tErr == nil && sControllerKind == tControllerKind {
  167. spec.SetControllerKind(sControllerKind)
  168. }
  169. sNamespace, sErr := p.GetNamespace()
  170. tNamespace, tErr := that.GetNamespace()
  171. if sErr == nil && tErr == nil && sNamespace == tNamespace {
  172. spec.SetNamespace(sNamespace)
  173. }
  174. sPod, sErr := p.GetPod()
  175. tPod, tErr := that.GetPod()
  176. if sErr == nil && tErr == nil && sPod == tPod {
  177. spec.SetPod(sPod)
  178. }
  179. // TODO niko/etl intersection of services and labels and annotations
  180. return *spec
  181. }
  182. // Length returns the number of Properties
  183. func (p *Properties) Length() int {
  184. if p == nil {
  185. return 0
  186. }
  187. return len(*p)
  188. }
  189. func (p *Properties) String() string {
  190. if p == nil {
  191. return "<nil>"
  192. }
  193. strs := []string{}
  194. for key, prop := range *p {
  195. strs = append(strs, fmt.Sprintf("%s:%s", key, prop))
  196. }
  197. return fmt.Sprintf("{%s}", strings.Join(strs, "; "))
  198. }
  199. // AggregationStrings converts a Properties object into a slice of strings
  200. // representing a request to aggregate by certain properties.
  201. // NOTE: today, the ordering of the properties *has to match the ordering
  202. // of the allocaiton function generateKey*
  203. func (p *Properties) AggregationStrings() []string {
  204. if p == nil {
  205. return []string{}
  206. }
  207. aggStrs := []string{}
  208. if p.HasCluster() {
  209. aggStrs = append(aggStrs, ClusterProp.String())
  210. }
  211. if p.HasNode() {
  212. aggStrs = append(aggStrs, NodeProp.String())
  213. }
  214. if p.HasNamespace() {
  215. aggStrs = append(aggStrs, NamespaceProp.String())
  216. }
  217. if p.HasControllerKind() {
  218. aggStrs = append(aggStrs, ControllerKindProp.String())
  219. }
  220. if p.HasController() {
  221. aggStrs = append(aggStrs, ControllerProp.String())
  222. }
  223. if p.HasPod() {
  224. aggStrs = append(aggStrs, PodProp.String())
  225. }
  226. if p.HasContainer() {
  227. aggStrs = append(aggStrs, ContainerProp.String())
  228. }
  229. if p.HasService() {
  230. aggStrs = append(aggStrs, ServiceProp.String())
  231. }
  232. if p.HasLabel() {
  233. // e.g. expect format map[string]string{
  234. // "env":""
  235. // "app":"",
  236. // }
  237. // for aggregating by "label:app,label:env"
  238. labels, _ := p.GetLabels()
  239. labelAggStrs := []string{}
  240. for labelName := range labels {
  241. labelAggStrs = append(labelAggStrs, fmt.Sprintf("label:%s", labelName))
  242. }
  243. if len(labelAggStrs) > 0 {
  244. // Enforce alphabetical ordering, then append to aggStrs
  245. sort.Strings(labelAggStrs)
  246. for _, labelName := range labelAggStrs {
  247. aggStrs = append(aggStrs, labelName)
  248. }
  249. }
  250. }
  251. return aggStrs
  252. }
  253. func (p *Properties) Get(prop Property) (string, error) {
  254. if raw, ok := (*p)[prop]; ok {
  255. if result, ok := raw.(string); ok {
  256. return result, nil
  257. }
  258. return "", fmt.Errorf("%s is not a string", prop)
  259. }
  260. return "", fmt.Errorf("%s not set", prop)
  261. }
  262. func (p *Properties) Has(prop Property) bool {
  263. _, ok := (*p)[prop]
  264. return ok
  265. }
  266. func (p *Properties) Set(prop Property, value string) {
  267. (*p)[prop] = value
  268. }
  269. func (p *Properties) GetCluster() (string, error) {
  270. if raw, ok := (*p)[ClusterProp]; ok {
  271. if cluster, ok := raw.(string); ok {
  272. return cluster, nil
  273. }
  274. return "", fmt.Errorf("ClusterProp is not a string")
  275. }
  276. return "", fmt.Errorf("ClusterProp not set")
  277. }
  278. func (p *Properties) HasCluster() bool {
  279. _, ok := (*p)[ClusterProp]
  280. return ok
  281. }
  282. func (p *Properties) SetCluster(cluster string) {
  283. (*p)[ClusterProp] = cluster
  284. }
  285. func (p *Properties) GetNode() (string, error) {
  286. if raw, ok := (*p)[NodeProp]; ok {
  287. if node, ok := raw.(string); ok {
  288. return node, nil
  289. }
  290. return "", fmt.Errorf("NodeProp is not a string")
  291. }
  292. return "", fmt.Errorf("NodeProp not set")
  293. }
  294. func (p *Properties) HasNode() bool {
  295. _, ok := (*p)[NodeProp]
  296. return ok
  297. }
  298. func (p *Properties) SetNode(node string) {
  299. (*p)[NodeProp] = node
  300. }
  301. func (p *Properties) GetContainer() (string, error) {
  302. if raw, ok := (*p)[ContainerProp]; ok {
  303. if container, ok := raw.(string); ok {
  304. return container, nil
  305. }
  306. return "", fmt.Errorf("ContainerProp is not a string")
  307. }
  308. return "", fmt.Errorf("ContainerProp not set")
  309. }
  310. func (p *Properties) HasContainer() bool {
  311. _, ok := (*p)[ContainerProp]
  312. return ok
  313. }
  314. func (p *Properties) SetContainer(container string) {
  315. (*p)[ContainerProp] = container
  316. }
  317. func (p *Properties) GetController() (string, error) {
  318. if raw, ok := (*p)[ControllerProp]; ok {
  319. if controller, ok := raw.(string); ok {
  320. return controller, nil
  321. }
  322. return "", fmt.Errorf("ControllerProp is not a string")
  323. }
  324. return "", fmt.Errorf("ControllerProp not set")
  325. }
  326. func (p *Properties) HasController() bool {
  327. _, ok := (*p)[ControllerProp]
  328. return ok
  329. }
  330. func (p *Properties) SetController(controller string) {
  331. (*p)[ControllerProp] = controller
  332. }
  333. func (p *Properties) GetControllerKind() (string, error) {
  334. if raw, ok := (*p)[ControllerKindProp]; ok {
  335. if controllerKind, ok := raw.(string); ok {
  336. return controllerKind, nil
  337. }
  338. return "", fmt.Errorf("ControllerKindProp is not a string")
  339. }
  340. return "", fmt.Errorf("ControllerKindProp not set")
  341. }
  342. func (p *Properties) HasControllerKind() bool {
  343. _, ok := (*p)[ControllerKindProp]
  344. return ok
  345. }
  346. func (p *Properties) SetControllerKind(controllerKind string) {
  347. (*p)[ControllerKindProp] = controllerKind
  348. }
  349. func (p *Properties) GetLabels() (map[string]string, error) {
  350. if raw, ok := (*p)[LabelProp]; ok {
  351. if labels, ok := raw.(map[string]string); ok {
  352. return labels, nil
  353. }
  354. return map[string]string{}, fmt.Errorf("LabelProp is not a map[string]string")
  355. }
  356. return map[string]string{}, fmt.Errorf("LabelProp not set")
  357. }
  358. func (p *Properties) HasLabel() bool {
  359. _, ok := (*p)[LabelProp]
  360. return ok
  361. }
  362. func (p *Properties) SetLabels(labels map[string]string) {
  363. (*p)[LabelProp] = labels
  364. }
  365. func (p *Properties) GetAnnotations() (map[string]string, error) {
  366. if raw, ok := (*p)[AnnotationProp]; ok {
  367. if annotations, ok := raw.(map[string]string); ok {
  368. return annotations, nil
  369. }
  370. return map[string]string{}, fmt.Errorf("AnnotationProp is not a map[string]string")
  371. }
  372. return map[string]string{}, fmt.Errorf("AnnotationProp not set")
  373. }
  374. func (p *Properties) HasAnnotations() bool {
  375. _, ok := (*p)[AnnotationProp]
  376. return ok
  377. }
  378. func (p *Properties) SetAnnotations(annotations map[string]string) {
  379. (*p)[AnnotationProp] = annotations
  380. }
  381. func (p *Properties) GetNamespace() (string, error) {
  382. if raw, ok := (*p)[NamespaceProp]; ok {
  383. if namespace, ok := raw.(string); ok {
  384. return namespace, nil
  385. }
  386. return "", fmt.Errorf("NamespaceProp is not a string")
  387. }
  388. return "", fmt.Errorf("NamespaceProp not set")
  389. }
  390. func (p *Properties) HasNamespace() bool {
  391. _, ok := (*p)[NamespaceProp]
  392. return ok
  393. }
  394. func (p *Properties) SetNamespace(namespace string) {
  395. (*p)[NamespaceProp] = namespace
  396. }
  397. func (p *Properties) GetPod() (string, error) {
  398. if raw, ok := (*p)[PodProp]; ok {
  399. if pod, ok := raw.(string); ok {
  400. return pod, nil
  401. }
  402. return "", fmt.Errorf("PodProp is not a string")
  403. }
  404. return "", fmt.Errorf("PodProp not set")
  405. }
  406. func (p *Properties) HasPod() bool {
  407. _, ok := (*p)[PodProp]
  408. return ok
  409. }
  410. func (p *Properties) SetPod(pod string) {
  411. (*p)[PodProp] = pod
  412. }
  413. func (p *Properties) GetServices() ([]string, error) {
  414. if raw, ok := (*p)[ServiceProp]; ok {
  415. if services, ok := raw.([]string); ok {
  416. return services, nil
  417. }
  418. return []string{}, fmt.Errorf("ServiceProp is not a string")
  419. }
  420. return []string{}, fmt.Errorf("ServiceProp not set")
  421. }
  422. func (p *Properties) HasService() bool {
  423. _, ok := (*p)[ServiceProp]
  424. return ok
  425. }
  426. func (p *Properties) SetServices(services []string) {
  427. (*p)[ServiceProp] = services
  428. }
  429. func (p *Properties) MarshalBinary() (data []byte, err error) {
  430. buff := util.NewBuffer()
  431. buff.WriteUInt8(CodecVersion) // version
  432. // ClusterProp
  433. cluster, err := p.GetCluster()
  434. if err != nil {
  435. buff.WriteUInt8(uint8(0)) // write nil byte
  436. } else {
  437. buff.WriteUInt8(uint8(1)) // write non-nil byte
  438. buff.WriteString(cluster) // write string
  439. }
  440. // NodeProp
  441. node, err := p.GetNode()
  442. if err != nil {
  443. buff.WriteUInt8(uint8(0)) // write nil byte
  444. } else {
  445. buff.WriteUInt8(uint8(1)) // write non-nil byte
  446. buff.WriteString(node) // write string
  447. }
  448. // ContainerProp
  449. container, err := p.GetContainer()
  450. if err != nil {
  451. buff.WriteUInt8(uint8(0)) // write nil byte
  452. } else {
  453. buff.WriteUInt8(uint8(1)) // write non-nil byte
  454. buff.WriteString(container) // write string
  455. }
  456. // ControllerProp
  457. controller, err := p.GetController()
  458. if err != nil {
  459. buff.WriteUInt8(uint8(0)) // write nil byte
  460. } else {
  461. buff.WriteUInt8(uint8(1)) // write non-nil byte
  462. buff.WriteString(controller) // write string
  463. }
  464. // ControllerKindProp
  465. controllerKind, err := p.GetControllerKind()
  466. if err != nil {
  467. buff.WriteUInt8(uint8(0)) // write nil byte
  468. } else {
  469. buff.WriteUInt8(uint8(1)) // write non-nil byte
  470. buff.WriteString(controllerKind) // write string
  471. }
  472. // NamespaceProp
  473. namespace, err := p.GetNamespace()
  474. if err != nil {
  475. buff.WriteUInt8(uint8(0)) // write nil byte
  476. } else {
  477. buff.WriteUInt8(uint8(1)) // write non-nil byte
  478. buff.WriteString(namespace) // write string
  479. }
  480. // PodProp
  481. pod, err := p.GetPod()
  482. if err != nil {
  483. buff.WriteUInt8(uint8(0)) // write nil byte
  484. } else {
  485. buff.WriteUInt8(uint8(1)) // write non-nil byte
  486. buff.WriteString(pod) // write string
  487. }
  488. // LabelProp
  489. labels, err := p.GetLabels()
  490. if err != nil {
  491. buff.WriteUInt8(uint8(0)) // write nil byte
  492. } else {
  493. buff.WriteUInt8(uint8(1)) // write non-nil byte
  494. buff.WriteInt(len(labels)) // map length
  495. for k, v := range labels {
  496. buff.WriteString(k) // write string
  497. buff.WriteString(v) // write string
  498. }
  499. }
  500. // AnnotationProp
  501. annotations, err := p.GetAnnotations()
  502. if err != nil {
  503. buff.WriteUInt8(uint8(0)) // write nil byte
  504. } else {
  505. buff.WriteUInt8(uint8(1)) // write non-nil byte
  506. buff.WriteInt(len(annotations)) // map length
  507. for k, v := range annotations {
  508. buff.WriteString(k) // write string
  509. buff.WriteString(v) // write string
  510. }
  511. }
  512. // ServiceProp
  513. services, err := p.GetServices()
  514. if err != nil {
  515. buff.WriteUInt8(uint8(0)) // write nil byte
  516. } else {
  517. buff.WriteUInt8(uint8(1)) // write non-nil byte
  518. buff.WriteInt(len(services)) // slice length
  519. for _, v := range services {
  520. buff.WriteString(v) // write string
  521. }
  522. }
  523. return buff.Bytes(), nil
  524. }
  525. func (p *Properties) UnmarshalBinary(data []byte) error {
  526. buff := util.NewBufferFromBytes(data)
  527. v := buff.ReadUInt8() // version
  528. if v != CodecVersion {
  529. return fmt.Errorf("Invalid Version. Expected %d, got %d", CodecVersion, v)
  530. }
  531. *p = Properties{}
  532. // ClusterProp
  533. if buff.ReadUInt8() == 1 { // read nil byte
  534. cluster := buff.ReadString() // read string
  535. p.SetCluster(cluster)
  536. }
  537. // NodeProp
  538. if buff.ReadUInt8() == 1 { // read nil byte
  539. node := buff.ReadString() // read string
  540. p.SetNode(node)
  541. }
  542. // ContainerProp
  543. if buff.ReadUInt8() == 1 { // read nil byte
  544. container := buff.ReadString() // read string
  545. p.SetContainer(container)
  546. }
  547. // ControllerProp
  548. if buff.ReadUInt8() == 1 { // read nil byte
  549. controller := buff.ReadString() // read string
  550. p.SetController(controller)
  551. }
  552. // ControllerKindProp
  553. if buff.ReadUInt8() == 1 { // read nil byte
  554. controllerKind := buff.ReadString() // read string
  555. p.SetControllerKind(controllerKind)
  556. }
  557. // NamespaceProp
  558. if buff.ReadUInt8() == 1 { // read nil byte
  559. namespace := buff.ReadString() // read string
  560. p.SetNamespace(namespace)
  561. }
  562. // PodProp
  563. if buff.ReadUInt8() == 1 { // read nil byte
  564. pod := buff.ReadString() // read string
  565. p.SetPod(pod)
  566. }
  567. // LabelProp
  568. if buff.ReadUInt8() == 1 { // read nil byte
  569. length := buff.ReadInt() // read map len
  570. labels := make(map[string]string, length)
  571. for idx := 0; idx < length; idx++ {
  572. key := buff.ReadString()
  573. val := buff.ReadString()
  574. labels[key] = val
  575. }
  576. p.SetLabels(labels)
  577. }
  578. // AnnotationProp
  579. if buff.ReadUInt8() == 1 { // read nil byte
  580. length := buff.ReadInt() // read map len
  581. annotations := make(map[string]string, length)
  582. for idx := 0; idx < length; idx++ {
  583. key := buff.ReadString()
  584. val := buff.ReadString()
  585. annotations[key] = val
  586. }
  587. p.SetAnnotations(annotations)
  588. }
  589. // ServiceProp
  590. if buff.ReadUInt8() == 1 { // read nil byte
  591. length := buff.ReadInt() // read map len
  592. services := make([]string, length)
  593. for idx := 0; idx < length; idx++ {
  594. val := buff.ReadString()
  595. services[idx] = val
  596. }
  597. p.SetServices(services)
  598. }
  599. return nil
  600. }