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 ==================================================================================
30 "github.com/spf13/viper"
36 var execCommand = exec.Command
38 func Exec(args string) (out []byte, err error) {
39 cmd := execCommand("/bin/sh", "-c", strings.Join([]string{"helm", args}, " "))
41 // In testing environment, don't print command traces ...
42 if !strings.HasSuffix(os.Args[0], ".test") {
43 log.Printf("Running command: %v", cmd)
46 out, err = cmd.CombinedOutput()
48 mdclog(Mdclog_err, formatLog("Command failed", args, err.Error()))
52 if !strings.HasSuffix(os.Args[0], ".test") {
53 mdclog(Mdclog_debug, formatLog("command success", string(out), ""))
59 func (h *Helm) Run(args string) (out []byte, err error) {
60 if h.initDone == false {
61 if _, err := h.Init(); err != nil {
62 mdclog(Mdclog_err, formatLog("helm init failed", args, err.Error()))
65 mdclog(Mdclog_debug, formatLog("Helm init done successfully!", args, ""))
68 if _, err := h.AddRepo(); err != nil {
69 mdclog(Mdclog_err, formatLog("Helm repo addition failed", args, err.Error()))
73 mdclog(Mdclog_debug, formatLog("Helm repo added successfully", string(out), ""))
81 func (h *Helm) Init() (out []byte, err error) {
83 // Add Tiller address as environment variable
84 if err := addTillerEnv(); err != nil {
88 return Exec(strings.Join([]string{"init -c"}, ""))
91 func (h *Helm) AddRepo() (out []byte, err error) {
93 // Get helm repo user name and password from files mounted by secret object
94 credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
96 mdclog(Mdclog_err, formatLog("helm_repo_username ReadFile failed", "", err.Error()))
100 username := " --username " + string(credFile)
102 credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
104 mdclog(Mdclog_err, formatLog("helm_repo_password ReadFile failed", "", err.Error()))
108 pwd := " --password " + string(credFile)
110 // Get internal helm repo name
111 rname := viper.GetString("helm.repo-name")
113 // Get helm repo address from values.yaml
114 repo := viper.GetString("helm.repo")
116 return Exec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
119 func (h *Helm) Install(name string) (xapp Xapp, err error) {
120 out, err := h.Run(strings.Join([]string{"repo update "}, ""))
125 rname := viper.GetString("helm.repo-name")
127 ns := getNamespaceArgs()
128 out, err = h.Run(strings.Join([]string{"install ", rname, "/", name, " --name ", name, ns}, ""))
133 return h.ParseStatus(name, string(out))
136 func (h *Helm) Status(name string) (xapp Xapp, err error) {
138 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
140 mdclog(Mdclog_err, formatLog("Getting xapps status", "", err.Error()))
144 return h.ParseStatus(name, string(out))
147 func (h *Helm) StatusAll() (xapps []Xapp, err error) {
148 xappNameList, err := h.List()
150 mdclog(Mdclog_err, formatLog("Helm list failed", "", err.Error()))
154 return h.parseAllStatus(xappNameList)
157 func (h *Helm) List() (names []string, err error) {
159 ns := getNamespaceArgs()
160 out, err := h.Run(strings.Join([]string{"list --all --output yaml ", ns}, ""))
162 mdclog(Mdclog_err, formatLog("Listing deployed xapps failed", "", err.Error()))
166 return h.GetNames(string(out))
169 func (h *Helm) Delete(name string) (xapp Xapp, err error) {
170 xapp, err = h.Status(name)
172 mdclog(Mdclog_err, formatLog("Fetching xapp status failed", "", err.Error()))
176 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
180 func (h *Helm) Fetch(name , tarDir string) (error) {
181 if strings.HasSuffix(os.Args[0], ".test") {
185 rname := viper.GetString("helm.repo-name") + "/"
187 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
192 func (h *Helm) GetMessages(name string) (msgs MessageTypes, err error) {
193 tarDir := viper.GetString("xapp.tarDir")
198 if h.Fetch(name, tarDir); err != nil {
199 mdclog(Mdclog_err, formatLog("Fetch chart failed", "", err.Error()))
203 return h.ParseMessages(name, tarDir, "msg_type.yaml")
207 func (h *Helm) ParseMessages(name string, chartDir, msgFile string) (msgs MessageTypes, err error) {
208 yamlFile, err := ioutil.ReadFile(path.Join(chartDir, name, msgFile))
210 mdclog(Mdclog_err, formatLog("ReadFile failed", "", err.Error()))
214 err = yaml.Unmarshal(yamlFile, &msgs)
216 mdclog(Mdclog_err, formatLog("Unmarshal failed", "", err.Error()))
220 if err = os.RemoveAll(path.Join(chartDir, name)); err != nil {
221 mdclog(Mdclog_err, formatLog("RemoveAll failed", "", err.Error()))
227 func (h *Helm) GetVersion(name string) (version string) {
229 ns := getNamespaceArgs()
230 out, err := h.Run(strings.Join([]string{"list --output yaml ", name, ns}, ""))
235 var re = regexp.MustCompile(`AppVersion: .*`)
236 ver := re.FindStringSubmatch(string(out))
238 version = strings.Split(ver[0], ": ")[1]
239 version, _ = strconv.Unquote(version)
245 func (h *Helm) GetState(out string) (status string) {
246 re := regexp.MustCompile(`STATUS: .*`)
247 result := re.FindStringSubmatch(string(out))
249 status = strings.ToLower(strings.Split(result[0], ": ")[1])
255 func (h *Helm) GetAddress(out string) (ip, port string) {
257 re := regexp.MustCompile(`ClusterIP.*`)
258 addr := re.FindStringSubmatch(string(out))
260 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
266 func (h *Helm) GetNames(out string) (names []string, err error) {
267 re := regexp.MustCompile(`Name: .*`)
268 result := re.FindAllStringSubmatch(out, -1)
273 for _, v := range result {
274 xappName := strings.Split(v[0], ": ")[1]
275 if strings.Contains(xappName, "appmgr") == false {
276 names = append(names, xappName)
282 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
283 ip, port := h.GetAddress(out)
286 r := regexp.MustCompile(`(?s)\/Pod.*?\/Service`)
287 result := r.FindStringSubmatch(string(out))
292 re := regexp.MustCompile(name + "-(\\d+).*")
293 resources := re.FindAllStringSubmatch(string(result[0]), -1)
294 if resources != nil {
295 for _, v := range resources {
297 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
298 x.Status = strings.ToLower(x.Status)
300 x.Port, _ = strconv.Atoi(strings.Split(port, "/")[0])
301 x.TxMessages = msgs.TxMessages
302 x.RxMessages = msgs.RxMessages
303 xapp.Instances = append(xapp.Instances, x)
308 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
309 types, err := h.GetMessages(name)
315 xapp.Version = h.GetVersion(name)
316 xapp.Status = h.GetState(out)
317 h.FillInstanceData(name, out, &xapp, types)
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) {
337 service := viper.GetString("helm.tiller-service")
338 namespace := viper.GetString("helm.tiller-namespace")
339 port := viper.GetString("helm.tiller-port")
341 if err = os.Setenv("HELM_HOST", service + "." + namespace + ":" + port); err != nil {
342 mdclog(Mdclog_err, formatLog("Tiller Env Setting Failed", "", err.Error()))
348 func getNamespaceArgs() (string) {
349 ns := viper.GetString("xapp.namespace")
353 return " --namespace=" + ns
356 func formatLog(text string, args string, err string) (string) {
357 return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)