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 m.Namespace = getNamespace(m.Namespace)
154 if err = h.cm.GetConfigMap(m, &cm); err != nil {
155 out, err = h.Run(getInstallArgs(m, false))
159 return h.ParseStatus(m.Name, string(out))
162 // ConfigMap exists, try to override
163 out, err = h.Run(getInstallArgs(m, true))
165 return h.ParseStatus(m.Name, string(out))
168 cm, cmErr := h.cm.PurgeConfigMap(m)
169 out, err = h.Run(getInstallArgs(m, false))
175 cmErr = h.cm.RestoreConfigMap(m, cm)
177 return h.ParseStatus(m.Name, string(out))
180 func (h *Helm) Status(name string) (xapp Xapp, err error) {
181 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
183 mdclog(MdclogErr, formatLog("Getting xapps status", "", err.Error()))
187 return h.ParseStatus(name, string(out))
190 func (h *Helm) StatusAll() (xapps []Xapp, err error) {
191 xappNameList, err := h.List()
193 mdclog(MdclogErr, formatLog("Helm list failed", "", err.Error()))
197 return h.parseAllStatus(xappNameList)
200 func (h *Helm) List() (names []string, err error) {
201 ns := getNamespace("")
202 out, err := h.Run(strings.Join([]string{"list --all --output yaml --namespace=", ns}, ""))
204 mdclog(MdclogErr, formatLog("Listing deployed xapps failed", "", err.Error()))
208 return h.GetNames(string(out))
211 func (h *Helm) Delete(name string) (xapp Xapp, err error) {
212 xapp, err = h.Status(name)
214 mdclog(MdclogErr, formatLog("Fetching xapp status failed", "", err.Error()))
218 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
222 func (h *Helm) Fetch(name, tarDir string) error {
223 if strings.HasSuffix(os.Args[0], ".test") {
227 rname := viper.GetString("helm.repo-name") + "/"
229 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
234 func (h *Helm) GetVersion(name string) (version string) {
235 ns := getNamespace("")
236 out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
241 var re = regexp.MustCompile(`AppVersion: .*`)
242 ver := re.FindStringSubmatch(string(out))
244 version = strings.Split(ver[0], ": ")[1]
245 version, _ = strconv.Unquote(version)
251 func (h *Helm) GetState(out string) (status string) {
252 re := regexp.MustCompile(`STATUS: .*`)
253 result := re.FindStringSubmatch(string(out))
255 status = strings.ToLower(strings.Split(result[0], ": ")[1])
261 func (h *Helm) GetAddress(out string) (ip, port string) {
263 re := regexp.MustCompile(`ClusterIP.*`)
264 addr := re.FindStringSubmatch(string(out))
266 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
272 func (h *Helm) GetNames(out string) (names []string, err error) {
273 re := regexp.MustCompile(`Name: .*`)
274 result := re.FindAllStringSubmatch(out, -1)
279 for _, v := range result {
280 xappName := strings.Split(v[0], ": ")[1]
281 if strings.Contains(xappName, "appmgr") == false {
282 names = append(names, xappName)
288 func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
289 ip, port := h.GetAddress(out)
292 r := regexp.MustCompile(`(?s)\/Pod.*?\/Service`)
293 result := r.FindStringSubmatch(string(out))
298 re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
299 resources := re.FindAllStringSubmatch(string(result[0]), -1)
300 if resources != nil {
301 for _, v := range resources {
303 fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
304 x.Status = strings.ToLower(x.Status)
306 x.Port, _ = strconv.Atoi(strings.Split(port, "/")[0])
307 x.TxMessages = msgs.TxMessages
308 x.RxMessages = msgs.RxMessages
309 xapp.Instances = append(xapp.Instances, x)
314 func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
316 xapp.Version = h.GetVersion(name)
317 xapp.Status = h.GetState(out)
319 h.FillInstanceData(name, out, &xapp, h.cm.GetMessages(name))
324 func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
327 for _, name := range names {
328 x, err := h.Status(name)
330 xapps = append(xapps, x)
337 func addTillerEnv() (err error) {
338 service := viper.GetString("helm.tiller-service")
339 namespace := viper.GetString("helm.tiller-namespace")
340 port := viper.GetString("helm.tiller-port")
342 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
343 mdclog(MdclogErr, formatLog("Tiller Env Setting Failed", "", err.Error()))
349 func getNamespace(namespace string) string {
354 ns := viper.GetString("xapp.namespace")
361 func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
362 args = args + " --namespace=" + x.Namespace
364 if x.ImageRepo != "" {
365 args = args + " --set global.repository=" + x.ImageRepo
368 if x.ServiceName != "" {
369 args = args + " --set ricapp.service.name=" + x.ServiceName
372 if x.Hostname != "" {
373 args = args + " --set ricapp.hostname=" + x.Hostname
376 if cmOverride == true {
377 args = args + " --set ricapp.appconfig.override=" + x.Name + "-appconfig"
380 rname := viper.GetString("helm.repo-name")
381 return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)
384 func formatLog(text string, args string, err string) string {
385 return fmt.Sprintf("Helm: %s: args=%s err=%s\n", text, args, err)