From 6e0b4df46f51f9793f2d88626234edaaf9992403 Mon Sep 17 00:00:00 2001 From: Rajamohan Raj Date: Wed, 15 Apr 2020 18:45:47 +0000 Subject: Added intentResolver 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 Change-Id: I7d29901e46a5349ef502786c187c1c88bea61a12 --- src/orchestrator/api/add_intents_handler.go | 1 - .../api/composite_profilehandler_test.go | 2 +- src/orchestrator/api/projecthandler_test.go | 4 +- src/orchestrator/pkg/gpic/gpic.go | 120 +++++++++++++++++++++ src/orchestrator/pkg/infra/contextdb/mock.go | 2 +- src/orchestrator/pkg/module/add_intents.go | 5 - src/orchestrator/pkg/module/app.go | 1 - src/orchestrator/pkg/module/app_intent.go | 33 ++---- src/orchestrator/pkg/module/app_intent_test.go | 23 ++-- src/orchestrator/pkg/module/instantiation.go | 50 ++++++++- 10 files changed, 190 insertions(+), 51 deletions(-) create mode 100644 src/orchestrator/pkg/gpic/gpic.go (limited to 'src') diff --git a/src/orchestrator/api/add_intents_handler.go b/src/orchestrator/api/add_intents_handler.go index fbf9007d..ac8b400d 100644 --- a/src/orchestrator/api/add_intents_handler.go +++ b/src/orchestrator/api/add_intents_handler.go @@ -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) diff --git a/src/orchestrator/api/composite_profilehandler_test.go b/src/orchestrator/api/composite_profilehandler_test.go index 42b9b3a1..ec3ec24b 100644 --- a/src/orchestrator/api/composite_profilehandler_test.go +++ b/src/orchestrator/api/composite_profilehandler_test.go @@ -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", diff --git a/src/orchestrator/api/projecthandler_test.go b/src/orchestrator/api/projecthandler_test.go index 5e820aa2..0212e57a 100644 --- a/src/orchestrator/api/projecthandler_test.go +++ b/src/orchestrator/api/projecthandler_test.go @@ -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 index 00000000..f02e5352 --- /dev/null +++ b/src/orchestrator/pkg/gpic/gpic.go @@ -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 +} diff --git a/src/orchestrator/pkg/infra/contextdb/mock.go b/src/orchestrator/pkg/infra/contextdb/mock.go index fc0f8ff7..9aaed750 100644 --- a/src/orchestrator/pkg/infra/contextdb/mock.go +++ b/src/orchestrator/pkg/infra/contextdb/mock.go @@ -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 diff --git a/src/orchestrator/pkg/module/add_intents.go b/src/orchestrator/pkg/module/add_intents.go index a4d677b7..89bf255f 100644 --- a/src/orchestrator/pkg/module/add_intents.go +++ b/src/orchestrator/pkg/module/add_intents.go @@ -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{ diff --git a/src/orchestrator/pkg/module/app.go b/src/orchestrator/pkg/module/app.go index 40659de8..1e1a5974 100644 --- a/src/orchestrator/pkg/module/app.go +++ b/src/orchestrator/pkg/module/app.go @@ -38,7 +38,6 @@ type AppMetaData struct { } //AppContent contains fileContent -// TODO : This should have been []byte type AppContent struct { FileContent string } diff --git a/src/orchestrator/pkg/module/app_intent.go b/src/orchestrator/pkg/module/app_intent.go index 5f4acb4d..9da252e5 100644 --- a/src/orchestrator/pkg/module/app_intent.go +++ b/src/orchestrator/pkg/module/app_intent.go @@ -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 diff --git a/src/orchestrator/pkg/module/app_intent_test.go b/src/orchestrator/pkg/module/app_intent_test.go index 726ce0a3..089f09ff 100644 --- a/src/orchestrator/pkg/module/app_intent_test.go +++ b/src/orchestrator/pkg/module/app_intent_test.go @@ -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", diff --git a/src/orchestrator/pkg/module/instantiation.go b/src/orchestrator/pkg/module/instantiation.go index 5fabe81e..56021547 100644 --- a/src/orchestrator/pkg/module/instantiation.go +++ b/src/orchestrator/pkg/module/instantiation.go @@ -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 -- cgit 1.2.3-korg