blob: cfa1f18dd55d3134fb230e4ab8d6c22bd896175b [file] [log] [blame]
Abukar Mohamed8504f6a2019-04-03 11:07:48 +00001/*
2==================================================================================
3 Copyright (c) 2019 AT&T Intellectual Property.
4 Copyright (c) 2019 Nokia
5
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
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
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==================================================================================
18*/
19
20package main
21
22import (
23 "fmt"
24 "log"
25 "os"
26 "os/exec"
27 "regexp"
28 "strconv"
29 "strings"
30 "github.com/spf13/viper"
31 "gopkg.in/yaml.v2"
32 "io/ioutil"
33 "path"
34)
35
36var execCommand = exec.Command
37
38func Exec(args string) (out []byte, err error) {
39 cmd := execCommand("/bin/sh", "-c", strings.Join([]string{"helm", args}, " "))
40
41 // In testing environment, don't print command traces ...
42 if !strings.HasSuffix(os.Args[0], ".test") {
43 log.Printf("Running command: %v", cmd)
44 }
45
46 out, err = cmd.CombinedOutput()
47 if err != nil {
48 mdclog(Mdclog_err, formatLog("Command failed", args, err.Error()))
49 return out, err
50 }
51
52 if !strings.HasSuffix(os.Args[0], ".test") {
53 mdclog(Mdclog_debug, formatLog("command success", string(out), ""))
54 }
55
56 return out, err
57}
58
59func (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()))
63 return out, err
64 }
65 mdclog(Mdclog_debug, formatLog("Helm init done successfully!", args, ""))
66
67 // Add helm repo
68 if _, err := h.AddRepo(); err != nil {
69 mdclog(Mdclog_err, formatLog("Helm repo addition failed", args, err.Error()))
70 return out, err
71 }
72
73 mdclog(Mdclog_debug, formatLog("Helm repo added successfully", string(out), ""))
74 h.initDone = true
75 }
76
77 return Exec(args)
78}
79
80// API functions
81func (h *Helm) Init() (out []byte, err error) {
82
83 // Add Tiller address as environment variable
84 if err := addTillerEnv(); err != nil {
85 return out, err
86 }
87
88 return Exec(strings.Join([]string{"init -c"}, ""))
89}
90
91func (h *Helm) AddRepo() (out []byte, err error) {
92
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"))
95 if err != nil {
96 mdclog(Mdclog_err, formatLog("helm_repo_username ReadFile failed", "", err.Error()))
97 return
98 }
99
100 username := " --username " + string(credFile)
101
102 credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
103 if err != nil {
104 mdclog(Mdclog_err, formatLog("helm_repo_password ReadFile failed", "", err.Error()))
105 return
106 }
107
108 pwd := " --password " + string(credFile)
109
110 // Get internal helm repo name
111 rname := viper.GetString("helm.repo-name")
112
113 // Get helm repo address from values.yaml
114 repo := viper.GetString("helm.repo")
115
116 return Exec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
117}
118
119func (h *Helm) Install(name string) (xapp Xapp, err error) {
120 out, err := h.Run(strings.Join([]string{"repo update "}, ""))
121 if err != nil {
122 return
123 }
124
125 rname := viper.GetString("helm.repo-name")
126
127 ns := getNamespaceArgs()
128 out, err = h.Run(strings.Join([]string{"install ", rname, "/", name, " --name ", name, ns}, ""))
129 if err != nil {
130 return
131 }
132
133 return h.ParseStatus(name, string(out))
134}
135
136func (h *Helm) Status(name string) (xapp Xapp, err error) {
137
138 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
139 if err != nil {
140 mdclog(Mdclog_err, formatLog("Getting xapps status", "", err.Error()))
141 return
142 }
143
144 return h.ParseStatus(name, string(out))
145}
146
147func (h *Helm) StatusAll() (xapps []Xapp, err error) {
148 xappNameList, err := h.List()
149 if err != nil {
150 mdclog(Mdclog_err, formatLog("Helm list failed", "", err.Error()))
151 return
152 }
153
154 return h.parseAllStatus(xappNameList)
155}
156
157func (h *Helm) List() (names []string, err error) {
158
159 ns := getNamespaceArgs()
160 out, err := h.Run(strings.Join([]string{"list --all --output yaml ", ns}, ""))
161 if err != nil {
162 mdclog(Mdclog_err, formatLog("Listing deployed xapps failed", "", err.Error()))
163 return
164 }
165
166 return h.GetNames(string(out))
167}
168
169func (h *Helm) Delete(name string) (xapp Xapp, err error) {
170 xapp, err = h.Status(name)
171 if err != nil {
172 mdclog(Mdclog_err, formatLog("Fetching xapp status failed", "", err.Error()))
173 return
174 }
175
176 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
177 return xapp, err
178}
179
180func (h *Helm) Fetch(name , tarDir string) (error) {
181 if strings.HasSuffix(os.Args[0], ".test") {
182 return nil
183 }
184
185 rname := viper.GetString("helm.repo-name") + "/"
186
187 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
188 return err
189}
190
191// Helper functions
192func (h *Helm) GetMessages(name string) (msgs MessageTypes, err error) {
193 tarDir := viper.GetString("xapp.tarDir")
194 if tarDir == "" {
195 tarDir = "/tmp"
196 }
197
198 if h.Fetch(name, tarDir); err != nil {
199 mdclog(Mdclog_err, formatLog("Fetch chart failed", "", err.Error()))
200 return
201 }
202
203 return h.ParseMessages(name, tarDir, "msg_type.yaml")
204
205}
206
207func (h *Helm) ParseMessages(name string, chartDir, msgFile string) (msgs MessageTypes, err error) {
208 yamlFile, err := ioutil.ReadFile(path.Join(chartDir, name, msgFile))
209 if err != nil {
210 mdclog(Mdclog_err, formatLog("ReadFile failed", "", err.Error()))
211 return
212 }
213
214 err = yaml.Unmarshal(yamlFile, &msgs)
215 if err != nil {
216 mdclog(Mdclog_err, formatLog("Unmarshal failed", "", err.Error()))
217 return
218 }
219
220 if err = os.RemoveAll(path.Join(chartDir, name)); err != nil {
221 mdclog(Mdclog_err, formatLog("RemoveAll failed", "", err.Error()))
222 }
223
224 return
225}
226
227func (h *Helm) GetVersion(name string) (version string) {
228
229 ns := getNamespaceArgs()
230 out, err := h.Run(strings.Join([]string{"list --output yaml ", name, ns}, ""))
231 if err != nil {
232 return
233 }
234
235 var re = regexp.MustCompile(`AppVersion: .*`)
236 ver := re.FindStringSubmatch(string(out))
237 if ver != nil {
238 version = strings.Split(ver[0], ": ")[1]
239 version, _ = strconv.Unquote(version)
240 }
241
242 return
243}
244
245func (h *Helm) GetState(out string) (status string) {
246 re := regexp.MustCompile(`STATUS: .*`)
247 result := re.FindStringSubmatch(string(out))
248 if result != nil {
249 status = strings.ToLower(strings.Split(result[0], ": ")[1])
250 }
251
252 return
253}
254
255func (h *Helm) GetAddress(out string) (ip, port string) {
256 var tmp string
257 re := regexp.MustCompile(`ClusterIP.*`)
258 addr := re.FindStringSubmatch(string(out))
259 if addr != nil {
260 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
261 }
262
263 return
264}
265
266func (h *Helm) GetNames(out string) (names []string, err error) {
267 re := regexp.MustCompile(`Name: .*`)
268 result := re.FindAllStringSubmatch(out, -1)
269 if result == nil {
270 return
271 }
272
273 for _, v := range result {
274 xappName := strings.Split(v[0], ": ")[1]
275 if strings.Contains(xappName, "appmgr") == false {
276 names = append(names, xappName)
277 }
278 }
279 return names, nil
280}
281
282func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
283 ip, port := h.GetAddress(out)
284
285 var tmp string
286 r := regexp.MustCompile(`(?s)\/Pod.*?\/Service`)
287 result := r.FindStringSubmatch(string(out))
288 if result == nil {
289 return
290 }
291
292 re := regexp.MustCompile(name + "-(\\d+).*")
293 resources := re.FindAllStringSubmatch(string(result[0]), -1)
294 if resources != nil {
295 for _, v := range resources {
296 var x XappInstance
297 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
298 x.Status = strings.ToLower(x.Status)
299 x.Ip = ip
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)
304 }
305 }
306}
307
308func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
309 types, err := h.GetMessages(name)
310 if (err != nil) {
311 return
312 }
313
314 xapp.Name = name
315 xapp.Version = h.GetVersion(name)
316 xapp.Status = h.GetState(out)
317 h.FillInstanceData(name, out, &xapp, types)
318
319 return
320}
321
322func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
323 xapps = []Xapp{}
324
325 for _, name := range names {
326 x, err := h.Status(name)
327 if err == nil {
328 xapps = append(xapps, x)
329 }
330 }
331
332 return
333}
334
335func addTillerEnv() (err error) {
336
337 service := viper.GetString("helm.tiller-service")
338 namespace := viper.GetString("helm.tiller-namespace")
339 port := viper.GetString("helm.tiller-port")
340
341 if err = os.Setenv("HELM_HOST", service + "." + namespace + ":" + port); err != nil {
342 mdclog(Mdclog_err, formatLog("Tiller Env Setting Failed", "", err.Error()))
343 }
344
345 return err
346}
347
348func getNamespaceArgs() (string) {
349 ns := viper.GetString("xapp.namespace")
350 if ns == "" {
351 ns = "ricxapp"
352 }
353 return " --namespace=" + ns
354}
355
356func formatLog(text string, args string, err string) (string) {
357 return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)
358}
359