add python compatibility module
[multicloud/k8s.git] / src / orchestrator / pkg / rtcontext / rtcontext.go
1 /*
2  * Copyright 2020 Intel Corporation, Inc
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package rtcontext
18
19 import (
20         "fmt"
21         "math/rand"
22         "strings"
23         "time"
24
25         "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/contextdb"
26         pkgerrors "github.com/pkg/errors"
27 )
28
29 const maxrand = 0x7fffffffffffffff
30 const prefix string = "/context/"
31
32 type RunTimeContext struct {
33         cid  interface{}
34         meta interface{}
35 }
36
37 type Rtcontext interface {
38         RtcInit() (interface{}, error)
39         RtcLoad(interface{}) (interface{}, error)
40         RtcCreate() (interface{}, error)
41         RtcAddMeta(meta interface{}) error
42         RtcGet() (interface{}, error)
43         RtcAddLevel(handle interface{}, level string, value string) (interface{}, error)
44         RtcAddResource(handle interface{}, resname string, value interface{}) (interface{}, error)
45         RtcAddInstruction(handle interface{}, level string, insttype string, value interface{}) (interface{}, error)
46         RtcDeletePair(handle interface{}) error
47         RtcDeletePrefix(handle interface{}) error
48         RtcGetHandles(handle interface{}) ([]interface{}, error)
49         RtcGetValue(handle interface{}, value interface{}) error
50         RtcUpdateValue(handle interface{}, value interface{}) error
51         RtcGetMeta() (interface{}, error)
52         RtcAddOneLevel(pl interface{}, level string, value interface{}) (interface{}, error)
53 }
54
55 //Intialize context by assiging a new id
56 func (rtc *RunTimeContext) RtcInit() (interface{}, error) {
57         if rtc.cid != nil {
58                 return nil, pkgerrors.Errorf("Error, context already initialized")
59         }
60         ra := rand.New(rand.NewSource(time.Now().UnixNano()))
61         rn := ra.Int63n(maxrand)
62         id := fmt.Sprintf("%v", rn)
63         cid := (prefix + id + "/")
64         rtc.cid = interface{}(cid)
65         return interface{}(id), nil
66
67 }
68
69 //Load context using the given id
70 func (rtc *RunTimeContext) RtcLoad(id interface{}) (interface{}, error) {
71         str := fmt.Sprintf("%v", id)
72         if str == "" {
73                 return nil, pkgerrors.Errorf("Not a valid context id")
74         }
75         cid := (prefix + str + "/")
76         rtc.cid = interface{}(cid)
77         handle, err := rtc.RtcGet()
78         if err != nil {
79                 return nil, pkgerrors.Errorf("Error finding the context id: %s", err.Error())
80         }
81         return handle, nil
82 }
83
84 func (rtc *RunTimeContext) RtcCreate() (interface{}, error) {
85         cid := fmt.Sprintf("%v", rtc.cid)
86         if cid == "" {
87                 return nil, pkgerrors.Errorf("Error, context not intialized")
88         }
89         if !strings.HasPrefix(cid, prefix) {
90                 return nil, pkgerrors.Errorf("Not a valid run time context prefix")
91         }
92         id := strings.SplitN(cid, "/", 4)[2]
93         err := contextdb.Db.Put(cid, id)
94         if err != nil {
95                 return nil, pkgerrors.Errorf("Error creating run time context: %s", err.Error())
96         }
97
98         return rtc.cid, nil
99 }
100
101 //RtcAddMeta is used for saving meta data of appContext into ETCD.
102 func (rtc *RunTimeContext) RtcAddMeta(meta interface{}) error {
103         cid := fmt.Sprintf("%v", rtc.cid)
104         if cid == "" {
105                 return pkgerrors.Errorf("Error, context not intialized")
106         }
107         if !strings.HasPrefix(cid, prefix) {
108                 return pkgerrors.Errorf("Not a valid run time context prefix")
109         }
110
111         rtc.meta = meta
112         k := cid + "meta" + "/"
113         err := contextdb.Db.Put(k, rtc.meta)
114         if err != nil {
115                 return pkgerrors.Errorf("Error saving metadata in run time context: %s", err.Error())
116         }
117
118         return nil
119 }
120
121 //Get the root handle
122 func (rtc *RunTimeContext) RtcGet() (interface{}, error) {
123         str := fmt.Sprintf("%v", rtc.cid)
124         if !strings.HasPrefix(str, prefix) {
125                 return nil, pkgerrors.Errorf("Not a valid run time context")
126         }
127
128         var value string
129         err := contextdb.Db.Get(str, &value)
130         if err != nil {
131                 return nil, pkgerrors.Errorf("Error getting run time context metadata: %s", err.Error())
132         }
133         if !strings.Contains(str, value) {
134                 return nil, pkgerrors.Errorf("Error matching run time context metadata")
135         }
136
137         return rtc.cid, nil
138 }
139
140 // RtcGetMeta method fetches the meta data of the rtc object and returns it.
141 func (rtc *RunTimeContext) RtcGetMeta() (interface{}, error) {
142         str := fmt.Sprintf("%v", rtc.cid)
143         if !strings.HasPrefix(str, prefix) {
144                 return nil, pkgerrors.Errorf("Not a valid run time context")
145         }
146
147         var value interface{}
148         k := str + "meta" + "/"
149         err := contextdb.Db.Get(k, &value)
150         if err != nil {
151                 return nil, pkgerrors.Errorf("Error getting run time context metadata: %s", err.Error())
152         }
153         return value, nil
154
155 }
156
157 //Add a new level at a given handle and return the new handle
158 func (rtc *RunTimeContext) RtcAddLevel(handle interface{}, level string, value string) (interface{}, error) {
159         str := fmt.Sprintf("%v", handle)
160         sid := fmt.Sprintf("%v", rtc.cid)
161         if !strings.HasPrefix(str, sid) {
162                 return nil, pkgerrors.Errorf("Not a valid run time context handle")
163         }
164
165         if level == "" {
166                 return nil, pkgerrors.Errorf("Not a valid run time context level")
167         }
168         if value == "" {
169                 return nil, pkgerrors.Errorf("Not a valid run time context level value")
170         }
171
172         key := str + level + "/" + value + "/"
173         err := contextdb.Db.Put(key, value)
174         if err != nil {
175                 return nil, pkgerrors.Errorf("Error adding run time context level: %s", err.Error())
176         }
177
178         return (interface{})(key), nil
179 }
180
181 // RtcAddOneLevel adds one more level to the existing context prefix.RtcAddOneLevel. It takes in PreviousContentLevel as inteface, new level to be appended as string and the value to be saved of any type. It returns the updated interface and nil if no error.
182 //
183 func (rtc *RunTimeContext) RtcAddOneLevel(pl interface{}, level string, value interface{}) (interface{}, error) {
184         str := fmt.Sprintf("%v", pl)
185         sid := fmt.Sprintf("%v", rtc.cid)
186         if !strings.HasPrefix(str, sid) {
187                 return nil, pkgerrors.Errorf("Not a valid run time context handle")
188         }
189
190         if level == "" {
191                 return nil, pkgerrors.Errorf("Not a valid run time context level")
192         }
193         if value == "" {
194                 return nil, pkgerrors.Errorf("Not a valid run time context level value")
195         }
196
197         key := str + level + "/"
198         err := contextdb.Db.Put(key, value)
199         if err != nil {
200                 return nil, pkgerrors.Errorf("Error adding run time context level: %s", err.Error())
201         }
202         return (interface{})(key), nil
203 }
204
205 // Add a resource under the given level and return new handle
206 func (rtc *RunTimeContext) RtcAddResource(handle interface{}, resname string, value interface{}) (interface{}, error) {
207
208         str := fmt.Sprintf("%v", handle)
209         sid := fmt.Sprintf("%v", rtc.cid)
210         if !strings.HasPrefix(str, sid) {
211                 return nil, pkgerrors.Errorf("Not a valid run time context handle")
212         }
213         if resname == "" {
214                 return nil, pkgerrors.Errorf("Not a valid run time context resource name")
215         }
216         if value == nil {
217                 return nil, pkgerrors.Errorf("Not a valid run time context resource value")
218         }
219
220         k := str + "resource" + "/" + resname + "/"
221         err := contextdb.Db.Put(k, value)
222         if err != nil {
223                 return nil, pkgerrors.Errorf("Error adding run time context resource: %s", err.Error())
224         }
225         return (interface{})(k), nil
226 }
227
228 // Add instruction at a given level and type, return the new handle
229 func (rtc *RunTimeContext) RtcAddInstruction(handle interface{}, level string, insttype string, value interface{}) (interface{}, error) {
230         str := fmt.Sprintf("%v", handle)
231         sid := fmt.Sprintf("%v", rtc.cid)
232         if !strings.HasPrefix(str, sid) {
233                 return nil, pkgerrors.Errorf("Not a valid run time context handle")
234         }
235
236         if level == "" {
237                 return nil, pkgerrors.Errorf("Not a valid run time context level")
238         }
239         if insttype == "" {
240                 return nil, pkgerrors.Errorf("Not a valid run time context instruction type")
241         }
242         if value == nil {
243                 return nil, pkgerrors.Errorf("Not a valid run time context instruction value")
244         }
245         k := str + level + "/" + "instruction" + "/" + insttype + "/"
246         err := contextdb.Db.Put(k, fmt.Sprintf("%v", value))
247         if err != nil {
248                 return nil, pkgerrors.Errorf("Error adding run time context instruction: %s", err.Error())
249         }
250
251         return (interface{})(k), nil
252 }
253
254 //Delete the key value pair using given handle
255 func (rtc *RunTimeContext) RtcDeletePair(handle interface{}) error {
256         str := fmt.Sprintf("%v", handle)
257         sid := fmt.Sprintf("%v", rtc.cid)
258         if !strings.HasPrefix(str, sid) {
259                 return pkgerrors.Errorf("Not a valid run time context handle")
260         }
261         err := contextdb.Db.Delete(str)
262         if err != nil {
263                 return pkgerrors.Errorf("Error deleting run time context pair: %s", err.Error())
264         }
265
266         return nil
267 }
268
269 // Delete all handles underneath the given handle
270 func (rtc *RunTimeContext) RtcDeletePrefix(handle interface{}) error {
271         str := fmt.Sprintf("%v", handle)
272         sid := fmt.Sprintf("%v", rtc.cid)
273         if !strings.HasPrefix(str, sid) {
274                 return pkgerrors.Errorf("Not a valid run time context handle")
275         }
276
277         err := contextdb.Db.DeleteAll(str)
278         if err != nil {
279                 return pkgerrors.Errorf("Error deleting run time context with prefix: %s", err.Error())
280         }
281
282         return nil
283 }
284
285 // Return the list of handles under the given handle
286 func (rtc *RunTimeContext) RtcGetHandles(handle interface{}) ([]interface{}, error) {
287         str := fmt.Sprintf("%v", handle)
288         sid := fmt.Sprintf("%v", rtc.cid)
289         if !strings.HasPrefix(str, sid) {
290                 return nil, pkgerrors.Errorf("Not a valid run time context handle")
291         }
292
293         s, err := contextdb.Db.GetAllKeys(str)
294         if err != nil {
295                 return nil, pkgerrors.Errorf("Error getting run time context handles: %s", err.Error())
296         }
297         r := make([]interface{}, len(s))
298         for i, v := range s {
299                 r[i] = v
300         }
301         return r, nil
302 }
303
304 // Get the value for a given handle
305 func (rtc *RunTimeContext) RtcGetValue(handle interface{}, value interface{}) error {
306         str := fmt.Sprintf("%v", handle)
307         sid := fmt.Sprintf("%v", rtc.cid)
308         if !strings.HasPrefix(str, sid) {
309                 return pkgerrors.Errorf("Not a valid run time context handle")
310         }
311
312         err := contextdb.Db.Get(str, value)
313         if err != nil {
314                 return pkgerrors.Errorf("Error getting run time context value: %s", err.Error())
315         }
316
317         return nil
318 }
319
320 // Update the value of a given handle
321 func (rtc *RunTimeContext) RtcUpdateValue(handle interface{}, value interface{}) error {
322         str := fmt.Sprintf("%v", handle)
323         sid := fmt.Sprintf("%v", rtc.cid)
324         if !strings.HasPrefix(str, sid) {
325                 return pkgerrors.Errorf("Not a valid run time context handle")
326         }
327         err := contextdb.Db.Put(str, value)
328         if err != nil {
329                 return pkgerrors.Errorf("Error updating run time context value: %s", err.Error())
330         }
331         return nil
332
333 }