Added intentResolver 41/106041/4
authorRajamohan Raj <rajamohan.raj@intel.com>
Wed, 15 Apr 2020 18:45:47 +0000 (18:45 +0000)
committerRajamohan Raj <rajamohan.raj@intel.com>
Fri, 17 Apr 2020 23:33:04 +0000 (23:33 +0000)
IntentResolver shall collect the clusterdetails for each of the app
where it needs to be deployed. This shall be called by
the instantiation code.

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

kud/tests/plugin_collection_v2.sh
src/orchestrator/api/add_intents_handler.go
src/orchestrator/api/composite_profilehandler_test.go
src/orchestrator/api/projecthandler_test.go
src/orchestrator/pkg/gpic/gpic.go [new file with mode: 0644]
src/orchestrator/pkg/infra/contextdb/mock.go
src/orchestrator/pkg/module/add_intents.go
src/orchestrator/pkg/module/app.go
src/orchestrator/pkg/module/app_intent.go
src/orchestrator/pkg/module/app_intent_test.go
src/orchestrator/pkg/module/instantiation.go

index 3351d8f..09dec5c 100755 (executable)
@@ -42,7 +42,7 @@ project_description="test_project_description"
 userData1="user1"
 userData2="user2"
 
-composite_app_name="test_composite_app"
+composite_app_name="test_composite_app_collection"
 composite_app_description="test_project_description"
 composite_app_version="test_composite_app_version"
 app1_helm_path="$CSAR_DIR/$csar_id/collectd.tar.gz"
@@ -58,7 +58,8 @@ app2_desc="prometheus_desc"
 main_composite_profile_name="main_composite_profile"
 sub_composite_profile_name1="test_composite_profile1"
 sub_composite_profile_name2="test_composite_profile2"
-composite_profile_description="test_composite_profile_description"
+main_composite_profile_description="main_composite_profile_description"
+sub_composite_profile_description="sub_composite_profile_description"
 
 genericPlacementIntentName="test_gen_placement_intent1"
 genericPlacementIntentDesc="test_gen_placement_intent_desc"
