Enabling helm3 Support for appmgr.
[ric-plt/appmgr.git] / pkg / helm / helm.go
index e777403..806a6c8 100755 (executable)
 package helm
 
 import (
-       "fmt"
-       "github.com/ghodss/yaml"
-       "github.com/spf13/viper"
-       "io/ioutil"
-       "os"
-       "regexp"
-       "strconv"
-       "strings"
-       "time"
-
-       "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
-       "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/cm"
-       "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
-       "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
+        "fmt"
+        "github.com/ghodss/yaml"
+        "github.com/spf13/viper"
+        "io/ioutil"
+        "os"
+        "regexp"
+        "strconv"
+        "strings"
+        "time"
+
+        "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
+        "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/cm"
+        "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
+        "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
 )
 
 var kubeExec = util.KubectlExec
 var helmExec = util.HelmExec
 
 type Helm struct {
-       initDone bool
-       cm       *cm.CM
+        initDone bool
+        cm       *cm.CM
 }
 
+func GetHelmVersion() {
+        var temp string
+        temp = os.Getenv("HELMVERSION")
+        appmgr.Logger.Info("Inside new Helm")
+        temp = strings.TrimLeft(temp,"v")
+        cm.EnvHelmVersion = string(temp[0:1]) //s.TrimRight(temp, ".")
+        appmgr.Logger.Info(cm.EnvHelmVersion)
+}
+
+
 func NewHelm() *Helm {
-       return &Helm{initDone: false, cm: cm.NewCM()}
+        GetHelmVersion()
+        return &Helm{initDone: false, cm: cm.NewCM()}
 }
 
 func (h *Helm) Initialize() {
-       if h.initDone == true {
-               return
-       }
-
-       for {
-               if _, err := h.Init(); err == nil {
-                       appmgr.Logger.Info("Helm init done successfully!")
-                       break
-               }
-               appmgr.Logger.Info("helm init failed, retyring ...")
-               time.Sleep(time.Duration(10) * time.Second)
-       }
-
-       for {
-               if _, err := h.AddRepo(); err == nil {
-                       appmgr.Logger.Info("Helm repo added successfully")
-                       break
-               }
-               appmgr.Logger.Info("Helm repo addition failed, retyring ...")
-               time.Sleep(time.Duration(10) * time.Second)
-       }
-       h.initDone = true
+        if h.initDone == true {
+                return
+        }
+        appmgr.Logger.Info("START")
+        for {
+                if _, err := h.Init(); err == nil {
+                        appmgr.Logger.Info("Helm init done successfully!")
+                        break
+                }
+                appmgr.Logger.Info("helm init failed, retyring ...")
+                time.Sleep(time.Duration(10) * time.Second)
+        }
+        if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
+                appmgr.Logger.Info("Codintion met for HELM3")
+                util.HelmExec(strings.Join([]string{"repo add stable https://kubernetes-charts.storage.googleapis.com/ "}, ""))
+        }
+
+        for {
+                if _, err := h.AddRepo(); err == nil {
+                        appmgr.Logger.Info("Helm repo added successfully")
+                        break
+                }
+                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 helmExec(args)
 }
 
 // API functions
 func (h *Helm) Init() (out []byte, err error) {
-       if err := h.AddTillerEnv(); err != nil {
-               return out, err
-       }
-
-       return helmExec(strings.Join([]string{"init -c --skip-refresh"}, ""))
+        if err := h.AddTillerEnv(); err != nil {
+                return out, err
+        }
+        if cm.EnvHelmVersion == cm.HELM_VERSION_2{
+                appmgr.Logger.Info("Init for Version 2")
+                return helmExec(strings.Join([]string{"init -c --skip-refresh"}, ""))
+        }
+
+        return out, err
 }
 
 func (h *Helm) AddRepo() (out []byte, err error) {
-       // Get helm repo user name and password from files mounted by secret object
-       username, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
-       if err != nil {
-               appmgr.Logger.Info("helm_repo_username ReadFile failed: %v", err.Error())
-               return
-       }
-
-       password, err := ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
-       if err != nil {
-               appmgr.Logger.Info("helm_repo_password ReadFile failed: %v", err.Error())
-               return
-       }
-
-       repoArgs := fmt.Sprintf(" %s %s ", viper.GetString("helm.repo-name"), viper.GetString("helm.repo"))
-       credentials := fmt.Sprintf(" --username %s --password %s", string(username), string(password))
-
-       return helmExec(strings.Join([]string{"repo add ", repoArgs, credentials}, ""))
+        // Get helm repo user name and password from files mounted by secret object
+        username, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
+        if err != nil {
+                appmgr.Logger.Info("helm_repo_username ReadFile failed: %v", err.Error())
+                return
+        }
+
+        password, err := ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
+        if err != nil {
+                appmgr.Logger.Info("helm_repo_password ReadFile failed: %v", err.Error())
+                return
+        }
+
+        repoArgs := fmt.Sprintf(" %s %s ", viper.GetString("helm.repo-name"), viper.GetString("helm.repo"))
+        credentials := fmt.Sprintf(" --username %s --password %s", string(username), string(password))
+
+        return helmExec(strings.Join([]string{"repo add ", repoArgs, credentials}, ""))
 }
 
 func (h *Helm) Install(m models.XappDescriptor) (xapp models.Xapp, err error) {
-       m.Namespace = h.cm.GetNamespace(m.Namespace)
-
-       out, err := h.Run(strings.Join([]string{"repo update "}, ""))
-       if err != nil {
-               return
-       }
-
-       out, err = h.Run(h.GetInstallArgs(m, false))
-       if err != nil {
-               return
-       }
-       return h.ParseStatus(*m.XappName, string(out))
+        m.Namespace = h.cm.GetNamespace(m.Namespace)
+
+        out, err := h.Run(strings.Join([]string{"repo update "}, ""))
+        if err != nil {
+                return
+        }
+
+        out, err = h.Run(h.GetInstallArgs(m, false))
+        if err != nil {
+                return
+        }
+        return h.ParseStatus(*m.XappName, string(out))
 }
 
 func (h *Helm) Status(name string) (xapp models.Xapp, err error) {
-       out, err := h.Run(strings.Join([]string{"status ", name}, ""))
-       if err != nil {
-               appmgr.Logger.Info("Getting xapps status: %v", err.Error())
-               return
-       }
-       return h.ParseStatus(name, string(out))
+         var command string
+        if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
+                names  := h.cm.GetNamespace("")
+                command = strings.Join([]string{"status ", name," --namespace ", names}, "")
+                appmgr.Logger.Info ("Status: Version 3")
+        }else {
+                command = strings.Join([]string{"status ", name}, "")
+                appmgr.Logger.Info ("Status: Version 2")
+        }
+        out, err := h.Run(command)
+
+        if err != nil {
+                appmgr.Logger.Info("Getting xapps status: %v", err.Error())
+                return
+        }
+        return h.ParseStatus(name, string(out))
 }
 
 func (h *Helm) StatusAll() (xapps models.AllDeployedXapps, err error) {
-       xappNameList, err := h.List()
-       if err != nil {
-               appmgr.Logger.Info("Helm list failed: %v", err.Error())
-               return
-       }
+        xappNameList, err := h.List()
+        if err != nil {
+                appmgr.Logger.Info("Helm list failed: %v", err.Error())
+                return
+        }
 
-       return h.parseAllStatus(xappNameList)
+        return h.parseAllStatus(xappNameList)
 }
 
 func (h *Helm) List() (names []string, err error) {
-       ns := h.cm.GetNamespace("")
-       out, err := h.Run(strings.Join([]string{"list --all --deployed --output yaml --namespace=", ns}, ""))
-       if err != nil {
-               appmgr.Logger.Info("Listing deployed xapps failed: %v", err.Error())
-               return
-       }
-
-       return h.GetNames(string(out))
+        ns := h.cm.GetNamespace("")
+        out, err := h.Run(strings.Join([]string{"list --all --deployed --output yaml --namespace=", ns}, ""))
+        if err != nil {
+                appmgr.Logger.Info("Listing deployed xapps failed: %v", err.Error())
+                return
+        }
+
+        return h.GetNames(string(out))
 }
 
 func (h *Helm) SearchAll() models.AllDeployableXapps {
-       return h.cm.GetNamesFromHelmRepo()
+        return h.cm.GetNamesFromHelmRepo()
 }
 
 func (h *Helm) Delete(name string) (xapp models.Xapp, err error) {
-       xapp, err = h.Status(name)
-       if err != nil {
-               appmgr.Logger.Info("Fetching xapp status failed: %v", err.Error())
-               return
-       }
-
-       _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
-       return xapp, err
+        xapp, err = h.Status(name)
+        var command string = ""
+        ns := h.cm.GetNamespace("")
+
+        if err != nil {
+                appmgr.Logger.Info("Fetching xapp status failed: %v", err.Error())
+                return
+        }
+        if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
+                command = strings.Join([]string{"uninstall ", name," -n ", ns}, "")
+                appmgr.Logger.Info ("DELETE: Version 3")
+        } else {
+                command = strings.Join([]string{"del --purge ", name}, "")
+                appmgr.Logger.Info ("DELETE: Version 2")
+        }
+         _, err = h.Run (command)
+
+        return xapp, err
 }
 
 func (h *Helm) Fetch(name, tarDir string) error {
-       if strings.HasSuffix(os.Args[0], ".test") {
-               return nil
-       }
+        if strings.HasSuffix(os.Args[0], ".test") {
+                return nil
+        }
 
-       rname := viper.GetString("helm.repo-name") + "/"
+        rname := viper.GetString("helm.repo-name") + "/"
 
-       _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
-       return err
+        _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
+        return err
 }
 
 // Helper functions
 func (h *Helm) GetVersion(name string) (version string) {
-       ns := h.cm.GetNamespace("")
-       out, err := h.Run(strings.Join([]string{"list --deployed --output yaml --namespace=", ns, " ", name}, ""))
-       if err != nil {
-               return
-       }
-
-       var re = regexp.MustCompile(`AppVersion: .*`)
-       ver := re.FindStringSubmatch(string(out))
-       if ver != nil {
-               version = strings.Split(ver[0], ": ")[1]
-               version, _ = strconv.Unquote(version)
-       }
-
-       return
+        ns := h.cm.GetNamespace("")
+        var command string = ""
+        if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
+                command = strings.Join([]string{"list --deployed --output yaml --namespace=", ns, " ","-f ",name}, "")
+                appmgr.Logger.Info ("GetVersion: Version 3")
+        } else {
+                command = strings.Join([]string{"list --deployed --output yaml --namespace=", ns, " ", name}, "")
+                appmgr.Logger.Info ("GetVersion: Version 2")
+        }
+        out, err := h.Run(command)
+
+        if err != nil {
+                return
+        }
+
+        var re = regexp.MustCompile(`AppVersion: .*`)
+        ver := re.FindStringSubmatch(string(out))
+        if ver != nil {
+                version = strings.Split(ver[0], ": ")[1]
+                version, _ = strconv.Unquote(version)
+        }
+
+        return
 }
 
 func (h *Helm) GetState(out string) (status string) {
-       re := regexp.MustCompile(`STATUS: .*`)
-       result := re.FindStringSubmatch(string(out))
-       if result != nil {
-               status = strings.ToLower(strings.Split(result[0], ": ")[1])
-       }
+        re := regexp.MustCompile(`STATUS: .*`)
+        result := re.FindStringSubmatch(string(out))
+        if result != nil {
+                status = strings.ToLower(strings.Split(result[0], ": ")[1])
+        }
 
-       return
+        return
 }
 
 func (h *Helm) GetAddress(out string) (ip, port string) {
-       var tmp string
-       re := regexp.MustCompile(`ClusterIP.*`)
-       addr := re.FindStringSubmatch(string(out))
-       if addr != nil {
-               fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
-       }
-
-       return
+        var tmp string
+        re := regexp.MustCompile(`ClusterIP.*`)
+        addr := re.FindStringSubmatch(string(out))
+        if addr != nil {
+                fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
+        }
+
+        return
 }
 
 func (h *Helm) GetEndpointInfo(name string) (svc string, port int) {
-       port = 4560 // Default
-       ns := h.cm.GetNamespace("")
-       args := fmt.Sprintf(" get service -n %s service-%s-%s-rmr -o json", ns, ns, name)
-       out, err := kubeExec(args)
-       if err != nil {
-               return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
-       }
-       appmgr.Logger.Debug("Endpoint IP address of %s: %s", name, string(out))
-
-       v, err := h.cm.ParseJson(string(out))
-       if err != nil {
-               return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
-       }
-
-       for _, p := range v.GetArray("spec", "ports") {
-               if string(p.GetStringBytes("name")) == "rmrdata" {
-                       port = int(p.GetInt("port"))
-                       break
-               }
-       }
-       appmgr.Logger.Info("service-%s-%s-rmr.%s %d", ns, name, ns, port)
-
-       return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), port
+        port = 4560 // Default
+        ns := h.cm.GetNamespace("")
+        args := fmt.Sprintf(" get service -n %s service-%s-%s-rmr -o json", ns, ns, name)
+        out, err := kubeExec(args)
+        if err != nil {
+                return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
+        }
+        appmgr.Logger.Debug("Endpoint IP address of %s: %s", name, string(out))
+
+        v, err := h.cm.ParseJson(string(out))
+        if err != nil {
+                return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
+        }
+
+        for _, p := range v.GetArray("spec", "ports") {
+                if string(p.GetStringBytes("name")) == "rmrdata" {
+                        port = int(p.GetInt("port"))
+                        break
+                }
+        }
+        appmgr.Logger.Info("service-%s-%s-rmr.%s %d", ns, name, ns, port)
+
+        return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), port
 }
 
 func (h *Helm) GetNames(out string) (names []string, err error) {
-       re := regexp.MustCompile(`Name: .*`)
-       result := re.FindAllStringSubmatch(out, -1)
-       if result == nil {
-               return
-       }
-
-       for _, v := range result {
-               xappName := strings.Split(v[0], ": ")[1]
-               if strings.Contains(xappName, "appmgr") == false {
-                       names = append(names, xappName)
-               }
-       }
-       return names, nil
+        re := regexp.MustCompile(`Name: .*`)
+        result := re.FindAllStringSubmatch(out, -1)
+        if result == nil {
+                return
+        }
+
+        for _, v := range result {
+                xappName := strings.Split(v[0], ": ")[1]
+                if strings.Contains(xappName, "appmgr") == false {
+                        names = append(names, xappName)
+                }
+        }
+        return names, nil
 }
 
 func (h *Helm) FillInstanceData(name string, out string, xapp *models.Xapp, rtData appmgr.RtmData) {
-       ip, port := h.GetEndpointInfo(name)
-       if ip == "" {
-               appmgr.Logger.Info("Endpoint IP address not found, using CluserIP")
-               ip, _ = h.GetAddress(out)
-       }
-
-       var tmp string
-       r := regexp.MustCompile(`.*(?s)(Running|Pending|Succeeded|Failed|Unknown).*?\r?\n\r?\n`)
-       result := r.FindStringSubmatch(string(out))
-       if result == nil {
-               return
-       }
-
-       re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
-       resources := re.FindAllStringSubmatch(string(result[0]), -1)
-       if resources != nil {
-               for _, v := range resources {
-                       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 = int64(port)
-                       x.TxMessages = rtData.TxMessages
-                       x.RxMessages = rtData.RxMessages
-                       x.Policies = rtData.Policies
-                       xapp.Instances = append(xapp.Instances, &x)
-               }
-       }
+        ip, port := h.GetEndpointInfo(name)
+        if ip == "" {
+                appmgr.Logger.Info("Endpoint IP address not found, using CluserIP")
+                ip, _ = h.GetAddress(out)
+        }
+
+        var tmp string
+        r := regexp.MustCompile(`.*(?s)(Running|Pending|Succeeded|Failed|Unknown).*?\r?\n\r?\n`)
+        result := r.FindStringSubmatch(string(out))
+        if result == nil {
+                return
+        }
+
+        re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
+        resources := re.FindAllStringSubmatch(string(result[0]), -1)
+        if resources != nil {
+                for _, v := range resources {
+                        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 = int64(port)
+                        x.TxMessages = rtData.TxMessages
+                        x.RxMessages = rtData.RxMessages
+                        x.Policies = rtData.Policies
+                        xapp.Instances = append(xapp.Instances, &x)
+                }
+        }
 }
 
 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)
