Commit 3f7db7ba authored by Yann Garcia's avatar Yann Garcia
Browse files

Enhance GIS engine to support simu5g

parent 8c563a42
Loading
Loading
Loading
Loading
+36 −8
Changes for go-apps/meep-sandbox-api/server/sandbox_api.go: 36 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -891,14 +891,7 @@ func sandboxNetworkScenarioPOST(w http.ResponseWriter, r *http.Request) {
		return
	}

	_, err = sandboxApiConnectors.gisClient[sandbox_name].AutomationApi.SetAutomationStateByName(context.TODO(), "MOVEMENT", true)
	if err != nil {
		log.Error(err.Error())
		errHandlerProblemDetails(w, err.Error(), http.StatusInternalServerError)
		return
	}
	_, err = sandboxApiConnectors.gisClient[sandbox_name].AutomationApi.SetAutomationStateByName(context.TODO(), "MOBILITY", true)
	if err != nil {
	if err := applyGisAutomationAfterActivate(sandbox_name); err != nil {
		log.Error(err.Error())
		errHandlerProblemDetails(w, err.Error(), http.StatusInternalServerError)
		return
@@ -1602,3 +1595,38 @@ func parseUes(scenario sandboxCtrlClient.Scenario) (ues map[string][]sandboxCtrl

	return ues, ues_count, nil
}

func usesExternalNwSimulator() bool {
	t := strings.ToLower(strings.TrimSpace(os.Getenv("MEEP_NW_SIMULATOR_TYPE")))
	return t == "simu5g" || t == "oai"
}

func applyGisAutomationAfterActivate(sandboxName string) error {
	gisClient := sandboxApiConnectors.gisClient[sandboxName]
	if gisClient == nil {
		return errors.New("GIS client not found")
	}
	movement := true
	poasInRange := false
	if usesExternalNwSimulator() {
		movement = false
		poasInRange = true
	}
	if _, err := gisClient.AutomationApi.SetAutomationStateByName(context.TODO(), "MOVEMENT", movement); err != nil {
		return err
	}
	if _, err := gisClient.AutomationApi.SetAutomationStateByName(context.TODO(), "MOBILITY", true); err != nil {
		return err
	}
	if usesExternalNwSimulator() {
		if _, err := gisClient.AutomationApi.SetAutomationStateByName(context.TODO(), "NETWORK-CHARACTERISTICS-UPDATE", false); err != nil {
			return err
		}
	}
	if poasInRange {
		if _, err := gisClient.AutomationApi.SetAutomationStateByName(context.TODO(), "POAS-IN-RANGE", true); err != nil {
			return err
		}
	}
	return nil
}
+2 −0
Changes for go-apps/meep-sandbox-ctrl/go.mod: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ require (
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-metrics v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-model v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mq v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-nw-simu-catalog v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-pdu-session-store v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-redis v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-replay-manager v0.0.0
@@ -34,6 +35,7 @@ replace (
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-metrics => ../../go-packages/meep-metrics
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-model => ../../go-packages/meep-model
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mq => ../../go-packages/meep-mq
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-nw-simu-catalog => ../../go-packages/meep-nw-simu-catalog
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-pdu-session-store => ../../go-packages/meep-pdu-session-store
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-redis => ../../go-packages/meep-redis
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-replay-manager => ../../go-packages/meep-replay-manager
+49 −3
Changes for go-apps/meep-sandbox-ctrl/server/sandbox-ctrl.go: 49 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import (
	met "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-metrics"
	mod "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-model"
	mq "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mq"
	nwcat "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-nw-simu-catalog"
	pss "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-pdu-session-store"
	replay "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-replay-manager"
	ss "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-sandbox-store"
@@ -61,6 +62,8 @@ type SandboxCtrl struct {
	replayMgr         *replay.ReplayMgr
	pduSessionStore   *pss.PduSessionStore
	sandboxStore      *ss.SandboxStore
	nwCatalog         *nwcat.Client
	nemInstance       *nwcat.Instance
	gracefulRemoveMap map[string]chan bool
	mutex             sync.Mutex
}
@@ -118,6 +121,13 @@ func Init() (err error) {
	}
	log.Info("MEEP_SANDBOX_NAME: ", sbxCtrl.sandboxName)

	nwCfg := nwcat.FromEnv()
	sbxCtrl.nwCatalog = nwcat.New(nwCfg, nil)
	log.Info("MEEP_NW_SIMULATOR_TYPE: ", nwCfg.Type)
	log.Info("MEEP_NEM_URL: ", nwCfg.NemURL)
	log.Info("MEEP_NEM_TIMEOUT_MS: ", nwCfg.TimeoutMs)
	log.Info("MEEP_NEM_ACTIVATE_TIMEOUT_MS: ", nwCfg.ActivateTimeoutMs)

	// Create Global message queue
	sbxCtrl.mqGlobal, err = mq.NewMsgQueue(mq.GetGlobalName(), moduleName, sbxCtrl.sandboxName, redisDBAddr)
	if err != nil {
@@ -253,6 +263,8 @@ func Stop() (err error) {
		return
	}

	sbxCtrl.deleteNemInstance()

	if sbxCtrl.apiMgr != nil {
		// Stop Swagger API Manager
		_ = sbxCtrl.apiMgr.Stop()
@@ -286,15 +298,25 @@ func activateScenario(scenarioName string) (err error) {
	}

	// Make sure scenario is not already deployed
	if sbxCtrl.activeModel.Active {
	if sbxCtrl.scenarioAlreadyActive() {
		err = errors.New("Scenario already active")
		return err
	}

	err = sbxCtrl.createNemInstance(scenarioName)
	if err != nil {
		log.Error("Failed to create NEM instance: ", err.Error())
		return err
	}

	// Retrieve scenario to activate from DB
	var scenario []byte
	scenario, err = sbxCtrl.scenarioStore.GetDoc(false, scenarioName)
	if err != nil {
		if sbxCtrl.usesNem() {
			log.Warn("No CouchDB companion for NEM scenario ", scenarioName, ": ", err.Error())
			return nil
		}
		log.Error("Failed to retrieve scenario from store with err: ", err.Error())
		return err
	}
@@ -303,6 +325,7 @@ func activateScenario(scenarioName string) (err error) {
	err = sbxCtrl.metricStore.SetStore(scenarioName, sbxCtrl.sandboxName, true)
	if err != nil {
		log.Error("Failed to set scenario metrics store with err: ", err.Error())
		sbxCtrl.deleteNemInstance()
		return err
	}

@@ -310,11 +333,13 @@ func activateScenario(scenarioName string) (err error) {
	err = sbxCtrl.activeModel.SetScenario(scenario)
	if err != nil {
		log.Error("Failed to set active scenario with err: ", err.Error())
		sbxCtrl.deleteNemInstance()
		return err
	}
	err = sbxCtrl.activeModel.Activate()
	if err != nil {
		log.Error("Failed to activate scenario with err: ", err.Error())
		sbxCtrl.deleteNemInstance()
		return err
	}

@@ -365,16 +390,29 @@ func ceActivateScenario(w http.ResponseWriter, r *http.Request) {
	}

	// Make sure scenario is not already deployed
	if sbxCtrl.activeModel.Active {
	if sbxCtrl.scenarioAlreadyActive() {
		log.Error("Scenario already active")
		http.Error(w, "Scenario already active", http.StatusBadRequest)
		return
	}

	err := sbxCtrl.createNemInstance(scenarioName)
	if err != nil {
		mapNemActivateError(w, err)
		return
	}

	// Retrieve scenario to activate from DB
	var scenario []byte
	scenario, err := sbxCtrl.scenarioStore.GetDoc(false, scenarioName)
	scenario, err = sbxCtrl.scenarioStore.GetDoc(false, scenarioName)
	if err != nil {
		if sbxCtrl.usesNem() {
			log.Warn("No CouchDB companion for NEM scenario ", scenarioName, ": ", err.Error())
			_ = httpLog.ReInit(moduleName, sbxCtrl.sandboxName, scenarioName, redisDBAddr, influxDBAddr)
			w.Header().Set("Content-Type", "application/json; charset=UTF-8")
			w.WriteHeader(http.StatusOK)
			return
		}
		log.Error(err.Error())
		http.Error(w, err.Error(), http.StatusNotFound)
		return
@@ -384,6 +422,7 @@ func ceActivateScenario(w http.ResponseWriter, r *http.Request) {
	err = sbxCtrl.metricStore.SetStore(scenarioName, sbxCtrl.sandboxName, true)
	if err != nil {
		log.Error(err.Error())
		sbxCtrl.deleteNemInstance()
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
@@ -392,12 +431,14 @@ func ceActivateScenario(w http.ResponseWriter, r *http.Request) {
	err = sbxCtrl.activeModel.SetScenario(scenario)
	if err != nil {
		log.Error(err.Error())
		sbxCtrl.deleteNemInstance()
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = sbxCtrl.activeModel.Activate()
	if err != nil {
		log.Error(err.Error())
		sbxCtrl.deleteNemInstance()
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
@@ -462,6 +503,9 @@ func ceGetActiveScenario(w http.ResponseWriter, r *http.Request) {
	log.Debug("CEGetActiveScenario")

	if sbxCtrl.activeModel == nil || !sbxCtrl.activeModel.Active {
		if sbxCtrl.writeNemActiveScenario(w) {
			return
		}
		// Return 200 OK with a response body indicating no scenario is active
		// This allows frontend to distinguish between "no scenario" and actual errors
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
@@ -768,6 +812,8 @@ func ceGetActiveNodeServiceMaps(w http.ResponseWriter, r *http.Request) {
func ceTerminateScenario(w http.ResponseWriter, r *http.Request) {
	log.Debug("ceTerminateScenario")

	sbxCtrl.deleteNemInstance()

	var scenarioName string
	if sbxCtrl.activeModel != nil && sbxCtrl.activeModel.Active {
		scenarioName = sbxCtrl.activeModel.GetScenarioName()
+18 −3
Changes for go-apps/meep-simu5g-mobility-adapter/README.md: 18 added lines, 3 removed lines.
Original line number Diff line number Diff line
# meep-simu5g-mobility-adapter

Runs on **NativeEdge Connector**. Listens for UDP telemetry from **Network Emulation Stack (Simu5G/SimuLTE)** (`UeTelemetryUdpSender`, port 9100) and publishes UE locations to GIS (TODO).
Runs on **NativeEdge Connector**. Listens for UDP telemetry from **Network Emulation Stack (Simu5G/SimuLTE)** (`UeTelemetryUdpSender`, port 9100) and publishes UE locations to `meep-gis-engine` via `POST /gis/v1/geodata/{assetName}`.

GIS asset names are `ue-car-*` / `ue-ped-*` from the companion YAML. The adapter talks to the GIS **ClusterIP** (no ingress session cookie). `--dry-run` skips GIS writes.

monaco-harbor must be **active** in the sandbox UI. NEM running on host S is not enough: GIS returns `No active scenario` until the companion scenario is loaded.

## Run (live, two-host)

Rebuild after pulling code:

```bash
go run . --config /path/to/simu5g-config.json
go build -o bin/meep-simu5g-mobility-adapter ./go-apps/meep-simu5g-mobility-adapter
./bin/meep-simu5g-mobility-adapter --config /home/ubuntu-template/etsi-mec-sandbox/tools/simu5g/monaco-harbor-integration-config.json
```

Configure the Network Emulation Stack to send telemetry to `NativeEdgeConnectorNode:9100`.
Listens on **UDP 9100**. monaco-harbor INI must send to host B (`172.29.10.53:9100`). After each GIS write the adapter GETs `poaInRange` and logs when the set changes.

Optional: `--gis-url http://<gis-cluster-ip>/gis/v1` or `--sandbox <ns>` if `gis.sandboxName` in the JSON is wrong.

Parse-only (no GIS writes):

```bash
./bin/meep-simu5g-mobility-adapter --config .../monaco-harbor-integration-config.json --dry-run
```

## Run (offline replay)

+2 −0
Changes for go-apps/meep-simu5g-mobility-adapter/go.mod: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -3,11 +3,13 @@ module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-simu5g-mobility-adapte
go 1.12

require (
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-gis-engine-client v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger v0.0.0
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-simu5g-bridge v0.0.0
)

replace (
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-gis-engine-client => ../../go-packages/meep-gis-engine-client
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger => ../../go-packages/meep-logger
	github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-simu5g-bridge => ../../go-packages/meep-simu5g-bridge
)
Loading