Add DeploymentIntentGroup APIs 55/102355/6
authorRajamohan Raj <rajamohan.raj@intel.com>
Wed, 26 Feb 2020 02:07:34 +0000 (02:07 +0000)
committerRajamohan Raj <rajamohan.raj@intel.com>
Wed, 4 Mar 2020 23:43:43 +0000 (23:43 +0000)
Implemented the routes for creation,
deletion and getting DeploymentIntentGroup.

Added routes for adding, getting and deleting intents.

Issue-ID: MULTICLOUD-1002
Signed-off-by: Rajamohan Raj <rajamohan.raj@intel.com>
Change-Id: I07ba3744107bcf30aa30ed89caa21bf474c0d92a

16 files changed:
src/orchestrator/api/add_intents_handler.go [new file with mode: 0644]
src/orchestrator/api/api.go
src/orchestrator/api/clusterhandler.go
src/orchestrator/api/clusterhandler_test.go
src/orchestrator/api/controllerhandler_test.go
src/orchestrator/api/deployment_intent_groups_handler.go [new file with mode: 0644]
src/orchestrator/api/projecthandler_test.go
src/orchestrator/cmd/main.go
src/orchestrator/go.mod
src/orchestrator/go.sum
src/orchestrator/pkg/module/add_intents.go [new file with mode: 0644]
src/orchestrator/pkg/module/deployment_intent_groups.go [new file with mode: 0644]
src/orchestrator/pkg/module/deployment_intent_groups_test.go [new file with mode: 0644]
src/orchestrator/pkg/module/generic_placement_intent.go
src/orchestrator/pkg/module/generic_placement_intent_test.go
src/orchestrator/pkg/module/module.go

diff --git a/src/orchestrator/api/add_intents_handler.go b/src/orchestrator/api/add_intents_handler.go
new file mode 100644 (file)
index 0000000..dfe1a49
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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"
+)
+
+type intentHandler struct {
+       client moduleLib.IntentManager
+}
+
+func (h intentHandler) addIntentHandler(w http.ResponseWriter, r *http.Request) {
+       var i moduleLib.Intent
+
+       err := json.NewDecoder(r.Body).Decode(&i)
+       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 i.MetaData.Name == "" {
+               http.Error(w, "Missing Intent in POST request", http.StatusBadRequest)
+               return
+       }
+
+       vars := mux.Vars(r)
+       p := vars["project-name"]
+       ca := vars["composite-app-name"]
+       v := vars["composite-app-version"]
+       d := vars["deployment-intent-group-name"]
+
+       intent, addError := h.client.AddIntent(i, p, ca, v, d)
+       if addError != nil {
+               http.Error(w, addError.Error(), http.StatusInternalServerError)
+               return
+       }
+
+       w.Header().Set("Content-Type", "application/json")
+       w.WriteHeader(http.StatusCreated)
+       err = json.NewEncoder(w).Encode(intent)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+}
+
+func (h intentHandler) getIntentHandler(w http.ResponseWriter, r *http.Request) {
+
+       vars := mux.Vars(r)
+
+       i := vars["intent-name"]
+       if i == "" {
+               http.Error(w, "Missing intentName in GET request", http.StatusBadRequest)
+               return
+       }
+
+       p := vars["project-name"]
+       if p == "" {
+               http.Error(w, "Missing projectName in GET request", http.StatusBadRequest)
+               return
+       }
+       ca := vars["composite-app-name"]
+       if ca == "" {
+               http.Error(w, "Missing compositeAppName in GET request", http.StatusBadRequest)
+               return
+       }
+
+       v := vars["composite-app-version"]
+       if v == "" {
+               http.Error(w, "Missing version of compositeApp in GET request", http.StatusBadRequest)
+               return
+       }
+
+       di := vars["deployment-intent-group-name"]
+       if di == "" {
+               http.Error(w, "Missing name of DeploymentIntentGroup in GET request", http.StatusBadRequest)
+               return
+       }
+
+       intent, err := h.client.GetIntent(i, p, ca, v, di)
+       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(intent)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+}
+
+func (h intentHandler) deleteIntentHandler(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+
+       i := vars["intent-name"]
+       p := vars["project-name"]
+       ca := vars["composite-app-name"]
+       v := vars["composite-app-version"]
+       di := vars["deployment-intent-group-name"]
+
+       err := h.client.DeleteIntent(i, p, ca, v, di)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+       w.WriteHeader(http.StatusNoContent)
+}
index f4381e6..f3e3b17 100644 (file)
@@ -28,7 +28,9 @@ func NewRouter(projectClient moduleLib.ProjectManager,
        ControllerClient moduleLib.ControllerManager,
        clusterClient moduleLib.ClusterManager,
        genericPlacementIntentClient moduleLib.GenericPlacementIntentManager,
-       appIntentClient moduleLib.AppIntentManager) *mux.Router {
+       appIntentClient moduleLib.AppIntentManager,
+       deploymentIntentGrpClient moduleLib.DeploymentIntentGroupManager,
+       intentClient moduleLib.IntentManager) *mux.Router {
 
        router := mux.NewRouter().PathPrefix("/v2").Subrouter()
 
@@ -114,5 +116,30 @@ func NewRouter(projectClient moduleLib.ProjectManager,
        router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}/app-intents/{app-intent-name}", appIntentHandler.getAppIntentHandler).Methods("GET")
        router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/generic-placement-intents/{intent-name}/app-intents/{app-intent-name}", appIntentHandler.deleteAppIntentHandler).Methods("DELETE")
 
+       //setting routes for deploymentIntentGroup
+       if deploymentIntentGrpClient == nil {
+               deploymentIntentGrpClient = moduleClient.DeploymentIntentGroup
+       }
+
+       deploymentIntentGrpHandler := deploymentIntentGroupHandler{
+               client: deploymentIntentGrpClient,
+       }
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups", deploymentIntentGrpHandler.createDeploymentIntentGroupHandler).Methods("POST")
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}", deploymentIntentGrpHandler.getDeploymentIntentGroupHandler).Methods("GET")
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}", deploymentIntentGrpHandler.deleteDeploymentIntentGroupHandler).Methods("DELETE")
+
+       // setting routes for AddingIntents
+       if intentClient == nil {
+               intentClient = moduleClient.Intent
+       }
+
+       intentHandler := intentHandler{
+               client: intentClient,
+       }
+
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/intents", intentHandler.addIntentHandler).Methods("POST")
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/intents/{intent-name}", intentHandler.getIntentHandler).Methods("GET")
+       router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/intents/{intent-name}", intentHandler.deleteIntentHandler).Methods("DELETE")
+
        return router
 }
