key.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. package costmodel
  2. import (
  3. "fmt"
  4. "github.com/opencost/opencost/core/pkg/opencost"
  5. "github.com/opencost/opencost/core/pkg/source"
  6. "github.com/opencost/opencost/pkg/env"
  7. )
  8. func newResultPodKey(cluster string, namespace string, pod string) (podKey, error) {
  9. if cluster == "" {
  10. cluster = env.GetClusterID()
  11. }
  12. if namespace == "" {
  13. return podKey{}, fmt.Errorf("namespace is required")
  14. }
  15. if pod == "" {
  16. return podKey{}, fmt.Errorf("pod is required")
  17. }
  18. return newPodKey(cluster, namespace, pod), nil
  19. }
  20. type podKey struct {
  21. namespaceKey
  22. Pod string
  23. }
  24. func (k podKey) String() string {
  25. return fmt.Sprintf("%s/%s/%s", k.Cluster, k.Namespace, k.Pod)
  26. }
  27. func newPodKey(cluster, namespace, pod string) podKey {
  28. return podKey{
  29. namespaceKey: namespaceKey{
  30. Cluster: cluster,
  31. Namespace: namespace,
  32. },
  33. Pod: pod,
  34. }
  35. }
  36. // getUnmountedPodKey while certain Unmounted costs can have a namespace, all unmounted costs for a single cluster will be represented by the same asset
  37. func getUnmountedPodKey(cluster string) podKey {
  38. return newPodKey(cluster, opencost.UnmountedSuffix, opencost.UnmountedSuffix)
  39. }
  40. // resultPodKey converts a Prometheus query result to a podKey by looking
  41. // up values associated with the given label names. For example, passing
  42. // "cluster_id" for clusterLabel will use the value of the label "cluster_id"
  43. // as the podKey's Cluster field. If a given field does not exist on the
  44. // result, an error is returned. (The only exception to that is clusterLabel,
  45. // which we expect may not exist, but has a default value.)
  46. func resultPodKey(res *source.QueryResult) (podKey, error) {
  47. key := podKey{}
  48. cluster, err := res.GetCluster()
  49. if err != nil {
  50. cluster = env.GetClusterID()
  51. }
  52. key.Cluster = cluster
  53. namespace, err := res.GetNamespace()
  54. if err != nil {
  55. return key, err
  56. }
  57. key.Namespace = namespace
  58. pod, err := res.GetPod()
  59. if err != nil {
  60. return key, err
  61. }
  62. key.Pod = pod
  63. return key, nil
  64. }
  65. type namespaceKey struct {
  66. Cluster string
  67. Namespace string
  68. }
  69. func (k namespaceKey) String() string {
  70. return fmt.Sprintf("%s/%s", k.Cluster, k.Namespace)
  71. }
  72. func newNamespaceKey(cluster, namespace string) namespaceKey {
  73. return namespaceKey{
  74. Cluster: cluster,
  75. Namespace: namespace,
  76. }
  77. }
  78. // resultNamespaceKey converts a Prometheus query result to a namespaceKey by
  79. // looking up values associated with the given label names. For example,
  80. // passing "cluster_id" for clusterLabel will use the value of the label
  81. // "cluster_id" as the namespaceKey's Cluster field. If a given field does not
  82. // exist on the result, an error is returned. (The only exception to that is
  83. // clusterLabel, which we expect may not exist, but has a default value.)
  84. func resultNamespaceKey(res *source.QueryResult) (namespaceKey, error) {
  85. key := namespaceKey{}
  86. cluster, err := res.GetCluster()
  87. if err != nil {
  88. cluster = env.GetClusterID()
  89. }
  90. key.Cluster = cluster
  91. namespace, err := res.GetNamespace()
  92. if err != nil {
  93. return key, err
  94. }
  95. key.Namespace = namespace
  96. return key, nil
  97. }
  98. func newResultNamespaceKey(cluster string, namespace string) (namespaceKey, error) {
  99. if cluster == "" {
  100. cluster = env.GetClusterID()
  101. }
  102. if namespace == "" {
  103. return namespaceKey{}, fmt.Errorf("namespace is required")
  104. }
  105. return newNamespaceKey(cluster, namespace), nil
  106. }
  107. type controllerKey struct {
  108. Cluster string
  109. Namespace string
  110. ControllerKind string
  111. Controller string
  112. }
  113. func (k controllerKey) String() string {
  114. return fmt.Sprintf("%s/%s/%s/%s", k.Cluster, k.Namespace, k.ControllerKind, k.Controller)
  115. }
  116. func newControllerKey(cluster, namespace, controllerKind, controller string) controllerKey {
  117. return controllerKey{
  118. Cluster: cluster,
  119. Namespace: namespace,
  120. ControllerKind: controllerKind,
  121. Controller: controller,
  122. }
  123. }
  124. func newResultControllerKey(cluster, namespace, controller, controllerKind string) (controllerKey, error) {
  125. if cluster == "" {
  126. cluster = env.GetClusterID()
  127. }
  128. if namespace == "" {
  129. return controllerKey{}, fmt.Errorf("namespace is required")
  130. }
  131. if controller == "" {
  132. return controllerKey{}, fmt.Errorf("controller is required")
  133. }
  134. return newControllerKey(cluster, namespace, controllerKind, controller), nil
  135. }
  136. type serviceKey struct {
  137. Cluster string
  138. Namespace string
  139. Service string
  140. }
  141. func (k serviceKey) String() string {
  142. return fmt.Sprintf("%s/%s/%s", k.Cluster, k.Namespace, k.Service)
  143. }
  144. func newServiceKey(cluster, namespace, service string) serviceKey {
  145. return serviceKey{
  146. Cluster: cluster,
  147. Namespace: namespace,
  148. Service: service,
  149. }
  150. }
  151. // resultServiceKey converts a Prometheus query result to a serviceKey by
  152. // looking up values associated with the given label names. For example,
  153. // passing "cluster_id" for clusterLabel will use the value of the label
  154. // "cluster_id" as the serviceKey's Cluster field. If a given field does not
  155. // exist on the result, an error is returned. (The only exception to that is
  156. // clusterLabel, which we expect may not exist, but has a default value.)
  157. func resultServiceKey(res *source.QueryResult, serviceLabel string) (serviceKey, error) {
  158. key := serviceKey{}
  159. cluster, err := res.GetCluster()
  160. if err != nil {
  161. cluster = env.GetClusterID()
  162. }
  163. key.Cluster = cluster
  164. namespace, err := res.GetNamespace()
  165. if err != nil {
  166. return key, err
  167. }
  168. key.Namespace = namespace
  169. service, err := res.GetString(serviceLabel)
  170. if err != nil {
  171. return key, err
  172. }
  173. key.Service = service
  174. return key, nil
  175. }
  176. func newResultServiceKey(cluster, namespace, service string) (serviceKey, error) {
  177. if cluster == "" {
  178. cluster = env.GetClusterID()
  179. }
  180. if namespace == "" {
  181. return serviceKey{}, fmt.Errorf("namespace is required")
  182. }
  183. if service == "" {
  184. return serviceKey{}, fmt.Errorf("service is required")
  185. }
  186. return newServiceKey(cluster, namespace, service), nil
  187. }
  188. type nodeKey struct {
  189. Cluster string
  190. Node string
  191. }
  192. func (k nodeKey) String() string {
  193. return fmt.Sprintf("%s/%s", k.Cluster, k.Node)
  194. }
  195. func newNodeKey(cluster, node string) nodeKey {
  196. return nodeKey{
  197. Cluster: cluster,
  198. Node: node,
  199. }
  200. }
  201. // resultNodeKey converts a Prometheus query result to a nodeKey by
  202. // looking up values associated with the given label names. For example,
  203. // passing "cluster_id" for clusterLabel will use the value of the label
  204. // "cluster_id" as the nodeKey's Cluster field. If a given field does not
  205. // exist on the result, an error is returned. (The only exception to that is
  206. // clusterLabel, which we expect may not exist, but has a default value.)
  207. func resultNodeKey(res *source.QueryResult) (nodeKey, error) {
  208. key := nodeKey{}
  209. cluster, err := res.GetCluster()
  210. if err != nil {
  211. cluster = env.GetClusterID()
  212. }
  213. key.Cluster = cluster
  214. node, err := res.GetNode()
  215. if err != nil {
  216. return key, err
  217. }
  218. key.Node = node
  219. return key, nil
  220. }
  221. func newResultNodeKey(cluster string, node string) (nodeKey, error) {
  222. if cluster == "" {
  223. cluster = env.GetClusterID()
  224. }
  225. if node == "" {
  226. return nodeKey{}, fmt.Errorf("node is required")
  227. }
  228. return newNodeKey(cluster, node), nil
  229. }
  230. type pvcKey struct {
  231. Cluster string
  232. Namespace string
  233. PersistentVolumeClaim string
  234. }
  235. func (k pvcKey) String() string {
  236. return fmt.Sprintf("%s/%s/%s", k.Cluster, k.Namespace, k.PersistentVolumeClaim)
  237. }
  238. func newPVCKey(cluster, namespace, persistentVolumeClaim string) pvcKey {
  239. return pvcKey{
  240. Cluster: cluster,
  241. Namespace: namespace,
  242. PersistentVolumeClaim: persistentVolumeClaim,
  243. }
  244. }
  245. // resultPVCKey converts a Prometheus query result to a pvcKey by
  246. // looking up values associated with the given label names. For example,
  247. // passing "cluster_id" for clusterLabel will use the value of the label
  248. // "cluster_id" as the pvcKey's Cluster field. If a given field does not
  249. // exist on the result, an error is returned. (The only exception to that is
  250. // clusterLabel, which we expect may not exist, but has a default value.)
  251. func resultPVCKey(res *source.QueryResult, pvcLabel string) (pvcKey, error) {
  252. key := pvcKey{}
  253. cluster, err := res.GetCluster()
  254. if err != nil {
  255. cluster = env.GetClusterID()
  256. }
  257. key.Cluster = cluster
  258. namespace, err := res.GetNamespace()
  259. if err != nil {
  260. return key, err
  261. }
  262. key.Namespace = namespace
  263. pvc, err := res.GetString(pvcLabel)
  264. if err != nil {
  265. return key, err
  266. }
  267. key.PersistentVolumeClaim = pvc
  268. return key, nil
  269. }
  270. // resultPVCKey converts a Prometheus query result to a pvcKey by
  271. // looking up values associated with the given label names. For example,
  272. // passing "cluster_id" for clusterLabel will use the value of the label
  273. // "cluster_id" as the pvcKey's Cluster field. If a given field does not
  274. // exist on the result, an error is returned. (The only exception to that is
  275. // clusterLabel, which we expect may not exist, but has a default value.)
  276. func newResultPVCKey(cluster, namespace, pvc string) (pvcKey, error) {
  277. if cluster == "" {
  278. cluster = env.GetClusterID()
  279. }
  280. if namespace == "" {
  281. return pvcKey{}, fmt.Errorf("namespace is required")
  282. }
  283. if pvc == "" {
  284. return pvcKey{}, fmt.Errorf("persistentvolumeclaim is required")
  285. }
  286. return newPVCKey(cluster, namespace, pvc), nil
  287. }
  288. type pvKey struct {
  289. Cluster string
  290. PersistentVolume string
  291. }
  292. func (k pvKey) String() string {
  293. return fmt.Sprintf("%s/%s", k.Cluster, k.PersistentVolume)
  294. }
  295. func newPVKey(cluster, persistentVolume string) pvKey {
  296. return pvKey{
  297. Cluster: cluster,
  298. PersistentVolume: persistentVolume,
  299. }
  300. }
  301. // resultPVKey converts a Prometheus query result to a pvKey by
  302. // looking up values associated with the given label names. For example,
  303. // passing "cluster_id" for clusterLabel will use the value of the label
  304. // "cluster_id" as the pvKey's Cluster field. If a given field does not
  305. // exist on the result, an error is returned. (The only exception to that is
  306. // clusterLabel, which we expect may not exist, but has a default value.)
  307. func resultPVKey(res *source.QueryResult, persistentVolumeLabel string) (pvKey, error) {
  308. key := pvKey{}
  309. cluster, err := res.GetCluster()
  310. if err != nil {
  311. cluster = env.GetClusterID()
  312. }
  313. key.Cluster = cluster
  314. persistentVolume, err := res.GetString(persistentVolumeLabel)
  315. if err != nil {
  316. return key, err
  317. }
  318. key.PersistentVolume = persistentVolume
  319. return key, nil
  320. }
  321. func newResultPVKey(cluster, pv string) (pvKey, error) {
  322. if cluster == "" {
  323. cluster = env.GetClusterID()
  324. }
  325. if pv == "" {
  326. return pvKey{}, fmt.Errorf("persistentvolume is required")
  327. }
  328. return newPVKey(cluster, pv), nil
  329. }