diff options
author | Ritu Sood <Ritu.Sood@intel.com> | 2020-05-14 00:05:49 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2020-05-14 00:05:49 +0000 |
commit | 22a56b401408ad2d3f0d77c245cc2c69df83e456 (patch) | |
tree | 7cdb3873c7a6f485c3bebd24843f24bc4d0aaac3 /src/orchestrator | |
parent | a08968c161b999238cbd61ea2eb9fd597a5b37e6 (diff) | |
parent | 8fd7fd2ba9db1fb2dbe22c0cf89edb80454cff6d (diff) |
Merge "Create appContext and save to etcd"
Diffstat (limited to 'src/orchestrator')
-rw-r--r-- | src/orchestrator/pkg/appcontext/appcontext.go | 13 | ||||
-rw-r--r-- | src/orchestrator/pkg/gpic/gpic.go | 12 | ||||
-rw-r--r-- | src/orchestrator/pkg/module/instantiation.go | 248 | ||||
-rw-r--r-- | src/orchestrator/utils/utils.go | 100 |
4 files changed, 338 insertions, 35 deletions
diff --git a/src/orchestrator/pkg/appcontext/appcontext.go b/src/orchestrator/pkg/appcontext/appcontext.go index d92b1d11..8f7841ac 100644 --- a/src/orchestrator/pkg/appcontext/appcontext.go +++ b/src/orchestrator/pkg/appcontext/appcontext.go @@ -22,6 +22,8 @@ import ( "github.com/onap/multicloud-k8s/src/orchestrator/pkg/rtcontext" pkgerrors "github.com/pkg/errors" + //"log" + log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" ) type AppContext struct { @@ -81,6 +83,7 @@ func (ac *AppContext) AddApp(handle interface{}, appname string) (interface{}, e if err != nil { return nil, err } + log.Info(":: Added app handle ::", log.Fields{"AppHandle":h}) return h, nil } @@ -93,7 +96,7 @@ func (ac *AppContext) DeleteApp(handle interface{}) error { return nil } -//Returns the hanlde for a given app +//Returns the handle for a given app func (ac *AppContext) GetAppHandle(appname string) (interface{}, error) { if appname == "" { return nil, pkgerrors.Errorf("Not a valid run time context app name") @@ -123,6 +126,7 @@ func (ac *AppContext) AddCluster(handle interface{}, clustername string) (interf if err != nil { return nil, err } + log.Info(":: Added cluster handle ::", log.Fields{"ClusterHandler":h}) return h, nil } @@ -193,11 +197,13 @@ func (ac *AppContext) GetClusterNames(appname string) ([]string, error) { } //Add resource under app and cluster -func (ac *AppContext) AddResource(handle interface{}, resname string, value interface{}) (interface{}, error) { +func (ac *AppContext) AddResource(handle interface{}, resname string, value []byte) (interface{}, error) { h, err := ac.rtc.RtcAddResource(handle, resname, value) if err != nil { return nil, err } + log.Info(":: Added resource handle ::", log.Fields{"ResourceHandler":h}) + return h, nil } @@ -238,7 +244,7 @@ func (ac *AppContext) GetResourceHandle(appname string, clustername string, resn } //Update the resource value usign the given handle -func (ac *AppContext) UpdateResourceValue(handle interface{}, value interface{}) error { +func (ac *AppContext) UpdateResourceValue(handle interface{}, value []byte) error { return ac.rtc.RtcUpdateValue(handle, value) } @@ -254,6 +260,7 @@ func (ac *AppContext) AddInstruction(handle interface{}, level string, insttype if err != nil { return nil, err } + log.Info(":: Added instruction handle ::", log.Fields{"InstructionHandler":h}) return h, nil } diff --git a/src/orchestrator/pkg/gpic/gpic.go b/src/orchestrator/pkg/gpic/gpic.go index f02e5352..256d3b41 100644 --- a/src/orchestrator/pkg/gpic/gpic.go +++ b/src/orchestrator/pkg/gpic/gpic.go @@ -22,14 +22,14 @@ package gpic */ import ( - "log" ncmmodule "github.com/onap/multicloud-k8s/src/ncm/pkg/module" pkgerrors "github.com/pkg/errors" + "log" ) // Clusters has 1 field - a list of ClusterNames type Clusters struct { - ClustersWithName []ClusterWithName + ClustersWithName []ClusterWithName } // ClusterWithName has two fields - ProviderName and ClusterName @@ -82,7 +82,7 @@ func intentResolverHelper(pn, cn, cln string, clustersWithName []ClusterWithName for _, eachClusterName := range clusterNamesList { eachClusterWithPN := ClusterWithName{pn, eachClusterName} clustersWithName = append(clustersWithName, eachClusterWithPN) - log.Printf("Added Cluster: %s ", cln) + log.Printf("Added Cluster :: %s through its label: %s ", eachClusterName, cln) } } return clustersWithName, nil @@ -95,13 +95,13 @@ func IntentResolver(intent IntentStruc) (Clusters, error) { for _, eachAllOf := range intent.AllOfArray { clustersWithName, err = intentResolverHelper(eachAllOf.ProviderName, eachAllOf.ClusterName, eachAllOf.ClusterLabelName, clustersWithName) - if err!=nil { + 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 { + if err != nil { return Clusters{}, pkgerrors.Wrap(err, "intentResolverHelper error") } } @@ -110,7 +110,7 @@ func IntentResolver(intent IntentStruc) (Clusters, error) { if len(intent.AnyOfArray) > 0 { for _, eachAnyOf := range intent.AnyOfArray { clustersWithName, err = intentResolverHelper(eachAnyOf.ProviderName, eachAnyOf.ClusterName, eachAnyOf.ClusterLabelName, clustersWithName) - if err!=nil { + if err != nil { return Clusters{}, pkgerrors.Wrap(err, "intentResolverHelper error") } } diff --git a/src/orchestrator/pkg/module/instantiation.go b/src/orchestrator/pkg/module/instantiation.go index 56021547..58706ef6 100644 --- a/src/orchestrator/pkg/module/instantiation.go +++ b/src/orchestrator/pkg/module/instantiation.go @@ -17,15 +17,17 @@ package module import ( + "encoding/base64" "fmt" - + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext" gpic "github.com/onap/multicloud-k8s/src/orchestrator/pkg/gpic" - - "encoding/base64" - + "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/db" + "github.com/onap/multicloud-k8s/src/orchestrator/utils" "github.com/onap/multicloud-k8s/src/orchestrator/utils/helm" pkgerrors "github.com/pkg/errors" - "log" + "io/ioutil" + //"log" + log "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/logutils" ) // ManifestFileName is the name given to the manifest file in the profile package @@ -34,10 +36,29 @@ const ManifestFileName = "manifest.yaml" // GenericPlacementIntentName denotes the generic placement intent name const GenericPlacementIntentName = "generic-placement-intent" +// SEPARATOR used while creating clusternames to store in etcd +const SEPARATOR = "+" + // InstantiationClient implements the InstantiationManager type InstantiationClient struct { - storeName string - tagMetaData string + db InstantiationClientDbInfo +} + +/* +InstantiationKey used in storing the contextid in the momgodb +It consists of +GenericPlacementIntentName, +ProjectName, +CompositeAppName, +CompositeAppVersion, +DeploymentIntentGroup +*/ +type InstantiationKey struct { + IntentName string + Project string + CompositeApp string + Version string + DeploymentIntentGroup string } // InstantiationManager is an interface which exposes the @@ -47,11 +68,19 @@ type InstantiationManager interface { Instantiate(p string, ca string, v string, di string) error } +// InstantiationClientDbInfo consists of storeName and tagContext +type InstantiationClientDbInfo struct { + storeName string // name of the mongodb collection to use for Instantiationclient documents + tagContext string // attribute key name for context object in App Context +} + // NewInstantiationClient returns an instance of InstantiationClient func NewInstantiationClient() *InstantiationClient { return &InstantiationClient{ - storeName: "orchestrator", - tagMetaData: "instantiation", + db: InstantiationClientDbInfo{ + storeName: "orchestrator", + tagContext: "contextid", + }, } } @@ -70,10 +99,10 @@ func getOverrideValuesByAppName(ov []OverrideValues, a string) map[string]string } /* -FindGenericPlacementIntent takes in projectName, CompositeAppName, CompositeAppVersion, DeploymentIntentName +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) { +func findGenericPlacementIntent(p, ca, v, di string) (string, error) { var gi string var found bool iList, err := NewIntentClient().GetAllIntents(p, ca, v, di) @@ -82,7 +111,7 @@ func FindGenericPlacementIntent(p, ca, v, di string) (string, error) { } for _, eachMap := range iList.ListOfIntents { if gi, found := eachMap[GenericPlacementIntentName]; found { - log.Printf("::Name of the generic-placement-intent:: %s", gi) + log.Info(":: Name of the generic-placement-intent ::", log.Fields{"GenPlmtIntent":gi}) return gi, err } } @@ -97,7 +126,8 @@ func FindGenericPlacementIntent(p, ca, v, di string) (string, error) { //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) { - log.Println("Processing App.. ", appName) + + log.Info(":: Processing App ::", log.Fields{"appName":appName}) var sortedTemplates []helm.KubernetesResourceTemplate @@ -109,7 +139,8 @@ func GetSortedTemplateForApp(appName, p, ca, v, rName, cp string, overrideValues if err != nil { return sortedTemplates, pkgerrors.Wrap(err, "Fail to convert to byte array") } - log.Println("Got the app content..") + + log.Info(":: Got the app content.. ::", log.Fields{"appName":appName}) appPC, err := NewAppProfileClient().GetAppProfileContentByApp(p, ca, v, cp, appName) if err != nil { @@ -120,7 +151,7 @@ func GetSortedTemplateForApp(appName, p, ca, v, rName, cp string, overrideValues return sortedTemplates, pkgerrors.Wrap(err, "Fail to convert to byte array") } - log.Println("Got the app Profile content ...") + log.Info(":: Got the app Profile content .. ::", log.Fields{"appName":appName}) overrideValuesOfApp := getOverrideValuesByAppName(overrideValues, appName) //Convert override values from map to array of strings of the following format @@ -137,12 +168,111 @@ func GetSortedTemplateForApp(appName, p, ca, v, rName, cp string, overrideValues appProfileContent, overrideValuesOfAppStr, appName) - log.Printf("The len of the sortedTemplates :: %d", len(sortedTemplates)) + log.Info(":: Total no. of sorted templates ::", log.Fields{"len(sortedTemplates):":len(sortedTemplates)}) return sortedTemplates, err } -// Instantiate methods takes in project +// resource consists of name of reource +type resource struct { + name string + filecontent []byte +} + +// getResources shall take in the sorted templates and output the resources +// which consists of name(name+kind) and filecontent +func getResources(st []helm.KubernetesResourceTemplate) ([]resource, error) { + var resources []resource + for _, t := range st { + yamlStruct, err := utils.ExtractYamlParameters(t.FilePath) + yamlFile, err := ioutil.ReadFile(t.FilePath) + if err != nil { + return nil, pkgerrors.Wrap(err, "Failed to get the resources..") + } + n := yamlStruct.Metadata.Name + SEPARATOR + yamlStruct.Kind + + resources = append(resources, resource{name: n, filecontent: yamlFile}) + + log.Info(":: Added resource into resource-order ::", log.Fields{"ResourceName":n}) + } + return resources, nil +} + +func addResourcesToCluster(ct appcontext.AppContext, ch interface{}, resources []resource, resourceOrder []string) error { + for _, resource := range resources { + + resourceOrder = append(resourceOrder, resource.name) + _, err := ct.AddResource(ch, resource.name, resource.filecontent) + if err != nil { + cleanuperr := ct.DeleteCompositeApp() + if cleanuperr != nil { + log.Info(":: Error Cleaning up AppContext after add resource failure ::", log.Fields{"Resource":resource.name, "Error":cleanuperr.Error}) + } + return pkgerrors.Wrapf(err, "Error adding resource ::%s to AppContext", resource.name) + } + _, err = ct.AddInstruction(ch, "resource", "order", resourceOrder) + if err != nil { + cleanuperr := ct.DeleteCompositeApp() + if cleanuperr != nil { + log.Info(":: Error Cleaning up AppContext after add instruction failure ::", log.Fields{"Resource":resource.name, "Error":cleanuperr.Error}) + } + return pkgerrors.Wrapf(err, "Error adding instruction for resource ::%s to AppContext", resource.name) + } + } + return nil +} + +func addClustersToAppContext(l gpic.Clusters, ct appcontext.AppContext, appHandle interface{}, resources []resource) error { + for _, c := range l.ClustersWithName { + p := c.ProviderName + n := c.ClusterName + var resourceOrder []string + clusterhandle, err := ct.AddCluster(appHandle, p+SEPARATOR+n) + if err != nil { + cleanuperr := ct.DeleteCompositeApp() + if cleanuperr != nil { + log.Info(":: Error Cleaning up AppContext after add cluster failure ::", log.Fields{"cluster-provider":p, "cluster-name":n, "Error":cleanuperr.Error}) + } + return pkgerrors.Wrapf(err, "Error adding Cluster(provider::%s and name::%s) to AppContext", p, n) + } + + err = addResourcesToCluster(ct, clusterhandle, resources, resourceOrder) + if err != nil { + return pkgerrors.Wrapf(err, "Error adding Resources to Cluster(provider::%s and name::%s) to AppContext", p, n) + } + } + return nil +} + +/* +verifyResources method is just to check if the resource handles are correctly saved. +*/ + +func verifyResources(l gpic.Clusters, ct appcontext.AppContext, resources []resource, appName string) error { + for _, c := range l.ClustersWithName { + p := c.ProviderName + n := c.ClusterName + cn := p + SEPARATOR + n + for _, res := range resources { + + rh, err := ct.GetResourceHandle(appName, cn, res.name) + if err != nil { + return pkgerrors.Wrapf(err, "Error getting resoure handle for resource :: %s, app:: %s, cluster :: %s", appName, res.name, cn) + } + log.Info(":: GetResourceHandle ::", log.Fields{"ResourceHandler":rh, "appName":appName, "Cluster": cn, "Resource":res.name}) + + } + + } + + return nil +} + +/* +Instantiate methods takes in projectName, compositeAppName, compositeAppVersion, +DeploymentIntentName. This method is responsible for template resolution, intent +resolution, creation and saving of context for saving into etcd. +*/ func (c InstantiationClient) Instantiate(p string, ca string, v string, di string) error { dIGrp, err := NewDeploymentIntentGroupClient().GetDeploymentIntentGroup(di, p, ca, v) @@ -153,36 +283,102 @@ 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) + 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) + log.Info(":: The name of the GenPlacIntent ::", log.Fields{"GenPlmtIntent":gIntent}) + log.Info(":: DeploymentIntentGroup, ReleaseName, CompositeProfile ::", log.Fields{"dIGrp":dIGrp.MetaData.Name, "releaseName":rName, "cp":cp}) + allApps, err := NewAppClient().GetApps(p, ca, v) if err != nil { return pkgerrors.Wrap(err, "Not finding the apps") } + + // Make an app context for the compositeApp + context := appcontext.AppContext{} + ctxval, err := context.InitAppContext() + if err != nil { + return pkgerrors.Wrap(err, "Error creating AppContext CompositeApp") + } + compositeHandle, err := context.CreateCompositeApp() + if err != nil { + return pkgerrors.Wrap(err, "Error creating AppContext") + } + + var appOrder []string + + // Add composite app using appContext for _, eachApp := range allApps { + appOrder = append(appOrder, eachApp.Metadata.Name) sortedTemplates, err := GetSortedTemplateForApp(eachApp.Metadata.Name, p, ca, v, rName, cp, overrideValues) + if err != nil { return pkgerrors.Wrap(err, "Unable to get the sorted templates for app") } - log.Printf("Resolved all the templates for app :: %s under the compositeApp...", eachApp.Metadata.Name) - log.Printf("sortedTemplates :: %v ", sortedTemplates) + + log.Info(":: Resolved all the templates ::", log.Fields{"appName":eachApp.Metadata.Name, "SortedTemplate":sortedTemplates}) + + resources, err := getResources(sortedTemplates) + if err != nil { + return pkgerrors.Wrapf(err, "Unable to get the resources for app :: %s", eachApp.Metadata.Name) + } 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 { + 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.Info(":: listOfClusters ::", log.Fields{"listOfClusters":listOfClusters}) + + //BEGIN: storing into etcd + // Add an app to the app context + apphandle, err := context.AddApp(compositeHandle, eachApp.Metadata.Name) + if err != nil { + cleanuperr := context.DeleteCompositeApp() + if cleanuperr != nil { + log.Info(":: Error Cleaning up AppContext compositeApp failure ::", log.Fields{"Error":cleanuperr.Error(), "AppName":eachApp.Metadata.Name}) + } + return pkgerrors.Wrap(err, "Error adding App to AppContext") + } + err = addClustersToAppContext(listOfClusters, context, apphandle, resources) + if err != nil { + log.Info(":: Error while adding cluster and resources to app ::", log.Fields{"Error":err.Error(), "AppName":eachApp.Metadata.Name}) + } + err = verifyResources(listOfClusters, context, resources, eachApp.Metadata.Name) + if err != nil { + log.Info(":: Error while verifying resources in app ::", log.Fields{"Error":err.Error(), "AppName":eachApp.Metadata.Name}) + } + + } + context.AddInstruction(compositeHandle, "app", "order", appOrder) + //END: storing into etcd + + // BEGIN:: save the context in the orchestrator db record + key := InstantiationKey{ + IntentName: gIntent, + Project: p, + CompositeApp: ca, + Version: v, + DeploymentIntentGroup: di, + } + + err = db.DBconn.Insert(c.db.storeName, key, nil, c.db.tagContext, ctxval) + if err != nil { + cleanuperr := context.DeleteCompositeApp() + if cleanuperr != nil { + + log.Info(":: Error Cleaning up AppContext while saving context in the db for GPIntent ::", log.Fields{"Error":cleanuperr.Error(), "GPIntent":gIntent, "DeploymentIntentGroup":di, "CompositeApp":ca, "CompositeAppVersion":v, "Project":p}) + } + return pkgerrors.Wrap(err, "Error adding AppContext to DB") } - log.Printf("Done with instantiation...") + // END:: save the context in the orchestrator db record + + log.Info(":: Done with instantiation... ::", log.Fields{"CompositeAppName":ca}) return err } diff --git a/src/orchestrator/utils/utils.go b/src/orchestrator/utils/utils.go index 13c78ba4..22ce903b 100644 --- a/src/orchestrator/utils/utils.go +++ b/src/orchestrator/utils/utils.go @@ -19,15 +19,105 @@ package utils import ( "archive/tar" "compress/gzip" + "strings" + "io" "io/ioutil" + "log" "os" "path" "path/filepath" pkgerrors "github.com/pkg/errors" + yaml "gopkg.in/yaml.v3" ) +// ListYamlStruct is applied when the kind is list +type ListYamlStruct struct { + APIVersion string `yaml:"apiVersion,omitempty"` + Kind string `yaml:"kind,omitempty"` + items []YamlStruct `yaml:"items,omitempty"` +} + +// YamlStruct represents normal parameters in a manifest file. +// Over the course of time, Pls add more parameters as and when you require. +type YamlStruct struct { + APIVersion string `yaml:"apiVersion,omitempty"` + Kind string `yaml:"kind,omitempty"` + Metadata struct { + Name string `yaml:"name,omitempty"` + Namespace string `yaml:"namespace,omitempty"` + Labels struct { + RouterDeisIoRoutable string `yaml:"router.deis.io/routable,omitempty"` + } `yaml:"labels"` + Annotations struct { + RouterDeisIoDomains string `yaml:"router.deis.io/domains,omitempty"` + } `yaml:"annotations,omitempty"` + } `yaml:"metadata,omitempty"` + Spec struct { + Type string `yaml:"type,omitempty"` + Selector struct { + App string `yaml:"app,omitempty"` + } `yaml:"selector,omitempty"` + Ports []struct { + Name string `yaml:"name,omitempty"` + Port int `yaml:"port,omitempty"` + NodePort int `yaml:"nodePort,omitempty"` + } `yaml:"ports"` + } `yaml:"spec"` +} + +func (y YamlStruct) isValid() bool { + if y.APIVersion == "" { + log.Printf("apiVersion is missing in manifest file") + return false + } + if y.Kind == "" { + log.Printf("kind is missing in manifest file") + return false + } + if y.Metadata.Name == "" { + log.Printf("metadata.name is missing in manifest file") + return false + } + return true +} + +// ExtractYamlParameters is a method which takes in the abolute path of a manifest file +// and returns a struct accordingly +func ExtractYamlParameters(f string) (YamlStruct, error) { + filename, _ := filepath.Abs(f) + yamlFile, err := ioutil.ReadFile(filename) + + var yamlStruct YamlStruct + + err = yaml.Unmarshal(yamlFile, &yamlStruct) + if err != nil { + return YamlStruct{}, pkgerrors.New("Cant unmarshal yaml file ..") + } + + /* This is a special case handling when the kind is "List". + When the kind is list and the metadata name is empty. + We set the metadata name as the file name. For eg: + if filename is "/tmp/helm-tmpl-240995533/prometheus/templates/serviceaccount.yaml-0". + We set metadata name as "serviceaccount.yaml-0" + Usually when the kind is list, the list might contains a list of + */ + if yamlStruct.Kind == "List" && yamlStruct.Metadata.Name == "" { + li := strings.LastIndex(filename, "/") + fn := string(filename[li+1:]) + yamlStruct.Metadata.Name = fn + log.Printf("Setting the metadata name as :: %s", fn) + } + if yamlStruct.isValid() { + log.Printf("YAML parameters for file ::%s \n %v", f, yamlStruct) + return yamlStruct, nil + } + log.Printf("YAML file ::%s has errors", f) + return YamlStruct{}, pkgerrors.Errorf("Cant extract parameters from yaml file :: %s", filename) + +} + //ExtractTarBall provides functionality to extract a tar.gz file //into a temporary location for later use. //It returns the path to the new location @@ -114,3 +204,13 @@ func EnsureDirectory(f string) error { } return os.MkdirAll(base, 0755) } + +// func main() { +// filename := "./test.yaml" +// yamlStruct, err := ExtractYamlParameters(filename) +// if err!=nil { +// log.Print(err) +// } +// fmt.Printf("%s+%s", yamlStruct.Metadata.Name, yamlStruct.Kind) +// fmt.Printf("%v", yamlStruct) +// } |