New class link to handle links between components and possible errors
This commit is contained in:
		@@ -14,17 +14,38 @@ type Link struct {
 | 
			
		||||
// Use ResourceObject parameter to process certain components type differently
 | 
			
		||||
// and Id's to identify each component as a node in an oriented graph
 | 
			
		||||
 | 
			
		||||
func NewLink(src ResourceObject, srcId string, dst ResourceObject, dstId string) (link Link) {
 | 
			
		||||
// In the case of DCLink we choose to always consider the DC as the destination
 | 
			
		||||
// in order to facilitate some logic
 | 
			
		||||
 | 
			
		||||
func NewLink(src ResourceObject, srcId string, dst ResourceObject, dstId string) (link Link) {
 | 
			
		||||
	link.Source = srcId
 | 
			
		||||
	link.Destination = dstId
 | 
			
		||||
 | 
			
		||||
	// If the link is between a DC and a component make sure that the DC is destination
 | 
			
		||||
	// and if the component is computing, update the DataCenterID
 | 
			
		||||
 | 
			
		||||
	if (src.getRtype() == rtype.DATACENTER || dst.getRtype() == rtype.DATACENTER){
 | 
			
		||||
		var linked ResourceObject
 | 
			
		||||
 | 
			
		||||
		link.DCLink = true
 | 
			
		||||
 | 
			
		||||
		if src.getRtype() == rtype.DATACENTER {
 | 
			
		||||
			linked = dst
 | 
			
		||||
		} else {
 | 
			
		||||
			linked = src
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if( link.DCLink && src.getRtype() == rtype.DATACENTER){
 | 
			
		||||
			link.Destination = srcId
 | 
			
		||||
			link.Source = dstId
 | 
			
		||||
		} 
 | 
			
		||||
		
 | 
			
		||||
		if (linked.getRtype() == rtype.COMPUTING){
 | 
			
		||||
			linked.(*ComputingObject).DataCenterID = link.Destination
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -41,15 +41,35 @@ type MxObject struct {
 | 
			
		||||
 | 
			
		||||
// Didn't manage to differentiate Links and cells containing components using 
 | 
			
		||||
// only structures and unmarshal, so we use this method post-umarshalling
 | 
			
		||||
func (g *MxGraphModel) createLinks()  error {
 | 
			
		||||
func (g *MxGraphModel) createLinks()  {
 | 
			
		||||
	var cells_without_links []MxCell 
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	for i, mxcell := range g.Root.MxCell {
 | 
			
		||||
		if mxcell.Edge != nil {
 | 
			
		||||
		
 | 
			
		||||
		if mxcell.Edge != nil {	
 | 
			
		||||
			mxcell.processLinks()
 | 
			
		||||
			newLink := MxLink{mxcell.ID,*mxcell.Source,*mxcell.Target}
 | 
			
		||||
			g.Root.MxLink = append(g.Root.MxLink,newLink)
 | 
			
		||||
			g.Root.MxCell = append(g.Root.MxCell[:i],g.Root.MxCell[i+1:]...)
 | 
			
		||||
		} else {
 | 
			
		||||
			cells_without_links = append(cells_without_links,g.Root.MxCell[i])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	g.Root.MxCell = nil
 | 
			
		||||
	g.Root.MxCell = cells_without_links
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cell *MxCell) processLinks() {
 | 
			
		||||
	v := ""
 | 
			
		||||
	if cell.Source == nil {
 | 
			
		||||
		cell.Source = &v
 | 
			
		||||
	}
 | 
			
		||||
	if cell.Target == nil {
 | 
			
		||||
		cell.Target = &v
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mxissue struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -546,12 +546,8 @@ func ParseMxGraph(username, workflowName, xmlData string) (err error, mxissues [
 | 
			
		||||
		return err, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = xmlModel.createLinks()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logs.Alert("Error creating links")
 | 
			
		||||
		return err, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	xmlModel.createLinks()
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	targetWorkspaceWorkflow, err, mxissues := userWorkspace.ConsumeMxGraphModel(xmlModel)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -652,6 +648,23 @@ func (ws Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Wor
 | 
			
		||||
			// issues = append(issues, errors.New("MxCell with ID "+cell.ID+" doesn't have a valid link"))
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			// Not root nor resource. Should be only links
 | 
			
		||||
			sourceObj := returned_wf.GetResource(cell.Source)
 | 
			
		||||
			targetObj := returned_wf.GetResource(cell.Target)
 | 
			
		||||
 | 
			
		||||
			if sourceObj == nil || targetObj == nil {
 | 
			
		||||
				if sourceObj == nil && targetObj == nil {
 | 
			
		||||
					issues = append(issues, errors.New("Arrow "+cell.ID+" is alone"))
 | 
			
		||||
				} else if sourceObj == nil {
 | 
			
		||||
					issues = append(issues, errors.New("Arrow ("+cell.ID+") to "+*targetObj.getName()+" without parent"))
 | 
			
		||||
				} else {
 | 
			
		||||
					issues = append(issues, errors.New("Arrow "+cell.ID+" from "+*sourceObj.getName()+" without target"))
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// If is a invalid link, we can't save it in the DB
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Not root nor resource. Should be only links
 | 
			
		||||
			// If is a invalid link, we can't save it in the DB
 | 
			
		||||
			// We should always get a ID because we already registered resources and discarded which doesn't correspond to existent models
 | 
			
		||||
@@ -665,58 +678,59 @@ func (ws Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Wor
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	issues = ws.CreateLinks(returned_wf,xmlmodel.Root.MxLink, issues)
 | 
			
		||||
	issues = returned_wf.CreateLinks(xmlmodel.Root.MxLink, issues)
 | 
			
		||||
	issues = returned_wf.CheckLinks(issues)
 | 
			
		||||
 | 
			
		||||
	dcslist := make(map[string]bool)
 | 
			
		||||
	dataslist := make(map[string]bool)
 | 
			
		||||
	// datalist := make(map[string]bool)
 | 
			
		||||
	// dcslist := make(map[string]bool)
 | 
			
		||||
	// dataslist := make(map[string]bool)
 | 
			
		||||
	// // datalist := make(map[string]bool)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// Test wether the computing components are linked with a DC
 | 
			
		||||
	for _, comp := range returned_wf.Computing {
 | 
			
		||||
		if comp.DataCenterID == "" {
 | 
			
		||||
			issues = append(issues, errors.New("Computing "+*comp.getName()+" without a Datacenter"))
 | 
			
		||||
		} else {
 | 
			
		||||
			// If doesn't exist in the list, means is new element to register as used
 | 
			
		||||
			dcslist[comp.DataCenterID] = true
 | 
			
		||||
	// // Test wether the computing components are linked with a DC
 | 
			
		||||
	// for _, comp := range returned_wf.Computing {
 | 
			
		||||
	// 	if comp.DataCenterID == "" {
 | 
			
		||||
	// 		issues = append(issues, errors.New("Computing "+*comp.getName()+" without a Datacenter"))
 | 
			
		||||
	// 	} else {
 | 
			
		||||
	// 		// If doesn't exist in the list, means is new element to register as used
 | 
			
		||||
	// 		dcslist[comp.DataCenterID] = true
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	// 	}
 | 
			
		||||
 | 
			
		||||
		for _, dcin := range comp.Inputs {
 | 
			
		||||
			switch returned_wf.GetResource(&dcin).getRtype() {
 | 
			
		||||
			case rtype.DATA:
 | 
			
		||||
				dataslist[dcin] = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	// 	for _, dcin := range comp.Inputs {
 | 
			
		||||
	// 		switch returned_wf.GetResource(&dcin).getRtype() {
 | 
			
		||||
	// 		case rtype.DATA:
 | 
			
		||||
	// 			dataslist[dcin] = true
 | 
			
		||||
	// 		}
 | 
			
		||||
	// 	}
 | 
			
		||||
 | 
			
		||||
		for _, dcout := range comp.Outputs {
 | 
			
		||||
			switch returned_wf.GetResource(&dcout).getRtype() {
 | 
			
		||||
			case rtype.DATA:
 | 
			
		||||
				dataslist[dcout] = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	// 	for _, dcout := range comp.Outputs {
 | 
			
		||||
	// 		switch returned_wf.GetResource(&dcout).getRtype() {
 | 
			
		||||
	// 		case rtype.DATA:
 | 
			
		||||
	// 			dataslist[dcout] = true
 | 
			
		||||
	// 		}
 | 
			
		||||
	// 	}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	for _, storage_component := range returned_wf.Storage {
 | 
			
		||||
		if storage_component.Inputs == nil && storage_component.Outputs == nil {
 | 
			
		||||
			issues = append(issues, errors.New("Storage "+*storage_component.getName()+" without compatible inputs and outputs"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// for _, storage_component := range returned_wf.Storage {
 | 
			
		||||
	// 	if storage_component.Inputs == nil && storage_component.Outputs == nil {
 | 
			
		||||
	// 		issues = append(issues, errors.New("Storage "+*storage_component.getName()+" without compatible inputs and outputs"))
 | 
			
		||||
	// 	}
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	for dcID, dc_component := range returned_wf.Datacenter {
 | 
			
		||||
		// if rID doesn't exist in the list, it means that it's not used
 | 
			
		||||
		if _, ok := dcslist[dcID]; !ok {
 | 
			
		||||
			issues = append(issues, errors.New("DC "+*dc_component.getName()+" not atached to any Computing"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// for dcID, dc_component := range returned_wf.Datacenter {
 | 
			
		||||
	// 	// if rID doesn't exist in the list, it means that it's not used
 | 
			
		||||
	// 	if _, ok := dcslist[dcID]; !ok {
 | 
			
		||||
	// 		issues = append(issues, errors.New("DC "+*dc_component.getName()+" not attached to any Computing"))
 | 
			
		||||
	// 	}
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	for dcID, data_component := range returned_wf.Data {
 | 
			
		||||
		// if rID doesn't exist in the list, it means that it's not used
 | 
			
		||||
		if _, ok := dataslist[dcID]; !ok {
 | 
			
		||||
			issues = append(issues, errors.New("Data "+*data_component.getName()+" not atached to any Computing"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// for dcID, data_component := range returned_wf.Data {
 | 
			
		||||
	// 	// if rID doesn't exist in the list, it means that it's not used
 | 
			
		||||
	// 	if _, ok := dataslist[dcID]; !ok {
 | 
			
		||||
	// 		issues = append(issues, errors.New("Data "+*data_component.getName()+" not attached to any Computing"))
 | 
			
		||||
	// 	}
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	//////////////////////////////////////////////////////////
 | 
			
		||||
	//														//
 | 
			
		||||
@@ -819,57 +833,116 @@ func (ws Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Wor
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w Workspace) CreateLinks(returned_wf *Workflow, links []MxLink, issues []error) []error {
 | 
			
		||||
func (w *Workflow) CreateLinks(links []MxLink, issues []error) []error {
 | 
			
		||||
	
 | 
			
		||||
	for _, link := range links {	
 | 
			
		||||
		sourceObj := returned_wf.GetResource(&link.Source)
 | 
			
		||||
		targetObj := returned_wf.GetResource(&link.Target)
 | 
			
		||||
 | 
			
		||||
		link_object := NewLink(sourceObj,link.Source, targetObj, link.Target)
 | 
			
		||||
		returned_wf.AddLinkToWorkflow(link_object,link.ID)
 | 
			
		||||
 | 
			
		||||
		if sourceObj == nil || targetObj == nil {
 | 
			
		||||
			if sourceObj == nil && targetObj == nil {
 | 
			
		||||
				issues = append(issues, errors.New("Arrow "+link.ID +" is alone"))
 | 
			
		||||
			} else if sourceObj == nil {
 | 
			
		||||
				issues = append(issues, errors.New("Arrow ("+link.ID+") to "+*targetObj.getName()+" without parent"))
 | 
			
		||||
			} else {
 | 
			
		||||
				issues = append(issues, errors.New("Arrow "+link.ID+" from "+*sourceObj.getName()+" without target"))
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		if (len(link.Source) > 0 && len(link.Target) > 0){
 | 
			
		||||
			sourceObj := w.GetResource(&link.Source)
 | 
			
		||||
			targetObj := w.GetResource(&link.Target)
 | 
			
		||||
			link_object := NewLink(sourceObj,link.Source, targetObj, link.Target)
 | 
			
		||||
			w.AddLinkToWorkflow(link_object,link.ID)
 | 
			
		||||
		} else {
 | 
			
		||||
			issues = append(issues, w.processLinkErrors(link))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
		// if sourceObj.getRtype() == rtype.DATACENTER || targetObj.getRtype() == rtype.DATACENTER {
 | 
			
		||||
		// 	var datacenter, datacenterLinked *string
 | 
			
		||||
 | 
			
		||||
		// 	if sourceObj.getRtype() == rtype.DATACENTER {
 | 
			
		||||
		// 		datacenter = &link.Source
 | 
			
		||||
		// 		datacenterLinked = &link.Target
 | 
			
		||||
		// 	} else {
 | 
			
		||||
		// 		datacenter = &link.Target
 | 
			
		||||
		// 		datacenterLinked = &link.Source
 | 
			
		||||
		// 	}
 | 
			
		||||
 | 
			
		||||
		// 	switch returned_wf.GetResource(datacenterLinked).getRtype() {
 | 
			
		||||
		// 	case rtype.COMPUTING:
 | 
			
		||||
		// 		computingObj := returned_wf.GetResource(datacenterLinked).(*ComputingObject)
 | 
			
		||||
 | 
			
		||||
		// 		computingObj.DataCenterID = *datacenter
 | 
			
		||||
		// 		returned_wf.UpdateObj(computingObj, *datacenterLinked)
 | 
			
		||||
		// 	}
 | 
			
		||||
 | 
			
		||||
		// } else {
 | 
			
		||||
		// 	targetObj.addLink(INPUT, *link.Source)
 | 
			
		||||
		// 	returned_wf.UpdateObj(targetObj, *link.Target)
 | 
			
		||||
 | 
			
		||||
		// 	sourceObj.addLink(OUTPUT, *link.Target)
 | 
			
		||||
		// 	returned_wf.UpdateObj(sourceObj, *link.Source)
 | 
			
		||||
		// }
 | 
			
		||||
	}
 | 
			
		||||
	return issues
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Workflow) processLinkErrors(link MxLink) (issue error) {
 | 
			
		||||
	if len(link.Source) == 0 && len(link.Target) == 0  {
 | 
			
		||||
		issue = errors.New("Arrow "+link.ID+" is alone")
 | 
			
		||||
	} else if len(link.Source) == 0{
 | 
			
		||||
		targetObj := w.GetResource(&link.Target)
 | 
			
		||||
		issue = errors.New("Arrow ("+link.ID+") to "+*targetObj.getName()+" without parent")
 | 
			
		||||
	} else {
 | 
			
		||||
		sourceObj := w.GetResource(&link.Source)
 | 
			
		||||
		issue = errors.New("Arrow "+link.ID+" from "+*sourceObj.getName()+" without target")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return issue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Workflow) CheckLinks(issues []error) []error {
 | 
			
		||||
	
 | 
			
		||||
	// Check that storage components have a valid link
 | 
			
		||||
	for id, storage := range w.Storage {
 | 
			
		||||
		if(!w.IsComponentSrc(id) && !w.IsComponentDst(id)){
 | 
			
		||||
			issues = append(issues, errors.New("Storage "+*storage.getName()+" without compatible inputs and outputs"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Check that data components are linked to a computing component
 | 
			
		||||
	for id, data := range w.Data {
 | 
			
		||||
		if(!w.HasLinkageToComputing(id)){
 | 
			
		||||
			issues = append(issues, errors.New("Data "+*data.getName()+" not attached to any Computing"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check that DC is linked to a computing component
 | 
			
		||||
	for id, dc:= range w.Datacenter {
 | 
			
		||||
		if(!w.HasLinkageToComputing(id)){
 | 
			
		||||
			issues = append(issues, errors.New("Datacenter "+*dc.getName()+" not attached to any Computing"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Check that all data computing components are linked to a DC
 | 
			
		||||
	for id,comp:= range w.Computing {
 | 
			
		||||
		if(!w.HasLinkageToDC(id)){
 | 
			
		||||
			issues = append(issues, errors.New("Computing "+*comp.getName()+" not attached to any datacenter"))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} 
 | 
			
		||||
 | 
			
		||||
	return issues
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func (w *Workflow) IsComponentSrc(id string) bool {
 | 
			
		||||
	
 | 
			
		||||
	for _, link := range w.Links{
 | 
			
		||||
		if(link.Source == id && link.Source != ""){
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Workflow) IsComponentDst(id string) bool {
 | 
			
		||||
	
 | 
			
		||||
	for _, link := range w.Links{
 | 
			
		||||
		if(link.Destination == id && link.Source != ""){
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Workflow) HasLinkageToComputing(id string) bool {
 | 
			
		||||
 | 
			
		||||
	for idComputing, _ := range w.Computing {
 | 
			
		||||
		if( (w.IsComponentSrc(id) && w.IsComponentDst(idComputing)) || (w.IsComponentSrc(idComputing) && w.IsComponentDst(id))){
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *Workflow) HasLinkageToDC(id string) bool {
 | 
			
		||||
 | 
			
		||||
	for _, link := range w.Links{
 | 
			
		||||
		if(link.Source == id && link.DCLink){
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sumExecutionReqs(exeqReq ...ExecutionRequirementsModel) (ret ExecutionRequirementsModel) {
 | 
			
		||||
	for _, v := range exeqReq {
 | 
			
		||||
		ret.CPUs += v.CPUs
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user