8d13a71cb5e14a164ef74c1d5b0a8bc7de0c8150
[icn/sdwan.git] /
1 // SPDX-License-Identifier: Apache-2.0\r
2 // Copyright (c) 2020 Intel Corporation\r
3 \r
4 package appcontext\r
5 \r
6 import (\r
7         "fmt"\r
8         "strings"\r
9 \r
10         log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"\r
11         "github.com/open-ness/EMCO/src/orchestrator/pkg/rtcontext"\r
12         pkgerrors "github.com/pkg/errors"\r
13 )\r
14 \r
15 // metaPrefix used for denoting clusterMeta level\r
16 const metaGrpPREFIX = "!@#metaGrp"\r
17 \r
18 type AppContext struct {\r
19         initDone bool\r
20         rtcObj   rtcontext.RunTimeContext\r
21         rtc      rtcontext.Rtcontext\r
22 }\r
23 \r
24 // AppContextStatus represents the current status of the appcontext\r
25 //      Instantiating - instantiate has been invoked and is still in progress\r
26 //      Instantiated - instantiate has completed\r
27 //      Terminating - terminate has been invoked and is still in progress\r
28 //      Terminated - terminate has completed\r
29 //      InstantiateFailed - the instantiate action has failed\r
30 //      TerminateFailed - the terminate action has failed\r
31 type AppContextStatus struct {\r
32         Status StatusValue\r
33 }\r
34 type StatusValue string\r
35 type statuses struct {\r
36         Instantiating     StatusValue\r
37         Instantiated      StatusValue\r
38         Terminating       StatusValue\r
39         Terminated        StatusValue\r
40         InstantiateFailed StatusValue\r
41         TerminateFailed   StatusValue\r
42 }\r
43 \r
44 var AppContextStatusEnum = &statuses{\r
45         Instantiating:     "Instantiating",\r
46         Instantiated:      "Instantiated",\r
47         Terminating:       "Terminating",\r
48         Terminated:        "Terminated",\r
49         InstantiateFailed: "InstantiateFailed",\r
50         TerminateFailed:   "TerminateFailed",\r
51 }\r
52 \r
53 // CompositeAppMeta consists of projectName, CompositeAppName,\r
54 // CompositeAppVersion, ReleaseName. This shall be used for\r
55 // instantiation of a compositeApp\r
56 type CompositeAppMeta struct {\r
57         Project               string `json:"Project"`\r
58         CompositeApp          string `json:"CompositeApp"`\r
59         Version               string `json:"Version"`\r
60         Release               string `json:"Release"`\r
61         DeploymentIntentGroup string `json:"DeploymentIntentGroup"`\r
62         Namespace             string `json:"Namespace"`\r
63         Level                 string `json:"Level"`\r
64 }\r
65 \r
66 // Init app context\r
67 func (ac *AppContext) InitAppContext() (interface{}, error) {\r
68         ac.rtcObj = rtcontext.RunTimeContext{}\r
69         ac.rtc = &ac.rtcObj\r
70         return ac.rtc.RtcInit()\r
71 }\r
72 \r
73 // Load app context that was previously created\r
74 func (ac *AppContext) LoadAppContext(cid interface{}) (interface{}, error) {\r
75         ac.rtcObj = rtcontext.RunTimeContext{}\r
76         ac.rtc = &ac.rtcObj\r
77         return ac.rtc.RtcLoad(cid)\r
78 }\r
79 \r
80 // CreateCompositeApp method returns composite app handle as interface.\r
81 func (ac *AppContext) CreateCompositeApp() (interface{}, error) {\r
82         h, err := ac.rtc.RtcCreate()\r
83         if err != nil {\r
84                 return nil, err\r
85         }\r
86         log.Info(":: CreateCompositeApp ::", log.Fields{"CompositeAppHandle": h})\r
87         return h, nil\r
88 }\r
89 \r
90 // AddCompositeAppMeta adds the meta data associated with a composite app\r
91 func (ac *AppContext) AddCompositeAppMeta(meta interface{}) error {\r
92         err := ac.rtc.RtcAddMeta(meta)\r
93         if err != nil {\r
94                 return err\r
95         }\r
96         return nil\r
97 }\r
98 \r
99 // Deletes the entire context\r
100 func (ac *AppContext) DeleteCompositeApp() error {\r
101         h, err := ac.rtc.RtcGet()\r
102         if err != nil {\r
103                 return err\r
104         }\r
105         err = ac.rtc.RtcDeletePrefix(h)\r
106         if err != nil {\r
107                 return err\r
108         }\r
109         return nil\r
110 }\r
111 \r
112 //Returns the handles for a given composite app context\r
113 func (ac *AppContext) GetCompositeAppHandle() (interface{}, error) {\r
114         h, err := ac.rtc.RtcGet()\r
115         if err != nil {\r
116                 return nil, err\r
117         }\r
118         return h, nil\r
119 }\r
120 \r
121 // GetLevelHandle returns the handle for the supplied level at the given handle.\r
122 // For example, to get the handle of the 'status' level at a given handle.\r
123 func (ac *AppContext) GetLevelHandle(handle interface{}, level string) (interface{}, error) {\r
124         ach := fmt.Sprintf("%v%v/", handle, level)\r
125         hs, err := ac.rtc.RtcGetHandles(ach)\r
126         if err != nil {\r
127                 return nil, err\r
128         }\r
129         for _, v := range hs {\r
130                 if v == ach {\r
131                         return v, nil\r
132                 }\r
133         }\r
134         return nil, pkgerrors.Errorf("No handle was found for level %v", level)\r
135 }\r
136 \r
137 //Add app to the context under composite app\r
138 func (ac *AppContext) AddApp(handle interface{}, appname string) (interface{}, error) {\r
139         h, err := ac.rtc.RtcAddLevel(handle, "app", appname)\r
140         if err != nil {\r
141                 return nil, err\r
142         }\r
143         log.Info(":: Added app handle ::", log.Fields{"AppHandle": h})\r
144         return h, nil\r
145 }\r
146 \r
147 //Delete app from the context and everything underneth\r
148 func (ac *AppContext) DeleteApp(handle interface{}) error {\r
149         err := ac.rtc.RtcDeletePrefix(handle)\r
150         if err != nil {\r
151                 return err\r
152         }\r
153         return nil\r
154 }\r
155 \r
156 //Returns the handle for a given app\r
157 func (ac *AppContext) GetAppHandle(appname string) (interface{}, error) {\r
158         if appname == "" {\r
159                 return nil, pkgerrors.Errorf("Not a valid run time context app name")\r
160         }\r
161 \r
162         rh, err := ac.rtc.RtcGet()\r
163         if err != nil {\r
164                 return nil, err\r
165         }\r
166 \r
167         apph := fmt.Sprintf("%v", rh) + "app/" + appname + "/"\r
168         hs, err := ac.rtc.RtcGetHandles(apph)\r
169         if err != nil {\r
170                 return nil, err\r
171         }\r
172         for _, v := range hs {\r
173                 if v == apph {\r
174                         return v, nil\r
175                 }\r
176         }\r
177         return nil, pkgerrors.Errorf("No handle was found for the given app")\r
178 }\r
179 \r
180 // AddCluster helps to add cluster to the context under app. It takes in the app handle and clusterName as value.\r
181 func (ac *AppContext) AddCluster(handle interface{}, clustername string) (interface{}, error) {\r
182         h, err := ac.rtc.RtcAddLevel(handle, "cluster", clustername)\r
183         if err != nil {\r
184                 return nil, err\r
185         }\r
186         log.Info(":: Added cluster handle ::", log.Fields{"ClusterHandler": h})\r
187         return h, nil\r
188 }\r
189 \r
190 // AddClusterMetaGrp adds the meta info of groupNumber to which a cluster belongs.\r
191 // It takes in cluster handle and groupNumber as arguments\r
192 func (ac *AppContext) AddClusterMetaGrp(ch interface{}, gn string) error {\r
193         mh, err := ac.rtc.RtcAddOneLevel(ch, metaGrpPREFIX, gn)\r
194         if err != nil {\r
195                 return err\r
196         }\r
197         log.Info(":: Added cluster meta handle ::", log.Fields{"ClusterMetaHandler": mh})\r
198         return nil\r
199 }\r
200 \r
201 // DeleteClusterMetaGrpHandle deletes the group number to which the cluster belongs, it takes in the cluster handle.\r
202 func (ac *AppContext) DeleteClusterMetaGrpHandle(ch interface{}) error {\r
203         err := ac.rtc.RtcDeletePrefix(ch)\r
204         if err != nil {\r
205                 return err\r
206         }\r
207         log.Info(":: Deleted cluster meta handle ::", log.Fields{"ClusterMetaHandler": ch})\r
208         return nil\r
209 }\r
210 \r
211 /*\r
212 GetClusterMetaHandle takes in appName and ClusterName as string arguments and return the ClusterMetaHandle as string\r
213 */\r
214 func (ac *AppContext) GetClusterMetaHandle(app string, cluster string) (string, error) {\r
215         if app == "" {\r
216                 return "", pkgerrors.Errorf("Not a valid run time context app name")\r
217         }\r
218         if cluster == "" {\r
219                 return "", pkgerrors.Errorf("Not a valid run time context cluster name")\r
220         }\r
221 \r
222         ch, err := ac.GetClusterHandle(app, cluster)\r
223         if err != nil {\r
224                 return "", err\r
225         }\r
226         cmh := fmt.Sprintf("%v", ch) + metaGrpPREFIX + "/"\r
227         return cmh, nil\r
228 \r
229 }\r
230 \r
231 /*\r
232 GetClusterGroupMap shall take in appName and return a map showing the grouping among the clusters.\r
233 sample output of "GroupMap" :{"1":["cluster_provider1+clusterName3","cluster_provider1+clusterName5"],"2":["cluster_provider2+clusterName4","cluster_provider2+clusterName6"]}\r
234 */\r
235 func (ac *AppContext) GetClusterGroupMap(an string) (map[string][]string, error) {\r
236         cl, err := ac.GetClusterNames(an)\r
237         if err != nil {\r
238                 log.Info(":: Unable to fetch clusterList for app ::", log.Fields{"AppName ": an})\r
239                 return nil, err\r
240         }\r
241         rh, err := ac.rtc.RtcGet()\r
242         if err != nil {\r
243                 return nil, err\r
244         }\r
245 \r
246         var gmap = make(map[string][]string)\r
247         for _, cn := range cl {\r
248                 s := fmt.Sprintf("%v", rh) + "app/" + an + "/cluster/" + cn + "/" + metaGrpPREFIX + "/"\r
249                 var v string\r
250                 err = ac.rtc.RtcGetValue(s, &v)\r
251                 if err != nil {\r
252                         log.Info(":: No group number for cluster  ::", log.Fields{"cluster": cn, "Reason": err})\r
253                         continue\r
254                 }\r
255                 gn := fmt.Sprintf("%v", v)\r
256                 log.Info(":: GroupNumber retrieved  ::", log.Fields{"GroupNumber": gn})\r
257 \r
258                 cl, found := gmap[gn]\r
259                 if found == false {\r
260                         cl = make([]string, 0)\r
261                 }\r
262                 cl = append(cl, cn)\r
263                 gmap[gn] = cl\r
264         }\r
265         return gmap, nil\r
266 }\r
267 \r
268 //Delete cluster from the context and everything underneth\r
269 func (ac *AppContext) DeleteCluster(handle interface{}) error {\r
270         err := ac.rtc.RtcDeletePrefix(handle)\r
271         if err != nil {\r
272                 return err\r
273         }\r
274         return nil\r
275 }\r
276 \r
277 //Returns the handle for a given app and cluster\r
278 func (ac *AppContext) GetClusterHandle(appname string, clustername string) (interface{}, error) {\r
279         if appname == "" {\r
280                 return nil, pkgerrors.Errorf("Not a valid run time context app name")\r
281         }\r
282         if clustername == "" {\r
283                 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")\r
284         }\r
285 \r
286         rh, err := ac.rtc.RtcGet()\r
287         if err != nil {\r
288                 return nil, err\r
289         }\r
290 \r
291         ach := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/"\r
292         hs, err := ac.rtc.RtcGetHandles(ach)\r
293         if err != nil {\r
294                 return nil, err\r
295         }\r
296         for _, v := range hs {\r
297                 if v == ach {\r
298                         return v, nil\r
299                 }\r
300         }\r
301         return nil, pkgerrors.Errorf("No handle was found for the given cluster")\r
302 }\r
303 \r
304 //Returns a list of all clusters for a given app\r
305 func (ac *AppContext) GetClusterNames(appname string) ([]string, error) {\r
306         if appname == "" {\r
307                 return nil, pkgerrors.Errorf("Not a valid run time context app name")\r
308         }\r
309 \r
310         rh, err := ac.rtc.RtcGet()\r
311         if err != nil {\r
312                 return nil, err\r
313         }\r
314 \r
315         prefix := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/"\r
316         hs, err := ac.rtc.RtcGetHandles(prefix)\r
317         if err != nil {\r
318                 return nil, pkgerrors.Errorf("Error getting handles for %v", prefix)\r
319         }\r
320         var cs []string\r
321         for _, h := range hs {\r
322                 hstr := fmt.Sprintf("%v", h)\r
323                 ks := strings.Split(hstr, prefix)\r
324                 for _, k := range ks {\r
325                         ck := strings.Split(k, "/")\r
326                         if len(ck) == 2 && ck[1] == "" {\r
327                                 cs = append(cs, ck[0])\r
328                         }\r
329                 }\r
330         }\r
331         return cs, nil\r
332 }\r
333 \r
334 //Add resource under app and cluster\r
335 func (ac *AppContext) AddResource(handle interface{}, resname string, value interface{}) (interface{}, error) {\r
336         h, err := ac.rtc.RtcAddResource(handle, resname, value)\r
337         if err != nil {\r
338                 return nil, err\r
339         }\r
340         log.Info(":: Added resource handle ::", log.Fields{"ResourceHandler": h})\r
341 \r
342         return h, nil\r
343 }\r
344 \r
345 //Return the handle for given app, cluster and resource name\r
346 func (ac *AppContext) GetResourceHandle(appname string, clustername string, resname string) (interface{}, error) {\r
347         if appname == "" {\r
348                 return nil, pkgerrors.Errorf("Not a valid run time context app name")\r
349         }\r
350         if clustername == "" {\r
351                 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")\r
352         }\r
353 \r
354         rh, err := ac.rtc.RtcGet()\r
355         if err != nil {\r
356                 return nil, err\r
357         }\r
358 \r
359         acrh := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/resource/" + resname + "/"\r
360         hs, err := ac.rtc.RtcGetHandles(acrh)\r
361         if err != nil {\r
362                 return nil, err\r
363         }\r
364         for _, v := range hs {\r
365                 if v == acrh {\r
366                         return v, nil\r
367                 }\r
368         }\r
369         return nil, pkgerrors.Errorf("No handle was found for the given resource")\r
370 }\r
371 \r
372 //Update the resource value using the given handle\r
373 func (ac *AppContext) UpdateResourceValue(handle interface{}, value interface{}) error {\r
374         return ac.rtc.RtcUpdateValue(handle, value)\r
375 }\r
376 \r
377 //Return the handle for given app, cluster and resource name\r
378 func (ac *AppContext) GetResourceStatusHandle(appname string, clustername string, resname string) (interface{}, error) {\r
379         if appname == "" {\r
380                 return nil, pkgerrors.Errorf("Not a valid run time context app name")\r
381         }\r
382         if clustername == "" {\r
383                 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")\r
384         }\r
385         if resname == "" {\r
386                 return nil, pkgerrors.Errorf("Not a valid run time context resource name")\r
387         }\r
388 \r
389         rh, err := ac.rtc.RtcGet()\r
390         if err != nil {\r
391                 return nil, err\r
392         }\r
393 \r
394         acrh := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/resource/" + resname + "/status/"\r
395         hs, err := ac.rtc.RtcGetHandles(acrh)\r
396         if err != nil {\r
397                 return nil, err\r
398         }\r
399         for _, v := range hs {\r
400                 if v == acrh {\r
401                         return v, nil\r
402                 }\r
403         }\r
404         return nil, pkgerrors.Errorf("No handle was found for the given resource")\r
405 }\r
406 \r
407 //Add instruction under given handle and type\r
408 func (ac *AppContext) AddInstruction(handle interface{}, level string, insttype string, value interface{}) (interface{}, error) {\r
409         if !(insttype == "order" || insttype == "dependency") {\r
410                 log.Error("Not a valid app context instruction type", log.Fields{})\r
411                 return nil, pkgerrors.Errorf("Not a valid app context instruction type")\r
412         }\r
413         if !(level == "app" || level == "resource" || level == "subresource") {\r
414                 log.Error("Not a valid app context instruction level", log.Fields{})\r
415                 return nil, pkgerrors.Errorf("Not a valid app context instruction level")\r
416         }\r
417         h, err := ac.rtc.RtcAddInstruction(handle, level, insttype, value)\r
418         if err != nil {\r
419                 log.Error("ac.rtc.RtcAddInstruction(handle, level, insttype, value)", log.Fields{"err": err})\r
420                 return nil, err\r
421         }\r
422         log.Info(":: Added instruction handle ::", log.Fields{"InstructionHandler": h})\r
423         return h, nil\r
424 }\r
425 \r
426 //Delete instruction under given handle\r
427 func (ac *AppContext) DeleteInstruction(handle interface{}) error {\r
428         err := ac.rtc.RtcDeletePair(handle)\r
429         if err != nil {\r
430                 return err\r
431         }\r
432         return nil\r
433 }\r
434 \r
435 //Returns the app instruction for a given instruction type\r
436 func (ac *AppContext) GetAppInstruction(insttype string) (interface{}, error) {\r
437         if !(insttype == "order" || insttype == "dependency") {\r
438                 log.Error("Not a valid app context instruction type", log.Fields{})\r
439                 return nil, pkgerrors.Errorf("Not a valid app context instruction type")\r
440         }\r
441         rh, err := ac.rtc.RtcGet()\r
442         if err != nil {\r
443                 log.Error("ac.rtc.RtcGet()", log.Fields{"err": err})\r
444                 return nil, err\r
445         }\r
446         s := fmt.Sprintf("%v", rh) + "app/" + "instruction/" + insttype + "/"\r
447         log.Info("Getting app instruction", log.Fields{"s": s})\r
448         var v string\r
449         err = ac.rtc.RtcGetValue(s, &v)\r
450         if err != nil {\r
451                 log.Error("ac.rtc.RtcGetValue(s, &v)", log.Fields{"err": err})\r
452                 return nil, err\r
453         }\r
454         return v, nil\r
455 }\r
456 \r
457 //Update the instruction usign the given handle\r
458 func (ac *AppContext) UpdateInstructionValue(handle interface{}, value interface{}) error {\r
459         return ac.rtc.RtcUpdateValue(handle, value)\r
460 }\r
461 \r
462 //Returns the resource instruction for a given instruction type\r
463 func (ac *AppContext) GetResourceInstruction(appname string, clustername string, insttype string) (interface{}, error) {\r
464         if !(insttype == "order" || insttype == "dependency") {\r
465                 log.Error("Not a valid app context instruction type", log.Fields{})\r
466                 return nil, pkgerrors.Errorf("Not a valid app context instruction type")\r
467         }\r
468         rh, err := ac.rtc.RtcGet()\r
469         if err != nil {\r
470                 log.Error("ac.rtc.RtcGet()", log.Fields{"err": err})\r
471                 return nil, err\r
472         }\r
473         s := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/resource/instruction/" + insttype + "/"\r
474         var v string\r
475         err = ac.rtc.RtcGetValue(s, &v)\r
476         if err != nil {\r
477                 log.Error("ac.rtc.RtcGetValue(s, &v)", log.Fields{"err": err})\r
478                 return nil, err\r
479         }\r
480         return v, nil\r
481 }\r
482 \r
483 // AddLevelValue for holding a state object at a given level\r
484 // will make a handle with an appended "<level>/" to the key\r
485 func (ac *AppContext) AddLevelValue(handle interface{}, level string, value interface{}) (interface{}, error) {\r
486         h, err := ac.rtc.RtcAddOneLevel(handle, level, value)\r
487         if err != nil {\r
488                 return nil, err\r
489         }\r
490         log.Info(":: Added handle ::", log.Fields{"Handle": h})\r
491 \r
492         return h, nil\r
493 }\r
494 \r
495 // GetClusterStatusHandle returns the handle for cluster status for a given app and cluster\r
496 func (ac *AppContext) GetClusterStatusHandle(appname string, clustername string) (interface{}, error) {\r
497         if appname == "" {\r
498                 return nil, pkgerrors.Errorf("Not a valid run time context app name")\r
499         }\r
500         if clustername == "" {\r
501                 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")\r
502         }\r
503 \r
504         rh, err := ac.rtc.RtcGet()\r
505         if err != nil {\r
506                 return nil, err\r
507         }\r
508 \r
509         acrh := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/status/"\r
510         hs, err := ac.rtc.RtcGetHandles(acrh)\r
511         if err != nil {\r
512                 return nil, err\r
513         }\r
514         for _, v := range hs {\r
515                 if v == acrh {\r
516                         return v, nil\r
517                 }\r
518         }\r
519         return nil, pkgerrors.Errorf("No handle was found for the given resource")\r
520 }\r
521 \r
522 //UpdateStatusValue updates the status value with the given handle\r
523 func (ac *AppContext) UpdateStatusValue(handle interface{}, value interface{}) error {\r
524         return ac.rtc.RtcUpdateValue(handle, value)\r
525 }\r
526 \r
527 //UpdateValue updates the state value with the given handle\r
528 func (ac *AppContext) UpdateValue(handle interface{}, value interface{}) error {\r
529         return ac.rtc.RtcUpdateValue(handle, value)\r
530 }\r
531 \r
532 //Return all the handles under the composite app\r
533 func (ac *AppContext) GetAllHandles(handle interface{}) ([]interface{}, error) {\r
534         hs, err := ac.rtc.RtcGetHandles(handle)\r
535         if err != nil {\r
536                 return nil, err\r
537         }\r
538         return hs, nil\r
539 }\r
540 \r
541 //Returns the value for a given handle\r
542 func (ac *AppContext) GetValue(handle interface{}) (interface{}, error) {\r
543         var v interface{}\r
544         err := ac.rtc.RtcGetValue(handle, &v)\r
545         if err != nil {\r
546                 return nil, err\r
547         }\r
548         return v, nil\r
549 }\r
550 \r
551 // GetCompositeAppMeta returns the meta data associated with the compositeApp\r
552 // Its return type is CompositeAppMeta\r
553 func (ac *AppContext) GetCompositeAppMeta() (CompositeAppMeta, error) {\r
554         mi, err := ac.rtcObj.RtcGetMeta()\r
555 \r
556         if err != nil {\r
557                 return CompositeAppMeta{}, pkgerrors.Errorf("Failed to get compositeApp meta")\r
558         }\r
559         datamap, ok := mi.(map[string]interface{})\r
560         if ok == false {\r
561                 return CompositeAppMeta{}, pkgerrors.Errorf("Failed to cast meta interface to compositeApp meta")\r
562         }\r
563 \r
564         p := fmt.Sprintf("%v", datamap["Project"])\r
565         ca := fmt.Sprintf("%v", datamap["CompositeApp"])\r
566         v := fmt.Sprintf("%v", datamap["Version"])\r
567         rn := fmt.Sprintf("%v", datamap["Release"])\r
568         dig := fmt.Sprintf("%v", datamap["DeploymentIntentGroup"])\r
569         namespace := fmt.Sprintf("%v", datamap["Namespace"])\r
570         level := fmt.Sprintf("%v", datamap["Level"])\r
571 \r
572         return CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rn, DeploymentIntentGroup: dig, Namespace: namespace, Level: level}, nil\r
573 }\r