Fix resolution of values for Config API 34/125334/1 0.9.3
authorLukasz Rajewski <lukasz.rajewski@orange.com>
Mon, 25 Oct 2021 20:21:16 +0000 (22:21 +0200)
committerLukasz Rajewski <lukasz.rajewski@orange.com>
Mon, 25 Oct 2021 20:21:16 +0000 (22:21 +0200)
Issue-ID: MULTICLOUD-1414
Signed-off-by: Lukasz Rajewski <lukasz.rajewski@orange.com>
Change-Id: Ibca5846ffe083bfc4d505c4c3c13efac2c6e2426

src/k8splugin/internal/app/config_backend.go
src/k8splugin/internal/app/config_test.go
src/k8splugin/internal/app/instance.go
src/k8splugin/internal/helm/helm.go
src/k8splugin/internal/helm/helm_test.go
src/k8splugin/internal/namegenerator/namegenerator.go
src/k8splugin/internal/rb/profile.go

index 1f22922..c365363 100644 (file)
@@ -461,7 +461,7 @@ func applyConfig(instanceID string, p Config, pChannel chan configResourceList,
                return []helm.KubernetesResource{}, pkgerrors.Wrap(err, "Retrieving model info")
        }
        // Get Template and Resolve the template with values
-       crl, err := resolve(rbName, rbVersion, profileName, p, releaseName)
+       crl, err := resolve(rbName, rbVersion, profileName, instanceID, p, releaseName)
        if err != nil {
                return []helm.KubernetesResource{}, pkgerrors.Wrap(err, "Resolve Config")
        }
