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