1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (c) 2020 Intel Corporation
10 log "github.com/open-ness/EMCO/src/orchestrator/pkg/infra/logutils"
11 "github.com/open-ness/EMCO/src/orchestrator/pkg/rtcontext"
12 pkgerrors "github.com/pkg/errors"
15 // metaPrefix used for denoting clusterMeta level
16 const metaGrpPREFIX = "!@#metaGrp"
18 type AppContext struct {
20 rtcObj rtcontext.RunTimeContext
21 rtc rtcontext.Rtcontext
24 // AppContextStatus represents the current status of the appcontext
25 // Instantiating - instantiate has been invoked and is still in progress
26 // Instantiated - instantiate has completed
27 // Terminating - terminate has been invoked and is still in progress
28 // Terminated - terminate has completed
29 // InstantiateFailed - the instantiate action has failed
30 // TerminateFailed - the terminate action has failed
31 type AppContextStatus struct {
34 type StatusValue string
35 type statuses struct {
36 Instantiating StatusValue
37 Instantiated StatusValue
38 Terminating StatusValue
39 Terminated StatusValue
40 InstantiateFailed StatusValue
41 TerminateFailed StatusValue
44 var AppContextStatusEnum = &statuses{
45 Instantiating: "Instantiating",
46 Instantiated: "Instantiated",
47 Terminating: "Terminating",
48 Terminated: "Terminated",
49 InstantiateFailed: "InstantiateFailed",
50 TerminateFailed: "TerminateFailed",
53 // CompositeAppMeta consists of projectName, CompositeAppName,
54 // CompositeAppVersion, ReleaseName. This shall be used for
55 // instantiation of a compositeApp
56 type CompositeAppMeta struct {
57 Project string `json:"Project"`
58 CompositeApp string `json:"CompositeApp"`
59 Version string `json:"Version"`
60 Release string `json:"Release"`
61 DeploymentIntentGroup string `json:"DeploymentIntentGroup"`
62 Namespace string `json:"Namespace"`
63 Level string `json:"Level"`
64 ChildContextIDs []string `json:"ChildContextIDs"`
68 func (ac *AppContext) InitAppContext() (interface{}, error) {
69 ac.rtcObj = rtcontext.RunTimeContext{}
71 return ac.rtc.RtcInit()
74 // Load app context that was previously created
75 func (ac *AppContext) LoadAppContext(cid interface{}) (interface{}, error) {
76 ac.rtcObj = rtcontext.RunTimeContext{}
78 return ac.rtc.RtcLoad(cid)
81 // CreateCompositeApp method returns composite app handle as interface.
82 func (ac *AppContext) CreateCompositeApp() (interface{}, error) {
83 h, err := ac.rtc.RtcCreate()
87 log.Info(":: CreateCompositeApp ::", log.Fields{"CompositeAppHandle": h})
91 // AddCompositeAppMeta adds the meta data associated with a composite app
92 func (ac *AppContext) AddCompositeAppMeta(meta interface{}) error {
93 err := ac.rtc.RtcAddMeta(meta)
100 // Deletes the entire context
101 func (ac *AppContext) DeleteCompositeApp() error {
102 h, err := ac.rtc.RtcGet()
106 err = ac.rtc.RtcDeletePrefix(h)
113 //Returns the handles for a given composite app context
114 func (ac *AppContext) GetCompositeAppHandle() (interface{}, error) {
115 h, err := ac.rtc.RtcGet()
122 // GetLevelHandle returns the handle for the supplied level at the given handle.
123 // For example, to get the handle of the 'status' level at a given handle.
124 func (ac *AppContext) GetLevelHandle(handle interface{}, level string) (interface{}, error) {
125 ach := fmt.Sprintf("%v%v/", handle, level)
126 hs, err := ac.rtc.RtcGetHandles(ach)
130 for _, v := range hs {
135 return nil, pkgerrors.Errorf("No handle was found for level %v", level)
138 //Add app to the context under composite app
139 func (ac *AppContext) AddApp(handle interface{}, appname string) (interface{}, error) {
140 h, err := ac.rtc.RtcAddLevel(handle, "app", appname)
144 log.Info(":: Added app handle ::", log.Fields{"AppHandle": h})
148 //Delete app from the context and everything underneth
149 func (ac *AppContext) DeleteApp(handle interface{}) error {
150 err := ac.rtc.RtcDeletePrefix(handle)
157 //Returns the handle for a given app
158 func (ac *AppContext) GetAppHandle(appname string) (interface{}, error) {
160 return nil, pkgerrors.Errorf("Not a valid run time context app name")
163 rh, err := ac.rtc.RtcGet()
168 apph := fmt.Sprintf("%v", rh) + "app/" + appname + "/"
169 hs, err := ac.rtc.RtcGetHandles(apph)
173 for _, v := range hs {
178 return nil, pkgerrors.Errorf("No handle was found for the given app")
181 // AddCluster helps to add cluster to the context under app. It takes in the app handle and clusterName as value.
182 func (ac *AppContext) AddCluster(handle interface{}, clustername string) (interface{}, error) {
183 h, err := ac.rtc.RtcAddLevel(handle, "cluster", clustername)
187 log.Info(":: Added cluster handle ::", log.Fields{"ClusterHandler": h})
191 // AddClusterMetaGrp adds the meta info of groupNumber to which a cluster belongs.
192 // It takes in cluster handle and groupNumber as arguments
193 func (ac *AppContext) AddClusterMetaGrp(ch interface{}, gn string) error {
194 mh, err := ac.rtc.RtcAddOneLevel(ch, metaGrpPREFIX, gn)
198 log.Info(":: Added cluster meta handle ::", log.Fields{"ClusterMetaHandler": mh})
202 // DeleteClusterMetaGrpHandle deletes the group number to which the cluster belongs, it takes in the cluster handle.
203 func (ac *AppContext) DeleteClusterMetaGrpHandle(ch interface{}) error {
204 err := ac.rtc.RtcDeletePrefix(ch)
208 log.Info(":: Deleted cluster meta handle ::", log.Fields{"ClusterMetaHandler": ch})
213 GetClusterMetaHandle takes in appName and ClusterName as string arguments and return the ClusterMetaHandle as string
215 func (ac *AppContext) GetClusterMetaHandle(app string, cluster string) (string, error) {
217 return "", pkgerrors.Errorf("Not a valid run time context app name")
220 return "", pkgerrors.Errorf("Not a valid run time context cluster name")
223 ch, err := ac.GetClusterHandle(app, cluster)
227 cmh := fmt.Sprintf("%v", ch) + metaGrpPREFIX + "/"
233 GetClusterGroupMap shall take in appName and return a map showing the grouping among the clusters.
234 sample output of "GroupMap" :{"1":["cluster_provider1+clusterName3","cluster_provider1+clusterName5"],"2":["cluster_provider2+clusterName4","cluster_provider2+clusterName6"]}
236 func (ac *AppContext) GetClusterGroupMap(an string) (map[string][]string, error) {
237 cl, err := ac.GetClusterNames(an)
239 log.Info(":: Unable to fetch clusterList for app ::", log.Fields{"AppName ": an})
242 rh, err := ac.rtc.RtcGet()
247 var gmap = make(map[string][]string)
248 for _, cn := range cl {
249 s := fmt.Sprintf("%v", rh) + "app/" + an + "/cluster/" + cn + "/" + metaGrpPREFIX + "/"
251 err = ac.rtc.RtcGetValue(s, &v)
253 log.Info(":: No group number for cluster ::", log.Fields{"cluster": cn, "Reason": err})
256 gn := fmt.Sprintf("%v", v)
257 log.Info(":: GroupNumber retrieved ::", log.Fields{"GroupNumber": gn})
259 cl, found := gmap[gn]
261 cl = make([]string, 0)
269 //Delete cluster from the context and everything underneth
270 func (ac *AppContext) DeleteCluster(handle interface{}) error {
271 err := ac.rtc.RtcDeletePrefix(handle)
278 //Returns the handle for a given app and cluster
279 func (ac *AppContext) GetClusterHandle(appname string, clustername string) (interface{}, error) {
281 return nil, pkgerrors.Errorf("Not a valid run time context app name")
283 if clustername == "" {
284 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")
287 rh, err := ac.rtc.RtcGet()
292 ach := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/"
293 hs, err := ac.rtc.RtcGetHandles(ach)
297 for _, v := range hs {
302 return nil, pkgerrors.Errorf("No handle was found for the given cluster")
305 //Returns a list of all clusters for a given app
306 func (ac *AppContext) GetClusterNames(appname string) ([]string, error) {
308 return nil, pkgerrors.Errorf("Not a valid run time context app name")
311 rh, err := ac.rtc.RtcGet()
316 prefix := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/"
317 hs, err := ac.rtc.RtcGetHandles(prefix)
319 return nil, pkgerrors.Errorf("Error getting handles for %v", prefix)
322 for _, h := range hs {
323 hstr := fmt.Sprintf("%v", h)
324 ks := strings.Split(hstr, prefix)
325 for _, k := range ks {
326 ck := strings.Split(k, "/")
327 if len(ck) == 2 && ck[1] == "" {
328 cs = append(cs, ck[0])
334 err = pkgerrors.New("Cluster list is empty")
335 log.Error("Cluster list is empty",
336 log.Fields{"clusters": cs})
342 //Add resource under app and cluster
343 func (ac *AppContext) AddResource(handle interface{}, resname string, value interface{}) (interface{}, error) {
344 h, err := ac.rtc.RtcAddResource(handle, resname, value)
348 log.Info(":: Added resource handle ::", log.Fields{"ResourceHandler": h})
353 //Return the handle for given app, cluster and resource name
354 func (ac *AppContext) GetResourceHandle(appname string, clustername string, resname string) (interface{}, error) {
356 return nil, pkgerrors.Errorf("Not a valid run time context app name")
358 if clustername == "" {
359 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")
362 rh, err := ac.rtc.RtcGet()
367 acrh := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/resource/" + resname + "/"
368 hs, err := ac.rtc.RtcGetHandles(acrh)
372 for _, v := range hs {
377 return nil, pkgerrors.Errorf("No handle was found for the given resource")
380 //Update the resource value using the given handle
381 func (ac *AppContext) UpdateResourceValue(handle interface{}, value interface{}) error {
382 return ac.rtc.RtcUpdateValue(handle, value)
385 //Return the handle for given app, cluster and resource name
386 func (ac *AppContext) GetResourceStatusHandle(appname string, clustername string, resname string) (interface{}, error) {
388 return nil, pkgerrors.Errorf("Not a valid run time context app name")
390 if clustername == "" {
391 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")
394 return nil, pkgerrors.Errorf("Not a valid run time context resource name")
397 rh, err := ac.rtc.RtcGet()
402 acrh := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/resource/" + resname + "/status/"
403 hs, err := ac.rtc.RtcGetHandles(acrh)
407 for _, v := range hs {
412 return nil, pkgerrors.Errorf("No handle was found for the given resource")
415 //GetResourceNames ... Returns a list of all resource names for a given app
416 func (ac *AppContext) GetResourceNames(appname string, clustername string) ([]string, error) {
418 return nil, pkgerrors.Errorf("Not a valid run time context app name")
420 if clustername == "" {
421 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")
424 rh, err := ac.rtc.RtcGet()
429 prefix := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/resource/"
430 hs, err := ac.rtc.RtcGetHandles(prefix)
432 return nil, pkgerrors.Errorf("Error getting handles for %v", prefix)
435 for _, h := range hs {
436 hstr := fmt.Sprintf("%v", h)
437 ks := strings.Split(hstr, prefix)
438 for _, k := range ks {
439 ck := strings.Split(k, "/")
440 if len(ck) == 2 && ck[1] == "" {
441 cs = append(cs, ck[0])
448 //Add instruction under given handle and type
449 func (ac *AppContext) AddInstruction(handle interface{}, level string, insttype string, value interface{}) (interface{}, error) {
450 if !(insttype == "order" || insttype == "dependency") {
451 log.Error("Not a valid app context instruction type", log.Fields{})
452 return nil, pkgerrors.Errorf("Not a valid app context instruction type")
454 if !(level == "app" || level == "resource" || level == "subresource") {
455 log.Error("Not a valid app context instruction level", log.Fields{})
456 return nil, pkgerrors.Errorf("Not a valid app context instruction level")
458 h, err := ac.rtc.RtcAddInstruction(handle, level, insttype, value)
460 log.Error("ac.rtc.RtcAddInstruction(handle, level, insttype, value)", log.Fields{"err": err})
463 log.Info(":: Added instruction handle ::", log.Fields{"InstructionHandler": h})
467 //Delete instruction under given handle
468 func (ac *AppContext) DeleteInstruction(handle interface{}) error {
469 err := ac.rtc.RtcDeletePair(handle)
476 //Returns the app instruction for a given instruction type
477 func (ac *AppContext) GetAppInstruction(insttype string) (interface{}, error) {
478 if !(insttype == "order" || insttype == "dependency") {
479 log.Error("Not a valid app context instruction type", log.Fields{})
480 return nil, pkgerrors.Errorf("Not a valid app context instruction type")
482 rh, err := ac.rtc.RtcGet()
484 log.Error("ac.rtc.RtcGet()", log.Fields{"err": err})
487 s := fmt.Sprintf("%v", rh) + "app/" + "instruction/" + insttype + "/"
488 log.Info("Getting app instruction", log.Fields{"s": s})
490 err = ac.rtc.RtcGetValue(s, &v)
492 log.Error("ac.rtc.RtcGetValue(s, &v)", log.Fields{"err": err})
498 //Update the instruction usign the given handle
499 func (ac *AppContext) UpdateInstructionValue(handle interface{}, value interface{}) error {
500 return ac.rtc.RtcUpdateValue(handle, value)
503 //Returns the resource instruction for a given instruction type
504 func (ac *AppContext) GetResourceInstruction(appname string, clustername string, insttype string) (interface{}, error) {
505 if !(insttype == "order" || insttype == "dependency") {
506 log.Error("Not a valid app context instruction type", log.Fields{})
507 return nil, pkgerrors.Errorf("Not a valid app context instruction type")
509 rh, err := ac.rtc.RtcGet()
511 log.Error("ac.rtc.RtcGet()", log.Fields{"err": err})
514 s := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/resource/instruction/" + insttype + "/"
516 err = ac.rtc.RtcGetValue(s, &v)
518 log.Error("ac.rtc.RtcGetValue(s, &v)", log.Fields{"err": err})
524 // AddLevelValue for holding a state object at a given level
525 // will make a handle with an appended "<level>/" to the key
526 func (ac *AppContext) AddLevelValue(handle interface{}, level string, value interface{}) (interface{}, error) {
527 h, err := ac.rtc.RtcAddOneLevel(handle, level, value)
531 log.Info(":: Added handle ::", log.Fields{"Handle": h})
536 // GetClusterStatusHandle returns the handle for cluster status for a given app and cluster
537 func (ac *AppContext) GetClusterStatusHandle(appname string, clustername string) (interface{}, error) {
539 return nil, pkgerrors.Errorf("Not a valid run time context app name")
541 if clustername == "" {
542 return nil, pkgerrors.Errorf("Not a valid run time context cluster name")
545 rh, err := ac.rtc.RtcGet()
550 acrh := fmt.Sprintf("%v", rh) + "app/" + appname + "/cluster/" + clustername + "/status/"
551 hs, err := ac.rtc.RtcGetHandles(acrh)
555 for _, v := range hs {
560 return nil, pkgerrors.Errorf("No handle was found for the given resource")
563 //UpdateStatusValue updates the status value with the given handle
564 func (ac *AppContext) UpdateStatusValue(handle interface{}, value interface{}) error {
565 return ac.rtc.RtcUpdateValue(handle, value)
568 //UpdateValue updates the state value with the given handle
569 func (ac *AppContext) UpdateValue(handle interface{}, value interface{}) error {
570 return ac.rtc.RtcUpdateValue(handle, value)
573 //Return all the handles under the composite app
574 func (ac *AppContext) GetAllHandles(handle interface{}) ([]interface{}, error) {
575 hs, err := ac.rtc.RtcGetHandles(handle)
582 //Returns the value for a given handle
583 func (ac *AppContext) GetValue(handle interface{}) (interface{}, error) {
585 err := ac.rtc.RtcGetValue(handle, &v)
592 // GetCompositeAppMeta returns the meta data associated with the compositeApp
593 // Its return type is CompositeAppMeta
594 func (ac *AppContext) GetCompositeAppMeta() (CompositeAppMeta, error) {
595 mi, err := ac.rtcObj.RtcGetMeta()
598 return CompositeAppMeta{}, pkgerrors.Errorf("Failed to get compositeApp meta")
600 datamap, ok := mi.(map[string]interface{})
602 return CompositeAppMeta{}, pkgerrors.Errorf("Failed to cast meta interface to compositeApp meta")
605 p := fmt.Sprintf("%v", datamap["Project"])
606 ca := fmt.Sprintf("%v", datamap["CompositeApp"])
607 v := fmt.Sprintf("%v", datamap["Version"])
608 rn := fmt.Sprintf("%v", datamap["Release"])
609 dig := fmt.Sprintf("%v", datamap["DeploymentIntentGroup"])
610 namespace := fmt.Sprintf("%v", datamap["Namespace"])
611 level := fmt.Sprintf("%v", datamap["Level"])
612 var childInterface []interface{}
613 childCtxs := make([]string, len(childInterface))
614 if datamap["ChildContextIDs"] != nil {
615 childInterface = datamap["ChildContextIDs"].([]interface{})
616 for _, v := range childInterface {
617 childCtxs = append(childCtxs, v.(string))
621 return CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rn, DeploymentIntentGroup: dig, Namespace: namespace, Level: level, ChildContextIDs: childCtxs}, nil