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 ==================================================================================
26 "github.com/spf13/viper"
27 "github.com/valyala/fastjson"
28 "github.com/xeipuuv/gojsonschema"
36 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/appmgr"
37 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/models"
38 "gerrit.o-ran-sc.org/r/ric-plt/appmgr/pkg/util"
41 var kubeExec = util.KubectlExec
42 var helmExec = util.HelmExec
50 func (cm *CM) UploadConfigAll() (configList models.AllXappConfig) {
51 return cm.UploadConfigElement("")
54 func (cm *CM) UploadConfigElement(Element string) (configList models.AllXappConfig) {
55 namespace := cm.GetNamespace("")
56 for _, name := range cm.GetNamesFromHelmRepo() {
57 var activeConfig interface{}
59 if err := cm.GetConfigmap(xAppName, namespace, &activeConfig); err != nil {
60 appmgr.Logger.Info("No active configMap found for '%s', ignoring ...", xAppName)
65 m := activeConfig.(map[string]interface{})
66 if m[Element] == nil {
67 appmgr.Logger.Info("xApp '%s' doesn't have requested element '%s' in config", name, Element)
70 activeConfig = m[Element]
73 c := models.XAppConfig{
74 Metadata: &models.ConfigMetadata{XappName: &xAppName, Namespace: &namespace},
77 configList = append(configList, &c)
82 func (cm *CM) GetConfigmap(name, namespace string, c *interface{}) (err error) {
83 cmJson, err := cm.ReadConfigmap(name, namespace)
88 return json.Unmarshal([]byte(cmJson), &c)
91 func (cm *CM) ReadSchema(name string, desc *interface{}) (err error) {
92 if err = cm.FetchChart(name); err != nil {
96 tarDir := viper.GetString("xapp.tarDir")
97 err = cm.ReadFile(path.Join(tarDir, name, viper.GetString("xapp.schema")), desc)
102 if err = os.RemoveAll(path.Join(tarDir, name)); err != nil {
103 appmgr.Logger.Info("RemoveAll failed: %v", err)
109 func (cm *CM) UpdateConfigMap(r models.XAppConfig) (models.ConfigValidationErrors, error) {
110 fmt.Printf("Configmap update: xappName=%s namespace=%s config: %v\n", *r.Metadata.XappName, *r.Metadata.Namespace, r.Config)
111 if validationErrors, err := cm.Validate(r); err != nil {
112 return validationErrors, err
115 cmContent, err := cm.BuildConfigMap(r)
120 if err := cm.GenerateJSONFile(cmContent); err != nil {
123 err = cm.ReplaceConfigMap(*r.Metadata.XappName, *r.Metadata.Namespace)
128 func (cm *CM) BuildConfigMap(r models.XAppConfig) (string, error) {
129 configJson, err := json.Marshal(r.Config)
131 appmgr.Logger.Info("Config marshalling failed: %v", err)
135 cmContent, err := cm.ReadConfigmap(*r.Metadata.XappName, *r.Metadata.Namespace)
140 v, err := cm.ParseJson(cmContent)
142 v.Set("controls", fastjson.MustParse(string(configJson)))
143 fmt.Println(v.String())
144 return v.String(), nil
150 func (cm *CM) ParseJson(dsContent string) (*fastjson.Value, error) {
151 var p fastjson.Parser
152 v, err := p.Parse(dsContent)
154 appmgr.Logger.Info("fastjson.Parser failed: %v", err)
159 func (cm *CM) GenerateJSONFile(jsonString string) error {
160 cmJson, err := json.RawMessage(jsonString).MarshalJSON()
162 appmgr.Logger.Error("Config marshalling failed: %v", err)
166 err = ioutil.WriteFile(viper.GetString("xapp.tmpConfig"), cmJson, 0644)
168 appmgr.Logger.Error("WriteFile failed: %v", err)
175 func (cm *CM) ReadFile(name string, data interface{}) (err error) {
176 f, err := ioutil.ReadFile(name)
178 appmgr.Logger.Info("Reading '%s' file failed: %v", name, err)
182 err = json.Unmarshal(f, &data)
184 appmgr.Logger.Info("Unmarshalling '%s' file failed: %v", name, err)
191 func (cm *CM) ReadConfigmap(name string, ns string) (string, error) {
192 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns))
193 out, err := kubeExec(args)
194 return string(out), err
197 func (cm *CM) ReplaceConfigMap(name, ns string) error {
198 cmd := " create configmap -n %s %s --from-file=%s -o json --dry-run | kubectl replace -f -"
199 args := fmt.Sprintf(cmd, ns, cm.GetConfigMapName(name, ns), viper.GetString("xapp.tmpConfig"))
200 _, err := kubeExec(args)
204 func (cm *CM) FetchChart(name string) (err error) {
205 tarDir := viper.GetString("xapp.tarDir")
206 repo := viper.GetString("helm.repo-name")
207 fetchArgs := fmt.Sprintf("--untar --untardir %s %s/%s", tarDir, repo, name)
209 _, err = helmExec(strings.Join([]string{"fetch ", fetchArgs}, ""))
213 func (cm *CM) GetRtmData(name string) (msgs appmgr.RtmData) {
214 appmgr.Logger.Info("Fetching RT data for xApp=%s", name)
216 ns := cm.GetNamespace("")
217 args := fmt.Sprintf("get configmap -o jsonpath='{.data.config-file\\.json}' -n %s %s", ns, cm.GetConfigMapName(name, ns))
218 out, err := kubeExec(args)
223 var p fastjson.Parser
224 v, err := p.Parse(string(out))
226 appmgr.Logger.Info("fastjson.Parser for '%s' failed: %v", name, err)
231 for _, m := range v.GetArray("rmr", "txMessages") {
232 msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
235 for _, m := range v.GetArray("rmr", "rxMessages") {
236 msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))
239 for _, m := range v.GetArray("rmr", "policies") {
240 if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil {
241 msgs.Policies = append(msgs.Policies, int64(val))
245 for _, p := range v.GetArray("messaging", "ports") {
246 appmgr.Logger.Info("txMessages=%v, rxMessages=%v", p.GetArray("txMessages"), p.GetArray("rxMessages"))
247 for _, m := range p.GetArray("txMessages") {
248 msgs.TxMessages = append(msgs.TxMessages, strings.Trim(m.String(), `"`))
251 for _, m := range p.GetArray("rxMessages") {
252 msgs.RxMessages = append(msgs.RxMessages, strings.Trim(m.String(), `"`))
255 for _, m := range p.GetArray("policies") {
256 if val, err := strconv.Atoi(strings.Trim(m.String(), `"`)); err == nil {
257 msgs.Policies = append(msgs.Policies, int64(val))
265 func (cm *CM) GetConfigMapName(xappName, namespace string) string {
266 return " configmap-" + namespace + "-" + xappName + "-appconfig"
269 func (cm *CM) GetNamespace(ns string) string {
274 ns = viper.GetString("xapp.namespace")
281 func (cm *CM) GetNamesFromHelmRepo() (names []string) {
282 rname := viper.GetString("helm.repo-name")
284 cmdArgs := strings.Join([]string{"search ", rname}, "")
285 out, err := helmExec(cmdArgs)
290 re := regexp.MustCompile(rname + `/.*`)
291 result := re.FindAllStringSubmatch(string(out), -1)
294 for _, v := range result {
295 fmt.Sscanf(v[0], "%s", &tmp)
296 names = append(names, strings.Split(tmp, "/")[1])
302 func (cm *CM) Validate(req models.XAppConfig) (errList models.ConfigValidationErrors, err error) {
304 err = cm.ReadSchema(*req.Metadata.XappName, &desc)
306 appmgr.Logger.Info("No schema file found for '%s', aborting ...", *req.Metadata.XappName)
309 return cm.doValidate(desc, req.Config)
312 func (cm *CM) doValidate(schema, cfg interface{}) (errList models.ConfigValidationErrors, err error) {
313 schemaLoader := gojsonschema.NewGoLoader(schema)
314 documentLoader := gojsonschema.NewGoLoader(cfg)
316 result, err := gojsonschema.Validate(schemaLoader, documentLoader)
318 appmgr.Logger.Info("Validation failed: %v", err)
322 if result.Valid() == false {
323 appmgr.Logger.Info("The document is not valid, Errors: %v", result.Errors())
324 for _, desc := range result.Errors() {
325 field := desc.Field()
326 validationError := desc.Description()
327 errList = append(errList, &models.ConfigValidationError{Field: &field, Error: &validationError})
329 return errList, errors.New("Validation failed!")
331 appmgr.Logger.Info("Config validation successful!")