--- /dev/null
+// -
+// ========================LICENSE_START=================================
+// O-RAN-SC
+// %%
+// Copyright (C) 2022: Nordix Foundation
+// %%
+// 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.
+// ========================LICENSE_END===================================
+//
+
+package helmmanagement
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "github.com/pkg/errors"
+ log "github.com/sirupsen/logrus"
+ "gopkg.in/yaml.v2"
+ "helm.sh/helm/v3/pkg/action"
+ "helm.sh/helm/v3/pkg/chart/loader"
+ "helm.sh/helm/v3/pkg/cli"
+ "helm.sh/helm/v3/pkg/getter"
+ "helm.sh/helm/v3/pkg/kube"
+ "helm.sh/helm/v3/pkg/repo"
+ "k8s.io/cli-runtime/pkg/genericclioptions"
+ "k8s.io/client-go/rest"
+)
+
+//go:generate mockery --name HelmManager
+type HelmManager interface {
+ AddToRepo(repoName, url string) error
+ InstallHelmChart(namespace, repoName, chartName, releaseName string) error
+ UninstallHelmChart(namespace, chartName string)
+}
+
+type helmManagerImpl struct {
+ settings *cli.EnvSettings
+}
+
+func NewHelmManager() *helmManagerImpl {
+ return &helmManagerImpl{
+ settings: cli.New(),
+ }
+}
+
+func (hm *helmManagerImpl) AddToRepo(repoName, url string) error {
+ repoFile := hm.settings.RepositoryConfig
+
+ //Ensure the file directory exists as it is required for file locking
+ err := os.MkdirAll(filepath.Dir(repoFile), os.ModePerm)
+ if err != nil && !os.IsExist(err) {
+ return err
+ }
+
+ b, err := ioutil.ReadFile(repoFile)
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ var f repo.File
+ if err := yaml.Unmarshal(b, &f); err != nil {
+ return err
+ }
+
+ if f.Has(repoName) {
+ fmt.Printf("repository name (%s) already exists\n", repoName)
+ return nil
+ }
+
+ c := repo.Entry{
+ Name: repoName,
+ URL: url,
+ }
+
+ r, err := repo.NewChartRepository(&c, getter.All(hm.settings))
+ if err != nil {
+ return err
+ }
+
+ if _, err := r.DownloadIndexFile(); err != nil {
+ err := errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", url)
+ return err
+ }
+
+ f.Update(&c)
+
+ if err := f.WriteFile(repoFile, 0644); err != nil {
+ return err
+ }
+ fmt.Printf("%q has been added to your repositories\n", repoName)
+ return nil
+}
+
+func (hm *helmManagerImpl) InstallHelmChart(namespace, repoName, chartName, releaseName string) error {
+ actionConfig, err := getActionConfig(namespace)
+ if err != nil {
+ return err
+ }
+
+ install := action.NewInstall(actionConfig)
+
+ cp, err := install.ChartPathOptions.LocateChart(fmt.Sprintf("%s/%s", repoName, chartName), hm.settings)
+ if err != nil {
+ log.Error("Unable to locate chart!")
+ return err
+ }
+
+ chartRequested, err := loader.Load(cp)
+ if err != nil {
+ log.Error("Unable to load chart path!")
+ return err
+ }
+
+ install.Namespace = namespace
+ install.ReleaseName = releaseName
+ _, err = install.Run(chartRequested, nil)
+ if err != nil {
+ log.Error("Unable to run chart!")
+ return err
+ }
+ log.Debug("Successfully onboarded ", namespace, repoName, chartName, releaseName)
+ return nil
+}
+
+func (hm *helmManagerImpl) UninstallHelmChart(namespace, chartName string) {
+ actionConfig, err := getActionConfig(namespace)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ iCli := action.NewUninstall(actionConfig)
+
+ resp, err := iCli.Run(chartName)
+ if err != nil {
+ fmt.Println(err)
+ }
+ log.Debug("Successfully uninstalled chart: ", resp.Release.Name)
+}
+
+func getActionConfig(namespace string) (*action.Configuration, error) {
+ actionConfig := new(action.Configuration)
+ // Create the rest config instance with ServiceAccount values loaded in them
+ config, err := rest.InClusterConfig()
+ if err != nil {
+ // fallback to kubeconfig
+ home, exists := os.LookupEnv("HOME")
+ if !exists {
+ home = "/root"
+ }
+ kubeconfigPath := filepath.Join(home, ".kube", "config")
+ if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
+ kubeconfigPath = envvar
+ }
+ if err := actionConfig.Init(kube.GetConfig(kubeconfigPath, "", namespace), namespace, os.Getenv("HELM_DRIVER"),
+ func(format string, v ...interface{}) {
+ fmt.Sprintf(format, v)
+ }); err != nil {
+ fmt.Println(err)
+ }
+ } else {
+ // Create the ConfigFlags struct instance with initialized values from ServiceAccount
+ kubeConfig := genericclioptions.NewConfigFlags(false)
+ kubeConfig.APIServer = &config.Host
+ kubeConfig.BearerToken = &config.BearerToken
+ kubeConfig.CAFile = &config.CAFile
+ kubeConfig.Namespace = &namespace
+ if err := actionConfig.Init(kubeConfig, namespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
+ fmt.Sprintf(format, v)
+ }); err != nil {
+ fmt.Println(err)
+ }
+ }
+ return actionConfig, err
+}