diff options
Diffstat (limited to 'src/k8splugin/internal')
-rw-r--r-- | src/k8splugin/internal/app/client.go | 136 | ||||
-rw-r--r-- | src/k8splugin/internal/app/config_backend.go | 11 | ||||
-rw-r--r-- | src/k8splugin/internal/app/instance.go | 117 | ||||
-rw-r--r-- | src/k8splugin/internal/app/instance_test.go | 122 | ||||
-rw-r--r-- | src/k8splugin/internal/helm/helm.go | 34 | ||||
-rw-r--r-- | src/k8splugin/internal/helm/helm_test.go | 29 | ||||
-rw-r--r-- | src/k8splugin/internal/plugin/helpers.go | 3 | ||||
-rw-r--r-- | src/k8splugin/internal/plugin/helpers_test.go | 83 | ||||
-rw-r--r-- | src/k8splugin/internal/rb/profile.go | 33 | ||||
-rw-r--r-- | src/k8splugin/internal/rb/profile_test.go | 239 |
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("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" + - "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) + } }) } } |