Rsync & AppContext
Appcontext Data Format
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)
Creating AppContext
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
Creating AppContext
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.
Creating AppContext
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"
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