github.com/splunk/dan1-qbec@v0.7.3/internal/commands/filter.go (about)

     1  /*
     2     Copyright 2019 Splunk Inc.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package commands
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/spf13/cobra"
    23  	"github.com/splunk/qbec/internal/eval"
    24  	"github.com/splunk/qbec/internal/model"
    25  	"github.com/splunk/qbec/internal/sio"
    26  )
    27  
    28  type filterParams struct {
    29  	includes        []string
    30  	excludes        []string
    31  	kindFilter      model.Filter
    32  	componentFilter model.Filter
    33  }
    34  
    35  func (f filterParams) Includes(o model.K8sQbecMeta) bool {
    36  	if !(f.kindFilter == nil || f.kindFilter.ShouldInclude(o.GetKind())) {
    37  		return false
    38  	}
    39  	if !(f.componentFilter == nil || f.componentFilter.ShouldInclude(o.Component())) {
    40  		return false
    41  	}
    42  	return true
    43  }
    44  
    45  func addFilterParams(cmd *cobra.Command, includeKindFilters bool) func() (filterParams, error) {
    46  	var includes, excludes, kindIncludes, kindExcludes []string
    47  
    48  	cmd.Flags().StringArrayVarP(&includes, "component", "c", nil, "include just this component")
    49  	cmd.Flags().StringArrayVarP(&excludes, "exclude-component", "C", nil, "exclude this component")
    50  	if includeKindFilters {
    51  		cmd.Flags().StringArrayVarP(&kindIncludes, "kind", "k", nil, "include objects with this kind")
    52  		cmd.Flags().StringArrayVarP(&kindExcludes, "exclude-kind", "K", nil, "exclude objects with this kind")
    53  	}
    54  	return func() (filterParams, error) {
    55  		of, err := model.NewKindFilter(kindIncludes, kindExcludes)
    56  		if err != nil {
    57  			return filterParams{}, newUsageError(err.Error())
    58  		}
    59  		cf, err := model.NewComponentFilter(includes, excludes)
    60  		if err != nil {
    61  			return filterParams{}, newUsageError(err.Error())
    62  		}
    63  		return filterParams{
    64  			includes:        includes,
    65  			excludes:        excludes,
    66  			kindFilter:      of,
    67  			componentFilter: cf,
    68  		}, nil
    69  	}
    70  }
    71  
    72  // keyFunc is a function that provides a string key for an object
    73  type keyFunc func(object model.K8sMeta) string
    74  
    75  func allObjects(cfg *Config, env string) ([]model.K8sLocalObject, error) {
    76  	return filteredObjects(cfg, env, nil, filterParams{kindFilter: nil})
    77  }
    78  
    79  func displayName(obj model.K8sLocalObject) string {
    80  	group := obj.GroupVersionKind().Group
    81  	if group != "" {
    82  		group += "/"
    83  	}
    84  	ns := obj.GetNamespace()
    85  	if ns != "" {
    86  		ns += "/"
    87  	}
    88  	return fmt.Sprintf("%s%s %s%s (component: %s)", group, obj.GetKind(), ns, obj.GetName(), obj.Component())
    89  }
    90  
    91  func checkDuplicates(objects []model.K8sLocalObject, kf keyFunc) error {
    92  	if kf == nil {
    93  		return nil
    94  	}
    95  	objectsByKey := map[string]model.K8sLocalObject{}
    96  	for _, o := range objects {
    97  		if o.GetName() == "" { // generated name
    98  			continue
    99  		}
   100  		key := kf(o)
   101  		if prev, ok := objectsByKey[key]; ok {
   102  			return fmt.Errorf("duplicate objects %s and %s", displayName(prev), displayName(o))
   103  		}
   104  		objectsByKey[key] = o
   105  	}
   106  	return nil
   107  }
   108  
   109  func filteredObjects(cfg *Config, env string, kf keyFunc, fp filterParams) ([]model.K8sLocalObject, error) {
   110  	components, err := cfg.App().ComponentsForEnvironment(env, fp.includes, fp.excludes)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	output, err := eval.Components(components, cfg.EvalContext(env))
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	if err := checkDuplicates(output, kf); err != nil {
   119  		return nil, err
   120  	}
   121  	of := fp.kindFilter
   122  	if of == nil || !of.HasFilters() {
   123  		return output, nil
   124  	}
   125  	var ret []model.K8sLocalObject
   126  	for _, o := range output {
   127  		if of.ShouldInclude(o.GetKind()) {
   128  			ret = append(ret, o)
   129  		}
   130  	}
   131  	if len(output) > 0 && len(ret) == 0 {
   132  		sio.Warnf("0 of %d matches for kind filter, check for typos and abbreviations\n", len(output))
   133  	}
   134  	return ret, nil
   135  }