summaryrefslogtreecommitdiffstats
path: root/src/orchestrator/pkg/module
diff options
context:
space:
mode:
Diffstat (limited to 'src/orchestrator/pkg/module')
-rw-r--r--src/orchestrator/pkg/module/app.go202
-rw-r--r--src/orchestrator/pkg/module/app_test.go327
-rw-r--r--src/orchestrator/pkg/module/compositeapp.go8
-rw-r--r--src/orchestrator/pkg/module/module.go2
4 files changed, 535 insertions, 4 deletions
diff --git a/src/orchestrator/pkg/module/app.go b/src/orchestrator/pkg/module/app.go
new file mode 100644
index 00000000..c25a1b51
--- /dev/null
+++ b/src/orchestrator/pkg/module/app.go
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2020 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 governinog permissions and
+ * limitations under the License.
+ */
+
+package module
+
+import (
+ "encoding/json"
+
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+// App contains metadata for Apps
+type App struct {
+ Metadata AppMetaData `json:"metadata"`
+}
+
+//AppMetaData contains the parameters needed for Apps
+type AppMetaData struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ UserData1 string `json:"userData1"`
+ UserData2 string `json:"userData2"`
+}
+
+//AppContent contains fileContent
+type AppContent struct {
+ FileContent string
+}
+
+// AppKey is the key structure that is used in the database
+type AppKey struct {
+ App string `json:"app"`
+ Project string `json:"project"`
+ CompositeApp string `json:"compositeapp"`
+ CompositeAppVersion string `json:"compositeappversion"`
+}
+
+// We will use json marshalling to convert to string to
+// preserve the underlying structure.
+func (aK AppKey) String() string {
+ out, err := json.Marshal(aK)
+ if err != nil {
+ return ""
+ }
+ return string(out)
+}
+
+// AppManager is an interface exposes the App functionality
+type AppManager interface {
+ CreateApp(a App, ac AppContent, p string, cN string, cV string) (App, error)
+ GetApp(name string, p string, cN string, cV string) (App, error)
+ GetAppContent(name string, p string, cN string, cV string) (AppContent, error)
+ DeleteApp(name string, p string, cN string, cV string) error
+}
+
+// AppClient implements the AppManager
+// It will also be used to maintain some localized state
+type AppClient struct {
+ storeName string
+ tagMeta, tagContent string
+}
+
+// NewAppClient returns an instance of the AppClient
+// which implements the AppManager
+func NewAppClient() *AppClient {
+ return &AppClient{
+ storeName: "orchestrator",
+ tagMeta: "appmetadata",
+ tagContent: "appcontent",
+ }
+}
+
+// CreateApp creates a new collection based on the App
+func (v *AppClient) CreateApp(a App, ac AppContent, p string, cN string, cV string) (App, error) {
+
+ //Construct the composite key to select the entry
+ key := AppKey{
+ App: a.Metadata.Name,
+ Project: p,
+ CompositeApp: cN,
+ CompositeAppVersion: cV,
+ }
+
+ //Check if this App already exists
+ _, err := v.GetApp(a.Metadata.Name, p, cN, cV)
+ if err == nil {
+ return App{}, pkgerrors.New("App already exists")
+ }
+
+ //Check if Project exists
+ _, err = NewProjectClient().GetProject(p)
+ if err != nil {
+ return App{}, pkgerrors.New("Unable to find the project")
+ }
+
+ //check if CompositeApp with version exists
+ _, err = NewCompositeAppClient().GetCompositeApp(cN, cV, p)
+ if err != nil {
+ return App{}, pkgerrors.New("Unable to find the composite app with version")
+ }
+
+ err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, a)
+ if err != nil {
+ return App{}, pkgerrors.Wrap(err, "Creating DB Entry")
+ }
+
+ err = db.DBconn.Insert(v.storeName, key, nil, v.tagContent, ac)
+ if err != nil {
+ return App{}, pkgerrors.Wrap(err, "Creating DB Entry")
+ }
+
+ return a, nil
+}
+
+// GetApp returns the App for corresponding name
+func (v *AppClient) GetApp(name string, p string, cN string, cV string) (App, error) {
+
+ //Construct the composite key to select the entry
+ key := AppKey{
+ App: name,
+ Project: p,
+ CompositeApp: cN,
+ CompositeAppVersion: cV,
+ }
+ value, err := db.DBconn.Find(v.storeName, key, v.tagMeta)
+ if err != nil {
+ return App{}, pkgerrors.Wrap(err, "Get app")
+ }
+
+ //value is a byte array
+ if value != nil {
+ app := App{}
+ err = db.DBconn.Unmarshal(value[0], &app)
+ if err != nil {
+ return App{}, pkgerrors.Wrap(err, "Unmarshaling Value")
+ }
+ return app, nil
+ }
+
+ return App{}, pkgerrors.New("Error getting app")
+}
+
+// GetAppContent returns content for corresponding app
+func (v *AppClient) GetAppContent(name string, p string, cN string, cV string) (AppContent, error) {
+
+ //Construct the composite key to select the entry
+ key := AppKey{
+ App: name,
+ Project: p,
+ CompositeApp: cN,
+ CompositeAppVersion: cV,
+ }
+ value, err := db.DBconn.Find(v.storeName, key, v.tagContent)
+ if err != nil {
+ return AppContent{}, pkgerrors.Wrap(err, "Get app content")
+ }
+
+ //value is a byte array
+ if value != nil {
+ ac := AppContent{}
+ err = db.DBconn.Unmarshal(value[0], &ac)
+ if err != nil {
+ return AppContent{}, pkgerrors.Wrap(err, "Unmarshaling Value")
+ }
+ return ac, nil
+ }
+
+ return AppContent{}, pkgerrors.New("Error getting app content")
+}
+
+// DeleteApp deletes the App from database
+func (v *AppClient) DeleteApp(name string, p string, cN string, cV string) error {
+
+ //Construct the composite key to select the entry
+ key := AppKey{
+ App: name,
+ Project: p,
+ CompositeApp: cN,
+ CompositeAppVersion: cV,
+ }
+ err := db.DBconn.Remove(v.storeName, key)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Delete App Entry;")
+ }
+
+ return nil
+}
diff --git a/src/orchestrator/pkg/module/app_test.go b/src/orchestrator/pkg/module/app_test.go
new file mode 100644
index 00000000..42c08ef6
--- /dev/null
+++ b/src/orchestrator/pkg/module/app_test.go
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2020 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 module
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
+ pkgerrors "github.com/pkg/errors"
+ // pkgerrors "github.com/pkg/errors"
+)
+
+func TestCreateApp(t *testing.T) {
+ testCases := []struct {
+ label string
+ inpApp App
+ inpAppContent AppContent
+ inpProject string
+ inpCompositeAppName string
+ inpCompositeAppVersion string
+ expectedError string
+ mockdb *db.MockDB
+ expected App
+ }{
+ {
+ label: "Create App",
+ inpApp: App{
+ Metadata: AppMetaData{
+ Name: "testApp",
+ Description: "A sample app used for unit testing",
+ UserData1: "userData1",
+ UserData2: "userData2",
+ },
+ },
+
+ inpAppContent: AppContent{
+ FileContent: "Sample file content",
+ },
+ inpProject: "testProject",
+ inpCompositeAppName: "testCompositeApp",
+ inpCompositeAppVersion: "v1",
+ expected: App{
+ Metadata: AppMetaData{
+ Name: "testApp",
+ Description: "A sample app used for unit testing",
+ UserData1: "userData1",
+ UserData2: "userData2",
+ },
+ },
+ expectedError: "",
+ mockdb: &db.MockDB{
+ Items: map[string]map[string][]byte{
+ ProjectKey{ProjectName: "testProject"}.String(): {
+ "projectmetadata": []byte(
+ "{" +
+ "\"metadata\": {" +
+ "\"Name\": \"testProject\"," +
+ "\"Description\": \"Test project for unit testing\"," +
+ "\"UserData1\": \"userData1\"," +
+ "\"UserData2\": \"userData2\"}" +
+ "}"),
+ },
+ CompositeAppKey{CompositeAppName: "testCompositeApp", Version: "v1", Project: "testProject"}.String(): {
+ "compositeapp": []byte(
+ "{" +
+ "\"metadata\":{" +
+ "\"Name\":\"testCompositeApp\"," +
+ "\"Description\":\"Test CompositeApp for unit testing\"," +
+ "\"UserData1\":\"userData1\"," +
+ "\"UserData2\":\"userData2\"}," +
+ "\"spec\":{" +
+ "\"Version\":\"v1\"}" +
+ "}"),
+ },
+ },
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewAppClient()
+ got, err := impl.CreateApp(testCase.inpApp, testCase.inpAppContent, testCase.inpProject, testCase.inpCompositeAppName, testCase.inpCompositeAppVersion)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("Create returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("Create returned an unexpected error %s", err)
+ }
+ } else {
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("Create returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestGetApp(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ inpApp string
+ inpProject string
+ inpCompositeAppName string
+ inpCompositeAppVersion string
+ expectedError string
+ mockdb *db.MockDB
+ expected App
+ }{
+ {
+ label: "Get Composite App",
+ inpApp: "testApp",
+ inpProject: "testProject",
+ inpCompositeAppName: "testCompositeApp",
+ inpCompositeAppVersion: "v1",
+ expected: App{
+ Metadata: AppMetaData{
+ Name: "testApp",
+ Description: "Test App for unit testing",
+ UserData1: "userData1",
+ UserData2: "userData2",
+ },
+ },
+ expectedError: "",
+ mockdb: &db.MockDB{
+ Items: map[string]map[string][]byte{
+ AppKey{App: "testApp", Project: "testProject", CompositeApp: "testCompositeApp", CompositeAppVersion: "v1"}.String(): {
+ "appmetadata": []byte(
+ "{" +
+ "\"metadata\": {" +
+ "\"Name\": \"testApp\"," +
+ "\"Description\": \"Test App for unit testing\"," +
+ "\"UserData1\": \"userData1\"," +
+ "\"UserData2\": \"userData2\"}" +
+ "}"),
+ "appcontent": []byte(
+ "{" +
+ "\"FileContent\": \"sample file content\"" +
+ "}"),
+ },
+ },
+ },
+ },
+ {
+ label: "Get Error",
+ expectedError: "DB Error",
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("DB Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewAppClient()
+ got, err := impl.GetApp(testCase.inpApp, testCase.inpProject, testCase.inpCompositeAppName, testCase.inpCompositeAppVersion)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("Get returned an unexpected error: %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("Get returned an unexpected error: %s", err)
+ }
+ } else {
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("Get returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestGetAppContent(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ inpApp string
+ inpProject string
+ inpCompositeAppName string
+ inpCompositeAppVersion string
+ expectedError string
+ mockdb *db.MockDB
+ expected AppContent
+ }{
+ {
+ label: "Get App content",
+ inpApp: "testApp",
+ inpProject: "testProject",
+ inpCompositeAppName: "testCompositeApp",
+ inpCompositeAppVersion: "v1",
+ expected: AppContent{
+ FileContent: "Samplefilecontent",
+ },
+ expectedError: "",
+ mockdb: &db.MockDB{
+ Items: map[string]map[string][]byte{
+ AppKey{App: "testApp", Project: "testProject", CompositeApp: "testCompositeApp", CompositeAppVersion: "v1"}.String(): {
+ "appmetadata": []byte(
+ "{" +
+ "\"metadata\": {" +
+ "\"Name\": \"testApp\"," +
+ "\"Description\": \"Test App for unit testing\"," +
+ "\"UserData1\": \"userData1\"," +
+ "\"UserData2\": \"userData2\"}" +
+ "}"),
+ "appcontent": []byte(
+ "{" +
+ "\"FileContent\": \"Samplefilecontent\"" +
+ "}"),
+ },
+ },
+ },
+ },
+ {
+ label: "Get Error",
+ expectedError: "DB Error",
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("DB Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewAppClient()
+ got, err := impl.GetAppContent(testCase.inpApp, testCase.inpProject, testCase.inpCompositeAppName, testCase.inpCompositeAppVersion)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("Get returned an unexpected error: %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("Get returned an unexpected error: %s", err)
+ }
+ } else {
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("Get returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+}
+
+func TestDeleteApp(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ inpApp string
+ inpProject string
+ inpCompositeAppName string
+ inpCompositeAppVersion string
+ expectedError string
+ mockdb *db.MockDB
+ }{
+ {
+ label: "Delete App",
+ inpApp: "testApp",
+ inpProject: "testProject",
+ inpCompositeAppName: "testCompositeApp",
+ inpCompositeAppVersion: "v1",
+ mockdb: &db.MockDB{
+ Items: map[string]map[string][]byte{
+ AppKey{App: "testApp", Project: "testProject", CompositeApp: "testCompositeApp", CompositeAppVersion: "v1"}.String(): {
+ "appmetadata": []byte(
+ "{" +
+ "\"metadata\": {" +
+ "\"Name\": \"testApp\"," +
+ "\"Description\": \"Test App for unit testing\"," +
+ "\"UserData1\": \"userData1\"," +
+ "\"UserData2\": \"userData2\"}" +
+ "}"),
+ "appcontent": []byte(
+ "{" +
+ "\"FileContent\": \"Samplefilecontent\"" +
+ "}"),
+ },
+ },
+ },
+ },
+ {
+ label: "Delete Error",
+ expectedError: "DB Error",
+ mockdb: &db.MockDB{
+ Err: pkgerrors.New("DB Error"),
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ impl := NewAppClient()
+ err := impl.DeleteApp(testCase.inpApp, testCase.inpProject, testCase.inpCompositeAppName, testCase.inpCompositeAppVersion)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("Delete returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("Delete returned an unexpected error %s", err)
+ }
+ }
+ })
+ }
+}
diff --git a/src/orchestrator/pkg/module/compositeapp.go b/src/orchestrator/pkg/module/compositeapp.go
index 74fbe0d5..59fbbab5 100644
--- a/src/orchestrator/pkg/module/compositeapp.go
+++ b/src/orchestrator/pkg/module/compositeapp.go
@@ -105,7 +105,7 @@ func (v *CompositeAppClient) CreateCompositeApp(c CompositeApp, p string) (Compo
return CompositeApp{}, pkgerrors.New("Unable to find the project")
}
- err = db.DBconn.Create(v.storeName, key, v.tagMeta, c)
+ err = db.DBconn.Insert(v.storeName, key, nil, v.tagMeta, c)
if err != nil {
return CompositeApp{}, pkgerrors.Wrap(err, "Creating DB Entry")
}
@@ -122,7 +122,7 @@ func (v *CompositeAppClient) GetCompositeApp(name string, version string, p stri
Version: version,
Project: p,
}
- value, err := db.DBconn.Read(v.storeName, key, v.tagMeta)
+ value, err := db.DBconn.Find(v.storeName, key, v.tagMeta)
if err != nil {
return CompositeApp{}, pkgerrors.Wrap(err, "Get composite application")
}
@@ -130,7 +130,7 @@ func (v *CompositeAppClient) GetCompositeApp(name string, version string, p stri
//value is a byte array
if value != nil {
compApp := CompositeApp{}
- err = db.DBconn.Unmarshal(value, &compApp)
+ err = db.DBconn.Unmarshal(value[0], &compApp)
if err != nil {
return CompositeApp{}, pkgerrors.Wrap(err, "Unmarshaling Value")
}
@@ -149,7 +149,7 @@ func (v *CompositeAppClient) DeleteCompositeApp(name string, version string, p s
Version: version,
Project: p,
}
- err := db.DBconn.Delete(v.storeName, key, v.tagMeta)
+ err := db.DBconn.Remove(v.storeName, key)
if err != nil {
return pkgerrors.Wrap(err, "Delete CompositeApp Entry;")
}
diff --git a/src/orchestrator/pkg/module/module.go b/src/orchestrator/pkg/module/module.go
index 8f2948dd..77a2f5bf 100644
--- a/src/orchestrator/pkg/module/module.go
+++ b/src/orchestrator/pkg/module/module.go
@@ -20,6 +20,7 @@ package module
type Client struct {
Project *ProjectClient
CompositeApp *CompositeAppClient
+ App *AppClient
Controller *ControllerClient
Cluster *ClusterClient
GenericPlacementIntent *GenericPlacementIntentClient
@@ -36,6 +37,7 @@ func NewClient() *Client {
c := &Client{}
c.Project = NewProjectClient()
c.CompositeApp = NewCompositeAppClient()
+ c.App = NewAppClient()
c.Controller = NewControllerClient()
c.Cluster = NewClusterClient()
c.GenericPlacementIntent = NewGenericPlacementIntentClient()