diff options
Diffstat (limited to 'src/k8splugin/internal')
-rw-r--r-- | src/k8splugin/internal/app/client.go | 39 | ||||
-rw-r--r-- | src/k8splugin/internal/app/client_test.go | 2 | ||||
-rw-r--r-- | src/k8splugin/internal/app/config_backend.go | 6 | ||||
-rw-r--r-- | src/k8splugin/internal/app/instance.go | 14 | ||||
-rw-r--r-- | src/k8splugin/internal/app/instance_test.go | 2 | ||||
-rw-r--r-- | src/k8splugin/internal/healthcheck/healthcheck.go | 157 | ||||
-rw-r--r-- | src/k8splugin/internal/healthcheck/kubeclient.go | 59 | ||||
-rw-r--r-- | src/k8splugin/internal/helm/helm.go | 89 | ||||
-rw-r--r-- | src/k8splugin/internal/helm/helm_test.go | 2 | ||||
-rw-r--r-- | src/k8splugin/internal/rb/profile.go | 28 | ||||
-rw-r--r-- | src/k8splugin/internal/rb/profile_test.go | 2 |
11 files changed, 363 insertions, 37 deletions
diff --git a/src/k8splugin/internal/app/client.go b/src/k8splugin/internal/app/client.go index f0edf8c9..85fefe69 100644 --- a/src/k8splugin/internal/app/client.go +++ b/src/k8splugin/internal/app/client.go @@ -16,6 +16,7 @@ limitations under the License. package app import ( + "io/ioutil" "os" "strings" "time" @@ -32,9 +33,11 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" "k8s.io/client-go/discovery/cached/disk" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" "k8s.io/client-go/restmapper" "k8s.io/client-go/tools/clientcmd" ) @@ -42,6 +45,8 @@ import ( // KubernetesClient encapsulates the different clients' interfaces // we need when interacting with a Kubernetes cluster type KubernetesClient struct { + rawConfig clientcmd.ClientConfig + restConfig *rest.Config clientSet kubernetes.Interface dynamicClient dynamic.Interface discoverClient *disk.CachedDiscoveryClient @@ -168,8 +173,8 @@ func (k *KubernetesClient) getKubeConfig(cloudregion string) (string, error) { return kubeConfigPath, nil } -// init loads the Kubernetes configuation values stored into the local configuration file -func (k *KubernetesClient) init(cloudregion string, iid string) error { +// Init loads the Kubernetes configuation values stored into the local configuration file +func (k *KubernetesClient) Init(cloudregion string, iid string) error { if cloudregion == "" { return pkgerrors.New("Cloudregion is empty") } @@ -209,6 +214,21 @@ func (k *KubernetesClient) init(cloudregion string, iid string) error { } k.restMapper = restmapper.NewDeferredDiscoveryRESTMapper(k.discoverClient) + k.restConfig = config + + //Spawn ClientConfig + kubeFile, err := os.Open(configPath) + if err != nil { + return pkgerrors.Wrap(err, "Opening kubeConfig") + } + kubeData, err := ioutil.ReadAll(kubeFile) + if err != nil { + return pkgerrors.Wrap(err, "Reading kubeConfig") + } + k.rawConfig, err = clientcmd.NewClientConfigFromBytes(kubeData) + if err != nil { + return pkgerrors.Wrap(err, "Creating rawConfig") + } return nil } @@ -423,3 +443,18 @@ func (k *KubernetesClient) GetStandardClient() kubernetes.Interface { func (k *KubernetesClient) GetInstanceID() string { return k.instanceID } + +//Following set of methods are implemented so that KubernetesClient +//implements genericclioptions.RESTClientGetter interface +func (k *KubernetesClient) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + return k.discoverClient, nil +} +func (k *KubernetesClient) ToRESTMapper() (meta.RESTMapper, error) { + return k.GetMapper(), nil +} +func (k *KubernetesClient) ToRawKubeConfigLoader() clientcmd.ClientConfig { + return k.rawConfig +} +func (k *KubernetesClient) ToRESTConfig() (*rest.Config, error) { + return k.restConfig, nil +} diff --git a/src/k8splugin/internal/app/client_test.go b/src/k8splugin/internal/app/client_test.go index 7001d9e2..6db541a4 100644 --- a/src/k8splugin/internal/app/client_test.go +++ b/src/k8splugin/internal/app/client_test.go @@ -72,7 +72,7 @@ func TestInit(t *testing.T) { kubeClient := KubernetesClient{} // Refer to the connection via its name - err = kubeClient.init("mock_connection", "abcdefg") + err = kubeClient.Init("mock_connection", "abcdefg") if err != nil { t.Fatalf("TestGetKubeClient returned an error (%s)", err) } diff --git a/src/k8splugin/internal/app/config_backend.go b/src/k8splugin/internal/app/config_backend.go index 5771c83f..e2f802c7 100644 --- a/src/k8splugin/internal/app/config_backend.go +++ b/src/k8splugin/internal/app/config_backend.go @@ -391,7 +391,7 @@ func scheduleResources(c chan configResourceList) { log.Printf("[scheduleResources]: POST %v %v", data.profile, data.resourceTemplates) for _, inst := range resp { k8sClient := KubernetesClient{} - err = k8sClient.init(inst.Request.CloudRegion, inst.ID) + err = k8sClient.Init(inst.Request.CloudRegion, inst.ID) if err != nil { log.Printf("Getting CloudRegion Information: %s", err.Error()) //Move onto the next cloud region @@ -418,7 +418,7 @@ func scheduleResources(c chan configResourceList) { log.Printf("[scheduleResources]: DELETE %v %v", data.profile, data.resourceTemplates) for _, inst := range resp { k8sClient := KubernetesClient{} - err = k8sClient.init(inst.Request.CloudRegion, inst.ID) + err = k8sClient.Init(inst.Request.CloudRegion, inst.ID) if err != nil { log.Printf("Getting CloudRegion Information: %s", err.Error()) //Move onto the next cloud region @@ -488,7 +488,7 @@ var resolve = func(rbName, rbVersion, profileName string, p Config) (configResou profile.ReleaseName) chartPath := filepath.Join(chartBasePath, t.ChartName) - resTemplates, err = helmClient.GenerateKubernetesArtifacts(chartPath, + resTemplates, _, err = helmClient.GenerateKubernetesArtifacts(chartPath, []string{outputfile.Name()}, nil) if err != nil { diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go index b11283e0..337ce687 100644 --- a/src/k8splugin/internal/app/instance.go +++ b/src/k8splugin/internal/app/instance.go @@ -22,6 +22,8 @@ import ( "log" "strings" + protorelease "k8s.io/helm/pkg/proto/hapi/release" + "github.com/onap/multicloud-k8s/src/k8splugin/internal/db" "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm" "github.com/onap/multicloud-k8s/src/k8splugin/internal/namegenerator" @@ -49,6 +51,7 @@ type InstanceResponse struct { Namespace string `json:"namespace"` ReleaseName string `json:"release-name"` Resources []helm.KubernetesResource `json:"resources"` + Hooks []*protorelease.Hook `json:"hooks"` } // InstanceMiniResponse contains the response from instantiation @@ -147,7 +150,7 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) { } //Execute the kubernetes create command - sortedTemplates, releaseName, err := rb.NewProfileClient().Resolve(i.RBName, i.RBVersion, i.ProfileName, overrideValues, i.ReleaseName) + sortedTemplates, hookList, 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") } @@ -156,7 +159,7 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) { id := namegenerator.Generate() k8sClient := KubernetesClient{} - err = k8sClient.init(i.CloudRegion, id) + err = k8sClient.Init(i.CloudRegion, id) if err != nil { return InstanceResponse{}, pkgerrors.Wrap(err, "Getting CloudRegion Information") } @@ -173,6 +176,7 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) { Namespace: profile.Namespace, ReleaseName: releaseName, Resources: createdResources, + Hooks: hookList, } key := InstanceKey{ @@ -230,7 +234,7 @@ func (v *InstanceClient) Query(id, apiVersion, kind, name, labels string) (Insta } k8sClient := KubernetesClient{} - err = k8sClient.init(resResp.Request.CloudRegion, id) + err = k8sClient.Init(resResp.Request.CloudRegion, id) if err != nil { return InstanceStatus{}, pkgerrors.Wrap(err, "Getting CloudRegion Information") } @@ -296,7 +300,7 @@ func (v *InstanceClient) Status(id string) (InstanceStatus, error) { } k8sClient := KubernetesClient{} - err = k8sClient.init(resResp.Request.CloudRegion, id) + err = k8sClient.Init(resResp.Request.CloudRegion, id) if err != nil { return InstanceStatus{}, pkgerrors.Wrap(err, "Getting CloudRegion Information") } @@ -432,7 +436,7 @@ func (v *InstanceClient) Delete(id string) error { } k8sClient := KubernetesClient{} - err = k8sClient.init(inst.Request.CloudRegion, inst.ID) + err = k8sClient.Init(inst.Request.CloudRegion, inst.ID) if err != nil { return pkgerrors.Wrap(err, "Getting CloudRegion Information") } diff --git a/src/k8splugin/internal/app/instance_test.go b/src/k8splugin/internal/app/instance_test.go index b79cf388..2711a52f 100644 --- a/src/k8splugin/internal/app/instance_test.go +++ b/src/k8splugin/internal/app/instance_test.go @@ -179,7 +179,7 @@ func TestInstanceCreate(t *testing.T) { log.Println(ir) if len(ir.Resources) == 0 { - t.Fatalf("TestInstanceCreate returned empty data (%s)", ir) + t.Fatalf("TestInstanceCreate returned empty data (%+v)", ir) } }) diff --git a/src/k8splugin/internal/healthcheck/healthcheck.go b/src/k8splugin/internal/healthcheck/healthcheck.go new file mode 100644 index 00000000..341b1dba --- /dev/null +++ b/src/k8splugin/internal/healthcheck/healthcheck.go @@ -0,0 +1,157 @@ +/* +Copyright © 2021 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 healthcheck + +import ( + "encoding/json" + + protorelease "k8s.io/helm/pkg/proto/hapi/release" + "k8s.io/helm/pkg/releasetesting" + + "github.com/onap/multicloud-k8s/src/k8splugin/internal/app" + "github.com/onap/multicloud-k8s/src/k8splugin/internal/db" + log "github.com/onap/multicloud-k8s/src/k8splugin/internal/logutils" + "github.com/onap/multicloud-k8s/src/k8splugin/internal/namegenerator" + + pkgerrors "github.com/pkg/errors" +) + +// HealthcheckState holds possible states of Healthcheck instance +type HealthcheckState string + +const ( + HcS_UNKNOWN HealthcheckState = "UNKNOWN" + HcS_STARTED HealthcheckState = "STARTED" + HcS_RUNNING HealthcheckState = "RUNNING" + HcS_SUCCESS HealthcheckState = "SUCCESS" + HcS_FAILURE HealthcheckState = "FAILURE" +) + +// InstanceHCManager interface exposes instance Healthcheck fuctionalities +type InstanceHCManager interface { + Create(instanceId string) (InstanceHCStatus, error) + Get(instanceId, healthcheckId string) (InstanceHCStatus, error) + List(instanceId string) ([]InstanceHCStatus, error) + Delete(instanceId, healthcheckId string) error +} + +// HealthcheckKey is used as the primary key in the db +type HealthcheckKey struct { + InstanceId string `json:"instance-id"` + HealthcheckId string `json:"healthcheck-id"` +} + +// We will use json marshalling to convert to string to +// preserve the underlying structure. +func (dk HealthcheckKey) String() string { + out, err := json.Marshal(dk) + if err != nil { + return "" + } + + return string(out) +} + +// InstanceHCClient implements InstanceHCManager +type InstanceHCClient struct { + storeName string + tagInst string +} + +// InstanceHCStatus holds healthcheck status +type InstanceHCStatus struct { + releasetesting.TestSuite + Id string + Status HealthcheckState +} + +func NewHCClient() *InstanceHCClient { + return &InstanceHCClient{ + storeName: "rbdef", + tagInst: "instanceHC", + } +} + +func (ihc InstanceHCClient) Create(instanceId string) (InstanceHCStatus, error) { + //Generate ID + id := namegenerator.Generate() + + //Determine Cloud Region and namespace + v := app.NewInstanceClient() + instance, err := v.Get(instanceId) + if err != nil { + return InstanceHCStatus{}, pkgerrors.Wrap(err, "Getting instance") + } + + //Prepare Environment, Request and Release structs + //TODO In future could derive params from request + client, err := NewKubeClient(instanceId, instance.Request.CloudRegion) + if err != nil { + return InstanceHCStatus{}, pkgerrors.Wrap(err, "Preparing KubeClient") + } + env := &releasetesting.Environment{ + Namespace: instance.Namespace, + KubeClient: client, + Parallel: false, + } + release := protorelease.Release{ + Name: instance.ReleaseName, + Hooks: instance.Hooks, + } + + //Run HC + testSuite, err := releasetesting.NewTestSuite(&release) + if err != nil { + log.Error("Error creating TestSuite", log.Fields{ + "Release": release, + }) + return InstanceHCStatus{}, pkgerrors.Wrap(err, "Creating TestSuite") + } + if err = testSuite.Run(env); err != nil { + log.Error("Error running TestSuite", log.Fields{ + "TestSuite": testSuite, + "Environment": env, + }) + return InstanceHCStatus{}, pkgerrors.Wrap(err, "Running TestSuite") + } + + //Save state + ihcs := InstanceHCStatus{ + TestSuite: *testSuite, + Id: id, + Status: HcS_STARTED, + } + key := HealthcheckKey{ + InstanceId: instance.ID, + HealthcheckId: id, + } + err = db.DBconn.Create(ihc.storeName, key, ihc.tagInst, ihcs) + if err != nil { + return ihcs, pkgerrors.Wrap(err, "Creating Instance DB Entry") + } + + return ihcs, nil +} + +func (ihc InstanceHCClient) Get(instanceId, healthcheckId string) (InstanceHCStatus, error) { + return InstanceHCStatus{}, nil +} + +func (ihc InstanceHCClient) Delete(instanceId, healthcheckId string) error { + return nil +} + +func (ihc InstanceHCClient) List(instanceId string) ([]InstanceHCStatus, error) { + return make([]InstanceHCStatus, 0), nil +} diff --git a/src/k8splugin/internal/healthcheck/kubeclient.go b/src/k8splugin/internal/healthcheck/kubeclient.go new file mode 100644 index 00000000..be4c6fcc --- /dev/null +++ b/src/k8splugin/internal/healthcheck/kubeclient.go @@ -0,0 +1,59 @@ +/* +Copyright © 2021 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 healthcheck + +import ( + "k8s.io/helm/pkg/kube" + "k8s.io/helm/pkg/tiller/environment" + + "github.com/onap/multicloud-k8s/src/k8splugin/internal/app" + "github.com/onap/multicloud-k8s/src/k8splugin/internal/config" + + pkgerrors "github.com/pkg/errors" +) + +//implements environment.KubeClient but overrides it so that +//custom labels can be injected into created resources +// using internal k8sClient +type KubeClientImpl struct { + environment.KubeClient + labels map[string]string + k app.KubernetesClient +} + +func NewKubeClient(instanceId, cloudRegion string) (*KubeClientImpl, error) { + k8sClient := app.KubernetesClient{} + err := k8sClient.Init(cloudRegion, instanceId) + if err != nil { + return nil, pkgerrors.Wrap(err, "Initializing k8sClient") + } + return &KubeClientImpl{ + labels: map[string]string{ + config.GetConfiguration().KubernetesLabelName: instanceId, + }, + KubeClient: kube.New(&k8sClient), + k: k8sClient, + }, nil +} + +/* FIXME +// Need to correct this later and provide override of Create method to use our k8sClient +// So that healthcheck hook resources would be labeled with vf-module data just like currently +// every k8splugin-managed resource is + +//Create function is overrided to label test resources with custom labels +func (kci *KubeClientImpl) Create(namespace string, reader io.Reader, timeout int64, shouldWait bool) error { + return nil +} +*/ diff --git a/src/k8splugin/internal/helm/helm.go b/src/k8splugin/internal/helm/helm.go index d3715fce..d39e8404 100644 --- a/src/k8splugin/internal/helm/helm.go +++ b/src/k8splugin/internal/helm/helm.go @@ -1,5 +1,6 @@ /* * Copyright 2018 Intel Corporation, Inc + * Copyright © 2021 Samsung Electronics * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +25,7 @@ import ( "path/filepath" "regexp" "sort" + "strconv" "strings" utils "github.com/onap/multicloud-k8s/src/k8splugin/internal" @@ -35,8 +37,10 @@ import ( "k8s.io/apimachinery/pkg/util/validation" k8syaml "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/helm/pkg/chartutil" + "k8s.io/helm/pkg/hooks" "k8s.io/helm/pkg/manifest" "k8s.io/helm/pkg/proto/hapi/chart" + protorelease "k8s.io/helm/pkg/proto/hapi/release" "k8s.io/helm/pkg/releaseutil" "k8s.io/helm/pkg/renderutil" "k8s.io/helm/pkg/tiller" @@ -46,6 +50,7 @@ import ( // Template is the interface for all helm templating commands // Any backend implementation will implement this interface and will // access the functionality via this. +// FIXME Template is not referenced anywhere type Template interface { GenerateKubernetesArtifacts( chartPath string, @@ -74,6 +79,12 @@ func NewTemplateClient(k8sversion, namespace, releasename string) *TemplateClien } } +// Define hooks that are honored by k8splugin +var honoredEvents = map[string]protorelease.Hook_Event{ + hooks.ReleaseTestSuccess: protorelease.Hook_RELEASE_TEST_SUCCESS, + hooks.ReleaseTestFailure: protorelease.Hook_RELEASE_TEST_FAILURE, +} + // Combines valueFiles and values into a single values stream. // values takes precedence over valueFiles func (h *TemplateClient) processValues(valueFiles []string, values []string) ([]byte, error) { @@ -138,12 +149,60 @@ func (h *TemplateClient) mergeValues(dest map[string]interface{}, src map[string return dest } +// Checks whether resource is a hook and if it is, returns hook struct +//Logic is based on private method +//file *manifestFile) sort(result *result) error +//of helm/pkg/tiller package +func isHook(path, resource string) (*protorelease.Hook, error) { + + var entry releaseutil.SimpleHead + err := yaml.Unmarshal([]byte(resource), &entry) + if err != nil { + return nil, pkgerrors.Wrap(err, "Loading resource to YAML") + } + //If resource has no metadata it can't be a hook + if entry.Metadata == nil || + entry.Metadata.Annotations == nil || + len(entry.Metadata.Annotations) == 0 { + return nil, nil + } + //Determine hook weight + hookWeight, err := strconv.Atoi(entry.Metadata.Annotations[hooks.HookWeightAnno]) + if err != nil { + hookWeight = 0 + } + //Prepare hook obj + resultHook := &protorelease.Hook{ + Name: entry.Metadata.Name, + Kind: entry.Kind, + Path: path, + Manifest: resource, + Events: []protorelease.Hook_Event{}, + Weight: int32(hookWeight), + DeletePolicies: []protorelease.Hook_DeletePolicy{}, + } + //Determine hook's events + hookTypes, ok := entry.Metadata.Annotations[hooks.HookAnno] + if !ok { + return resultHook, nil + } + for _, hookType := range strings.Split(hookTypes, ",") { + hookType = strings.ToLower(strings.TrimSpace(hookType)) + e, ok := honoredEvents[hookType] + if ok { + resultHook.Events = append(resultHook.Events, e) + } + } + return resultHook, nil +} + // GenerateKubernetesArtifacts a mapping of type to fully evaluated helm template func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFiles []string, - values []string) ([]KubernetesResourceTemplate, error) { + values []string) ([]KubernetesResourceTemplate, []*protorelease.Hook, error) { var outputDir, chartPath, namespace, releaseName string var retData []KubernetesResourceTemplate + var hookList []*protorelease.Hook releaseName = h.releaseName namespace = h.kubeNameSpace @@ -151,16 +210,16 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile // verify chart path exists if _, err := os.Stat(inputPath); err == nil { if chartPath, err = filepath.Abs(inputPath); err != nil { - return retData, err + return retData, hookList, err } } else { - return retData, err + return retData, hookList, err } //Create a temp directory in the system temp folder outputDir, err := ioutil.TempDir("", "helm-tmpl-") if err != nil { - return retData, pkgerrors.Wrap(err, "Got error creating temp dir") + return retData, hookList, pkgerrors.Wrap(err, "Got error creating temp dir") } if namespace == "" { @@ -170,18 +229,18 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile // get combined values and create config rawVals, err := h.processValues(valueFiles, values) if err != nil { - return retData, err + return retData, hookList, err } config := &chart.Config{Raw: string(rawVals), Values: map[string]*chart.Value{}} if msgs := validation.IsDNS1123Label(releaseName); releaseName != "" && len(msgs) > 0 { - return retData, fmt.Errorf("release name %s is not a valid DNS label: %s", releaseName, strings.Join(msgs, ";")) + return retData, hookList, fmt.Errorf("release name %s is not a valid DNS label: %s", releaseName, strings.Join(msgs, ";")) } // Check chart requirements to make sure all dependencies are present in /charts c, err := chartutil.Load(chartPath) if err != nil { - return retData, pkgerrors.Errorf("Got error: %s", err.Error()) + return retData, hookList, pkgerrors.Errorf("Got error: %s", err.Error()) } renderOpts := renderutil.Options{ @@ -197,7 +256,7 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile renderedTemplates, err := renderutil.Render(c, config, renderOpts) if err != nil { - return retData, err + return retData, hookList, err } newRenderedTemplates := make(map[string]string) @@ -246,16 +305,24 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile continue } + hook, _ := isHook(b, data) + // if hook is not nil, then append it to hooks list and continue + // if it's not, disregard error + if hook != nil { + hookList = append(hookList, hook) + continue + } + mfilePath := filepath.Join(outputDir, m.Name) utils.EnsureDirectory(mfilePath) err = ioutil.WriteFile(mfilePath, []byte(data), 0666) if err != nil { - return retData, err + return retData, hookList, err } gvk, err := getGroupVersionKind(data) if err != nil { - return retData, err + return retData, hookList, err } kres := KubernetesResourceTemplate{ @@ -264,7 +331,7 @@ func (h *TemplateClient) GenerateKubernetesArtifacts(inputPath string, valueFile } retData = append(retData, kres) } - return retData, nil + return retData, hookList, nil } func getGroupVersionKind(data string) (schema.GroupVersionKind, error) { diff --git a/src/k8splugin/internal/helm/helm_test.go b/src/k8splugin/internal/helm/helm_test.go index d25ca091..358577ea 100644 --- a/src/k8splugin/internal/helm/helm_test.go +++ b/src/k8splugin/internal/helm/helm_test.go @@ -200,7 +200,7 @@ func TestGenerateKubernetesArtifacts(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.GenerateKubernetesArtifacts(testCase.chartPath, testCase.valueFiles, + out, _, err := tc.GenerateKubernetesArtifacts(testCase.chartPath, testCase.valueFiles, testCase.values) if err != nil { if testCase.expectedError == "" { diff --git a/src/k8splugin/internal/rb/profile.go b/src/k8splugin/internal/rb/profile.go index f8b07abf..df4d2e5c 100644 --- a/src/k8splugin/internal/rb/profile.go +++ b/src/k8splugin/internal/rb/profile.go @@ -1,5 +1,6 @@ /* * Copyright 2018 Intel Corporation, Inc + * Copyright © 2021 Samsung Electronics * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +24,8 @@ import ( "log" "path/filepath" + protorelease "k8s.io/helm/pkg/proto/hapi/release" + "github.com/onap/multicloud-k8s/src/k8splugin/internal/db" "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm" @@ -270,49 +273,50 @@ func (v *ProfileClient) Download(rbName, rbVersion, prName string) ([]byte, erro //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, - profileName string, values []string, overrideReleaseName string) ([]helm.KubernetesResourceTemplate, string, error) { + profileName string, values []string, overrideReleaseName string) ([]helm.KubernetesResourceTemplate, []*protorelease.Hook, string, error) { var sortedTemplates []helm.KubernetesResourceTemplate + var hookList []*protorelease.Hook 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, finalReleaseName, pkgerrors.Wrap(err, "Downloading Profile") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Downloading Profile") } prPath, err := ExtractTarBall(bytes.NewBuffer(prData)) if err != nil { - return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Extracting Profile Content") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Extracting Profile Content") } prYamlClient, err := ProcessProfileYaml(prPath, v.manifestName) if err != nil { - return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Processing Profile Manifest") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Processing Profile Manifest") } definitionClient := NewDefinitionClient() definition, err := definitionClient.Get(rbName, rbVersion) if err != nil { - return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Getting Definition Metadata") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Getting Definition Metadata") } defData, err := definitionClient.Download(rbName, rbVersion) if err != nil { - return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Downloading Definition") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Downloading Definition") } chartBasePath, err := ExtractTarBall(bytes.NewBuffer(defData)) if err != nil { - return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Extracting Definition Charts") + return sortedTemplates, hookList, 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, finalReleaseName, pkgerrors.Wrap(err, "Getting Profile") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Getting Profile") } //Copy the profile configresources to the chart locations @@ -322,7 +326,7 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string, // chartpath: chart/config/resources/config.yaml err = prYamlClient.CopyConfigurationOverrides(chartBasePath) if err != nil { - return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Copying configresources to chart") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Copying configresources to chart") } if overrideReleaseName == "" { @@ -336,14 +340,14 @@ func (v *ProfileClient) Resolve(rbName string, rbVersion string, finalReleaseName) chartPath := filepath.Join(chartBasePath, definition.ChartName) - sortedTemplates, err = helmClient.GenerateKubernetesArtifacts(chartPath, + sortedTemplates, hookList, err = helmClient.GenerateKubernetesArtifacts(chartPath, []string{prYamlClient.GetValues()}, values) if err != nil { - return sortedTemplates, finalReleaseName, pkgerrors.Wrap(err, "Generate final k8s yaml") + return sortedTemplates, hookList, finalReleaseName, pkgerrors.Wrap(err, "Generate final k8s yaml") } - return sortedTemplates, finalReleaseName, nil + return sortedTemplates, hookList, 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 a434e5a1..3c40c2c9 100644 --- a/src/k8splugin/internal/rb/profile_test.go +++ b/src/k8splugin/internal/rb/profile_test.go @@ -773,7 +773,7 @@ func TestResolveProfile(t *testing.T) { t.Run(testCase.label, func(t *testing.T) { db.DBconn = testCase.mockdb impl := NewProfileClient() - data, releaseName, err := impl.Resolve(testCase.rbname, + data, _, releaseName, err := impl.Resolve(testCase.rbname, testCase.rbversion, testCase.prname, []string{}, testCase.releaseName) defer cleanup(data) if err != nil { |