[VOL-5481] - Implement KeyExists API in kv-store

Change-Id: I2ea7196d538596afb6c8bd57af1103df64c83132
Signed-off-by: Sridhar Ravindra <sridhar.ravindra@radisys.com>
diff --git a/VERSION b/VERSION
index ceddb88..3c0381a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.6.8
+7.6.9
diff --git a/pkg/db/backend.go b/pkg/db/backend.go
index bb99970..8c31295 100644
--- a/pkg/db/backend.go
+++ b/pkg/db/backend.go
@@ -179,6 +179,21 @@
 	return alive
 }
 
+// KeyExists checks if the specified key exists in kv-store or not
+func (b *Backend) KeyExists(ctx context.Context, key string) (bool, error) {
+	span, ctx := log.CreateChildSpan(ctx, "kvs-key-exists")
+	defer span.Finish()
+
+	formattedPath := b.makePath(ctx, key)
+	logger.Debugw(ctx, "checking-key-exists", log.Fields{"key": key, "path": formattedPath})
+
+	keyExists, err := b.Client.KeyExists(ctx, formattedPath)
+
+	b.updateLiveness(ctx, b.isErrorIndicatingAliveKvstore(err))
+
+	return keyExists, err
+}
+
 // List retrieves one or more items that match the specified key
 func (b *Backend) List(ctx context.Context, key string) (map[string]*kvstore.KVPair, error) {
 	span, ctx := log.CreateChildSpan(ctx, "kvs-list")
diff --git a/pkg/db/kvstore/client.go b/pkg/db/kvstore/client.go
index 85bc5f5..c84eacf 100644
--- a/pkg/db/kvstore/client.go
+++ b/pkg/db/kvstore/client.go
@@ -75,6 +75,7 @@
 // Client represents the set of APIs a KV Client must implement
 type Client interface {
 	List(ctx context.Context, key string) (map[string]*KVPair, error)
+	KeyExists(ctx context.Context, key string) (bool, error)
 	Get(ctx context.Context, key string) (*KVPair, error)
 	GetWithPrefix(ctx context.Context, prefixKey string) (map[string]*KVPair, error)
 	GetWithPrefixKeysOnly(ctx context.Context, prefixKey string) ([]string, error)
diff --git a/pkg/db/kvstore/etcdclient.go b/pkg/db/kvstore/etcdclient.go
index c5df1d8..d15bb6e 100644
--- a/pkg/db/kvstore/etcdclient.go
+++ b/pkg/db/kvstore/etcdclient.go
@@ -101,6 +101,25 @@
 	return true
 }
 
+// KeyExists returns boolean value based on the existence of the key in kv-store. Timeout defines how long the function will
+// wait for a response
+func (c *EtcdClient) KeyExists(ctx context.Context, key string) (bool, error) {
+	client, err := c.pool.Get(ctx)
+	if err != nil {
+		return false, err
+	}
+	defer c.pool.Put(client)
+	resp, err := client.Get(ctx, key, v3Client.WithKeysOnly(), v3Client.WithCountOnly())
+	if err != nil {
+		logger.Error(ctx, err)
+		return false, err
+	}
+	if resp.Count > 0 {
+		return true, nil
+	}
+	return false, nil
+}
+
 // List returns an array of key-value pairs with key as a prefix.  Timeout defines how long the function will
 // wait for a response
 func (c *EtcdClient) List(ctx context.Context, key string) (map[string]*KVPair, error) {
diff --git a/pkg/db/kvstore/redisclient.go b/pkg/db/kvstore/redisclient.go
index 7ed4159..3a7e512 100644
--- a/pkg/db/kvstore/redisclient.go
+++ b/pkg/db/kvstore/redisclient.go
@@ -120,6 +120,19 @@
 	return allkeys, nil
 }
 
+func (c *RedisClient) KeyExists(ctx context.Context, key string) (bool, error) {
+	var err error
+	var keyCount int64
+
+	if keyCount, err = c.redisAPI.Exists(ctx, key).Result(); err != nil {
+		return false, err
+	}
+	if keyCount > 0 {
+		return true, nil
+	}
+	return false, nil
+}
+
 func (c *RedisClient) List(ctx context.Context, key string) (map[string]*KVPair, error) {
 	var err error
 	var keys []string
diff --git a/pkg/ponresourcemanager/ponresourcemanager_test.go b/pkg/ponresourcemanager/ponresourcemanager_test.go
index 626864e..7d9c85d 100644
--- a/pkg/ponresourcemanager/ponresourcemanager_test.go
+++ b/pkg/ponresourcemanager/ponresourcemanager_test.go
@@ -54,6 +54,11 @@
 	return nil, errors.New("key didn't find")
 }
 
+// List function implemented for KVClient.
+func (kvclient *MockResKVClient) KeyExists(ctx context.Context, key string) (bool, error) {
+	return false, errors.New("key didn't find")
+}
+
 // Get mock function implementation for KVClient
 func (kvclient *MockResKVClient) Get(ctx context.Context, key string) (*kvstore.KVPair, error) {
 	logger.Debugw(ctx, "Get of MockKVClient called", log.Fields{"key": key})