2 ==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================================
24 "github.com/ghodss/yaml"
25 "github.com/spf13/viper"
33 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
34 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/cm"
35 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
36 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
44 func NewHelm() *Helm {
45 return &Helm{initDone: false, cm: cm.NewCM()}
48 func (h *Helm) Initialize() {
49 if h.initDone == true {
54 if _, err := h.Init(); err == nil {
55 appmgr.Logger.Info("Helm init done successfully!")
58 appmgr.Logger.Info("helm init failed, retyring ...")
59 time.Sleep(time.Duration(10) * time.Second)
63 if _, err := h.AddRepo(); err == nil {
64 appmgr.Logger.Info("Helm repo added successfully")
67 appmgr.Logger.Info("Helm repo addition failed, retyring ...")
68 time.Sleep(time.Duration(10) * time.Second)
73 func (h *Helm) Run(args string) (out []byte, err error) {
74 return util.HelmExec(args)
78 func (h *Helm) Init() (out []byte, err error) {
79 if err := h.AddTillerEnv(); err != nil {
83 return util.HelmExec(strings.Join([]string{"init -c --skip-refresh"}, ""))
86 func (h *Helm) AddRepo() (out []byte, err error) {
87 // Get helm repo user name and password from files mounted by secret object
88 username, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
90 appmgr.Logger.Info("helm_repo_username ReadFile failed: %v", err.Error())
94 password, err := ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
96 appmgr.Logger.Info("helm_repo_password ReadFile failed: %v", err.Error())
100 repoArgs := fmt.Sprintf(" %s %s ", viper.GetString("helm.repo-name"), viper.GetString("helm.repo"))
101 credentials := fmt.Sprintf(" --username %s --password %s", string(username), string(password))
103 return util.HelmExec(strings.Join([]string{"repo add ", repoArgs, credentials}, ""))
106 func (h *Helm) Install(m models.XappDescriptor) (xapp models.Xapp, err error) {
107 m.Namespace = h.cm.GetNamespace(m.Namespace)
109 out, err := h.Run(strings.Join([]string{"repo update "}, ""))
114 out, err = h.Run(h.GetInstallArgs(m, false))
118 return h.ParseStatus(*m.XappName, string(out))
121 func (h *Helm) Status(name string) (xapp models.Xapp, err error) {
122 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
124 appmgr.Logger.Info("Getting xapps status: %v", err.Error())
128 return h.ParseStatus(name, string(out))
131 func (h *Helm) StatusAll() (xapps models.AllDeployedXapps, err error) {
132 xappNameList, err := h.List()
134 appmgr.Logger.Info("Helm list failed: %v", err.Error())
138 return h.parseAllStatus(xappNameList)
141 func (h *Helm) List() (names []string, err error) {
142 ns := h.cm.GetNamespace("")
143 out, err := h.Run(strings.Join([]string{"list --all --deployed --output yaml --namespace=", ns}, ""))
145 appmgr.Logger.Info("Listing deployed xapps failed: %v", err.Error())
149 return h.GetNames(string(out))
152 func (h *Helm) SearchAll() models.AllDeployableXapps {
153 return h.cm.GetNamesFromHelmRepo()
156 func (h *Helm) Delete(name string) (xapp models.Xapp, err error) {
157 xapp, err = h.Status(name)
159 appmgr.Logger.Info("Fetching xapp status failed: %v", err.Error())
163 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
167 func (h *Helm) Fetch(name, tarDir string) error {
168 if strings.HasSuffix(os.Args[0], ".test") {
172 rname := viper.GetString("helm.repo-name") + "/"
174 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
179 func (h *Helm) GetVersion(name string) (version string) {
180 ns := h.cm.GetNamespace("")
181 out, err := h.Run(strings.Join([]string{"list --deployed --output yaml --namespace=", ns, " ", name}, ""))
186 var re = regexp.MustCompile(`AppVersion: .*`)
187 ver := re.FindStringSubmatch(string(out))
189 version = strings.Split(ver[0], ": ")[1]
190 version, _ = strconv.Unquote(version)
196 func (h *Helm) GetState(out string) (status string) {
197 re := regexp.MustCompile(`STATUS: .*`)
198 result := re.FindStringSubmatch(string(out))
200 status = strings.ToLower(strings.Split(result[0], ": ")[1])
206 func (h *Helm) GetAddress(out string) (ip, port string) {
208 re := regexp.MustCompile(`ClusterIP.*`)
209 addr := re.FindStringSubmatch(string(out))
211 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
217 func (h *Helm) GetEndpointInfo(name string) (svc string, port int) {
218 port = 4560 // Default
219 ns := h.cm.GetNamespace("")
220 args := fmt.Sprintf(" get service -n ricxapp service-%s-%s-rmr -o json", ns, name)
221 out, err := util.KubectlExec(args)
223 return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
225 appmgr.Logger.Debug("Endpoint IP address of %s: %s", name, string(out))
227 v, err := h.cm.ParseJson(string(out))
229 return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
232 for _, p := range v.GetArray("spec", "ports") {
233 if string(p.GetStringBytes("name")) == "rmrdata" {
234 port = int(p.GetInt("port"))
238 appmgr.Logger.Info("service-%s-%s-rmr.%s %d", ns, name, ns, port)
240 return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), port
243 func (h *Helm) GetNames(out string) (names []string, err error) {
244 re := regexp.MustCompile(`Name: .*`)
245 result := re.FindAllStringSubmatch(out, -1)
250 for _, v := range result {
251 xappName := strings.Split(v[0], ": ")[1]
252 if strings.Contains(xappName, "appmgr") == false {
253 names = append(names, xappName)
259 func (h *Helm) FillInstanceData(name string, out string, xapp *models.Xapp, rtData appmgr.RtmData) {
260 ip, port := h.GetEndpointInfo(name)
262 appmgr.Logger.Info("Endpoint IP address not found, using CluserIP")
263 ip, _ = h.GetAddress(out)
267 r := regexp.MustCompile(`.*(?s)(Running|Pending|Succeeded|Failed|Unknown).*?\r?\n\r?\n`)
268 result := r.FindStringSubmatch(string(out))
273 re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
274 resources := re.FindAllStringSubmatch(string(result[0]), -1)
275 if resources != nil {
276 for _, v := range resources {
277 var x models.XappInstance
279 fmt.Sscanf(v[0], "%s %s %s", &name, &tmp, &x.Status)
281 x.Status = strings.ToLower(x.Status)
284 x.TxMessages = rtData.TxMessages
285 x.RxMessages = rtData.RxMessages
286 x.Policies = rtData.Policies
287 xapp.Instances = append(xapp.Instances, &x)
292 func (h *Helm) ParseStatus(name string, out string) (xapp models.Xapp, err error) {
294 xapp.Version = h.GetVersion(name)
295 xapp.Status = h.GetState(out)
297 h.FillInstanceData(name, out, &xapp, h.cm.GetRtmData(name))
301 func (h *Helm) parseAllStatus(names []string) (xapps models.AllDeployedXapps, err error) {
302 xapps = models.AllDeployedXapps{}
303 for _, name := range names {
305 err := h.cm.ReadSchema(name, &desc)
310 x, err := h.Status(name)
312 xapps = append(xapps, &x)
318 func (h *Helm) AddTillerEnv() (err error) {
319 service := viper.GetString("helm.tiller-service")
320 namespace := viper.GetString("helm.tiller-namespace")
321 port := viper.GetString("helm.tiller-port")
323 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
324 appmgr.Logger.Info("Tiller Env Setting Failed: %v", err.Error())
329 func (h *Helm) GetInstallArgs(x models.XappDescriptor, cmOverride bool) (args string) {
330 args = fmt.Sprintf("%s --namespace=%s", args, x.Namespace)
331 if x.HelmVersion != "" {
332 args = fmt.Sprintf("%s --version=%s", args, x.HelmVersion)
335 if x.ReleaseName != "" {
336 args = fmt.Sprintf("%s --name=%s", args, x.ReleaseName)
338 args = fmt.Sprintf("%s --name=%s", args, *x.XappName)
341 if cmOverride == true {
342 args = fmt.Sprintf("%s ---set ricapp.appconfig.override=%s-appconfig", args, *x.XappName)
345 if x.OverrideFile != nil {
346 if overrideYaml, err := yaml.JSONToYAML([]byte(x.OverrideFile.(string))); err == nil {
347 err = ioutil.WriteFile("/tmp/appmgr_override.yaml", overrideYaml, 0644)
349 appmgr.Logger.Info("ioutil.WriteFile(/tmp/appmgr_override.yaml) failed: %v", err)
351 args = args + " -f=/tmp/appmgr_override.yaml"
354 appmgr.Logger.Info("yaml.JSONToYAML failed: %v", err)
358 repoName := viper.GetString("helm.repo-name")
360 repoName = "helm-repo"
362 return fmt.Sprintf("install %s/%s %s", repoName, *x.XappName, args)