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 func HelmExec(args string) (out []byte, err error) {
67 return Exec(strings.Join([]string{"helm", args}, " "))
70 func KubectlExec(args string) (out []byte, err error) {
71 return Exec(strings.Join([]string{"kubectl", args}, " "))
74 func (h *Helm) Initialize() {
75 if h.initDone == true {
80 if _, err := h.Init(); err == nil {
81 mdclog(MdclogDebug, formatLog("Helm init done successfully!", "", ""))
84 mdclog(MdclogErr, formatLog("helm init failed, retyring ...", "", ""))
85 time.Sleep(time.Duration(10) * time.Second)
89 if _, err := h.AddRepo(); err == nil {
90 mdclog(MdclogDebug, formatLog("Helm repo added successfully", "", ""))
93 mdclog(MdclogErr, formatLog("Helm repo addition failed, retyring ...", "", ""))
94 time.Sleep(time.Duration(10) * time.Second)
100 func (h *Helm) Run(args string) (out []byte, err error) {
101 return HelmExec(args)
105 func (h *Helm) Init() (out []byte, err error) {
107 // Add Tiller address as environment variable
108 if err := addTillerEnv(); err != nil {
112 return HelmExec(strings.Join([]string{"init -c"}, ""))
115 func (h *Helm) AddRepo() (out []byte, err error) {
117 // Get helm repo user name and password from files mounted by secret object
118 credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
120 mdclog(MdclogErr, formatLog("helm_repo_username ReadFile failed", "", err.Error()))
124 username := " --username " + string(credFile)
126 credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
128 mdclog(MdclogErr, formatLog("helm_repo_password ReadFile failed", "", err.Error()))
132 pwd := " --password " + string(credFile)
134 // Get internal helm repo name
135 rname := viper.GetString("helm.repo-name")
137 // Get helm repo address from values.yaml
138 repo := viper.GetString("helm.repo")
140 return HelmExec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
143 func (h *Helm) Install(m ConfigMetadata) (xapp Xapp, err error) {
144 out, err := h.Run(strings.Join([]string{"repo update "}, ""))
149 m.Namespace = getNamespace(m.Namespace)
150 cm, cmErr := PurgeConfigMap(m)
152 ns := " --namespace=" + m.Namespace
153 rname := viper.GetString("helm.repo-name")
154 out, err = h.Run(strings.Join([]string{"install ", rname, "/", m.Name, " --name ", m.Name, ns}, ""))
160 cmErr = RestoreConfigMap(m, cm)
162 return h.ParseStatus(m.Name, string(out))
165 func (h *Helm) Status(name string) (xapp Xapp, err error) {
167 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
169 mdclog(MdclogErr, formatLog("Getting xapps status", "", err.Error()))
173 return h.ParseStatus(name, string(out))
176 func (h *Helm) StatusAll() (xapps []Xapp, err error) {
177 xappNameList, err := h.List()
179 mdclog(MdclogErr, formatLog("Helm list failed", "", err.Error()))
183 return h.parseAllStatus(xappNameList)
186 func (h *Helm) List() (names []string, err error) {
188 ns := getNamespace("")
189 out, err := h.Run(strings.Join([]string{"list --all --output yaml --namespace=", ns}, ""))
191 mdclog(MdclogErr, formatLog("Listing deployed xapps failed", "", err.Error()))
195 return h.GetNames(string(out))
198 func (h *Helm) Delete(name string) (xapp Xapp, err error) {
199 xapp, err = h.Status(name)
201 mdclog(MdclogErr, formatLog("Fetching xapp status failed", "", err.Error()))
205 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
209 func (h *Helm) Fetch(name, tarDir string) error {
210 if strings.HasSuffix(os.Args[0], ".test") {
214 rname := viper.GetString("helm.repo-name") + "/"
216 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
221 func (h *Helm) GetVersion(name string) (version string) {
223 ns := getNamespace("")
224 out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
229 var re = regexp.MustCompile(`AppVersion: .*`)
230 ver := re.FindStringSubmatch(string(out))
232 version = strings.Split(ver[0], ": ")[1]
233 version, _ = strconv.Unquote(version)
239 func (h *Helm) GetState(out string) (status string) {
240 re := regexp.MustCompile(`STATUS: .*`)
241 result := re.FindStringSubmatch(string(out))
243 status = strings.ToLower(strings.Split(result[0], ": ")[1])
249 func (h *Helm) GetAddress(out string) (ip, port string) {
251 re := regexp.MustCompile(`ClusterIP.*`)
252 addr := re.FindStringSubmatch(string(out))
254 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
260 func (h *Helm) GetNames(out string) (names []string, err error) {
261 re := regexp.MustCompile(`Name: .*`)
262 result := re.FindAllStringSubmatch(out, -1)
267 for _, v := range result {
268 xappName := strings.Split(v[0], ": ")[1]
269 if strings.Contains(xappName, "appmgr") == false {
270 names = append(names, xappName)
276 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
277 ip, port := h.GetAddress(out)
280 r := regexp.MustCompile(`(?s)\/Pod.*?\/Service`)
281 result := r.FindStringSubmatch(string(out))
286 re := regexp.MustCompile(name + "-(\\d+).*")
287 resources := re.FindAllStringSubmatch(string(result[0]), -1)
288 if resources != nil {
289 for _, v := range resources {
291 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
292 x.Status = strings.ToLower(x.Status)
294 x.Port, _ = strconv.Atoi(strings.Split(port, "/")[0])
295 x.TxMessages = msgs.TxMessages
296 x.RxMessages = msgs.RxMessages
297 xapp.Instances = append(xapp.Instances, x)
302 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
305 xapp.Version = h.GetVersion(name)
306 xapp.Status = h.GetState(out)
308 types, err := GetMessages(name)
310 // xAPP can still be deployed if the msg_type file is missing.
311 mdclog(MdclogWarn, formatLog("GetMessages Failed....", "", err.Error()))
313 //Set err back to nil, so it does not cause issues in called functions.
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(MdclogErr, formatLog("Tiller Env Setting Failed", "", err.Error()))
348 func getNamespace(namespace string) string {
353 ns := viper.GetString("xapp.namespace")
360 func formatLog(text string, args string, err string) string {
361 return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)