Table of Contents |
---|
...
The following figure depicts the hierarchical data store for runtime data. The notes in the figure is additional data stored in each type of node. Rsync uses this information to schedule resources. Status is updated by Rsync.
AppContext Library
To create and work with appcontext a library is provided: github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext
Creating AppContext Flow
The following example shows how to create an AppContext for a CompositeApp with one App. This pattern is used by controllers that are creating new AppContextID. Examples are Orchestrator, NCM(create networks), CLM(create clusters) and DCM(create logical clouds)
Code Block | ||||
---|---|---|---|---|
| ||||
import "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext" func createAppContextWithOneApp(appName string) { context := appcontext.AppContext{} ctxVal, err := context.InitAppContext() if err != nil { return nil } handle, err := context.CreateCompositeApp() if err != nil { return nil } // This is optional err = context.AddCompositeAppMeta(appcontext.CompositeAppMeta{Project: p, CompositeApp: ca, Version: v, Release: rName}) if err != nil { return nil } appHandle, err := context.AddApp(handle, appName) if err != nil { return nil } // Iterate through cluster list and add all the clusters for _, cluster := range clusterList { clusterName := strings.Join([]string{cluster.ClusterProvider, "+", cluster.ClusterName}, "") clusterHandle, err := context.AddCluster(appHandle, clusterName) if err != nil { return nil } // Add resource _, err = context.AddResource(clusterHandle, nameofRes1, resYaml1) if err != nil { return nil } // Add resource _, err = context.AddResource(clusterHandle, nameofRes2, resYaml2) if err != nil { return nil } // Add Resource Order resOrder, err := json.Marshal(map[string][]string{"resorder": []string{nameofRes1, nameofRes2}}) if err != nil { return nil } _, err = context.AddInstruction(clusterHandle, "resource", "order", string(resOrder)) if err != nil { return nil } } } |
Action Controller flow
Action controllers will follow the following pattern to add and update existing resources in AppContext. AppContextId is provided to the action controllers from the orchestrator using gRpc call. Examples are ovnAction controller
Code Block | ||||
---|---|---|---|---|
| ||||
import "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
func updateAppContext(appContextId string)
{
var context appcontext.AppContext
_, err = context.LoadAppContext(appContextId)
if err != nil {
return nil
}
// Get all clusters from the AppContext for an App
clusters, err := context.GetClusterNames("testApp")
for _, c := range clusters {
// Resources in AppContext are named is the format (ResourceName+ResourceType) "res3+Deployment"
appContextResName := strings.Join([]string{"resName", "Deployment"}, "+"
rh, err := context.GetResourceHandle("testApp", c, appContextResName )
if err != nil {
return err
}
r, err := context.GetValue(rh)
if err != nil {
return err
}
// Unmarshal resource extract the Kubernetes object definition
kubObj, err := runtime.Decode(scheme.Codecs.UniversalDeserializer(), []byte(r.(string)))
//Modify resource to add/modify existing contents
......
// Put back updated resource in AppContext
err = context.UpdateResourceValue(rh, updatedRes)
if err != nil {
return nil
}
}
|
Placement Controller flow
Placement controllers will follow the following pattern to select a cluster from group of clusters for an App. AppContextId is provided to the placement controllers from the orchestrator using gRpc call.
Code Block | ||||
---|---|---|---|---|
| ||||
func placement(appContextId string)
{
var context appcontext.AppContext
_, err = context.LoadAppContext(appContextId)
if err != nil {
return nil
}
// Get AppContext for an App
gmap, err := context.GetClusterGroupMap("testApp")
// sample output {"1":["cluster_provider1+clusterName3","cluster_provider1+clusterName5"],"2":["cluster_provider2+clusterName4","cluster_provider2+clusterName6"]}
for gr, cl := range gmap {
for i, cn := range cl {
// Based on the output decide which cluster is not suitable
.......
//Delete the cluster not suitable
ch, err := ct.GetClusterHandle(an, cn)
err = ct.DeleteCluster(ch)
}
}
}
|
RPC Communication
AppContext API
GoDoc: package appcontext // import "github.com/onap/multicloud-k8s/src/orchestrator/pkg/appcontext"
...
Code Block | ||
---|---|---|
| ||
func (ac *AppContext) CreateCompositeApp() (interface{}, error)
CreateCompositeApp method returns composite app handle as interface.
func (ac *AppContext) AddCompositeAppMeta(meta interface{}) error
AddCompositeAppMeta adds the meta data associated with a composite app
func (ac *AppContext) AddApp(handle interface{}, appname string) (interface{}, error)
Add app to the context under composite app
func (ac *AppContext) AddCluster(handle interface{}, clustername string) (interface{}, error)
AddCluster helps to add cluster to the context under app. It takes in the
app handle and clusterName as value.
func (ac *AppContext) AddClusterMetaGrp(ch interface{}, gn string) error
AddClusterMetaGrp adds the meta info of groupNumber to which a cluster
belongs. It takes in cluster handle and groupNumber as arguments. Used when
using AnyOf
func (ac *AppContext) AddResource(handle interface{}, resname string, value interface{}) (interface{}, error)
Add resource under app and cluster
func (ac *AppContext) AddInstruction(handle interface{}, level string, insttype string, value interface{}) (interface{}, error)
Add instruction under given handle and type
func (ac *AppContext) AddLevelValue(handle interface{}, level string, value interface{}) (interface{}, error)
AddLevelValue for holding a state object at a given level will make a handle
with an appended "<level>/" to the key
func (ac *AppContext) AddResource(handle interface{}, resname string, value interface{}) (interface{}, error)
Add resource under app and cluster
func (ac *AppContext) DeleteApp(handle interface{}) error
Delete app from the context and everything underneth
func (ac *AppContext) DeleteCluster(handle interface{}) error
Delete cluster from the context and everything underneath
func (ac *AppContext) DeleteClusterMetaGrpHandle(ch interface{}) error
DeleteClusterMetaGrpHandle deletes the group number to which the cluster
belongs, it takes in the cluster handle.
func (ac *AppContext) DeleteCompositeApp() error
Deletes the entire context
func (ac *AppContext) DeleteInstruction(handle interface{}) error
Delete instruction under given handle
func (ac *AppContext) GetAllHandles(handle interface{}) ([]interface{}, error)
Return all the handles under the composite app
func (ac *AppContext) GetAppHandle(appname string) (interface{}, error)
Returns the handle for a given app
func (ac *AppContext) GetAppInstruction(insttype string) (interface{}, error)
Returns the app instruction for a given instruction type
func (ac *AppContext) GetClusterGroupMap(an string) (map[string][]string, error)
GetClusterGroupMap shall take in appName and return a map showing the
grouping among the clusters. sample output of "GroupMap"
:{"1":["cluster_provider1+clusterName3","cluster_provider1+clusterName5"],"2":["cluster_provider2+clusterName4","cluster_provider2+clusterName6"]}
func (ac *AppContext) GetClusterHandle(appname string, clustername string) (interface{}, error)
Returns the handle for a given app and cluster
func (ac *AppContext) GetClusterMetaHandle(app string, cluster string) (string, error)
GetClusterMetaHandle takes in appName and ClusterName as string arguments
and return the ClusterMetaHandle as string
func (ac *AppContext) GetClusterNames(appname string) ([]string, error)
Returns a list of all clusters for a given app
func (ac *AppContext) GetClusterStatusHandle(appname string, clustername string) (interface{}, error)
GetClusterStatusHandle returns the handle for cluster status for a given app
and cluster
func (ac *AppContext) GetCompositeAppHandle() (interface{}, error)
Returns the handles for a given composite app context
func (ac *AppContext) GetCompositeAppMeta() (CompositeAppMeta, error)
GetCompositeAppMeta returns the meta data associated with the compositeApp
Its return type is CompositeAppMeta
func (ac *AppContext) GetLevelHandle(handle interface{}, level string) (interface{}, error)
GetLevelHandle returns the handle for the supplied level at the given
handle. For example, to get the handle of the 'status' level at a given
handle.
func (ac *AppContext) GetResourceHandle(appname string, clustername string, resname string) (interface{}, error)
Return the handle for given app, cluster and resource name
func (ac *AppContext) GetResourceInstruction(appname string, clustername string, insttype string) (interface{}, error)
Returns the resource instruction for a given instruction type
func (ac *AppContext) GetResourceStatusHandle(appname string, clustername string, resname string) (interface{}, error)
Return the handle for given app, cluster and resource name
func (ac *AppContext) GetValue(handle interface{}) (interface{}, error)
Returns the value for a given handle
func (ac *AppContext) InitAppContext() (interface{}, error)
Init app context
func (ac *AppContext) LoadAppContext(cid interface{}) (interface{}, error)
Load app context that was previously created
func (ac *AppContext) UpdateInstructionValue(handle interface{}, value interface{}) error
Update the instruction usign the given handle
func (ac *AppContext) UpdateResourceValue(handle interface{}, value interface{}) error
Update the resource value using the given handle
func (ac *AppContext) UpdateStatusValue(handle interface{}, value interface{}) error
UpdateStatusValue updates the status value with the given handle
func (ac *AppContext) UpdateValue(handle interface{}, value interface{}) error
UpdateValue updates the state value with the given handle
|
RSYNC registration outside of orchestration.
There have been use cases when we need to invoke RSYNC outside of orchestrator.
For such cases, we have provided a method - NewRsyncInfo()
This method directly takes in Rsync controller name, hostname and port number.
After that , we have a method initRsyncClient() which creates the required gRPC client connection.
Use the above two methods to register a rsync controller outside of orchestrator.
The relevant portion in the code is shown below :
File to import : orchestrator/pkg/grpc/installappclient/client.go
Code Block | ||||
---|---|---|---|---|
| ||||
func NewRsyncInfo(rName, h string, pN int) RsyncInfo { mutex.Lock() defer mutex.Unlock() rsyncInfo = RsyncInfo{RsyncName: rName, hostName: h, portNumber: pN} return rsyncInfo } |
Code Block | ||||
---|---|---|---|---|
| ||||
func initRsyncClient() bool {
if (RsyncInfo{}) == rsyncInfo {
mutex.Lock()
defer mutex.Unlock()
log.Error("RsyncInfo not set. InitRsyncClient failed", log.Fields{
"Rsyncname": rsyncInfo.RsyncName,
"Hostname": rsyncInfo.hostName,
"PortNumber": rsyncInfo.portNumber,
})
return false
}
rpc.UpdateRpcConn(rsyncInfo.RsyncName, rsyncInfo.hostName, rsyncInfo.portNumber)
return true
}
|