8ed8a08d87cec2e4c88f0320e424fc94a5fb4ff2
[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
30         "gerrit.o-ran-sc.org/r/ric-plt/a1/pkg/a1"
31         "gerrit.o-ran-sc.org/r/ric-plt/a1/pkg/models"
32         "gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
33
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 : ", 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
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         httpBodyString := fmt.Sprint((httpBody))
348         isvalid := validate(httpBodyString, schemaString)
349         if isvalid {
350                 var operation string
351                 operation, err = rh.StorePolicyInstance(policyTypeId, policyInstanceID, httpBody)
352                 if err != nil {
353                         a1.Logger.Error("error :%+v", err)
354                         return err
355                 }
356                 a1.Logger.Debug("policy instance :%+v", operation)
357                 iscreated,errmetadata := rh.StorePolicyInstanceMetadata(policyTypeId, policyInstanceID)
358                 if errmetadata != nil {
359                         a1.Logger.Error("error :%+v", errmetadata)
360                         return errmetadata
361                 }
362                 if iscreated {
363                 a1.Logger.Debug("policy instance metadata created")
364                 }
365         } else {
366                 a1.Logger.Error("%+v", invalidJsonSchema)
367                 return invalidJsonSchema
368         }
369
370         return nil
371 }
372
373 func (rh *Resthook) GetPolicyInstance(policyTypeId models.PolicyTypeID, policyInstanceID models.PolicyInstanceID) (interface{}, error) {
374         a1.Logger.Debug("GetPolicyInstance1")
375
376         var keys [1]string
377
378         typekey := a1PolicyPrefix + strconv.FormatInt((int64(policyTypeId)), 10)
379         keys[0] = typekey
380
381         a1.Logger.Debug("key1 : %+v", typekey)
382
383         valmap, err := rh.db.Get(a1MediatorNs, keys[:])
384         if len(valmap) == 0 {
385                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
386                 return "{}", policyTypeNotFoundError
387         }
388
389         if err != nil {
390                 a1.Logger.Error("error in retrieving policy type. err: %v", err)
391                 return "{}", err
392         }
393
394         if valmap[typekey] == nil {
395                 a1.Logger.Debug("policy type Not Present for policyid : %v", policyTypeId)
396                 return "{}", policyTypeNotFoundError
397         }
398
399         a1.Logger.Debug("keysmap : %+v", valmap[typekey])
400
401         instancekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "." + string(policyInstanceID)
402         a1.Logger.Debug("key2 : %+v", instancekey)
403         keys[0] = instancekey
404         instanceMap, err := rh.db.Get(a1MediatorNs, keys[:])
405         if err != nil {
406                 a1.Logger.Error("policy instance error : %v", err)
407         }
408         a1.Logger.Debug("policyinstancetype map : %+v", instanceMap)
409
410         if instanceMap[instancekey] == nil {
411                 a1.Logger.Debug("policy instance Not Present for policyinstaneid : %v", policyInstanceID)
412                 return "{}", policyInstanceNotFoundError
413         }
414
415         valStr := fmt.Sprint(instanceMap[instancekey])
416         return valStr, nil
417 }
418
419 func (rh *Resthook) GetAllPolicyInstance(policyTypeId models.PolicyTypeID) []models.PolicyInstanceID ,error {
420         a1.Logger.Debug("GetAllPolicyInstance")
421         var policyTypeInstances =  []models.PolicyInstanceID{} 
422
423         keys, err := rh.db.GetAll("A1m_ns")
424
425         if err != nil {
426                 a1.Logger.Error("error in retrieving policy. err: %v", err)
427                 return policyTypeInstances ,err
428         }
429         a1.Logger.Debug("keys : %+v", keys)
430         typekey := a1InstancePrefix + strconv.FormatInt((int64(policyTypeId)), 10) + "."
431
432         for _, key := range keys {
433                 if strings.HasPrefix(strings.TrimLeft(key, " "), typekey) {
434                         pti := strings.Split(strings.Trim(key, " "), typekey)[1]
435                         a1.Logger.Debug("pti %+v", pti)
436                         policyTypeInstances = append(policyTypeInstances, models.PolicyInstanceID(pti))
437                 }
438         }
439
440         if len(policyTypeInstances)==0{
441                 a1.Logger.Debug("policy instance Not Present  ")
442         }
443
444         a1.Logger.Debug("return : %+v", policyTypeInstances)
445         return policyTypeInstances ,nil
446 }