Move capifcore code to separate folder
[nonrtric/plt/sme.git] / capifcore / internal / helmmanagement / helm.go
diff --git a/capifcore/internal/helmmanagement/helm.go b/capifcore/internal/helmmanagement/helm.go
new file mode 100644 (file)
index 0000000..cfed6eb
--- /dev/null
@@ -0,0 +1,187 @@
+// -
+//   ========================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
+}