Commit a19c070e authored by Mudassar Khan's avatar Mudassar Khan
Browse files

feat: update deployment handling for MEC services

- Append MEC platform name to MEC service deployments
- Allow same-named MEC services on different platforms on the website
- Update admin panel (/alt) to support these changes
- Fix conflict where identical service names were previously not permitted
parent 7c092b27
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -250,18 +250,23 @@ func getScenarioAppInstanceList(activeModel *mod.Model) ([]*apps.Application, er
	var appList []*apps.Application

	if activeModel != nil {
		// Get active scenario node names
		appNames := activeModel.GetNodeNames(mod.NodeTypeEdgeApp)
		for _, appName := range appNames {
			// Get scenario Process & context
			proc, ctx, err := getScenarioProcess(appName, activeModel)
			if err != nil {
				log.Error(err.Error())
		// Get all processes
		processes := activeModel.GetProcesses(nil)
		for _, proc := range processes.Processes {
			// Only handle EDGE-APP for duplicates
			if proc.Type_ != mod.NodeTypeEdgeApp {
				continue
			}

			// Get context by ID
			ctx := activeModel.GetNodeContextById(proc.Id)
			if ctx == nil {
				log.Error("Failed to get context for process ID: " + proc.Id)
				continue
			}

			// Create app instance
			app, err := createAppInstance(proc, ctx)
			app, err := createAppInstance(&proc, ctx)
			if err != nil {
				log.Error(err.Error())
				continue
+1 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@ require (
	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-watchdog v0.0.0
	github.com/google/uuid v1.2.0 // indirect
)

replace (
+18 −16
Original line number Diff line number Diff line
@@ -182,29 +182,22 @@ func getAppEnablement(mepName string, model *mod.Model) string {
func generateScenarioCharts(sandboxName string, procName string, model *mod.Model) (charts []helm.Chart, err error) {
	serviceMap := map[string]string{}

	procNames := model.GetNodeNames("CLOUD-APP")
	procNames = append(procNames, model.GetNodeNames("EDGE-APP")...)
	procNames = append(procNames, model.GetNodeNames("UE-APP")...)
	for _, name := range procNames {
	processes := model.GetProcesses(nil)
	for _, proc := range processes.Processes {
		// Check if single process is being added
		if procName != "" && name != procName {
		if procName != "" && proc.Name != procName {
			continue
		}

		// Retrieve node process information from model
		node := model.GetNode(name)
		node := model.GetNodeById(proc.Id)
		if node == nil {
			err = errors.New("Error finding process: " + name)
			return nil, err
		}
		proc, ok := node.(*dataModel.Process)
		if !ok {
			err = errors.New("Error casting process: " + name)
			err = errors.New("Error finding process: " + proc.Name + " with ID: " + proc.Id)
			return nil, err
		}
		ctx := model.GetNodeContext(name)
		ctx := model.GetNodeContextById(proc.Id)
		if ctx == nil {
			err = errors.New("Error finding context for process: " + name)
			err = errors.New("Error finding context for process: " + proc.Name + " with ID: " + proc.Id)
			return nil, err
		}

@@ -256,12 +249,13 @@ func generateScenarioCharts(sandboxName string, procName string, model *mod.Mode
					}
				}
			}
		} else if mepService := getMepService(proc); mepService != "" {
		} else if mepService := getMepService(&proc); mepService != "" {
			log.Debug("Processing MEP Service chart for element[", proc.Name, "]")

			// Get MEP Name
			mepName := ctx.Parents[mod.PhyLoc]

			// Important part of code.
			// Create Sandbox template
			var sandboxTemplate SandboxTemplate
			sandboxTemplate.InstanceId = proc.Id
@@ -291,7 +285,10 @@ func generateScenarioCharts(sandboxName string, procName string, model *mod.Mode
			}

			// Create chart
			chartName := proc.Name
			chartName := mepName + "-" + proc.Name
			if len(chartName) > 53 {
				chartName = chartName[:53]
			}
			chartLocation, _, err := createChart(chartName, sandboxName, scenarioName, mepService, sandboxTemplate)
			if err != nil {
				log.Debug("yaml creation file process: ", err)
@@ -572,6 +569,11 @@ func newChart(chartName string, sandboxName string, scenarioName string, chartLo
		chart.ReleaseName = "meep-" + scenarioName + "-" + chartName
	}

	// Truncate release name to 53 characters to comply with Helm requirements
	if len(chart.ReleaseName) > 53 {
		chart.ReleaseName = chart.ReleaseName[:53]
	}

	chart.Name = chartName
	chart.Namespace = sandboxName
	chart.Location = chartLocation
+70 −53
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package model
import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"sync"
@@ -240,6 +241,7 @@ func (m *Model) SetScenario(j []byte) (err error) {
	m.scenario = scenario

	err = m.parseNodes()
	// No Prob in Parsing Nodes
	if err != nil {
		log.Error(err.Error())
		return err
@@ -550,12 +552,6 @@ func (m *Model) addPhyLoc(node *dataModel.ScenarioNode, parentNode *Node) (err e
		return err
	}

	// Make sure node Name is unique
	n := m.nodeMap.FindByName(pl.Name)
	if n != nil {
		return errors.New("Element " + pl.Name + " already exists in scenario " + m.name)
	}

	// Ignore any configured processes
	pl.Processes = make([]dataModel.Process, 0)

@@ -581,12 +577,6 @@ func (m *Model) addProcess(node *dataModel.ScenarioNode, parentNode *Node) (err
		return err
	}

	// Make sure node Name is unique
	n := m.nodeMap.FindByName(proc.Name)
	if n != nil {
		return errors.New("Element " + proc.Name + " already exists in scenario " + m.name)
	}

	// Add Proc to parent PhyLoc
	pl.Processes = append(pl.Processes, *proc)

@@ -858,11 +848,15 @@ func (m *Model) GetNodeNames(typ ...string) []string {
	nm := make(map[string]*Node)
	for _, t := range typ {
		if t == "" || t == "ANY" {
			nm = m.nodeMap.nameMap
			for name, nodes := range m.nodeMap.nameMap {
				if len(nodes) > 0 {
					nm[name] = nodes[0]
				}
			}
			break
		}
		for k, v := range m.nodeMap.typeMap[t] {
			nm[k] = v
		for name, node := range m.nodeMap.FindAllByType(t) {
			nm[name] = node
		}
	}

@@ -879,7 +873,9 @@ func (m *Model) GetEdges() (edgeMap map[string]string) {
	defer m.lock.RUnlock()

	edgeMap = make(map[string]string)
	for k, node := range m.nodeMap.nameMap {
	for k, nodes := range m.nodeMap.nameMap {
		if len(nodes) > 0 {
			node := nodes[0]
			p := reflect.ValueOf(node.parent)
			pName := reflect.Indirect(p).FieldByName("Name")
			if pName.IsValid() {
@@ -887,10 +883,12 @@ func (m *Model) GetEdges() (edgeMap map[string]string) {
				// fmt.Printf("%s (%T) \t\t %s(%T)\n", k, node.object, pName, node.parent)
			}
		}
	}
	return edgeMap
}

// GetNode - Get a node by its name
//
//			Returned value is of type interface{}
//	   Good practice: returned node should be type asserted with val,ok := node.(someType) to prevent panic
func (m *Model) GetNode(name string) (node interface{}) {
@@ -899,13 +897,14 @@ func (m *Model) GetNode(name string) (node interface{}) {

	node = nil
	n := m.nodeMap.nameMap[name]
	if n != nil {
		node = n.object
	if len(n) > 0 {
		node = n[0].object
	}
	return node
}

// GetNodeById - Get a node by its id
//
//			Returned value is of type interface{}
//	   Returned node may be nil
func (m *Model) GetNodeById(id string) (node interface{}) {
@@ -927,8 +926,8 @@ func (m *Model) GetNodeId(name string) (id string) {

	id = ""
	n := m.nodeMap.nameMap[name]
	if n != nil {
		id = n.id
	if len(n) > 0 {
		id = n[0].id
	}
	return id
}
@@ -940,8 +939,8 @@ func (m *Model) GetNodeType(name string) (typ string) {

	typ = ""
	n := m.nodeMap.nameMap[name]
	if n != nil {
		typ = n.nodeType
	if len(n) > 0 {
		typ = n[0].nodeType
	}
	return typ
}
@@ -953,8 +952,8 @@ func (m *Model) GetNodeParent(name string) (parent interface{}) {

	parent = nil
	n := m.nodeMap.nameMap[name]
	if n != nil {
		parent = n.parent
	if len(n) > 0 {
		parent = n[0].parent
	}
	return parent
}
@@ -966,8 +965,8 @@ func (m *Model) GetNodeChild(name string) (child interface{}) {

	child = nil
	n := m.nodeMap.nameMap[name]
	if n != nil {
		child = n.child
	if len(n) > 0 {
		child = n[0].child
	}
	return child
}
@@ -979,11 +978,30 @@ func (m *Model) GetNodeContext(name string) (ctx *NodeContext) {

	ctx = nil
	n := m.nodeMap.nameMap[name]
	log.Debug("Node name: ", name, " Node: ", fmt.Sprintf("%+v", n))
	if len(n) > 0 {
		nodeCtx := n[0].context
		var ok bool
		if ctx, ok = nodeCtx.(*NodeContext); !ok {
			log.Error("Error casting node context for node: " + name)
			return nil
		}
	}
	return ctx
}

// GetNodeContextById - Get a node context by ID
func (m *Model) GetNodeContextById(id string) (ctx *NodeContext) {
	m.lock.RLock()
	defer m.lock.RUnlock()

	ctx = nil
	n := m.nodeMap.idMap[id]
	if n != nil {
		nodeCtx := n.context
		var ok bool
		if ctx, ok = nodeCtx.(*NodeContext); !ok {
			log.Error("Error casting node context for node: " + name)
			log.Error("Error casting node context for node ID: " + id)
			return nil
		}
	}
@@ -1221,16 +1239,13 @@ func (m *Model) GetProcesses(filter *NodeFilter) dataModel.Processes {
	m.lock.RLock()
	defer m.lock.RUnlock()

	// Get process nodes
	nMap := make(map[string]*Node)
	m.mergeNodeMap(nMap, m.nodeMap.FindAllByType(NodeTypeUEApp))
	m.mergeNodeMap(nMap, m.nodeMap.FindAllByType(NodeTypeEdgeApp))
	m.mergeNodeMap(nMap, m.nodeMap.FindAllByType(NodeTypeCloudApp))

	// Find nodes that match filter criteria
	var processes dataModel.Processes
	processes.Processes = []dataModel.Process{}
	for _, node := range nMap {
	types := []string{NodeTypeUEApp, NodeTypeEdgeApp, NodeTypeCloudApp}
	for _, typ := range types {
		for _, nodes := range m.nodeMap.typeMap[typ] {
			for _, node := range nodes {
				if m.filterNode(node, Proc, filter) {
					process := *(node.object.(*dataModel.Process))

@@ -1238,6 +1253,8 @@ func (m *Model) GetProcesses(filter *NodeFilter) dataModel.Processes {
					processes.Processes = append(processes.Processes, process)
				}
			}
		}
	}
	return processes
}

@@ -1316,7 +1333,7 @@ func (m *Model) parseNodes() (err error) {
								procCtx := NewNodeContext(m.scenario.Name, domain.Name, zone.Name, nl.Name, pl.Name)
								m.nodeMap.AddNode(NewNode(proc.Id, proc.Name, proc.Type_, proc, nil, pl, procCtx))
								m.networkGraph.AddNode(proc.Name, pl.Name, false)

								log.Info("Model.go: Added process: ", proc.Name, " type: ", proc.Type_, " to physical location: ", pl.Name)
								// Update service map for external processes
								if proc.IsExternal {
									var nodeServiceMaps dataModel.NodeServiceMaps
+23 −10
Original line number Diff line number Diff line
@@ -30,16 +30,16 @@ type Node struct {
// NodeMap - Model node map
type NodeMap struct {
	idMap   map[string]*Node
	nameMap map[string]*Node
	typeMap map[string]map[string]*Node
	nameMap map[string][]*Node
	typeMap map[string]map[string][]*Node
}

// NewNodeMap - allocate a blank NodeMap
func NewNodeMap() (nm *NodeMap) {
	nm = new(NodeMap)
	nm.idMap = make(map[string]*Node)
	nm.nameMap = make(map[string]*Node)
	nm.typeMap = make(map[string]map[string]*Node)
	nm.nameMap = make(map[string][]*Node)
	nm.typeMap = make(map[string]map[string][]*Node)
	return nm
}

@@ -59,11 +59,14 @@ func NewNode(id string, name string, nodeType string, object interface{}, child
// AddNode - Add a node to the NodeMap
func (nm *NodeMap) AddNode(n *Node) {
	nm.idMap[n.id] = n
	nm.nameMap[n.name] = n
	nm.nameMap[n.name] = []*Node{n}
	if nm.typeMap[n.nodeType] == nil {
		nm.typeMap[n.nodeType] = make(map[string]*Node)
		nm.typeMap[n.nodeType] = make(map[string][]*Node)
	}
	nm.typeMap[n.nodeType][n.name] = n
	if nm.typeMap[n.nodeType][n.name] == nil {
		nm.typeMap[n.nodeType][n.name] = []*Node{}
	}
	nm.typeMap[n.nodeType][n.name] = append(nm.typeMap[n.nodeType][n.name], n)
}

// FindById - find a node using its name
@@ -73,15 +76,25 @@ func (nm *NodeMap) FindById(id string) (n *Node) {

// FindByName - find a node using its name
func (nm *NodeMap) FindByName(name string) (n *Node) {
	return nm.nameMap[name]
	nodes := nm.nameMap[name]
	if len(nodes) > 0 {
		return nodes[0]
	}
	return nil
}

// FindByType - find a node using its type - NOT SURE WE NEED THIS
func (nm *NodeMap) FindByType(name string, nodeType string) (n *Node) {
func (nm *NodeMap) FindByType(name string, nodeType string) []*Node {
	return nm.typeMap[nodeType][name]
}

// FindAllByType - find a list of nodes using a type
func (nm *NodeMap) FindAllByType(nodeType string) map[string]*Node {
	return nm.typeMap[nodeType]
	result := make(map[string]*Node)
	for name, nodes := range nm.typeMap[nodeType] {
		if len(nodes) > 0 {
			result[name] = nodes[0]
		}
	}
	return result
}
Loading