summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/k8splugin/api/brokerhandler.go14
-rw-r--r--src/k8splugin/api/brokerhandler_test.go49
-rw-r--r--src/k8splugin/api/profilehandler.go29
-rw-r--r--src/k8splugin/api/profilehandler_test.go13
-rw-r--r--src/k8splugin/internal/app/instance.go27
-rw-r--r--src/k8splugin/internal/db/README.md123
-rw-r--r--src/k8splugin/internal/db/testing.go14
-rw-r--r--src/k8splugin/internal/rb/definition.go48
-rw-r--r--src/k8splugin/internal/rb/profile.go28
-rw-r--r--src/orchestrator/go.sum1
-rw-r--r--src/orchestrator/internal/db/README.md123
-rw-r--r--src/orchestrator/internal/logutils/logger.go28
12 files changed, 433 insertions, 64 deletions
diff --git a/src/k8splugin/api/brokerhandler.go b/src/k8splugin/api/brokerhandler.go
index b377baf1..7671db44 100644
--- a/src/k8splugin/api/brokerhandler.go
+++ b/src/k8splugin/api/brokerhandler.go
@@ -134,15 +134,13 @@ func (b brokerInstanceHandler) createHandler(w http.ResponseWriter, r *http.Requ
return
}
- rbName := req.getAttributeValue(req.SDNCDirectives, "k8s-rb-definition-name")
- if rbName == "" {
- http.Error(w, "k8s-rb-definition-name is missing from sdnc-directives", http.StatusBadRequest)
+ if req.VFModuleModelInvariantID == "" {
+ http.Error(w, "vf-module-model-invariant-id is empty", http.StatusBadRequest)
return
}
- rbVersion := req.getAttributeValue(req.SDNCDirectives, "k8s-rb-definition-version")
- if rbVersion == "" {
- http.Error(w, "k8s-rb-definition-version is missing from sdnc-directives", http.StatusBadRequest)
+ if req.VFModuleModelVersionID == "" {
+ http.Error(w, "vf-module-model-version-id is empty", http.StatusBadRequest)
return
}
@@ -160,8 +158,8 @@ func (b brokerInstanceHandler) createHandler(w http.ResponseWriter, r *http.Requ
// Setup the resource parameters for making the request
var instReq app.InstanceRequest
- instReq.RBName = rbName
- instReq.RBVersion = rbVersion
+ instReq.RBName = req.VFModuleModelInvariantID
+ instReq.RBVersion = req.VFModuleModelVersionID
instReq.ProfileName = profileName
instReq.CloudRegion = cloudRegion
instReq.Labels = map[string]string{
diff --git a/src/k8splugin/api/brokerhandler_test.go b/src/k8splugin/api/brokerhandler_test.go
index 00ca3b7b..83ff588b 100644
--- a/src/k8splugin/api/brokerhandler_test.go
+++ b/src/k8splugin/api/brokerhandler_test.go
@@ -48,18 +48,19 @@ func TestBrokerCreateHandler(t *testing.T) {
expectedCode: http.StatusUnprocessableEntity,
},
{
- label: "Missing parameter failure",
+ label: "Missing vf-module-*-id parameter",
input: bytes.NewBuffer([]byte(`{
"vf-module-model-customization-id": "84sdfkio938",
- "user_directives": {
+ "vf-module-model-invariant-id": "123456qwerty",
+ "sdnc_directives": {
"attributes": [
{
- "attribute_name": "k8s-rb-definition-name",
- "attribute_value": "test-rbdef"
+ "attribute_name": "vf_module_name",
+ "attribute_value": "test-vf-module-name"
},
{
- "attribute_name": "k8s-rb-definition-version",
- "attribute_value": "v1"
+ "attribute_name": "k8s-rb-profile-name",
+ "attribute_value": "profile1"
}
]
}
@@ -67,9 +68,11 @@ func TestBrokerCreateHandler(t *testing.T) {
expectedCode: http.StatusBadRequest,
},
{
- label: "Deprecated parameters passed (user_directives)",
+ label: "Missing parameter from sdnc_directives",
input: bytes.NewBuffer([]byte(`{
- "vf-module-model-customization-id": "97sdfkio168",
+ "vf-module-model-customization-id": "84sdfkio938",
+ "vf-module-model-invariant-id": "123456qwerty",
+ "vf-module-model-version-id": "123qweasdzxc",
"sdnc_directives": {
"attributes": [
{
@@ -77,22 +80,6 @@ func TestBrokerCreateHandler(t *testing.T) {
"attribute_value": "test-vf-module-name"
}
]
- },
- "user_directives": {
- "attributes": [
- {
- "attribute_name": "rb-definition-name",
- "attribute_value": "test-rbdef"
- },
- {
- "attribute_name": "rb-definition-version",
- "attribute_value": "v1"
- },
- {
- "attribute_name": "rb-profile-name",
- "attribute_value": "profile1"
- }
- ]
}
}`)),
expectedCode: http.StatusBadRequest,
@@ -101,6 +88,8 @@ func TestBrokerCreateHandler(t *testing.T) {
label: "Succesfully create an Instance",
input: bytes.NewBuffer([]byte(`{
"vf-module-model-customization-id": "84sdfkio938",
+ "vf-module-model-invariant-id": "123456qwerty",
+ "vf-module-model-version-id": "123qweasdzxc",
"sdnc_directives": {
"attributes": [
{
@@ -108,14 +97,6 @@ func TestBrokerCreateHandler(t *testing.T) {
"attribute_value": "test-vf-module-name"
},
{
- "attribute_name": "k8s-rb-definition-name",
- "attribute_value": "test-rbdef"
- },
- {
- "attribute_name": "k8s-rb-definition-version",
- "attribute_value": "v1"
- },
- {
"attribute_name": "k8s-rb-profile-name",
"attribute_value": "profile1"
}
@@ -149,8 +130,8 @@ func TestBrokerCreateHandler(t *testing.T) {
{
ID: "HaKpys8e",
Request: app.InstanceRequest{
- RBName: "test-rbdef",
- RBVersion: "v1",
+ RBName: "123456qwerty",
+ RBVersion: "123qweasdzxc",
ProfileName: "profile1",
CloudRegion: "region1",
},
diff --git a/src/k8splugin/api/profilehandler.go b/src/k8splugin/api/profilehandler.go
index 68ab77a4..acd23060 100644
--- a/src/k8splugin/api/profilehandler.go
+++ b/src/k8splugin/api/profilehandler.go
@@ -21,6 +21,7 @@ import (
"io"
"io/ioutil"
"net/http"
+ "strings"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/rb"
@@ -30,12 +31,12 @@ import (
// Used to store backend implementations objects
// Also simplifies mocking for unit testing purposes
type rbProfileHandler struct {
- // Interface that implements bundle Definition operations
- // We will set this variable with a mock interface for testing
+ // Interface that implements bundle profile operations
+ // Set this variable with a mock interface for testing
client rb.ProfileManager
}
-// createHandler handles creation of the definition entry in the database
+// createHandler creates a profile entry in the database
func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request) {
var p rb.Profile
@@ -70,7 +71,7 @@ func (h rbProfileHandler) createHandler(w http.ResponseWriter, r *http.Request)
}
}
-// uploadHandler handles upload of the bundle tar file into the database
+// uploadHandler uploads the profile artifact tar file into the database
func (h rbProfileHandler) uploadHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
@@ -97,8 +98,8 @@ func (h rbProfileHandler) uploadHandler(w http.ResponseWriter, r *http.Request)
w.WriteHeader(http.StatusOK)
}
-// getHandler handles GET operations on a particular ids
-// Returns a rb.Definition
+// getHandler gets a Profile Key in the database
+// Returns an rb.Profile
func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
@@ -107,8 +108,14 @@ func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
ret, err := h.client.Get(rbName, rbVersion, prName)
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ // Separate "Not found" from generic DB errors
+ if strings.Contains(err.Error(), "Error finding") {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ } else {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
}
w.Header().Set("Content-Type", "application/json")
@@ -120,8 +127,8 @@ func (h rbProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
}
}
-// getHandler handles GET operations on a particular ids
-// Returns a rb.Definition
+// getHandler gets all profiles of a Resource Bundle Key in the database
+// Returns a list of rb.Profile
func (h rbProfileHandler) listHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
@@ -142,7 +149,7 @@ func (h rbProfileHandler) listHandler(w http.ResponseWriter, r *http.Request) {
}
}
-// deleteHandler handles DELETE operations on a particular bundle definition id
+// deleteHandler deletes a particular Profile Key in the database
func (h rbProfileHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
rbName := vars["rbname"]
diff --git a/src/k8splugin/api/profilehandler_test.go b/src/k8splugin/api/profilehandler_test.go
index 4dae377c..9ec9c54c 100644
--- a/src/k8splugin/api/profilehandler_test.go
+++ b/src/k8splugin/api/profilehandler_test.go
@@ -184,10 +184,19 @@ func TestRBProfileGetHandler(t *testing.T) {
},
},
{
- label: "Get Non-Exiting Bundle Profile",
- expectedCode: http.StatusInternalServerError,
+ label: "Get Non-Existing Profile",
+ expectedCode: http.StatusNotFound,
prname: "non-existing-profile",
rbProClient: &mockRBProfile{
+ Items: nil,
+ Err: pkgerrors.New("Error finding master table"),
+ },
+ },
+ {
+ label: "Faulty DB response",
+ expectedCode: http.StatusInternalServerError,
+ prname: "profile",
+ rbProClient: &mockRBProfile{
// list of Profiles that will be returned by the mockclient
Items: []rb.Profile{},
Err: pkgerrors.New("Internal Error"),
diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go
index fef9962f..5d8b2100 100644
--- a/src/k8splugin/internal/app/instance.go
+++ b/src/k8splugin/internal/app/instance.go
@@ -32,19 +32,21 @@ import (
// InstanceRequest contains the parameters needed for instantiation
// of profiles
type InstanceRequest struct {
- RBName string `json:"rb-name"`
- RBVersion string `json:"rb-version"`
- ProfileName string `json:"profile-name"`
- CloudRegion string `json:"cloud-region"`
- Labels map[string]string `json:"labels"`
+ RBName string `json:"rb-name"`
+ RBVersion string `json:"rb-version"`
+ ProfileName string `json:"profile-name"`
+ CloudRegion string `json:"cloud-region"`
+ Labels map[string]string `json:"labels"`
+ OverrideValues map[string]string `json:"override-values"`
}
// InstanceResponse contains the response from instantiation
type InstanceResponse struct {
- ID string `json:"id"`
- Request InstanceRequest `json:"request"`
- Namespace string `json:"namespace"`
- Resources []helm.KubernetesResource `json:"resources"`
+ ID string `json:"id"`
+ Request InstanceRequest `json:"request"`
+ Namespace string `json:"namespace"`
+ Resources []helm.KubernetesResource `json:"resources"`
+ OverrideValues map[string]string `json:"override-values"`
}
// InstanceMiniResponse contains the response from instantiation
@@ -133,7 +135,14 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
return InstanceResponse{}, pkgerrors.New("Unable to find Profile to create instance")
}
+ //Convert override values from map to array of strings of the following format
+ //foo=bar
overrideValues := []string{}
+ if i.OverrideValues != nil {
+ for k, v := range i.OverrideValues {
+ overrideValues = append(overrideValues, k+"="+v)
+ }
+ }
//Execute the kubernetes create command
sortedTemplates, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues)
diff --git a/src/k8splugin/internal/db/README.md b/src/k8splugin/internal/db/README.md
new file mode 100644
index 00000000..cba1b7ea
--- /dev/null
+++ b/src/k8splugin/internal/db/README.md
@@ -0,0 +1,123 @@
+# Database Abstraction Layer
+
+This package contains implementations of the Database interface defined in `store.go`
+Any database can be used as the backend as long as the following interface is implemented;
+
+```go
+type Store interface {
+ // Returns nil if db health is good
+ HealthCheck() error
+
+ // Unmarshal implements any unmarshaling needed for the database
+ Unmarshal(inp []byte, out interface{}) error
+
+ // 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 string, key Key, tag string, data interface{}) error
+
+ // Reads data for a particular key with specific tag.
+ Read(table string, key Key, tag string) ([]byte, error)
+
+ // Update data for particular key with specific tag
+ Update(table string, key Key, tag string, data interface{}) error
+
+ // Deletes a specific tag data for key.
+ // TODO: If tag is empty, it will delete all tags under key.
+ Delete(table string, key Key, tag string) error
+
+ // Reads all master tables and data from the specified tag in table
+ ReadAll(table string, tag string) (map[string][]byte, error)
+}
+```
+
+Therefore, `mongo.go`, `consul.go` implement the above interface and can be used as the backend as needed based on initial configuration.
+
+## Details on Mongo Implementation
+
+`mongo.go` implements the above interface using the `go.mongodb.org/mongo-driver` package.
+The code converts incoming binary data and creates a new document in the database.
+
+### Create
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+data []byte
+```
+
+Create inserts the provided `data` into the `collection` which returns an auto-generated (by `mongodb`) ID which we then associate with the `key` that is provided as one of the arguments.
+
+We use the `FindOneAndUpdate` mongo API to achieve this with the `upsert` option set to `true`.
+We create the following documents in mongodb for each new definition added to the database:
+
+There is a Master Key document that contains references to other documents which are related to this `key`.
+
+#### Master Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554b78a15f71d2dce7e"),
+ "key" : { "rbname" : "edgex", "rbversion" : "v1"},
+ "defmetadata" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defcontent" : ObjectId("5e0a8377bcfcdd0f01dc7b0d")
+}
+```
+#### Metadata Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defmetadata" : { "rbname" : "edgex", "rbversion" : "v1", "chartname" : "", "description" : "", "labels" : null }
+}
+```
+#### Definition Content
+```json
+{
+ "_id" : ObjectId("5e0a8377bcfcdd0f01dc7b0d"),
+ "defcontent" : "H4sICCVd3FwAA3Byb2ZpbGUxLnRhcgDt1NEKgjAUxvFd7ylG98aWOsGXiYELxLRwJvj2rbyoIPDGiuD/uzmwM9iB7Vvruvrgw7CdXHsUn6Ejm2W3aopcP9eZLYRJM1voPN+ZndAm16kVSn9onheXMLheKeGqfdM0rq07/3bfUv9PJUkiR9+H+tSVajRymM6+lEqN7njxoVSbU+z2deX388r9nWzkr8fGSt5d79pnLOZfm0f+dRrzb7P4DZD/LyDJAAAAAAAAAAAAAAAA/+0Ksq1N5QAoAAA="
+}
+```
+
+### Unmarshal
+
+Data in mongo is stored as `bson` which is a compressed form of `json`. We need mongo to convert the stored `bson` data to regular `json`
+that we can use in our code when returned.
+
+We just use the `bson.Unmarshal` API to achieve this.
+
+### Read
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+```
+
+Read is straight forward and it uses the `FindOne` API to find our Mongo document based on the provided `key` and then gets the corresponding data for the given `tag`. It will return []byte which can then be passed to the `Unmarshal` function to get the desired GO object.
+
+### Delete
+
+Delete is similar to Read and deletes all the objectIDs being stored for a given `key` in the collection.
+
+## Testing Interfaces
+
+The following interface exists to allow for the development of unit tests which don't require mongo to be running.
+It is mentioned so in the code as well.
+
+```go
+// MongoCollection defines the a subset of MongoDB operations
+// Note: This interface is defined mainly for mock testing
+type MongoCollection interface {
+ InsertOne(ctx context.Context, document interface{},
+ opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
+ FindOne(ctx context.Context, filter interface{},
+ opts ...*options.FindOneOptions) *mongo.SingleResult
+ FindOneAndUpdate(ctx context.Context, filter interface{},
+ update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult
+ DeleteOne(ctx context.Context, filter interface{},
+ opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
+ Find(ctx context.Context, filter interface{},
+ opts ...*options.FindOptions) (*mongo.Cursor, error)
+}
+``` \ No newline at end of file
diff --git a/src/k8splugin/internal/db/testing.go b/src/k8splugin/internal/db/testing.go
index 5f69dcb4..9a427e03 100644
--- a/src/k8splugin/internal/db/testing.go
+++ b/src/k8splugin/internal/db/testing.go
@@ -15,6 +15,7 @@ package db
import (
"encoding/json"
+
pkgerrors "github.com/pkg/errors"
)
@@ -40,6 +41,19 @@ func (m *MockDB) HealthCheck() error {
}
func (m *MockDB) Create(table string, key Key, tag string, data interface{}) error {
+ djs, err := json.Marshal(data)
+ if err != nil {
+ return err
+ }
+
+ d := make(map[string][]byte)
+ d[tag] = djs
+
+ if m.Items == nil {
+ m.Items = make(map[string]map[string][]byte)
+ }
+ m.Items[key.String()] = d
+
return m.Err
}
diff --git a/src/k8splugin/internal/rb/definition.go b/src/k8splugin/internal/rb/definition.go
index 65ae8e00..73ea44da 100644
--- a/src/k8splugin/internal/rb/definition.go
+++ b/src/k8splugin/internal/rb/definition.go
@@ -26,6 +26,7 @@ import (
"path/filepath"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/db"
+ "github.com/onap/multicloud-k8s/src/k8splugin/internal/logutils"
pkgerrors "github.com/pkg/errors"
)
@@ -101,6 +102,40 @@ func (v *DefinitionClient) Create(def Definition) (Definition, error) {
return Definition{}, pkgerrors.Wrap(err, "Creating DB Entry")
}
+ // Create a default profile automatically
+ prc := NewProfileClient()
+ pr, err := prc.Create(Profile{
+ RBName: def.RBName,
+ RBVersion: def.RBVersion,
+ ProfileName: "default",
+ Namespace: "default",
+ ReleaseName: "default",
+ })
+
+ if err != nil {
+ logutils.Error("Create Default Profile", logutils.Fields{
+ "error": err,
+ "rb-name": def.RBName,
+ "rb-version": def.RBVersion,
+ "profile-name": "default",
+ "namespace": "default",
+ "release-name": "default",
+ })
+ return Definition{}, pkgerrors.Wrap(err, "Creating Default Profile")
+ }
+
+ err = prc.Upload(pr.RBName, pr.RBVersion, pr.ProfileName, prc.getEmptyProfile())
+ if err != nil {
+ logutils.Error("Upload Empty Profile", logutils.Fields{
+ "error": err,
+ "rb-name": pr.RBName,
+ "rb-version": pr.RBVersion,
+ "profile-name": pr.ProfileName,
+ "profile-content": prc.getEmptyProfile(),
+ })
+ return Definition{}, pkgerrors.Wrap(err, "Upload Empty Profile")
+ }
+
return def, nil
}
@@ -173,6 +208,19 @@ func (v *DefinitionClient) Delete(name string, version string) error {
return pkgerrors.Wrap(err, "Delete Resource Bundle Definition Content")
}
+ //Delete the default profile as well
+ prc := NewProfileClient()
+ err = prc.Delete(name, version, "default")
+ if err != nil {
+ logutils.Error("Delete Default Profile", logutils.Fields{
+ "error": err,
+ "rb-name": name,
+ "rb-version": version,
+ "profile-name": "default",
+ })
+ return pkgerrors.Wrap(err, "Deleting default profile")
+ }
+
return nil
}
diff --git a/src/k8splugin/internal/rb/profile.go b/src/k8splugin/internal/rb/profile.go
index 49768d4b..6efa23b8 100644
--- a/src/k8splugin/internal/rb/profile.go
+++ b/src/k8splugin/internal/rb/profile.go
@@ -338,3 +338,31 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string,
return sortedTemplates, nil
}
+
+// Returns an empty profile with the following contents
+// Contains a manifest.yaml pointing to an override_values.yaml
+// The override_values.yaml file is empty.
+func (v *ProfileClient) getEmptyProfile() []byte {
+ return []byte{
+ 0x1F, 0x8B, 0x08, 0x08, 0x25, 0x5D, 0xDC, 0x5C, 0x00, 0x03, 0x70,
+ 0x72, 0x6F, 0x66, 0x69, 0x6C, 0x65, 0x31, 0x2E, 0x74, 0x61, 0x72,
+ 0x00, 0xED, 0xD4, 0xD1, 0x0A, 0x82, 0x30, 0x14, 0xC6, 0xF1, 0x5D,
+ 0xEF, 0x29, 0x46, 0xF7, 0xC6, 0x96, 0x3A, 0xC1, 0x97, 0x89, 0x81,
+ 0x0B, 0xC4, 0xB4, 0x70, 0x26, 0xF8, 0xF6, 0xAD, 0xBC, 0xA8, 0x20,
+ 0xF0, 0xC6, 0x8A, 0xE0, 0xFF, 0xBB, 0x39, 0xB0, 0x33, 0xD8, 0x81,
+ 0xED, 0x5B, 0xEB, 0xBA, 0xFA, 0xE0, 0xC3, 0xB0, 0x9D, 0x5C, 0x7B,
+ 0x14, 0x9F, 0xA1, 0x23, 0x9B, 0x65, 0xB7, 0x6A, 0x8A, 0x5C, 0x3F,
+ 0xD7, 0x99, 0x2D, 0x84, 0x49, 0x33, 0x5B, 0xE8, 0x3C, 0xDF, 0x99,
+ 0x9D, 0xD0, 0x26, 0xD7, 0xA9, 0x15, 0x4A, 0x7F, 0x68, 0x9E, 0x17,
+ 0x97, 0x30, 0xB8, 0x5E, 0x29, 0xE1, 0xAA, 0x7D, 0xD3, 0x34, 0xAE,
+ 0xAD, 0x3B, 0xFF, 0x76, 0xDF, 0x52, 0xFF, 0x4F, 0x25, 0x49, 0x22,
+ 0x47, 0xDF, 0x87, 0xFA, 0xD4, 0x95, 0x6A, 0x34, 0x72, 0x98, 0xCE,
+ 0xBE, 0x94, 0x4A, 0x8D, 0xEE, 0x78, 0xF1, 0xA1, 0x54, 0x9B, 0x53,
+ 0xEC, 0xF6, 0x75, 0xE5, 0xF7, 0xF3, 0xCA, 0xFD, 0x9D, 0x6C, 0xE4,
+ 0xAF, 0xC7, 0xC6, 0x4A, 0xDE, 0x5D, 0xEF, 0xDA, 0x67, 0x2C, 0xE6,
+ 0x5F, 0x9B, 0x47, 0xFE, 0x75, 0x1A, 0xF3, 0x6F, 0xB3, 0xF8, 0x0D,
+ 0x90, 0xFF, 0x2F, 0x20, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xED, 0x0A, 0xB2, 0xAD,
+ 0x4D, 0xE5, 0x00, 0x28, 0x00, 0x00,
+ }
+}
diff --git a/src/orchestrator/go.sum b/src/orchestrator/go.sum
index dcda41d4..732bc280 100644
--- a/src/orchestrator/go.sum
+++ b/src/orchestrator/go.sum
@@ -201,6 +201,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rubenv/sql-migrate v0.0.0-20190902133344-8926f37f0bc1/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
diff --git a/src/orchestrator/internal/db/README.md b/src/orchestrator/internal/db/README.md
new file mode 100644
index 00000000..cba1b7ea
--- /dev/null
+++ b/src/orchestrator/internal/db/README.md
@@ -0,0 +1,123 @@
+# Database Abstraction Layer
+
+This package contains implementations of the Database interface defined in `store.go`
+Any database can be used as the backend as long as the following interface is implemented;
+
+```go
+type Store interface {
+ // Returns nil if db health is good
+ HealthCheck() error
+
+ // Unmarshal implements any unmarshaling needed for the database
+ Unmarshal(inp []byte, out interface{}) error
+
+ // 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 string, key Key, tag string, data interface{}) error
+
+ // Reads data for a particular key with specific tag.
+ Read(table string, key Key, tag string) ([]byte, error)
+
+ // Update data for particular key with specific tag
+ Update(table string, key Key, tag string, data interface{}) error
+
+ // Deletes a specific tag data for key.
+ // TODO: If tag is empty, it will delete all tags under key.
+ Delete(table string, key Key, tag string) error
+
+ // Reads all master tables and data from the specified tag in table
+ ReadAll(table string, tag string) (map[string][]byte, error)
+}
+```
+
+Therefore, `mongo.go`, `consul.go` implement the above interface and can be used as the backend as needed based on initial configuration.
+
+## Details on Mongo Implementation
+
+`mongo.go` implements the above interface using the `go.mongodb.org/mongo-driver` package.
+The code converts incoming binary data and creates a new document in the database.
+
+### Create
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+data []byte
+```
+
+Create inserts the provided `data` into the `collection` which returns an auto-generated (by `mongodb`) ID which we then associate with the `key` that is provided as one of the arguments.
+
+We use the `FindOneAndUpdate` mongo API to achieve this with the `upsert` option set to `true`.
+We create the following documents in mongodb for each new definition added to the database:
+
+There is a Master Key document that contains references to other documents which are related to this `key`.
+
+#### Master Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554b78a15f71d2dce7e"),
+ "key" : { "rbname" : "edgex", "rbversion" : "v1"},
+ "defmetadata" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defcontent" : ObjectId("5e0a8377bcfcdd0f01dc7b0d")
+}
+```
+#### Metadata Key Entry
+```json
+{
+ "_id" : ObjectId("5e0a8554be261ecb57f067eb"),
+ "defmetadata" : { "rbname" : "edgex", "rbversion" : "v1", "chartname" : "", "description" : "", "labels" : null }
+}
+```
+#### Definition Content
+```json
+{
+ "_id" : ObjectId("5e0a8377bcfcdd0f01dc7b0d"),
+ "defcontent" : "H4sICCVd3FwAA3Byb2ZpbGUxLnRhcgDt1NEKgjAUxvFd7ylG98aWOsGXiYELxLRwJvj2rbyoIPDGiuD/uzmwM9iB7Vvruvrgw7CdXHsUn6Ejm2W3aopcP9eZLYRJM1voPN+ZndAm16kVSn9onheXMLheKeGqfdM0rq07/3bfUv9PJUkiR9+H+tSVajRymM6+lEqN7njxoVSbU+z2deX388r9nWzkr8fGSt5d79pnLOZfm0f+dRrzb7P4DZD/LyDJAAAAAAAAAAAAAAAA/+0Ksq1N5QAoAAA="
+}
+```
+
+### Unmarshal
+
+Data in mongo is stored as `bson` which is a compressed form of `json`. We need mongo to convert the stored `bson` data to regular `json`
+that we can use in our code when returned.
+
+We just use the `bson.Unmarshal` API to achieve this.
+
+### Read
+
+Arguments:
+```go
+collection string
+key interface
+tag string
+```
+
+Read is straight forward and it uses the `FindOne` API to find our Mongo document based on the provided `key` and then gets the corresponding data for the given `tag`. It will return []byte which can then be passed to the `Unmarshal` function to get the desired GO object.
+
+### Delete
+
+Delete is similar to Read and deletes all the objectIDs being stored for a given `key` in the collection.
+
+## Testing Interfaces
+
+The following interface exists to allow for the development of unit tests which don't require mongo to be running.
+It is mentioned so in the code as well.
+
+```go
+// MongoCollection defines the a subset of MongoDB operations
+// Note: This interface is defined mainly for mock testing
+type MongoCollection interface {
+ InsertOne(ctx context.Context, document interface{},
+ opts ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
+ FindOne(ctx context.Context, filter interface{},
+ opts ...*options.FindOneOptions) *mongo.SingleResult
+ FindOneAndUpdate(ctx context.Context, filter interface{},
+ update interface{}, opts ...*options.FindOneAndUpdateOptions) *mongo.SingleResult
+ DeleteOne(ctx context.Context, filter interface{},
+ opts ...*options.DeleteOptions) (*mongo.DeleteResult, error)
+ Find(ctx context.Context, filter interface{},
+ opts ...*options.FindOptions) (*mongo.Cursor, error)
+}
+``` \ No newline at end of file
diff --git a/src/orchestrator/internal/logutils/logger.go b/src/orchestrator/internal/logutils/logger.go
new file mode 100644
index 00000000..2e8f9969
--- /dev/null
+++ b/src/orchestrator/internal/logutils/logger.go
@@ -0,0 +1,28 @@
+package logutils
+
+import (
+ log "github.com/sirupsen/logrus"
+)
+
+//Fields is type that will be used by the calling function
+type Fields map[string]interface{}
+
+func init() {
+ // Log as JSON instead of the default ASCII formatter.
+ log.SetFormatter(&log.JSONFormatter{})
+}
+
+// Error uses the fields provided and logs
+func Error(msg string, fields Fields) {
+ log.WithFields(log.Fields(fields)).Error(msg)
+}
+
+// Warn uses the fields provided and logs
+func Warn(msg string, fields Fields) {
+ log.WithFields(log.Fields(fields)).Warn(msg)
+}
+
+// Info uses the fields provided and logs
+func Info(msg string, fields Fields) {
+ log.WithFields(log.Fields(fields)).Info(msg)
+}