1package dependency 2 3import ( 4 "io/ioutil" 5 "log" 6 "os" 7 "strings" 8 "time" 9 10 "github.com/pkg/errors" 11) 12 13var ( 14 // Ensure implements 15 _ Dependency = (*VaultAgentTokenQuery)(nil) 16) 17 18const ( 19 // VaultAgentTokenSleepTime is the amount of time to sleep between queries, since 20 // the fsnotify library is not compatible with solaris and other OSes yet. 21 VaultAgentTokenSleepTime = 15 * time.Second 22) 23 24// VaultAgentTokenQuery is the dependency to Vault Agent token 25type VaultAgentTokenQuery struct { 26 stopCh chan struct{} 27 path string 28 stat os.FileInfo 29} 30 31// NewVaultAgentTokenQuery creates a new dependency. 32func NewVaultAgentTokenQuery(path string) (*VaultAgentTokenQuery, error) { 33 return &VaultAgentTokenQuery{ 34 stopCh: make(chan struct{}, 1), 35 path: path, 36 }, nil 37} 38 39// Fetch retrieves this dependency and returns the result or any errors that 40// occur in the process. 41func (d *VaultAgentTokenQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) { 42 log.Printf("[TRACE] %s: READ %s", d, d.path) 43 44 select { 45 case <-d.stopCh: 46 log.Printf("[TRACE] %s: stopped", d) 47 return "", nil, ErrStopped 48 case r := <-d.watch(d.stat): 49 if r.err != nil { 50 return "", nil, errors.Wrap(r.err, d.String()) 51 } 52 53 log.Printf("[TRACE] %s: reported change", d) 54 55 token, err := ioutil.ReadFile(d.path) 56 if err != nil { 57 return "", nil, errors.Wrap(err, d.String()) 58 } 59 60 d.stat = r.stat 61 clients.Vault().SetToken(strings.TrimSpace(string(token))) 62 } 63 64 return respWithMetadata("") 65} 66 67// CanShare returns if this dependency is sharable. 68func (d *VaultAgentTokenQuery) CanShare() bool { 69 return false 70} 71 72// Stop halts the dependency's fetch function. 73func (d *VaultAgentTokenQuery) Stop() { 74 close(d.stopCh) 75} 76 77// String returns the human-friendly version of this dependency. 78func (d *VaultAgentTokenQuery) String() string { 79 return "vault-agent.token" 80} 81 82// Type returns the type of this dependency. 83func (d *VaultAgentTokenQuery) Type() Type { 84 return TypeVault 85} 86 87// watch watches the file for changes 88func (d *VaultAgentTokenQuery) watch(lastStat os.FileInfo) <-chan *watchResult { 89 ch := make(chan *watchResult, 1) 90 91 go func(lastStat os.FileInfo) { 92 for { 93 stat, err := os.Stat(d.path) 94 if err != nil { 95 select { 96 case <-d.stopCh: 97 return 98 case ch <- &watchResult{err: err}: 99 return 100 } 101 } 102 103 changed := lastStat == nil || 104 lastStat.Size() != stat.Size() || 105 lastStat.ModTime() != stat.ModTime() 106 107 if changed { 108 select { 109 case <-d.stopCh: 110 return 111 case ch <- &watchResult{stat: stat}: 112 return 113 } 114 } 115 116 time.Sleep(VaultAgentTokenSleepTime) 117 } 118 }(lastStat) 119 120 return ch 121} 122