github.hscsec.cn/hashicorp/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 }