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 ==================================================================================
24 "github.com/ghodss/yaml"
25 "github.com/spf13/viper"
33 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
34 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/cm"
35 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
36 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
39 var kubeExec = util.KubectlExec
40 var helmExec = util.HelmExec
47 func NewHelm() *Helm {
48 return &Helm{initDone: false, cm: cm.NewCM()}
51 func (h *Helm) Initialize() {
52 if h.initDone == true {
57 if _, err := h.Init(); err == nil {
58 appmgr.Logger.Info("Helm init done successfully!")
61 appmgr.Logger.Info("helm init failed, retyring ...")
62 time.Sleep(time.Duration(10) * time.Second)
66 if _, err := h.AddRepo(); err == nil {
67 appmgr.Logger.Info("Helm repo added successfully")
70 appmgr.Logger.Info("Helm repo addition failed, retyring ...")
71 time.Sleep(time.Duration(10) * time.Second)
76 func (h *Helm) Run(args string) (out []byte, err error) {
81 func (h *Helm) Init() (out []byte, err error) {
82 if err := h.AddTillerEnv(); err != nil {
86 return helmExec(strings.Join([]string{"init -c --skip-refresh"}, ""))
89 func (h *Helm) AddRepo() (out []byte, err error) {
90 // Get helm repo user name and password from files mounted by secret object
91 username, err := ioutil.ReadFile(viper.GetString("helm.helm-username-file"))
93 appmgr.Logger.Info("helm_repo_username ReadFile failed: %v", err.Error())
97 password, err := ioutil.ReadFile(viper.GetString("helm.helm-password-file"))
99 appmgr.Logger.Info("helm_repo_password ReadFile failed: %v", err.Error())
103 repoArgs := fmt.Sprintf(" %s %s ", viper.GetString("helm.repo-name"), viper.GetString("helm.repo"))
104 credentials := fmt.Sprintf(" --username %s --password %s", string(username), string(password))
106 return helmExec(strings.Join([]string{"repo add ", repoArgs, credentials}, ""))
109 func (h *Helm) Install(m models.XappDescriptor) (xapp models.Xapp, err error) {
110 m.Namespace = h.cm.GetNamespace(m.Namespace)
112 out, err := h.Run(strings.Join([]string{"repo update "}, ""))
117 out, err = h.Run(h.GetInstallArgs(m, false))
121 return h.ParseStatus(*m.XappName, string(out))
124 func (h *Helm) Status(name string) (xapp models.Xapp, err error) {
125 out, err := h.Run(strings.Join([]string{"status ", name}, ""))
127 appmgr.Logger.Info("Getting xapps status: %v", err.Error())
130 return h.ParseStatus(name, string(out))
133 func (h *Helm) StatusAll() (xapps models.AllDeployedXapps, err error) {
134 xappNameList, err := h.List()
136 appmgr.Logger.Info("Helm list failed: %v", err.Error())
140 return h.parseAllStatus(xappNameList)
143 func (h *Helm) List() (names []string, err error) {
144 ns := h.cm.GetNamespace("")
145 out, err := h.Run(strings.Join([]string{"list --all --deployed --output yaml --namespace=", ns}, ""))
147 appmgr.Logger.Info("Listing deployed xapps failed: %v", err.Error())
151 return h.GetNames(string(out))
154 func (h *Helm) SearchAll() models.AllDeployableXapps {
155 return h.cm.GetNamesFromHelmRepo()
158 func (h *Helm) Delete(name string) (xapp models.Xapp, err error) {
159 xapp, err = h.Status(name)
161 appmgr.Logger.Info("Fetching xapp status failed: %v", err.Error())
165 _, err = h.Run(strings.Join([]string{"del --purge ", name}, ""))
169 func (h *Helm) Fetch(name, tarDir string) error {
170 if strings.HasSuffix(os.Args[0], ".test") {
174 rname := viper.GetString("helm.repo-name") + "/"
176 _, err := h.Run(strings.Join([]string{"fetch --untar --untardir ", tarDir, " ", rname, name}, ""))
181 func (h *Helm) GetVersion(name string) (version string) {
182 ns := h.cm.GetNamespace("")
183 out, err := h.Run(strings.Join([]string{"list --deployed --output yaml --namespace=", ns, " ", name}, ""))
188 var re = regexp.MustCompile(`AppVersion: .*`)
189 ver := re.FindStringSubmatch(string(out))
191 version = strings.Split(ver[0], ": ")[1]
192 version, _ = strconv.Unquote(version)
198 func (h *Helm) GetState(out string) (status string) {
199 re := regexp.MustCompile(`STATUS: .*`)
200 result := re.FindStringSubmatch(string(out))
202 status = strings.ToLower(strings.Split(result[0], ": ")[1])
208 func (h *Helm) GetAddress(out string) (ip, port string) {
210 re := regexp.MustCompile(`ClusterIP.*`)
211 addr := re.FindStringSubmatch(string(out))
213 fmt.Sscanf(addr[0], "%s %s %s %s", &tmp, &ip, &tmp, &port)
219 func (h *Helm) GetEndpointInfo(name string) (svc string, port int) {
220 port = 4560 // Default
221 ns := h.cm.GetNamespace("")
222 args := fmt.Sprintf(" get service -n %s service-%s-%s-rmr -o json", ns, ns, name)
223 out, err := kubeExec(args)
225 return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
227 appmgr.Logger.Debug("Endpoint IP address of %s: %s", name, string(out))
229 v, err := h.cm.ParseJson(string(out))
231 return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), 4560
234 for _, p := range v.GetArray("spec", "ports") {
235 if string(p.GetStringBytes("name")) == "rmrdata" {
236 port = int(p.GetInt("port"))
240 appmgr.Logger.Info("service-%s-%s-rmr.%s %d", ns, name, ns, port)
242 return fmt.Sprintf("service-%s-%s-rmr.%s", ns, name, ns), port
245 func (h *Helm) GetNames(out string) (names []string, err error) {
246 re := regexp.MustCompile(`Name: .*`)
247 result := re.FindAllStringSubmatch(out, -1)
252 for _, v := range result {
253 xappName := strings.Split(v[0], ": ")[1]
254 if strings.Contains(xappName, "appmgr") == false {
255 names = append(names, xappName)
261 func (h *Helm) FillInstanceData(name string, out string, xapp *models.Xapp, rtData appmgr.RtmData) {
262 ip, port := h.GetEndpointInfo(name)
264 appmgr.Logger.Info("Endpoint IP address not found, using CluserIP")
265 ip, _ = h.GetAddress(out)
269 r := regexp.MustCompile(`.*(?s)(Running|Pending|Succeeded|Failed|Unknown).*?\r?\n\r?\n`)
270 result := r.FindStringSubmatch(string(out))
275 re := regexp.MustCompile(name + "-(\\w+-\\w+).*")
276 resources := re.FindAllStringSubmatch(string(result[0]), -1)
277 if resources != nil {
278 for _, v := range resources {
279 var x models.XappInstance
281 fmt.Sscanf(v[0], "%s %s %s", &name, &tmp, &x.Status)
283 x.Status = strings.ToLower(x.Status)
286 x.TxMessages = rtData.TxMessages
287 x.RxMessages = rtData.RxMessages
288 x.Policies = rtData.Policies
289 xapp.Instances = append(xapp.Instances, &x)
294 func (h *Helm) ParseStatus(name string, out string) (xapp models.Xapp, err error) {
296 xapp.Version = h.GetVersion(name)
297 xapp.Status = h.GetState(out)
299 h.FillInstanceData(name, out, &xapp, h.cm.GetRtmData(name))
303 func (h *Helm) parseAllStatus(names []string) (xapps models.AllDeployedXapps, err error) {
304 xapps = models.AllDeployedXapps{}
305 for _, name := range names {
307 err := h.cm.ReadSchema(name, &desc)
312 x, err := h.Status(name)
314 xapps = append(xapps, &x)
320 func (h *Helm) AddTillerEnv() (err error) {
321 service := viper.GetString("helm.tiller-service")
322 namespace := viper.GetString("helm.tiller-namespace")
323 port := viper.GetString("helm.tiller-port")
325 if err = os.Setenv("HELM_HOST", service+"."+namespace+":"+port); err != nil {
326 appmgr.Logger.Info("Tiller Env Setting Failed: %v", err.Error())
331 func (h *Helm) GetInstallArgs(x models.XappDescriptor, cmOverride bool) (args string) {
332 args = fmt.Sprintf("%s --namespace=%s", args, x.Namespace)
333 if x.HelmVersion != "" {
334 args = fmt.Sprintf("%s --version=%s", args, x.HelmVersion)
337 if x.ReleaseName != "" {
338 args = fmt.Sprintf("%s --name=%s", args, x.ReleaseName)
340 args = fmt.Sprintf("%s --name=%s", args, *x.XappName)
343 if cmOverride == true {
344 args = fmt.Sprintf("%s --set ricapp.appconfig.override=%s-appconfig", args, *x.XappName)
347 if x.OverrideFile != nil {
348 if overrideYaml, err := yaml.JSONToYAML([]byte(x.OverrideFile.(string))); err == nil {
349 err = ioutil.WriteFile("/tmp/appmgr_override.yaml", overrideYaml, 0644)
351 appmgr.Logger.Info("ioutil.WriteFile(/tmp/appmgr_override.yaml) failed: %v", err)
353 args = args + " -f=/tmp/appmgr_override.yaml"
356 appmgr.Logger.Info("yaml.JSONToYAML failed: %v", err)
360 repoName := viper.GetString("helm.repo-name")
362 repoName = "helm-repo"
364 return fmt.Sprintf("install %s/%s %s", repoName, *x.XappName, args)