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) Delete(name string) (xapp Xapp, err error) {
212 xapp, err = h.Status(name)
214 Logger.Error("Fetching xapp status failed: %v", err.Error())
218 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
222 func (h *Helm) Fetch(name, tarDir string) error {
223 if strings.HasSuffix(os.Args[0], ".test") {
227 rname := viper.GetString("helm.repo-name") + "/"
229 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
234 func (h *Helm) GetVersion(name string) (version string) {
235 ns := h.cm.GetNamespace("")
236 out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
241 var re = regexp.MustCompile(`AppVersion: .*`)
242 ver := re.FindStringSubmatch(string(out))
244 version = strings.Split(ver[0], ": ")[1]
245 version, _ = strconv.Unquote(version)
251 func (h *Helm) GetState(out string) (status string) {
252 re := regexp.MustCompile(`STATUS: .*`)
253 result := re.FindStringSubmatch(string(out))
255 status = strings.ToLower(strings.Split(result[0], ": ")[1])
261 func (h *Helm) GetAddress(out string) (ip, port string) {
263 re := regexp.MustCompile(`ClusterIP.*`)
264 addr := re.FindStringSubmatch(string(out))
266 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
272 func (h *Helm) GetNames(out string) (names []string, err error) {
273 re := regexp.MustCompile(`Name: .*`)
274 result := re.FindAllStringSubmatch(out, -1)
279 for _, v := range result {
280 xappName := strings.Split(v[0], ": ")[1]
281 if strings.Contains(xappName, "appmgr") == false {
282 names = append(names, xappName)
288 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
289 ip, port := h.GetAddress(out)
292 r := regexp.MustCompile(`(?s)\/Pod.*?\/Service`)
293 result := r.FindStringSubmatch(string(out))
298 re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
299 resources := re.FindAllStringSubmatch(string(result[0]), -1)
300 if resources != nil {
301 for _, v := range resources {
303 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
304 x.Status = strings.ToLower(x.Status)
306 x.Port, _ = strconv.Atoi(strings.Split(port, "/")[0])
307 x.TxMessages = msgs.TxMessages
308 x.RxMessages = msgs.RxMessages
309 xapp.Instances = append(xapp.Instances, x)
314 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
316 xapp.Version = h.GetVersion(name)
317 xapp.Status = h.GetState(out)
319 h.FillInstanceData(name, out, &xapp, h.cm.GetMessages(name))
324 func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
327 for _, name := range names {
328 err := h.cm.ReadSchema(name, &XAppConfig{})
333 x, err := h.Status(name)
335 xapps = append(xapps, x)
342 func addTillerEnv() (err error) {
343 service := viper.GetString("helm.tiller-service")
344 namespace := viper.GetString("helm.tiller-namespace")
345 port := viper.GetString("helm.tiller-port")
347 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
348 Logger.Error("Tiller Env Setting Failed: %v", err.Error())
354 func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
355 args = args + " --namespace=" + x.Namespace
357 if x.ImageRepo != "" {
358 args = args + " --set global.repository=" + x.ImageRepo
361 if x.ServiceName != "" {
362 args = args + " --set ricapp.service.name=" + x.ServiceName
365 if x.Hostname != "" {
366 args = args + " --set ricapp.hostname=" + x.Hostname
369 if cmOverride == true {
370 args = args + " --set ricapp.appconfig.override=" + x.Name + "-appconfig"
373 rname := viper.GetString("helm.repo-name")
374 return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)