github.com/Iqoqo/consul@v1.4.5/command/intention/finder/finder.go (about)

     1  package finder
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"sync"
     7  
     8  	"github.com/hashicorp/consul/api"
     9  )
    10  
    11  // Finder finds intentions by a src/dst exact match. There is currently
    12  // no direct API to do this so this struct downloads all intentions and
    13  // caches them once, and searches in-memory for this. For now this works since
    14  // even with a very large number of intentions, the size of the data gzipped
    15  // over HTTP will be relatively small.
    16  //
    17  // The Finder will only download the intentions one time. This struct is
    18  // not expected to be used over a long period of time. Though it may be
    19  // reused multile times, the intentions list is only downloaded once.
    20  type Finder struct {
    21  	// Client is the API client to use for any requests.
    22  	Client *api.Client
    23  
    24  	lock sync.Mutex
    25  	ixns []*api.Intention // cached list of intentions
    26  }
    27  
    28  // ID returns the intention ID for the given CLI args. An error is returned
    29  // if args is not 1 or 2 elements.
    30  func (f *Finder) IDFromArgs(args []string) (string, error) {
    31  	switch len(args) {
    32  	case 1:
    33  		return args[0], nil
    34  
    35  	case 2:
    36  		ixn, err := f.Find(args[0], args[1])
    37  		if err != nil {
    38  			return "", err
    39  		}
    40  		if ixn == nil {
    41  			return "", fmt.Errorf(
    42  				"Intention with source %q and destination %q not found.",
    43  				args[0], args[1])
    44  		}
    45  
    46  		return ixn.ID, nil
    47  
    48  	default:
    49  		return "", fmt.Errorf("command requires exactly 1 or 2 arguments")
    50  	}
    51  }
    52  
    53  // Find finds the intention that matches the given src and dst. This will
    54  // return nil when the result is not found.
    55  func (f *Finder) Find(src, dst string) (*api.Intention, error) {
    56  	src = StripDefaultNS(src)
    57  	dst = StripDefaultNS(dst)
    58  
    59  	f.lock.Lock()
    60  	defer f.lock.Unlock()
    61  
    62  	// If the list of ixns is nil, then we haven't fetched yet, so fetch
    63  	if f.ixns == nil {
    64  		ixns, _, err := f.Client.Connect().Intentions(nil)
    65  		if err != nil {
    66  			return nil, err
    67  		}
    68  
    69  		f.ixns = ixns
    70  	}
    71  
    72  	// Go through the intentions and find an exact match
    73  	for _, ixn := range f.ixns {
    74  		if ixn.SourceString() == src && ixn.DestinationString() == dst {
    75  			return ixn, nil
    76  		}
    77  	}
    78  
    79  	return nil, nil
    80  }
    81  
    82  // StripDefaultNS strips the default namespace from an argument. For now,
    83  // the API and lookups strip this value from string output so we strip it.
    84  func StripDefaultNS(v string) string {
    85  	if idx := strings.IndexByte(v, '/'); idx > 0 {
    86  		if v[:idx] == api.IntentionDefaultNamespace {
    87  			return v[:idx+1]
    88  		}
    89  	}
    90  
    91  	return v
    92  }