Make datastore generic to support Consul/Cassandra 77/37277/5
authorShashank Kumar Shankar <shashank.kumar.shankar@intel.com>
Tue, 20 Mar 2018 23:48:05 +0000 (16:48 -0700)
committerShashank Kumar Shankar <shashank.kumar.shankar@intel.com>
Thu, 22 Mar 2018 23:42:43 +0000 (16:42 -0700)
This patch makes the backend datastore to be generic so that the
backend datastore can be either Consul or Cassandra. This way,
MUSIC's core functionality can be used and makes other minor fixes.

Change-Id: Iba4eaa751fe60a293d6f2fd60ad06a8c4be1dd1e
Issue-ID: MUSIC-55
Signed-off-by: Shashank Kumar Shankar <shashank.kumar.shankar@intel.com>
15 files changed:
README.rst [moved from README.md with 100% similarity]
deployment/docker-entrypoint.sh
deployment/run.sh
deployment/setup-dependency.sh [deleted file]
src/dkv/api/backendCassandraDatastore.go [new file with mode: 0644]
src/dkv/api/backendConsulDatastore.go [moved from src/dkv/api/backendConsulConnection.go with 61% similarity]
src/dkv/api/backendDatastoreConnection.go [new file with mode: 0644]
src/dkv/api/backendFilesystemConnection.go
src/dkv/api/backendPropertiesConnection.go
src/dkv/api/backendfakes.go
src/dkv/api/configHandlers_test.go
src/dkv/api/initialise.go
src/dkv/api/initialise_test.go
src/dkv/api/queryDatastoreHandlers.go [moved from src/dkv/api/queryConsulHandlers.go with 95% similarity]
src/dkv/api/queryDatastoreHandlers_test.go [moved from src/dkv/api/queryConsulHandlers_test.go with 80% similarity]

similarity index 100%
rename from README.md
rename to README.rst
index 62cf23b..bc442b4 100755 (executable)
@@ -9,8 +9,10 @@ function start_api_server {
     ./dkv
 }
 
-if [ "$CONSUL_IP" = "localhost" ]; then
-    start_consul_server
-    sleep 5
+if [ "$DATASTORE_IP" = "localhost" ]; then
+    if  [ "$DATASTORE" = "consul" ]; then
+        start_consul_server
+        sleep 5
+    fi
 fi
 start_api_server
index 1be2ef2..996b70e 100755 (executable)
@@ -1,10 +1,12 @@
 #!/bin/bash
 
-CONSUL_IP="localhost"
+DATASTORE="consul"
+DATASTORE_IP="localhost"
+
 MOUNTPATH="/dkv_mount_path/configs/"
 DEFAULT_CONFIGS=$(pwd)/../mountpath/default # TODO(sshank): Change this to think from Kubernetes Volumes perspective.
 
-docker run -e CONSUL_IP=$CONSUL_IP -e MOUNTPATH=$MOUNTPATH -it \
+docker run -e DATASTORE=$DATASTORE -e DATASTORE_IP=$DATASTORE_IP -e MOUNTPATH=$MOUNTPATH -it \
            --name dkv \
            -v $DEFAULT_CONFIGS:/dkv_mount_path/configs/default \
            -p 8200:8200 -p 8080:8080 nexus3.onap.org:10003/onap/music/distributed-kv-store
diff --git a/deployment/setup-dependency.sh b/deployment/setup-dependency.sh
deleted file mode 100755 (executable)
index f1ca4c2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-function create_mountpath {
-    cp -r mountpath/ /configs
-}
-
-create_mountpath
diff --git a/src/dkv/api/backendCassandraDatastore.go b/src/dkv/api/backendCassandraDatastore.go
new file mode 100644 (file)
index 0000000..555ad0f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package api
+
+// (TODO)sahank: Complete MUSIC Cassandra Connections.
+
+type CassandraStruct struct{}
+
+func (c *CassandraStruct) InitializeDatastoreClient() error {
+       return nil
+}
+
+func (c *CassandraStruct) CheckDatastoreHealth() error {
+       return nil
+}
+
+func (c *CassandraStruct) RequestPUT(key string, value string) error {
+       return nil
+}
+
+func (c *CassandraStruct) RequestGET(key string) (string, error) {
+       return "", nil
+}
+
+func (c *CassandraStruct) RequestGETS() ([]string, error) {
+       return []string{"", ""}, nil
+}
+
+func (c *CassandraStruct) RequestDELETE(key string) error {
+       return nil
+}
similarity index 61%
rename from src/dkv/api/backendConsulConnection.go
rename to src/dkv/api/backendConsulDatastore.go
index 9c2f8d6..231980c 100644 (file)
@@ -22,38 +22,16 @@ import (
        "os"
 )
 