@@ -571,11 +571,12 @@ func scheduleResources(c chan configResourceList) {
 
 //Resolve returns the path where the helm chart merged with
 //configuration overrides resides.
-var resolve = func(rbName, rbVersion, profileName string, p Config, releaseName string) (configResourceList, error) {
+var resolve = func(rbName, rbVersion, profileName, instanceId string, p Config, releaseName string) (configResourceList, error) {
 
        var resTemplates []helm.KubernetesResourceTemplate
 
-       profile, err := rb.NewProfileClient().Get(rbName, rbVersion, profileName)
+       profileClient := rb.NewProfileClient()
+       profile, err := profileClient.Get(rbName, rbVersion, profileName)
        if err != nil {
                return configResourceList{}, pkgerrors.Wrap(err, "Reading Profile Data")
        }
@@ -593,8 +594,42 @@ var resolve = func(rbName, rbVersion, profileName string, p Config, releaseName
                return configResourceList{}, pkgerrors.Wrap(err, "Downloading Template")
        }
 
+       ic := NewInstanceClient()
+       instance, err := ic.Get(instanceId)
+       if err != nil {
+               return configResourceList{}, pkgerrors.Wrap(err, "Getting Instance")
+       }
+
+       var finalReleaseName string
+
+       if releaseName == "" {
+               finalReleaseName = profile.ReleaseName
+       } else {
+               finalReleaseName = releaseName
+       }
+
+       helmClient := helm.NewTemplateClient(profile.KubernetesVersion,
+               profile.Namespace,
+               finalReleaseName)
+
+       //copy values from the instance
+       valuesArr := []string{}
+       if instance.Request.OverrideValues != nil {
+               for k, v := range instance.Request.OverrideValues {
+                       valuesArr = append(valuesArr, k+"="+v)
+               }
+       }
+       valuesArr = append(valuesArr, "k8s-rb-instance-id="+instanceId)
+       rawValues, err := helmClient.ProcessValues([]string{}, valuesArr)
+       if err != nil {
+               return configResourceList{}, pkgerrors.Wrap(err, "Processing values")
+       }
+
+       for k, v := range p.Values {
+               rawValues[k] = v
+       }
        //Create a temp file in the system temp folder for values input
-       b, err := json.Marshal(p.Values)
+       b, err := json.Marshal(rawValues)
        if err != nil {
                return configResourceList{}, pkgerrors.Wrap(err, "Error Marshalling config data")
        }
@@ -613,26 +648,21 @@ var resolve = func(rbName, rbVersion, profileName string, p Config, releaseName
        }
        defer outputfile.Close()
 
-       chartBasePath, err := rb.ExtractTarBall(bytes.NewBuffer(def))
+       //Download and process the profile first
+       //If everything seems okay, then download the config templates
+       prYamlClient, err := profileClient.GetYamlClient(rbName, rbVersion, profileName)
        if err != nil {
-               return configResourceList{}, pkgerrors.Wrap(err, "Extracting Template")
+               return configResourceList{}, pkgerrors.Wrap(err, "Processing Profile Manifest")
        }
 
-       var finalReleaseName string
-
-       if releaseName == "" {
-               finalReleaseName = profile.ReleaseName
-       } else {
-               finalReleaseName = releaseName
+       chartBasePath, err := rb.ExtractTarBall(bytes.NewBuffer(def))
+       if err != nil {
+               return configResourceList{}, pkgerrors.Wrap(err, "Extracting Template")
        }
 
-       helmClient := helm.NewTemplateClient(profile.KubernetesVersion,
-               profile.Namespace,
-               finalReleaseName)
-
        chartPath := filepath.Join(chartBasePath, t.ChartName)
        resTemplates, crdList, _, err := helmClient.GenerateKubernetesArtifacts(chartPath,
-               []string{outputfile.Name()},
+               []string{prYamlClient.GetValues(), outputfile.Name()},
                nil)
        if err != nil {
                return configResourceList{}, pkgerrors.Wrap(err, "Generate final k8s yaml")
index 0cc3c3c..1aef665 100644 (file)
@@ -91,7 +91,7 @@ func TestCreateConfig(t *testing.T) {
                        db.Etcd = testCase.mockdb
                        db.DBconn = provideMockModelData(testCase.instanceID, testCase.rbName,
                                testCase.rbVersion, testCase.profileName)
-                       resolve = func(rbName, rbVersion, profileName string, p Config, releaseName string) (configResourceList, error) {
+                       resolve = func(rbName, rbVersion, profileName, instanceId string, p Config, releaseName string) (configResourceList, error) {
                                return configResourceList{}, nil
                        }
                        impl := NewConfigClient()
@@ -204,7 +204,7 @@ func TestRollbackConfig(t *testing.T) {
                        db.Etcd = testCase.mockdb
                        db.DBconn = provideMockModelData(testCase.instanceID, testCase.rbName,
                                testCase.rbVersion, testCase.profileName)
-                       resolve = func(rbName, rbVersion, profileName string, p Config, releaseName string) (configResourceList, error) {
+                       resolve = func(rbName, rbVersion, profileName, instanceID string, p Config, releaseName string) (configResourceList, error) {
                                return configResourceList{}, nil
                        }
                        impl := NewConfigClient()
index e50a59e..71042f0 100644 (file)
@@ -224,18 +224,21 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
                postDeleteTimeout = 600
        }
 
+       id := namegenerator.Generate()
+
+       overrideValues = append(overrideValues, "k8s-rb-instance-id="+id)
+
        //Execute the kubernetes create command
        sortedTemplates, crdList, hookList, releaseName, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues, i.ReleaseName)
        if err != nil {
+               namegenerator.Release(id)
                return InstanceResponse{}, pkgerrors.Wrap(err, "Error resolving helm charts")
        }
 
-       // TODO: Only generate if id is not provided
-       id := namegenerator.Generate()
-
        k8sClient := KubernetesClient{}
        err = k8sClient.Init(i.CloudRegion, id)
        if err != nil {
+               namegenerator.Release(id)
                return InstanceResponse{}, pkgerrors.Wrap(err, "Getting CloudRegion Information")
        }
 
@@ -273,19 +276,21 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
                PostDeleteTimeout:  postDeleteTimeout,
        }
 
+       err = k8sClient.ensureNamespace(profile.Namespace)
+       if err != nil {
+               namegenerator.Release(id)
+               return InstanceResponse{}, pkgerrors.Wrap(err, "Creating Namespace")
+       }
+
        key := InstanceKey{
                ID: id,
        }
        err = db.DBconn.Create(v.storeName, key, v.tagInst, dbData)
        if err != nil {
+               namegenerator.Release(id)
                return InstanceResponse{}, pkgerrors.Wrap(err, "Creating Instance DB Entry")
        }
 
-       err = k8sClient.ensureNamespace(profile.Namespace)
-       if err != nil {
-               return InstanceResponse{}, pkgerrors.Wrap(err, "Creating Namespace")
-       }
-
        if len(crdList) > 0 {
                log.Printf("Pre-Installing CRDs")
                _, err = k8sClient.createResources(crdList, profile.Namespace)
@@ -303,6 +308,8 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
                        err2 := db.DBconn.Delete(v.storeName, key, v.tagInst)
                        if err2 != nil {
                                log.Printf("Error cleaning failed instance in DB, please check DB.")
+                       } else {
+                               namegenerator.Release(id)
                        }
                        return InstanceResponse{}, pkgerrors.Wrap(err, "Error running preinstall hooks")
                }
@@ -314,6 +321,8 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
                err2 := db.DBconn.Delete(v.storeName, key, v.tagInst)
                if err2 != nil {
                        log.Printf("Delete Instance DB Entry for release %s has error.", releaseName)
+               } else {
+                       namegenerator.Release(id)
                }
                return InstanceResponse{}, pkgerrors.Wrap(err, "Update Instance DB Entry")
        }
@@ -330,6 +339,8 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
                err2 := db.DBconn.Delete(v.storeName, key, v.tagInst)
                if err2 != nil {
                        log.Printf("Delete Instance DB Entry for release %s has error.", releaseName)
+               } else {
+                       namegenerator.Release(id)
                }
                return InstanceResponse{}, pkgerrors.Wrap(err, "Create Kubernetes Resources")
        }
index b27c8ae..846366e 100644 (file)
@@ -72,9 +72,9 @@ func NewTemplateClient(k8sversion, namespace, releasename string) *TemplateClien
        }
 }
 
-// Combines valueFiles and values into a single values stream.
+// ProcessValues Combines valueFiles and values into a single values stream.
 // values takes precedence over valueFiles
-func (h *TemplateClient) processValues(valueFiles []string, values []string) (map[string]interface{}, error) {
+func (h *TemplateClient) ProcessValues(valueFiles []string, values []string) (map[string]interface{}, error) {
        settings := cli.New()
        providers := getter.All(settings)
        options := helmOptions.Options{
@@ -121,7 +121,7 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile
        }
 
        // get combined values and create config
-       rawVals, err := h.processValues(valueFiles, values)
+       rawVals, err := h.ProcessValues(valueFiles, values)
        if err != nil {
                return retData, crdData, hookList, err
        }
index 951ff92..8f0269a 100644 (file)
@@ -95,7 +95,7 @@ func TestProcessValues(t *testing.T) {
        for _, testCase := range testCases {
                t.Run(testCase.label, func(t *testing.T) {
                        tc := NewTemplateClient("1.12.3", "testnamespace", "testreleasename")
-                       out, err := tc.processValues(testCase.valueFiles, testCase.values)
+                       out, err := tc.ProcessValues(testCase.valueFiles, testCase.values)
                        if err != nil {
                                if testCase.expectedError == "" {
                                        t.Fatalf("Got an error %s", err)
index 52eef36..0a49633 100644 (file)
@@ -141,8 +141,28 @@ func (c *cache) generateName() string {
        }
 }
 
+func (c *cache) releaseName(name string) {
+       c.mux.Lock()
+       defer c.mux.Unlock()
+
+       c.init()
+
+       if c.isAlreadyUsed(name) {
+               c.cache[name] = false
+
+               // Update the cache and db
+               c.writeCacheToDB()
+       }
+}
+
 // Generate returns an autogenerated name
 func Generate() string {
 
        return nameCache.generateName()
 }
+
+// Release name from cache
+func Release(name string) {
+
+       nameCache.releaseName(name)
+}
index 7739858..ac90a63 100644 (file)
@@ -279,6 +279,25 @@ func (v *ProfileClient) Download(rbName, rbVersion, prName string) ([]byte, erro
        return nil, pkgerrors.New("Error downloading Profile content")
 }
 
+//GetYamlClient GEt Yaml Files client for profile
+func (v *ProfileClient) GetYamlClient(rbName string, rbVersion string, profileName string) (ProfileYamlClient, error) {
+       prData, err := v.Download(rbName, rbVersion, profileName)
+       if err != nil {
+               return ProfileYamlClient{}, pkgerrors.Wrap(err, "Downloading Profile")
+       }
+
+       prPath, err := ExtractTarBall(bytes.NewBuffer(prData))
+       if err != nil {
+               return ProfileYamlClient{}, pkgerrors.Wrap(err, "Extracting Profile Content")
+       }
+
+       prYamlClient, err := ProcessProfileYaml(prPath, v.manifestName)
+       if err != nil {
+               return ProfileYamlClient{}, pkgerrors.Wrap(err, "Processing Profile Manifest")
+       }
+       return prYamlClient, nil
+}
+
 //Resolve returns the path where the helm chart merged with
 //configuration overrides resides and final ReleaseName picked for instantiation
 func (v *ProfileClient) Resolve(rbName string, rbVersion string,
@@ -291,17 +310,7 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string,
 
        //Download and process the profile first
        //If everything seems okay, then download the definition
-       prData, err := v.Download(rbName, rbVersion, profileName)
-       if err != nil {
-               return sortedTemplates, crdList, hookList, finalReleaseName, pkgerrors.Wrap(err, "Downloading Profile")
-       }
-
-       prPath, err := ExtractTarBall(bytes.NewBuffer(prData))
-       if err != nil {
-               return sortedTemplates, crdList, hookList, finalReleaseName, pkgerrors.Wrap(err, "Extracting Profile Content")
-       }
-
-       prYamlClient, err := ProcessProfileYaml(prPath, v.manifestName)
+       prYamlClient, err := v.GetYamlClient(rbName, rbVersion, profileName)
        if err != nil {
                return sortedTemplates, crdList, hookList, finalReleaseName, pkgerrors.Wrap(err, "Processing Profile Manifest")
        }