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