@@ -65,11 +65,19 @@ func newEtcdClient() *clientv3.Client {
6565
6666func NewKeystore () keystoreregistry.Keystore {
6767 cli := newEtcdClient ()
68- return & etcKeystore {cli }
68+ return & etcKeystore {
69+ Watcher : cli .Watcher ,
70+ KV : cli .KV ,
71+ Lease : cli .Lease ,
72+ Client : cli ,
73+ }
6974}
7075
7176type etcKeystore struct {
72- * clientv3.Client
77+ Watcher clientv3.Watcher
78+ KV clientv3.KV
79+ Lease clientv3.Lease
80+ Client * clientv3.Client
7381}
7482
7583func (client * etcKeystore ) NewMutex (lockKey string ) (keystoreregistry.Mutex , error ) {
@@ -97,6 +105,10 @@ func handleError(err error) {
97105 }
98106}
99107
108+ func (client * etcKeystore ) Close () error {
109+ return client .Client .Close ()
110+ }
111+
100112func (client * etcKeystore ) runTransaction (ifOps []clientv3.Cmp , thenOps []clientv3.Op ) error {
101113 kvc := clientv3 .NewKV (client .Client )
102114 kvc .Txn (context .Background ())
@@ -195,7 +207,7 @@ func (client *etcKeystore) Get(key string) (keystoreregistry.KeyValueVersion, er
195207
196208func (client * etcKeystore ) WatchPrefix (prefix string ,
197209 onUpdate func (old * keystoreregistry.KeyValueVersion , new * keystoreregistry.KeyValueVersion )) {
198- rch := client .Watch (context .Background (), prefix , clientv3 .WithPrefix (), clientv3 .WithPrevKV ())
210+ rch := client .Client . Watch (context .Background (), prefix , clientv3 .WithPrefix (), clientv3 .WithPrevKV ())
199211 go func () {
200212 for wresp := range rch {
201213 for _ , ev := range wresp .Events {
@@ -213,7 +225,7 @@ func (client *etcKeystore) WatchPrefix(prefix string,
213225
214226func (client * etcKeystore ) WatchKey (ctxt context.Context , key string ,
215227 onUpdate func (old * keystoreregistry.KeyValueVersion , new * keystoreregistry.KeyValueVersion )) {
216- rch := client .Watch (ctxt , key , clientv3 .WithPrevKV ())
228+ rch := client .Client . Watch (ctxt , key , clientv3 .WithPrevKV ())
217229 go func () {
218230 for watchResponse := range rch {
219231 for _ , ev := range watchResponse .Events {
@@ -232,6 +244,66 @@ func (client *etcKeystore) WatchKey(ctxt context.Context, key string,
232244 }()
233245}
234246
247+ // TODO: this needs fixing up
248+ func (client * etcKeystore ) WatchForCondition (ctxt context.Context , key string , fromRevision int64 ,
249+ check func (update keystoreregistry.KeyValueUpdate ) bool ) (bool , error ) {
250+
251+ // check key is present and find revision of the last update
252+ initialValue , err := client .Get (key )
253+ if err != nil {
254+ return false , err
255+ }
256+ if fromRevision < initialValue .CreateRevision {
257+ return false , errors .New ("incorrect fromRevision" )
258+ }
259+
260+ // no deadline set, so add default timeout of 10 mins
261+ var cancelFunc context.CancelFunc
262+ _ , ok := ctxt .Deadline ()
263+ if ! ok {
264+ ctxt , cancelFunc = context .WithTimeout (ctxt , time .Minute * 10 )
265+ }
266+
267+ // open channel with etcd, starting with the last revision of the key from above
268+ rch := client .Client .Watch (ctxt , key , clientv3 .WithPrefix (), clientv3 .WithRev (fromRevision ))
269+ if rch == nil {
270+ cancelFunc ()
271+ return false , errors .New ("no watcher returned from etcd" )
272+ }
273+
274+ conditionMet := false
275+ go func () {
276+ for watchResponse := range rch {
277+ // TODO: this should instead use Watch from above!
278+ for _ , ev := range watchResponse .Events {
279+ update := keystoreregistry.KeyValueUpdate {
280+ New : getKeyValueVersion (ev .Kv ),
281+ Old : getKeyValueVersion (ev .PrevKv ),
282+ }
283+
284+ // show deleted by returning nil for new
285+ isKeyDeleted := false
286+ if ev .Type == clientv3 .EventTypeDelete {
287+ update .New = nil
288+ isKeyDeleted = true
289+ }
290+
291+ conditionMet := check (update )
292+
293+ // stop watching if the condition passed or key was deleted
294+ if conditionMet || isKeyDeleted {
295+ cancelFunc ()
296+ return
297+ }
298+ }
299+ }
300+ // Assuming we get here when the context is cancelled or hits its timeout
301+ // i.e. there are no more events, so we close the channel
302+ }()
303+
304+ return conditionMet , nil
305+ }
306+
235307func (client * etcKeystore ) KeepAliveKey (key string ) error {
236308 kvc := clientv3 .NewKV (client .Client )
237309
@@ -243,7 +315,7 @@ func (client *etcKeystore) KeepAliveKey(key string) error {
243315
244316 // TODO what about configure timeout and ttl?
245317 var ttl int64 = 10
246- grantResponse , err := client .Grant (context .Background (), ttl )
318+ grantResponse , err := client .Client . Grant (context .Background (), ttl )
247319 if err != nil {
248320 log .Fatal (err )
249321 }
@@ -258,7 +330,7 @@ func (client *etcKeystore) KeepAliveKey(key string) error {
258330 return fmt .Errorf ("unable to create keep-alive key: %s" , key )
259331 }
260332
261- ch , err := client .KeepAlive (context .Background (), leaseID )
333+ ch , err := client .Client . KeepAlive (context .Background (), leaseID )
262334 if err != nil {
263335 log .Fatal (err )
264336 }
0 commit comments