Swagger-baser server REST API interface
[ric-plt/appmgr.git] / pkg / helm / helm.go
similarity index 57%
rename from cmd/appmgr/helm.go
rename to pkg/helm/helm.go
index 8a8154a..a3d7b18 100755 (executable)
 ==================================================================================
 */
 
-package main
+package helm
 
 import (
-       "bytes"
-       "errors"
        "fmt"
+       "github.com/ghodss/yaml"
        "github.com/spf13/viper"
        "io/ioutil"
-       "log"
        "os"
-       "os/exec"
        "regexp"
        "strconv"
        "strings"
        "time"
-)
-
-var execCommand = exec.Command
-
-func Exec(args string) (out []byte, err error) {
-       cmd := execCommand("/bin/sh", "-c", args)
-
-       var stdout bytes.Buffer
-       var stderr bytes.Buffer
-       cmd.Stdout = &stdout
-       cmd.Stderr = &stderr
-
-       log.Println("Running command: ", cmd)
-       for i := 0; i < viper.GetInt("helm.retry"); i++ {
-               err = cmd.Run()
-               if err != nil {
-                       Logger.Error("Command '%s' failed with error: %v, retrying", args, err.Error()+stderr.String())
-                       time.Sleep(time.Duration(2) * time.Second)
-                       continue
-               }
-               break
-       }
 
-       if err == nil && !strings.HasSuffix(os.Args[0], ".test") {
-               Logger.Info("command success: %s", stdout.String())
-               return stdout.Bytes(), nil
-       }
-
-       return stdout.Bytes(), errors.New(stderr.String())
-}
-
-var HelmExec = func(args string) (out []byte, err error) {
-       return Exec(strings.Join([]string{"helm", args}, " "))
-}
+       "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/appmgr"
+       "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/cm"
+       "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/models"
+       "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/util"
+)
 
