From 8fd7fd2ba9db1fb2dbe22c0cf89edb80454cff6d Mon Sep 17 00:00:00 2001 From: Rajamohan Raj Date: Thu, 30 Apr 2020 23:07:15 +0000 Subject: [PATCH] Create appContext and save to etcd In this patch, following tasks are accomplished 1. Creation of appContext and storing the appcontexts for each app in the compositeApp into etcd as part of the instantiation process 2. Added a util method to extract parameters from k8s manifest files. 3. Added a new testing script to auto create NCM artifacts through the NCM APIs 4. Modified the existing plugin_collection_v2.sh to better test the orchestrator APIs. 5. Added logging to appcontext lib 6. Bug fix in the helm charts. Issue-ID: MULTICLOUD-1064 Signed-off-by: Rajamohan Raj Change-Id: I1b0e4d1351ad3a083be529239748015ea5db2a41 --- kud/tests/plugin_collection_v2.sh | 67 +++++- kud/tests/plugin_ncm_v2.sh | 196 ++++++++++++++++ .../app2/helm/prometheus/templates/role.yaml | 2 - .../helm/prometheus/templates/rolebinding.yaml | 2 - src/orchestrator/pkg/appcontext/appcontext.go | 13 +- src/orchestrator/pkg/gpic/gpic.go | 12 +- src/orchestrator/pkg/module/instantiation.go | 248 ++++++++++++++++++--- src/orchestrator/utils/utils.go | 100 +++++++++ 8 files changed, 591 insertions(+), 49 deletions(-) create mode 100755 kud/tests/plugin_ncm_v2.sh diff --git a/kud/tests/plugin_collection_v2.sh b/kud/tests/plugin_collection_v2.sh index 09dec5c4..5ebed6ad 100755 --- a/kud/tests/plugin_collection_v2.sh +++ b/kud/tests/plugin_collection_v2.sh @@ -33,6 +33,7 @@ if [ ${1:+1} ]; then fi base_url=${base_url:-"http://localhost:9015/v2"} + kubeconfig_path="$HOME/.kube/config" csar_id=cb009bfe-bbee-11e8-9766-525400435678 @@ -69,12 +70,12 @@ appIntentNameForApp1="appIntentForApp1" appIntentForApp1Desc="AppIntentForApp1Desc" appIntentNameForApp2="appIntentForApp2" appIntentForApp2Desc="AppIntentForApp2Desc" -providerName1="aws" -providerName2="azure" -clusterName1="edge1" -clusterName2="edge2" -clusterLabelName1="east-us1" -clusterLabelName2="east-us2" +providerName1="cluster_provider1" +providerName2="cluster_provider2" +clusterName1="clusterName1" +clusterName2="clusterName2" +clusterLabelName1="clusterLabel1" +clusterLabelName2="clusterLabel2" deploymentIntentGroupName="test_deployment_intent_group" deploymentIntentGroupNameDesc="test_deployment_intent_group_desc" @@ -93,7 +94,53 @@ cloud_region_owner="localhost" install_deps populate_CSAR_composite_app_helm "$csar_id" -# BEGIN: Register project API +# BEGIN :: Delete statements are issued so that we clean up the 'orchestrator' collection +# and freshly populate the documents, also it serves as a direct test +# for all our DELETE APIs and an indirect test for all GET APIs + + +print_msg "Deleting intentToBeAddedinDeploymentIntentGroup" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/deployment-intent-groups/${deploymentIntentGroupName}/intents/${intentToBeAddedinDeploymentIntentGroup}" + +print_msg "Deleting ${deploymentIntentGroupName}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/deployment-intent-groups/${deploymentIntentGroupName}" + +print_msg "Deleting ${appIntentNameForApp2}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/generic-placement-intents/${genericPlacementIntentName}/app-intents/${appIntentNameForApp2}" + +print_msg "Deleting ${appIntentNameForApp1}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/generic-placement-intents/${genericPlacementIntentName}/app-intents/${appIntentNameForApp1}" + +print_msg "Deleting ${genericPlacementIntentName}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/generic-placement-intents/${genericPlacementIntentName}" + +print_msg "Deleting ${sub_composite_profile_name2}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/composite-profiles/${main_composite_profile_name}/profiles/${sub_composite_profile_name2}" + +print_msg "Deleting ${sub_composite_profile_name1}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/composite-profiles/${main_composite_profile_name}/profiles/${sub_composite_profile_name1}" + +print_msg "Deleting ${main_composite_profile_name}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/composite-profiles/${main_composite_profile_name}" + +print_msg "Deleting ${app2_name}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/apps/${app2_name}" + +print_msg "Deleting ${app1_name}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/apps/${app1_name}" + +print_msg "Deleting ${composite_app_name}/${composite_app_version}" +delete_resource "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}" + +print_msg "Deleting ${project_name}" +delete_resource "${base_url}/projects/${project_name}" + +# END :: Delete statements were issued so that we clean up the db +# and freshly populate the documents, also it serves as a direct test +# for all our DELETE APIs and an indirect test for all GET APIs + + +# BEGIN: Register project print_msg "Registering project" payload="$(cat </dev/null #massive output + + +print_msg "Registering cluster2" +payload="$(cat </dev/null #massive output + + +print_msg "Registering cluster3" +payload="$(cat </dev/null #massive output + + +print_msg "Registering cluster4" +payload="$(cat </dev/null #massive output + +# END : Register cluster1, cluster2, cluster3 and cluster4 + + +# BEGIN: adding labels to cluster3 and cluster4 +print_msg "Adding label to cluster3" +payload="$(cat < 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) +// } -- 2.16.6