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 ==================================================================================
26 "github.com/spf13/viper"
37 var execCommand = exec.Command
39 func Exec(args string) (out []byte, err error) {
40 cmd := execCommand("/bin/sh", "-c", args)
42 var stdout bytes.Buffer
43 var stderr bytes.Buffer
47 log.Println("Running command: ", cmd)
48 for i := 0; i < viper.GetInt("helm.retry"); i++ {
51 Logger.Error("Command '%s' failed with error: %v, retrying", args, err.Error()+stderr.String())
52 time.Sleep(time.Duration(2) * time.Second)
58 if err == nil && !strings.HasSuffix(os.Args[0], ".test") {
59 Logger.Info("command success: %s", stdout.String())
60 return stdout.Bytes(), nil
63 return stdout.Bytes(), errors.New(stderr.String())
66 var HelmExec = func(args string) (out []byte, err error) {
67 return Exec(strings.Join([]string{"helm", args}, " "))
70 var KubectlExec = func(args string) (out []byte, err error) {
71 return Exec(strings.Join([]string{"kubectl", args}, " "))
74 func (h *Helm) SetCM(cm ConfigMapper) {
78 func (h *Helm) Initialize() {
79 if h.initDone == true {
84 if _, err := h.Init(); err == nil {
85 Logger.Info("Helm init done successfully!")
88 Logger.Error("helm init failed, retyring ...")
89 time.Sleep(time.Duration(10) * time.Second)
93 if _, err := h.AddRepo(); err == nil {
94 Logger.Info("Helm repo added successfully")
97 Logger.Error("Helm repo addition failed, retyring ...")
98 time.Sleep(time.Duration(10) * time.Second)
104 func (h *Helm) Run(args string) (out []byte, err error) {
105 return HelmExec(args)
109 func (h *Helm) Init() (out []byte, err error) {
110 // Add Tiller address as environment variable
111 if err := addTillerEnv(); err != nil {
115 return HelmExec(strings.Join([]string{"init -c"}, ""))
118 func (h *Helm) AddRepo() (out []byte, err error) {
119 // Get helm repo user name and password from files mounted by secret object
120 credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
122 Logger.Error("helm_repo_username ReadFile failed: %v", err.Error())
126 username := " --username " + string(credFile)
128 credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
130 Logger.Error("helm_repo_password ReadFile failed: %v", err.Error())
134 pwd := " --password " + string(credFile)
136 // Get internal helm repo name
137 rname := viper.GetString("helm.repo-name")
139 // Get helm repo address from values.yaml
140 repo := viper.GetString("helm.repo")
142 return HelmExec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
145 func (h *Helm) Install(m XappDeploy) (xapp Xapp, err error) {
146 out, err := h.Run(strings.Join([]string{"repo update "}, ""))
152 m.Namespace = h.cm.GetNamespace(m.Namespace)
154 if err = h.cm.GetConfigMap(m, &cm); err != nil {
155 out, err = h.Run(getInstallArgs(m, false))
159 return h.ParseStatus(m.Name, string(out))
162 // ConfigMap exists, try to override
163 out, err = h.Run(getInstallArgs(m, true))
165 return h.ParseStatus(m.Name, string(out))
168 cm, cmErr := h.cm.PurgeConfigMap(m)
169 out, err = h.Run(getInstallArgs(m, false))
175 cmErr = h.cm.RestoreConfigMap(m, cm)
177 return h.ParseStatus(m.Name, string(out))
180 func (h *Helm) Status(name string) (xapp Xapp, err error) {
181 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
183 Logger.Error("Getting xapps status: %v", err.Error())
187 return h.ParseStatus(name, string(out))
190 func (h *Helm) StatusAll() (xapps []Xapp, err error) {
191 xappNameList, err := h.List()
193 Logger.Error("Helm list failed: %v", err.Error())
197 return h.parseAllStatus(xappNameList)
200 func (h *Helm) List() (names []string, err error) {
201 ns := h.cm.GetNamespace("")
202 out, err := h.Run(strings.Join([]string{"list --all --output yaml --namespace=", ns}, ""))
204 Logger.Error("Listing deployed xapps failed: %v", err.Error())
208 return h.GetNames(string(out))
211 func (h *Helm) SearchAll() (names []string) {
212 return h.cm.GetNamesFromHelmRepo()
215 func (h *Helm) Delete(name string) (xapp Xapp, err error) {
216 xapp, err = h.Status(name)
218 Logger.Error("Fetching xapp status failed: %v", err.Error())
222 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
226 func (h *Helm) Fetch(name, tarDir string) error {
227 if strings.HasSuffix(os.Args[0], ".test") {
231 rname := viper.GetString("helm.repo-name") + "/"
233 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
238 func (h *Helm) GetVersion(name string) (version string) {
239 ns := h.cm.GetNamespace("")
240 out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
245 var re = regexp.MustCompile(`AppVersion: .*`)
246 ver := re.FindStringSubmatch(string(out))
248 version = strings.Split(ver[0], ": ")[1]
249 version, _ = strconv.Unquote(version)
255 func (h *Helm) GetState(out string) (status string) {
256 re := regexp.MustCompile(`STATUS: .*`)
257 result := re.FindStringSubmatch(string(out))
259 status = strings.ToLower(strings.Split(result[0], ": ")[1])
265 func (h *Helm) GetAddress(out string) (ip, port string) {
267 re := regexp.MustCompile(`ClusterIP.*`)
268 addr := re.FindStringSubmatch(string(out))
270 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
276 func (h *Helm) GetEndpointInfo(name string) (ip string, port int) {
277 args := fmt.Sprintf(" get endpoints -o=jsonpath='{.subsets[*].addresses[*].ip}' %s -n %s", name, h.cm.GetNamespace(""))
278 out, err := KubectlExec(args)
283 return string(out), 4560
286 func (h *Helm) GetNames(out string) (names []string, err error) {
287 re := regexp.MustCompile(`Name: .*`)
288 result := re.FindAllStringSubmatch(out, -1)
293 for _, v := range result {
294 xappName := strings.Split(v[0], ": ")[1]
295 if strings.Contains(xappName, "appmgr") == false {
296 names = append(names, xappName)
302 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
303 ip, port := h.GetEndpointInfo(name)
305 Logger.Info("Endpoint IP address not found, using CluserIP")
306 ip, _ = h.GetAddress(out)
310 r := regexp.MustCompile(`.*(?s)(Running|Pending|Succeeded|Failed|Unknown).*?\r?\n\r?\n`)
311 result := r.FindStringSubmatch(string(out))
316 re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
317 resources := re.FindAllStringSubmatch(string(result[0]), -1)
318 if resources != nil {
319 for _, v := range resources {
321 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
322 x.Status = strings.ToLower(x.Status)
325 x.TxMessages = msgs.TxMessages
326 x.RxMessages = msgs.RxMessages
327 xapp.Instances = append(xapp.Instances, x)
332 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
334 xapp.Version = h.GetVersion(name)
335 xapp.Status = h.GetState(out)
337 h.FillInstanceData(name, out, &xapp, h.cm.GetMessages(name))
342 func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
345 for _, name := range names {
346 err := h.cm.ReadSchema(name, &XAppConfig{})
351 x, err := h.Status(name)
353 xapps = append(xapps, x)
360 func addTillerEnv() (err error) {
361 service := viper.GetString("helm.tiller-service")
362 namespace := viper.GetString("helm.tiller-namespace")
363 port := viper.GetString("helm.tiller-port")
365 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
366 Logger.Error("Tiller Env Setting Failed: %v", err.Error())
372 func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
373 args = args + " --namespace=" + x.Namespace
375 if x.ImageRepo != "" {
376 args = args + " --set global.repository=" + x.ImageRepo
379 if x.ServiceName != "" {
380 args = args + " --set ricapp.service.name=" + x.ServiceName
383 if x.Hostname != "" {
384 args = args + " --set ricapp.hostname=" + x.Hostname
387 if cmOverride == true {
388 args = args + " --set ricapp.appconfig.override=" + x.Name + "-appconfig"
391 rname := viper.GetString("helm.repo-name")
392 return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)