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 ==================================================================================
32 "github.com/spf13/viper"
33 "github.com/valyala/fastjson"
34 "github.com/xeipuuv/gojsonschema"
36 "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/appmgr"
37 "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/models"
38 "gerrit.oran-osc.org/r/ric-plt/appmgr/pkg/util"
47 func (cm *CM) UploadConfigAll() (configList models.AllXappConfig) {
48 return cm.UploadConfigElement("")
51 func (cm *CM) UploadConfigElement(Element string) (configList models.AllXappConfig) {
52 namespace := cm.GetNamespace("")
53 for _, name := range cm.GetNamesFromHelmRepo() {
54 var activeConfig interface{}
56 if err := cm.GetConfigmap(xAppName, namespace, &activeConfig); err != nil {
57 appmgr.Logger.Info("No active configMap found for '%s', ignoring ...", xAppName)
62 m := activeConfig.(map[string]interface{})
63 if m[Element] == nil {
64 appmgr.Logger.Info("xApp '%s' doesn't have requested element '%s' in config", name, Element)
67 activeConfig = m[Element]
70 c := models.XAppConfig{
71 Metadata: &models.ConfigMetadata{XappName: &xAppName, Namespace: &namespace},
74 configList = append(configList, &c)
79 func (cm *CM) GetConfigmap(name, namespace string, c *interface{}) (err error) {
80 cmJson, err := cm.ReadConfigmap(name, namespace)
85 return json.Unmarshal([]byte(cmJson), &c)
88 func (cm *CM) ReadSchema(name string, desc *interface{}) (err error) {
89 if err = cm.FetchChart(name); err != nil {
93 tarDir := viper.GetString("xapp.tarDir")
94 err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), desc)
99 if err = os.RemoveAll(path.Join(tarDir, name)); err != nil {
100 appmgr.Logger.Info("RemoveAll failed: %v", err)
106 func (cm *CM) UpdateConfigMap(r models.XAppConfig) (models.ConfigValidationErrors, error) {
107 fmt.Printf("Configmap update: xappName=%s namespace=%s config: %v", *r.Metadata.XappName, *r.Metadata.Namespace, r.Config)
108 if validationErrors, err := cm.Validate(r); err != nil {
109 return validationErrors, err
112 cmContent, err := cm.BuildConfigMap(r)
117 if err := cm.GenerateJSONFile(cmContent); err != nil {
120 err = cm.ReplaceConfigMap(*r.Metadata.XappName, *r.Metadata.Namespace)
125 func (cm *CM) BuildConfigMap(r models.XAppConfig) (string, error) {
126 configJson, err := json.Marshal(r.Config)
128 appmgr.Logger.Info("Config marshalling failed: %v", err)
132 cmContent, err := cm.ReadConfigmap(*r.Metadata.XappName, *r.Metadata.Namespace)
137 v, err := cm.ParseJson(cmContent)
139 v.Set("controls", fastjson.MustParse(string(configJson)))
140 fmt.Println(v.String())
141 return v.String(), nil
147 func (cm *CM) ParseJson(dsContent string) (*fastjson.Value, error) {
148 var p fastjson.Parser
149 v, err := p.Parse(dsContent)
151 appmgr.Logger.Info("fastjson.Parser failed: %v", err)
157 func (cm *CM) GenerateJSONFile(jsonString string) error {
158 cmJson, err := json.RawMessage(jsonString).MarshalJSON()
160 appmgr.Logger.Error("Config marshalling failed: %v", err)
164 err = ioutil.WriteFile(viper.GetString("xapp.tmpConfig"), cmJson, 0644)
166 appmgr.Logger.Error("WriteFile failed: %v", err)
173 func (cm *CM) ReadFile(name string, data interface{}) (err error) {
174 f, err := ioutil.ReadFile(name)
176 appmgr.Logger.Info("Reading '%s' file failed: %v", name, err)
180 err = json.Unmarshal(f, &data)
182 appmgr.Logger.Info("Unmarshalling '%s' file failed: %v", name, err)
189 func (cm *CM) ReadConfigmap(name string, ns string) (string, error) {
190 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns))
191 out, err := util.KubectlExec(args)
192 return string(out), err
195 func (cm *CM) ReplaceConfigMap(name, ns string) (error) {
196 cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl replace -f -"
197 args := fmt.Sprintf(cmd, ns, cm.GetConfigMapName(name, ns), viper.GetString("xapp.tmpConfig"))
198 _, err := util.KubectlExec(args)
202 func (cm *CM) FetchChart(name string) (err error) {
203 tarDir := viper.GetString("xapp.tarDir")
204 repo := viper.GetString("helm.repo-name")
205 fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name)
207 _, err = util.HelmExec(strings.Join([]string{"fetch ", fetchArgs}, ""))
211 func (cm *CM) GetRtmData(name string) (msgs appmgr.RtmData) {
212 appmgr.Logger.Info("Fetching RT data for xApp=%s", name)
214 ns := cm.GetNamespace("")
215 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns))
216 out, err := util.KubectlExec(args)
221 var p fastjson.Parser
222 v, err := p.Parse(string(out))
224 appmgr.Logger.Info("fastjson.Parser for '%s' failed: %v", name, err)
228 for _, m := range v.GetArray("rmr", "txMessages") {
229 msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
232 for _, m := range v.GetArray("rmr", "rxMessages") {
233 msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))
236 for _, m := range v.GetArray("rmr", "policies") {
237 if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil {
238 msgs.Policies = append(msgs.Policies, int64(val))
245 func (cm *CM) GetConfigMapName(xappName, namespace string) string {
246 return " configmap-" + namespace + "-" + xappName + "-appconfig"
249 func (cm *CM) GetNamespace(ns string) string {
254 ns = viper.GetString("xapp.namespace")
261 func (cm *CM) GetNamesFromHelmRepo() (names []string) {
262 rname := viper.GetString("helm.repo-name")
264 cmdArgs := strings.Join([]string{"search ", rname}, "")
265 out, err := util.HelmExec(cmdArgs)
270 re := regexp.MustCompile(rname + `/.*`)
271 result := re.FindAllStringSubmatch(string(out), -1)
274 for _, v := range result {
275 fmt.Sscanf(v[0], "%s", &tmp)
276 names = append(names, strings.Split(tmp, "/")[1])
282 func (cm *CM) Validate(req models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
284 err = cm.ReadSchema(*req.Metadata.XappName, &desc)
286 appmgr.Logger.Info("No schema file found for '%s', aborting ...", *req.Metadata.XappName)
289 return cm.doValidate(desc, req.Config)
292 func (cm *CM) doValidate(schema, cfg interface{}) (errList models.ConfigValidationErrors, err error) {
293 schemaLoader := gojsonschema.NewGoLoader(schema)
294 documentLoader := gojsonschema.NewGoLoader(cfg)
296 result, err := gojsonschema.Validate(schemaLoader, documentLoader)
298 appmgr.Logger.Info("Validation failed: %v", err)
302 if result.Valid() == false {
303 appmgr.Logger.Info("The document is not valid, Errors: %v", result.Errors())
304 for _, desc := range result.Errors() {
305 field := desc.Field()
306 validationError := desc.Description()
307 errList = append(errList, &models.ConfigValidationError{Field: &field, Error: &validationError})
309 return errList, errors.New("Validation failed!")
311 appmgr.Logger.Info("Config validation successful!")