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