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 mdclog(MdclogErr, formatLog("Command failed, 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 mdclog(MdclogDebug, formatLog("command success", 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 mdclog(MdclogDebug, formatLog("Helm init done successfully!", "", ""))
88 mdclog(MdclogErr, formatLog("helm init failed, retyring ...", "", ""))
89 time.Sleep(time.Duration(10) * time.Second)
93 if _, err := h.AddRepo(); err == nil {
94 mdclog(MdclogDebug, formatLog("Helm repo added successfully", "", ""))
97 mdclog(MdclogErr, formatLog("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 mdclog(MdclogErr, formatLog("helm_repo_username ReadFile failed", "", err.Error()))
126 username := " --username " + string(credFile)
128 credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
130 mdclog(MdclogErr, formatLog("helm_repo_password ReadFile failed", "", 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 if err = h.cm.ReadConfigMap(m.Name, m.Namespace, &cm); err != nil {
153 out, err = h.Run(getInstallArgs(m, false))
157 return h.ParseStatus(m.Name, string(out))
160 // ConfigMap exists, try to override
161 out, err = h.Run(getInstallArgs(m, true))
163 return h.ParseStatus(m.Name, string(out))
166 cm, cmErr := h.cm.PurgeConfigMap(m)
167 out, err = h.Run(getInstallArgs(m, false))
173 cmErr = h.cm.RestoreConfigMap(m, cm)
175 return h.ParseStatus(m.Name, string(out))
178 func (h *Helm) Status(name string) (xapp Xapp, err error) {
179 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
181 mdclog(MdclogErr, formatLog("Getting xapps status", "", err.Error()))
185 return h.ParseStatus(name, string(out))
188 func (h *Helm) StatusAll() (xapps []Xapp, err error) {
189 xappNameList, err := h.List()
191 mdclog(MdclogErr, formatLog("Helm list failed", "", err.Error()))
195 return h.parseAllStatus(xappNameList)
198 func (h *Helm) List() (names []string, err error) {
199 ns := getNamespace("")
200 out, err := h.Run(strings.Join([]string{"list --all --output yaml --namespace=", ns}, ""))
202 mdclog(MdclogErr, formatLog("Listing deployed xapps failed", "", err.Error()))
206 return h.GetNames(string(out))
209 func (h *Helm) Delete(name string) (xapp Xapp, err error) {
210 xapp, err = h.Status(name)
212 mdclog(MdclogErr, formatLog("Fetching xapp status failed", "", err.Error()))
216 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
220 func (h *Helm) Fetch(name, tarDir string) error {
221 if strings.HasSuffix(os.Args[0], ".test") {
225 rname := viper.GetString("helm.repo-name") + "/"
227 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
232 func (h *Helm) GetVersion(name string) (version string) {
233 ns := getNamespace("")
234 out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
239 var re = regexp.MustCompile(`AppVersion: .*`)
240 ver := re.FindStringSubmatch(string(out))
242 version = strings.Split(ver[0], ": ")[1]
243 version, _ = strconv.Unquote(version)
249 func (h *Helm) GetState(out string) (status string) {
250 re := regexp.MustCompile(`STATUS: .*`)
251 result := re.FindStringSubmatch(string(out))
253 status = strings.ToLower(strings.Split(result[0], ": ")[1])
259 func (h *Helm) GetAddress(out string) (ip, port string) {
261 re := regexp.MustCompile(`ClusterIP.*`)
262 addr := re.FindStringSubmatch(string(out))
264 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
270 func (h *Helm) GetNames(out string) (names []string, err error) {
271 re := regexp.MustCompile(`Name: .*`)
272 result := re.FindAllStringSubmatch(out, -1)
277 for _, v := range result {
278 xappName := strings.Split(v[0], ": ")[1]
279 if strings.Contains(xappName, "appmgr") == false {
280 names = append(names, xappName)
286 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
287 ip, port := h.GetAddress(out)
290 r := regexp.MustCompile(`(?s)\/Pod.*?\/Service`)
291 result := r.FindStringSubmatch(string(out))
296 re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
297 resources := re.FindAllStringSubmatch(string(result[0]), -1)
298 if resources != nil {
299 for _, v := range resources {
301 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
302 x.Status = strings.ToLower(x.Status)
304 x.Port, _ = strconv.Atoi(strings.Split(port, "/")[0])
305 x.TxMessages = msgs.TxMessages
306 x.RxMessages = msgs.RxMessages
307 xapp.Instances = append(xapp.Instances, x)
312 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
314 xapp.Version = h.GetVersion(name)
315 xapp.Status = h.GetState(out)
317 h.FillInstanceData(name, out, &xapp, h.cm.GetMessages(name))
322 func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
325 for _, name := range names {
326 x, err := h.Status(name)
328 xapps = append(xapps, x)
335 func addTillerEnv() (err error) {
336 service := viper.GetString("helm.tiller-service")
337 namespace := viper.GetString("helm.tiller-namespace")
338 port := viper.GetString("helm.tiller-port")
340 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
341 mdclog(MdclogErr, formatLog("Tiller Env Setting Failed", "", err.Error()))
347 func getNamespace(namespace string) string {
352 ns := viper.GetString("xapp.namespace")
359 func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
360 x.Namespace = getNamespace(x.Namespace)
361 args = args + " --namespace=" + x.Namespace
363 if x.ImageRepo != "" {
364 args = args + " --set image.repository=" + x.ImageRepo
367 if x.ServiceName != "" {
368 args = args + " --set service.name=" + x.ServiceName
371 if x.Hostname != "" {
372 args = args + " --set hostname=" + x.Hostname
375 if cmOverride == true {
376 args = args + " --set appconfig.override=true"
379 rname := viper.GetString("helm.repo-name")
380 return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)
383 func formatLog(text string, args string, err string) string {
384 return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)