Add generated code
[nonrtric/plt/sme.git] / capifcore / internal / helmmanagement / helm.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
7 //   Licensed under the Apache License, Version 2.0 (the "License");
8 //   you may not use this file except in compliance with the License.
9 //   You may obtain a copy of the License at
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
13 //   Unless required by applicable law or agreed to in writing, software
14 //   distributed under the License is distributed on an "AS IS" BASIS,
15 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 //   See the License for the specific language governing permissions and
17 //   limitations under the License.
18 //   ========================LICENSE_END===================================
19 //
20
21 package helmmanagement
22
23 import (
24         "fmt"
25         "io/ioutil"
26         "os"
27         "path/filepath"
28
29         "github.com/pkg/errors"
30         log "github.com/sirupsen/logrus"
31         "gopkg.in/yaml.v2"
32         "helm.sh/helm/v3/pkg/action"
33         "helm.sh/helm/v3/pkg/chart/loader"
34         "helm.sh/helm/v3/pkg/cli"
35         "helm.sh/helm/v3/pkg/getter"
36         "helm.sh/helm/v3/pkg/kube"
37         "helm.sh/helm/v3/pkg/repo"
38         "k8s.io/cli-runtime/pkg/genericclioptions"
39         "k8s.io/client-go/rest"
40 )
41
42 //go:generate mockery --name HelmManager
43 type HelmManager interface {
44         AddToRepo(repoName, url string) error
45         InstallHelmChart(namespace, repoName, chartName, releaseName string) error
46         UninstallHelmChart(namespace, chartName string)
47 }
48
49 type helmManagerImpl struct {
50         settings *cli.EnvSettings
51 }
52
53 func NewHelmManager() *helmManagerImpl {
54         return &helmManagerImpl{
55                 settings: cli.New(),
56         }
57 }
58
59 func (hm *helmManagerImpl) AddToRepo(repoName, url string) error {
60         repoFile := hm.settings.RepositoryConfig
61
62         //Ensure the file directory exists as it is required for file locking
63         err := os.MkdirAll(filepath.Dir(repoFile), os.ModePerm)
64         if err != nil && !os.IsExist(err) {
65                 return err
66         }
67
68         b, err := ioutil.ReadFile(repoFile)
69         if err != nil && !os.IsNotExist(err) {
70                 return err
71         }
72
73         var f repo.File
74         if err := yaml.Unmarshal(b, &f); err != nil {
75                 return err
76         }
77
78         if f.Has(repoName) {
79                 fmt.Printf("repository name (%s) already exists\n", repoName)
80                 return nil
81         }
82
83         c := repo.Entry{
84                 Name: repoName,
85                 URL:  url,
86         }
87
88         r, err := repo.NewChartRepository(&c, getter.All(hm.settings))
89         if err != nil {
90                 return err
91         }
92
93         if _, err := r.DownloadIndexFile(); err != nil {
94                 err := errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", url)
95                 return err
96         }
97
98         f.Update(&c)
99
100         if err := f.WriteFile(repoFile, 0644); err != nil {
101                 return err
102         }
103         fmt.Printf("%q has been added to your repositories\n", repoName)
104         return nil
105 }
106
107 func (hm *helmManagerImpl) InstallHelmChart(namespace, repoName, chartName, releaseName string) error {
108         actionConfig, err := getActionConfig(namespace)
109         if err != nil {
110                 return err
111         }
112
113         install := action.NewInstall(actionConfig)
114
115         cp, err := install.ChartPathOptions.LocateChart(fmt.Sprintf("%s/%s", repoName, chartName), hm.settings)
116         if err != nil {
117                 log.Error("Unable to locate chart!")
118                 return err
119         }
120
121         chartRequested, err := loader.Load(cp)
122         if err != nil {
123                 log.Error("Unable to load chart path!")
124                 return err
125         }
126
127         install.Namespace = namespace
128         install.ReleaseName = releaseName
129         _, err = install.Run(chartRequested, nil)
130         if err != nil {
131                 log.Error("Unable to run chart!")
132                 return err
133         }
134         log.Debug("Successfully onboarded ", namespace, repoName, chartName, releaseName)
135         return nil
136 }
137
138 func (hm *helmManagerImpl) UninstallHelmChart(namespace, chartName string) {
139         actionConfig, err := getActionConfig(namespace)
140         if err != nil {
141                 fmt.Println(err)
142         }
143
144         iCli := action.NewUninstall(actionConfig)
145
146         resp, err := iCli.Run(chartName)
147         if err != nil {
148                 fmt.Println(err)
149         }
150         log.Debug("Successfully uninstalled chart: ", resp.Release.Name)
151 }
152
153 func getActionConfig(namespace string) (*action.Configuration, error) {
154         actionConfig := new(action.Configuration)
155         // Create the rest config instance with ServiceAccount values loaded in them
156         config, err := rest.InClusterConfig()
157         if err != nil {
158                 // fallback to kubeconfig
159                 home, exists := os.LookupEnv("HOME")
160                 if !exists {
161                         home = "/root"
162                 }
163                 kubeconfigPath := filepath.Join(home, ".kube", "config")
164                 if envvar := os.Getenv("KUBECONFIG"); len(envvar) > 0 {
165                         kubeconfigPath = envvar
166                 }
167                 if err := actionConfig.Init(kube.GetConfig(kubeconfigPath, "", namespace), namespace, os.Getenv("HELM_DRIVER"),
168                         func(format string, v ...interface{}) {
169                                 fmt.Sprintf(format, v)
170                         }); err != nil {
171                         fmt.Println(err)
172                 }
173         } else {
174                 // Create the ConfigFlags struct instance with initialized values from ServiceAccount
175                 kubeConfig := genericclioptions.NewConfigFlags(false)
176                 kubeConfig.APIServer = &config.Host
177                 kubeConfig.BearerToken = &config.BearerToken
178                 kubeConfig.CAFile = &config.CAFile
179                 kubeConfig.Namespace = &namespace
180                 if err := actionConfig.Init(kubeConfig, namespace, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) {
181                         fmt.Sprintf(format, v)
182                 }); err != nil {
183                         fmt.Println(err)
184                 }
185         }
186         return actionConfig, err
187 }