queryresult.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. package source
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/opencost/opencost/core/pkg/log"
  6. "github.com/opencost/opencost/core/pkg/util"
  7. )
  8. // QueryResultsChan is a channel of query results
  9. type QueryResultsChan chan *QueryResults
  10. // Await returns query results, blocking until they are made available, and
  11. // deferring the closure of the underlying channel
  12. func (qrc QueryResultsChan) Await() ([]*QueryResult, error) {
  13. defer close(qrc)
  14. results := <-qrc
  15. if results.Error != nil {
  16. return nil, results.Error
  17. }
  18. return results.Results, nil
  19. }
  20. // ResultKeys is a "configuration" struct that contains the keys/labels used to resolve labeled query
  21. // results. ResultKeys can be defined with every QueryResults instance if necessary, and alter the keys
  22. // used to fetch results when calling the following methods on QueryResults:
  23. //
  24. // GetCluster()
  25. // GetNamespace()
  26. // GetNode()
  27. // GetInstance()
  28. // GetInstanceType()
  29. // GetContainer()
  30. // GetPod()
  31. // GetProviderID()
  32. // GetDevice()
  33. type ResultKeys struct {
  34. ClusterKey string
  35. NamespaceKey string
  36. NodeKey string
  37. InstanceKey string
  38. InstanceTypeKey string
  39. ContainerKey string
  40. PodKey string
  41. ProviderIDKey string
  42. DeviceKey string
  43. }
  44. // DefaultResultKeys returns a new ResultKeys instance with typical default values.
  45. func DefaultResultKeys() *ResultKeys {
  46. return &ResultKeys{
  47. ClusterKey: ClusterIDLabel,
  48. NamespaceKey: NamespaceLabel,
  49. NodeKey: NodeLabel,
  50. InstanceKey: InstanceLabel,
  51. InstanceTypeKey: InstanceTypeLabel,
  52. ContainerKey: ContainerLabel,
  53. PodKey: PodLabel,
  54. ProviderIDKey: ProviderIDLabel,
  55. DeviceKey: DeviceLabel,
  56. }
  57. }
  58. // ClusterKeyWithDefaults returns a new ResultKeys instance with the provided cluster key and the
  59. // rest of the keys set to their default values.
  60. func ClusterKeyWithDefaults(clusterKey string) *ResultKeys {
  61. keys := DefaultResultKeys()
  62. keys.ClusterKey = clusterKey
  63. return keys
  64. }
  65. // QueryResults contains all of the query results and the source query string.
  66. type QueryResults struct {
  67. Query string
  68. Error error
  69. Results []*QueryResult
  70. }
  71. func NewQueryResults(query string) *QueryResults {
  72. return &QueryResults{
  73. Query: query,
  74. }
  75. }
  76. // QueryResult contains a single result from a prometheus query. It's common
  77. // to refer to query results as a slice of QueryResult
  78. type QueryResult struct {
  79. Metric map[string]interface{} `json:"metric"`
  80. Values []*util.Vector `json:"values"`
  81. keys *ResultKeys
  82. }
  83. func NewQueryResult(metrics map[string]any, values []*util.Vector, keys *ResultKeys) *QueryResult {
  84. if keys == nil {
  85. keys = DefaultResultKeys()
  86. }
  87. return &QueryResult{
  88. Metric: metrics,
  89. Values: values,
  90. keys: keys,
  91. }
  92. }
  93. func (qr *QueryResult) GetCluster() (string, error) {
  94. return qr.GetString(qr.keys.ClusterKey)
  95. }
  96. func (qr *QueryResult) GetNamespace() (string, error) {
  97. return qr.GetString(qr.keys.NamespaceKey)
  98. }
  99. func (qr *QueryResult) GetNode() (string, error) {
  100. return qr.GetString(qr.keys.NodeKey)
  101. }
  102. func (qr *QueryResult) GetInstance() (string, error) {
  103. return qr.GetString(qr.keys.InstanceKey)
  104. }
  105. func (qr *QueryResult) GetInstanceType() (string, error) {
  106. return qr.GetString(qr.keys.InstanceTypeKey)
  107. }
  108. func (qr *QueryResult) GetContainer() (string, error) {
  109. value, err := qr.GetString(qr.keys.ContainerKey)
  110. if value == "" || err != nil {
  111. alternate, e := qr.GetString(qr.keys.ContainerKey + "_name")
  112. if alternate == "" || e != nil {
  113. return "", fmt.Errorf("'%s' and '%s' fields do not exist in data result vector", qr.keys.ContainerKey, qr.keys.ContainerKey+"_name")
  114. }
  115. return alternate, nil
  116. }
  117. return value, nil
  118. }
  119. func (qr *QueryResult) GetPod() (string, error) {
  120. value, err := qr.GetString(qr.keys.PodKey)
  121. if value == "" || err != nil {
  122. alternate, e := qr.GetString(qr.keys.PodKey + "_name")
  123. if alternate == "" || e != nil {
  124. return "", fmt.Errorf("'%s' and '%s' fields do not exist in data result vector", qr.keys.PodKey, qr.keys.PodKey+"_name")
  125. }
  126. return alternate, nil
  127. }
  128. return value, nil
  129. }
  130. func (qr *QueryResult) GetProviderID() (string, error) {
  131. return qr.GetString(qr.keys.ProviderIDKey)
  132. }
  133. func (qr *QueryResult) GetDevice() (string, error) {
  134. return qr.GetString(qr.keys.DeviceKey)
  135. }
  136. // GetString returns the requested field, or an error if it does not exist
  137. func (qr *QueryResult) GetString(field string) (string, error) {
  138. f, ok := qr.Metric[field]
  139. if !ok {
  140. return "", fmt.Errorf("'%s' field does not exist in data result vector", field)
  141. }
  142. strField, ok := f.(string)
  143. if !ok {
  144. return "", fmt.Errorf("'%s' field is improperly formatted and cannot be converted to string", field)
  145. }
  146. return strField, nil
  147. }
  148. // GetStrings returns the requested fields, or an error if it does not exist
  149. func (qr *QueryResult) GetStrings(fields ...string) (map[string]string, error) {
  150. values := map[string]string{}
  151. for _, field := range fields {
  152. f, ok := qr.Metric[field]
  153. if !ok {
  154. return nil, fmt.Errorf("'%s' field does not exist in data result vector", field)
  155. }
  156. value, ok := f.(string)
  157. if !ok {
  158. return nil, fmt.Errorf("'%s' field is improperly formatted and cannot be converted to string", field)
  159. }
  160. values[field] = value
  161. }
  162. return values, nil
  163. }
  164. // GetLabels returns all labels and their values from the query result
  165. func (qr *QueryResult) GetLabels() map[string]string {
  166. result := make(map[string]string)
  167. // Find All keys with prefix label_, remove prefix, add to labels
  168. for k, v := range qr.Metric {
  169. if !strings.HasPrefix(k, "label_") {
  170. continue
  171. }
  172. label := strings.TrimPrefix(k, "label_")
  173. value, ok := v.(string)
  174. if !ok {
  175. log.Warnf("Failed to parse label value for label: '%s'", label)
  176. continue
  177. }
  178. result[label] = value
  179. }
  180. return result
  181. }
  182. // GetAnnotations returns all annotations and their values from the query result
  183. func (qr *QueryResult) GetAnnotations() map[string]string {
  184. result := make(map[string]string)
  185. // Find All keys with prefix annotation_, remove prefix, add to annotations
  186. for k, v := range qr.Metric {
  187. if !strings.HasPrefix(k, "annotation_") {
  188. continue
  189. }
  190. annotations := strings.TrimPrefix(k, "annotation_")
  191. value, ok := v.(string)
  192. if !ok {
  193. log.Warnf("Failed to parse label value for label: '%s'", annotations)
  194. continue
  195. }
  196. result[annotations] = value
  197. }
  198. return result
  199. }