Delete Policy Type Api
[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                 isSent := rh.iRmrSenderInst.RmrSendToXapp(httpBodyString)
374                 if isSent {
375                         a1.Logger.Debug("rmrSendToXapp : message sent")
376                 } else {
377                         a1.Logger.Debug("rmrSendToXapp : message not sent")
378                 }
379
380         } else {
381                 a1.Logger.Error("%+v", invalidJsonSchema)
382                 return invalidJsonSchema
383         }
384
385         return nil
386 }
387
388 func (rh *Resthook) GetPolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (interface{}, error) {
389         a1.Logger.Debug("GetPolicyInstance1")
390
391         var keys [1]string
392
393         typekey := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
394         keys[0] = typekey
395
396         a1.Logger.Debug("key1 : %+v", typekey)
397
398         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
399         if len(valmap) == 0 {
400                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
401                 return "{}", policyTypeNotFoundError
402         }
403
404         if err != nil {
405                 a1.Logger.Error("error in retrieving policy type. err: %v", err)
406                 return "{}", err
407         }
408
409         if valmap[typekey] == nil {
410                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
411                 return "{}", policyTypeNotFoundError
412         }
413
414         a1.Logger.Debug("keysmap : %+v", valmap[typekey])
415
416         instancekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
417         a1.Logger.Debug("key2 : %+v", instancekey)
418         keys[0] = instancekey
419         instanceMap, err := rh.db.Get(a1MediatorNs, keys[:])
420         if err != nil {
421                 a1.Logger.Error("policy instance error : %v", err)
422         }
423         a1.Logger.Debug("policyinstancetype map : %+v", instanceMap)
424
425         if instanceMap[instancekey] == nil {
426                 a1.Logger.Debug("policy instance Not Present for policyinstaneid : %v", policyInstanceID)
427                 return "{}", policyInstanceNotFoundError
428         }
429
430         valStr := fmt.Sprint(instanceMap[instancekey])
431         return valStr, nil
432 }
433
434 func (rh *Resthook) GetAllPolicyInstance(policyTypeId models.PolicyTypeID) ([]models.PolicyInstanceID, error) {
435         a1.Logger.Debug("GetAllPolicyInstance")
436         var policyTypeInstances = []models.PolicyInstanceID{}
437
438         keys, err := rh.db.GetAll("A1m_ns")
439
440         if err != nil {
441                 a1.Logger.Error("error in retrieving policy. err: %v", err)
442                 return policyTypeInstances, err
443         }
444         a1.Logger.Debug("keys : %+v", keys)
445         typekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "."
446
447         for _, key := range keys {
448                 if strings.HasPrefix(strings.TrimLeft(key, " "), typekey) {
449                         pti := strings.Split(strings.Trim(key, " "), typekey)[1]
450                         a1.Logger.Debug("pti %+v", pti)
451                         policyTypeInstances = append(policyTypeInstances, models.PolicyInstanceID(pti))
452                 }
453         }
454
455         if len(policyTypeInstances) == 0 {
456                 a1.Logger.Debug("policy instance Not Present  ")
457         }
458
459         a1.Logger.Debug("return : %+v", policyTypeInstances)
460         return policyTypeInstances, nil
461 }
462
463 func (rh *Resthook) DeletePolicyType(policyTypeId models.PolicyTypeID) error {
464         a1.Logger.Debug("DeletePolicyType")
465
466         policyinstances, err := rh.GetAllPolicyInstance(policyTypeId)
467         if err != nil {
468                 a1.Logger.Error("error in retrieving policy. err: %v", err)
469                 return err
470         }
471
472         var keys [1]string
473         key := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
474         keys[0] = key
475         if len(policyinstances) == 0 {
476                 err := rh.db.Remove(a1MediatorNs, keys[:])
477                 if err != nil {
478                         a1.Logger.Error("error in deleting policy type err: %v", err)
479                         return err
480                 }
481         } else {
482                 a1.Logger.Error("tried to delete a type that isn't empty")
483                 return policyTypeCanNotBeDeletedError
484         }
485         return nil
486 }