allocationprops.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. package kubecost
  2. import (
  3. "fmt"
  4. "sort"
  5. "strings"
  6. "github.com/kubecost/cost-model/pkg/prom"
  7. )
  8. const (
  9. AllocationNilProp string = ""
  10. AllocationClusterProp string = "cluster"
  11. AllocationNodeProp string = "node"
  12. AllocationContainerProp string = "container"
  13. AllocationControllerProp string = "controller"
  14. AllocationControllerKindProp string = "controllerKind"
  15. AllocationNamespaceProp string = "namespace"
  16. AllocationPodProp string = "pod"
  17. AllocationProviderIDProp string = "providerID"
  18. AllocationServiceProp string = "service"
  19. AllocationLabelProp string = "label"
  20. AllocationAnnotationProp string = "annotation"
  21. AllocationDeploymentProp string = "deployment"
  22. AllocationStatefulSetProp string = "statefulset"
  23. AllocationDaemonSetProp string = "daemonset"
  24. AllocationJobProp string = "job"
  25. AllocationDepartmentProp string = "department"
  26. AllocationEnvironmentProp string = "environment"
  27. AllocationOwnerProp string = "owner"
  28. AllocationProductProp string = "product"
  29. AllocationTeamProp string = "team"
  30. )
  31. func ParseProperty(text string) (string, error) {
  32. switch strings.TrimSpace(strings.ToLower(text)) {
  33. case "cluster":
  34. return AllocationClusterProp, nil
  35. case "node":
  36. return AllocationNodeProp, nil
  37. case "container":
  38. return AllocationContainerProp, nil
  39. case "controller":
  40. return AllocationControllerProp, nil
  41. case "controllerkind":
  42. return AllocationControllerKindProp, nil
  43. case "namespace":
  44. return AllocationNamespaceProp, nil
  45. case "pod":
  46. return AllocationPodProp, nil
  47. case "providerid":
  48. return AllocationProviderIDProp, nil
  49. case "service":
  50. return AllocationServiceProp, nil
  51. case "label":
  52. return AllocationLabelProp, nil
  53. case "annotation":
  54. return AllocationAnnotationProp, nil
  55. case "deployment":
  56. return AllocationDeploymentProp, nil
  57. case "daemonset":
  58. return AllocationDaemonSetProp, nil
  59. case "statefulset":
  60. return AllocationStatefulSetProp, nil
  61. case "job":
  62. return AllocationJobProp, nil
  63. case "department":
  64. return AllocationDepartmentProp, nil
  65. case "environment":
  66. return AllocationEnvironmentProp, nil
  67. case "owner":
  68. return AllocationOwnerProp, nil
  69. case "product":
  70. return AllocationProductProp, nil
  71. case "team":
  72. return AllocationTeamProp, nil
  73. }
  74. if strings.HasPrefix(text, "label:") {
  75. label := prom.SanitizeLabelName(strings.TrimSpace(strings.TrimPrefix(text, "label:")))
  76. return fmt.Sprintf("label:%s", label), nil
  77. }
  78. if strings.HasPrefix(text, "annotation:") {
  79. annotation := prom.SanitizeLabelName(strings.TrimSpace(strings.TrimPrefix(text, "annotation:")))
  80. return fmt.Sprintf("annotation:%s", annotation), nil
  81. }
  82. return AllocationNilProp, fmt.Errorf("invalid allocation property: %s", text)
  83. }
  84. // AllocationProperties describes a set of Kubernetes objects.
  85. type AllocationProperties struct {
  86. Cluster string `json:"cluster,omitempty"`
  87. Node string `json:"node,omitempty"`
  88. Container string `json:"container,omitempty"`
  89. Controller string `json:"controller,omitempty"`
  90. ControllerKind string `json:"controllerKind,omitempty"`
  91. Namespace string `json:"namespace,omitempty"`
  92. Pod string `json:"pod,omitempty"`
  93. Services []string `json:"services,omitempty"`
  94. ProviderID string `json:"providerID,omitempty"`
  95. Labels AllocationLabels `json:"labels,omitempty"`
  96. Annotations AllocationAnnotations `json:"annotations,omitempty"`
  97. }
  98. // AllocationLabels is a schema-free mapping of key/value pairs that can be
  99. // attributed to an Allocation
  100. type AllocationLabels map[string]string
  101. // AllocationAnnotations is a schema-free mapping of key/value pairs that can be
  102. // attributed to an Allocation
  103. type AllocationAnnotations map[string]string
  104. func (p *AllocationProperties) Clone() *AllocationProperties {
  105. if p == nil {
  106. return nil
  107. }
  108. clone := &AllocationProperties{}
  109. clone.Cluster = p.Cluster
  110. clone.Node = p.Node
  111. clone.Container = p.Container
  112. clone.Controller = p.Controller
  113. clone.ControllerKind = p.ControllerKind
  114. clone.Namespace = p.Namespace
  115. clone.Pod = p.Pod
  116. clone.ProviderID = p.ProviderID
  117. var services []string
  118. for _, s := range p.Services {
  119. services = append(services, s)
  120. }
  121. clone.Services = services
  122. labels := make(map[string]string)
  123. for k, v := range p.Labels {
  124. labels[k] = v
  125. }
  126. clone.Labels = labels
  127. annotations := make(map[string]string)
  128. for k, v := range p.Annotations {
  129. annotations[k] = v
  130. }
  131. clone.Annotations = annotations
  132. return clone
  133. }
  134. func (p *AllocationProperties) Equal(that *AllocationProperties) bool {
  135. if p == nil || that == nil {
  136. return false
  137. }
  138. if p.Cluster != that.Cluster {
  139. return false
  140. }
  141. if p.Node != that.Node {
  142. return false
  143. }
  144. if p.Container != that.Container {
  145. return false
  146. }
  147. if p.Controller != that.Controller {
  148. return false
  149. }
  150. if p.ControllerKind != that.ControllerKind {
  151. return false
  152. }
  153. if p.Namespace != that.Namespace {
  154. return false
  155. }
  156. if p.Pod != that.Pod {
  157. return false
  158. }
  159. if p.ProviderID != that.ProviderID {
  160. return false
  161. }
  162. pLabels := p.Labels
  163. thatLabels := that.Labels
  164. if len(pLabels) == len(thatLabels) {
  165. for k, pv := range pLabels {
  166. tv, ok := thatLabels[k]
  167. if !ok || tv != pv {
  168. return false
  169. }
  170. }
  171. } else {
  172. return false
  173. }
  174. pAnnotations := p.Annotations
  175. thatAnnotations := that.Annotations
  176. if len(pAnnotations) == len(thatAnnotations) {
  177. for k, pv := range pAnnotations {
  178. tv, ok := thatAnnotations[k]
  179. if !ok || tv != pv {
  180. return false
  181. }
  182. }
  183. } else {
  184. return false
  185. }
  186. pServices := p.Services
  187. thatServices := that.Services
  188. if len(pServices) == len(thatServices) {
  189. sort.Strings(pServices)
  190. sort.Strings(thatServices)
  191. for i, pv := range pServices {
  192. tv := thatServices[i]
  193. if tv != pv {
  194. return false
  195. }
  196. }
  197. } else {
  198. return false
  199. }
  200. return true
  201. }
  202. // Intersection returns an *AllocationProperties which contains all matching fields between the calling and parameter AllocationProperties
  203. // nillable slices and maps are left as nil
  204. func (p *AllocationProperties) Intersection(that *AllocationProperties) *AllocationProperties {
  205. if p == nil || that == nil {
  206. return nil
  207. }
  208. intersectionProps := &AllocationProperties{}
  209. if p.Cluster == that.Cluster {
  210. intersectionProps.Cluster = p.Cluster
  211. }
  212. if p.Node == that.Node {
  213. intersectionProps.Node = p.Node
  214. }
  215. if p.Container == that.Container {
  216. intersectionProps.Container = p.Container
  217. }
  218. if p.Controller == that.Controller {
  219. intersectionProps.Controller = p.Controller
  220. }
  221. if p.ControllerKind == that.ControllerKind {
  222. intersectionProps.ControllerKind = p.ControllerKind
  223. }
  224. if p.Namespace == that.Namespace {
  225. intersectionProps.Namespace = p.Namespace
  226. }
  227. if p.Pod == that.Pod {
  228. intersectionProps.Pod = p.Pod
  229. }
  230. if p.ProviderID == that.ProviderID {
  231. intersectionProps.ProviderID = p.ProviderID
  232. }
  233. return intersectionProps
  234. }
  235. func (p *AllocationProperties) String() string {
  236. if p == nil {
  237. return "<nil>"
  238. }
  239. strs := []string{}
  240. if p.Cluster != "" {
  241. strs = append(strs, "Cluster:"+p.Cluster)
  242. }
  243. if p.Node != "" {
  244. strs = append(strs, "Node:"+p.Node)
  245. }
  246. if p.Container != "" {
  247. strs = append(strs, "Container:"+p.Container)
  248. }
  249. if p.Controller != "" {
  250. strs = append(strs, "Controller:"+p.Controller)
  251. }
  252. if p.ControllerKind != "" {
  253. strs = append(strs, "ControllerKind:"+p.ControllerKind)
  254. }
  255. if p.Namespace != "" {
  256. strs = append(strs, "Namespace:"+p.Namespace)
  257. }
  258. if p.Pod != "" {
  259. strs = append(strs, "Pod:"+p.Pod)
  260. }
  261. if p.ProviderID != "" {
  262. strs = append(strs, "ProviderID:"+p.ProviderID)
  263. }
  264. if len(p.Services) > 0 {
  265. strs = append(strs, "Services:"+strings.Join(p.Services, ";"))
  266. }
  267. var labelStrs []string
  268. for k, prop := range p.Labels {
  269. labelStrs = append(labelStrs, fmt.Sprintf("%s:%s", k, prop))
  270. }
  271. strs = append(strs, fmt.Sprintf("Labels:{%s}", strings.Join(strs, ",")))
  272. var AnnotationStrs []string
  273. for k, prop := range p.Annotations {
  274. AnnotationStrs = append(AnnotationStrs, fmt.Sprintf("%s:%s", k, prop))
  275. }
  276. strs = append(strs, fmt.Sprintf("Annotations:{%s}", strings.Join(strs, ",")))
  277. return fmt.Sprintf("{%s}", strings.Join(strs, "; "))
  278. }