aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDileep Ranganathan <dileep.ranganathan@intel.com>2020-02-19 16:19:18 -0800
committerEric Multanen <eric.w.multanen@intel.com>2020-03-05 09:54:19 -0800
commit8e0c4c63e5a014c95805f16d30a64cd53ddc7385 (patch)
tree19c2cec8ca35760dd9c869dd52569bb0ecbcd6f7
parenta2c244896cb87eb8564743af8c463f170869a824 (diff)
Composite Profile API and Handler
Implemented Composite Profile API and handler, adding create, get and delete handlers for the composite profile. Issue-ID: MULTICLOUD-997 Signed-off-by: Eric Multanen <eric.w.multanen@intel.com> Signed-off-by: Dileep Ranganathan <dileep.ranganathan@intel.com> Change-Id: Iab105cf88ef4635038cd36e90f3251bc900b2faf
-rw-r--r--src/orchestrator/api/api.go15
-rw-r--r--src/orchestrator/api/clusterhandler_test.go34
-rw-r--r--src/orchestrator/api/composite_profilehandler.go151
-rw-r--r--src/orchestrator/api/composite_profilehandler_test.go151
-rw-r--r--src/orchestrator/api/controllerhandler_test.go6
-rw-r--r--src/orchestrator/api/projecthandler_test.go6
-rw-r--r--src/orchestrator/cmd/main.go2
-rw-r--r--src/orchestrator/pkg/module/composite_profile.go192
-rw-r--r--src/orchestrator/pkg/module/composite_profile_test.go175
-rw-r--r--src/orchestrator/pkg/module/module.go9
10 files changed, 712 insertions, 29 deletions
diff --git a/src/orchestrator/api/api.go b/src/orchestrator/api/api.go
index f3e3b177..7c540dd3 100644
--- a/src/orchestrator/api/api.go
+++ b/src/orchestrator/api/api.go
@@ -30,7 +30,8 @@ func NewRouter(projectClient moduleLib.ProjectManager,
genericPlacementIntentClient moduleLib.GenericPlacementIntentManager,
appIntentClient moduleLib.AppIntentManager,
deploymentIntentGrpClient moduleLib.DeploymentIntentGroupManager,
- intentClient moduleLib.IntentManager) *mux.Router {
+ intentClient moduleLib.IntentManager,
+ compositeProfileClient moduleLib.CompositeProfileManager) *mux.Router {
router := mux.NewRouter().PathPrefix("/v2").Subrouter()
@@ -71,6 +72,18 @@ func NewRouter(projectClient moduleLib.ProjectManager,
router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{version}", compAppHandler.getHandler).Methods("GET")
router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{version}", compAppHandler.deleteHandler).Methods("DELETE")
+ if compositeProfileClient == nil {
+ compositeProfileClient = moduleClient.CompositeProfile
+ }
+ compProfilepHandler := compositeProfileHandler{
+ client: compositeProfileClient,
+ }
+
+ router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/composite-profiles", compProfilepHandler.createHandler).Methods("POST")
+ router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/composite-profiles", compProfilepHandler.getHandler).Methods("GET")
+ router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/composite-profiles/{composite-profile-name}", compProfilepHandler.getHandler).Methods("GET")
+ router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/composite-profiles/{composite-profile-name}", compProfilepHandler.deleteHandler).Methods("DELETE")
+
router.HandleFunc("/controllers", controlHandler.createHandler).Methods("POST")
router.HandleFunc("/controllers", controlHandler.createHandler).Methods("PUT")
router.HandleFunc("/controllers/{controller-name}", controlHandler.getHandler).Methods("GET")
diff --git a/src/orchestrator/api/clusterhandler_test.go b/src/orchestrator/api/clusterhandler_test.go
index a32bf021..58db6360 100644
--- a/src/orchestrator/api/clusterhandler_test.go
+++ b/src/orchestrator/api/clusterhandler_test.go
@@ -229,7 +229,7 @@ func TestClusterProviderCreateHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("POST", "/v2/cluster-providers", testCase.reader)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -307,7 +307,7 @@ func TestClusterProviderGetAllHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/cluster-providers", nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -377,7 +377,7 @@ func TestClusterProviderGetHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/cluster-providers/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -426,7 +426,7 @@ func TestClusterProviderDeleteHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("DELETE", "/v2/cluster-providers/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -538,7 +538,7 @@ of clusterTest
request := httptest.NewRequest("POST", "/v2/cluster-providers/clusterProvider1/clusters", bytes.NewBuffer(body.Bytes()))
request.Header.Set("Content-Type", multiwr.FormDataContentType())
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -625,7 +625,7 @@ func TestClusterGetAllHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvder1/clusters", nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -706,7 +706,7 @@ func TestClusterGetHandler(t *testing.T) {
if len(testCase.accept) > 0 {
request.Header.Set("Accept", testCase.accept)
}
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -784,7 +784,7 @@ of clusterTest
if len(testCase.accept) > 0 {
request.Header.Set("Accept", testCase.accept)
}
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -834,7 +834,7 @@ func TestClusterDeleteHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("DELETE", "/v2/cluster-providers/clusterProvider1/clusters/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -880,7 +880,7 @@ func TestClusterLabelCreateHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("POST", "/v2/cluster-providers/cp1/clusters/cl1/labels", testCase.reader)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -944,7 +944,7 @@ func TestClusterLabelsGetHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/cluster-providers/cp1/clusters/cl1/labels", nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -1004,7 +1004,7 @@ func TestClusterLabelGetHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/cl1/labels/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -1053,7 +1053,7 @@ func TestClusterLabelDeleteHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("DELETE", "/v2/cluster-providers/cp1/clusters/cl1/labels/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -1144,7 +1144,7 @@ func TestClusterKvPairsCreateHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("POST", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs", testCase.reader)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -1262,7 +1262,7 @@ func TestClusterKvPairsGetAllHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs", nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -1352,7 +1352,7 @@ func TestClusterKvPairsGetHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/cluster-providers/clusterProvider1/clusters/cl1/kv-pairs/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -1401,7 +1401,7 @@ func TestClusterKvPairsDeleteHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("DELETE", "/v2/cluster-providers/cp1/clusters/cl1/kv-pairs/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
diff --git a/src/orchestrator/api/composite_profilehandler.go b/src/orchestrator/api/composite_profilehandler.go
new file mode 100644
index 00000000..66c64dda
--- /dev/null
+++ b/src/orchestrator/api/composite_profilehandler.go
@@ -0,0 +1,151 @@
+/*
+ * 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 api
+
+import (
+ "encoding/json"
+ "io"
+ "net/http"
+
+ moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module"
+
+ "github.com/gorilla/mux"
+)
+
+/* Used to store backend implementation objects
+Also simplifies mocking for unit testing purposes
+*/
+type compositeProfileHandler struct {
+ client moduleLib.CompositeProfileManager
+}
+
+// createCompositeProfileHandler handles the create operation of intent
+func (h compositeProfileHandler) createHandler(w http.ResponseWriter, r *http.Request) {
+
+ var cpf moduleLib.CompositeProfile
+
+ err := json.NewDecoder(r.Body).Decode(&cpf)
+ switch {
+ case err == io.EOF:
+ http.Error(w, "Empty body", http.StatusBadRequest)
+ return
+ case err != nil:
+ http.Error(w, err.Error(), http.StatusUnprocessableEntity)
+ return
+ }
+
+ if cpf.Metadata.Name == "" {
+ http.Error(w, "Missing compositeProfileName in POST request", http.StatusBadRequest)
+ return
+ }
+
+ vars := mux.Vars(r)
+ projectName := vars["project-name"]
+ compositeAppName := vars["composite-app-name"]
+ version := vars["composite-app-version"]
+
+ cProf, createErr := h.client.CreateCompositeProfile(cpf, projectName, compositeAppName, version)
+ if createErr != nil {
+ http.Error(w, createErr.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusCreated)
+ err = json.NewEncoder(w).Encode(cProf)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// getHandler handles the GET operations on CompositeProfile
+func (h compositeProfileHandler) getHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ cProfName := vars["composite-profile-name"]
+
+ projectName := vars["project-name"]
+ if projectName == "" {
+ http.Error(w, "Missing projectName in GET request", http.StatusBadRequest)
+ return
+ }
+ compositeAppName := vars["composite-app-name"]
+ if compositeAppName == "" {
+ http.Error(w, "Missing compositeAppName in GET request", http.StatusBadRequest)
+ return
+ }
+
+ version := vars["composite-app-version"]
+ if version == "" {
+ http.Error(w, "Missing version in GET request", http.StatusBadRequest)
+ return
+ }
+
+ // handle the get all composite profile case
+ if len(cProfName) == 0 {
+ var retList []moduleLib.CompositeProfile
+
+ ret, err := h.client.GetCompositeProfiles(projectName, compositeAppName, version)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ for _, cl := range ret {
+ retList = append(retList, moduleLib.CompositeProfile{Metadata: cl.Metadata})
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ err = json.NewEncoder(w).Encode(retList)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ return
+ }
+
+ cProf, err := h.client.GetCompositeProfile(cProfName, projectName, compositeAppName, version)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ err = json.NewEncoder(w).Encode(cProf)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+// deleteHandler handles the delete operations on CompostiteProfile
+func (h compositeProfileHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ c := vars["composite-profile-name"]
+ p := vars["project-name"]
+ ca := vars["composite-app-name"]
+ v := vars["composite-app-version"]
+
+ err := h.client.DeleteCompositeProfile(c, p, ca, v)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ w.WriteHeader(http.StatusNoContent)
+}
diff --git a/src/orchestrator/api/composite_profilehandler_test.go b/src/orchestrator/api/composite_profilehandler_test.go
new file mode 100644
index 00000000..e98ed961
--- /dev/null
+++ b/src/orchestrator/api/composite_profilehandler_test.go
@@ -0,0 +1,151 @@
+/*
+ * 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 api
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "reflect"
+ "testing"
+
+ moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module"
+)
+
+//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
+type mockCompositeProfileManager struct {
+ // Items and err will be used to customize each test
+ // via a localized instantiation of mockCompositeProfileManager
+ Items []moduleLib.CompositeProfile
+ Err error
+}
+
+func (m *mockCompositeProfileManager) CreateCompositeProfile(inp moduleLib.CompositeProfile, p string, ca string,
+ v string) (moduleLib.CompositeProfile, error) {
+ if m.Err != nil {
+ return moduleLib.CompositeProfile{}, m.Err
+ }
+
+ return m.Items[0], nil
+}
+
+func (m *mockCompositeProfileManager) GetCompositeProfile(name string, projectName string,
+ compositeAppName string, version string) (moduleLib.CompositeProfile, error) {
+ if m.Err != nil {
+ return moduleLib.CompositeProfile{}, m.Err
+ }
+
+ return m.Items[0], nil
+}
+
+func (m *mockCompositeProfileManager) GetCompositeProfiles(projectName string,
+ compositeAppName string, version string) ([]moduleLib.CompositeProfile, error) {
+ if m.Err != nil {
+ return []moduleLib.CompositeProfile{}, m.Err
+ }
+
+ return m.Items, nil
+}
+
+func (m *mockCompositeProfileManager) DeleteCompositeProfile(name string, projectName string,
+ compositeAppName string, version string) error {
+ return m.Err
+}
+
+func Test_compositeProfileHandler_createHandler(t *testing.T) {
+ testCases := []struct {
+ label string
+ reader io.Reader
+ expected moduleLib.CompositeProfile
+ expectedCode int
+ cProfClient *mockCompositeProfileManager
+ }{
+ {
+ label: "Missing Body Failure",
+ expectedCode: http.StatusBadRequest,
+ cProfClient: &mockCompositeProfileManager{},
+ },
+ {
+ label: "Create Composite Profile",
+ expectedCode: http.StatusCreated,
+ reader: bytes.NewBuffer([]byte(`{
+ "metadata" : {
+ "name": "testCompositeProfile",
+ "description": "Test CompositeProfile used for unit testing",
+ "userData1": "data1",
+ "userData2": "data2"
+ }
+ }`)),
+ expected: moduleLib.CompositeProfile{
+ Metadata: moduleLib.CompositeProfileMetadata{
+ Name: "testCompositeProfile",
+ Description: "Test CompositeProfile used for unit testing",
+ UserData1: "data1",
+ UserData2: "data2",
+ },
+ },
+ cProfClient: &mockCompositeProfileManager{
+ //Items that will be returned by the mocked Client
+ Items: []moduleLib.CompositeProfile{
+ moduleLib.CompositeProfile{
+ Metadata: moduleLib.CompositeProfileMetadata{
+ Name: "testCompositeProfile",
+ Description: "Test CompositeProfile used for unit testing",
+ UserData1: "data1",
+ UserData2: "data2",
+ },
+ },
+ },
+ },
+ },
+ {
+ label: "Missing Composite Profile Name in Request Body",
+ reader: bytes.NewBuffer([]byte(`{
+ "description":"test description"
+ }`)),
+ expectedCode: http.StatusBadRequest,
+ cProfClient: &mockCompositeProfileManager{},
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ request := httptest.NewRequest("POST", "/v2/projects/{project-name}/composite-apps/{composite-app-name}/{version}/composite-profiles", testCase.reader)
+ resp := executeRequest(request, NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, testCase.cProfClient))
+
+ //Check returned code
+ if resp.StatusCode != testCase.expectedCode {
+ t.Fatalf("Expected %d; Got: %d", testCase.expectedCode, resp.StatusCode)
+ }
+
+ //Check returned body only if statusCreated
+ if resp.StatusCode == http.StatusCreated {
+ got := moduleLib.CompositeProfile{}
+ json.NewDecoder(resp.Body).Decode(&got)
+
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("createHandler returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+ })
+ }
+
+}
diff --git a/src/orchestrator/api/controllerhandler_test.go b/src/orchestrator/api/controllerhandler_test.go
index dd542de7..a195cb83 100644
--- a/src/orchestrator/api/controllerhandler_test.go
+++ b/src/orchestrator/api/controllerhandler_test.go
@@ -110,7 +110,7 @@ func TestControllerCreateHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("POST", "/v2/controllers", testCase.reader)
- resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -173,7 +173,7 @@ func TestControllerGetHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/controllers/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -222,7 +222,7 @@ func TestControllerDeleteHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("DELETE", "/v2/controllers/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
diff --git a/src/orchestrator/api/projecthandler_test.go b/src/orchestrator/api/projecthandler_test.go
index eccccb90..547420b3 100644
--- a/src/orchestrator/api/projecthandler_test.go
+++ b/src/orchestrator/api/projecthandler_test.go
@@ -119,7 +119,7 @@ func TestProjectCreateHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("POST", "/v2/projects", testCase.reader)
- resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -188,7 +188,7 @@ func TestProjectGetHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("GET", "/v2/projects/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
@@ -237,7 +237,7 @@ func TestProjectDeleteHandler(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
request := httptest.NewRequest("DELETE", "/v2/projects/"+testCase.name, nil)
- resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil))
+ resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil, nil))
//Check returned code
if resp.StatusCode != testCase.expectedCode {
diff --git a/src/orchestrator/cmd/main.go b/src/orchestrator/cmd/main.go
index 9296a54c..0385416e 100644
--- a/src/orchestrator/cmd/main.go
+++ b/src/orchestrator/cmd/main.go
@@ -47,7 +47,7 @@ func main() {
log.Fatalln("Exiting...")
}
- httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil, nil, nil)
+ httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil, nil, nil, nil)
loggedRouter := handlers.LoggingHandler(os.Stdout, httpRouter)
log.Println("Starting Kubernetes Multicloud API")
diff --git a/src/orchestrator/pkg/module/composite_profile.go b/src/orchestrator/pkg/module/composite_profile.go
new file mode 100644
index 00000000..dca2116a
--- /dev/null
+++ b/src/orchestrator/pkg/module/composite_profile.go
@@ -0,0 +1,192 @@
+/*
+ * 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 (
+ "encoding/json"
+
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
+
+ pkgerrors "github.com/pkg/errors"
+)
+
+// CompositeProfile contains the parameters needed for CompositeProfiles
+// It implements the interface for managing the CompositeProfiles
+type CompositeProfile struct {
+ Metadata CompositeProfileMetadata `json:"metadata"`
+}
+
+// CompositeProfileMetadata contains the metadata for CompositeProfiles
+type CompositeProfileMetadata struct {
+ Name string `json:"name"`
+ Description string `json:"description"`
+ UserData1 string `json:"userData1"`
+ UserData2 string `json:"userData2"`
+}
+
+// CompositeProfileKey is the key structure that is used in the database
+type CompositeProfileKey struct {
+ Name string `json:"compositeprofile"`
+ Project string `json:"project"`
+ CompositeApp string `json:"compositeapp"`
+ Version string `json:"compositeappversion"`
+}
+
+// We will use json marshalling to convert to string to
+// preserve the underlying structure.
+func (cpk CompositeProfileKey) String() string {
+ out, err := json.Marshal(cpk)
+ if err != nil {
+ return ""
+ }
+
+ return string(out)
+}
+
+// CompositeProfileManager exposes the CompositeProfile functionality
+type CompositeProfileManager interface {
+ CreateCompositeProfile(cpf CompositeProfile, p string, ca string,
+ v string) (CompositeProfile, error)
+ GetCompositeProfile(compositeProfileName string, projectName string,
+ compositeAppName string, version string) (CompositeProfile, error)
+ GetCompositeProfiles(projectName string, compositeAppName string,
+ version string) ([]CompositeProfile, error)
+ DeleteCompositeProfile(compositeProfileName string, projectName string,
+ compositeAppName string, version string) error
+}
+
+// CompositeProfileClient implements the Manager
+// It will also be used to maintain some localized state
+type CompositeProfileClient struct {
+ storeName string
+ tagMeta string
+}
+
+// NewCompositeProfileClient returns an instance of the CompositeProfileClient
+// which implements the Manager
+func NewCompositeProfileClient() *CompositeProfileClient {
+ return &CompositeProfileClient{
+ storeName: "orchestrator",
+ tagMeta: "compositeprofilemetadata",
+ }
+}
+
+// CreateCompositeProfile creates an entry for CompositeProfile in the database. Other Input parameters for it - projectName, compositeAppName, version
+func (c *CompositeProfileClient) CreateCompositeProfile(cpf CompositeProfile, p string, ca string,
+ v string) (CompositeProfile, error) {
+
+ res, err := c.GetCompositeProfile(cpf.Metadata.Name, p, ca, v)
+ if res != (CompositeProfile{}) {
+ return CompositeProfile{}, pkgerrors.New("CompositeProfile already exists")
+ }
+
+ //Check if project exists
+ _, err = NewProjectClient().GetProject(p)
+ if err != nil {
+ return CompositeProfile{}, pkgerrors.New("Unable to find the project")
+ }
+
+ // check if compositeApp exists
+ _, err = NewCompositeAppClient().GetCompositeApp(ca, v, p)
+ if err != nil {
+ return CompositeProfile{}, pkgerrors.New("Unable to find the composite-app")
+ }
+
+ cProfkey := CompositeProfileKey{
+ Name: cpf.Metadata.Name,
+ Project: p,
+ CompositeApp: ca,
+ Version: v,
+ }
+
+ err = db.DBconn.Insert(c.storeName, cProfkey, nil, c.tagMeta, cpf)
+ if err != nil {
+ return CompositeProfile{}, pkgerrors.Wrap(err, "Create DB entry error")
+ }
+
+ return cpf, nil
+}
+
+// GetCompositeProfile shall take arguments - name of the composite profile, name of //// the project, name of the composite app and version of the composite app. It shall return the CompositeProfile if its present.
+func (c *CompositeProfileClient) GetCompositeProfile(cpf string, p string, ca string, v string) (CompositeProfile, error) {
+ key := CompositeProfileKey{
+ Name: cpf,
+ Project: p,
+ CompositeApp: ca,
+ Version: v,
+ }
+
+ result, err := db.DBconn.Find(c.storeName, key, c.tagMeta)
+ if err != nil {
+ return CompositeProfile{}, pkgerrors.Wrap(err, "Get Composite Profile error")
+ }
+
+ if result != nil {
+ cProf := CompositeProfile{}
+ err = db.DBconn.Unmarshal(result[0], &cProf)
+ if err != nil {
+ return CompositeProfile{}, pkgerrors.Wrap(err, "Unmarshalling CompositeProfile")
+ }
+ return cProf, nil
+ }
+
+ return CompositeProfile{}, pkgerrors.New("Error getting CompositeProfile")
+}
+
+// GetCompositeProfile shall take arguments - name of the composite profile, name of //// the project, name of the composite app and version of the composite app. It shall return the CompositeProfile if its present.
+func (c *CompositeProfileClient) GetCompositeProfiles(p string, ca string, v string) ([]CompositeProfile, error) {
+ key := CompositeProfileKey{
+ Name: "",
+ Project: p,
+ CompositeApp: ca,
+ Version: v,
+ }
+
+ values, err := db.DBconn.Find(c.storeName, key, c.tagMeta)
+ if err != nil {
+ return []CompositeProfile{}, pkgerrors.Wrap(err, "Get Composite Profiles error")
+ }
+
+ var resp []CompositeProfile
+
+ for _, value := range values {
+ cp := CompositeProfile{}
+ err = db.DBconn.Unmarshal(value, &cp)
+ if err != nil {
+ return []CompositeProfile{}, pkgerrors.Wrap(err, "Get Composite Profiles unmarshalling error")
+ }
+ resp = append(resp, cp)
+ }
+
+ return resp, nil
+}
+
+// DeleteCompositeProfile the intent from the database
+func (c *CompositeProfileClient) DeleteCompositeProfile(cpf string, p string, ca string, v string) error {
+ key := CompositeProfileKey{
+ Name: cpf,
+ Project: p,
+ CompositeApp: ca,
+ Version: v,
+ }
+
+ err := db.DBconn.Remove(c.storeName, key)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Delete CompositeProfile entry;")
+ }
+ return nil
+}
diff --git a/src/orchestrator/pkg/module/composite_profile_test.go b/src/orchestrator/pkg/module/composite_profile_test.go
new file mode 100644
index 00000000..af0dd7b7
--- /dev/null
+++ b/src/orchestrator/pkg/module/composite_profile_test.go
@@ -0,0 +1,175 @@
+/*
+ * 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
+
+//pkgerrors "github.com/pkg/errors"
+
+/* TODO - db.MockDB needs to be enhanced and then these can be fixed up
+func TestCreateCompositeProfile(t *testing.T) {
+ testCases := []struct {
+ label string
+ compositeProfile CompositeProfile
+ projectName string
+ compositeApp string
+ compositeAppVersion string
+ expectedError string
+ mockdb *db.MockDB
+ expected CompositeProfile
+ }{
+ {
+ label: "Create CompositeProfile",
+ compositeProfile: CompositeProfile{
+ Metadata: CompositeProfileMetadata{
+ Name: "testCompositeProfile",
+ Description: "A sample Composite Profile for testing",
+ UserData1: "userData1",
+ UserData2: "userData2",
+ },
+ },
+ projectName: "testProject",
+ compositeApp: "testCompositeApp",
+ compositeAppVersion: "v1",
+ expected: CompositeProfile{
+ Metadata: CompositeProfileMetadata{
+ Name: "testCompositeProfile",
+ Description: "A sample Composite Profile for 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", Project: "testProject", Version: "v1"}.String(): {
+ "compositeAppmetadata": []byte(
+ "{" +
+ "\"metadata\" : {" +
+ "\"Name\":\"testCompositeApp\"," +
+ "\"Description\":\"Test Composite App 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
+ cprofCli := NewCompositeProfileClient()
+ got, err := cprofCli.CreateCompositeProfile(testCase.compositeProfile, testCase.projectName, testCase.compositeApp, testCase.compositeAppVersion)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("CreateCompositeProfile returned an unexpected error %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("CreateCompositeProfile returned an unexpected error %s", err)
+ }
+ } else {
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("CreateCompositeProfile returned unexpected body: got %v; "+" expected %v", got, testCase.expected)
+ }
+ }
+ })
+
+ }
+}
+
+func TestGetCompositeProfile(t *testing.T) {
+
+ testCases := []struct {
+ label string
+ expectedError string
+ expected CompositeProfile
+ mockdb *db.MockDB
+ compositeProfileName string
+ projectName string
+ compositeAppName string
+ compositeAppVersion string
+ }{
+ {
+ label: "Get CompositeProfile",
+ compositeProfileName: "testCompositeProfile",
+ projectName: "testProject",
+ compositeAppName: "testCompositeApp",
+ compositeAppVersion: "v1",
+ expected: CompositeProfile{
+ Metadata: CompositeProfileMetadata{
+ Name: "testCompositeProfile",
+ Description: "A sample CompositeProfile for testing",
+ UserData1: "userData1",
+ UserData2: "userData2",
+ },
+ },
+ expectedError: "",
+ mockdb: &db.MockDB{
+ Items: map[string]map[string][]byte{
+ CompositeProfileKey{
+ Name: "testCompositeProfile",
+ Project: "testProject",
+ CompositeApp: "testCompositeApp",
+ Version: "v1",
+ }.String(): {
+ "compositeprofile": []byte(
+ "{\"metadata\":{\"Name\":\"testCompositeProfile\"," +
+ "\"Description\":\"A sample CompositeProfile for testing\"," +
+ "\"UserData1\": \"userData1\"," +
+ "\"UserData2\": \"userData2\"}}"),
+ },
+ },
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.label, func(t *testing.T) {
+ db.DBconn = testCase.mockdb
+ cprofCli := NewCompositeProfileClient()
+ got, err := cprofCli.GetCompositeProfile(testCase.compositeProfileName, testCase.projectName, testCase.compositeAppName, testCase.compositeAppVersion)
+ if err != nil {
+ if testCase.expectedError == "" {
+ t.Fatalf("GetCompositeProfile returned an unexpected error: %s", err)
+ }
+ if strings.Contains(err.Error(), testCase.expectedError) == false {
+ t.Fatalf("GetCompositeProfile returned an unexpected error: %s", err)
+ }
+ } else {
+ if reflect.DeepEqual(testCase.expected, got) == false {
+ t.Errorf("GetCompositeProfile returned unexpected body: got %v;"+
+ " expected %v", got, testCase.expected)
+ }
+ }
+
+ })
+ }
+
+}
+*/
diff --git a/src/orchestrator/pkg/module/module.go b/src/orchestrator/pkg/module/module.go
index b46c6068..fb46b895 100644
--- a/src/orchestrator/pkg/module/module.go
+++ b/src/orchestrator/pkg/module/module.go
@@ -24,23 +24,24 @@ type Client struct {
Cluster *ClusterClient
GenericPlacementIntent *GenericPlacementIntentClient
AppIntent *AppIntentClient
+ DeploymentIntentGroup *DeploymentIntentGroupClient
+ Intent *IntentClient
+ CompositeProfile *CompositeProfileClient
// Add Clients for API's here
- DeploymentIntentGroup *DeploymentIntentGroupClient
- Intent *IntentClient
}
// NewClient creates a new client for using the services
func NewClient() *Client {
c := &Client{}
- // Add Client API handlers here
c.Project = NewProjectClient()
c.CompositeApp = NewCompositeAppClient()
c.Controller = NewControllerClient()
c.Cluster = NewClusterClient()
- // Add Client API handlers here
c.GenericPlacementIntent = NewGenericPlacementIntentClient()
c.AppIntent = NewAppIntentClient()
c.DeploymentIntentGroup = NewDeploymentIntentGroupClient()
c.Intent = NewIntentClient()
+ c.CompositeProfile = NewCompositeProfileClient()
+ // Add Client API handlers here
return c
}