X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=pkg%2Fcm%2Fcm.go;h=fb80276a39cd8e2d09d8e90573a227a90dc5070c;hb=aca8f3cfeaa7e6af5245c2f0370ef517254d62f2;hp=a073c0a5d130daea0685d4909136e893b5ecd2d2;hpb=e8b05b6a0f6fa82ddb2a4e9c9a90629b7528a809;p=ric-plt%2Fappmgr.git diff --git a/pkg/cm/cm.go b/pkg/cm/cm.go index a073c0a..fb80276 100755 --- a/pkg/cm/cm.go +++ b/pkg/cm/cm.go @@ -23,16 +23,15 @@ import ( "encoding/json" "errors" "fmt" - "github.com/spf13/viper" - "github.com/valyala/fastjson" - "github.com/xeipuuv/gojsonschema" "io/ioutil" "os" "path" "regexp" "strings" "strconv" - "time" + "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" @@ -45,44 +44,54 @@ func NewCM() *CM { return &CM{} } -func (cm *CM) UploadConfig() (cfg models.AllXappConfig) { - ns := cm.GetNamespace("") +func (cm *CM) UploadConfigAll() (configList models.AllXappConfig) { + return cm.UploadConfigElement("") +} + +func (cm *CM) UploadConfigElement(Element string) (configList models.AllXappConfig) { + namespace := cm.GetNamespace("") for _, name := range cm.GetNamesFromHelmRepo() { - if name == "appmgr" { + 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 } - c := models.XAppConfig{ - Metadata: &models.ConfigMetadata{Name: &name, Namespace: ns, ConfigName: cm.GetConfigMapName(name, ns)}, - } - - err := cm.ReadSchema(name, &c) - if err != nil { - 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] } - err = cm.ReadConfigMap(c.Metadata.ConfigName, ns, &c.Config) - if err != nil { - appmgr.Logger.Info("No active configMap found, using default!") + c := models.XAppConfig{ + Metadata: &models.ConfigMetadata{XappName: &xAppName, Namespace: &namespace}, + Config: activeConfig, } - - cfg = append(cfg, &c) + configList = append(configList, &c) } return } -func (cm *CM) ReadSchema(name string, c *models.XAppConfig) (err error) { - if err = cm.FetchChart(name); err != nil { - return +func (cm *CM) GetConfigmap(name, namespace string, c *interface{}) (err error) { + cmJson, err := cm.ReadConfigmap(name, namespace) + if err != nil { + return err } - tarDir := viper.GetString("xapp.tarDir") - err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), &c.Descriptor) - if err != nil { + return json.Unmarshal([]byte(cmJson), &c) +} + +func (cm *CM) ReadSchema(name string, desc *interface{}) (err error) { + if err = cm.FetchChart(name); err != nil { return } - err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.config")), &c.Config) + tarDir := viper.GetString("xapp.tarDir") + err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), desc) if err != nil { return } @@ -94,148 +103,71 @@ func (cm *CM) ReadSchema(name string, c *models.XAppConfig) (err error) { return } -func (cm *CM) ReadConfigMap(ConfigName string, ns string, c *interface{}) (err error) { - args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, ConfigName) - configMapJson, err := util.KubectlExec(args) - if err != nil { - 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 } - err = json.Unmarshal([]byte(configMapJson), &c) + cmContent, err := cm.BuildConfigMap(r) if err != nil { - return + return nil, err } - return -} - -func (cm *CM) ApplyConfigMap(r models.XAppConfig, action string) (err error) { - c := appmgr.ConfigMap{ - Kind: "ConfigMap", - ApiVersion: "v1", - Metadata: appmgr.CMMetadata{Name: *r.Metadata.Name, Namespace: r.Metadata.Namespace}, - Data: r.Config, + if err := cm.GenerateJSONFile(cmContent); err != nil { + return nil, err } + err = cm.ReplaceConfigMap(*r.Metadata.XappName, *r.Metadata.Namespace) - cmJson, err := json.Marshal(c.Data) - if err != nil { - appmgr.Logger.Info("Config marshalling failed: %v", err) - return - } + return nil, err +} - cmFile := viper.GetString("xapp.tmpConfig") - err = ioutil.WriteFile(cmFile, cmJson, 0644) +func (cm *CM) BuildConfigMap(r models.XAppConfig) (string, error) { + configJson, err := json.Marshal(r.Config) if err != nil { - appmgr.Logger.Info("WriteFile failed: %v", err) - return + appmgr.Logger.Info("Config marshalling failed: %v", err) + return "", err } - cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl %s -f -" - args := fmt.Sprintf(cmd, r.Metadata.Namespace, r.Metadata.ConfigName, cmFile, action) - _, err = util.KubectlExec(args) + cmContent, err := cm.ReadConfigmap(*r.Metadata.XappName, *r.Metadata.Namespace) if err != nil { - return - } - appmgr.Logger.Info("Configmap changes done!") - - return -} - -func (cm *CM) GetConfigMap(m models.XappDescriptor, c *interface{}) (err error) { - return cm.ReadConfigMap(cm.GetConfigMapName(*m.XappName, m.Namespace), m.Namespace, c) -} - -func (cm *CM) CreateConfigMap(r models.XAppConfig) (errList models.ConfigValidationErrors, err error) { - if errList, err = cm.Validate(r); err != nil { - return - } - err = cm.ApplyConfigMap(r, "create") - return -} - -func (cm *CM) UpdateConfigMap(r models.XAppConfig) (errList models.ConfigValidationErrors, err error) { - if errList, err = cm.Validate(r); err != nil { - return + return "", err } - // Re-create the configmap with the new parameters - err = cm.ApplyConfigMap(r, "apply") - return -} - -func (cm *CM) DeleteConfigMap(r models.ConfigMetadata) (c interface{}, err error) { - err = cm.ReadConfigMap(r.ConfigName, r.Namespace, &c) + v, err := cm.ParseJson(cmContent) if err == nil { - args := fmt.Sprintf(" delete configmap --namespace=%s %s", r.Namespace, r.ConfigName) - _, err = util.KubectlExec(args) + v.Set("controls", fastjson.MustParse(string(configJson))) + fmt.Println(v.String()) + return v.String(), nil } - return -} - -func (cm *CM) PurgeConfigMap(m models.XappDescriptor) (c interface{}, err error) { - md := models.ConfigMetadata{Name: m.XappName, Namespace: m.Namespace, ConfigName: cm.GetConfigMapName(*m.XappName, m.Namespace)} - return cm.DeleteConfigMap(md) + return "", err } -func (cm *CM) RestoreConfigMap(m models.XappDescriptor, c interface{}) (err error) { - md := &models.ConfigMetadata{Name: m.XappName, Namespace: m.Namespace, ConfigName: cm.GetConfigMapName(*m.XappName, m.Namespace)} - time.Sleep(time.Duration(10 * time.Second)) - - return cm.ApplyConfigMap(models.XAppConfig{Metadata: md, Config: c}, "create") -} - -func (cm *CM) GetNamesFromHelmRepo() (names []string) { - rname := viper.GetString("helm.repo-name") - - cmdArgs := strings.Join([]string{"search ", rname}, "") - out, err := util.HelmExec(cmdArgs) +func (cm *CM) ParseJson(dsContent string) (*fastjson.Value, error) { + var p fastjson.Parser + v, err := p.Parse(dsContent) if err != nil { - return + appmgr.Logger.Info("fastjson.Parser failed: %v", err) } - - 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 + return v, err } -func (cm *CM) Validate(req models.XAppConfig) (errList models.ConfigValidationErrors, err error) { - c := models.XAppConfig{} - err = cm.ReadSchema(*req.Metadata.Name, &c) + +func (cm *CM) GenerateJSONFile(jsonString string) error { + cmJson, err := json.RawMessage(jsonString).MarshalJSON() if err != nil { - appmgr.Logger.Info("No schema file found for '%s', aborting ...", *req.Metadata.Name) - return + appmgr.Logger.Error("Config marshalling failed: %v", err) + return err } - return cm.doValidate(c.Descriptor, 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) + err = ioutil.WriteFile(viper.GetString("xapp.tmpConfig"), cmJson, 0644) if err != nil { - appmgr.Logger.Info("Validation failed: %v", err) - return + appmgr.Logger.Error("WriteFile failed: %v", err) + return err } - 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!") - } - return + return nil } func (cm *CM) ReadFile(name string, data interface{}) (err error) { @@ -254,6 +186,19 @@ func (cm *CM) ReadFile(name string, data interface{}) (err error) { 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 +} + +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) FetchChart(name string) (err error) { tarDir := viper.GetString("xapp.tarDir") repo := viper.GetString("helm.repo-name") @@ -283,9 +228,11 @@ func (cm *CM) GetRtmData(name string) (msgs appmgr.RtmData) { 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)) @@ -310,3 +257,58 @@ func (cm *CM) GetNamespace(ns string) string { } 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 +} + +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) +} + +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