X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=pkg%2Fcm%2Fcm.go;h=0356b197bb21a41580010c30efc585f42b2c5752;hb=bc99f0bbf612db426f0805b0e1f70067b60ddbc7;hp=fb80276a39cd8e2d09d8e90573a227a90dc5070c;hpb=aca8f3cfeaa7e6af5245c2f0370ef517254d62f2;p=ric-plt%2Fappmgr.git diff --git a/pkg/cm/cm.go b/pkg/cm/cm.go index fb80276..0356b19 100755 --- a/pkg/cm/cm.go +++ b/pkg/cm/cm.go @@ -20,295 +20,326 @@ package cm import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "regexp" - "strings" - "strconv" - "github.com/spf13/viper" - "github.com/valyala/fastjson" - "github.com/xeipuuv/gojsonschema" - - "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/appmgr" - "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/models" - "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/util" + "encoding/json" + "errors" + "fmt" + "github.com/spf13/viper" + "github.com/valyala/fastjson" + "github.com/xeipuuv/gojsonschema" + "io/ioutil" + "os" + "path" + "regexp" + "strconv" + "strings" + + "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr" + "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 CM struct{} +const HELM_VERSION_3 = "3" +const HELM_VERSION_2 = "2" +var EnvHelmVersion string = "" + + func NewCM() *CM { - return &CM{} + return &CM{} } func (cm *CM) UploadConfigAll() (configList models.AllXappConfig) { - return cm.UploadConfigElement("") + return cm.UploadConfigElement("") } func (cm *CM) UploadConfigElement(Element string) (configList models.AllXappConfig) { - namespace := cm.GetNamespace("") - for _, name := range cm.GetNamesFromHelmRepo() { - var activeConfig interface{} - xAppName := name - if err := cm.GetConfigmap(xAppName, namespace, &activeConfig); err != nil { - appmgr.Logger.Info("No active configMap found for '%s', ignoring ...", xAppName) - continue - } - - if Element != "" { - m := activeConfig.(map[string]interface{}) - if m[Element] == nil { - appmgr.Logger.Info("xApp '%s' doesn't have requested element '%s' in config", name, Element) - continue - } - activeConfig = m[Element] - } - - c := models.XAppConfig{ - Metadata: &models.ConfigMetadata{XappName: &xAppName, Namespace: &namespace}, - Config: activeConfig, - } - configList = append(configList, &c) - } - return + namespace := cm.GetNamespace("") + for _, name := range cm.GetNamesFromHelmRepo() { + var activeConfig interface{} + xAppName := name + if err := cm.GetConfigmap(xAppName, namespace, &activeConfig); err != nil { + appmgr.Logger.Info("No active configMap found for '%s', ignoring ...", xAppName) + continue + } + + if Element != "" { + m := activeConfig.(map[string]interface{}) + if m[Element] == nil { + appmgr.Logger.Info("xApp '%s' doesn't have requested element '%s' in config", name, Element) + continue + } + activeConfig = m[Element] + } + + c := models.XAppConfig{ + Metadata: &models.ConfigMetadata{XappName: &xAppName, Namespace: &namespace}, + Config: activeConfig, + } + configList = append(configList, &c) + } + return } func (cm *CM) GetConfigmap(name, namespace string, c *interface{}) (err error) { - cmJson, err := cm.ReadConfigmap(name, namespace) - if err != nil { - return err - } + cmJson, err := cm.ReadConfigmap(name, namespace) + if err != nil { + return err + } - return json.Unmarshal([]byte(cmJson), &c) + return json.Unmarshal([]byte(cmJson), &c) } func (cm *CM) ReadSchema(name string, desc *interface{}) (err error) { - if err = cm.FetchChart(name); err != nil { - return - } + if err = cm.FetchChart(name); err != nil { + return + } - tarDir := viper.GetString("xapp.tarDir") - err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), desc) - if err != nil { - return - } + tarDir := viper.GetString("xapp.tarDir") + err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), desc) + if err != nil { + return + } - if err = os.RemoveAll(path.Join(tarDir, name)); err != nil { - appmgr.Logger.Info("RemoveAll failed: %v", err) - } + if err = os.RemoveAll(path.Join(tarDir, name)); err != nil { + appmgr.Logger.Info("RemoveAll failed: %v", err) + } - return + return } func (cm *CM) UpdateConfigMap(r models.XAppConfig) (models.ConfigValidationErrors, error) { - fmt.Printf("Configmap update: xappName=%s namespace=%s config: %v", *r.Metadata.XappName, *r.Metadata.Namespace, r.Config) - if validationErrors, err := cm.Validate(r); err != nil { - return validationErrors, err - } - - cmContent, err := cm.BuildConfigMap(r) - if err != nil { - return nil, err - } - - if err := cm.GenerateJSONFile(cmContent); err != nil { - return nil, err - } - err = cm.ReplaceConfigMap(*r.Metadata.XappName, *r.Metadata.Namespace) - - return nil, err + fmt.Printf("Configmap update: xappName=%s namespace=%s config: %v\n", *r.Metadata.XappName, *r.Metadata.Namespace, r.Config) + if validationErrors, err := cm.Validate(r); err != nil { + return validationErrors, err + } + + cmContent, err := cm.BuildConfigMap(r) + if err != nil { + return nil, err + } + + if err := cm.GenerateJSONFile(cmContent); err != nil { + return nil, err + } + err = cm.ReplaceConfigMap(*r.Metadata.XappName, *r.Metadata.Namespace) + + return nil, err } func (cm *CM) BuildConfigMap(r models.XAppConfig) (string, error) { - configJson, err := json.Marshal(r.Config) - if err != nil { - appmgr.Logger.Info("Config marshalling failed: %v", err) - return "", err - } - - cmContent, err := cm.ReadConfigmap(*r.Metadata.XappName, *r.Metadata.Namespace) - if err != nil { - return "", err - } - - v, err := cm.ParseJson(cmContent) - if err == nil { - v.Set("controls", fastjson.MustParse(string(configJson))) - fmt.Println(v.String()) - return v.String(), nil - } - - return "", err + configJson, err := json.Marshal(r.Config) + if err != nil { + appmgr.Logger.Info("Config marshalling failed: %v", err) + return "", err + } + + cmContent, err := cm.ReadConfigmap(*r.Metadata.XappName, *r.Metadata.Namespace) + if err != nil { + return "", err + } + + v, err := cm.ParseJson(cmContent) + if err == nil { + v.Set("controls", fastjson.MustParse(string(configJson))) + fmt.Println(v.String()) + return v.String(), nil + } + + return "", err } func (cm *CM) ParseJson(dsContent string) (*fastjson.Value, error) { - var p fastjson.Parser - v, err := p.Parse(dsContent) - if err != nil { - appmgr.Logger.Info("fastjson.Parser failed: %v", err) - } - return v, err + var p fastjson.Parser + v, err := p.Parse(dsContent) + if err != nil { + appmgr.Logger.Info("fastjson.Parser failed: %v", err) + } + return v, err } - func (cm *CM) GenerateJSONFile(jsonString string) error { - cmJson, err := json.RawMessage(jsonString).MarshalJSON() - if err != nil { - appmgr.Logger.Error("Config marshalling failed: %v", err) - return err - } - - err = ioutil.WriteFile(viper.GetString("xapp.tmpConfig"), cmJson, 0644) - if err != nil { - appmgr.Logger.Error("WriteFile failed: %v", err) - return err - } - - return nil + cmJson, err := json.RawMessage(jsonString).MarshalJSON() + if err != nil { + appmgr.Logger.Error("Config marshalling failed: %v", err) + return err + } + + err = ioutil.WriteFile(viper.GetString("xapp.tmpConfig"), cmJson, 0644) + if err != nil { + appmgr.Logger.Error("WriteFile failed: %v", err) + return err + } + + return nil } func (cm *CM) ReadFile(name string, data interface{}) (err error) { - f, err := ioutil.ReadFile(name) - if err != nil { - appmgr.Logger.Info("Reading '%s' file failed: %v", name, err) - return - } - - err = json.Unmarshal(f, &data) - if err != nil { - appmgr.Logger.Info("Unmarshalling '%s' file failed: %v", name, err) - return - } - - return + f, err := ioutil.ReadFile(name) + if err != nil { + appmgr.Logger.Info("Reading '%s' file failed: %v", name, err) + return + } + + err = json.Unmarshal(f, &data) + if err != nil { + appmgr.Logger.Info("Unmarshalling '%s' file failed: %v", name, err) + return + } + + return } func (cm *CM) ReadConfigmap(name string, ns string) (string, error) { - args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns)) - out, err := util.KubectlExec(args) - return string(out), err + args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns)) + out, err := kubeExec(args) + return string(out), err } -func (cm *CM) ReplaceConfigMap(name, ns string) (error) { - cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl replace -f -" - args := fmt.Sprintf(cmd, ns, cm.GetConfigMapName(name, ns), viper.GetString("xapp.tmpConfig")) - _, err := util.KubectlExec(args) - return err +func (cm *CM) ReplaceConfigMap(name, ns string) error { + cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl replace -f -" + args := fmt.Sprintf(cmd, ns, cm.GetConfigMapName(name, ns), viper.GetString("xapp.tmpConfig")) + _, err := kubeExec(args) + return err } func (cm *CM) FetchChart(name string) (err error) { - tarDir := viper.GetString("xapp.tarDir") - repo := viper.GetString("helm.repo-name") - fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name) + tarDir := viper.GetString("xapp.tarDir") + repo := viper.GetString("helm.repo-name") + fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name) - _, err = util.HelmExec(strings.Join([]string{"fetch ", fetchArgs}, "")) - return + _, err = helmExec(strings.Join([]string{"fetch ", fetchArgs}, "")) + return } func (cm *CM) GetRtmData(name string) (msgs appmgr.RtmData) { - appmgr.Logger.Info("Fetching RT data for xApp=%s", name) - - ns := cm.GetNamespace("") - args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns)) - out, err := util.KubectlExec(args) - if err != nil { - return - } - - var p fastjson.Parser - v, err := p.Parse(string(out)) - if err != nil { - appmgr.Logger.Info("fastjson.Parser for '%s' failed: %v", name, err) - return - } - - for _, m := range v.GetArray("rmr", "txMessages") { - msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`)) - } - - for _, m := range v.GetArray("rmr", "rxMessages") { - msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`)) - } - - for _, m := range v.GetArray("rmr", "policies") { - if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil { - msgs.Policies = append(msgs.Policies, int64(val)) - } - } - - return + appmgr.Logger.Info("Fetching RT data for xApp=%s", name) + + ns := cm.GetNamespace("") + args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns)) + out, err := kubeExec(args) + if err != nil { + return + } + + var p fastjson.Parser + v, err := p.Parse(string(out)) + if err != nil { + appmgr.Logger.Info("fastjson.Parser for '%s' failed: %v", name, err) + return + } + + if v.Exists("rmr") { + for _, m := range v.GetArray("rmr", "txMessages") { + msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`)) + } + + for _, m := range v.GetArray("rmr", "rxMessages") { + msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`)) + } + + for _, m := range v.GetArray("rmr", "policies") { + if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil { + msgs.Policies = append(msgs.Policies, int64(val)) + } + } + } else { + for _, p := range v.GetArray("messaging", "ports") { + appmgr.Logger.Info("txMessages=%v, rxMessages=%v", p.GetArray("txMessages"), p.GetArray("rxMessages")) + for _, m := range p.GetArray("txMessages") { + msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`)) + } + + for _, m := range p.GetArray("rxMessages") { + msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`)) + } + + for _, m := range p.GetArray("policies") { + if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil { + msgs.Policies = append(msgs.Policies, int64(val)) + } + } + } + } + return } func (cm *CM) GetConfigMapName(xappName, namespace string) string { - return " configmap-" + namespace + "-" + xappName + "-appconfig" + return " configmap-" + namespace + "-" + xappName + "-appconfig" } func (cm *CM) GetNamespace(ns string) string { - if ns != "" { - return ns - } - - ns = viper.GetString("xapp.namespace") - if ns == "" { - ns = "ricxapp" - } - return ns + if ns != "" { + return ns + } + + ns = viper.GetString("xapp.namespace") + if ns == "" { + ns = "ricxapp" + } + return ns } func (cm *CM) GetNamesFromHelmRepo() (names []string) { - rname := viper.GetString("helm.repo-name") - - cmdArgs := strings.Join([]string{"search ", rname}, "") - out, err := util.HelmExec(cmdArgs) - if err != nil { - return - } - - re := regexp.MustCompile(rname + `/.*`) - result := re.FindAllStringSubmatch(string(out), -1) - if result != nil { - var tmp string - for _, v := range result { - fmt.Sscanf(v[0], "%s", &tmp) - names = append(names, strings.Split(tmp, "/")[1]) - } - } - return names + rname := viper.GetString("helm.repo-name") + + var cmdArgs string = "" + if EnvHelmVersion == HELM_VERSION_3 { + cmdArgs = strings.Join([]string{"search repo ", rname}, "") + }else { + cmdArgs = strings.Join([]string{"search ", rname}, "") + } + + out, err := helmExec(cmdArgs) + if err != nil { + return + } + + re := regexp.MustCompile(rname + `/.*`) + result := re.FindAllStringSubmatch(string(out), -1) + if result != nil { + var tmp string + for _, v := range result { + fmt.Sscanf(v[0], "%s", &tmp) + names = append(names, strings.Split(tmp, "/")[1]) + } + } + return names } func (cm *CM) Validate(req models.XAppConfig) (errList models.ConfigValidationErrors, err error) { - var desc interface{} - err = cm.ReadSchema(*req.Metadata.XappName, &desc) - if err != nil { - appmgr.Logger.Info("No schema file found for '%s', aborting ...", *req.Metadata.XappName) - return - } - return cm.doValidate(desc, req.Config) + var desc interface{} + err = cm.ReadSchema(*req.Metadata.XappName, &desc) + if err != nil { + appmgr.Logger.Info("No schema file found for '%s', aborting ...", *req.Metadata.XappName) + return + } + return cm.doValidate(desc, req.Config) } func (cm *CM) doValidate(schema, cfg interface{}) (errList models.ConfigValidationErrors, err error) { - schemaLoader := gojsonschema.NewGoLoader(schema) - documentLoader := gojsonschema.NewGoLoader(cfg) - - result, err := gojsonschema.Validate(schemaLoader, documentLoader) - if err != nil { - appmgr.Logger.Info("Validation failed: %v", err) - return - } - - if result.Valid() == false { - appmgr.Logger.Info("The document is not valid, Errors: %v", result.Errors()) - for _, desc := range result.Errors() { - field := desc.Field() - validationError := desc.Description() - errList = append(errList, &models.ConfigValidationError{Field: &field, Error: &validationError}) - } - return errList, errors.New("Validation failed!") - } - appmgr.Logger.Info("Config validation successful!") - - return -} \ No newline at end of file + schemaLoader := gojsonschema.NewGoLoader(schema) + documentLoader := gojsonschema.NewGoLoader(cfg) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + if err != nil { + appmgr.Logger.Info("Validation failed: %v", err) + return + } + + if result.Valid() == false { + appmgr.Logger.Info("The document is not valid, Errors: %v", result.Errors()) + for _, desc := range result.Errors() { + field := desc.Field() + validationError := desc.Description() + errList = append(errList, &models.ConfigValidationError{Field: &field, Error: &validationError}) + } + return errList, errors.New("Validation failed!") + } + appmgr.Logger.Info("Config validation successful!") + + return +}