aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKiran Kamineni <kiran.k.kamineni@intel.com>2019-03-15 15:03:01 -0700
committerKiran Kamineni <kiran.k.kamineni@intel.com>2019-03-25 14:41:34 -0700
commit037cfda2181e4995e4e2a47db6f1121b532b686b (patch)
treef9cb838fc5cc037c01a9f55f561c3b5621236667
parent8cdd50b6a06aef5cb0541e74a07b10bd4b01b589 (diff)
Add support for composite keys
Composite keys help us store objects which are unique for a given set of pre-existing objects. Eg: Many profiles can exist for a definition and its key will have a definition name as a part of the composite key. P2: Use a predefined interface for keys instead of generic interfaceP{} P3: Add check for empty strings in stringer interface P5: Add appropriate keys in other packages. Issue-ID: MULTICLOUD-531 Change-Id: I314b1fbd718489ae8a45f0f38915c08ca32f9f43 Signed-off-by: Kiran Kamineni <kiran.k.kamineni@intel.com>
-rw-r--r--src/k8splugin/api/handler.go16
-rw-r--r--src/k8splugin/internal/db/consul.go37
-rw-r--r--src/k8splugin/internal/db/consul_test.go42
-rw-r--r--src/k8splugin/internal/db/mongo.go27
-rw-r--r--src/k8splugin/internal/db/mongo_test.go191
-rw-r--r--src/k8splugin/internal/db/store.go15
-rw-r--r--src/k8splugin/internal/db/testing.go18
-rw-r--r--src/k8splugin/internal/rb/definition.go24
-rw-r--r--src/k8splugin/internal/rb/profile.go24
9 files changed, 236 insertions, 158 deletions
diff --git a/src/k8splugin/api/handler.go b/src/k8splugin/api/handler.go
index 4d6abe27..b1cc6709 100644
--- a/src/k8splugin/api/handler.go
+++ b/src/k8splugin/api/handler.go
@@ -35,6 +35,14 @@ import (
var storeName = "rbinst"
var tagData = "data"
+type instanceKey struct {
+ Key string
+}
+
+func (dk instanceKey) String() string {
+ return dk.Key
+}
+
// GetVNFClient retrieves the client used to communicate with a Kubernetes Cluster
var GetVNFClient = func(kubeConfigPath string) (kubernetes.Clientset, error) {
client, err := helper.GetKubeClient(kubeConfigPath)
@@ -130,7 +138,7 @@ func CreateHandler(w http.ResponseWriter, r *http.Request) {
// key: cloud1-default-uuid
// value: "{"deployment":<>,"service":<>}"
- err = db.DBconn.Create(storeName, internalVNFID, tagData, resourceNameMap)
+ err = db.DBconn.Create(storeName, instanceKey{Key: internalVNFID}, tagData, resourceNameMap)
if err != nil {
werr := pkgerrors.Wrap(err, "Create VNF deployment DB error")
http.Error(w, werr.Error(), http.StatusInternalServerError)
@@ -202,7 +210,7 @@ func DeleteHandler(w http.ResponseWriter, r *http.Request) {
// key: cloud1-default-uuid
// value: "{"deployment":<>,"service":<>}"
- res, err := db.DBconn.Read(storeName, internalVNFID, tagData)
+ res, err := db.DBconn.Read(storeName, instanceKey{Key: internalVNFID}, tagData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -237,7 +245,7 @@ func DeleteHandler(w http.ResponseWriter, r *http.Request) {
return
}
- err = db.DBconn.Delete(storeName, internalVNFID, tagData)
+ err = db.DBconn.Delete(storeName, instanceKey{Key: internalVNFID}, tagData)
if err != nil {
werr := pkgerrors.Wrap(err, "Delete VNF db record error")
http.Error(w, werr.Error(), http.StatusInternalServerError)
@@ -330,7 +338,7 @@ func GetHandler(w http.ResponseWriter, r *http.Request) {
// key: cloud1-default-uuid
// value: "{"deployment":<>,"service":<>}"
- res, err := db.DBconn.Read(storeName, internalVNFID, tagData)
+ res, err := db.DBconn.Read(storeName, instanceKey{Key: internalVNFID}, tagData)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
diff --git a/src/k8splugin/internal/db/consul.go b/src/k8splugin/internal/db/consul.go
index a61a4c10..23d2ae88 100644
--- a/src/k8splugin/internal/db/consul.go
+++ b/src/k8splugin/internal/db/consul.go
@@ -54,7 +54,7 @@ func NewConsulStore(store ConsulKVStore) (Store, error) {
// HealthCheck verifies if the database is up and running
func (c *ConsulStore) HealthCheck() error {
- _, err := c.Read("test", "test", "test")
+ _, _, err := c.client.Get("test", nil)
if err != nil {
return pkgerrors.New("[ERROR] Cannot talk to Datastore. Check if it is running/reachable.")
}
@@ -67,7 +67,13 @@ func (c *ConsulStore) Unmarshal(inp []byte, out interface{}) error {
}
// Create is used to create a DB entry
-func (c *ConsulStore) Create(root, key, tag string, data interface{}) error {
+func (c *ConsulStore) Create(root string, key Key, tag string, data interface{}) error {
+
+ //Convert to string as Consul only supports string based keys
+ k := key.String()
+ if k == "" {
+ return pkgerrors.New("Key.String() returned an empty string")
+ }
value, err := Serialize(data)
if err != nil {
@@ -75,7 +81,7 @@ func (c *ConsulStore) Create(root, key, tag string, data interface{}) error {
}
p := &api.KVPair{
- Key: key,
+ Key: k,
Value: []byte(value),
}
_, err = c.client.Put(p, nil)
@@ -83,9 +89,16 @@ func (c *ConsulStore) Create(root, key, tag string, data interface{}) error {
}
// Read method returns the internalID for a particular externalID
-func (c *ConsulStore) Read(root, key, tag string) ([]byte, error) {
- key = root + "/" + key + "/" + tag
- pair, _, err := c.client.Get(key, nil)
+func (c *ConsulStore) Read(root string, key Key, tag string) ([]byte, error) {
+
+ //Convert to string as Consul only supports string based keys
+ k := key.String()
+ if k == "" {
+ return nil, pkgerrors.New("Key.String() returned an empty string")
+ }
+
+ k = root + "/" + k + "/" + tag
+ pair, _, err := c.client.Get(k, nil)
if err != nil {
return nil, err
}
@@ -96,13 +109,19 @@ func (c *ConsulStore) Read(root, key, tag string) ([]byte, error) {
}
// Delete method removes an internalID from the Database
-func (c *ConsulStore) Delete(root, key, tag string) error {
- _, err := c.client.Delete(key, nil)
+func (c *ConsulStore) Delete(root string, key Key, tag string) error {
+
+ //Convert to string as Consul only supports string based keys
+ k := key.String()
+ if k == "" {
+ return pkgerrors.New("Key.String() returned an empty string")
+ }
+ _, err := c.client.Delete(k, nil)
return err
}
// ReadAll is used to get all ExternalIDs in a namespace
-func (c *ConsulStore) ReadAll(root, tag string) (map[string][]byte, error) {
+func (c *ConsulStore) ReadAll(root string, tag string) (map[string][]byte, error) {
pairs, _, err := c.client.List(root, nil)
if err != nil {
return nil, err
diff --git a/src/k8splugin/internal/db/consul_test.go b/src/k8splugin/internal/db/consul_test.go
index 754112ad..6d127841 100644
--- a/src/k8splugin/internal/db/consul_test.go
+++ b/src/k8splugin/internal/db/consul_test.go
@@ -102,19 +102,20 @@ func TestConsulCreate(t *testing.T) {
testCases := []struct {
label string
input map[string]string
+ key Key
mock *mockConsulKVStore
expectedError string
}{
{
label: "Sucessful register a record to Consul Database",
- input: map[string]string{"root": "rbinst", "key": "test-key",
- "tag": "data", "value": "test-value"},
- mock: &mockConsulKVStore{},
+ key: mockKey{Key: "test-key"},
+ input: map[string]string{"root": "rbinst", "tag": "data", "value": "test-value"},
+ mock: &mockConsulKVStore{},
},
{
label: "Fail to create a new record in Consul Database",
- input: map[string]string{"root": "rbinst", "key": "test-key",
- "tag": "data", "value": "test-value"},
+ key: mockKey{Key: "test-key"},
+ input: map[string]string{"root": "rbinst", "tag": "data", "value": "test-value"},
mock: &mockConsulKVStore{
Err: pkgerrors.New("DB error"),
},
@@ -125,7 +126,7 @@ func TestConsulCreate(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
client, _ := NewConsulStore(testCase.mock)
- err := client.Create(testCase.input["root"], testCase.input["key"],
+ err := client.Create(testCase.input["root"], testCase.key,
testCase.input["tag"], testCase.input["value"])
if err != nil {
if testCase.expectedError == "" {
@@ -143,14 +144,15 @@ func TestConsulRead(t *testing.T) {
testCases := []struct {
label string
input map[string]string
+ key Key
mock *mockConsulKVStore
expectedError string
expectedResult string
}{
{
label: "Sucessful retrieve a record from Consul Database",
- input: map[string]string{"root": "rbinst", "key": "test",
- "tag": "data"},
+ key: mockKey{Key: "test"},
+ input: map[string]string{"root": "rbinst", "tag": "data"},
mock: &mockConsulKVStore{
Items: api.KVPairs{
&api.KVPair{
@@ -163,14 +165,14 @@ func TestConsulRead(t *testing.T) {
},
{
label: "Fail retrieve a non-existing record from Consul Database",
- input: map[string]string{"root": "rbinst", "key": "test-key",
- "tag": "data"},
- mock: &mockConsulKVStore{},
+ key: mockKey{Key: "test-key"},
+ input: map[string]string{"root": "rbinst", "tag": "data"},
+ mock: &mockConsulKVStore{},
},
{
label: "Fail retrieve a record from Consul Database",
- input: map[string]string{"root": "rbinst", "key": "test-key",
- "tag": "data"},
+ key: mockKey{Key: "test-key"},
+ input: map[string]string{"root": "rbinst", "tag": "data"},
mock: &mockConsulKVStore{
Err: pkgerrors.New("DB error"),
},
@@ -181,7 +183,7 @@ func TestConsulRead(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
client, _ := NewConsulStore(testCase.mock)
- result, err := client.Read(testCase.input["root"], testCase.input["key"],
+ result, err := client.Read(testCase.input["root"], testCase.key,
testCase.input["tag"])
if err != nil {
if testCase.expectedError == "" {
@@ -196,7 +198,7 @@ func TestConsulRead(t *testing.T) {
}
if !reflect.DeepEqual(testCase.expectedResult, string(result)) {
- t.Fatalf("Read method returned: \n%v\n and it was expected: \n%v", result, testCase.expectedResult)
+ t.Fatalf("Read method returned: \n%v\n while expected value was: \n%v", result, testCase.expectedResult)
}
}
})
@@ -207,17 +209,19 @@ func TestConsulDelete(t *testing.T) {
testCases := []struct {
label string
input map[string]string
+ key Key
mock *mockConsulKVStore
expectedError string
}{
{
label: "Sucessful delete a record to Consul Database",
- input: map[string]string{"root": "rbinst", "key": "test-key",
- "tag": "data"},
- mock: &mockConsulKVStore{},
+ key: mockKey{Key: "test-key"},
+ input: map[string]string{"root": "rbinst", "tag": "data"},
+ mock: &mockConsulKVStore{},
},
{
label: "Fail to delete a record in Consul Database",
+ key: mockKey{Key: "test-key"},
mock: &mockConsulKVStore{
Err: pkgerrors.New("DB error"),
},
@@ -228,7 +232,7 @@ func TestConsulDelete(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
client, _ := NewConsulStore(testCase.mock)
- err := client.Delete(testCase.input["root"], testCase.input["key"],
+ err := client.Delete(testCase.input["root"], testCase.key,
testCase.input["tag"])
if err != nil {
if testCase.expectedError == "" {
diff --git a/src/k8splugin/internal/db/mongo.go b/src/k8splugin/internal/db/mongo.go
index d414f543..8c422380 100644
--- a/src/k8splugin/internal/db/mongo.go
+++ b/src/k8splugin/internal/db/mongo.go
@@ -108,10 +108,17 @@ func (m *MongoStore) HealthCheck() error {
}
// validateParams checks to see if any parameters are empty
-func (m *MongoStore) validateParams(args ...string) bool {
+func (m *MongoStore) validateParams(args ...interface{}) bool {
for _, v := range args {
- if v == "" {
- return false
+ val, ok := v.(string)
+ if ok {
+ if val == "" {
+ return false
+ }
+ } else {
+ if v == nil {
+ return false
+ }
}
}
@@ -119,7 +126,7 @@ func (m *MongoStore) validateParams(args ...string) bool {
}
// Create is used to create a DB entry
-func (m *MongoStore) Create(coll, key, tag string, data interface{}) error {
+func (m *MongoStore) Create(coll string, key Key, tag string, data interface{}) error {
if data == nil || !m.validateParams(coll, key, tag) {
return pkgerrors.New("No Data to store")
}
@@ -168,7 +175,7 @@ func (m *MongoStore) Unmarshal(inp []byte, out interface{}) error {
}
// Read method returns the data stored for this key and for this particular tag
-func (m *MongoStore) Read(coll, key, tag string) ([]byte, error) {
+func (m *MongoStore) Read(coll string, key Key, tag string) ([]byte, error) {
if !m.validateParams(coll, key, tag) {
return nil, pkgerrors.New("Mandatory fields are missing")
}
@@ -223,7 +230,7 @@ func (m *MongoStore) deleteObjectByID(coll string, objID primitive.ObjectID) err
// Delete method removes a document from the Database that matches key
// TODO: delete all referenced docs if tag is empty string
-func (m *MongoStore) Delete(coll, key, tag string) error {
+func (m *MongoStore) Delete(coll string, key Key, tag string) error {
if !m.validateParams(coll, key, tag) {
return pkgerrors.New("Mandatory fields are missing")
}
@@ -314,10 +321,10 @@ func (m *MongoStore) ReadAll(coll, tag string) (map[string][]byte, error) {
d := cursor.Current
//Read key of each master table
- key, ok := d.Lookup("key").StringValueOK()
+ key, ok := d.Lookup("key").DocumentOK()
if !ok {
- log.Printf("Unable to read key string from mastertable %s", err.Error())
- continue
+ //Throw error if key is not found
+ pkgerrors.New("Unable to read key from mastertable")
}
//Get objectID of tag document
@@ -333,7 +340,7 @@ func (m *MongoStore) ReadAll(coll, tag string) (map[string][]byte, error) {
log.Printf("Unable to decode tag data %s", err.Error())
continue
}
- result[key] = tagData.Lookup(tag).Value
+ result[key.String()] = tagData.Lookup(tag).Value
}
if len(result) == 0 {
diff --git a/src/k8splugin/internal/db/mongo_test.go b/src/k8splugin/internal/db/mongo_test.go
index 973921c3..deb51044 100644
--- a/src/k8splugin/internal/db/mongo_test.go
+++ b/src/k8splugin/internal/db/mongo_test.go
@@ -84,7 +84,7 @@ func TestCreate(t *testing.T) {
label: "Successfull creation of entry",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "tagName",
"data": "Data In String Format",
},
@@ -95,7 +95,7 @@ func TestCreate(t *testing.T) {
label: "UnSuccessfull creation of entry",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "tagName",
"data": "Data In String Format",
},
@@ -108,7 +108,7 @@ func TestCreate(t *testing.T) {
label: "Missing input fields",
input: map[string]interface{}{
"coll": "",
- "key": "",
+ "key": mockKey{Key: ""},
"tag": "",
"data": "",
},
@@ -129,7 +129,7 @@ func TestCreate(t *testing.T) {
return testCase.bson, testCase.mockColl.Err
}
- err := m.Create(testCase.input["coll"].(string), testCase.input["key"].(string),
+ err := m.Create(testCase.input["coll"].(string), testCase.input["key"].(Key),
testCase.input["tag"].(string), testCase.input["data"])
if err != nil {
if testCase.expectedError == "" {
@@ -156,59 +156,57 @@ func TestRead(t *testing.T) {
label: "Successfull Read of entry",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "metadata",
},
// Binary form of
// {
// "_id" : ObjectId("5c115156777ff85654248ae1"),
- // "key" : "b82c4bb1-09ff-6093-4d58-8327b94e1e20",
+ // "key" : bson.D{{"name","testdef"},{"version","v1"}},
// "metadata" : ObjectId("5c115156c9755047e318bbfd")
// }
bson: bson.Raw{
- '\x5a', '\x00', '\x00', '\x00', '\x07', '\x5f', '\x69', '\x64',
- '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', '\xf8',
- '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x02', '\x6b', '\x65',
- '\x79', '\x00', '\x25', '\x00', '\x00', '\x00', '\x62', '\x38',
- '\x32', '\x63', '\x34', '\x62', '\x62', '\x31', '\x2d', '\x30',
- '\x39', '\x66', '\x66', '\x2d', '\x36', '\x30', '\x39', '\x33',
- '\x2d', '\x34', '\x64', '\x35', '\x38', '\x2d', '\x38', '\x33',
- '\x32', '\x37', '\x62', '\x39', '\x34', '\x65', '\x31', '\x65',
- '\x32', '\x30', '\x00', '\x07', '\x6d', '\x65', '\x74', '\x61',
- '\x64', '\x61', '\x74', '\x61', '\x00', '\x5c', '\x11', '\x51',
- '\x56', '\xc9', '\x75', '\x50', '\x47', '\xe3', '\x18', '\xbb',
- '\xfd', '\x00',
+ '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79',
+ '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61',
+ '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74',
+ '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02',
+ '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00',
+ '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00',
+ '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74',
+ '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f',
+ '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f',
+ '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77',
+ '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00',
},
mockColl: &mockCollection{},
// This is not the document because we are mocking decodeBytes
- expected: []byte{92, 17, 81, 86, 201, 117, 80, 71, 227, 24, 187, 253},
+ expected: []byte{92, 17, 81, 86, 119, 127, 248, 86, 84, 36, 138, 225},
},
{
label: "UnSuccessfull Read of entry: object not found",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "badtag",
},
// Binary form of
// {
// "_id" : ObjectId("5c115156777ff85654248ae1"),
- // "key" : "b82c4bb1-09ff-6093-4d58-8327b94e1e20",
+ // "key" : bson.D{{"name","testdef"},{"version","v1"}},
// "metadata" : ObjectId("5c115156c9755047e318bbfd")
// }
bson: bson.Raw{
- '\x5a', '\x00', '\x00', '\x00', '\x07', '\x5f', '\x69', '\x64',
- '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', '\xf8',
- '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x02', '\x6b', '\x65',
- '\x79', '\x00', '\x25', '\x00', '\x00', '\x00', '\x62', '\x38',
- '\x32', '\x63', '\x34', '\x62', '\x62', '\x31', '\x2d', '\x30',
- '\x39', '\x66', '\x66', '\x2d', '\x36', '\x30', '\x39', '\x33',
- '\x2d', '\x34', '\x64', '\x35', '\x38', '\x2d', '\x38', '\x33',
- '\x32', '\x37', '\x62', '\x39', '\x34', '\x65', '\x31', '\x65',
- '\x32', '\x30', '\x00', '\x07', '\x6d', '\x65', '\x74', '\x61',
- '\x64', '\x61', '\x74', '\x61', '\x00', '\x5c', '\x11', '\x51',
- '\x56', '\xc9', '\x75', '\x50', '\x47', '\xe3', '\x18', '\xbb',
- '\xfd', '\x00',
+ '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79',
+ '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61',
+ '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74',
+ '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02',
+ '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00',
+ '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00',
+ '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74',
+ '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f',
+ '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f',
+ '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77',
+ '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00',
},
mockColl: &mockCollection{},
expectedError: "Error finding objectID",
@@ -217,7 +215,7 @@ func TestRead(t *testing.T) {
label: "UnSuccessfull Read of entry",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "tagName",
},
mockColl: &mockCollection{
@@ -229,7 +227,7 @@ func TestRead(t *testing.T) {
label: "Missing input fields",
input: map[string]interface{}{
"coll": "",
- "key": "",
+ "key": mockKey{Key: ""},
"tag": "",
},
expectedError: "Mandatory fields are missing",
@@ -248,7 +246,7 @@ func TestRead(t *testing.T) {
decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) {
return testCase.bson, testCase.mockColl.Err
}
- got, err := m.Read(testCase.input["coll"].(string), testCase.input["key"].(string),
+ got, err := m.Read(testCase.input["coll"].(string), testCase.input["key"].(Key),
testCase.input["tag"].(string))
if err != nil {
if testCase.expectedError == "" {
@@ -259,7 +257,7 @@ func TestRead(t *testing.T) {
}
} else {
if bytes.Compare(got, testCase.expected) != 0 {
- t.Fatalf("Read returned unexpected data: %s, expected: %s",
+ t.Fatalf("Read returned unexpected data: %v, expected: %v",
string(got), testCase.expected)
}
}
@@ -279,28 +277,27 @@ func TestDelete(t *testing.T) {
label: "Successfull Delete of entry",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "metadata",
},
// Binary form of
// {
// "_id" : ObjectId("5c115156777ff85654248ae1"),
- // "key" : "b82c4bb1-09ff-6093-4d58-8327b94e1e20",
+ // "key" : bson.D{{"name","testdef"},{"version","v1"}},
// "metadata" : ObjectId("5c115156c9755047e318bbfd")
// }
bson: bson.Raw{
- '\x5a', '\x00', '\x00', '\x00', '\x07', '\x5f', '\x69', '\x64',
- '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', '\xf8',
- '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x02', '\x6b', '\x65',
- '\x79', '\x00', '\x25', '\x00', '\x00', '\x00', '\x62', '\x38',
- '\x32', '\x63', '\x34', '\x62', '\x62', '\x31', '\x2d', '\x30',
- '\x39', '\x66', '\x66', '\x2d', '\x36', '\x30', '\x39', '\x33',
- '\x2d', '\x34', '\x64', '\x35', '\x38', '\x2d', '\x38', '\x33',
- '\x32', '\x37', '\x62', '\x39', '\x34', '\x65', '\x31', '\x65',
- '\x32', '\x30', '\x00', '\x07', '\x6d', '\x65', '\x74', '\x61',
- '\x64', '\x61', '\x74', '\x61', '\x00', '\x5c', '\x11', '\x51',
- '\x56', '\xc9', '\x75', '\x50', '\x47', '\xe3', '\x18', '\xbb',
- '\xfd', '\x00',
+ '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79',
+ '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61',
+ '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74',
+ '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02',
+ '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00',
+ '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00',
+ '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74',
+ '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f',
+ '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f',
+ '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77',
+ '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00',
},
mockColl: &mockCollection{},
},
@@ -308,7 +305,7 @@ func TestDelete(t *testing.T) {
label: "UnSuccessfull Delete of entry",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "tagName",
},
mockColl: &mockCollection{
@@ -320,22 +317,27 @@ func TestDelete(t *testing.T) {
label: "UnSuccessfull Delete, key not found",
input: map[string]interface{}{
"coll": "collname",
- "key": "keyvalue",
+ "key": mockKey{Key: "keyvalue"},
"tag": "tagName",
},
+ // Binary form of
+ // {
+ // "_id" : ObjectId("5c115156777ff85654248ae1"),
+ // "key" : bson.D{{"name","testdef"},{"version","v1"}},
+ // "metadata" : ObjectId("5c115156c9755047e318bbfd")
+ // }
bson: bson.Raw{
- '\x5a', '\x00', '\x00', '\x00', '\x07', '\x5f', '\x69', '\x64',
- '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', '\xf8',
- '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x02', '\x6b', '\x65',
- '\x79', '\x00', '\x25', '\x00', '\x00', '\x00', '\x62', '\x38',
- '\x32', '\x63', '\x34', '\x62', '\x62', '\x31', '\x2d', '\x30',
- '\x39', '\x66', '\x66', '\x2d', '\x36', '\x30', '\x39', '\x33',
- '\x2d', '\x34', '\x64', '\x35', '\x38', '\x2d', '\x38', '\x33',
- '\x32', '\x37', '\x62', '\x39', '\x34', '\x65', '\x31', '\x65',
- '\x32', '\x30', '\x00', '\x07', '\x6d', '\x65', '\x74', '\x61',
- '\x64', '\x61', '\x74', '\x61', '\x00', '\x5c', '\x11', '\x51',
- '\x56', '\xc9', '\x75', '\x50', '\x47', '\xe3', '\x18', '\xbb',
- '\xfd', '\x00',
+ '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79',
+ '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61',
+ '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74',
+ '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02',
+ '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00',
+ '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00',
+ '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74',
+ '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f',
+ '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f',
+ '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77',
+ '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00',
},
mockColl: &mockCollection{},
expectedError: "Error finding objectID",
@@ -344,7 +346,7 @@ func TestDelete(t *testing.T) {
label: "Missing input fields",
input: map[string]interface{}{
"coll": "",
- "key": "",
+ "key": mockKey{Key: ""},
"tag": "",
},
expectedError: "Mandatory fields are missing",
@@ -363,7 +365,7 @@ func TestDelete(t *testing.T) {
decodeBytes = func(sr *mongo.SingleResult) (bson.Raw, error) {
return testCase.bson, testCase.mockColl.Err
}
- err := m.Delete(testCase.input["coll"].(string), testCase.input["key"].(string),
+ err := m.Delete(testCase.input["coll"].(string), testCase.input["key"].(Key),
testCase.input["tag"].(string))
if err != nil {
if testCase.expectedError == "" {
@@ -397,29 +399,29 @@ func TestReadAll(t *testing.T) {
// Binary form of
// {
// "_id" : ObjectId("5c115156777ff85654248ae1"),
- // "key" : "b82c4bb1-09ff-6093-4d58-8327b94e1e20",
+ // "key" : bson.D{{"name","testdef"},{"version","v1"}},
// "metadata" : ObjectId("5c115156c9755047e318bbfd")
// }
+
Current: bson.Raw{
- '\x5a', '\x00', '\x00', '\x00', '\x07', '\x5f', '\x69', '\x64',
- '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', '\xf8',
- '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x02', '\x6b', '\x65',
- '\x79', '\x00', '\x25', '\x00', '\x00', '\x00', '\x62', '\x38',
- '\x32', '\x63', '\x34', '\x62', '\x62', '\x31', '\x2d', '\x30',
- '\x39', '\x66', '\x66', '\x2d', '\x36', '\x30', '\x39', '\x33',
- '\x2d', '\x34', '\x64', '\x35', '\x38', '\x2d', '\x38', '\x33',
- '\x32', '\x37', '\x62', '\x39', '\x34', '\x65', '\x31', '\x65',
- '\x32', '\x30', '\x00', '\x07', '\x6d', '\x65', '\x74', '\x61',
- '\x64', '\x61', '\x74', '\x61', '\x00', '\x5c', '\x11', '\x51',
- '\x56', '\xc9', '\x75', '\x50', '\x47', '\xe3', '\x18', '\xbb',
- '\xfd', '\x00',
+ '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79',
+ '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61',
+ '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74',
+ '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02',
+ '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00',
+ '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00',
+ '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74',
+ '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f',
+ '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f',
+ '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77',
+ '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00',
},
},
mCursorCount: 1,
},
expected: map[string][]byte{
- "b82c4bb1-09ff-6093-4d58-8327b94e1e20": []byte{
- 92, 17, 81, 86, 201, 117, 80, 71, 227, 24, 187, 253},
+ `{"name": "testdef","version": "v1"}`: []byte{
+ 92, 17, 81, 86, 119, 127, 248, 86, 84, 36, 138, 225},
},
},
{
@@ -444,22 +446,21 @@ func TestReadAll(t *testing.T) {
// Binary form of
// {
// "_id" : ObjectId("5c115156777ff85654248ae1"),
- // "key" : "b82c4bb1-09ff-6093-4d58-8327b94e1e20",
+ // "key" : bson.D{{"name","testdef"},{"version","v1"}},
// "metadata" : ObjectId("5c115156c9755047e318bbfd")
// }
Current: bson.Raw{
- '\x5a', '\x00', '\x00', '\x00', '\x07', '\x5f', '\x69', '\x64',
- '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f', '\xf8',
- '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x02', '\x6b', '\x65',
- '\x79', '\x00', '\x25', '\x00', '\x00', '\x00', '\x62', '\x38',
- '\x32', '\x63', '\x34', '\x62', '\x62', '\x31', '\x2d', '\x30',
- '\x39', '\x66', '\x66', '\x2d', '\x36', '\x30', '\x39', '\x33',
- '\x2d', '\x34', '\x64', '\x35', '\x38', '\x2d', '\x38', '\x33',
- '\x32', '\x37', '\x62', '\x39', '\x34', '\x65', '\x31', '\x65',
- '\x32', '\x30', '\x00', '\x07', '\x6d', '\x65', '\x74', '\x61',
- '\x64', '\x61', '\x74', '\x61', '\x00', '\x5c', '\x11', '\x51',
- '\x56', '\xc9', '\x75', '\x50', '\x47', '\xe3', '\x18', '\xbb',
- '\xfd', '\x00',
+ '\x58', '\x00', '\x00', '\x00', '\x03', '\x6b', '\x65', '\x79',
+ '\x00', '\x27', '\x00', '\x00', '\x00', '\x02', '\x6e', '\x61',
+ '\x6d', '\x65', '\x00', '\x08', '\x00', '\x00', '\x00', '\x74',
+ '\x65', '\x73', '\x74', '\x64', '\x65', '\x66', '\x00', '\x02',
+ '\x76', '\x65', '\x72', '\x73', '\x69', '\x6f', '\x6e', '\x00',
+ '\x03', '\x00', '\x00', '\x00', '\x76', '\x31', '\x00', '\x00',
+ '\x07', '\x6d', '\x65', '\x74', '\x61', '\x64', '\x61', '\x74',
+ '\x61', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77', '\x7f',
+ '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x07', '\x5f',
+ '\x69', '\x64', '\x00', '\x5c', '\x11', '\x51', '\x56', '\x77',
+ '\x7f', '\xf8', '\x56', '\x54', '\x24', '\x8a', '\xe1', '\x00',
},
},
mCursorCount: 1,
diff --git a/src/k8splugin/internal/db/store.go b/src/k8splugin/internal/db/store.go
index a235597a..148e078e 100644
--- a/src/k8splugin/internal/db/store.go
+++ b/src/k8splugin/internal/db/store.go
@@ -23,6 +23,13 @@ import (
// DBconn interface used to talk a concrete Database connection
var DBconn Store
+// Key is an interface that will be implemented by anypackage
+// that wants to use the Store interface. This allows various
+// db backends and key types.
+type Key interface {
+ String() string
+}
+
// Store is an interface for accessing a database
type Store interface {
// Returns nil if db health is good
@@ -33,19 +40,19 @@ type Store interface {
// Creates a new master table with key and links data with tag and
// creates a pointer to the newly added data in the master table
- Create(table, key, tag string, data interface{}) error
+ Create(table string, key Key, tag string, data interface{}) error
// Reads data for a particular key with specific tag.
- Read(table, key, tag string) ([]byte, error)
+ Read(table string, key Key, tag string) ([]byte, error)
//TODO: Update(context.Context, string, interface{}) error
// Deletes a specific tag data for key.
// TODO: If tag is empty, it will delete all tags under key.
- Delete(table, key, tag string) error
+ Delete(table string, key Key, tag string) error
// Reads all master tables and data from the specified tag in table
- ReadAll(table, tag string) (map[string][]byte, error)
+ ReadAll(table string, tag string) (map[string][]byte, error)
}
// CreateDBClient creates the DB client
diff --git a/src/k8splugin/internal/db/testing.go b/src/k8splugin/internal/db/testing.go
index a6c940ef..a411790e 100644
--- a/src/k8splugin/internal/db/testing.go
+++ b/src/k8splugin/internal/db/testing.go
@@ -20,6 +20,14 @@ import (
pkgerrors "github.com/pkg/errors"
)
+type mockKey struct {
+ Key string
+}
+
+func (m mockKey) String() string {
+ return m.Key
+}
+
//Creating an embedded interface via anonymous variable
//This allows us to make mockDB satisfy the DatabaseConnection
//interface even if we are not implementing all the methods in it
@@ -29,7 +37,7 @@ type MockDB struct {
Err error
}
-func (m *MockDB) Create(table, key, tag string, data interface{}) error {
+func (m *MockDB) Create(table string, key Key, tag string, data interface{}) error {
return m.Err
}
@@ -42,13 +50,13 @@ func (m *MockDB) Unmarshal(inp []byte, out interface{}) error {
return nil
}
-func (m *MockDB) Read(table, key, tag string) ([]byte, error) {
+func (m *MockDB) Read(table string, key Key, tag string) ([]byte, error) {
if m.Err != nil {
return nil, m.Err
}
for k, v := range m.Items {
- if k == key {
+ if k == key.String() {
return v[tag], nil
}
}
@@ -56,11 +64,11 @@ func (m *MockDB) Read(table, key, tag string) ([]byte, error) {
return nil, m.Err
}
-func (m *MockDB) Delete(table, key, tag string) error {
+func (m *MockDB) Delete(table string, key Key, tag string) error {
return m.Err
}
-func (m *MockDB) ReadAll(table, tag string) (map[string][]byte, error) {
+func (m *MockDB) ReadAll(table string, tag string) (map[string][]byte, error) {
if m.Err != nil {
return nil, m.Err
}
diff --git a/src/k8splugin/internal/rb/definition.go b/src/k8splugin/internal/rb/definition.go
index 4eaa9578..2ebbb08a 100644
--- a/src/k8splugin/internal/rb/definition.go
+++ b/src/k8splugin/internal/rb/definition.go
@@ -49,6 +49,14 @@ type DefinitionManager interface {
Upload(resID string, inp []byte) error
}
+type definitionKey struct {
+ Key string
+}
+
+func (dk definitionKey) String() string {
+ return dk.Key
+}
+
// DefinitionClient implements the DefinitionManager
// It will also be used to maintain some localized state
type DefinitionClient struct {
@@ -73,7 +81,7 @@ func (v *DefinitionClient) Create(def Definition) (Definition, error) {
if def.UUID == "" {
def.UUID, _ = uuid.GenerateUUID()
}
- key := def.UUID
+ key := definitionKey{Key: def.UUID}
err := db.DBconn.Create(v.storeName, key, v.tagMeta, def)
if err != nil {
@@ -109,7 +117,8 @@ func (v *DefinitionClient) List() ([]Definition, error) {
// Get returns the Resource Bundle Definition for corresponding ID
func (v *DefinitionClient) Get(id string) (Definition, error) {
- value, err := db.DBconn.Read(v.storeName, id, v.tagMeta)
+ key := definitionKey{Key: id}
+ value, err := db.DBconn.Read(v.storeName, key, v.tagMeta)
if err != nil {
return Definition{}, pkgerrors.Wrap(err, "Get Resource Bundle definition")
}
@@ -129,13 +138,14 @@ func (v *DefinitionClient) Get(id string) (Definition, error) {
// Delete the Resource Bundle definition from database
func (v *DefinitionClient) Delete(id string) error {
- err := db.DBconn.Delete(v.storeName, id, v.tagMeta)
+ key := definitionKey{Key: id}
+ err := db.DBconn.Delete(v.storeName, key, v.tagMeta)
if err != nil {
return pkgerrors.Wrap(err, "Delete Resource Bundle Definition")
}
//Delete the content when the delete operation happens
- err = db.DBconn.Delete(v.storeName, id, v.tagContent)
+ err = db.DBconn.Delete(v.storeName, key, v.tagContent)
if err != nil {
return pkgerrors.Wrap(err, "Delete Resource Bundle Definition Content")
}
@@ -146,6 +156,7 @@ func (v *DefinitionClient) Delete(id string) error {
// Upload the contents of resource bundle into database
func (v *DefinitionClient) Upload(id string, inp []byte) error {
+ key := definitionKey{Key: id}
//Check if definition metadata exists
def, err := v.Get(id)
if err != nil {
@@ -192,7 +203,7 @@ func (v *DefinitionClient) Upload(id string, inp []byte) error {
//Encode given byte stream to text for storage
encodedStr := base64.StdEncoding.EncodeToString(inp)
- err = db.DBconn.Create(v.storeName, id, v.tagContent, encodedStr)
+ err = db.DBconn.Create(v.storeName, key, v.tagContent, encodedStr)
if err != nil {
return pkgerrors.Errorf("Error uploading data to db: %s", err.Error())
}
@@ -205,6 +216,7 @@ func (v *DefinitionClient) Upload(id string, inp []byte) error {
// ExtractTarBall code to create the folder structure on disk
func (v *DefinitionClient) Download(id string) ([]byte, error) {
+ key := definitionKey{Key: id}
//ignore the returned data here
//Check if id is valid
_, err := v.Get(id)
@@ -212,7 +224,7 @@ func (v *DefinitionClient) Download(id string) ([]byte, error) {
return nil, pkgerrors.Errorf("Invalid Definition ID provided: %s", err.Error())
}
- value, err := db.DBconn.Read(v.storeName, id, v.tagContent)
+ value, err := db.DBconn.Read(v.storeName, key, v.tagContent)
if err != nil {
return nil, pkgerrors.Wrap(err, "Get Resource Bundle definition content")
}
diff --git a/src/k8splugin/internal/rb/profile.go b/src/k8splugin/internal/rb/profile.go
index 086c3486..006fa913 100644
--- a/src/k8splugin/internal/rb/profile.go
+++ b/src/k8splugin/internal/rb/profile.go
@@ -49,6 +49,14 @@ type ProfileManager interface {
Upload(resID string, inp []byte) error
}
+type profileKey struct {
+ Key string
+}
+
+func (dk profileKey) String() string {
+ return dk.Key
+}
+
// ProfileClient implements the ProfileManager
// It will also be used to maintain some localized state
type ProfileClient struct {
@@ -95,7 +103,7 @@ func (v *ProfileClient) Create(p Profile) (Profile, error) {
if p.UUID == "" {
p.UUID, _ = uuid.GenerateUUID()
}
- key := p.UUID
+ key := profileKey{Key: p.UUID}
err = db.DBconn.Create(v.storeName, key, v.tagMeta, p)
if err != nil {
@@ -132,7 +140,8 @@ func (v *ProfileClient) List() ([]Profile, error) {
// Get returns the Resource Bundle Profile for corresponding ID
func (v *ProfileClient) Get(id string) (Profile, error) {
- value, err := db.DBconn.Read(v.storeName, id, v.tagMeta)
+ key := profileKey{Key: id}
+ value, err := db.DBconn.Read(v.storeName, key, v.tagMeta)
if err != nil {
return Profile{}, pkgerrors.Wrap(err, "Get Resource Bundle Profile")
}
@@ -152,12 +161,13 @@ func (v *ProfileClient) Get(id string) (Profile, error) {
// Delete the Resource Bundle Profile from database
func (v *ProfileClient) Delete(id string) error {
- err := db.DBconn.Delete(v.storeName, id, v.tagMeta)
+ key := profileKey{Key: id}
+ err := db.DBconn.Delete(v.storeName, key, v.tagMeta)
if err != nil {
return pkgerrors.Wrap(err, "Delete Resource Bundle Profile")
}
- err = db.DBconn.Delete(v.storeName, id, v.tagContent)
+ err = db.DBconn.Delete(v.storeName, key, v.tagContent)
if err != nil {
return pkgerrors.Wrap(err, "Delete Resource Bundle Profile Content")
}
@@ -168,6 +178,7 @@ func (v *ProfileClient) Delete(id string) error {
// Upload the contents of resource bundle into database
func (v *ProfileClient) Upload(id string, inp []byte) error {
+ key := profileKey{Key: id}
//ignore the returned data here.
_, err := v.Get(id)
if err != nil {
@@ -181,7 +192,7 @@ func (v *ProfileClient) Upload(id string, inp []byte) error {
//Encode given byte stream to text for storage
encodedStr := base64.StdEncoding.EncodeToString(inp)
- err = db.DBconn.Create(v.storeName, id, v.tagContent, encodedStr)
+ err = db.DBconn.Create(v.storeName, key, v.tagContent, encodedStr)
if err != nil {
return pkgerrors.Errorf("Error uploading data to db %s", err.Error())
}
@@ -194,6 +205,7 @@ func (v *ProfileClient) Upload(id string, inp []byte) error {
// ExtractTarBall code to create the folder structure on disk
func (v *ProfileClient) Download(id string) ([]byte, error) {
+ key := profileKey{Key: id}
//ignore the returned data here
//Check if id is valid
_, err := v.Get(id)
@@ -201,7 +213,7 @@ func (v *ProfileClient) Download(id string) ([]byte, error) {
return nil, pkgerrors.Errorf("Invalid Profile ID provided: %s", err.Error())
}
- value, err := db.DBconn.Read(v.storeName, id, v.tagContent)
+ value, err := db.DBconn.Read(v.storeName, key, v.tagContent)
if err != nil {
return nil, pkgerrors.Wrap(err, "Get Resource Bundle Profile content")
}