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) GetNames(out string) (names []string, err error) {
277 re := regexp.MustCompile(`Name: .*`)
278 result := re.FindAllStringSubmatch(out, -1)
283 for _, v := range result {
284 xappName := strings.Split(v[0], ": ")[1]
285 if strings.Contains(xappName, "appmgr") == false {
286 names = append(names, xappName)
292 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
293 ip, port := h.GetAddress(out)
296 r := regexp.MustCompile(`.*(?s)(Running|Pending|Succeeded|Failed|Unknown).*?\r?\n\r?\n`)
297 result := r.FindStringSubmatch(string(out))
302 re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
303 resources := re.FindAllStringSubmatch(string(result[0]), -1)
304 if resources != nil {
305 for _, v := range resources {
307 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
308 x.Status = strings.ToLower(x.Status)
310 x.Port, _ = strconv.Atoi(strings.Split(port, "/")[0])
311 x.TxMessages = msgs.TxMessages
312 x.RxMessages = msgs.RxMessages
313 xapp.Instances = append(xapp.Instances, x)
318 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
320 xapp.Version = h.GetVersion(name)
321 xapp.Status = h.GetState(out)
323 h.FillInstanceData(name, out, &xapp, h.cm.GetMessages(name))
328 func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
331 for _, name := range names {
332 err := h.cm.ReadSchema(name, &XAppConfig{})
337 x, err := h.Status(name)
339 xapps = append(xapps, x)
346 func addTillerEnv() (err error) {
347 service := viper.GetString("helm.tiller-service")
348 namespace := viper.GetString("helm.tiller-namespace")
349 port := viper.GetString("helm.tiller-port")
351 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
352 Logger.Error("Tiller Env Setting Failed: %v", err.Error())
358 func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
359 args = args + " --namespace=" + x.Namespace
361 if x.ImageRepo != "" {
362 args = args + " --set global.repository=" + x.ImageRepo
365 if x.ServiceName != "" {
366 args = args + " --set ricapp.service.name=" + x.ServiceName
369 if x.Hostname != "" {
370 args = args + " --set ricapp.hostname=" + x.Hostname
373 if cmOverride == true {
374 args = args + " --set ricapp.appconfig.override=" + x.Name + "-appconfig"
377 rname := viper.GetString("helm.repo-name")
378 return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)