index 7e769f3..ac4191e 100644 (file)
@@ -255,12 +255,12 @@ func (h clusterHandler) getClusterHandler(w http.ResponseWriter, r *http.Request
                        http.Error(w, err.Error(), http.StatusInternalServerError)
                        return
                }
-               kc_bytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig)
+               kcBytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig)
                if err != nil {
                        http.Error(w, err.Error(), http.StatusInternalServerError)
                        return
                }
-               _, err = pw.Write(kc_bytes)
+               _, err = pw.Write(kcBytes)
                if err != nil {
                        http.Error(w, err.Error(), http.StatusInternalServerError)
                        return
@@ -276,12 +276,12 @@ func (h clusterHandler) getClusterHandler(w http.ResponseWriter, r *http.Request
        case "application/octet-stream":
                w.Header().Set("Content-Type", "application/octet-stream")
                w.WriteHeader(http.StatusOK)
-               kc_bytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig)
+               kcBytes, err := base64.StdEncoding.DecodeString(retKubeconfig.Kubeconfig)
                if err != nil {
                        http.Error(w, err.Error(), http.StatusInternalServerError)
                        return
                }
-               _, err = w.Write(kc_bytes)
+               _, err = w.Write(kcBytes)
                if err != nil {
                        http.Error(w, err.Error(), http.StatusInternalServerError)
                        return
index ad7635e..a32bf02 100644 (file)
@@ -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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, nil, testCase.clusterClient, nil, nil, nil, nil))
 
                        //Check returned code
                        if resp.StatusCode != testCase.expectedCode {
index bcc06f9..dd542de 100644 (file)
@@ -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))
+                       resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, 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))
+                       resp := executeRequest(request, NewRouter(nil, nil, testCase.controllerClient, nil, nil, nil, nil, nil))
 
                        //Check returned code
                        if resp.StatusCode != testCase.expectedCode {
diff --git a/src/orchestrator/api/deployment_intent_groups_handler.go b/src/orchestrator/api/deployment_intent_groups_handler.go
new file mode 100644 (file)
index 0000000..3f5b396
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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 deploymentIntentGroupHandler struct {
+       client moduleLib.DeploymentIntentGroupManager
+}
+
+// createDeploymentIntentGroupHandler handles the create operation of DeploymentIntentGroup
+func (h deploymentIntentGroupHandler) createDeploymentIntentGroupHandler(w http.ResponseWriter, r *http.Request) {
+
+       var d moduleLib.DeploymentIntentGroup
+
+       err := json.NewDecoder(r.Body).Decode(&d)
+       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 d.MetaData.Name == "" {
+               http.Error(w, "Missing deploymentIntentGroupName in POST request", http.StatusBadRequest)
+               return
+       }
+
+       vars := mux.Vars(r)
+       projectName := vars["project-name"]
+       compositeAppName := vars["composite-app-name"]
+       version := vars["composite-app-version"]
+
+       dIntent, createErr := h.client.CreateDeploymentIntentGroup(d, 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(dIntent)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+}
+
+func (h deploymentIntentGroupHandler) getDeploymentIntentGroupHandler(w http.ResponseWriter, r *http.Request) {
+
+       vars := mux.Vars(r)
+
+       p := vars["project-name"]
+       if p == "" {
+               http.Error(w, "Missing projectName in GET request", http.StatusBadRequest)
+               return
+       }
+       ca := vars["composite-app-name"]
+       if ca == "" {
+               http.Error(w, "Missing compositeAppName in GET request", http.StatusBadRequest)
+               return
+       }
+
+       v := vars["composite-app-version"]
+       if v == "" {
+               http.Error(w, "Missing version of compositeApp in GET request", http.StatusBadRequest)
+               return
+       }
+
+       di := vars["deployment-intent-group-name"]
+       if v == "" {
+               http.Error(w, "Missing name of DeploymentIntentGroup in GET request", http.StatusBadRequest)
+               return
+       }
+
+       dIntentGrp, err := h.client.GetDeploymentIntentGroup(di, p, ca, v)
+       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(dIntentGrp)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+
+}
+
+func (h deploymentIntentGroupHandler) deleteDeploymentIntentGroupHandler(w http.ResponseWriter, r *http.Request) {
+       vars := mux.Vars(r)
+
+       p := vars["project-name"]
+       ca := vars["composite-app-name"]
+       v := vars["composite-app-version"]
+       di := vars["deployment-intent-group-name"]
+
+       err := h.client.DeleteDeploymentIntentGroup(di, p, ca, v)
+       if err != nil {
+               http.Error(w, err.Error(), http.StatusInternalServerError)
+               return
+       }
+       w.WriteHeader(http.StatusNoContent)
+}
index 84e6752..eccccb9 100644 (file)
@@ -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))
+                       resp := executeRequest(request, NewRouter(testCase.projectClient, 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))
+                       resp := executeRequest(request, NewRouter(testCase.projectClient, 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))
+                       resp := executeRequest(request, NewRouter(testCase.projectClient, nil, nil, nil, nil, nil, nil, nil))
 
                        //Check returned code
                        if resp.StatusCode != testCase.expectedCode {
index cf1faf4..9296a54 100644 (file)
@@ -47,7 +47,7 @@ func main() {
                log.Fatalln("Exiting...")
        }
 
-       httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil)
+       httpRouter := api.NewRouter(nil, nil, nil, nil, nil, nil, nil, nil)
        loggedRouter := handlers.LoggingHandler(os.Stdout, httpRouter)
        log.Println("Starting Kubernetes Multicloud API")
 
