package cm
import (
- "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"
+ "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
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\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
+ 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 := kubeExec(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 := kubeExec(args)
- return err
+ 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 = 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 := 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
+ 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 := 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
+ 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
}