Unverified Commit 41e943fe authored by Kevin Di Lallo's avatar Kevin Di Lallo Committed by GitHub
Browse files

Merge pull request #222 from dilallkx/kd_sp11_dev_mgm

App Lifecycle: MG Manager support
parents 867e9d96 48f38ae1
Loading
Loading
Loading
Loading
+216 −105
Original line number Diff line number Diff line
@@ -85,6 +85,9 @@ const lbAlgoHopCount = "HOP-COUNT"
// const lbAlgoDistance = "DISTANCE"
// const lbAlgoNone = "NONE"

// MQ payload fields
const fieldEventType = "event-type"

type mgInfo struct {
	mg                  mgModel.MobilityGroup
	appInfoMap          map[string]*appInfo
@@ -144,17 +147,11 @@ type MgManager struct {
	activeModel  *mod.Model
	lbRulesStore *lbRulesStore

	// Scenario network location list
	// Scenario data
	netLocList   []string

	// Scenario service mappings
	svcInfoMap   map[string]*serviceInfo
	mgSvcInfoMap map[string]*mgServiceInfo

	// mapping from element name to svc name for usercharts
	svcToElemMap map[string]string
	elemToSvcMap map[string]string

	// Network Element Info mapping
	netElemInfoMap map[string]*netElemInfo

@@ -170,8 +167,6 @@ func Init() (err error) {
	mgm.netLocList = make([]string, 0)
	mgm.svcInfoMap = make(map[string]*serviceInfo)
	mgm.mgSvcInfoMap = make(map[string]*mgServiceInfo)
	mgm.svcToElemMap = make(map[string]string)
	mgm.elemToSvcMap = make(map[string]string)
	mgm.netElemInfoMap = make(map[string]*netElemInfo)
	mgm.mgInfoMap = make(map[string]*mgInfo)

@@ -222,7 +217,7 @@ func Init() (err error) {
	_ = mgm.lbRulesStore.rc.DBFlush(mgm.baseKey)

	// Initialize Edge-LB rules with current active scenario
	processActiveScenarioUpdate()
	processScenarioActivate()

	return nil
}
@@ -246,35 +241,67 @@ func msgHandler(msg *mq.Msg, userData interface{}) {
	switch msg.Message {
	case mq.MsgScenarioActivate:
		log.Debug("RX MSG: ", mq.PrintMsg(msg))
		processActiveScenarioUpdate()
		processScenarioActivate()
	case mq.MsgScenarioUpdate:
		log.Debug("RX MSG: ", mq.PrintMsg(msg))
		processActiveScenarioUpdate()
		eventType := msg.Payload[fieldEventType]
		processScenarioUpdate(eventType)
	case mq.MsgScenarioTerminate:
		log.Debug("RX MSG: ", mq.PrintMsg(msg))
		processActiveScenarioUpdate()
		processScenarioTerminate()
	default:
		log.Trace("Ignoring unsupported message: ", mq.PrintMsg(msg))
	}
}

func processActiveScenarioUpdate() {
func processScenarioActivate() {

	// Sync with active scenario store
	mgm.activeModel.UpdateScenario()

	scenarioName := mgm.activeModel.GetScenarioName()
	if mgm.scenarioName != scenarioName {
		mgm.scenarioName = scenarioName
		_ = httpLog.ReInit(moduleName, mgm.sandboxName, scenarioName, redisAddr, influxAddr)
	// Get scenario name
	mgm.scenarioName = mgm.activeModel.GetScenarioName()
	if mgm.scenarioName == "" {
		log.Error("Failed to find active scenario")
		return
	}

	// Handle empty/missing scenario
	if scenarioName == "" {
		clearScenario()
	// Initialize HTTP metrics logger with scenario name
	_ = httpLog.ReInit(moduleName, mgm.sandboxName, mgm.scenarioName, redisAddr, influxAddr)

	// Parse scenario
	err := processScenario(mgm.activeModel)
	if err != nil {
		log.Error("Failed to process scenario with error: ", err.Error())
		return
	}

	// Re-evaluate Network location Edge-LB mappings
	refreshNetLocAppMaps()

	// Re-evaluate MG Service mapping
	refreshMgSvcMapping()

	// Store & Apply latest MG Service mappings
	applyMgSvcMapping()

	// Inform TC Engine of LB rules updatge
	publishLbRulesUpdate()
}

func processScenarioUpdate(eventType string) {

	// Ignore unsupported update types
	switch eventType {
	case mod.EventMobility, mod.EventPoaInRange, mod.EventAddNode, mod.EventModifyNode, mod.EventRemoveNode:
		break
	default:
		return
	}

	// Sync with active scenario store
	mgm.activeModel.UpdateScenario()

	// Parse scenario
	err := processScenario(mgm.activeModel)
	if err != nil {
@@ -282,30 +309,48 @@ func processActiveScenarioUpdate() {
		return
	}

	// Set Default Edge-LB mapping
	setDefaultNetLocAppMaps()
	// Re-evaluate Network location Edge-LB mappings
	refreshNetLocAppMaps()

	// Re-evaluate MG Service mapping
	refreshMgSvcMapping()

	// Store & Apply latest MG Service mappings
	applyMgSvcMapping()

	// Inform TC Engine of LB rules updatge
	publishLbRulesUpdate()
}

func processScenarioTerminate() {

	// Sync with active scenario store
	mgm.activeModel.UpdateScenario()

	// Clear scenario data
	clearScenario()

	// Inform TC Engine of LB rules updatge
	publishLbRulesUpdate()
}

func clearScenario() {
	log.Debug("clearScenario() -- Resetting all variables")

	mgm.scenarioName = ""
	mgm.networkGraph = nil
	mgm.netLocList = make([]string, 0)
	mgm.svcInfoMap = make(map[string]*serviceInfo)
	mgm.mgSvcInfoMap = make(map[string]*mgServiceInfo)
	mgm.svcToElemMap = make(map[string]string)
	mgm.elemToSvcMap = make(map[string]string)
	mgm.netElemInfoMap = make(map[string]*netElemInfo)
	mgm.mgInfoMap = make(map[string]*mgInfo)

	// Flush module data and send update
	_ = mgm.lbRulesStore.rc.DBFlush(mgm.baseKey)
}

// publishLbRulesUpdate - Inform TC Engine of LB rules update
func publishLbRulesUpdate() {

	// Send LB Rules Update message
	msg := mgm.mqLocal.CreateMsg(mq.MsgMgLbRulesUpdate, moduleTcEngine, mgm.sandboxName)
@@ -319,12 +364,20 @@ func clearScenario() {
func processScenario(model *mod.Model) error {
	log.Debug("processScenario")

	// Reset service info maps
	mgm.svcInfoMap = make(map[string]*serviceInfo)
	mgm.mgSvcInfoMap = make(map[string]*mgServiceInfo)

	// Populate net location list
	mgm.netLocList = model.GetNodeNames(mod.NodeTypePoa, mod.NodeTypePoa4G, mod.NodeTypePoa5G, mod.NodeTypePoaWifi)
	mgm.netLocList = append(mgm.netLocList, model.GetNodeNames("DEFAULT")...)

	// Get list of processes
	procNames := model.GetNodeNames("CLOUD-APP", "EDGE-APP", "UE-APP")
	procNamesMap := make(map[string]bool)
	for _, procName := range procNames {
		procNamesMap[procName] = true
	}

	// Get network graph from model
	mgm.networkGraph = model.GetNetworkGraph()
@@ -394,6 +447,38 @@ func processScenario(model *mod.Model) error {
		}
	}

	// Remove stale elements
	for procName := range mgm.netElemInfoMap {
		if _, found := procNamesMap[procName]; !found {
			log.Debug("Removing stale element: ", procName)
			delete(mgm.netElemInfoMap, procName)
		}
	}

	// Remove stale Mobility Groups
	for mgName, mgInfo := range mgm.mgInfoMap {
		if _, found := mgm.mgSvcInfoMap[mgName]; !found {
			log.Debug("Removing stale MG: ", mgName)
			delete(mgm.mgInfoMap, mgName)
		} else {
			// Remove stale MG Apps
			for appName := range mgInfo.appInfoMap {
				if _, found := procNamesMap[appName]; !found {
					log.Debug("Removing stale MG App: ", appName)
					delete(mgInfo.appInfoMap, appName)
				}
			}
			// Remove stale UEs
			for ueName := range mgInfo.ueInfoMap {
				ueNodeType := model.GetNodeType(ueName)
				if ueNodeType != mod.NodeTypeUE {
					log.Debug("Removing stale UE: ", ueName)
					delete(mgInfo.ueInfoMap, ueName)
				}
			}
		}
	}

	return nil
}

@@ -433,8 +518,6 @@ func addServiceInfo(svcName string, mgSvcName string, nodeName string) {

	// Add service instance to service info map
	mgm.svcInfoMap[svcInfo.name] = svcInfo
	mgm.svcToElemMap[svcInfo.name] = svcInfo.name
	mgm.elemToSvcMap[svcInfo.name] = svcInfo.name
}

func getNetElem(name string) *netElemInfo {
@@ -452,47 +535,57 @@ func getNetElem(name string) *netElemInfo {
	return netElem
}

func setDefaultNetLocAppMaps() {
	log.Debug("setDefaultNetLocAppMaps")
// refreshNetLocAppMaps - Update all default & current network location application maps
func refreshNetLocAppMaps() {
	log.Debug("refreshNetLocAppMaps")

	// For each MG Service & net location in scenario, use Group App instances from scenario and
	// default LB algorithm to determine which App instance is best for net location
	// For each mobility group, update the application maps
	for _, mgInfo := range mgm.mgInfoMap {
		// Only set on first pass
		if len(mgInfo.defaultNetLocAppMap) == 0 {
			for _, netLoc := range mgm.netLocList {
				mgInfo.defaultNetLocAppMap[netLoc] = runLbAlgoHopCount(mgm.mgSvcInfoMap[mgInfo.mg.Name].services, netLoc)
		// Refresh default Network Location App map
		refreshDefaultNetLocAppMap(mgInfo)

		// Refresh current Network Location App map
		refreshNetLocAppMap(mgInfo)
	}
}

// refreshDefaultNetLocAppMap - Update default network location application map for a single application
func refreshDefaultNetLocAppMap(mgInfo *mgInfo) {
	log.Debug("refreshDefaultNetLocAppMap: ", mgInfo.mg.Name)

	// Use default LB algorithm to determine which App instance is best for each net location
	defaultNetLocAppMap := make(map[string]string)
	for _, netLoc := range mgm.netLocList {
		curLbSvc := mgInfo.defaultNetLocAppMap[netLoc]
		defaultNetLocAppMap[netLoc] = runLbAlgoHopCount(mgm.mgSvcInfoMap[mgInfo.mg.Name].services, netLoc, curLbSvc)
	}
	mgInfo.defaultNetLocAppMap = defaultNetLocAppMap
}

// refreshNetLocAppMap - Update current network location application map for a single application
func refreshNetLocAppMap(mgInfo *mgInfo) {
	log.Debug("refreshNetLocAppMap")

	// Reset Net Loc App map
	mgInfo.netLocAppMap = make(map[string]string)
	log.Debug("refreshNetLocAppMap: ", mgInfo.mg.Name)

	// Retrieve list of registered app services
	var mgApps = map[string]*serviceInfo{}
	for _, appInfo := range mgInfo.appInfoMap {
		mgApps[appInfo.app.Id] = mgm.svcInfoMap[appInfo.app.Id]
		if mgApps[appInfo.app.Id] == nil {

			mgApps[appInfo.app.Id] = mgm.svcInfoMap[mgm.svcToElemMap[appInfo.app.Id]]
		}
	}

	// Refresh current Network Location App map
	// For each net location in scenario, use Group LB algorithm to determine which
	// registered Group App is best for net location
	netLocAppMap := make(map[string]string)
	for _, netLoc := range mgm.netLocList {
		if mgInfo.mg.LoadBalancingAlgorithm == lbAlgoHopCount {
			mgInfo.netLocAppMap[netLoc] = runLbAlgoHopCount(mgApps, netLoc)
			curLbSvc := mgInfo.netLocAppMap[netLoc]
			netLocAppMap[netLoc] = runLbAlgoHopCount(mgApps, netLoc, curLbSvc)
		} else {
			log.Error("LB algorithm not yet supported: ", mgInfo.mg.LoadBalancingAlgorithm)
			break
		}
	}
	mgInfo.netLocAppMap = netLocAppMap
}

func refreshMgSvcMapping() {
@@ -533,7 +626,7 @@ func refreshMgSvcMapping() {
				// notification and update mapping
				if bestApp != currentApp {
					log.Info("Best App: " + bestApp + " != Current App: " + currentApp)
					completeStateTransfer(mgInfo, netElemInfo, ueInfo, mgm.elemToSvcMap[currentApp])
					completeStateTransfer(mgInfo, netElemInfo, ueInfo, currentApp)
					setSvcMap(netElemInfo, mgInfo.mg.Name, bestApp)
				}

@@ -557,7 +650,7 @@ func refreshMgSvcMapping() {
				// notification and update mapping
				if bestApp != currentApp {
					log.Info("Best App: " + bestApp + " != Current App: " + currentApp)
					completeStateTransfer(mgInfo, netElemInfo, ueInfo, mgm.elemToSvcMap[currentApp])
					completeStateTransfer(mgInfo, netElemInfo, ueInfo, currentApp)
					setSvcMap(netElemInfo, mgInfo.mg.Name, bestApp)
				}

@@ -596,7 +689,8 @@ func setSvcMap(netElemInfo *netElemInfo, mgSvcName string, lbSvcName string) {
// LB Algorithm:
//   - Compare hop count from current pod to each instance
//   - Choose closest instance
func runLbAlgoHopCount(services map[string]*serviceInfo, elem string) string {
//   - Prefer current instance when hop counts equal
func runLbAlgoHopCount(services map[string]*serviceInfo, elem string, curLbSvc string) string {
	var minDist int64 = -1
	var lbSvc = ""

@@ -607,7 +701,7 @@ func runLbAlgoHopCount(services map[string]*serviceInfo, elem string) string {
		path, _ := mgm.networkGraph.Shortest(src, dst)

		// Store as LB service if closest service instance
		if lbSvc == "" || path.Distance < minDist {
		if lbSvc == "" || path.Distance < minDist || (path.Distance == minDist && svc.name == curLbSvc) {
			minDist = path.Distance
			lbSvc = svc.name
		}
@@ -624,8 +718,13 @@ func startStateTransfer(group *mgInfo, elem *netElemInfo, ue *ueInfo, app string
		event.Type_ = eventTypeStateTransferStart
		event.UeId = ue.ue.Id
		startTime := time.Now()
		appInfo := group.appInfoMap[app]
		if appInfo == nil {
			log.Error("App not found: ", app)
			return
		}
		//lint:ignore SA1012 context.TODO not supported here
		resp, err := group.appInfoMap[app].appClient.StateTransferApi.HandleEvent(nil, event)
		resp, err := appInfo.appClient.StateTransferApi.HandleEvent(nil, event)
		duration := float64(time.Since(startTime).Microseconds()) / 1000.0
		if err != nil {
			log.Error(err.Error())
@@ -648,8 +747,13 @@ func completeStateTransfer(group *mgInfo, elem *netElemInfo, ue *ueInfo, app str
		event.Type_ = eventTypeStateTransferComplete
		event.UeId = ue.ue.Id
		startTime := time.Now()
		appInfo := group.appInfoMap[app]
		if appInfo == nil {
			log.Error("App not found: ", app)
			return
		}
		//lint:ignore SA1012 context.TODO not supported here
		resp, err := group.appInfoMap[app].appClient.StateTransferApi.HandleEvent(nil, event)
		resp, err := appInfo.appClient.StateTransferApi.HandleEvent(nil, event)
		duration := float64(time.Since(startTime).Microseconds()) / 1000.0
		if err != nil {
			log.Error(err.Error())
@@ -659,7 +763,7 @@ func completeStateTransfer(group *mgInfo, elem *netElemInfo, ue *ueInfo, app str
		met.ObserveNotification(mgm.sandboxName, serviceName, notifStateTransferComplete, "", resp, duration)
	}()

	// Set flag indicating transfer has been started
	// Set flag indicating transfer has been completed
	elem.transferInProgress = false
}

@@ -672,8 +776,13 @@ func cancelStateTransfer(group *mgInfo, elem *netElemInfo, ue *ueInfo, app strin
		event.Type_ = eventTypeStateTransferCancel
		event.UeId = ue.ue.Id
		startTime := time.Now()
		appInfo := group.appInfoMap[app]
		if appInfo == nil {
			log.Error("App not found: ", app)
			return
		}
		//lint:ignore SA1012 context.TODO not supported here
		resp, err := group.appInfoMap[app].appClient.StateTransferApi.HandleEvent(nil, event)
		resp, err := appInfo.appClient.StateTransferApi.HandleEvent(nil, event)
		duration := float64(time.Since(startTime).Microseconds()) / 1000.0
		if err != nil {
			log.Error(err.Error())
@@ -723,22 +832,12 @@ func applyMgSvcMapping() {
		log.Error(err.Error())
		return
	}

	// Send LB Rules Update message
	msg := mgm.mqLocal.CreateMsg(mq.MsgMgLbRulesUpdate, moduleTcEngine, mgm.sandboxName)
	log.Debug("TX MSG: ", mq.PrintMsg(msg))
	err = mgm.mqLocal.SendMsg(msg)
	if err != nil {
		log.Error("Failed to send message. Error: ", err.Error())
	}
}

func mgCreate(mg *mgModel.MobilityGroup) error {
	// Make sure group does not already exist
	if mgm.mgInfoMap[mg.Name] != nil {
		log.Warn("Mobility group already exists: ", mg.Name)
		err := errors.New("Mobility group already exists")
		return err
		return errors.New("Mobility group already exists")
	}

	// Create new Mobility Group & copy data
@@ -760,8 +859,8 @@ func mgUpdate(mg *mgModel.MobilityGroup) error {
	// Make sure group exists
	mgInfo := mgm.mgInfoMap[mg.Name]
	if mgInfo == nil {
		log.Error("Mobility group does not exist: ", mg.Name)
		err := errors.New("Mobility group does not exist")
		err := errors.New("Mobility group does not exist: " + mg.Name)
		log.Error(err.Error())
		return err
	}

@@ -775,8 +874,8 @@ func mgUpdate(mg *mgModel.MobilityGroup) error {
func mgDelete(mgName string) error {
	// Make sure group exists
	if mgm.mgInfoMap[mgName] == nil {
		log.Error("Mobility group does not exist: ", mgName)
		err := errors.New("Mobility group does not exist")
		err := errors.New("Mobility group does not exist: " + mgName)
		log.Error(err.Error())
		return err
	}

@@ -791,14 +890,20 @@ func mgAppCreate(mgName string, mgApp *mgModel.MobilityGroupApp) error {
	// Make sure group exists
	mgInfo := mgm.mgInfoMap[mgName]
	if mgInfo == nil {
		log.Error("Mobility group does not exist: ", mgName)
		err := errors.New("Mobility group does not exist")
		err := errors.New("Mobility group does not exist: " + mgName)
		log.Error(err.Error())
		return err
	}
	// Make sure App does not already exist
	if mgInfo.appInfoMap[mgApp.Id] != nil {
		log.Error("Mobility group App already exists: ", mgApp.Id)
		err := errors.New("Mobility group App already exists")
		err := errors.New("Mobility group App already exists: " + mgApp.Id)
		log.Error(err.Error())
		return err
	}
	// Make sure App ID is equal to a service instance
	if mgm.svcInfoMap[mgApp.Id] == nil {
		err := errors.New("MG App ID not equal to service instance: " + mgApp.Id)
		log.Error(err.Error())
		return err
	}

@@ -819,6 +924,8 @@ func mgAppCreate(mgName string, mgApp *mgModel.MobilityGroupApp) error {
	// Add to MG App map & App client map
	mgInfo.appInfoMap[mgApp.Id] = mgAppInfo
	log.Info("Created new MG App: " + mgApp.Id + " in group: " + mgName)

	// Re-evaluate MG best app instance for each scenario network location
	refreshNetLocAppMap(mgInfo)

	// Re-evaluate MG Service mapping
@@ -827,6 +934,9 @@ func mgAppCreate(mgName string, mgApp *mgModel.MobilityGroupApp) error {
	// Store & Apply latest MG Service mappings
	applyMgSvcMapping()

	// Inform TC Engine of LB rules updatge
	publishLbRulesUpdate()

	return nil
}

@@ -834,15 +944,15 @@ func mgAppUpdate(mgName string, mgApp *mgModel.MobilityGroupApp) error {
	// Make sure group exists
	mgInfo := mgm.mgInfoMap[mgName]
	if mgInfo == nil {
		log.Error("Mobility group does not exist: ", mgName)
		err := errors.New("Mobility group does not exist")
		err := errors.New("Mobility group does not exist: " + mgName)
		log.Error(err.Error())
		return err
	}
	// Make sure App exists
	mgAppInfo := mgInfo.appInfoMap[mgApp.Id]
	if mgAppInfo == nil {
		log.Error("Mobility group App does not exist: ", mgApp.Id)
		err := errors.New("Mobility group App does not exist")
		err := errors.New("Mobility group App does not exist: " + mgApp.Id)
		log.Error(err.Error())
		return err
	}

@@ -854,8 +964,8 @@ func mgAppUpdate(mgName string, mgApp *mgModel.MobilityGroupApp) error {
	mgAppClientCfg.BasePath = mgApp.Url
	mgAppInfo.appClient = mga.NewAPIClient(mgAppClientCfg)
	if mgAppInfo.appClient == nil {
		log.Error("Failed to create MG App REST API client: ", mgAppClientCfg.BasePath)
		err := errors.New("Failed to create MG App REST API client")
		err := errors.New("Failed to create MG App REST API client: " + mgAppClientCfg.BasePath)
		log.Error(err.Error())
		return err
	}

@@ -867,20 +977,22 @@ func mgAppDelete(mgName string, appID string) error {
	// Make sure group exists
	mgInfo := mgm.mgInfoMap[mgName]
	if mgInfo == nil {
		log.Error("Mobility group does not exist: ", mgName)
		err := errors.New("Mobility group does not exist")
		err := errors.New("Mobility group does not exist: " + mgName)
		log.Error(err.Error())
		return err
	}
	// Make sure App exists
	if mgInfo.appInfoMap[appID] == nil {
		log.Error("Mobility group App does not exist: ", appID)
		err := errors.New("Mobility group App does not exist")
		err := errors.New("Mobility group App does not exist: " + appID)
		log.Error(err.Error())
		return err
	}

	// Remove entry from App map & App Client map
	delete(mgInfo.appInfoMap, appID)
	log.Info("Deleted MG App: " + appID + " in group: " + mgName)

	// Re-evaluate MG best app instance for each scenario network location
	refreshNetLocAppMap(mgInfo)

	return nil
@@ -890,14 +1002,21 @@ func mgUeCreate(mgName string, appID string, mgUe *mgModel.MobilityGroupUe) erro
	// Make sure group exists
	mgInfo := mgm.mgInfoMap[mgName]
	if mgInfo == nil {
		log.Error("Mobility group does not exist: ", mgName)
		err := errors.New("Mobility group does not exist")
		err := errors.New("Mobility group does not exist: " + mgName)
		log.Error(err.Error())
		return err
	}
	// Make sure App exists
	if mgInfo.appInfoMap[appID] == nil {
		log.Error("Mobility group App does not exist: ", appID)
		err := errors.New("Mobility group App does not exist")
		err := errors.New("Mobility group App does not exist: " + appID)
		log.Error(err.Error())
		return err
	}
	// Make sure UE is in active scenario
	ueNodeType := mgm.activeModel.GetNodeType(mgUe.Id)
	if ueNodeType != mod.NodeTypeUE {
		err := errors.New("MG UE ID not found in active scenario: " + mgUe.Id)
		log.Error(err.Error())
		return err
	}

@@ -915,6 +1034,9 @@ func mgUeCreate(mgName string, appID string, mgUe *mgModel.MobilityGroupUe) erro

		// Store & Apply latest MG Service mappings
		applyMgSvcMapping()

		// Inform TC Engine of LB rules updatge
		publishLbRulesUpdate()
	}
	return nil
}
@@ -925,23 +1047,22 @@ func processAppState(mgName string, appID string, mgAppState *mgModel.MobilityGr
	// Retrieve MG info
	mgInfo := mgm.mgInfoMap[mgName]
	if mgInfo == nil {
		log.Error("Mobility group does not exist: ", mgName)
		err := errors.New("Mobility group does not exist")
		err := errors.New("Mobility group does not exist: " + mgName)
		log.Error(err.Error())
		return err
	}
	// Retrieve App info
	appInfo := mgInfo.appInfoMap[appID]

	if appInfo == nil {
		log.Error("Mobility group App does not exist: ", appID)
		err := errors.New("Mobility group App does not exist")
		err := errors.New("Mobility group App does not exist: " + appID)
		log.Error(err.Error())
		return err
	}
	// Retrieve UE Info
	ueInfo := mgInfo.ueInfoMap[mgAppState.UeId]
	if ueInfo == nil {
		log.Error("Mobility group UE does not exist: ", mgAppState.UeId)
		err := errors.New("Mobility group UE does not exist")
		err := errors.New("Mobility group UE does not exist: " + mgAppState.UeId)
		log.Error(err.Error())
		return err
	}

@@ -955,8 +1076,6 @@ func processAppState(mgName string, appID string, mgAppState *mgModel.MobilityGr

	mgm.mutex.Lock()
	for appName := range ueInfo.appsInRange {
		appName = mgm.elemToSvcMap[appName]

		if appName != appID {
			appInfo := mgInfo.appInfoMap[appName]
			if appInfo == nil {
@@ -1432,14 +1551,6 @@ func mgTransferAppState(w http.ResponseWriter, r *http.Request) {
// 			log.Debug("         " + k)
// 		}
// 	}
// 	log.Debug("+++ svcToElemMap:")
// 	for k, v := range mgm.svcToElemMap {
// 		log.Debug("   " + k + ":" + v)
// 	}
// 	log.Debug("+++ elemToSvcMap:")
// 	for k, v := range mgm.elemToSvcMap {
// 		log.Debug("   " + k + ":" + v)
// 	}
// 	log.Debug("+++ netElemInfoMap:")
// 	for netElemName, netElemInfo := range mgm.netElemInfoMap {
// 		log.Debug("   " + netElemName + ":")
+3 −50
Original line number Diff line number Diff line
@@ -674,7 +674,6 @@ func sendEventPoasInRange(event dataModel.Event) (error, int, string) {
		err := errors.New("Malformed request: missing EventPoasInRange")
		return err, http.StatusBadRequest, ""
	}
	var ue *dataModel.PhysicalLocation

	// Retrieve UE name
	ueName := event.EventPoasInRange.Ue
@@ -685,41 +684,9 @@ func sendEventPoasInRange(event dataModel.Event) (error, int, string) {

	description := "[" + ueName + "] poas in range: " + strings.Join(poasInRange, ", ")

	// Find UE
	log.Debug("Searching for UE in active scenario")
	n := sbxCtrl.activeModel.GetNode(ueName)
	if n == nil {
		err := errors.New("Node not found " + ueName)
		return err, http.StatusNotFound, ""
	}
	ue, ok := n.(*dataModel.PhysicalLocation)
	if !ok {
		ue = nil
	} else if ue.Type_ != "UE" {
		ue = nil
	}

	// Update POAS in range if necessary
	if ue != nil {
		log.Debug("UE Found. Checking for update to visible POAs")

		// Compare new list of poas with current UE list and update if necessary
		if !equal(poasInRange, ue.NetworkLocationsInRange) {
			log.Debug("Updating POAs in range for UE: " + ue.Name)
			ue.NetworkLocationsInRange = poasInRange

			//Publish updated scenario
			err := sbxCtrl.activeModel.Activate()
	// Update active model
	err := sbxCtrl.activeModel.UpdatePoasInRange(ueName, poasInRange, nil)
	if err != nil {
				return err, http.StatusInternalServerError, ""
			}

			log.Debug("Active scenario updated")
		} else {
			log.Debug("POA list unchanged. Ignoring.")
		}
	} else {
		err := errors.New("Failed to find UE")
		return err, http.StatusNotFound, ""
	}
	return nil, -1, description
@@ -786,20 +753,6 @@ func getScenarioNodeName(node *dataModel.ScenarioNode) string {
	return name
}

// Equal tells whether a and b contain the same elements.
// A nil argument is equivalent to an empty slice.
func equal(a, b []string) bool {
	if len(a) != len(b) {
		return false
	}
	for i, v := range a {
		if v != b[i] {
			return false
		}
	}
	return true
}

func ceCreateReplayFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("ceCreateReplayFile")
	vars := mux.Vars(r)
+19 −0
Original line number Diff line number Diff line
@@ -32,6 +32,17 @@ const typeMeSvc string = "ME-SVC"
const typeIngressSvc string = "INGRESS-SVC"
const typeEgressSvc string = "EGRESS-SVC"

const fieldSvcType string = "svc-type"
const fieldSvcName string = "svc-name"
const fieldSvcIp string = "svc-ip"
const fieldSvcProtocol string = "svc-protocol"
const fieldSvcPort string = "svc-port"
const fieldLbSvcName string = "lb-svc-name"
const fieldLbSvcIp string = "lb-svc-ip"
const fieldLbSvcPort string = "lb-svc-port"
const fieldLbPodName string = "lb-pod-name"
const fieldLbPodIp string = "lb-pod-ip"

const DEFAULT_LB_RULES_DB = 0

// LbRulesStore -
@@ -96,6 +107,8 @@ func (re *RoutingEngine) RefreshLbRules() {
		for _, svcMap := range netElem.ServiceMaps {
			if svcInfo, found := svcInfoMap[svcMap.LbSvcName]; found {
				podInfo.MgSvcMap[svcMap.MgSvcName] = svcInfo
			} else {
				log.Error("failed to find service instance: ", svcMap.LbSvcName)
			}
		}
	}
@@ -141,6 +154,8 @@ func (re *RoutingEngine) applyLbRules() {
				fields[fieldLbSvcName] = svcInfo.Name
				fields[fieldLbSvcIp] = tce.ipManager.GetSvcIp(svcInfo.Name)
				fields[fieldLbSvcPort] = portInfo.Port
				fields[fieldLbPodName] = svcInfo.Node
				fields[fieldLbPodIp] = tce.ipManager.GetPodIp(svcInfo.Node)

				// Make unique key
				key := tce.netCharStore.baseKey + typeLb + ":" + podInfo.Name + ":" +
@@ -176,6 +191,8 @@ func (re *RoutingEngine) applyLbRules() {
			fields[fieldLbSvcName] = svcInfo.Name
			fields[fieldLbSvcIp] = tce.ipManager.GetSvcIp(svcInfo.Name)
			fields[fieldLbSvcPort] = svcMap.SvcPort
			fields[fieldLbPodName] = svcInfo.Node
			fields[fieldLbPodIp] = tce.ipManager.GetPodIp(svcInfo.Node)

			// Make unique key
			key := tce.netCharStore.baseKey + typeLb + ":" + podInfo.Name + ":" +
@@ -198,6 +215,8 @@ func (re *RoutingEngine) applyLbRules() {
			fields[fieldLbSvcName] = svcMap.SvcName
			fields[fieldLbSvcIp] = svcMap.SvcIp
			fields[fieldLbSvcPort] = svcMap.SvcPort
			fields[fieldLbPodName] = "n/a"
			fields[fieldLbPodIp] = IP_ADDR_NONE

			// Make unique key
			key := tce.netCharStore.baseKey + typeLb + ":" + podInfo.Name + ":" +
+0 −9
Original line number Diff line number Diff line
@@ -40,15 +40,6 @@ const tcEngineKey string = "tc-engine:"
const mgManagerKey string = "mg-manager:"
const typeNet string = "net"

const fieldSvcType string = "svc-type"
const fieldSvcName string = "svc-name"
const fieldSvcIp string = "svc-ip"
const fieldSvcProtocol string = "svc-protocol"
const fieldSvcPort string = "svc-port"
const fieldLbSvcName string = "lb-svc-name"
const fieldLbSvcIp string = "lb-svc-ip"
const fieldLbSvcPort string = "lb-svc-port"

// MQ payload fields
const fieldEventType = "event-type"

+2 −8
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ func (u *destination) compute() (st stat) {
	return
}

func (u *destination) processRxTx(ifbStatsStr string) float64 {
func (u *destination) processRxTx(ifbStatsStr string, curTime time.Time) float64 {

	// Retrieve ifb statistics from passed string
	// NOTE: we have to read the ifbStats from the back since based on the results are always at
@@ -164,9 +164,6 @@ func (u *destination) processRxTx(ifbStatsStr string) float64 {
		log.Error("Error in the ifb statistics output: ", ifbStats)
	}

	// Get timestamp for calculations
	curTime := time.Now()

	// Calculate throughput in Mbps
	var tput float64
	rxBytes := curRxBytes - u.prevRx.rxBytes
@@ -182,7 +179,7 @@ func (u *destination) processRxTx(ifbStatsStr string) float64 {
	return tput
}

func (u *destination) logRxTx(ifbStatsStr string) {
func (u *destination) logRxTx(ifbStatsStr string, curTime time.Time) {

	// Retrieve ifb statistics from passed string
	// NOTE: we have to read the ifbStats from the back since based on the results are always at
@@ -199,9 +196,6 @@ func (u *destination) logRxTx(ifbStatsStr string) {
		log.Error("Error in the ifb statistics output: ", ifbStats)
	}

	// Get timestamp for calculations
	curTime := time.Now()

	// Calculate packet loss percentage
	var loss float64
	rxPkt := curRxPkt - u.prevRxLog.rxPkt
Loading