+        xapp.Name = &name
+        xapp.Version = h.GetVersion(name)
+        xapp.Status = h.GetState(out)
 
-       h.FillInstanceData(name, out, &xapp, h.cm.GetRtmData(name))
-       return
+        h.FillInstanceData(name, out, &xapp, h.cm.GetRtmData(name))
+        return
 }
 
 func (h *Helm) parseAllStatus(names []string) (xapps models.AllDeployedXapps, err error) {
-       xapps = models.AllDeployedXapps{}
-       for _, name := range names {
-               var desc interface{}
-               err := h.cm.ReadSchema(name, &desc)
-               if err != nil {
-                       continue
-               }
-
-               x, err := h.Status(name)
-               if err == nil {
-                       xapps = append(xapps, &x)
-               }
-       }
-       return
+        xapps = models.AllDeployedXapps{}
+        for _, name := range names {
+                var desc interface{}
+                err := h.cm.ReadSchema(name, &desc)
+                if err != nil {
+                        continue
+                }
+
+                x, err := h.Status(name)
+                if err == nil {
+                        xapps = append(xapps, &x)
+                }
+        }
+        return
 }
 
 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 {
-               appmgr.Logger.Info("Tiller Env Setting Failed: %v", err.Error())
-       }
-       return err
+        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 {
+                appmgr.Logger.Info("Tiller Env Setting Failed: %v", err.Error())
+        }
+        return err
 }
 
 func (h *Helm) GetInstallArgs(x models.XappDescriptor, cmOverride bool) (args string) {
-       args = fmt.Sprintf("%s --namespace=%s", args, x.Namespace)
-       if x.HelmVersion != "" {
-               args = fmt.Sprintf("%s --version=%s", args, x.HelmVersion)
-       }
-
-       if x.ReleaseName != "" {
-               args = fmt.Sprintf("%s --name=%s", args, x.ReleaseName)
-       } else {
-               args = fmt.Sprintf("%s --name=%s", args, *x.XappName)
-       }
-
-       if cmOverride == true {
-               args = fmt.Sprintf("%s --set ricapp.appconfig.override=%s-appconfig", args, *x.XappName)
-       }
-
-       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)
-               }
-       }
-
-       repoName := viper.GetString("helm.repo-name")
-       if repoName == "" {
-               repoName = "helm-repo"
-       }
-       return fmt.Sprintf("install %s/%s %s", repoName, *x.XappName, args)
+        args = fmt.Sprintf("%s--namespace=%s", args, x.Namespace)
+        if x.HelmVersion != "" {
+                args = fmt.Sprintf("%s --version=%s", args, x.HelmVersion)
+        }
+
+
+        if cm.EnvHelmVersion == cm.HELM_VERSION_2 {
+                if x.ReleaseName != "" {
+                        args = fmt.Sprintf("%s --name=%s", args, x.ReleaseName)
+                } else {
+                        args = fmt.Sprintf("%s --name=%s", args, *x.XappName)
+                        appmgr.Logger.Info("")
+                }
+                appmgr.Logger.Info ("GetInstallArgs: Version 2")
+        }
+
+        if cmOverride == true {
+                args = fmt.Sprintf("%s --set ricapp.appconfig.override=%s-appconfig", args, *x.XappName)
+        }
+
+        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)
+                }
+        }
+
+        repoName := viper.GetString("helm.repo-name")
+        if repoName == "" {
+                repoName = "helm-repo"
+        }
+
+
+        if cm.EnvHelmVersion == cm.HELM_VERSION_3 {
+                appmgr.Logger.Info ("GetInstallArgs last: Version 3")
+                return fmt.Sprintf("install %s %s/%s %s",*x.XappName, repoName, *x.XappName, args)
+        } else {
+                appmgr.Logger.Info ("GetInstallArgs last: Version 2")
+                return fmt.Sprintf("install %s/%s %s", repoName, *x.XappName, args)
+        }
 }