github.com/splunk/dan1-qbec@v0.7.3/internal/commands/remote-list.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  	"sort"
    21  	"time"
    22  
    23  	"github.com/splunk/qbec/internal/model"
    24  	"github.com/splunk/qbec/internal/remote"
    25  	"github.com/splunk/qbec/internal/sio"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  )
    28  
    29  type listClient interface {
    30  	IsNamespaced(gvk schema.GroupVersionKind) (bool, error)
    31  	ListObjects(scope remote.ListQueryConfig) (remote.Collection, error)
    32  }
    33  
    34  type lister interface {
    35  	start(config remote.ListQueryConfig)
    36  	deletions(ignore []model.K8sLocalObject, filter func(obj model.K8sQbecMeta) bool) ([]model.K8sQbecMeta, error)
    37  }
    38  
    39  type stubLister struct{}
    40  
    41  func (s *stubLister) start(config remote.ListQueryConfig) {}
    42  func (s *stubLister) deletions(ignore []model.K8sLocalObject, filter func(obj model.K8sQbecMeta) bool) ([]model.K8sQbecMeta, error) {
    43  	return nil, nil
    44  }
    45  
    46  type remoteLister struct {
    47  	client       listClient
    48  	ch           chan listResult
    49  	unknownTypes map[schema.GroupVersionKind]bool
    50  	cfg          remote.ListQueryConfig
    51  }
    52  
    53  type listResult struct {
    54  	data     remote.Collection
    55  	duration time.Duration
    56  	err      error
    57  }
    58  
    59  func newRemoteLister(client listClient, allObjects []model.K8sLocalObject, defaultNs string) (*remoteLister, remote.ListQueryScope, error) {
    60  	nsMap := map[string]bool{}
    61  	if defaultNs != "" {
    62  		nsMap[defaultNs] = true
    63  	}
    64  	unknown := map[schema.GroupVersionKind]bool{}
    65  
    66  	clusterObjects := false
    67  	for _, o := range allObjects {
    68  		kind := o.GroupVersionKind()
    69  		b, err := client.IsNamespaced(kind)
    70  		if err != nil {
    71  			if !unknown[kind] {
    72  				sio.Warnf("unable to get metadata for %v, continue\n", o.GroupVersionKind())
    73  				unknown[kind] = true
    74  			}
    75  			continue
    76  		}
    77  		if b {
    78  			ns := o.GetNamespace()
    79  			if ns == "" {
    80  				ns = defaultNs
    81  			}
    82  			nsMap[ns] = true
    83  		} else {
    84  			clusterObjects = true
    85  		}
    86  	}
    87  	var nsList []string
    88  	for k := range nsMap {
    89  		nsList = append(nsList, k)
    90  	}
    91  	sort.Strings(nsList)
    92  
    93  	return &remoteLister{
    94  			client:       client,
    95  			ch:           make(chan listResult, 1),
    96  			unknownTypes: unknown,
    97  		},
    98  		remote.ListQueryScope{
    99  			Namespaces:     nsList,
   100  			ClusterObjects: clusterObjects,
   101  		},
   102  		nil
   103  }
   104  
   105  func (r *remoteLister) start(config remote.ListQueryConfig) {
   106  	r.cfg = config
   107  	go func() {
   108  		start := time.Now()
   109  		list, err := r.client.ListObjects(config)
   110  		r.ch <- listResult{data: list, err: err, duration: time.Since(start).Round(time.Millisecond)}
   111  	}()
   112  }
   113  
   114  func (r *remoteLister) deletions(all []model.K8sLocalObject, filter func(obj model.K8sQbecMeta) bool) ([]model.K8sQbecMeta, error) {
   115  	if len(r.ch) == 0 {
   116  		sio.Debugln("waiting for deletion list to be returned")
   117  	}
   118  	lr := <-r.ch
   119  	if lr.err != nil {
   120  		return nil, lr.err
   121  	}
   122  	sio.Debugf("server objects load took %v\n", lr.duration)
   123  
   124  	cfg := r.cfg
   125  	if cfg.KindFilter == nil {
   126  		f, _ := model.NewKindFilter(nil, nil)
   127  		cfg.KindFilter = f
   128  	}
   129  
   130  	var removals []model.K8sQbecMeta
   131  	for _, c := range all {
   132  		if r.unknownTypes[c.GroupVersionKind()] {
   133  			continue
   134  		}
   135  		if !cfg.KindFilter.ShouldInclude(c.GetKind()) {
   136  			continue
   137  		}
   138  		removals = append(removals, c)
   139  	}
   140  
   141  	coll := lr.data
   142  	if err := coll.Remove(removals); err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	retained := coll.ToList()
   147  	var ret []model.K8sQbecMeta
   148  	for _, o := range retained {
   149  		if filter(o) {
   150  			ret = append(ret, o)
   151  		}
   152  	}
   153  
   154  	return ret, nil
   155  }