aboutsummaryrefslogtreecommitdiffstats
path: root/src/k8splugin/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/k8splugin/internal')
-rw-r--r--src/k8splugin/internal/app/client.go136
-rw-r--r--src/k8splugin/internal/app/config_backend.go11
-rw-r--r--src/k8splugin/internal/app/instance.go117
-rw-r--r--src/k8splugin/internal/app/instance_test.go122
-rw-r--r--src/k8splugin/internal/helm/helm.go34
-rw-r--r--src/k8splugin/internal/helm/helm_test.go29
-rw-r--r--src/k8splugin/internal/plugin/helpers.go3
-rw-r--r--src/k8splugin/internal/plugin/helpers_test.go83
-rw-r--r--src/k8splugin/internal/rb/profile.go33
-rw-r--r--src/k8splugin/internal/rb/profile_test.go239
10 files changed, 522 insertions, 285 deletions
diff --git a/src/k8splugin/internal/app/client.go b/src/k8splugin/internal/app/client.go
index d3e5081a..6762d1bc 100644
--- a/src/k8splugin/internal/app/client.go
+++ b/src/k8splugin/internal/app/client.go
@@ -1,5 +1,7 @@
/*
Copyright 2018 Intel Corporation.
+Copyright © 2020 Samsung Electronics
+
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
@@ -18,6 +20,7 @@ import (
"strings"
"time"
+ "github.com/onap/multicloud-k8s/src/k8splugin/internal/config"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/connection"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
log "github.com/onap/multicloud-k8s/src/k8splugin/internal/logutils"
@@ -25,6 +28,9 @@ import (
pkgerrors "github.com/pkg/errors"
"k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery/cached/disk"
"k8s.io/client-go/dynamic"
@@ -43,6 +49,79 @@ type KubernetesClient struct {
instanceID string
}
+// ResourceStatus holds Resource Runtime Data
+type ResourceStatus struct {
+ Name string `json:"name"`
+ GVK schema.GroupVersionKind `json:"GVK"`
+ Status unstructured.Unstructured `json:"status"`
+}
+
+// getPodsByLabel yields status of all pods under given instance ID
+func (k *KubernetesClient) getPodsByLabel(namespace string) ([]ResourceStatus, error) {
+ client := k.GetStandardClient().CoreV1().Pods(namespace)
+ listOpts := metav1.ListOptions{
+ LabelSelector: config.GetConfiguration().KubernetesLabelName + "=" + k.instanceID,
+ }
+ podList, err := client.List(listOpts)
+ if err != nil {
+ return nil, pkgerrors.Wrap(err, "Retrieving PodList from cluster")
+ }
+ resp := make([]ResourceStatus, 0, len(podList.Items))
+ cumulatedErrorMsg := make([]string, 0)
+ for _, pod := range podList.Items {
+ podContent, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pod)
+ if err != nil {
+ cumulatedErrorMsg = append(cumulatedErrorMsg, err.Error())
+ continue
+ }
+ var unstrPod unstructured.Unstructured
+ unstrPod.SetUnstructuredContent(podContent)
+ podStatus := ResourceStatus{
+ Name: unstrPod.GetName(),
+ GVK: schema.FromAPIVersionAndKind("v1", "Pod"),
+ Status: unstrPod,
+ }
+ resp = append(resp, podStatus)
+ }
+ if len(cumulatedErrorMsg) != 0 {
+ return resp, pkgerrors.New("Converting podContent to unstruct error:\n" +
+ strings.Join(cumulatedErrorMsg, "\n"))
+ }
+ return resp, nil
+}
+
+// getResourcesStatus yields status of given generic resource
+func (k *KubernetesClient) getResourceStatus(res helm.KubernetesResource, namespace string) (ResourceStatus, error) {
+ dynClient := k.GetDynamicClient()
+ mapper := k.GetMapper()
+ mapping, err := mapper.RESTMapping(schema.GroupKind{
+ Group: res.GVK.Group,
+ Kind: res.GVK.Kind,
+ }, res.GVK.Version)
+ if err != nil {
+ return ResourceStatus{},
+ pkgerrors.Wrap(err, "Preparing mapper based on GVK")
+ }
+
+ gvr := mapping.Resource
+ opts := metav1.GetOptions{}
+ var unstruct *unstructured.Unstructured
+ switch mapping.Scope.Name() {
+ case meta.RESTScopeNameNamespace:
+ unstruct, err = dynClient.Resource(gvr).Namespace(namespace).Get(res.Name, opts)
+ case meta.RESTScopeNameRoot:
+ unstruct, err = dynClient.Resource(gvr).Get(res.Name, opts)
+ default:
+ return ResourceStatus{}, pkgerrors.New("Got an unknown RESTSCopeName for mapping: " + res.GVK.String())
+ }
+
+ if err != nil {
+ return ResourceStatus{}, pkgerrors.Wrap(err, "Getting object status")
+ }
+
+ return ResourceStatus{unstruct.GetName(), res.GVK, *unstruct}, nil
+}
+
// getKubeConfig uses the connectivity client to get the kubeconfig based on the name
// of the cloudregion. This is written out to a file.
func (k *KubernetesClient) getKubeConfig(cloudregion string) (string, error) {
@@ -181,6 +260,43 @@ func (k *KubernetesClient) createKind(resTempl helm.KubernetesResourceTemplate,
}, nil
}
+func (k *KubernetesClient) updateKind(resTempl helm.KubernetesResourceTemplate,
+ namespace string) (helm.KubernetesResource, error) {
+
+ if _, err := os.Stat(resTempl.FilePath); os.IsNotExist(err) {
+ return helm.KubernetesResource{}, pkgerrors.New("File " + resTempl.FilePath + "does not exists")
+ }
+
+ log.Info("Processing Kubernetes Resource", log.Fields{
+ "filepath": resTempl.FilePath,
+ })
+
+ pluginImpl, err := plugin.GetPluginByKind(resTempl.GVK.Kind)
+ if err != nil {
+ return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error loading plugin")
+ }
+
+ updatedResourceName, err := pluginImpl.Update(resTempl.FilePath, namespace, k)
+ if err != nil {
+ log.Error("Error Updating Resource", log.Fields{
+ "error": err,
+ "gvk": resTempl.GVK,
+ "filepath": resTempl.FilePath,
+ })
+ return helm.KubernetesResource{}, pkgerrors.Wrap(err, "Error in plugin "+resTempl.GVK.Kind+" plugin")
+ }
+
+ log.Info("Updated Kubernetes Resource", log.Fields{
+ "resource": updatedResourceName,
+ "gvk": resTempl.GVK,
+ })
+
+ return helm.KubernetesResource{
+ GVK: resTempl.GVK,
+ Name: updatedResourceName,
+ }, nil
+}
+
func (k *KubernetesClient) createResources(sortedTemplates []helm.KubernetesResourceTemplate,
namespace string) ([]helm.KubernetesResource, error) {
@@ -201,6 +317,26 @@ func (k *KubernetesClient) createResources(sortedTemplates []helm.KubernetesReso
return createdResources, nil
}
+func (k *KubernetesClient) updateResources(sortedTemplates []helm.KubernetesResourceTemplate,
+ namespace string) ([]helm.KubernetesResource, error) {
+
+ err := k.ensureNamespace(namespace)
+ if err != nil {
+ return nil, pkgerrors.Wrap(err, "Creating Namespace")
+ }
+
+ var updatedResources []helm.KubernetesResource
+ for _, resTempl := range sortedTemplates {
+ resUpdated, err := k.updateKind(resTempl, namespace)
+ if err != nil {
+ return nil, pkgerrors.Wrapf(err, "Error updating kind: %+v", resTempl.GVK)
+ }
+ updatedResources = append(updatedResources, resUpdated)
+ }
+
+ return updatedResources, nil
+}
+
func (k *KubernetesClient) deleteKind(resource helm.KubernetesResource, namespace string) error {
log.Warn("Deleting Resource", log.Fields{
"gvk": resource.GVK,
diff --git a/src/k8splugin/internal/app/config_backend.go b/src/k8splugin/internal/app/config_backend.go
index 6bc145ee..4cbe1da3 100644
--- a/src/k8splugin/internal/app/config_backend.go
+++ b/src/k8splugin/internal/app/config_backend.go
@@ -360,10 +360,17 @@ func scheduleResources(c chan configResourceList) {
//Move onto the next cloud region
continue
}
+ //assuming - the resource is not exist already
data.createdResources, err = k8sClient.createResources(data.resourceTemplates, inst.Namespace)
+ errCreate := err
if err != nil {
- log.Printf("Error Creating resources: %s", err.Error())
- continue
+ // assuming - the err represent the resource is already exist, so going for update
+ data.createdResources, err = k8sClient.updateResources(data.resourceTemplates, inst.Namespace)
+ if err != nil {
+ log.Printf("Error Creating resources: %s", errCreate.Error())
+ log.Printf("Error Updating resources: %s", err.Error())
+ continue
+ }
}
}
//TODO: Needs to add code to call Kubectl create
diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go
index d6eb91b4..a6e213c1 100644
--- a/src/k8splugin/internal/app/instance.go
+++ b/src/k8splugin/internal/app/instance.go
@@ -1,5 +1,6 @@
/*
* Copyright 2018 Intel Corporation, Inc
+ * Copyright © 2020 Samsung Electronics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +20,7 @@ package app
import (
"encoding/json"
"log"
+ "strings"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/db"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
@@ -26,7 +28,6 @@ import (
"github.com/onap/multicloud-k8s/src/k8splugin/internal/rb"
pkgerrors "github.com/pkg/errors"
- corev1 "k8s.io/api/core/v1"
)
// InstanceRequest contains the parameters needed for instantiation
@@ -35,6 +36,7 @@ type InstanceRequest struct {
RBName string `json:"rb-name"`
RBVersion string `json:"rb-version"`
ProfileName string `json:"profile-name"`
+ ReleaseName string `json:"release-name"`
CloudRegion string `json:"cloud-region"`
Labels map[string]string `json:"labels"`
OverrideValues map[string]string `json:"override-values"`
@@ -42,29 +44,21 @@ type InstanceRequest struct {
// InstanceResponse contains the response from instantiation
type InstanceResponse struct {
- ID string `json:"id"`
- Request InstanceRequest `json:"request"`
- Namespace string `json:"namespace"`
- Resources []helm.KubernetesResource `json:"resources"`
- OverrideValues map[string]string `json:"override-values"`
+ ID string `json:"id"`
+ Request InstanceRequest `json:"request"`
+ Namespace string `json:"namespace"`
+ ReleaseName string `json:"release-name"`
+ Resources []helm.KubernetesResource `json:"resources"`
}
// InstanceMiniResponse contains the response from instantiation
// It does NOT include the created resources.
// Use the regular GET to get the created resources for a particular instance
type InstanceMiniResponse struct {
- ID string `json:"id"`
- Request InstanceRequest `json:"request"`
- Namespace string `json:"namespace"`
-}
-
-// PodStatus defines the observed state of ResourceBundleState
-type PodStatus struct {
- Name string `json:"name"`
- Namespace string `json:"namespace"`
- Ready bool `json:"ready"`
- Status corev1.PodStatus `json:"status,omitempty"`
- IPAddresses []string `json:"ipaddresses"`
+ ID string `json:"id"`
+ Request InstanceRequest `json:"request"`
+ ReleaseName string `json:"release-name"`
+ Namespace string `json:"namespace"`
}
// InstanceStatus is what is returned when status is queried for an instance
@@ -72,8 +66,7 @@ type InstanceStatus struct {
Request InstanceRequest `json:"request"`
Ready bool `json:"ready"`
ResourceCount int32 `json:"resourceCount"`
- PodStatuses []PodStatus `json:"podStatuses"`
- ServiceStatuses []corev1.Service `json:"serviceStatuses"`
+ ResourcesStatus []ResourceStatus `json:"resourcesStatus"`
}
// InstanceManager is an interface exposes the instantiation functionality
@@ -105,18 +98,16 @@ func (dk InstanceKey) String() string {
// InstanceClient implements the InstanceManager interface
// It will also be used to maintain some localized state
type InstanceClient struct {
- storeName string
- tagInst string
- tagInstStatus string
+ storeName string
+ tagInst string
}
// NewInstanceClient returns an instance of the InstanceClient
// which implements the InstanceManager
func NewInstanceClient() *InstanceClient {
return &InstanceClient{
- storeName: "rbdef",
- tagInst: "instance",
- tagInstStatus: "instanceStatus",
+ storeName: "rbdef",
+ tagInst: "instance",
}
}
@@ -145,7 +136,7 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
}
//Execute the kubernetes create command
- sortedTemplates, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues)
+ sortedTemplates, releaseName, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues, i.ReleaseName)
if err != nil {
return InstanceResponse{}, pkgerrors.Wrap(err, "Error resolving helm charts")
}
@@ -166,10 +157,11 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
//Compose the return response
resp := InstanceResponse{
- ID: id,
- Request: i,
- Namespace: profile.Namespace,
- Resources: createdResources,
+ ID: id,
+ Request: i,
+ Namespace: profile.Namespace,
+ ReleaseName: releaseName,
+ Resources: createdResources,
}
key := InstanceKey{
@@ -214,22 +206,64 @@ func (v *InstanceClient) Status(id string) (InstanceStatus, error) {
ID: id,
}
- value, err := db.DBconn.Read(v.storeName, key, v.tagInstStatus)
+ value, err := db.DBconn.Read(v.storeName, key, v.tagInst)
if err != nil {
return InstanceStatus{}, pkgerrors.Wrap(err, "Get Instance")
}
//value is a byte array
- if value != nil {
- resp := InstanceStatus{}
- err = db.DBconn.Unmarshal(value, &resp)
+ if value == nil {
+ return InstanceStatus{}, pkgerrors.New("Status is not available")
+ }
+
+ resResp := InstanceResponse{}
+ err = db.DBconn.Unmarshal(value, &resResp)
+ if err != nil {
+ return InstanceStatus{}, pkgerrors.Wrap(err, "Unmarshaling Instance Value")
+ }
+
+ k8sClient := KubernetesClient{}
+ err = k8sClient.init(resResp.Request.CloudRegion, id)
+ if err != nil {
+ return InstanceStatus{}, pkgerrors.Wrap(err, "Getting CloudRegion Information")
+ }
+
+ cumulatedErrorMsg := make([]string, 0)
+ podsStatus, err := k8sClient.getPodsByLabel(resResp.Namespace)
+ if err != nil {
+ cumulatedErrorMsg = append(cumulatedErrorMsg, err.Error())
+ }
+
+ generalStatus := make([]ResourceStatus, 0, len(resResp.Resources))
+Main:
+ for _, resource := range resResp.Resources {
+ for _, pod := range podsStatus {
+ if resource.GVK == pod.GVK && resource.Name == pod.Name {
+ continue Main //Don't double check pods if someone decided to define pod explicitly in helm chart
+ }
+ }
+ status, err := k8sClient.getResourceStatus(resource, resResp.Namespace)
if err != nil {
- return InstanceStatus{}, pkgerrors.Wrap(err, "Unmarshaling Instance Value")
+ cumulatedErrorMsg = append(cumulatedErrorMsg, err.Error())
+ } else {
+ generalStatus = append(generalStatus, status)
}
- return resp, nil
+ }
+ resp := InstanceStatus{
+ Request: resResp.Request,
+ ResourceCount: int32(len(generalStatus) + len(podsStatus)),
+ Ready: false, //FIXME To determine readiness, some parsing of status fields is necessary
+ ResourcesStatus: append(generalStatus, podsStatus...),
}
- return InstanceStatus{}, pkgerrors.New("Status is not available")
+ if len(cumulatedErrorMsg) != 0 {
+ err = pkgerrors.New("Getting Resources Status:\n" +
+ strings.Join(cumulatedErrorMsg, "\n"))
+ return resp, err
+ }
+ //TODO Filter response content by requested verbosity (brief, ...)?
+
+ return resp, nil
}
// List returns the instance for corresponding ID
@@ -253,9 +287,10 @@ func (v *InstanceClient) List(rbname, rbversion, profilename string) ([]Instance
}
miniresp := InstanceMiniResponse{
- ID: resp.ID,
- Request: resp.Request,
- Namespace: resp.Namespace,
+ ID: resp.ID,
+ Request: resp.Request,
+ Namespace: resp.Namespace,
+ ReleaseName: resp.ReleaseName,
}
//Filter based on the accepted keys
diff --git a/src/k8splugin/internal/app/instance_test.go b/src/k8splugin/internal/app/instance_test.go
index 1b84b449..b79cf388 100644
--- a/src/k8splugin/internal/app/instance_test.go
+++ b/src/k8splugin/internal/app/instance_test.go
@@ -318,128 +318,6 @@ func TestInstanceGet(t *testing.T) {
})
}
-func TestInstanceStatus(t *testing.T) {
- oldkrdPluginData := utils.LoadedPlugins
-
- defer func() {
- utils.LoadedPlugins = oldkrdPluginData
- }()
-
- err := LoadMockPlugins(utils.LoadedPlugins)
- if err != nil {
- t.Fatalf("LoadMockPlugins returned an error (%s)", err)
- }
-
- t.Run("Successfully Get Instance Status", func(t *testing.T) {
- db.DBconn = &db.MockDB{
- Items: map[string]map[string][]byte{
- InstanceKey{ID: "HaKpys8e"}.String(): {
- "instanceStatus": []byte(
- `{
- "request": {
- "profile-name":"profile1",
- "rb-name":"test-rbdef",
- "rb-version":"v1",
- "cloud-region":"region1"
- },
- "ready": true,
- "resourceCount": 2,
- "podStatuses": [
- {
- "name": "test-pod1",
- "namespace": "default",
- "ready": true,
- "ipaddresses": ["192.168.1.1", "192.168.2.1"]
- },
- {
- "name": "test-pod2",
- "namespace": "default",
- "ready": true,
- "ipaddresses": ["192.168.4.1", "192.168.5.1"]
- }
- ]
- }`),
- },
- },
- }
-
- expected := InstanceStatus{
- Request: InstanceRequest{
- RBName: "test-rbdef",
- RBVersion: "v1",
- ProfileName: "profile1",
- CloudRegion: "region1",
- },
- Ready: true,
- ResourceCount: 2,
- PodStatuses: []PodStatus{
- {
- Name: "test-pod1",
- Namespace: "default",
- Ready: true,
- IPAddresses: []string{"192.168.1.1", "192.168.2.1"},
- },
- {
- Name: "test-pod2",
- Namespace: "default",
- Ready: true,
- IPAddresses: []string{"192.168.4.1", "192.168.5.1"},
- },
- },
- }
- ic := NewInstanceClient()
- id := "HaKpys8e"
- data, err := ic.Status(id)
- if err != nil {
- t.Fatalf("TestInstanceStatus returned an error (%s)", err)
- }
- if !reflect.DeepEqual(expected, data) {
- t.Fatalf("TestInstanceStatus returned:\n result=%v\n expected=%v",
- data, expected)
- }
- })
-
- t.Run("Get non-existing Instance", func(t *testing.T) {
- db.DBconn = &db.MockDB{
- Items: map[string]map[string][]byte{
- InstanceKey{ID: "HaKpys8e"}.String(): {
- "instanceStatus": []byte(
- `{
- "request": {
- "profile-name":"profile1",
- "rb-name":"test-rbdef",
- "rb-version":"v1",
- "cloud-region":"region1"
- },
- "ready": true,
- "resourceCount": 2,
- "podStatuses": [
- {
- "name": "test-pod1",
- "namespace": "default",
- "ready": true,
- "ipaddresses": ["192.168.1.1", "192.168.2.1"]
- },
- {
- "name": "test-pod2",
- "namespace": "default",
- "ready": true,
- "ipaddresses": ["192.168.4.1", "192.168.5.1"]
- }
- ]
- }`),
- },
- },
- }
-
- ic := NewInstanceClient()
- _, err := ic.Get("non-existing")
- if err == nil {
- t.Fatal("Expected error, got pass", err)
- }
- })
-}
-
func TestInstanceFind(t *testing.T) {
oldkrdPluginData := utils.LoadedPlugins
diff --git a/src/k8splugin/internal/helm/helm.go b/src/k8splugin/internal/helm/helm.go
index 2150758b..d3715fce 100644
--- a/src/k8splugin/internal/helm/helm.go
+++ b/src/k8splugin/internal/helm/helm.go
@@ -23,6 +23,7 @@ import (
"os"
"path/filepath"
"regexp"
+ "sort"
"strings"
utils "github.com/onap/multicloud-k8s/src/k8splugin/internal"
@@ -55,16 +56,17 @@ type Template interface {
// TemplateClient implements the Template interface
// It will also be used to maintain any localized state
type TemplateClient struct {
- whitespaceRegex *regexp.Regexp
- kubeVersion string
- kubeNameSpace string
- releaseName string
+ emptyRegex *regexp.Regexp
+ kubeVersion string
+ kubeNameSpace string
+ releaseName string
}
// NewTemplateClient returns a new instance of TemplateClient
func NewTemplateClient(k8sversion, namespace, releasename string) *TemplateClient {
return &TemplateClient{
- whitespaceRegex: regexp.MustCompile(`^\s*$`),
+ // emptyRegex defines template content that could be considered empty yaml-wise
+ emptyRegex: regexp.MustCompile(`(?m)\A(^(\s*#.*|\s*)$\n?)*\z`),
// defaultKubeVersion is the default value of --kube-version flag
kubeVersion: k8sversion,
kubeNameSpace: namespace,
@@ -209,11 +211,19 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile
continue
}
rmap := releaseutil.SplitManifests(v)
- count := 0
- for _, v1 := range rmap {
- key := fmt.Sprintf("%s-%d", k, count)
- newRenderedTemplates[key] = v1
- count = count + 1
+
+ // Iterating over map can yield different order at times
+ // so first we'll sort keys
+ sortedKeys := make([]string, len(rmap))
+ for k1, _ := range rmap {
+ sortedKeys = append(sortedKeys, k1)
+ }
+ // This makes empty files have the lowest indices
+ sort.Strings(sortedKeys)
+
+ for k1, v1 := range sortedKeys {
+ key := fmt.Sprintf("%s-%d", k, k1)
+ newRenderedTemplates[key] = rmap[v1]
}
}
@@ -232,7 +242,7 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile
}
// blank template after execution
- if h.whitespaceRegex.MatchString(data) {
+ if h.emptyRegex.MatchString(data) {
continue
}
@@ -260,7 +270,7 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile
func getGroupVersionKind(data string) (schema.GroupVersionKind, error) {
out, err := k8syaml.ToJSON([]byte(data))
if err != nil {
- return schema.GroupVersionKind{}, pkgerrors.Wrap(err, "Converting yaml to json")
+ return schema.GroupVersionKind{}, pkgerrors.Wrap(err, "Converting yaml to json:\n"+data)
}
simpleMeta := json.SimpleMetaFactory{}
diff --git a/src/k8splugin/internal/helm/helm_test.go b/src/k8splugin/internal/helm/helm_test.go
index 1e676c52..817bbaa3 100644
--- a/src/k8splugin/internal/helm/helm_test.go
+++ b/src/k8splugin/internal/helm/helm_test.go
@@ -155,6 +155,33 @@ func TestGenerateKubernetesArtifacts(t *testing.T) {
},
expectedError: "",
},
+ {
+ label: "Generate artifacts from multi-template and empty files v1",
+ chartPath: "../../mock_files/mock_charts/testchart3",
+ valueFiles: []string{},
+ values: []string{
+ "goingEmpty=false",
+ },
+ expectedHashMap: map[string]string{
+ "testchart3/templates/multi.yaml-2": "e24cbbefac2c2f700880b8fd041838f2dd48bbc1e099e7c1d2485ae7feb3da0d",
+ "testchart3/templates/multi.yaml-3": "592a8e5b2c35b8469aa45703a835bc00657bfe36b51eb08427a46e7d22fb1525",
+ },
+ expectedError: "",
+ },
+ {
+ label: "Generate artifacts from multi-template and empty files v2",
+ chartPath: "../../mock_files/mock_charts/testchart3",
+ valueFiles: []string{},
+ values: []string{
+ "goingEmpty=true",
+ },
+ expectedHashMap: map[string]string{
+ "testchart3/templates/multi.yaml-3": "e24cbbefac2c2f700880b8fd041838f2dd48bbc1e099e7c1d2485ae7feb3da0d",
+ "testchart3/templates/multi.yaml-4": "0bea01e65148584609ede5000c024241ba1c35b440b32ec0a4f7013015715bfe",
+ "testchart3/templates/multi.yaml-5": "6a5af22538c273b9d4a3156e3b6bb538c655041eae31e93db21a9e178f73ecf0",
+ },
+ expectedError: "",
+ },
}
h := sha256.New()
@@ -192,7 +219,7 @@ func TestGenerateKubernetesArtifacts(t *testing.T) {
}
}
if gotHash != expectedHash {
- t.Fatalf("Got unexpected hash for %s", f)
+ t.Fatalf("Got unexpected hash for %s: '%s'; expected: '%s'", f, gotHash, expectedHash)
}
}
}
diff --git a/src/k8splugin/internal/plugin/helpers.go b/src/k8splugin/internal/plugin/helpers.go
index ad785ab7..7078b813 100644
--- a/src/k8splugin/internal/plugin/helpers.go
+++ b/src/k8splugin/internal/plugin/helpers.go
@@ -68,6 +68,9 @@ type Reference interface {
//Delete a kubernetes resource described in the provided namespace
Delete(resource helm.KubernetesResource, namespace string, client KubernetesConnector) error
+
+ //Update kubernetes resource based on the groupVersionKind and resourceName provided in resource
+ Update(yamlFilePath string, namespace string, client KubernetesConnector) (string, error)
}
// GetPluginByKind returns a plugin by the kind name
diff --git a/src/k8splugin/internal/plugin/helpers_test.go b/src/k8splugin/internal/plugin/helpers_test.go
new file mode 100644
index 00000000..b968072f
--- /dev/null
+++ b/src/k8splugin/internal/plugin/helpers_test.go
@@ -0,0 +1,83 @@
+/*
+ * Copyright © 2020 Samsung Electronics
+ *
+ * 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 plugin
+
+import (
+ "testing"
+
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+
+ utils "github.com/onap/multicloud-k8s/src/k8splugin/internal"
+ "github.com/onap/multicloud-k8s/src/k8splugin/internal/config"
+)
+
+func TestTagPodsIfPresent(t *testing.T) {
+
+ testCases := []struct{
+ testName string
+ inputUnstructSrc string
+ valueToTag string
+ shouldFailBeforeCheck bool //This flag provides information if .spec.template.metadata.labels path should be reachable or not
+ }{
+ {
+ testName: "Resource with no child PodTemplateSpec",
+ inputUnstructSrc: "../../mock_files/mock_yamls/configmap.yaml",
+ valueToTag: "test1",
+ shouldFailBeforeCheck: true,
+ },
+ {
+ testName: "Deployment with PodTemplateSpec",
+ inputUnstructSrc: "../../mock_files/mock_yamls/deployment.yaml",
+ valueToTag: "test2",
+ shouldFailBeforeCheck: false,
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.testName, func(t *testing.T){
+ holderUnstr := new(unstructured.Unstructured)
+ _, err := utils.DecodeYAML(testCase.inputUnstructSrc, holderUnstr)
+ if err != nil {
+ t.Fatal("Couldn't decode Yaml:", err)
+ }
+ TagPodsIfPresent(holderUnstr, testCase.valueToTag)
+ t.Log(holderUnstr)
+ var labelsFinder map[string]interface{} = holderUnstr.Object
+ var ok bool
+ for _, key := range []string{"spec", "template", "metadata", "labels"} {
+ labelsFinder, ok = labelsFinder[key].(map[string]interface{})
+ if !ok {
+ if testCase.shouldFailBeforeCheck {
+ return
+ } else {
+ t.Fatalf("Error converting %s to map", key)
+ }
+ }
+ }
+ if testCase.shouldFailBeforeCheck {
+ t.Fatal("Error, nested element '.spec.template.metadata.labels' shouldn't be reachable")
+ }
+ label, ok := labelsFinder[config.GetConfiguration().KubernetesLabelName].(string)
+ if !ok {
+ t.Fatalf("Error extracting string label '%s'", config.GetConfiguration().KubernetesLabelName)
+ }
+ if label != testCase.valueToTag {
+ t.Fatalf("Error, expected label '%s' but received '%s'", testCase.valueToTag, label)
+ }
+ })
+ }
+}
diff --git a/src/k8splugin/internal/rb/profile.go b/src/k8splugin/internal/rb/profile.go
index 6efa23b8..f8b07abf 100644
--- a/src/k8splugin/internal/rb/profile.go
+++ b/src/k8splugin/internal/rb/profile.go
@@ -268,50 +268,51 @@ func (v *ProfileClient) Download(rbName, rbVersion, prName string) ([]byte, erro
}
//Resolve returns the path where the helm chart merged with
-//configuration overrides resides.
+//configuration overrides resides and final ReleaseName picked for instantiation
func (v *ProfileClient) Resolve(rbName string, rbVersion string,
- profileName string, values []string) ([]helm.KubernetesResourceTemplate, error) {
+ profileName string, values []string, overrideReleaseName string) ([]helm.KubernetesResourceTemplate, string, error) {
var sortedTemplates []helm.KubernetesResourceTemplate
+ var finalReleaseName 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, pkgerrors.Wrap(err, "Downloading Profile")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Downloading Profile")
}
prPath, err := ExtractTarBall(bytes.NewBuffer(prData))
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Extracting Profile Content")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Extracting Profile Content")
}
prYamlClient, err := ProcessProfileYaml(prPath, v.manifestName)
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Processing Profile Manifest")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Processing Profile Manifest")
}
definitionClient := NewDefinitionClient()
definition, err := definitionClient.Get(rbName, rbVersion)
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Getting Definition Metadata")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Getting Definition Metadata")
}
defData, err := definitionClient.Download(rbName, rbVersion)
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Downloading Definition")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Downloading Definition")
}
chartBasePath, err := ExtractTarBall(bytes.NewBuffer(defData))
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Extracting Definition Charts")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Extracting Definition Charts")
}
//Get the definition ID and download its contents
profile, err := v.Get(rbName, rbVersion, profileName)
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Getting Profile")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Getting Profile")
}
//Copy the profile configresources to the chart locations
@@ -321,22 +322,28 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string,
// chartpath: chart/config/resources/config.yaml
err = prYamlClient.CopyConfigurationOverrides(chartBasePath)
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Copying configresources to chart")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Copying configresources to chart")
+ }
+
+ if overrideReleaseName == "" {
+ finalReleaseName = profile.ReleaseName
+ } else {
+ finalReleaseName = overrideReleaseName
}
helmClient := helm.NewTemplateClient(profile.KubernetesVersion,
profile.Namespace,
- profile.ReleaseName)
+ finalReleaseName)
chartPath := filepath.Join(chartBasePath, definition.ChartName)
sortedTemplates, err = helmClient.GenerateKubernetesArtifacts(chartPath,
[]string{prYamlClient.GetValues()},
values)
if err != nil {
- return sortedTemplates, pkgerrors.Wrap(err, "Generate final k8s yaml")
+ return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Generate final k8s yaml")
}
- return sortedTemplates, nil
+ return sortedTemplates, finalReleaseName, nil
}
// Returns an empty profile with the following contents
diff --git a/src/k8splugin/internal/rb/profile_test.go b/src/k8splugin/internal/rb/profile_test.go
index 26b0161d..a434e5a1 100644
--- a/src/k8splugin/internal/rb/profile_test.go
+++ b/src/k8splugin/internal/rb/profile_test.go
@@ -18,12 +18,14 @@ package rb
import (
"bytes"
+ "os"
"reflect"
"sort"
"strings"
"testing"
"github.com/onap/multicloud-k8s/src/k8splugin/internal/db"
+ "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
pkgerrors "github.com/pkg/errors"
)
@@ -597,19 +599,142 @@ func TestDownloadProfile(t *testing.T) {
}
func TestResolveProfile(t *testing.T) {
+ profileContent := []byte("H4sICLmjT1wAA3Byb2ZpbGUudGFyAO1Y32/bNhD2s/6Kg/KyYZZsy" +
+ "78K78lLMsxY5gRxmqIYhoKWaJsYJWokZdfo+r/vSFmunCZNBtQJ1vF7sXX36e54vDN5T" +
+ "knGFlTpcEtS3jgO2ohBr2c/EXc/29Gg1+h0e1F32Ol1B1Gj3Ymifr8B7SPFc4BCaSIBG" +
+ "lII/SXeY/r/KIIg8NZUKiayEaw7nt7mdOQBrAkvqBqBL1ArWULflRJbJz4SYpEt2FJSJ" +
+ "QoZ21cAAlgwTnOiVyPQWFQLwVuqmCdMthKac7FNaVZWmqWjkRWRuuSvScF1gFZVwYOEr" +
+ "luapjknaOazd186Z98S7tver+3j0f5v1/q/18f+7w56bdf/zwFF5ZqV/WtbH6YioVdCa" +
+ "hRkJEVBVSFBvUNRmyNpesgwors0lmkqM8KNzRG8iqLIWN45GUGv57l+fkFUP9PH9GF6f" +
+ "IgH+kP9b76b/o+GUb9r5J1O1I0a0D9mUBX+5/1/55g+io9/sf+DnuF1sA4Gbv+fA1++p" +
+ "n0dH4+c/92oPaztv+n/fn84dOf/c+AETkW+lWy50hC1O69gguc1R6HEw5xoHAuaKIq9E" +
+ "+8ELvCikCmaQJElVIJeURjnJMaPnaYJt+UoAVHYhu8Mwd+p/O9/RAtbUUBKtnj+aygUR" +
+ "RNM2ZkB6PuY5hpvCzhY4L2fkSymsGF6Zd3sjIRo4u3OhJhrgmyC/ByfFnUeEG0DLrHSO" +
+ "h+1WpvNJiQ23FDIZYuXVNW6mJyeT2fnAYZsX3qdcaoUSPpXwSQudr4FkmNEMZljnJxsQ" +
+ "EggOPmgTgsT8UYyzbJlE5RY6A2RFK0kTGnJ5oU+SFcVH666TsCEkQz88QwmMx9+Gs8ms" +
+ "ybaeDO5+eXy9Q28GV9fj6c3k/MZXF7D6eX0bHIzuZzi088wnr6FXyfTsyZQTBa6oe9za" +
+ "eLHIJlJJE1M1maUHgSwEGVAKqcxW7AY15UtC7KksDS3uQyXAzmVKVNmOxWGl6AVzlKmb" +
+ "VGozxcVeh7J2W01S2LOVAsHyj9ZlozgbP+74qVUk4RoMtrfMD98wCzGvEiwXHD3U5GFi" +
+ "4Jzo/QhhI8fd0yFu3c/fa/d8zmZU67KsRRDefCt/Qu7YdQSw1PzNTS3W1QGnyRVef+N5" +
+ "YHDKZao/4MP/ju/siEpp0SVQYbX5UNlxxJwizCFyzuMWXkLNySzIyZs4wBrTpXE23I62" +
+ "wlPRZHp0qJCC7EWslxpSnS8uqgt/YmLr2btnZXaDhnwA4NPzueT8lEt126AyExPY44rS" +
+ "YA1bJPl15JgRaEdM9CKv/f1YDHdE5e1cYVFdiUwoduDJC+5mBMe5nstbndCF9Zfxakpa" +
+ "1aNP2LK/Xffhuc3fTNfUYlfzH8a/h97qhmVaikNPi2+nItq8exGtLA+SdW9rgUvUvqbq" +
+ "YkDi6mRXNk/V1pUxy0uYsI1S+meU+XsPo2kJLnMOKZGy4J6Xt3XgZuHTayEKv3XZLjy+" +
+ "yJ66WPQwcHBwcHBwcHBwcHBwcHBwcHhm8Q/mTHqWgAoAAA=")
+ defContent := []byte("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" +
+ "cOHDgwIEDB18K/AcxEDJDAHgAAA==")
testCases := []struct {
label string
rbname, rbversion, prname string
+ releaseName string
expected map[string][]string
+ expectedReleaseName string
expectedError string
mockdb *db.MockDB
}{
{
- label: "Resolve Resource Bundle Profile",
- rbname: "testresourcebundle",
- rbversion: "v1",
- prname: "profile1",
- expected: map[string][]string{},
+ label: "Resolve Resource Bundle Profile with override release name",
+ rbname: "testresourcebundle",
+ rbversion: "v1",
+ prname: "profile1",
+ expectedReleaseName: "testprofilereleasename",
+ expected: map[string][]string{},
+ mockdb: &db.MockDB{
+ Items: map[string]map[string][]byte{
+ ProfileKey{RBName: "testresourcebundle", RBVersion: "v1",
+ ProfileName: "profile1"}.String(): {
+ "profilemetadata": []byte(
+ "{\"profile-name\":\"profile1\"," +
+ "\"release-name\":\"testprofilereleasename\"," +
+ "\"namespace\":\"testnamespace\"," +
+ "\"rb-name\":\"testresourcebundle\"," +
+ "\"rb-version\":\"v1\"," +
+ "\"kubernetesversion\":\"1.12.3\"}"),
+ // base64 encoding of vagrant/tests/vnfs/testrb/helm/profile
+ "profilecontent": profileContent,
+ },
+ DefinitionKey{RBName: "testresourcebundle", RBVersion: "v1"}.String(): {
+ "defmetadata": []byte(
+ "{\"rb-name\":\"testresourcebundle\"," +
+ "\"rb-version\":\"v1\"," +
+ "\"chart-name\":\"vault-consul-dev\"," +
+ "\"description\":\"testresourcebundle\"}"),
+ // base64 encoding of vagrant/tests/vnfs/testrb/helm/vault-consul-dev
+ "defcontent": defContent,
+ },
+ },
+ },
+ },
+ {
+ label: "Resolve Resource Bundle Profile",
+ rbname: "testresourcebundle",
+ rbversion: "v1",
+ prname: "profile1",
+ releaseName: "overwritereleasename",
+ expectedReleaseName: "overwritereleasename",
+ expected: map[string][]string{},
mockdb: &db.MockDB{
Items: map[string]map[string][]byte{
ProfileKey{RBName: "testresourcebundle", RBVersion: "v1",
@@ -622,29 +747,7 @@ func TestResolveProfile(t *testing.T) {
"\"rb-version\":\"v1\"," +
"\"kubernetesversion\":\"1.12.3\"}"),
// base64 encoding of vagrant/tests/vnfs/testrb/helm/profile
- "profilecontent": []byte("H4sICLmjT1wAA3Byb2ZpbGUudGFyAO1Y32/bNhD2s/6Kg/KyYZZsy" +
- "78K78lLMsxY5gRxmqIYhoKWaJsYJWokZdfo+r/vSFmunCZNBtQJ1vF7sXX36e54vDN5T" +
- "knGFlTpcEtS3jgO2ohBr2c/EXc/29Gg1+h0e1F32Ol1B1Gj3Ymifr8B7SPFc4BCaSIBG" +
- "lII/SXeY/r/KIIg8NZUKiayEaw7nt7mdOQBrAkvqBqBL1ArWULflRJbJz4SYpEt2FJSJ" +
- "QoZ21cAAlgwTnOiVyPQWFQLwVuqmCdMthKac7FNaVZWmqWjkRWRuuSvScF1gFZVwYOEr" +
- "luapjknaOazd186Z98S7tver+3j0f5v1/q/18f+7w56bdf/zwFF5ZqV/WtbH6YioVdCa" +
- "hRkJEVBVSFBvUNRmyNpesgwors0lmkqM8KNzRG8iqLIWN45GUGv57l+fkFUP9PH9GF6f" +
- "IgH+kP9b76b/o+GUb9r5J1O1I0a0D9mUBX+5/1/55g+io9/sf+DnuF1sA4Gbv+fA1++p" +
- "n0dH4+c/92oPaztv+n/fn84dOf/c+AETkW+lWy50hC1O69gguc1R6HEw5xoHAuaKIq9E" +
- "+8ELvCikCmaQJElVIJeURjnJMaPnaYJt+UoAVHYhu8Mwd+p/O9/RAtbUUBKtnj+aygUR" +
- "RNM2ZkB6PuY5hpvCzhY4L2fkSymsGF6Zd3sjIRo4u3OhJhrgmyC/ByfFnUeEG0DLrHSO" +
- "h+1WpvNJiQ23FDIZYuXVNW6mJyeT2fnAYZsX3qdcaoUSPpXwSQudr4FkmNEMZljnJxsQ" +
- "EggOPmgTgsT8UYyzbJlE5RY6A2RFK0kTGnJ5oU+SFcVH666TsCEkQz88QwmMx9+Gs8ms" +
- "ybaeDO5+eXy9Q28GV9fj6c3k/MZXF7D6eX0bHIzuZzi088wnr6FXyfTsyZQTBa6oe9za" +
- "eLHIJlJJE1M1maUHgSwEGVAKqcxW7AY15UtC7KksDS3uQyXAzmVKVNmOxWGl6AVzlKmb" +
- "VGozxcVeh7J2W01S2LOVAsHyj9ZlozgbP+74qVUk4RoMtrfMD98wCzGvEiwXHD3U5GFi" +
- "4Jzo/QhhI8fd0yFu3c/fa/d8zmZU67KsRRDefCt/Qu7YdQSw1PzNTS3W1QGnyRVef+N5" +
- "YHDKZao/4MP/ju/siEpp0SVQYbX5UNlxxJwizCFyzuMWXkLNySzIyZs4wBrTpXE23I62" +
- "wlPRZHp0qJCC7EWslxpSnS8uqgt/YmLr2btnZXaDhnwA4NPzueT8lEt126AyExPY44rS" +
- "YA1bJPl15JgRaEdM9CKv/f1YDHdE5e1cYVFdiUwoduDJC+5mBMe5nstbndCF9Zfxakpa" +
- "1aNP2LK/Xffhuc3fTNfUYlfzH8a/h97qhmVaikNPi2+nItq8exGtLA+SdW9rgUvUvqbq" +
- "YkDi6mRXNk/V1pUxy0uYsI1S+meU+XsPo2kJLnMOKZGy4J6Xt3XgZuHTayEKv3XZLjy+" +
- "yJ66WPQwcHBwcHBwcHBwcHBwcHBwcHhm8Q/mTHqWgAoAAA="),
+ "profilecontent": profileContent,
},
DefinitionKey{RBName: "testresourcebundle", RBVersion: "v1"}.String(): {
"defmetadata": []byte(
@@ -653,81 +756,26 @@ func TestResolveProfile(t *testing.T) {
"\"chart-name\":\"vault-consul-dev\"," +
"\"description\":\"testresourcebundle\"}"),
// base64 encoding of vagrant/tests/vnfs/testrb/helm/vault-consul-dev
- "defcontent": []byte("H4sICEetS1wAA3ZhdWx0LWNvbnN1bC1kZXYudGFyAO0c7XLbNjK/+R" +
- "QYujdJehatb+V4czPnOmnPk9bO2Gk7nbaTgUhIxpgiGAK0o3P9QPca92S3C5AU9GXZiax" +
- "c7rA/LJEAFovdxX4AK1/RIlGNSKSySBoxuzp4sn1oAgx6Pf0JsPipv7c63XZ70O61W4Mn" +
- "zVZ7MGg9Ib1HoGUJCqloTsiTXAh1V79N7V8oXC3K/+iC5iqY0kmytTlQwP1ud538W51Wf" +
- "0H+3QF8kObWKLgD/s/lv0eORDbN+fhCkXaz9YIcp4ol8DLPRE4VF+k+vIq8PW+PfM8jlk" +
- "oWkyKNWU7UBSOHGY3go2zZJz+xXMIY0g6a5Bl28Msm//lfAcNUFGRCpyQVihSSAQouyYg" +
- "njLAPEcsU4SmJxCRLOE0jRq65utDTlEgCQPFLiUIMFYXeFPpn8DSy+xGqNMEGLpTKwoOD" +
- "6+vrgGpyA5GPDxLTVR58f3z06uT8VQNI1oN+TBMmJcnZ+4LnsNjhlNAMKIroEOhM6DURO" +
- "aHjnEGbEkjxdc4VT8f7RIqRuqY5Aywxlyrnw0LNsauiD1ZtdwCG0ZT4h+fk+Nwn3xyeH5" +
- "/vA46fj9/+4/THt+Tnw7Ozw5O3x6/OyekZOTo9eXn89vj0BJ6+JYcnv5DXxycv9wkDZsE" +
- "07EOWI/1AJEdGshi5ds7YHAEjYQiSGYv4iEewrnRc0DEjY3HF8hSWQzKWT7hEcUogLwYs" +
- "CZ9wpZVCLi8q8Dya8VIBQnLV8mImo5xnSj9ru4IMS2iRRhfkJzQ8iJcY44OMBPtDJiJmX" +
- "konDFAs2CbAn9X4m8Ffgp53VT2C9EB+n3s3fXmwZP+vaFIwuVUHsMH+d1vd3oL977X6TW" +
- "f/dwHO/jv7vzX7v/epAHN8l4ghTdApjPi4MCoIjmGEdkoGW5hirCcIPQJaGLM3Ildvcjb" +
- "iH0LSabbhbYYqLBUDBQzJzS2sqpK/JoVPgEue/os4jOUMq88WuKE+vNZmtfRgYTNooXPK" +
- "iiR5IwDRNCSHyTWdSsQ9SugY9YilWr9iNizGY2R/Y25aWWSwIVWtlp7u+EoPikMyoolk2" +
- "xHAoTXr40nBYLY46OFWlSwH7QuJygumXyRi/C5hVww4fHzy7enqTjFV9F3M4dXTA4PtAF" +
- "891Y3INWmwl6aAvOg1m9YLGZJGy6uFZuZQYP2MhBFsGhFoHOMmC4G+iCYXQqrQQgqTUnV" +
- "RSt8sQysUEF32UFG2AtnTX8Pw9/BFu9l8WjeqRMLSJIrZXrF5824C81+W79HoGAGRtJgM" +
- "YXOCUeQpuDfQZOnlTIv1SBQpKCasF7X/nCUsgqUaRaejEU+5mlZqn+ViyBZ0IKM5xGYK9" +
- "oiX8CtYk9TMxXGcJi9ZQqfnDIbEsJ5W02wnLuL5d3skZUCTpPkUVb9cDakQlhNfXzDQe6" +
- "bQtpJhzuhlJniqpEago0XcKrBOKcjrF2BRBZPpU9wi6NLBwaTwLQPJAVpcBfoLlsNoVu0" +
- "awzfAHPOPWYhnm4olvKBPIikm7IxFCeWTauefMaQDWmmELPgBpIAvafwzeBF2CqigTfJ/" +
- "wtv2dxy+T1Bib7RCHcQgbpajcjfSkawaz4uhaZcTaW8Az8Otwg1xapoBypPS5KH1W4qxP" +
- "bNbTlY1AOPBLdAEB8MOamtlrwxoSLpdzwMx5SUX2bxd+txBjoO1sBT/KwZRA1UQGG1tjo" +
- "ef/3UH/YE7/9sF3CH/GDyGmE5Y+qnHgZvyv2Z7MC9/sC6dvsv/dgF7Lv9z+d9jnP8Bz+T" +
- "BVcu75CnEAS9rW+JB9EgxOgnrGOTmBrgYJUUM6gLSn4g0GEGuhI0+CcjtbdlTgvRWd69b" +
- "6/4JHbKkjPuBlLWj6gEQ5OMJpe4YmEsQDISgsTF7U6n3HwTDaZiP+H/2if/Or3DkEFBTa" +
- "YgMzsxDhUd3ABEBC8cLPc5NnIadUCJIdhmvS9PxJ3MqZwfxBqOsIniNfUJVdPG9tfR7Lr" +
- "4y+iUWS0I6e5lDeG9+3osf1XLLLMvE6PVcDZNuh8S3mKBfBdpxARa/nmutMq2gS+N4YyX" +
- "kFn5zQBDM0nUQd5VZVX2sRgsrzkdR3X/1NXn+vm+SVfiCztX/fZYh2mkpLrRevAmoLXrK" +
- "ID6wQ3B7VpNm/IA6MYfRThyYig50rqr4hNV9Kp6tasGs6DRNplWWtFEg5TH+AyXSGFJIa" +
- "cC67Ewyhk6QCMyTqntIxqwCvYjFngVxzWX/OxGIPdUKcldhwHMKPb31rjqrWCDoc4clDn" +
- "YEd8T/ld355KugDfF/u99avP8ZdNz9/27Axf8u/n+s+38T+pex7f3i/tLmPHrov5Rf/Le" +
- "F/+a4dkUUiA0GWx2oNGb8XOxdnedW89/c8BFh71dj9avTYZ80yv7ZQ4LR2XHwcsw2f9dm" +
- "xW1+p9lG/q2YoxozI75BQLJsM3XswzJ1YObHTD0outYTpnE1Wy6UiEQSkrdHb5ZSr3smR" +
- "XdqyGew/0v+X2+DLR7+Pvmo8982dHfnvzuAdfI32rsdNXi4/Hu9rpP/TmCD/LdSDbwh/m" +
- "+1+93F+L876Ln4fxdgx////hemAANyOIlFJPfJNyyBTICmELa5+N/F/59Y/6sNSn3SLDU" +
- "JOljSCgNsFJp+Y3/KCmBjhVyV7+PBBvu/lWrgjec/gyX7P+i2nP3fBTj77+z/F1P/S4w5" +
- "glmpIhGwbAisTPWZihYUluqCyspiaKzYdsuF9/A3LCmwCKQOcxdpgXtBV+Vm5lQjr5rh+" +
- "YqlyjTiUkB9ysJFrdPG1dXFmSQvUs1ybASF0pLBM4HLF5Kgh1S6bnFVvbIphsQ7MzyTEp" +
- "IrkXMmzQWyeZyGJGUfCtkJREozVP6whWG3GVtXP4LnZdGlR2ZvziwMQkyAGLv12FwE1s8" +
- "NPT40LlqjToSpZNYXbR6pnm20pqAxYAmVikdBJGbdSvxDRsEdoY3Ab2Ev6FXozarxvg/4" +
- "jBd+eCa2osYa+1YKpK/g9JUXQYMOuzDXZzhTWMeI5VjJGesBsOvr6k5VXbPpnysBedpky" +
- "YVacXN1vr5YU6P92GpvQubrvfUV4Dbs/wb/v5VqwIfn/4Net+Py/13AveX/rj5oD1T2sG" +
- "BwU/7f73cW6v/anb7L/3cCNzcHX3suCHRB4LaCwK8Pbm89T6sVIWdMiuTKzFrbDx0/ATP" +
- "1bz+oSfgD8vaCzX6/UneVxQhCHfz9gayRVHKuB0JbGQwi2TmPY5YSPrJ+ZPKMjQO93Do0" +
- "fA44C4krRFQjkSTiGp90hBl6+latuiJKZXlrRcJqBns5JvgzC8cbI1gFBESrLijNvVXZx" +
- "1Qt2VdABt3SrI0SL4Pgo7HtW6L72/9ZPPlQB7DB/nc6ve6i/e93Xf3HTsDZf2f/d2f/a9" +
- "NtDoMX8tZpAEPQD2gjrMmzCp/LPsg2nXiDSEoruo+23AisXH9tpScM7FnK5aQaFsyb9rI" +
- "6wUJv2/jKSi/SqUnDkwbdIOcwznqdVmgsjGY+nUeuRY6KgHwvW4YUUsy13mU2buZewPXd" +
- "QY1V25DlPFUj4v9J+neNqPBi7YU1erHy1lrCevbWuHRZhe3WVirNEnMki3KG/0fkkqXr1" +
- "WVp3iPcxKUKhHOHI9hicndoy0P915R7UCmvRQ7JdvWtLLHnSUgYfpBnQl9u0OT5PeQTGN" +
- "LtKOArbCXh35aKRmyplqUjun+Ey4D+d69z1l9TCf3rYpu/+wZJoFtmHWkBRhY6zjQiRKU" +
- "wfZEl5deKFeQPMux3WRrNcFRDb36D0b/5IXziQNz28GRe7v/mVxjsd5qb9gskp36+vfVL" +
- "Tq0nx6zULKMm7VEDp/8RuH/8V5eKPTD733z/01zO/6G/i/92AS7+c/HfbuO/MuN/KkllU" +
- "bzSj1de6pqDyg3ZLMk3Y59ZDh5f1PEJxDuSqecYDhyCqcdhqFditFxRqmkox0kM4Rbiwb" +
- "mOq0LBsgN5xllgiHuuqasCAL3sVx8yWhJS9dcIddhYnlusjRjmSqCtWEFjsHy5XaW8ki3" +
- "Lpw0Gx8q1/oFXCuAz+x39lU/O9ckL8Rv+oh/93CbLwRbhYef/H+H8n2z2/612e8H/w5P7" +
- "/287Aef/nf9/PP9vOcIF97/e/y06vnv7uwe4sJpAyJfBugFR1Sz4w6ApeV/QBDgCUrFv5" +
- "bUFxFgFp6EoM6pwNlyQhIAloqjOUgCBr4shMJBhnaPx/JwlMXAwZ4Z/Rm205j8D3UIGvQ" +
- "RZQl9kOgrk+XoOzX68tJ3wYJb0N/RJ0NzPUr5y4YEDBw4cOHDgwIEDBw4cOHDgwIEDBw4" +
- "cOHDgwIEDB18K/AcxEDJDAHgAAA=="),
+ "defcontent": defContent,
},
},
},
},
}
+ cleanup := func(krts []helm.KubernetesResourceTemplate) {
+ for _, krt := range krts {
+ os.RemoveAll(krt.FilePath)
+ }
+ }
+
for _, testCase := range testCases {
t.Run(testCase.label, func(t *testing.T) {
db.DBconn = testCase.mockdb
impl := NewProfileClient()
- data, err := impl.Resolve(testCase.rbname, testCase.rbversion, testCase.prname,
- []string{})
+ data, releaseName, err := impl.Resolve(testCase.rbname,
+ testCase.rbversion, testCase.prname, []string{}, testCase.releaseName)
+ defer cleanup(data)
if err != nil {
if testCase.expectedError == "" {
t.Errorf("Resolve returned an unexpected error %s", err)
@@ -736,7 +784,10 @@ func TestResolveProfile(t *testing.T) {
t.Errorf("Resolve returned an unexpected error %s", err)
}
}
- t.Log(data)
+ if testCase.expectedReleaseName != releaseName {
+ t.Errorf("Resolve returned unexpected release name '%s', expected '%s'",
+ releaseName, testCase.expectedReleaseName)
+ }
})
}
}