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"
39 var execCommand = exec.Command
41 func Exec(args string) (out []byte, err error) {
42 cmd := execCommand("/bin/sh", "-c", strings.Join([]string{"helm", args}, " "))
44 if !strings.HasSuffix(os.Args[0], ".test") {
45 out, err = cmd.CombinedOutput()
47 mdclog(MdclogErr, formatLog("Command failed", args, err.Error()))
52 var stdout bytes.Buffer
53 var stderr bytes.Buffer
57 log.Printf("Running command: %v", cmd)
58 for i := 0; i < 3; i++ {
61 mdclog(MdclogErr, formatLog("Command failed, retrying", args, err.Error()+stderr.String()))
62 time.Sleep(time.Duration(5) * time.Second)
68 if err == nil && !strings.HasSuffix(os.Args[0], ".test") {
69 mdclog(MdclogDebug, formatLog("command success", stdout.String(), ""))
70 return stdout.Bytes(), nil
73 return stdout.Bytes(), errors.New(stderr.String())
76 func (h *Helm) Initialize() {
77 if h.initDone == true {
82 if _, err := h.Init(); err == nil {
83 mdclog(MdclogDebug, formatLog("Helm init done successfully!", "", ""))
86 mdclog(MdclogErr, formatLog("helm init failed, retyring ...", "", ""))
87 time.Sleep(time.Duration(10) * time.Second)
91 if _, err := h.AddRepo(); err == nil {
92 mdclog(MdclogDebug, formatLog("Helm repo added successfully", "", ""))
95 mdclog(MdclogErr, formatLog("Helm repo addition failed, retyring ...", "", ""))
96 time.Sleep(time.Duration(10) * time.Second)
101 func (h *Helm) Run(args string) (out []byte, err error) {
106 func (h *Helm) Init() (out []byte, err error) {
108 // Add Tiller address as environment variable
109 if err := addTillerEnv(); err != nil {
113 return Exec(strings.Join([]string{"init -c"}, ""))
116 func (h *Helm) AddRepo() (out []byte, err error) {
118 // Get helm repo user name and password from files mounted by secret object
119 credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
121 mdclog(MdclogErr, formatLog("helm_repo_username ReadFile failed", "", err.Error()))
125 username := " --username " + string(credFile)
127 credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
129 mdclog(MdclogErr, formatLog("helm_repo_password ReadFile failed", "", err.Error()))
133 pwd := " --password " + string(credFile)
135 // Get internal helm repo name
136 rname := viper.GetString("helm.repo-name")
138 // Get helm repo address from values.yaml
139 repo := viper.GetString("helm.repo")
141 return Exec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
144 func (h *Helm) Install(name string) (xapp Xapp, err error) {
145 out, err := h.Run(strings.Join([]string{"repo update "}, ""))
150 rname := viper.GetString("helm.repo-name")
152 ns := getNamespaceArgs()
153 out, err = h.Run(strings.Join([]string{"install ", rname, "/", name, " --name ", name, ns}, ""))
158 return h.ParseStatus(name, string(out))
161 func (h *Helm) Status(name string) (xapp Xapp, err error) {
163 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
165 mdclog(MdclogErr, formatLog("Getting xapps status", "", err.Error()))
169 return h.ParseStatus(name, string(out))
172 func (h *Helm) StatusAll() (xapps []Xapp, err error) {
173 xappNameList, err := h.List()
175 mdclog(MdclogErr, formatLog("Helm list failed", "", err.Error()))
179 return h.parseAllStatus(xappNameList)
182 func (h *Helm) List() (names []string, err error) {
184 ns := getNamespaceArgs()
185 out, err := h.Run(strings.Join([]string{"list --all --output yaml ", ns}, ""))
187 mdclog(MdclogErr, formatLog("Listing deployed xapps failed", "", err.Error()))
191 return h.GetNames(string(out))
194 func (h *Helm) Delete(name string) (xapp Xapp, err error) {
195 xapp, err = h.Status(name)
197 mdclog(MdclogErr, formatLog("Fetching xapp status failed", "", err.Error()))
201 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
205 func (h *Helm) Fetch(name, tarDir string) error {
206 if strings.HasSuffix(os.Args[0], ".test") {
210 rname := viper.GetString("helm.repo-name") + "/"
212 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
217 func (h *Helm) GetMessages(name string) (msgs MessageTypes, err error) {
218 tarDir := viper.GetString("xapp.tarDir")
223 if h.Fetch(name, tarDir); err != nil {
224 mdclog(MdclogWarn, formatLog("Fetch chart failed", "", err.Error()))
228 return h.ParseMessages(name, tarDir, viper.GetString("xapp.msg_type_file"))
232 func (h *Helm) ParseMessages(name string, chartDir, msgFile string) (msgs MessageTypes, err error) {
233 yamlFile, err := ioutil.ReadFile(path.Join(chartDir, name, msgFile))
235 mdclog(MdclogWarn, formatLog("ReadFile failed", "", err.Error()))
239 err = yaml.Unmarshal(yamlFile, &msgs)
241 mdclog(MdclogWarn, formatLog("Unmarshal failed", "", err.Error()))
245 if err = os.RemoveAll(path.Join(chartDir, name)); err != nil {
246 mdclog(MdclogWarn, formatLog("RemoveAll failed", "", err.Error()))
252 func (h *Helm) GetVersion(name string) (version string) {
254 ns := getNamespaceArgs()
255 out, err := h.Run(strings.Join([]string{"list --output yaml ", name, ns}, ""))
260 var re = regexp.MustCompile(`AppVersion: .*`)
261 ver := re.FindStringSubmatch(string(out))
263 version = strings.Split(ver[0], ": ")[1]
264 version, _ = strconv.Unquote(version)
270 func (h *Helm) GetState(out string) (status string) {
271 re := regexp.MustCompile(`STATUS: .*`)
272 result := re.FindStringSubmatch(string(out))
274 status = strings.ToLower(strings.Split(result[0], ": ")[1])
280 func (h *Helm) GetAddress(out string) (ip, port string) {
282 re := regexp.MustCompile(`ClusterIP.*`)
283 addr := re.FindStringSubmatch(string(out))
285 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
291 func (h *Helm) GetNames(out string) (names []string, err error) {
292 re := regexp.MustCompile(`Name: .*`)
293 result := re.FindAllStringSubmatch(out, -1)
298 for _, v := range result {
299 xappName := strings.Split(v[0], ": ")[1]
300 if strings.Contains(xappName, "appmgr") == false {
301 names = append(names, xappName)
307 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
308 ip, port := h.GetAddress(out)
311 r := regexp.MustCompile(`(?s)\/Pod.*?\/Service`)
312 result := r.FindStringSubmatch(string(out))
317 re := regexp.MustCompile(name + "-(\\d+).*")
318 resources := re.FindAllStringSubmatch(string(result[0]), -1)
319 if resources != nil {
320 for _, v := range resources {
322 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
323 x.Status = strings.ToLower(x.Status)
325 x.Port, _ = strconv.Atoi(strings.Split(port, "/")[0])
326 x.TxMessages = msgs.TxMessages
327 x.RxMessages = msgs.RxMessages
328 xapp.Instances = append(xapp.Instances, x)
333 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
336 xapp.Version = h.GetVersion(name)
337 xapp.Status = h.GetState(out)
339 types, err := h.GetMessages(name)
341 // xAPP can still be deployed if the msg_type file is missing.
342 mdclog(MdclogWarn, formatLog("method GetMessages Failed....", "", err.Error()))
344 //Set err back to nil, so it does not cause issues in called functions.
348 h.FillInstanceData(name, out, &xapp, types)
353 func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
356 for _, name := range names {
357 x, err := h.Status(name)
359 xapps = append(xapps, x)
366 func addTillerEnv() (err error) {
368 service := viper.GetString("helm.tiller-service")
369 namespace := viper.GetString("helm.tiller-namespace")
370 port := viper.GetString("helm.tiller-port")
372 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
373 mdclog(MdclogErr, formatLog("Tiller Env Setting Failed", "", err.Error()))
379 func getNamespaceArgs() string {
380 ns := viper.GetString("xapp.namespace")
384 return " --namespace=" + ns
387 func formatLog(text string, args string, err string) string {
388 return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)