| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- package allocation
- import (
- "fmt"
- "strings"
- "github.com/opencost/opencost/core/pkg/autocomplete"
- coreallocation "github.com/opencost/opencost/core/pkg/autocomplete/allocation"
- "github.com/opencost/opencost/core/pkg/opencost"
- )
- func QueryAllocationAutocompleteFromSetRange(asr *opencost.AllocationSetRange, req autocomplete.Request) (*autocomplete.Response, error) {
- field, err := autocomplete.NormalizeRequest(&req, coreallocation.ValidateField, autocomplete.NormalizeOptions{
- EnsureLabelConfig: true,
- })
- if err != nil {
- return nil, err
- }
- var matcher opencost.AllocationMatcher
- if req.Filter != nil {
- compiler := opencost.NewAllocationMatchCompiler(req.LabelConfig)
- matcher, err = compiler.Compile(req.Filter)
- if err != nil {
- return nil, fmt.Errorf("%w: failed to compile filter: %w", autocomplete.ErrBadRequest, err)
- }
- }
- search := strings.ToLower(req.Search)
- results := map[string]struct{}{}
- for _, as := range asr.Allocations {
- if as == nil {
- continue
- }
- for _, alloc := range as.Allocations {
- if alloc == nil || alloc.Properties == nil {
- continue
- }
- if matcher != nil && !matcher.Matches(alloc) {
- continue
- }
- values := allocationAutocompleteValues(alloc.Properties, field)
- for _, value := range values {
- if value == "" {
- continue
- }
- if search != "" && !strings.Contains(strings.ToLower(value), search) {
- continue
- }
- results[value] = struct{}{}
- }
- }
- }
- return &autocomplete.Response{Data: autocomplete.UniqueSortedLimited(results, req.Limit)}, nil
- }
- func allocationAutocompleteValues(props *opencost.AllocationProperties, field string) []string {
- switch {
- case field == "account":
- return nil
- case field == "cluster":
- return []string{props.Cluster}
- case field == "namespace":
- return []string{props.Namespace}
- case field == "node":
- return []string{props.Node}
- case field == "controllerkind":
- return []string{props.ControllerKind}
- case field == "controllername":
- return []string{props.Controller}
- case field == "pod":
- return []string{props.Pod}
- case field == "container":
- return []string{props.Container}
- case field == "label":
- return mapKeys(props.Labels)
- case strings.HasPrefix(field, "label:"):
- label := strings.TrimPrefix(field, "label:")
- if v, ok := autocomplete.MapValueFold(props.Labels, label); ok {
- return []string{v}
- }
- case field == "namespacelabel":
- return mapKeys(props.NamespaceLabels)
- case strings.HasPrefix(field, "namespacelabel:"):
- label := strings.TrimPrefix(field, "namespacelabel:")
- if v, ok := autocomplete.MapValueFold(props.NamespaceLabels, label); ok {
- return []string{v}
- }
- }
- return nil
- }
- func mapKeys(values map[string]string) []string {
- result := make([]string, 0, len(values))
- for k := range values {
- result = append(result, k)
- }
- return result
- }
|