-// Interface to have all signature methods.
-type ConsulRequester interface {
-       InitializeConsulClient() error
-       CheckConsulHealth() error
-       RequestPUT(string, string) error
-       RequestGET(string) (string, error)
-       RequestGETS() ([]string, error)
-       RequestDELETE(string) error
-}
-
 type ConsulStruct struct {
        consulClient *consulapi.Client
 }
 
-/*
-This var is an interface used to initialize ConsulStruct when the who API is brought up. This is done this way so
-that a fake Consul can be created which satisfies the interface and we can use that fake Consul in unit testing.
-*/
-var Consul ConsulRequester
-
-/*
-The following functions seems like they are not used. But since they are following the ConsulRequest interface,
-they can be visible to any Struct which is initiated using the ConsulRequest. This is done for this project in
-the initialise.go file where we are creating a ConsulStruct and assigning it to Consul var which is declared
-above.
-*/
-func (c *ConsulStruct) InitializeConsulClient() error {
-       if os.Getenv("CONSUL_IP") == "" {
-               return errors.New("CONSUL_IP environment variable not set.")
+func (c *ConsulStruct) InitializeDatastoreClient() error {
+       if os.Getenv("DATASTORE_IP") == "" {
+               return errors.New("DATASTORE_IP environment variable not set.")
        }
        config := consulapi.DefaultConfig()
-       config.Address = os.Getenv("CONSUL_IP") + ":8500"
+       config.Address = os.Getenv("DATASTORE_IP") + ":8500"
 
        client, err := consulapi.NewClient(config)
        if err != nil {
@@ -64,11 +42,11 @@ func (c *ConsulStruct) InitializeConsulClient() error {
        return nil
 }
 
-func (c *ConsulStruct) CheckConsulHealth() error {
+func (c *ConsulStruct) CheckDatastoreHealth() error {
        kv := c.consulClient.KV()
        _, _, err := kv.Get("test", nil)
        if err != nil {
-               return errors.New("[ERROR] Cannot talk to Consul. Check if it is running/reachable.")
+               return errors.New("[ERROR] Cannot talk to Datastore. Check if it is running/reachable.")
        }
        return nil
 }
diff --git a/src/dkv/api/backendDatastoreConnection.go b/src/dkv/api/backendDatastoreConnection.go
new file mode 100644 (file)
index 0000000..ebfcc4b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package api
+
+// Interface to have Data Store signature methods.
+type DatastoreConnector interface {
+       InitializeDatastoreClient() error
+       CheckDatastoreHealth() error
+       RequestPUT(string, string) error
+       RequestGET(string) (string, error)
+       RequestGETS() ([]string, error)
+       RequestDELETE(string) error
+}
index e6c37ab..519022c 100644 (file)
@@ -49,8 +49,6 @@ const (
 
 var MOUNTPATH = ""
 
-var Directory DirectoryOperationer
-
 func (d *DirectoryStruct) CreateService(body CreateRegisterServiceBody) (string, error) {
 
        // Having same name is prohibited?
index d485b40..df9683b 100644 (file)
@@ -34,8 +34,6 @@ type KeyValuesInterface interface {
 
 type KeyValuesStruct struct{}
 
-var KeyValues KeyValuesInterface
-
 func (kvStruct *KeyValuesStruct) WriteKVsToConsul(token string, subdomain string, kvs map[string]string) error {
        var prefix = ""
        if subdomain != "" {
@@ -45,7 +43,7 @@ func (kvStruct *KeyValuesStruct) WriteKVsToConsul(token string, subdomain string
        }
        for key, value := range kvs {
                key = prefix + key
-               err := Consul.RequestPUT(key, value)
+               err := Datastore.RequestPUT(key, value)
                if err != nil {
                        return err
                }
index c5ca39a..8c8b8a9 100644 (file)
@@ -31,6 +31,14 @@ type FakeConsul struct {
        ConsulStruct
 }
 
+func (f *FakeConsul) InitializeDatastoreClient() error {
+       return nil
+}
+
+func (f *FakeConsul) CheckDatastoreHealth() error {
+       return nil
+}
+
 func (f *FakeConsul) RequestGETS() ([]string, error) {
        return []string{"key1", "key2"}, nil
 }
@@ -52,6 +60,14 @@ type FakeConsulErr struct {
        ConsulStruct
 }
 
+func (f *FakeConsulErr) InitializeDatastoreClient() error {
+       return errors.New("Internal Server Error")
+}
+
+func (f *FakeConsulErr) CheckDatastoreHealth() error {
+       return errors.New("Internal Server Error")
+}
+
 func (f *FakeConsulErr) RequestGETS() ([]string, error) {
        return []string{"", ""}, errors.New("Internal Server Error")
 }
index e2f796a..bb11eb1 100644 (file)
@@ -75,14 +75,14 @@ func TestHandleConfigDelete_err(t *testing.T) {
 }
 
 func TestHandleConfigPOST(t *testing.T) {
-       oldConsul := Consul
+       oldDatastore := Datastore
        oldKeyValues := KeyValues
 
-       Consul = &FakeConsul{}
+       Datastore = &FakeConsul{}
        KeyValues = &FakeKeyValues{}
 
        defer func() {
-               Consul = oldConsul
+               Datastore = oldDatastore
                KeyValues = oldKeyValues
        }()
 
@@ -104,14 +104,14 @@ func TestHandleConfigPOST(t *testing.T) {
 }
 
 func TestHandleConfigPOST_only_token(t *testing.T) {
-       oldConsul := Consul
+       oldDatastore := Datastore
        oldKeyValues := KeyValues
 
-       Consul = &FakeConsul{}
+       Datastore = &FakeConsul{}
        KeyValues = &FakeKeyValues{}
 
        defer func() {
-               Consul = oldConsul
+               Datastore = oldDatastore
                KeyValues = oldKeyValues
        }()
 
@@ -133,14 +133,14 @@ func TestHandleConfigPOST_only_token(t *testing.T) {
 }
 
 func TestHandleConfigPOST_no_body(t *testing.T) {
-       oldConsul := Consul
+       oldDatastore := Datastore
        oldKeyValues := KeyValues
 
-       Consul = &FakeConsul{}
+       Datastore = &FakeConsul{}
        KeyValues = &FakeKeyValues{}
 
        defer func() {
-               Consul = oldConsul
+               Datastore = oldDatastore
                KeyValues = oldKeyValues
        }()
 
@@ -156,14 +156,14 @@ func TestHandleConfigPOST_no_body(t *testing.T) {
 }
 
 func TestHandleConfigPOST_ConsulError(t *testing.T) {
-       oldConsul := Consul
+       oldDatastore := Datastore
        oldKeyValues := KeyValues
 
-       Consul = &FakeConsulErr{}
+       Datastore = &FakeConsulErr{}
        KeyValues = &FakeKeyValuesErr{}
 
        defer func() {
-               Consul = oldConsul
+               Datastore = oldDatastore
                KeyValues = oldKeyValues
        }()
 
@@ -196,14 +196,14 @@ func TestHandleConfigUpload_err(t *testing.T) {
 }
 
 func TestHandleDefaultConfigLoad(t *testing.T) {
-       oldConsul := Consul
+       oldDatastore := Datastore
        oldKeyValues := KeyValues
 
-       Consul = &FakeConsul{}
+       Datastore = &FakeConsul{}
        KeyValues = &FakeKeyValues{}
 
        defer func() {
-               Consul = oldConsul
+               Datastore = oldDatastore
                KeyValues = oldKeyValues
        }()
 
@@ -215,14 +215,14 @@ func TestHandleDefaultConfigLoad(t *testing.T) {
 }
 
 func TestHandleDefaultConfigLoad_err(t *testing.T) {
-       oldConsul := Consul
+       oldDatastore := Datastore
        oldKeyValues := KeyValues
 
-       Consul = &FakeConsul{}
+       Datastore = &FakeConsul{}
        KeyValues = &FakeKeyValuesErr{}
 
        defer func() {
-               Consul = oldConsul
+               Datastore = oldDatastore
                KeyValues = oldKeyValues
        }()
 
index f4edc6c..20a5df4 100644 (file)
 
 package api
 
-import "os"
+import (
+       "errors"
+       "os"
+)
+
+var (
+       Datastore DatastoreConnector
+       KeyValues KeyValuesInterface
+       Directory DirectoryOperationer
+)
 
 func Initialise() error {
-       Consul = &ConsulStruct{}
+       if os.Getenv("DATASTORE") == "" {
+               return errors.New("DATASTORE environment variable not set.")
+       }
+       if os.Getenv("DATASTORE") == "consul" {
+               Datastore = &ConsulStruct{}
+       } else if os.Getenv("DATASTORE") == "cassandra" {
+               Datastore = &CassandraStruct{}
+       }
        KeyValues = &KeyValuesStruct{}
        Directory = &DirectoryStruct{directory: ""}
 
-       err := Consul.InitializeConsulClient()
+       err := Datastore.InitializeDatastoreClient()
        if err != nil {
                return err
        }
 
-       err = Consul.CheckConsulHealth()
+       err = Datastore.CheckDatastoreHealth()
        if err != nil {
                return err
        }
index 3063201..363edce 100644 (file)
@@ -22,20 +22,41 @@ import (
        "testing"
 )
 
-func TestInitialise_errorIP(t *testing.T) {
-       consul_ip := os.Getenv("CONSUL_IP")
-       os.Unsetenv("CONSUL_IP")
-       defer os.Setenv("CONSUL_IP", consul_ip)
+func TestInitialise_cassandra(t *testing.T) {
+       oldDatastore_ip := os.Getenv("DATASTORE_IP")
+       oldDatastore_type := os.Getenv("DATASTORE")
+
+       os.Setenv("DATASTORE_IP", "localhost")
+       os.Setenv("DATASTORE", "cassandra")
+
+       defer func() {
+               os.Setenv("DATASTORE_IP", oldDatastore_ip)
+               os.Setenv("DATASTORE", oldDatastore_type)
+       }()
+
+       err := Initialise()
+       assert.Nil(t, err)
+}
+func TestInitialise_consulError(t *testing.T) {
+       oldDatastore_ip := os.Getenv("DATASTORE_IP")
+       oldDatastore_type := os.Getenv("DATASTORE")
+
+       os.Setenv("DATASTORE_IP", "localhost")
+       os.Setenv("DATASTORE", "consul")
+
+       defer func() {
+               os.Setenv("DATASTORE_IP", oldDatastore_ip)
+               os.Setenv("DATASTORE", oldDatastore_type)
+       }()
 
        err := Initialise()
        assert.NotNil(t, err)
 }
 
-func TestInitialise_errorConsul(t *testing.T) {
-       // This is done this way cause the Consul interface with Fake Struct will get
-       // overridden with real Struct during runtime.
-       os.Setenv("CONSUL_IP", "test")
-       defer os.Unsetenv("CONSUL_IP")
+func TestInitialise_datastoreEmptyError(t *testing.T) {
+       datastore := os.Getenv("DATASTORE")
+       os.Unsetenv("DATASTORE")
+       defer os.Setenv("DATASTORE", datastore)
 
        err := Initialise()
        assert.NotNil(t, err)
similarity index 95%
rename from src/dkv/api/queryConsulHandlers.go
rename to src/dkv/api/queryDatastoreHandlers.go
index fb63b6d..4197ac0 100644 (file)
@@ -38,7 +38,7 @@ func HandleGET(w http.ResponseWriter, r *http.Request) {
        vars := mux.Vars(r)
        key := vars["token"] + "/" + vars["key"]
 
-       value, err := Consul.RequestGET(key)
+       value, err := Datastore.RequestGET(key)
 
        if err != nil {
                req := ResponseStringStruct{Response: string(err.Error())}
@@ -54,7 +54,7 @@ func HandleGET(w http.ResponseWriter, r *http.Request) {
 
 func HandleGETS(w http.ResponseWriter, r *http.Request) {
 
-       values, err := Consul.RequestGETS()
+       values, err := Datastore.RequestGETS()
 
        if err != nil {
                req := ResponseStringStruct{Response: string(err.Error())}
@@ -72,7 +72,7 @@ func HandleDELETE(w http.ResponseWriter, r *http.Request) {
        vars := mux.Vars(r)
        key := vars["key"]
 
-       err := Consul.RequestDELETE(key)
+       err := Datastore.RequestDELETE(key)
 
        if err != nil {
                req := ResponseStringStruct{Response: string(err.Error())}
similarity index 80%
rename from src/dkv/api/queryConsulHandlers_test.go
rename to src/dkv/api/queryDatastoreHandlers_test.go
index 38f3acd..c6211bc 100644 (file)
@@ -33,9 +33,9 @@ func RouterConsul() *mux.Router {
 }
 
 func TestHandleGETS(t *testing.T) {
-       oldConsul := Consul
-       Consul = &FakeConsul{}
-       defer func() { Consul = oldConsul }()
+       oldDataStore := Datastore
+       Datastore = &FakeConsul{}
+       defer func() { Datastore = oldDataStore }()
 
        request, _ := http.NewRequest("GET", "/v1/getconfigs", nil)
        response := httptest.NewRecorder()
@@ -45,9 +45,9 @@ func TestHandleGETS(t *testing.T) {
 }
 
 func TestHandleGETS_err(t *testing.T) {
-       oldConsul := Consul
-       Consul = &FakeConsulErr{}
-       defer func() { Consul = oldConsul }()
+       oldDataStore := Datastore
+       Datastore = &FakeConsulErr{}
+       defer func() { Datastore = oldDataStore }()
 
        request, _ := http.NewRequest("GET", "/v1/getconfigs", nil)
        response := httptest.NewRecorder()
@@ -57,9 +57,9 @@ func TestHandleGETS_err(t *testing.T) {
 }
 
 func TestHandleGET(t *testing.T) {
-       oldConsul := Consul
-       Consul = &FakeConsul{}
-       defer func() { Consul = oldConsul }()
+       oldDataStore := Datastore
+       Datastore = &FakeConsul{}
+       defer func() { Datastore = oldDataStore }()
 
        request, _ := http.NewRequest("GET", "/v1/getconfig/key1", nil)
        response := httptest.NewRecorder()
@@ -69,9 +69,9 @@ func TestHandleGET(t *testing.T) {
 }
 
 func TestHandleGET_err(t *testing.T) {
-       oldConsul := Consul
-       Consul = &FakeConsulErr{}
-       defer func() { Consul = oldConsul }()
+       oldDataStore := Datastore
+       Datastore = &FakeConsulErr{}
+       defer func() { Datastore = oldDataStore }()
 
        request, _ := http.NewRequest("GET", "/v1/getconfig/key1", nil)
        response := httptest.NewRecorder()
@@ -81,9 +81,9 @@ func TestHandleGET_err(t *testing.T) {
 }
 
 func TestHandleDELETE(t *testing.T) {
-       oldConsul := Consul
-       Consul = &FakeConsul{}
-       defer func() { Consul = oldConsul }()
+       oldDataStore := Datastore
+       Datastore = &FakeConsul{}
+       defer func() { Datastore = oldDataStore }()
 
        request, _ := http.NewRequest("DELETE", "/v1/deleteconfig/key1", nil)
        response := httptest.NewRecorder()
@@ -93,9 +93,9 @@ func TestHandleDELETE(t *testing.T) {
 }
 
 func TestHandleDELETE_err(t *testing.T) {
-       oldConsul := Consul
-       Consul = &FakeConsulErr{}
-       defer func() { Consul = oldConsul }()
+       oldDataStore := Datastore
+       Datastore = &FakeConsulErr{}
+       defer func() { Datastore = oldDataStore }()
 
        request, _ := http.NewRequest("DELETE", "/v1/deleteconfig/key1", nil)
        response := httptest.NewRecorder()