0c870f66576d2334fa72259c8a650a14ec0dc624
[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/a1/pkg/rmr"
34         "gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
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 var policyTypeCanNotBeDeletedError = errors.New("tried to delete a type that isn't empty")
54
55 func (rh *Resthook) CanPolicyTypeBeDeleted(err error) bool {
56         return err == policyTypeCanNotBeDeletedError
57 }
58
59 func (rh *Resthook) IsPolicyTypePresent(err error) bool {
60         return err == policyTypeNotFoundError
61 }
62
63 func (rh *Resthook) IsPolicyInstanceNotFound(err error) bool {
64         return err == policyInstanceNotFoundError
65 }
66
67 func (rh *Resthook) IsTypeAlready(err error) bool {
68         return err == typeAlreadyError
69 }
70 func (rh *Resthook) IsInstanceAlready(err error) bool {
71         return err == InstanceAlreadyError
72 }
73 func (rh *Resthook) IsTypeMismatch(err error) bool {
74         return err == typeMismatchError
75 }
76
77 func (rh *Resthook) IsValidJson(err error) bool {
78         return err == invalidJsonSchema
79 }
80 func NewResthook() *Resthook {
81         return createResthook(sdlgo.NewSyncStorage(), rmr.NewRMRSender())
82 }
83
84 func createResthook(sdlInst iSdl, rmrSenderInst rmr.IRmrSender) *Resthook {
85         return &Resthook{
86                 db:             sdlInst,
87                 iRmrSenderInst: rmrSenderInst,
88         }
89 }
90
91 func (rh *Resthook) GetAllPolicyType() []models.PolicyTypeID {
92
93         var policyTypeIDs []models.PolicyTypeID
94
95         keys, err := rh.db.GetAll("A1m_ns")
96
97         if err != nil {
98                 a1.Logger.Error("error in retrieving policy. err: %v", err)
99                 return policyTypeIDs
100         }
101         a1.Logger.Debug("keys : %+v", keys)
102
103         for _, key := range keys {
104                 if strings.HasPrefix(strings.TrimLeft(key, " "), a1PolicyPrefix) {
105                         pti := strings.Split(strings.Trim(key, " "), a1PolicyPrefix)[1]
106                         ptii, _ := strconv.ParseInt(pti, 10, 64)
107                         policyTypeIDs = append(policyTypeIDs, models.PolicyTypeID(ptii))
108                 }
109         }
110
111         a1.Logger.Debug("return : %+v", policyTypeIDs)
112         return policyTypeIDs
113 }
114
115 func (rh *Resthook) GetPolicyType(policyTypeId models.PolicyTypeID) *models.PolicyTypeSchema {
116         a1.Logger.Debug("GetPolicyType1")
117
118         var policytypeschema *models.PolicyTypeSchema
119         var keys [1]string
120
121         key := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
122         keys[0] = key
123
124         a1.Logger.Debug("key : %+v", key)
125
126         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
127
128         a1.Logger.Debug("policytype map : %+v", valmap)
129
130         if len(valmap) == 0 {
131                 a1.Logger.Error("policy type Not Present for policyid : %v", policyTypeId)
132                 return policytypeschema
133         }
134
135         if err != nil {
136                 a1.Logger.Error("error in retrieving policy type. err: %v", err)
137                 return nil
138         }
139
140         if valmap[key] == nil {
141                 a1.Logger.Error("policy type Not Present for policyid : %v", policyTypeId)
142                 return policytypeschema
143         }
144
145         a1.Logger.Debug("keysmap : %+v", valmap[key])
146
147         var item models.PolicyTypeSchema
148         valStr := fmt.Sprint(valmap[key])
149
150         a1.Logger.Debug("Policy type for %+v :  %+v", key, valStr)
151         valkey := "`" + valStr + "`"
152         valToUnmarshall, err := strconv.Unquote(valkey)
153         if err != nil {
154                 a1.Logger.Error("unquote error : %+v", err)
155                 return nil
156         }
157
158         a1.Logger.Debug("Policy type for %+v :  %+v", key, string(valToUnmarshall))
159
160         errunm := json.Unmarshal([]byte(valToUnmarshall), &item)
161
162         a1.Logger.Debug(" Unmarshalled json : %+v", (errunm))
163         a1.Logger.Debug("Policy type Name :  %v", (item.Name))
164
165         return &item
166 }
167
168 func (rh *Resthook) CreatePolicyType(policyTypeId models.PolicyTypeID, httprequest models.PolicyTypeSchema) error {
169         a1.Logger.Debug("CreatePolicyType function")
170         if policyTypeId != models.PolicyTypeID(*httprequest.PolicyTypeID) {
171                 //error message
172                 a1.Logger.Debug("Policytype Mismatch")
173                 return typeMismatchError
174         }
175         key := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
176         a1.Logger.Debug("key %+v ", key)
177         if data, err := httprequest.MarshalBinary(); err == nil {
178                 a1.Logger.Debug("Marshaled String : %+v", string(data))
179                 success, err1 := rh.db.SetIfNotExists(a1MediatorNs, key, string(data))
180                 a1.Logger.Info("success:%+v", success)
181                 if err1 != nil {
182                         a1.Logger.Error("error :%+v", err1)
183                         return err1
184                 }
185                 if !success {
186                         a1.Logger.Debug("Policy type %+v already exist", policyTypeId)
187                         return typeAlreadyError
188                 }
189         }
190         return nil
191 }
192
193 func toStringKeys(val interface{}) (interface{}, error) {
194         var err error
195         switch val := val.(type) {
196         case map[interface{}]interface{}:
197                 m := make(map[string]interface{})
198                 for k, v := range val {
199                         k, ok := k.(string)
200                         if !ok {
201                                 return nil, errors.New("found non-string key")
202                         }
203                         m[k], err = toStringKeys(v)
204                         if err != nil {
205                                 return nil, err
206                         }
207                 }
208                 return m, nil
209         case []interface{}:
210                 var l = make([]interface{}, len(val))
211                 for i, v := range val {
212                         l[i], err = toStringKeys(v)
213                         if err != nil {
214                                 return nil, err
215                         }
216                 }
217                 return l, nil
218         default:
219                 return val, nil
220         }
221 }
222
223 func validate(httpBodyString string, schemaString string) bool {
224         var m interface{}
225         err := yaml.Unmarshal([]byte(httpBodyString), &m)
226         if err != nil {
227                 a1.Logger.Error("Unmarshal error : %+v", err)
228         }
229         m, err = toStringKeys(m)
230         if err != nil {
231                 a1.Logger.Error("Conversion to string error : %+v", err)
232                 return false
233         }
234         compiler := jsonschema.NewCompiler()
235         if err := compiler.AddResource("schema.json", strings.NewReader(schemaString)); err != nil {
236                 a1.Logger.Error("string reader error : %+v", err)
237                 return false
238         }
239         schema, err := compiler.Compile("schema.json")
240         if err != nil {
241                 a1.Logger.Error("schema json compile error : %+v", err)
242                 return false
243         }
244         if err := schema.Validate(m); err != nil {
245                 a1.Logger.Error("schema validation error : %+v", err)
246                 return false
247         }
248         a1.Logger.Debug("validation successfull")
249         return true
250 }
251
252 func (rh *Resthook) storePolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID, httpBody interface{}) (string, error) {
253         var keys [1]string
254         operation := "CREATE"
255         typekey := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
256         keys[0] = typekey
257
258         a1.Logger.Debug("key1 : %+v", typekey)
259
260         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
261         if err != nil {
262                 a1.Logger.Error("policy type error : %+v", err)
263         }
264         a1.Logger.Debug("policytype map : %+v", valmap)
265         if valmap[typekey] == nil {
266                 a1.Logger.Error("policy type Not Present for policyid : %v", policyTypeId)
267                 return operation, policyTypeNotFoundError
268         }
269         // TODO : rmr creation_timestamp := time.Now() // will be needed for rmr to notify the creation of instance
270
271         instancekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
272         keys[0] = typekey
273         instanceMap, err := rh.db.Get(a1MediatorNs, keys[:])
274         if err != nil {
275                 a1.Logger.Error("policy type error : %v", err)
276         }
277         a1.Logger.Debug("policyinstancetype map : %+v", instanceMap)
278
279         if instanceMap[instancekey] != nil {
280                 operation = "UPDATE"
281                 a1.Logger.Debug("UPDATE")
282                 data, _ := json.Marshal(httpBody)
283                 a1.Logger.Debug("Marshaled String : %+v", string(data))
284                 a1.Logger.Debug("key   : %+v", instancekey)
285                 success, err1 := rh.db.SetIf(a1MediatorNs, instancekey, instanceMap[instancekey], string(data))
286                 if err1 != nil {
287                         a1.Logger.Error("error2 :%+v", err1)
288                         return operation, err1
289                 }
290                 if !success {
291                         a1.Logger.Debug("Policy instance %+v already exist", policyInstanceID)
292                         return operation, InstanceAlreadyError
293                 }
294         } else {
295                 data, _ := json.Marshal(httpBody)
296                 a1.Logger.Debug("Marshaled String : %+v", string(data))
297                 a1.Logger.Debug("key   : %+v", instancekey)
298
299                 var instance_map []interface{}
300                 instance_map = append(instance_map, instancekey, string(data))
301                 a1.Logger.Debug("policyinstancetype map : %+v", instance_map[1])
302                 a1.Logger.Debug("policyinstancetype to create : %+v", instance_map)
303
304                 err1 := rh.db.Set(a1MediatorNs, instancekey, string(data))
305                 if err1 != nil {
306                         a1.Logger.Error("error1 :%+v", err1)
307                         return operation, err1
308                 }
309         }
310         a1.Logger.Debug("Policy Instance created ")
311         return operation, nil
312 }
313
314 func (rh *Resthook) storePolicyInstanceMetadata(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (bool, error) {
315
316         creation_timestamp := time.Now()
317         instanceMetadataKey := a1InstanceMetadataPrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
318
319         a1.Logger.Debug("key : %+v", instanceMetadataKey)
320
321         var metadatajson []interface{}
322         metadatajson = append(metadatajson, map[string]string{"created_at": creation_timestamp.Format("2006-01-02 15:04:05"), "has_been_deleted": "False"})
323         metadata, _ := json.Marshal(metadatajson)
324
325         a1.Logger.Debug("policyinstanceMetaData to create : %+v", string(metadata))
326
327         err := rh.db.Set(a1MediatorNs, instanceMetadataKey, string(metadata))
328
329         if err != nil {
330                 a1.Logger.Error("error :%+v", err)
331                 return false, err
332         }
333
334         a1.Logger.Debug("Policy Instance Meta Data created at :%+v", creation_timestamp)
335
336         return true, nil
337 }
338
339 func (rh *Resthook) CreatePolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID, httpBody interface{}) error {
340         a1.Logger.Debug("CreatePolicyInstance function")
341         //  validate the PUT against the schema
342         var policyTypeSchema *models.PolicyTypeSchema
343         policyTypeSchema = rh.GetPolicyType(policyTypeId)
344         schemaStr, err := json.Marshal(policyTypeSchema.CreateSchema)
345         if err != nil {
346                 a1.Logger.Error("Json Marshal error : %+v", err)
347                 return err
348         }
349         a1.Logger.Debug("schema to validate %+v", string(schemaStr))
350         a1.Logger.Debug("httpbody to validate %+v", httpBody)
351         schemaString := fmt.Sprint(string(schemaStr))
352         httpBodyMarshal, err := json.Marshal(httpBody)
353         httpBodyString := string((httpBodyMarshal))
354         a1.Logger.Debug("schema to validate sprint  %+v", (schemaString))
355         a1.Logger.Debug("httpbody to validate sprint %+v", httpBodyString)
356         isvalid := validate(httpBodyString, schemaString)
357         if isvalid {
358                 var operation string
359                 operation, err = rh.storePolicyInstance(policyTypeId, policyInstanceID, httpBody)
360                 if err != nil {
361                         a1.Logger.Error("error :%+v", err)
362                         return err
363                 }
364                 a1.Logger.Debug("policy instance :%+v", operation)
365                 iscreated, errmetadata := rh.storePolicyInstanceMetadata(policyTypeId, policyInstanceID)
366                 if errmetadata != nil {
367                         a1.Logger.Error("error :%+v", errmetadata)
368                         return errmetadata
369                 }
370                 if iscreated {
371                         a1.Logger.Debug("policy instance metadata created")
372                 }
373
374                 message := rmr.Message{}
375                 rmrMessage, err := message.PolicyMessage(strconv.FormatInt((int64(policyTypeId)), 10), string(policyInstanceID), httpBodyString, operation)
376                 if err != nil {
377                         a1.Logger.Error("error : %v", err)
378                         return err
379                 }
380                 isSent := rh.iRmrSenderInst.RmrSendToXapp(rmrMessage)
381                 if isSent {
382                         a1.Logger.Debug("rmrSendToXapp : message sent")
383                 } else {
384                         a1.Logger.Debug("rmrSendToXapp : message not sent")
385                 }
386
387         } else {
388                 a1.Logger.Error("%+v", invalidJsonSchema)
389                 return invalidJsonSchema
390         }
391
392         return nil
393 }
394
395 func (rh *Resthook) GetPolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (interface{}, error) {
396         a1.Logger.Debug("GetPolicyInstance1")
397
398         var keys [1]string
399
400         typekey := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
401         keys[0] = typekey
402
403         a1.Logger.Debug("key1 : %+v", typekey)
404
405         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
406         if len(valmap) == 0 {
407                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
408                 return "{}", policyTypeNotFoundError
409         }
410
411         if err != nil {
412                 a1.Logger.Error("error in retrieving policy type. err: %v", err)
413                 return "{}", err
414         }
415
416         if valmap[typekey] == nil {
417                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
418                 return "{}", policyTypeNotFoundError
419         }
420
421         a1.Logger.Debug("keysmap : %+v", valmap[typekey])
422
423         instancekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
424         a1.Logger.Debug("key2 : %+v", instancekey)
425         keys[0] = instancekey
426         instanceMap, err := rh.db.Get(a1MediatorNs, keys[:])
427         if err != nil {
428                 a1.Logger.Error("policy instance error : %v", err)
429         }
430         a1.Logger.Debug("policyinstancetype map : %+v", instanceMap)
431
432         if instanceMap[instancekey] == nil {
433                 a1.Logger.Debug("policy instance Not Present for policyinstaneid : %v", policyInstanceID)
434                 return "{}", policyInstanceNotFoundError
435         }
436
437         valStr := fmt.Sprint(instanceMap[instancekey])
438         return valStr, nil
439 }
440
441 func (rh *Resthook) GetAllPolicyInstance(policyTypeId models.PolicyTypeID) ([]models.PolicyInstanceID, error) {
442         a1.Logger.Debug("GetAllPolicyInstance")
443         var policyTypeInstances = []models.PolicyInstanceID{}
444
445         keys, err := rh.db.GetAll("A1m_ns")
446
447         if err != nil {
448                 a1.Logger.Error("error in retrieving policy. err: %v", err)
449                 return policyTypeInstances, err
450         }
451         a1.Logger.Debug("keys : %+v", keys)
452         typekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "."
453
454         for _, key := range keys {
455                 if strings.HasPrefix(strings.TrimLeft(key, " "), typekey) {
456                         pti := strings.Split(strings.Trim(key, " "), typekey)[1]
457                         a1.Logger.Debug("pti %+v", pti)
458                         policyTypeInstances = append(policyTypeInstances, models.PolicyInstanceID(pti))
459                 }
460         }
461
462         if len(policyTypeInstances) == 0 {
463                 a1.Logger.Debug("policy instance Not Present  ")
464         }
465
466         a1.Logger.Debug("return : %+v", policyTypeInstances)
467         return policyTypeInstances, nil
468 }
469
470 func (rh *Resthook) DeletePolicyType(policyTypeId models.PolicyTypeID) error {
471         a1.Logger.Debug("DeletePolicyType")
472
473         policyinstances, err := rh.GetAllPolicyInstance(policyTypeId)
474         if err != nil {
475                 a1.Logger.Error("error in retrieving policy. err: %v", err)
476                 return err
477         }
478
479         var keys [1]string
480         key := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
481         keys[0] = key
482         if len(policyinstances) == 0 {
483                 err := rh.db.Remove(a1MediatorNs, keys[:])
484                 if err != nil {
485                         a1.Logger.Error("error in deleting policy type err: %v", err)
486                         return err
487                 }
488         } else {
489                 a1.Logger.Error("tried to delete a type that isn't empty")
490                 return policyTypeCanNotBeDeletedError
491         }
492         return nil
493 }
494
495 func (rh *Resthook) typeValidity(policyTypeId models.PolicyTypeID) error {
496         var keys [1]string
497
498         typekey := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
499         keys[0] = typekey
500
501         a1.Logger.Debug("key1 : %+v", typekey)
502         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
503         if err != nil {
504                 a1.Logger.Error("error in retrieving policytype err: %v", err)
505                 return err
506         }
507         if len(valmap) == 0 {
508                 a1.Logger.Error("policy type Not Present for policyid : %v", policyTypeId)
509                 return policyTypeNotFoundError
510         }
511 }
512
513 func (rh *Resthook) instanceValidity(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) error {
514         err := rh.typeValidity(policyTypeId)
515         if err != nil {
516                 return err
517         }
518         policyTypeInstances, err := rh.GetPolicyInstance(policyTypeId, policyInstanceID)
519         if err != nil {
520                 a1.Logger.Error("policy instance error : %v", err)
521                 return err
522         }
523         if len(policyTypeInstances.(string)) == 0 {
524                 a1.Logger.Debug("policy instance Not Present  ")
525                 return policyInstanceNotFoundError
526         }
527 }
528
529 func (rh *Resthook) getMetaData(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (map[string]interface{}, error) {
530         instanceMetadataKey := a1InstanceMetadataPrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
531         a1.Logger.Debug("instanceMetadata key : %+v", instanceMetadataKey)
532         var keys [1]string
533         keys[0] = instanceMetadataKey
534         instanceMetadataMap, err := rh.db.Get(a1MediatorNs, keys[:])
535         if err != nil {
536                 a1.Logger.Error("policy instance error : %v", err)
537         }
538         a1.Logger.Debug("instanceMetadata map : %+v", instanceMetadataMap)
539         if instanceMetadataMap[instanceMetadataKey] == nil {
540                 a1.Logger.Error("policy instance Not Present for policyinstaneid : %v", policyInstanceID)
541                 return map[string]interface{}{}, policyInstanceNotFoundError
542         }
543         return instanceMetadataMap, nil
544 }
545
546 func (rh *Resthook) GetPolicyInstanceStatus(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (*a1_mediator.A1ControllerGetPolicyInstanceStatusOKBody, error) {
547         err := rh.instanceValidity(policyTypeId, policyInstanceID)
548         if err != nil && err == policyInstanceNotFoundError || err == policyTypeNotFoundError {
549                 policyInstanceStatus.InstanceStatus = "NOT IN EFFECT"
550                 return &policyInstanceStatus, err
551         }
552         policyInstanceStatus := a1_mediator.A1ControllerGetPolicyInstanceStatusOKBody{}
553         metadata, err := rh.getMetaData(policyTypeId, policyInstanceID)
554         a1.Logger.Debug(" metadata %v", metadata)
555         if err != nil {
556                 a1.Logger.Error("policy instance error : %v", err)
557                 policyInstanceStatus.InstanceStatus = "NOT IN EFFECT"
558                 return &policyInstanceStatus, err
559         }
560         jsonbody, err := json.Marshal(metadata)
561         if err != nil {
562                 a1.Logger.Error("marshal error : %v", err)
563                 return &policyInstanceStatus, err
564         }
565
566         if err := json.Unmarshal(jsonbody, &policyInstanceStatus); err != nil {
567                 a1.Logger.Error("unmarshal error : %v", err)
568                 //this error maps to 503 error but can be mapped to 500: internal error
569                 return &policyInstanceStatus, err
570         }
571         if policyInstanceStatus.HasBeenDeleted == false {
572                 policyInstanceStatus.InstanceStatus = "IN EFFECT"
573         } else {
574                 policyInstanceStatus.InstanceStatus = "NOT IN EFFECT"
575         }
576         return &policyInstanceStatus, nil
577 }