index d6fada4..547fa8e 100644 (file)
@@ -1,6 +1,7 @@
 module github.com/onap/multicloud-k8s/src/orchestrator
 
 require (
+       github.com/coreos/etcd v3.3.12+incompatible
        github.com/docker/engine v0.0.0-20190620014054-c513a4c6c298
        github.com/ghodss/yaml v1.0.0
        github.com/gogo/protobuf v1.3.1 // indirect
@@ -32,3 +33,5 @@ replace (
        k8s.io/client-go => k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
        k8s.io/cloud-provider => k8s.io/cloud-provider v0.0.0-20190409023720-1bc0c81fa51d
 )
+
+go 1.13
index d201540..aeab3b5 100644 (file)
@@ -172,6 +172,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/onap/multicloud-k8s v0.0.0-20191115005109-f168ebb73d8d h1:3uFucXVv6gqa3H1u85CjoLOvGraREfD8/NL7m/9W9tc=
 github.com/onap/multicloud-k8s v0.0.0-20200131010833-90e13d101cf0 h1:2qDo6s4pdg/g7Vj6QGrCK02EP4jjwVehgEObnAfipSM=
+github.com/onap/multicloud-k8s v0.0.0-20200229013830-7b566f287523 h1:hVu6djUEav5nKQvVZZa3FT71ZD9QbCcTI3dM+1chvFU=
 github.com/onap/multicloud-k8s/src/k8splugin v0.0.0-20191115005109-f168ebb73d8d h1:ucIEjqzNVeFPnQofeuBfUqro0OnilX//fajEFxuLsgA=
 github.com/onap/multicloud-k8s/src/k8splugin v0.0.0-20191115005109-f168ebb73d8d/go.mod h1:EnQd/vQGZR1/55IihaHxiux4ZUig/zfXZux7bfmU0S8=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
diff --git a/src/orchestrator/pkg/module/add_intents.go b/src/orchestrator/pkg/module/add_intents.go
new file mode 100644 (file)
index 0000000..a657cce
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * 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 Addlicable 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"
+       "reflect"
+
+       "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
+
+       pkgerrors "github.com/pkg/errors"
+)
+
+// Intent shall have 2 fields - MetaData and Spec
+type Intent struct {
+       MetaData IntentMetaData `json:"metadata"`
+       Spec     IntentSpecData `json:"spec"`
+}
+
+// IntentMetaData has Name, Description, userdata1, userdata2
+type IntentMetaData struct {
+       Name        string `json:"name"`
+       Description string `json:"description"`
+       UserData1   string `json:"userData1"`
+       UserData2   string `json:"userData2"`
+}
+
+// IntentSpecData has Intent
+type IntentSpecData struct {
+       Intent IntentObj `json:"intent"`
+}
+
+// IntentObj has name of the generic placement intent
+type IntentObj struct {
+       Generic string `json:"generic"`
+}
+
+// ListOfIntents is a list of intents
+type ListOfIntents struct {
+       ListOfIntents []map[string]string `json:"intent"`
+}
+
+// IntentManager is an interface which exposes the IntentManager functionality
+type IntentManager interface {
+       AddIntent(a Intent, p string, ca string, v string, di string) (Intent, error)
+       GetIntent(i string, p string, ca string, v string, di string) (Intent, error)
+       DeleteIntent(i string, p string, ca string, v string, di string) error
+}
+
+// IntentKey consists of Name if the intent, Project name, CompositeApp name,
+// CompositeApp version
+type IntentKey struct {
+       Name                  string `json:"name"`
+       Project               string `json:"project"`
+       CompositeApp          string `json:"compositeapp"`
+       Version               string `json:"version"`
+       DeploymentIntentGroup string `json:"deployment-intent-group-name"`
+}
+
+// We will use json marshalling to convert to string to
+// preserve the underlying structure.
+func (ik IntentKey) String() string {
+       out, err := json.Marshal(ik)
+       if err != nil {
+               return ""
+       }
+       return string(out)
+}
+
+// IntentClient implements the AddIntentManager interface
+type IntentClient struct {
+       storeName   string
+       tagMetaData string
+}
+
+// NewIntentClient returns an instance of AddIntentClient
+func NewIntentClient() *IntentClient {
+       return &IntentClient{
+               storeName:   "orchestrator",
+               tagMetaData: "addintent",
+       }
+}
+
+// AddIntent adds a given intent to the deployment-intent-group and stores in the db. Other input parameters for it - projectName, compositeAppName, version, DeploymentIntentgroupName
+func (c *IntentClient) AddIntent(a Intent, p string, ca string, v string, di string) (Intent, error) {
+
+       //Check for the AddIntent already exists here.
+       res, err := c.GetIntent(a.MetaData.Name, p, ca, v, di)
+       if !reflect.DeepEqual(res, Intent{}) {
+               return Intent{}, pkgerrors.New("AppIntent already exists")
+       }
+
+       //Check if project exists
+       _, err = NewProjectClient().GetProject(p)
+       if err != nil {
+               return Intent{}, pkgerrors.New("Unable to find the project")
+       }
+
+       //check if compositeApp exists
+       _, err = NewCompositeAppClient().GetCompositeApp(ca, v, p)
+       if err != nil {
+               return Intent{}, pkgerrors.New("Unable to find the composite-app")
+       }
+
+       //check if DeploymentIntentGroup exists
+       _, err = NewDeploymentIntentGroupClient().GetDeploymentIntentGroup(di, p, ca, v)
+       if err != nil {
+               return Intent{}, pkgerrors.New("Unable to find the intent")
+       }
+
+       akey := IntentKey{
+               Name:                  a.MetaData.Name,
+               Project:               p,
+               CompositeApp:          ca,
+               Version:               v,
+               DeploymentIntentGroup: di,
+       }
+
+       err = db.DBconn.Insert(c.storeName, akey, nil, c.tagMetaData, a)
+       if err != nil {
+               return Intent{}, pkgerrors.Wrap(err, "Create DB entry error")
+       }
+       return a, nil
+}
+
+// GetIntent returns an Intent
+func (c *IntentClient) GetIntent(i string, p string, ca string, v string, di string) (Intent, error) {
+
+       k := IntentKey{
+               Name:                  i,
+               Project:               p,
+               CompositeApp:          ca,
+               Version:               v,
+               DeploymentIntentGroup: di,
+       }
+
+       result, err := db.DBconn.Find(c.storeName, k, c.tagMetaData)
+       if err != nil {
+               return Intent{}, pkgerrors.Wrap(err, "Get AppIntent error")
+       }
+
+       if result != nil {
+               a := Intent{}
+               err = db.DBconn.Unmarshal(result[0], &a)
+               if err != nil {
+                       return Intent{}, pkgerrors.Wrap(err, "Unmarshalling  AppIntent")
+               }
+               return a, nil
+
+       }
+       return Intent{}, pkgerrors.New("Error getting AppIntent")
+}
+
+// DeleteIntent deletes a given intent tied to project, composite app and deployment intent group
+func (c IntentClient) DeleteIntent(i string, p string, ca string, v string, di string) error {
+       k := IntentKey{
+               Name:                  i,
+               Project:               p,
+               CompositeApp:          ca,
+               Version:               v,
+               DeploymentIntentGroup: di,
+       }
+
+       err := db.DBconn.Remove(c.storeName, k)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Delete Project entry;")
+       }
+       return nil
+
+}
diff --git a/src/orchestrator/pkg/module/deployment_intent_groups.go b/src/orchestrator/pkg/module/deployment_intent_groups.go
new file mode 100644 (file)
index 0000000..fe62277
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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"
+       "reflect"
+
+       pkgerrors "github.com/pkg/errors"
+)
+
+// DeploymentIntentGroup shall have 2 fields - MetaData and Spec
+type DeploymentIntentGroup struct {
+       MetaData DepMetaData `json:"metadata"`
+       Spec     DepSpecData `json:"spec"`
+}
+
+// DepMetaData has Name, description, userdata1, userdata2
+type DepMetaData struct {
+       Name        string `json:"name"`
+       Description string `json:"description"`
+       UserData1   string `json:"userData1"`
+       UserData2   string `json:"userData2"`
+}
+
+// DepSpecData has profile, version, OverrideValuesObj
+type DepSpecData struct {
+       Profile           string           `json:"profile"`
+       Version           string           `json:"version"`
+       OverrideValuesObj []OverrideValues `json:"override-values"`
+}
+
+// OverrideValues has appName and ValuesObj
+type OverrideValues struct {
+       AppName   string            `json:"app-name"`
+       ValuesObj map[string]string `json:"values"`
+}
+
+// Values has ImageRepository
+// type Values struct {
+//     ImageRepository string `json:"imageRepository"`
+// }
+
+// DeploymentIntentGroupManager is an interface which exposes the DeploymentIntentGroupManager functionality
+type DeploymentIntentGroupManager interface {
+       CreateDeploymentIntentGroup(d DeploymentIntentGroup, p string, ca string, v string) (DeploymentIntentGroup, error)
+       GetDeploymentIntentGroup(di string, p string, ca string, v string) (DeploymentIntentGroup, error)
+       DeleteDeploymentIntentGroup(di string, p string, ca string, v string) error
+}
+
+// DeploymentIntentGroupKey consists of Name of the deployment group, project name, CompositeApp name, CompositeApp version
+type DeploymentIntentGroupKey struct {
+       Name         string `json:"name"`
+       Project      string `json:"project"`
+       CompositeApp string `json:"compositeapp"`
+       Version      string `json:"version"`
+}
+
+// We will use json marshalling to convert to string to
+// preserve the underlying structure.
+func (dk DeploymentIntentGroupKey) String() string {
+       out, err := json.Marshal(dk)
+       if err != nil {
+               return ""
+       }
+       return string(out)
+}
+
+// DeploymentIntentGroupClient implements the DeploymentIntentGroupManager interface
+type DeploymentIntentGroupClient struct {
+       storeName   string
+       tagMetaData string
+}
+
+// NewDeploymentIntentGroupClient return an instance of DeploymentIntentGroupClient which implements DeploymentIntentGroupManager
+func NewDeploymentIntentGroupClient() *DeploymentIntentGroupClient {
+       return &DeploymentIntentGroupClient{
+               storeName:   "orchestrator",
+               tagMetaData: "deploymentintentgroup",
+       }
+}
+
+// CreateDeploymentIntentGroup creates an entry for a given  DeploymentIntentGroup in the database. Other Input parameters for it - projectName, compositeAppName, version
+func (c *DeploymentIntentGroupClient) CreateDeploymentIntentGroup(d DeploymentIntentGroup, p string, ca string,
+       v string) (DeploymentIntentGroup, error) {
+
+       res, err := c.GetDeploymentIntentGroup(d.MetaData.Name, p, ca, v)
+       if !reflect.DeepEqual(res, DeploymentIntentGroup{}) {
+               return DeploymentIntentGroup{}, pkgerrors.New("AppIntent already exists")
+       }
+
+       //Check if project exists
+       _, err = NewProjectClient().GetProject(p)
+       if err != nil {
+               return DeploymentIntentGroup{}, pkgerrors.New("Unable to find the project")
+       }
+
+       //check if compositeApp exists
+       _, err = NewCompositeAppClient().GetCompositeApp(ca, v, p)
+       if err != nil {
+               return DeploymentIntentGroup{}, pkgerrors.New("Unable to find the composite-app")
+       }
+
+       gkey := DeploymentIntentGroupKey{
+               Name:         d.MetaData.Name,
+               Project:      p,
+               CompositeApp: ca,
+               Version:      v,
+       }
+
+       err = db.DBconn.Insert(c.storeName, gkey, nil, c.tagMetaData, d)
+       if err != nil {
+               return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Create DB entry error")
+       }
+
+       return d, nil
+}
+
+// GetDeploymentIntentGroup returns the DeploymentIntentGroup with a given name, project, compositeApp and version of compositeApp
+func (c *DeploymentIntentGroupClient) GetDeploymentIntentGroup(di string, p string, ca string, v string) (DeploymentIntentGroup, error) {
+
+       key := DeploymentIntentGroupKey{
+               Name:         di,
+               Project:      p,
+               CompositeApp: ca,
+               Version:      v,
+       }
+
+       result, err := db.DBconn.Find(c.storeName, key, c.tagMetaData)
+       if err != nil {
+               return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Get DeploymentIntentGroup error")
+       }
+
+       if result != nil {
+               d := DeploymentIntentGroup{}
+               err = db.DBconn.Unmarshal(result[0], &d)
+               if err != nil {
+                       return DeploymentIntentGroup{}, pkgerrors.Wrap(err, "Unmarshalling DeploymentIntentGroup")
+               }
+               return d, nil
+       }
+
+       return DeploymentIntentGroup{}, pkgerrors.New("Error getting DeploymentIntentGroup")
+
+}
+
+// DeleteDeploymentIntentGroup deletes a DeploymentIntentGroup
+func (c *DeploymentIntentGroupClient) DeleteDeploymentIntentGroup(di string, p string, ca string, v string) error {
+       k := DeploymentIntentGroupKey{
+               Name:         di,
+               Project:      p,
+               CompositeApp: ca,
+               Version:      v,
+       }
+
+       err := db.DBconn.Remove(c.storeName, k)
+       if err != nil {
+               return pkgerrors.Wrap(err, "Delete DeploymentIntentGroup entry;")
+       }
+       return nil
+
+}
diff --git a/src/orchestrator/pkg/module/deployment_intent_groups_test.go b/src/orchestrator/pkg/module/deployment_intent_groups_test.go
new file mode 100644 (file)
index 0000000..c0876ce
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * 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"
+)
+
+func TestCreateDeploymentIntentGroup(t *testing.T) {
+       testCases := []struct {
+               label                    string
+               inputDeploymentIntentGrp DeploymentIntentGroup
+               inputProject             string
+               inputCompositeApp        string
+               inputCompositeAppVersion string
+               expectedError            string
+               mockdb                   *db.MockDB
+               expected                 DeploymentIntentGroup
+       }{
+               {
+                       label: "Create DeploymentIntentGroup",
+                       inputDeploymentIntentGrp: DeploymentIntentGroup{
+                               MetaData: DepMetaData{
+                                       Name:        "testDeploymentIntentGroup",
+                                       Description: "DescriptionTestDeploymentIntentGroup",
+                                       UserData1:   "userData1",
+                                       UserData2:   "userData2",
+                               },
+                               Spec: DepSpecData{
+                                       Profile: "Testprofile",
+                                       Version: "version of deployment",
+                                       OverrideValuesObj: []OverrideValues{
+                                               {AppName: "TestAppName",
+                                                       ValuesObj: map[string]string{
+                                                               "imageRepository": "registry.hub.docker.com",
+                                                       }},
+                                               {AppName: "TestAppName",
+                                                       ValuesObj: map[string]string{
+                                                               "imageRepository": "registry.hub.docker.com",
+                                                       }},
+                                       },
+                               },
+                       },
+                       inputProject:             "testProject",
+                       inputCompositeApp:        "testCompositeApp",
+                       inputCompositeAppVersion: "testCompositeAppVersion",
+                       expected: DeploymentIntentGroup{
+                               MetaData: DepMetaData{
+                                       Name:        "testDeploymentIntentGroup",
+                                       Description: "DescriptionTestDeploymentIntentGroup",
+                                       UserData1:   "userData1",
+                                       UserData2:   "userData2",
+                               },
+                               Spec: DepSpecData{
+                                       Profile: "Testprofile",
+                                       Version: "version of deployment",
+                                       OverrideValuesObj: []OverrideValues{
+                                               {AppName: "TestAppName",
+                                                       ValuesObj: map[string]string{
+                                                               "imageRepository": "registry.hub.docker.com",
+                                                       }},
+                                               {AppName: "TestAppName",
+                                                       ValuesObj: map[string]string{
+                                                               "imageRepository": "registry.hub.docker.com",
+                                                       }},
+                                       },
+                               },
+                       },
+                       expectedError: "",
+                       mockdb: &db.MockDB{
+                               Items: map[string]map[string][]byte{
+                                       ProjectKey{ProjectName: "testProject"}.String(): {
+                                               "projectmetadata": []byte(
+                                                       "{\"project-name\":\"testProject\"," +
+                                                               "\"description\":\"Test project for unit testing\"}"),
+                                       },
+                                       CompositeAppKey{CompositeAppName: "testCompositeApp",
+                                               Version: "testCompositeAppVersion", Project: "testProject"}.String(): {
+                                               "compositeAppmetadata": []byte(
+                                                       "{\"metadata\":{" +
+                                                               "\"name\":\"testCompositeApp\"," +
+                                                               "\"description\":\"description\"," +
+                                                               "\"userData1\":\"user data\"," +
+                                                               "\"userData2\":\"user data\"" +
+                                                               "}," +
+                                                               "\"spec\":{" +
+                                                               "\"version\":\"version of the composite app\"}}"),
+                                       },
+                               },
+                       },
+               },
+       }
+
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       db.DBconn = testCase.mockdb
+                       depIntentCli := NewDeploymentIntentGroupClient()
+                       got, err := depIntentCli.CreateDeploymentIntentGroup(testCase.inputDeploymentIntentGrp, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion)
+                       if err != nil {
+                               if testCase.expectedError == "" {
+                                       t.Fatalf("CreateDeploymentIntentGroup returned an unexpected error %s, ", err)
+                               }
+                               if strings.Contains(err.Error(), testCase.expectedError) == false {
+                                       t.Fatalf("CreateDeploymentIntentGroup returned an unexpected error %s", err)
+                               }
+                       } else {
+                               if reflect.DeepEqual(testCase.expected, got) == false {
+                                       t.Errorf("CreateDeploymentIntentGroup returned unexpected body: got %v; "+" expected %v", got, testCase.expected)
+                               }
+                       }
+               })
+       }
+}
+
+func TestGetDeploymentIntentGroup(t *testing.T) {
+       testCases := []struct {
+               label                    string
+               inputDeploymentIntentGrp string
+               inputProject             string
+               inputCompositeApp        string
+               inputCompositeAppVersion string
+               expected                 DeploymentIntentGroup
+               expectedError            string
+               mockdb                   *db.MockDB
+       }{
+               {
+                       label:                    "Get DeploymentIntentGroup",
+                       inputDeploymentIntentGrp: "testDeploymentIntentGroup",
+                       inputProject:             "testProject",
+                       inputCompositeApp:        "testCompositeApp",
+                       inputCompositeAppVersion: "testCompositeAppVersion",
+                       expected: DeploymentIntentGroup{
+                               MetaData: DepMetaData{
+                                       Name:        "testDeploymentIntentGroup",
+                                       Description: "DescriptionTestDeploymentIntentGroup",
+                                       UserData1:   "userData1",
+                                       UserData2:   "userData2",
+                               },
+                               Spec: DepSpecData{
+                                       Profile: "Testprofile",
+                                       Version: "version of deployment",
+                                       OverrideValuesObj: []OverrideValues{
+                                               {AppName: "TestAppName",
+                                                       ValuesObj: map[string]string{
+                                                               "imageRepository": "registry.hub.docker.com",
+                                                       }},
+                                               {AppName: "TestAppName",
+                                                       ValuesObj: map[string]string{
+                                                               "imageRepository": "registry.hub.docker.com",
+                                                       }},
+                                       },
+                               },
+                       },
+                       expectedError: "",
+                       mockdb: &db.MockDB{
+                               Items: map[string]map[string][]byte{
+                                       DeploymentIntentGroupKey{
+                                               Name:         "testDeploymentIntentGroup",
+                                               Project:      "testProject",
+                                               CompositeApp: "testCompositeApp",
+                                               Version:      "testCompositeAppVersion",
+                                       }.String(): {
+                                               "deploymentintentgroup": []byte(
+                                                       "{\"metadata\":{\"name\":\"testDeploymentIntentGroup\"," +
+                                                               "\"description\":\"DescriptionTestDeploymentIntentGroup\"," +
+                                                               "\"userData1\": \"userData1\"," +
+                                                               "\"userData2\": \"userData2\"}," +
+                                                               "\"spec\":{\"profile\": \"Testprofile\"," +
+                                                               "\"version\": \"version of deployment\"," +
+                                                               "\"override-values\":[" +
+                                                               "{" +
+                                                               "\"app-name\": \"TestAppName\"," +
+                                                               "\"values\": " +
+                                                               "{" +
+                                                               "\"imageRepository\":\"registry.hub.docker.com\"" +
+                                                               "}" +
+                                                               "}," +
+                                                               "{" +
+                                                               "\"app-name\": \"TestAppName\"," +
+                                                               "\"values\": " +
+                                                               "{" +
+                                                               "\"imageRepository\":\"registry.hub.docker.com\"" +
+                                                               "}" +
+                                                               "}" +
+                                                               "]}}"),
+                                       },
+                               },
+                       },
+               },
+       }
+
+       for _, testCase := range testCases {
+               t.Run(testCase.label, func(t *testing.T) {
+                       db.DBconn = testCase.mockdb
+                       depIntentCli := NewDeploymentIntentGroupClient()
+                       got, err := depIntentCli.GetDeploymentIntentGroup(testCase.inputDeploymentIntentGrp, testCase.inputProject, testCase.inputCompositeApp, testCase.inputCompositeAppVersion)
+                       if err != nil {
+                               if testCase.expectedError == "" {
+                                       t.Fatalf("GetDeploymentIntentGroup returned an unexpected error: %s", err)
+                               }
+                               if strings.Contains(err.Error(), testCase.expectedError) == false {
+                                       t.Fatalf("GetDeploymentIntentGroup returned an unexpected error: %s", err)
+                               }
+                       } else {
+                               if reflect.DeepEqual(testCase.expected, got) == false {
+                                       t.Errorf("GetDeploymentIntentGroup returned unexpected body: got %v;"+
+                                               " expected %v", got, testCase.expected)
+                               }
+                       }
+               })
+       }
+}
index 4098194..8e739fc 100644 (file)
@@ -25,20 +25,20 @@ import (
 
 // GenericPlacementIntent shall have 2 fields - metadata and spec
 type GenericPlacementIntent struct {
-       MetaData IntentMetaData `json:"metadata"`
-       Spec     IntentSpecData `json:"spec"`
+       MetaData GenIntentMetaData `json:"metadata"`
+       Spec     GenIntentSpecData `json:"spec"`
 }
 
-// IntentMetaData has name, description, userdata1, userdata2
-type IntentMetaData struct {
+// GenIntentMetaData has name, description, userdata1, userdata2
+type GenIntentMetaData struct {
        Name        string `json:"name"`
        Description string `json:"description"`
        UserData1   string `json:"userData1"`
        UserData2   string `json:"userData2"`
 }
 
-// IntentSpecData has logical-cloud-name
-type IntentSpecData struct {
+// GenIntentSpecData has logical-cloud-name
+type GenIntentSpecData struct {
        LogicalCloud string `json:"logical-cloud"`
 }
 
index 3cb29e6..c87f9dd 100644 (file)
@@ -38,13 +38,13 @@ func TestCreateGenericPlacementIntent(t *testing.T) {
                {
                        label: "Create GenericPlacementIntent",
                        inputIntent: GenericPlacementIntent{
-                               MetaData: IntentMetaData{
+                               MetaData: GenIntentMetaData{
                                        Name:        "testGenericPlacement",
                                        Description: " A sample intent for testing",
                                        UserData1:   "userData1",
                                        UserData2:   "userData2",
                                },
-                               Spec: IntentSpecData{
+                               Spec: GenIntentSpecData{
                                        LogicalCloud: "logicalCloud1",
                                },
                        },
@@ -52,13 +52,13 @@ func TestCreateGenericPlacementIntent(t *testing.T) {
                        inputCompositeApp:        "testCompositeApp",
                        inputCompositeAppVersion: "testCompositeAppVersion",
                        expected: GenericPlacementIntent{
-                               MetaData: IntentMetaData{
+                               MetaData: GenIntentMetaData{
                                        Name:        "testGenericPlacement",
                                        Description: " A sample intent for testing",
                                        UserData1:   "userData1",
                                        UserData2:   "userData2",
                                },
-                               Spec: IntentSpecData{
+                               Spec: GenIntentSpecData{
                                        LogicalCloud: "logicalCloud1",
                                },
                        },
@@ -128,13 +128,13 @@ func TestGetGenericPlacementIntent(t *testing.T) {
                        compositeAppName:    "testCompositeApp",
                        compositeAppVersion: "testVersion",
                        expected: GenericPlacementIntent{
-                               MetaData: IntentMetaData{
+                               MetaData: GenIntentMetaData{
                                        Name:        "testIntent",
                                        Description: "A sample intent for testing",
                                        UserData1:   "userData1",
                                        UserData2:   "userData2",
                                },
-                               Spec: IntentSpecData{
+                               Spec: GenIntentSpecData{
                                        LogicalCloud: "logicalCloud1",
                                },
                        },
index 34a8462..b46c606 100644 (file)
@@ -18,13 +18,15 @@ package module
 
 // Client for using the services in the orchestrator
 type Client struct {
-       Project      *ProjectClient
-       CompositeApp *CompositeAppClient
-       Controller   *ControllerClient
-       Cluster      *ClusterClient
-       // Add Clients for API's here
+       Project                *ProjectClient
+       CompositeApp           *CompositeAppClient
+       Controller             *ControllerClient
+       Cluster                *ClusterClient
        GenericPlacementIntent *GenericPlacementIntentClient
        AppIntent              *AppIntentClient
+       // Add Clients for API's here
+       DeploymentIntentGroup *DeploymentIntentGroupClient
+       Intent                *IntentClient
 }
 
 // NewClient creates a new client for using the services
@@ -38,6 +40,7 @@ func NewClient() *Client {
        // Add Client API handlers here
        c.GenericPlacementIntent = NewGenericPlacementIntentClient()
        c.AppIntent = NewAppIntentClient()
-
+       c.DeploymentIntentGroup = NewDeploymentIntentGroupClient()
+       c.Intent = NewIntentClient()
        return c
 }