A1 to send policy instance data via RMR
[ric-plt/a1.git] / a1-go / pkg / resthooks / resthooks.go
1 /*
2 ==================================================================================
3   Copyright (c) 2021 Samsung
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17    This source code is part of the near-RT RIC (RAN Intelligent Controller)
18    platform project (RICP).
19 ==================================================================================
20 */
21 package resthooks
22
23 import (
24         "encoding/json"
25         "errors"
26         "fmt"
27         "strconv"
28         "strings"
29         "time"
30
31         "gerrit.o-ran-sc.org/r/ric-plt/a1/pkg/a1"
32         "gerrit.o-ran-sc.org/r/ric-plt/a1/pkg/models"
33         "gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
34         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
35         "github.com/santhosh-tekuri/jsonschema/v5"
36         "gopkg.in/yaml.v2"
37 )
38
39 const (
40         a1PolicyPrefix           = "a1.policy_type."
41         a1MediatorNs             = "A1m_ns"
42         a1InstancePrefix         = "a1.policy_instance."
43         a1InstanceMetadataPrefix = "a1.policy_inst_metadata."
44         a1HandlerPrefix          = "a1.policy_handler."
45 )
46
47 var typeAlreadyError = errors.New("Policy Type already exists")
48 var InstanceAlreadyError = errors.New("Policy Instance already exists")
49 var typeMismatchError = errors.New("Policytype Mismatch")
50 var invalidJsonSchema = errors.New("Invalid Json ")
51 var policyInstanceNotFoundError = errors.New("Policy Instance Not Found")
52 var policyTypeNotFoundError = errors.New("Policy Type Not Found")
53
54 func (rh *Resthook) IsPolicyTypePresent(err error) bool {
55         return err == policyTypeNotFoundError
56 }
57
58 func (rh *Resthook) IsPolicyInstanceNotFound(err error) bool {
59         return err == policyInstanceNotFoundError
60 }
61
62 func (rh *Resthook) IsTypeAlready(err error) bool {
63         return err == typeAlreadyError
64 }
65 func (rh *Resthook) IsInstanceAlready(err error) bool {
66         return err == InstanceAlreadyError
67 }
68 func (rh *Resthook) IsTypeMismatch(err error) bool {
69         return err == typeMismatchError
70 }
71
72 func (rh *Resthook) IsValidJson(err error) bool {
73         return err == invalidJsonSchema
74 }
75 func NewResthook() *Resthook {
76         return createResthook(sdlgo.NewSyncStorage(), rmr.NewRMRSender())
77 }
78
79 func createResthook(sdlInst iSdl, rmrSenderInst rmr.IRmrSender) *Resthook {
80         return &Resthook{
81                 db:             sdlInst,
82                 iRmrSenderInst: rmrSenderInst,
83         }
84 }
85
86 func (rh *Resthook) GetAllPolicyType() []models.PolicyTypeID {
87
88         var policyTypeIDs []models.PolicyTypeID
89
90         keys, err := rh.db.GetAll("A1m_ns")
91
92         if err != nil {
93                 a1.Logger.Error("error in retrieving policy. err: %v", err)
94                 return policyTypeIDs
95         }
96         a1.Logger.Debug("keys : %+v", keys)
97
98         for _, key := range keys {
99                 if strings.HasPrefix(strings.TrimLeft(key, " "), a1PolicyPrefix) {
100                         pti := strings.Split(strings.Trim(key, " "), a1PolicyPrefix)[1]
101                         ptii, _ := strconv.ParseInt(pti, 10, 64)
102                         policyTypeIDs = append(policyTypeIDs, models.PolicyTypeID(ptii))
103                 }
104         }
105
106         a1.Logger.Debug("return : %+v", policyTypeIDs)
107         return policyTypeIDs
108 }
109
110 func (rh *Resthook) GetPolicyType(policyTypeId models.PolicyTypeID) *models.PolicyTypeSchema {
111         a1.Logger.Debug("GetPolicyType1")
112
113         var policytypeschema *models.PolicyTypeSchema
114         var keys [1]string
115
116         key := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
117         keys[0] = key
118
119         a1.Logger.Debug("key : %+v", key)
120
121         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
122
123         a1.Logger.Debug("policytype map : %+v", valmap)
124
125         if len(valmap) == 0 {
126                 a1.Logger.Error("policy type Not Present for policyid : %v", policyTypeId)
127                 return policytypeschema
128         }
129
130         if err != nil {
131                 a1.Logger.Error("error in retrieving policy type. err: %v", err)
132                 return nil
133         }
134
135         if valmap[key] == nil {
136                 a1.Logger.Error("policy type Not Present for policyid : %v", policyTypeId)
137                 return policytypeschema
138         }
139
140         a1.Logger.Debug("keysmap : %+v", valmap[key])
141
142         var item models.PolicyTypeSchema
143         valStr := fmt.Sprint(valmap[key])
144
145         a1.Logger.Debug("Policy type for %+v :  %+v", key, valStr)
146         valkey := "`" + valStr + "`"
147         valToUnmarshall, err := strconv.Unquote(valkey)
148         if err != nil {
149                 a1.Logger.Error("unquote error : %+v", err)
150                 return nil
151         }
152
153         a1.Logger.Debug("Policy type for %+v :  %+v", key, string(valToUnmarshall))
154
155         errunm := json.Unmarshal([]byte(valToUnmarshall), &item)
156
157         a1.Logger.Debug(" Unmarshalled json : %+v", (errunm))
158         a1.Logger.Debug("Policy type Name :  %v", (item.Name))
159
160         return &item
161 }
162
163 func (rh *Resthook) CreatePolicyType(policyTypeId models.PolicyTypeID, httprequest models.PolicyTypeSchema) error {
164         a1.Logger.Debug("CreatePolicyType function")
165         if policyTypeId != models.PolicyTypeID(*httprequest.PolicyTypeID) {
166                 //error message
167                 a1.Logger.Debug("Policytype Mismatch")
168                 return typeMismatchError
169         }
170         key := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
171         a1.Logger.Debug("key %+v ", key)
172         if data, err := httprequest.MarshalBinary(); err == nil {
173                 a1.Logger.Debug("Marshaled String : %+v", string(data))
174                 success, err1 := rh.db.SetIfNotExists(a1MediatorNs, key, string(data))
175                 a1.Logger.Info("success:%+v", success)
176                 if err1 != nil {
177                         a1.Logger.Error("error :%+v", err1)
178                         return err1
179                 }
180                 if !success {
181                         a1.Logger.Debug("Policy type %+v already exist", policyTypeId)
182                         return typeAlreadyError
183                 }
184         }
185         return nil
186 }
187
188 func toStringKeys(val interface{}) (interface{}, error) {
189         var err error
190         switch val := val.(type) {
191         case map[interface{}]interface{}:
192                 m := make(map[string]interface{})
193                 for k, v := range val {
194                         k, ok := k.(string)
195                         if !ok {
196                                 return nil, errors.New("found non-string key")
197                         }
198                         m[k], err = toStringKeys(v)
199                         if err != nil {
200                                 return nil, err
201                         }
202                 }
203                 return m, nil
204         case []interface{}:
205                 var l = make([]interface{}, len(val))
206                 for i, v := range val {
207                         l[i], err = toStringKeys(v)
208                         if err != nil {
209                                 return nil, err
210                         }
211                 }
212                 return l, nil
213         default:
214                 return val, nil
215         }
216 }
217
218 func validate(httpBodyString string, schemaString string) bool {
219         var m interface{}
220         err := yaml.Unmarshal([]byte(httpBodyString), &m)
221         if err != nil {
222                 a1.Logger.Error("Unmarshal error : %+v", err)
223         }
224         m, err = toStringKeys(m)
225         if err != nil {
226                 a1.Logger.Error("Conversion to string error : %+v", err)
227                 return false
228         }
229         compiler := jsonschema.NewCompiler()
230         if err := compiler.AddResource("schema.json", strings.NewReader(schemaString)); err != nil {
231                 a1.Logger.Error("string reader error : %+v", err)
232                 return false
233         }
234         schema, err := compiler.Compile("schema.json")
235         if err != nil {
236                 a1.Logger.Error("schema json compile error : %+v", err)
237                 return false
238         }
239         if err := schema.Validate(m); err != nil {
240                 a1.Logger.Error("schema validation error : %+v", err)
241                 return false
242         }
243         a1.Logger.Debug("validation successfull")
244         return true
245 }
246
247 func (rh *Resthook) storePolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID, httpBody interface{}) (string, error) {
248         var keys [1]string
249         operation := "CREATE"
250         typekey := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
251         keys[0] = typekey
252
253         a1.Logger.Debug("key1 : %+v", typekey)
254
255         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
256         if err != nil {
257                 a1.Logger.Error("policy type error : %+v", err)
258         }
259         a1.Logger.Debug("policytype map : %+v", valmap)
260         if valmap[typekey] == nil {
261                 a1.Logger.Error("policy type Not Present for policyid : %v", policyTypeId)
262                 return operation, policyTypeNotFoundError
263         }
264         // TODO : rmr creation_timestamp := time.Now() // will be needed for rmr to notify the creation of instance
265
266         instancekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
267         keys[0] = typekey
268         instanceMap, err := rh.db.Get(a1MediatorNs, keys[:])
269         if err != nil {
270                 a1.Logger.Error("policy type error : %v", err)
271         }
272         a1.Logger.Debug("policyinstancetype map : %+v", instanceMap)
273
274         if instanceMap[instancekey] != nil {
275                 operation = "UPDATE"
276                 a1.Logger.Debug("UPDATE")
277                 data, _ := json.Marshal(httpBody)
278                 a1.Logger.Debug("Marshaled String : %+v", string(data))
279                 a1.Logger.Debug("key   : %+v", instancekey)
280                 success, err1 := rh.db.SetIf(a1MediatorNs, instancekey, instanceMap[instancekey], string(data))
281                 if err1 != nil {
282                         a1.Logger.Error("error2 :%+v", err1)
283                         return operation, err1
284                 }
285                 if !success {
286                         a1.Logger.Debug("Policy instance %+v already exist", policyInstanceID)
287                         return operation, InstanceAlreadyError
288                 }
289         } else {
290                 data, _ := json.Marshal(httpBody)
291                 a1.Logger.Debug("Marshaled String : %+v", string(data))
292                 a1.Logger.Debug("key   : %+v", instancekey)
293
294                 var instance_map []interface{}
295                 instance_map = append(instance_map, instancekey, string(data))
296                 a1.Logger.Debug("policyinstancetype map : %+v", instance_map[1])
297                 a1.Logger.Debug("policyinstancetype to create : %+v", instance_map)
298
299                 err1 := rh.db.Set(a1MediatorNs, instancekey, string(data))
300                 if err1 != nil {
301                         a1.Logger.Error("error1 :%+v", err1)
302                         return operation, err1
303                 }
304         }
305         a1.Logger.Debug("Policy Instance created ")
306         return operation, nil
307 }
308
309 func (rh *Resthook) storePolicyInstanceMetadata(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (bool, error) {
310
311         creation_timestamp := time.Now()
312         instanceMetadataKey := a1InstanceMetadataPrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
313
314         a1.Logger.Debug("key : %+v", instanceMetadataKey)
315
316         var metadatajson []interface{}
317         metadatajson = append(metadatajson, map[string]string{"created_at": creation_timestamp.Format("2006-01-02 15:04:05"), "has_been_deleted": "False"})
318         metadata, _ := json.Marshal(metadatajson)
319
320         a1.Logger.Debug("policyinstanceMetaData to create : %+v", string(metadata))
321
322         err := rh.db.Set(a1MediatorNs, instanceMetadataKey, string(metadata))
323
324         if err != nil {
325                 a1.Logger.Error("error :%+v", err)
326                 return false, err
327         }
328
329         a1.Logger.Debug("Policy Instance Meta Data created at :%+v", creation_timestamp)
330
331         return true, nil
332 }
333
334 func (rh *Resthook) CreatePolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID, httpBody interface{}) error {
335         a1.Logger.Debug("CreatePolicyInstance function")
336         //  validate the PUT against the schema
337         var policyTypeSchema *models.PolicyTypeSchema
338         policyTypeSchema = rh.GetPolicyType(policyTypeId)
339         schemaStr, err := json.Marshal(policyTypeSchema.CreateSchema)
340         if err != nil {
341                 a1.Logger.Error("Json Marshal error : %+v", err)
342                 return err
343         }
344         a1.Logger.Debug("schema to validate %+v", string(schemaStr))
345         a1.Logger.Debug("httpbody to validate %+v", httpBody)
346         schemaString := fmt.Sprint(string(schemaStr))
347         httpBodyMarshal, err := json.Marshal(httpBody)
348         httpBodyString := string((httpBodyMarshal))
349         a1.Logger.Debug("schema to validate sprint  %+v", (schemaString))
350         a1.Logger.Debug("httpbody to validate sprint %+v", httpBodyString)
351         isvalid := validate(httpBodyString, schemaString)
352         if isvalid {
353                 var operation string
354                 operation, err = rh.storePolicyInstance(policyTypeId, policyInstanceID, httpBody)
355                 if err != nil {
356                         a1.Logger.Error("error :%+v", err)
357                         return err
358                 }
359                 a1.Logger.Debug("policy instance :%+v", operation)
360                 iscreated, errmetadata := rh.storePolicyInstanceMetadata(policyTypeId, policyInstanceID)
361                 if errmetadata != nil {
362                         a1.Logger.Error("error :%+v", errmetadata)
363                         return errmetadata
364                 }
365                 if iscreated {
366                         a1.Logger.Debug("policy instance metadata created")
367                 }
368                 isSent := rh.iRmrSenderInst.RmrSendToXapp(httpBodyString)
369                 if isSent {
370                         a1.Logger.Debug("rmrSendToXapp : message sent")
371                 } else {
372                         a1.Logger.Debug("rmrSendToXapp : message not sent")
373                 }
374
375         } else {
376                 a1.Logger.Error("%+v", invalidJsonSchema)
377                 return invalidJsonSchema
378         }
379
380         return nil
381 }
382
383 func (rh *Resthook) GetPolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (interface{}, error) {
384         a1.Logger.Debug("GetPolicyInstance1")
385
386         var keys [1]string
387
388         typekey := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
389         keys[0] = typekey
390
391         a1.Logger.Debug("key1 : %+v", typekey)
392
393         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
394         if len(valmap) == 0 {
395                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
396                 return "{}", policyTypeNotFoundError
397         }
398
399         if err != nil {
400                 a1.Logger.Error("error in retrieving policy type. err: %v", err)
401                 return "{}", err
402         }
403
404         if valmap[typekey] == nil {
405                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
406                 return "{}", policyTypeNotFoundError
407         }
408
409         a1.Logger.Debug("keysmap : %+v", valmap[typekey])
410
411         instancekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
412         a1.Logger.Debug("key2 : %+v", instancekey)
413         keys[0] = instancekey
414         instanceMap, err := rh.db.Get(a1MediatorNs, keys[:])
415         if err != nil {
416                 a1.Logger.Error("policy instance error : %v", err)
417         }
418         a1.Logger.Debug("policyinstancetype map : %+v", instanceMap)
419
420         if instanceMap[instancekey] == nil {
421                 a1.Logger.Debug("policy instance Not Present for policyinstaneid : %v", policyInstanceID)
422                 return "{}", policyInstanceNotFoundError
423         }
424
425         valStr := fmt.Sprint(instanceMap[instancekey])
426         return valStr, nil
427 }
428
429 func (rh *Resthook) GetAllPolicyInstance(policyTypeId models.PolicyTypeID) ([]models.PolicyInstanceID, error) {
430         a1.Logger.Debug("GetAllPolicyInstance")
431         var policyTypeInstances = []models.PolicyInstanceID{}
432
433         keys, err := rh.db.GetAll("A1m_ns")
434
435         if err != nil {
436                 a1.Logger.Error("error in retrieving policy. err: %v", err)
437                 return policyTypeInstances, err
438         }
439         a1.Logger.Debug("keys : %+v", keys)
440         typekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "."
441
442         for _, key := range keys {
443                 if strings.HasPrefix(strings.TrimLeft(key, " "), typekey) {
444                         pti := strings.Split(strings.Trim(key, " "), typekey)[1]
445                         a1.Logger.Debug("pti %+v", pti)
446                         policyTypeInstances = append(policyTypeInstances, models.PolicyInstanceID(pti))
447                 }
448         }
449
450         if len(policyTypeInstances) == 0 {
451                 a1.Logger.Debug("policy instance Not Present  ")
452         }
453
454         a1.Logger.Debug("return : %+v", policyTypeInstances)
455         return policyTypeInstances, nil
456 }