-var KubectlExec = func(args string) (out []byte, err error) {
-       return Exec(strings.Join([]string{"kubectl", args}, " "))
+type Helm struct {
+       initDone bool
+       cm       *cm.CM
 }
 
-func (h *Helm) SetCM(cm ConfigMapper) {
-       h.cm = cm
+func NewHelm() *Helm {
+       return &Helm{initDone: false, cm: cm.NewCM()}
 }
 
 func (h *Helm) Initialize() {
@@ -82,115 +52,108 @@ func (h *Helm) Initialize() {
 
        for {
                if _, err := h.Init(); err == nil {
-                       Logger.Info("Helm init done successfully!")
+                       appmgr.Logger.Info("Helm init done successfully!")
                        break
                }
-               Logger.Error("helm init failed, retyring ...")
+               appmgr.Logger.Info("helm init failed, retyring ...")
                time.Sleep(time.Duration(10) * time.Second)
        }
 
        for {
                if _, err := h.AddRepo(); err == nil {
-                       Logger.Info("Helm repo added successfully")
+                       appmgr.Logger.Info("Helm repo added successfully")
                        break
                }
-               Logger.Error("Helm repo addition failed, retyring ...")
+               appmgr.Logger.Info("Helm repo addition failed, retyring ...")
                time.Sleep(time.Duration(10) * time.Second)
        }
-
        h.initDone = true
 }
 
 func (h *Helm) Run(args string) (out []byte, err error) {
-       return HelmExec(args)
+       return util.HelmExec(args)
 }
 
 // API functions
 func (h *Helm) Init() (out []byte, err error) {
-       // Add Tiller address as environment variable
-       if err := addTillerEnv(); err != nil {
+       if err := h.AddTillerEnv(); err != nil {
                return out, err
        }
 
-       return HelmExec(strings.Join([]string{"init -c --skip-refresh"}, ""))
+       return util.HelmExec(strings.Join([]string{"init -c --skip-refresh"}, ""))
 }
 
 func (h *Helm) AddRepo() (out []byte, err error) {
        // Get helm repo user name and password from files mounted by secret object
        credFile, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
        if err != nil {
-               Logger.Error("helm_repo_username ReadFile failed: %v", err.Error())
+               appmgr.Logger.Info("helm_repo_username ReadFile failed: %v", err.Error())
                return
        }
-
        username := " --username " + string(credFile)
 
        credFile, err = ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
        if err != nil {
-               Logger.Error("helm_repo_password ReadFile failed: %v", err.Error())
+               appmgr.Logger.Info("helm_repo_password ReadFile failed: %v", err.Error())
                return
        }
-
        pwd := " --password " + string(credFile)
 
-       // Get internal helm repo name
        rname := viper.GetString("helm.repo-name")
-
-       // Get helm repo address from values.yaml
        repo := viper.GetString("helm.repo")
 
-       return HelmExec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
+       return util.HelmExec(strings.Join([]string{"repo add ", rname, " ", repo, username, pwd}, ""))
 }
 
-func (h *Helm) Install(m XappDeploy) (xapp Xapp, err error) {
+func (h *Helm) Install(m models.XappDescriptor) (xapp models.Xapp, err error) {
+       var c interface{}
+       m.Namespace = h.cm.GetNamespace(m.Namespace)
+
        out, err := h.Run(strings.Join([]string{"repo update "}, ""))
        if err != nil {
                return
        }
 
-       var cm interface{}
-       m.Namespace = h.cm.GetNamespace(m.Namespace)
-
-       if err = h.cm.GetConfigMap(m, &cm); err != nil {
-               out, err = h.Run(getInstallArgs(m, false))
+       if err = h.cm.GetConfigMap(m, &c); err != nil {
+               out, err = h.Run(h.GetInstallArgs(m, false))
                if err != nil {
                        return
                }
-               return h.ParseStatus(m.Name, string(out))
+               return h.ParseStatus(*m.XappName, string(out))
        }
 
        // ConfigMap exists, try to override
-       out, err = h.Run(getInstallArgs(m, true))
+       out, err = h.Run(h.GetInstallArgs(m, true))
        if err == nil {
-               return h.ParseStatus(m.Name, string(out))
+               return h.ParseStatus(*m.XappName, string(out))
        }
 
-       cm, cmErr := h.cm.PurgeConfigMap(m)
-       out, err = h.Run(getInstallArgs(m, false))
+       c, cmErr := h.cm.PurgeConfigMap(m)
+       out, err = h.Run(h.GetInstallArgs(m, false))
        if err != nil {
                return
        }
 
        if cmErr == nil {
-               cmErr = h.cm.RestoreConfigMap(m, cm)
+               cmErr = h.cm.RestoreConfigMap(m, c)
        }
-       return h.ParseStatus(m.Name, string(out))
+       return h.ParseStatus(*m.XappName, string(out))
 }
 
-func (h *Helm) Status(name string) (xapp Xapp, err error) {
+func (h *Helm) Status(name string) (xapp models.Xapp, err error) {
        out, err := h.Run(strings.Join([]string{"status ", name}, ""))
        if err != nil {
-               Logger.Error("Getting xapps status: %v", err.Error())
+               appmgr.Logger.Info("Getting xapps status: %v", err.Error())
                return
        }
 
        return h.ParseStatus(name, string(out))
 }
 
-func (h *Helm) StatusAll() (xapps []Xapp, err error) {
+func (h *Helm) StatusAll() (xapps models.AllDeployedXapps, err error) {
        xappNameList, err := h.List()
        if err != nil {
-               Logger.Error("Helm list failed: %v", err.Error())
+               appmgr.Logger.Info("Helm list failed: %v", err.Error())
                return
        }
 
@@ -199,23 +162,23 @@ func (h *Helm) StatusAll() (xapps []Xapp, err error) {
 
 func (h *Helm) List() (names []string, err error) {
        ns := h.cm.GetNamespace("")
-       out, err := h.Run(strings.Join([]string{"list --all --output yaml --namespace=", ns}, ""))
+       out, err := h.Run(strings.Join([]string{"list --all --deployed --output yaml --namespace=", ns}, ""))
        if err != nil {
-               Logger.Error("Listing deployed xapps failed: %v", err.Error())
+               appmgr.Logger.Info("Listing deployed xapps failed: %v", err.Error())
                return
        }
 
        return h.GetNames(string(out))
 }
 
-func (h *Helm) SearchAll() (names []string) {
+func (h *Helm) SearchAll() models.AllDeployableXapps {
        return h.cm.GetNamesFromHelmRepo()
 }
 
-func (h *Helm) Delete(name string) (xapp Xapp, err error) {
+func (h *Helm) Delete(name string) (xapp models.Xapp, err error) {
        xapp, err = h.Status(name)
        if err != nil {
-               Logger.Error("Fetching xapp status failed: %v", err.Error())
+               appmgr.Logger.Info("Fetching xapp status failed: %v", err.Error())
                return
        }
 
@@ -237,7 +200,7 @@ func (h *Helm) Fetch(name, tarDir string) error {
 // Helper functions
 func (h *Helm) GetVersion(name string) (version string) {
        ns := h.cm.GetNamespace("")
-       out, err := h.Run(strings.Join([]string{"list --output yaml --namespace=", ns, " ", name}, ""))
+       out, err := h.Run(strings.Join([]string{"list --deployed --output yaml --namespace=", ns, " ", name}, ""))
        if err != nil {
                return
        }
@@ -276,14 +239,12 @@ func (h *Helm) GetAddress(out string) (ip, port string) {
 func (h *Helm) GetEndpointInfo(name string) (ip string, port int) {
        ns := h.cm.GetNamespace("")
        args := fmt.Sprintf(" get endpoints -o=jsonpath='{.subsets[*].addresses[*].ip}' service-%s-%s-rmr -n %s", ns, name, ns)
-       out, err := KubectlExec(args)
+       out, err := util.KubectlExec(args)
        if err != nil {
                return
        }
-       Logger.Info("Endpoint IP address of %s: %s", name, string(out))
-
-       // "service-<namespace>-<chartname>-rmr.<namespace>"
-       return "service-" + ns + "-" + name + "-rmr." + ns, 4560
+       appmgr.Logger.Info("Endpoint IP address of %s: %s", name, string(out))
+       return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
 }
 
 func (h *Helm) GetNames(out string) (names []string, err error) {
@@ -302,10 +263,10 @@ func (h *Helm) GetNames(out string) (names []string, err error) {
        return names, nil
 }
 
-func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs MessageTypes) {
+func (h *Helm) FillInstanceData(name string, out string, xapp *models.Xapp, msgs appmgr.MessageTypes) {
        ip, port := h.GetEndpointInfo(name)
        if ip == "" {
-               Logger.Info("Endpoint IP address not found, using CluserIP")
+               appmgr.Logger.Info("Endpoint IP address not found, using CluserIP")
                ip, _ = h.GetAddress(out)
        }
 
@@ -320,77 +281,88 @@ func (h *Helm) FillInstanceData(name string, out string, xapp *Xapp, msgs Messag
        resources := re.FindAllStringSubmatch(string(result[0]), -1)
        if resources != nil {
                for _, v := range resources {
-                       var x XappInstance
-                       fmt.Sscanf(v[0], "%s %s %s", &x.Name, &tmp, &x.Status)
+                       var x models.XappInstance
+                       var name string
+                       fmt.Sscanf(v[0], "%s %s %s", &name, &tmp, &x.Status)
+                       x.Name = &name
                        x.Status = strings.ToLower(x.Status)
-                       x.Ip = ip
-                       x.Port = port
+                       x.IP = ip
+                       x.Port = int64(port)
                        x.TxMessages = msgs.TxMessages
                        x.RxMessages = msgs.RxMessages
-                       xapp.Instances = append(xapp.Instances, x)
+                       xapp.Instances = append(xapp.Instances, &x)
                }
        }
 }
 
-func (h *Helm) ParseStatus(name string, out string) (xapp Xapp, err error) {
-       xapp.Name = name
+func (h *Helm) ParseStatus(name string, out string) (xapp models.Xapp, err error) {
+       xapp.Name = &name
        xapp.Version = h.GetVersion(name)
        xapp.Status = h.GetState(out)
 
        h.FillInstanceData(name, out, &xapp, h.cm.GetMessages(name))
-
        return
 }
 
-func (h *Helm) parseAllStatus(names []string) (xapps []Xapp, err error) {
-       xapps = []Xapp{}
-
+func (h *Helm) parseAllStatus(names []string) (xapps models.AllDeployedXapps, err error) {
+       xapps = models.AllDeployedXapps{}
        for _, name := range names {
-               err := h.cm.ReadSchema(name, &XAppConfig{})
+               err := h.cm.ReadSchema(name, &models.XAppConfig{})
                if err != nil {
                        continue
                }
 
                x, err := h.Status(name)
                if err == nil {
-                       xapps = append(xapps, x)
+                       xapps = append(xapps, &x)
                }
        }
-
        return
 }
 
-func addTillerEnv() (err error) {
+func (h *Helm) AddTillerEnv() (err error) {
        service := viper.GetString("helm.tiller-service")
        namespace := viper.GetString("helm.tiller-namespace")
        port := viper.GetString("helm.tiller-port")
 
        if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
-               Logger.Error("Tiller Env Setting Failed: %v", err.Error())
+               appmgr.Logger.Info("Tiller Env Setting Failed: %v", err.Error())
        }
-
        return err
 }
 
-func getInstallArgs(x XappDeploy, cmOverride bool) (args string) {
+func (h *Helm) GetInstallArgs(x models.XappDescriptor, cmOverride bool) (args string) {
        args = args + " --namespace=" + x.Namespace
-
-       if x.ImageRepo != "" {
-               args = args + " --set global.repository=" + x.ImageRepo
-       }
-
-       if x.ServiceName != "" {
-               args = args + " --set ricapp.service.name=" + x.ServiceName
+       if x.HelmVersion != "" {
+               args = args + " --version=" + x.HelmVersion
        }
 
-       if x.Hostname != "" {
-               args = args + " --set ricapp.hostname=" + x.Hostname
+       if x.ReleaseName != "" {
+               args = args + " --name=" + x.ReleaseName
+       } else {
+               args = args + " --name=" + *x.XappName
        }
 
        if cmOverride == true {
-               args = args + " --set ricapp.appconfig.override=" + x.Name + "-appconfig"
+               args = args + " --set ricapp.appconfig.override=" + *x.XappName + "-appconfig"
+       }
+
+       if x.OverrideFile != nil {
+               if overrideYaml, err := yaml.JSONToYAML([]byte(x.OverrideFile.(string))); err == nil {
+                       err = ioutil.WriteFile("/tmp/appmgr_override.yaml", overrideYaml, 0644)
+                       if err != nil {
+                               appmgr.Logger.Info("ioutil.WriteFile(/tmp/appmgr_override.yaml) failed: %v", err)
+                       } else {
+                               args = args + " -f=/tmp/appmgr_override.yaml"
+                       }
+               } else {
+                       appmgr.Logger.Info("yaml.JSONToYAML failed: %v", err)
+               }
        }
 
-       rname := viper.GetString("helm.repo-name")
-       return fmt.Sprintf("install %s/%s --name=%s %s", rname, x.Name, x.Name, args)
+       repoName := viper.GetString("helm.repo-name")
+       if repoName == "" {
+               repoName = "helm-repo"
+       }
+       return fmt.Sprintf("install %s/%s %s", repoName, *x.XappName, args)
 }