@@ -175,7 +176,7 @@ payload="$(cat <<EOF
 {
    "metadata":{
       "name":"${main_composite_profile_name}",
-      "description":"${composite_profile_description}",
+      "description":"${main_composite_profile_description}",
       "userData1":"${userData1}",
       "userData2":"${userData2}"
    }
@@ -192,7 +193,7 @@ payload="$(cat <<EOF
 {
    "metadata":{
       "name":"${sub_composite_profile_name1}",
-      "description":"${composite_profile_description}",
+      "description":"${sub_composite_profile_description}",
       "userData1":"${userData1}",
       "userData2":"${userData2}"
    },
@@ -212,7 +213,7 @@ payload="$(cat <<EOF
 {
    "metadata":{
       "name":"${sub_composite_profile_name2}",
-      "description":"${composite_profile_description}",
+      "description":"${sub_composite_profile_description}",
       "userData1":"${userData1}",
       "userData2":"${userData2}"
    },
index fbf9007..ac8b400 100644 (file)
@@ -94,7 +94,6 @@ func (h intentHandler) getIntentByNameHandler(w http.ResponseWriter, r *http.Req
                return
        }
 
-
        mapOfIntents, err := h.client.GetIntentByName(iN, p, ca, v, di)
        if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
index 42b9b3a..ec3ec24 100644 (file)
@@ -105,7 +105,7 @@ func Test_compositeProfileHandler_createHandler(t *testing.T) {
                        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",
index 5e820aa..0212e57 100644 (file)
@@ -95,7 +95,7 @@ func TestProjectCreateHandler(t *testing.T) {
                        projectClient: &mockProjectManager{
                                //Items that will be returned by the mocked Client
                                Items: []moduleLib.Project{
-                                       moduleLib.Project{
+                                       {
                                                MetaData: moduleLib.ProjectMetaData{
                                                        Name:        "testProject",
                                                        Description: "Test Project used for unit testing",
@@ -163,7 +163,7 @@ func TestProjectGetHandler(t *testing.T) {
                        name: "testProject",
                        projectClient: &mockProjectManager{
                                Items: []moduleLib.Project{
-                                       moduleLib.Project{
+                                       {
                                                MetaData: moduleLib.ProjectMetaData{
                                                        Name:        "testProject",
                                                        Description: "Test Project used for unit testing",
diff --git a/src/orchestrator/pkg/gpic/gpic.go b/src/orchestrator/pkg/gpic/gpic.go
new file mode 100644 (file)
index 0000000..f02e535
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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 gpic
+
+/*
+ gpic stands for GenericPlacementIntent Controller.
+ This file pertains to the implementation and handling of generic placement intents
+*/
+
+import (
+       "log"
+       ncmmodule "github.com/onap/multicloud-k8s/src/ncm/pkg/module"
+       pkgerrors "github.com/pkg/errors"
+)
+
+// Clusters has 1 field - a list of ClusterNames
+type Clusters struct {
+       ClustersWithName  []ClusterWithName
+}
+
+// ClusterWithName has two fields - ProviderName and ClusterName
+type ClusterWithName struct {
+       ProviderName string
+       ClusterName  string
+}
+
+// ClusterWithLabel has two fields - ProviderName and ClusterLabel
+type ClusterWithLabel struct {
+       ProviderName string
+       ClusterLabel string
+}
+
+// IntentStruc consists of AllOfArray and AnyOfArray
+type IntentStruc struct {
+       AllOfArray []AllOf `json:"allOf,omitempty"`
+       AnyOfArray []AnyOf `json:"anyOf,omitempty"`
+}
+
+// AllOf consists if ProviderName, ClusterName, ClusterLabelName and AnyOfArray. Any of them can be empty
+type AllOf struct {
+       ProviderName     string  `json:"provider-name,omitempty"`
+       ClusterName      string  `json:"cluster-name,omitempty"`
+       ClusterLabelName string  `json:"cluster-label-name,omitempty"`
+       AnyOfArray       []AnyOf `json:"anyOf,omitempty"`
+}
+
+// AnyOf consists of Array of ProviderName & ClusterLabelNames
+type AnyOf struct {
+       ProviderName     string `json:"provider-name,omitempty"`
+       ClusterName      string `json:"cluster-name,omitempty"`
+       ClusterLabelName string `json:"cluster-label-name,omitempty"`
+}
+
+// intentResolverHelper helps to populate the cluster lists
+func intentResolverHelper(pn, cn, cln string, clustersWithName []ClusterWithName) ([]ClusterWithName, error) {
+       if cln == "" && cn != "" {
+               eachClusterWithName := ClusterWithName{pn, cn}
+               clustersWithName = append(clustersWithName, eachClusterWithName)
+               log.Printf("Added Cluster: %s ", cn)
+       }
+       if cn == "" && cln != "" {
+               //Finding cluster names for the clusterlabel
+               clusterNamesList, err := ncmmodule.NewClusterClient().GetClustersWithLabel(pn, cln)
+               if err != nil {
+                       return []ClusterWithName{}, pkgerrors.Wrap(err, "Error getting clusterLabels")
+               }
+               // Populate the clustersWithName array with the clusternames found above
+               for _, eachClusterName := range clusterNamesList {
+                       eachClusterWithPN := ClusterWithName{pn, eachClusterName}
+                       clustersWithName = append(clustersWithName, eachClusterWithPN)
+                       log.Printf("Added Cluster: %s ", cln)
+               }
+       }
+       return clustersWithName, nil
+}
+
+// IntentResolver shall help to resolve the given intent into 2 lists of clusters where the app need to be deployed.
+func IntentResolver(intent IntentStruc) (Clusters, error) {
+       var clustersWithName []ClusterWithName
+       var err error
+
+       for _, eachAllOf := range intent.AllOfArray {
+               clustersWithName, err = intentResolverHelper(eachAllOf.ProviderName, eachAllOf.ClusterName, eachAllOf.ClusterLabelName, clustersWithName)
+               if err!=nil {
+                       return Clusters{}, pkgerrors.Wrap(err, "intentResolverHelper error")
+               }
+               if len(eachAllOf.AnyOfArray) > 0 {
+                       for _, eachAnyOf := range eachAllOf.AnyOfArray {
+                               clustersWithName, err = intentResolverHelper(eachAnyOf.ProviderName, eachAnyOf.ClusterName, eachAnyOf.ClusterLabelName, clustersWithName)
+                               if err!=nil {
+                                       return Clusters{}, pkgerrors.Wrap(err, "intentResolverHelper error")
+                               }
+                       }
+               }
+       }
+       if len(intent.AnyOfArray) > 0 {
+               for _, eachAnyOf := range intent.AnyOfArray {
+                       clustersWithName, err = intentResolverHelper(eachAnyOf.ProviderName, eachAnyOf.ClusterName, eachAnyOf.ClusterLabelName, clustersWithName)
+                       if err!=nil {
+                               return Clusters{}, pkgerrors.Wrap(err, "intentResolverHelper error")
+                       }
+               }
+       }
+       clusters := Clusters{clustersWithName}
+       return clusters, nil
+}
index fc0f8ff..9aaed75 100644 (file)
@@ -47,7 +47,7 @@ func (c *MockEtcd) Delete(key string) error {
 
 func (c *MockEtcd) GetAllKeys(path string) ([]string, error) {
        var keys []string
-       for k, _ := range c.Items {
+       for k := range c.Items {
                keys = append(keys, string(k))
        }
        return keys, nil
index a4d677b..89bf255 100644 (file)
@@ -49,13 +49,11 @@ type IntentSpecData struct {
        Intent map[string]string `json:"intent"`
 }
 
-
 // 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)
@@ -175,7 +173,6 @@ func (c *IntentClient) GetIntent(i string, p string, ca string, v string, di str
        return Intent{}, pkgerrors.New("Error getting Intent")
 }
 
-
 /*
 GetIntentByName takes in IntentName, projectName, CompositeAppName, CompositeAppVersion
 and deploymentIntentGroupName returns the list of intents under the IntentName.
@@ -200,7 +197,6 @@ func (c IntentClient) GetIntentByName(i string, p string, ca string, v string, d
        return a.Spec, nil
 }
 
-
 /*
 GetAllIntents takes in projectName, CompositeAppName, CompositeAppVersion,
 DeploymentIntentName . It returns ListOfIntents.
@@ -236,7 +232,6 @@ func (c IntentClient) GetAllIntents(p string, ca string, v string, di string) (L
        return ListOfIntents{}, err
 }
 
-
 // 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{
index 40659de..1e1a597 100644 (file)
@@ -38,7 +38,6 @@ type AppMetaData struct {
 }
 
 //AppContent contains fileContent
-// TODO : This should have been []byte
 type AppContent struct {
        FileContent string
 }
index 5f4acb4..9da252e 100644 (file)
@@ -25,8 +25,8 @@ import (
        "encoding/json"
        "reflect"
 
+       gpic "github.com/onap/multicloud-k8s/src/orchestrator/pkg/gpic"
        "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
-
        pkgerrors "github.com/pkg/errors"
 )
 
@@ -44,31 +44,10 @@ type MetaData struct {
        UserData2   string `json:"userData2"`
 }
 
-// AllOf consists of AnyOfArray and ClusterNames array
-type AllOf struct {
-       ProviderName     string  `json:"provider-name,omitempty"`
-       ClusterName      string  `json:"cluster-name,omitempty"`
-       ClusterLabelName string  `json:"cluster-label-name,omitempty"`
-       AnyOfArray       []AnyOf `json:"anyOf,omitempty"`
-}
-
-// AnyOf consists of Array of ProviderName & ClusterLabelNames
-type AnyOf struct {
-       ProviderName     string `json:"provider-name,omitempty"`
-       ClusterName      string `json:"cluster-name,omitempty"`
-       ClusterLabelName string `json:"cluster-label-name,omitempty"`
-}
-
-// IntentStruc consists of AllOfArray and AnyOfArray
-type IntentStruc struct {
-       AllOfArray []AllOf `json:"allOf,omitempty"`
-       AnyOfArray []AnyOf `json:"anyOf,omitempty"`
-}
-
 // SpecData consists of appName and intent
 type SpecData struct {
-       AppName string      `json:"app-name"`
-       Intent  IntentStruc `json:"intent"`
+       AppName string           `json:"app-name"`
+       Intent  gpic.IntentStruc `json:"intent"`
 }
 
 // AppIntentManager is an interface which exposes the
@@ -112,9 +91,9 @@ type ApplicationsAndClusterInfo struct {
 // AppClusterInfo is a type linking the app and the clusters
 // on which they need to be installed.
 type AppClusterInfo struct {
-       Name       string  `json:"name"`
-       AllOfArray []AllOf `json:"allOf,omitempty"`
-       AnyOfArray []AnyOf `json:"anyOf,omitempty"`
+       Name       string       `json:"name"`
+       AllOfArray []gpic.AllOf `json:"allOf,omitempty"`
+       AnyOfArray []gpic.AnyOf `json:"anyOf,omitempty"`
 }
 
 // We will use json marshalling to convert to string to
index 726ce0a..089f09f 100644 (file)
@@ -21,6 +21,7 @@ import (
        "strings"
        "testing"
 
+       gpic "github.com/onap/multicloud-k8s/src/orchestrator/pkg/gpic"
        "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db"
 )
 
@@ -47,8 +48,8 @@ func TestCreateAppIntent(t *testing.T) {
                                },
                                Spec: SpecData{
                                        AppName: "SampleApp",
-                                       Intent: IntentStruc{
-                                               AllOfArray: []AllOf{
+                                       Intent: gpic.IntentStruc{
+                                               AllOfArray: []gpic.AllOf{
                                                        {
                                                                ProviderName: "aws",
                                                                ClusterName:  "edge1",
@@ -60,7 +61,7 @@ func TestCreateAppIntent(t *testing.T) {
                                                                //ClusterLabelName: "edge2",
                                                        },
                                                        {
-                                                               AnyOfArray: []AnyOf{
+                                                               AnyOfArray: []gpic.AnyOf{
                                                                        {ProviderName: "aws",
                                                                                ClusterLabelName: "east-us1"},
                                                                        {ProviderName: "aws",
@@ -71,7 +72,7 @@ func TestCreateAppIntent(t *testing.T) {
                                                        },
                                                },
 
-                                               AnyOfArray: []AnyOf{},
+                                               AnyOfArray: []gpic.AnyOf{},
                                        },
                                },
                        },
@@ -89,8 +90,8 @@ func TestCreateAppIntent(t *testing.T) {
                                },
                                Spec: SpecData{
                                        AppName: "SampleApp",
-                                       Intent: IntentStruc{
-                                               AllOfArray: []AllOf{
+                                       Intent: gpic.IntentStruc{
+                                               AllOfArray: []gpic.AllOf{
                                                        {
                                                                ProviderName: "aws",
                                                                ClusterName:  "edge1",
@@ -102,7 +103,7 @@ func TestCreateAppIntent(t *testing.T) {
                                                                //ClusterLabelName: "edge2",
                                                        },
                                                        {
-                                                               AnyOfArray: []AnyOf{
+                                                               AnyOfArray: []gpic.AnyOf{
                                                                        {ProviderName: "aws",
                                                                                ClusterLabelName: "east-us1"},
                                                                        {ProviderName: "aws",
@@ -112,7 +113,7 @@ func TestCreateAppIntent(t *testing.T) {
                                                                },
                                                        },
                                                },
-                                               AnyOfArray: []AnyOf{},
+                                               AnyOfArray: []gpic.AnyOf{},
                                        },
                                },
                        },
@@ -202,8 +203,8 @@ func TestGetAppIntent(t *testing.T) {
                                },
                                Spec: SpecData{
                                        AppName: "SampleApp",
-                                       Intent: IntentStruc{
-                                               AllOfArray: []AllOf{
+                                       Intent: gpic.IntentStruc{
+                                               AllOfArray: []gpic.AllOf{
                                                        {
                                                                ProviderName: "aws",
                                                                ClusterName:  "edge1",
@@ -213,7 +214,7 @@ func TestGetAppIntent(t *testing.T) {
                                                                ClusterName:  "edge2",
                                                        },
                                                        {
-                                                               AnyOfArray: []AnyOf{
+                                                               AnyOfArray: []gpic.AnyOf{
                                                                        {ProviderName: "aws",
                                                                                ClusterLabelName: "east-us1"},
                                                                        {ProviderName: "aws",
index 5fabe81..5602154 100644 (file)
@@ -18,17 +18,22 @@ package module
 
 import (
        "fmt"
-       "github.com/onap/multicloud-k8s/src/orchestrator/utils/helm"
 
-       pkgerrors "github.com/pkg/errors"
+       gpic "github.com/onap/multicloud-k8s/src/orchestrator/pkg/gpic"
 
        "encoding/base64"
+
+       "github.com/onap/multicloud-k8s/src/orchestrator/utils/helm"
+       pkgerrors "github.com/pkg/errors"
        "log"
 )
 
 // ManifestFileName is the name given to the manifest file in the profile package
 const ManifestFileName = "manifest.yaml"
 
+// GenericPlacementIntentName denotes the generic placement intent name
+const GenericPlacementIntentName = "generic-placement-intent"
+
 // InstantiationClient implements the InstantiationManager
 type InstantiationClient struct {
        storeName   string
@@ -64,6 +69,30 @@ func getOverrideValuesByAppName(ov []OverrideValues, a string) map[string]string
        return map[string]string{}
 }
 
+/*
+FindGenericPlacementIntent takes in projectName, CompositeAppName, CompositeAppVersion, DeploymentIntentName
+and returns the name of the genericPlacementIntentName. Returns empty value if string not found.
+*/
+func FindGenericPlacementIntent(p, ca, v, di string) (string, error) {
+       var gi string
+       var found bool
+       iList, err := NewIntentClient().GetAllIntents(p, ca, v, di)
+       if err != nil {
+               return gi, err
+       }
+       for _, eachMap := range iList.ListOfIntents {
+               if gi, found := eachMap[GenericPlacementIntentName]; found {
+                       log.Printf("::Name of the generic-placement-intent:: %s", gi)
+                       return gi, err
+               }
+       }
+       if found == false {
+               fmt.Println("generic-placement-intent not found !")
+       }
+       return gi, pkgerrors.New("Generic-placement-intent not found")
+
+}
+
 // GetSortedTemplateForApp returns the sorted templates.
 //It takes in arguments - appName, project, compositeAppName, releaseName, compositeProfileName, array of override values
 func GetSortedTemplateForApp(appName, p, ca, v, rName, cp string, overrideValues []OverrideValues) ([]helm.KubernetesResourceTemplate, error) {
@@ -124,6 +153,12 @@ func (c InstantiationClient) Instantiate(p string, ca string, v string, di strin
        overrideValues := dIGrp.Spec.OverrideValuesObj
        cp := dIGrp.Spec.Profile
 
+       gIntent, err := FindGenericPlacementIntent(p, ca, v, di)
+       if err != nil {
+               return err
+       }
+       log.Printf("The name of the GenPlacIntent:: %s", gIntent)
+
        log.Printf("dIGrp :: %s, releaseName :: %s and cp :: %s \n", dIGrp.MetaData.Name, rName, cp)
        allApps, err := NewAppClient().GetApps(p, ca, v)
        if err != nil {
@@ -136,6 +171,17 @@ func (c InstantiationClient) Instantiate(p string, ca string, v string, di strin
                }
                log.Printf("Resolved all the templates for app :: %s under the compositeApp...", eachApp.Metadata.Name)
                log.Printf("sortedTemplates :: %v ", sortedTemplates)
+
+               specData, err := NewAppIntentClient().GetAllIntentsByApp(eachApp.Metadata.Name, p, ca, v, gIntent)
+               if err != nil {
+                       return pkgerrors.Wrap(err, "Unable to get the intents for app")
+               }
+               listOfClusters,err := gpic.IntentResolver(specData.Intent)
+               if err!=nil {
+                       return pkgerrors.Wrap(err, "Unable to get the intents resolved for app")
+               }
+               log.Printf("::listOfClusters:: %v", listOfClusters)
+
        }
        log.Printf("Done with instantiation...")
        return err