diff --git a/README.md b/README.md index b626da2..b4771ab 100644 --- a/README.md +++ b/README.md @@ -63,4 +63,37 @@ This script should be updated to be ran from anywhere. # More documentation -[Visit the docs/ directory](/docs/) \ No newline at end of file +[Visit the docs/ directory](/docs/) + +## UML + +We are currently using [goplantuml](https://github.com/jfeliu007/goplantuml/) to generate the oject diagrams directly from the go files. This tools creates `.plums` files directly from the directory where the go files are located. These UML files can then be visualized using plantuml and the VS Code extensions plantuml. + +**Setting up the plantuml environment** : + +``` +# Downloading the go tool goplantuml +go get github.com/jfeliu007/goplantuml/parser +go install github.com/jfeliu007/goplantuml/cmd/goplantuml@latest + +# Install the plantuml environment +sudo apt install default-jre +sudo apt install plantuml + +``` +**Rich PlantUML extension Link**: https://marketplace.visualstudio.com/items?itemName=jebbs.plantuml or search it in the marketplace panel of VS Code + +**Generate and view an UML diagram** + +``` +goplantuml path/to/code/directory > path/to/dest/file.puml +``` + +- open the .puml file generated +- alt + d to have the extension preview the plantUML code +- right click inside the .puml and select 'Export Current Diagram' to create an image file +- the output will be generated in a `out/` directory in the current path + +### Note + +Only `.puml` files ought to be commited to the git repository, because their nature allows to track changes, while image file do not fit the purpose of versioning. \ No newline at end of file diff --git a/docs/UML/plantuml/diagram_object_controllers.puml b/docs/UML/plantuml/diagram_object_controllers.puml new file mode 100644 index 0000000..1355311 --- /dev/null +++ b/docs/UML/plantuml/diagram_object_controllers.puml @@ -0,0 +1,77 @@ +@startuml +namespace controllers { + class ComputingController << (S,Aquamarine) >> { + + GetOneComputing(ID string) + + PostComputing(body models.ComputingNEWModel) + + GetMultipleComputing(IDs []string) + + } + class DataController << (S,Aquamarine) >> { + + GetOneData(ID string) + + GetMultipleData(IDs []string) + + PostData(body models.DataNEWModel) + + } + class DatacenterController << (S,Aquamarine) >> { + + GetMultipleDatacenter(IDs []string) + + GetOneDatacenter(ID string) + + PostDatacenter(body models.DatacenterNEWModel) + + } + class ScheduleController << (S,Aquamarine) >> { + + CreateSchedule(dcName string, workflowName string, cron string, duration uint, startDate time.Time, stopDate time.Time, requirements models.ExecutionRequirementsModel) + + CheckSchedule(cron string, duration uint, startDate time.Time, stopDate time.Time, requirements models.ExecutionRequirementsModel) + + GetSchedules(startDate time.Time, stopDate time.Time) + + GetNextSchedules(baseDate time.Time) + + GetPreviousSchedules(baseDate time.Time) + + } + class SearchController << (S,Aquamarine) >> { + + FindByWord(word string) + + } + class StorageController << (S,Aquamarine) >> { + + GetOneStorage(ID string) + + GetMultipleStorage(IDs []string) + + PostStorage(body models.StorageNEWModel) + + } + class UserController << (S,Aquamarine) >> { + + Login() + + Logout() + + } + class WorkflowController << (S,Aquamarine) >> { + + CreateWorkflow(workflowName string) + + ListWorkflows() + + GetWorkflow(workflowName string) + + AddElementWorkflow(workflowName string, rID string) + + MxGraphParser(workflowName string, xmlData string) + + MxGraphParserConsume(workflowName string) + + LinkElementsWorkflow(workflowName string, rObjIDsource string, rObjIDtarger string, isInput bool) + + GetWorkflowSchedule(workflowName string) + + SetWorkflowSchedule(workflowName string, cronString string, events string, isService bool, startDate time.Time, stopDate time.Time, duration uint) + + CheckWorkflowSchedule(workflowName string) + + BookWorkflowSchedule(workflowName string) + + } + class WorkspaceController << (S,Aquamarine) >> { + + AddModel(id string, rtype string) + + ListWorkspace() + + ListWorkspaceModel() + + DeleteElement(id string, rtype string) + + } +} +"web.Controller" *-- "controllers.ComputingController" +"web.Controller" *-- "controllers.DataController" +"web.Controller" *-- "controllers.DatacenterController" +"web.Controller" *-- "controllers.ScheduleController" +"web.Controller" *-- "controllers.SearchController" +"web.Controller" *-- "controllers.StorageController" +"web.Controller" *-- "controllers.UserController" +"web.Controller" *-- "controllers.WorkflowController" +"web.Controller" *-- "controllers.WorkspaceController" + + +@enduml diff --git a/docs/UML/plantuml/diagram_object_models.puml b/docs/UML/plantuml/diagram_object_models.puml new file mode 100644 index 0000000..983ac5b --- /dev/null +++ b/docs/UML/plantuml/diagram_object_models.puml @@ -0,0 +1,347 @@ +@startuml +namespace models { + class ComputingModel << (S,Aquamarine) >> { + + ID string + + - getRtype() rtype.Rtype + - getName() string + + + AddUserInput(inputs map[string]interface{}) + + } + class ComputingNEWModel << (S,Aquamarine) >> { + + Name string + + Description string + + ShortDescription string + + Logo string + + Type string + + Owner string + + License string + + Price uint + + ExecutionRequirements ExecutionRequirementsModel + + Dinputs []string + + Doutputs []string + + Image string + + Command string + + Arguments []string + + Environment []string + + Ports []string + + } + class ComputingObject << (S,Aquamarine) >> { + + ReferenceID primitive.ObjectID + + Inputs []string + + Outputs []string + + DataCenterID string + + - getHost() *string + - setReference(rID primitive.ObjectID) + - getReference() primitive.ObjectID + - getRtype() rtype.Rtype + - getModel() (ResourceModel, error) + - getName() *string + - isLinked(rObjID string) LinkingState + - addLink(direction LinkingState, rID string) + + } + class DCstatus << (S,Aquamarine) >> { + + DCname string + + DCobjID string + + IsReachable bool + + IsAvailable bool + + Booked *ScheduleInfo + + ErrorMessage string + + } + class DataIO << (S,Aquamarine) >> { + + Counter uint + + } + class DataModel << (S,Aquamarine) >> { + + ID string + + - getRtype() rtype.Rtype + - getName() string + + } + class DataNEWModel << (S,Aquamarine) >> { + + Name string + + Description string + + ShortDescription string + + Logo string + + Dtype string + + Type string + + Example string + + Protocol []string + + Location string + + } + class DataObject << (S,Aquamarine) >> { + + ReferenceID primitive.ObjectID + + - getHost() *string + - getModel() (ResourceModel, error) + - setReference(rID primitive.ObjectID) + - getReference() primitive.ObjectID + - getRtype() rtype.Rtype + - getName() *string + - isLinked(rID string) LinkingState + - addLink(direction LinkingState, rObjID string) + + } + class DatacenterCpuModel << (S,Aquamarine) >> { + + Cores uint + + Architecture string + + Shared bool + + MinimumMemory uint + + Platform string + + } + class DatacenterGpuModel << (S,Aquamarine) >> { + + CudaCores uint + + Model string + + Memory uint + + TensorCores uint + + } + class DatacenterMemoryModel << (S,Aquamarine) >> { + + Size uint + + Ecc bool + + } + class DatacenterModel << (S,Aquamarine) >> { + + ID string + + - getRtype() rtype.Rtype + - getName() string + + + GetTotalCPUs() uint + + GetTotalGPUs() uint + + GetTotalRAM() uint + + } + class DatacenterNEWModel << (S,Aquamarine) >> { + + Name string + + Type string + + Acronym string + + Hosts []string + + Description string + + ShortDescription string + + Logo string + + CPU DatacenterCpuModel + + RAM DatacenterMemoryModel + + GPU []DatacenterGpuModel + + Owner string + + BookingPrice int + + } + class DatacenterObject << (S,Aquamarine) >> { + + ReferenceID primitive.ObjectID + + - setReference(rID primitive.ObjectID) + - getModel() (ResourceModel, error) + - getReference() primitive.ObjectID + - getHost() *string + - getRtype() rtype.Rtype + - getName() *string + - isLinked(rID string) LinkingState + - addLink(direction LinkingState, rObjID string) + + } + class ExecutionRequirementsModel << (S,Aquamarine) >> { + + CPUs uint + + GPUs uint + + RAM uint + + Parallel bool + + ScalingModel uint + + DiskIO string + + } + class MxCell << (S,Aquamarine) >> { + + XMLName xml.Name + + ID string + + Parent *string + + RID *string + + Source *string + + Target *string + + } + class MxGraphModel << (S,Aquamarine) >> { + + XMLName xml.Name + + Root struct{xml.Name, []MxCell, *[]Object} + + } + class Object << (S,Aquamarine) >> { + + XMLName xml.Name + + ID string + + Command *string + + Args *string + + Env *string + + MxCell MxCell + + } + class RepositoryModel << (S,Aquamarine) >> { + + Credentials string + + Url string + + } + interface ResourceModel { + - getRtype() rtype.Rtype + - getName() string + + } + interface ResourceObject { + - getHost() *string + - getName() *string + - getModel() (ResourceModel, error) + - getRtype() rtype.Rtype + - setReference(rObjID primitive.ObjectID) + - getReference() primitive.ObjectID + - isLinked(rObjID string) LinkingState + - addLink(direction LinkingState, rObjID string) + + } + class ScheduleDB << (S,Aquamarine) >> { + + StartDate time.Time + + StopDate time.Time + + Workflow string + + ResourceQty ExecutionRequirementsModel + + } + class ScheduleInfo << (S,Aquamarine) >> { + + Total int + + NextExecutions []string + + } + class SearchResult << (S,Aquamarine) >> { + + Computing []ComputingModel + + Datacenter []DatacenterModel + + Storage []StorageModel + + Data []DataModel + + } + class StorageModel << (S,Aquamarine) >> { + + ID string + + - getRtype() rtype.Rtype + - getName() string + + + AddUserInput(inputs map[string]interface{}) + + } + class StorageNEWModel << (S,Aquamarine) >> { + + Name string + + Description string + + ShortDescription string + + Logo string + + Type string + + DCacronym string + + URL string + + Size uint + + Encryption bool + + Redundancy string + + Throughput string + + BookingPrice uint + + } + class StorageObject << (S,Aquamarine) >> { + + ReferenceID primitive.ObjectID + + Inputs []string + + Outputs []string + + - getHost() *string + - getModel() (ResourceModel, error) + - setReference(rID primitive.ObjectID) + - getReference() primitive.ObjectID + - getRtype() rtype.Rtype + - getName() *string + - isLinked(rObjID string) LinkingState + - addLink(direction LinkingState, rObjID string) + + } + class UserModel << (S,Aquamarine) >> { + + ID string + + Username string + + Password string + + Email string + + } + class Workflow << (S,Aquamarine) >> { + + Data map[string]DataObject + + Computing map[string]ComputingObject + + Storage map[string]StorageObject + + Datacenter map[string]DatacenterObject + + Schedules WorkflowSchedule + + MxgraphXML string + + + GetExecutionRequirements(dcIDobj string) (ExecutionRequirementsModel, error) + + GetResource(rObjID *string) ResourceObject + + GetResourceMapByRtype(rt rtype.Rtype) interface{} + + CreateResourceObject(rt rtype.Rtype) ResourceObject + + AddObj(robj ResourceObject) *primitive.ObjectID + + UpdateDB(userID string, workflowName string) error + + UpdateObj(robj ResourceObject, objID string) + + } + class WorkflowSchedule << (S,Aquamarine) >> { + + IsService bool + + StartDate time.Time + + StopDate time.Time + + Cron string + + Duration uint + + Events string + + IsBooked bool + + } + class Workspace << (S,Aquamarine) >> { + + UserID string + + Workflows map[string]Workflow + + Data []string + + Computing []string + + Datacenter []string + + Storage []string + + - getRtype(rID string) rtype.Rtype + - updateDB() error + + + ConsumeMxGraphModel(xmlmodel MxGraphModel) (*Workflow, error, []error) + + GetResources() map[rtype.Rtype][]string + + GetWorkflow(workflowName string) *Workflow + + GetWorkflows() []string + + NewResource(rID string, rType string) error + + GetAllWorkspacesProjects() chan *Workflow + + } + class WorkspaceModel << (S,Aquamarine) >> { + + UserID string + + Data []DataModel + + Computing []ComputingModel + + Datacenter []DatacenterModel + + Storage []StorageModel + + } + class models.LinkingState << (T, #FF7700) >> { + } + class mxissue << (S,Aquamarine) >> { + - msg string + + + Error() string + + } +} +"models.ComputingNEWModel" *-- "models.ComputingModel" +"models.DataNEWModel" *-- "models.DataModel" +"models.DatacenterNEWModel" *-- "models.DatacenterModel" +"models.StorageNEWModel" *-- "models.StorageModel" + +"models.ResourceModel" <|-- "models.ComputingModel" +"models.ResourceObject" <|-- "models.ComputingObject" +"models.ResourceModel" <|-- "models.DataModel" +"models.ResourceObject" <|-- "models.DataObject" +"models.ResourceModel" <|-- "models.DatacenterModel" +"models.ResourceObject" <|-- "models.DatacenterObject" +"models.ResourceModel" <|-- "models.StorageModel" +"models.ResourceObject" <|-- "models.StorageObject" + +"__builtin__.uint" #.. "models.LinkingState" +@enduml diff --git a/models/computing.go b/models/computing.go index c0f539a..7a50246 100644 --- a/models/computing.go +++ b/models/computing.go @@ -1,11 +1,13 @@ package models import ( + "encoding/xml" "fmt" "strings" "cloud.o-forge.io/core/oc-catalog/models/rtype" "cloud.o-forge.io/core/oc-catalog/services" + structtomap "github.com/Klathmon/StructToMap" "github.com/beego/beego/v2/core/logs" "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -35,7 +37,7 @@ type ComputingNEWModel struct { ShortDescription string `json:"short_description,omitempty" required:"true" validate:"required"` Logo string `json:"logo,omitempty" required:"true" validate:"required"` - // Type string `json:"type,omitempty" required:"true"` + Type string `json:"type,omitempty" required:"true"` Owner string `json:"owner,omitempty"` License string `json:"license,omitempty"` Price uint `json:"price,omitempty"` @@ -49,7 +51,7 @@ type ComputingNEWModel struct { Command string `json:"command,omitempty"` Arguments []string `json:"arguments,omitempty"` Environment []string `json:"environment,omitempty"` - // Ports []string `json:"ports,omitempty"` + Ports []string `json:"ports,omitempty"` // CustomDeployment string `json:"custom_deployment,omitempty"` @@ -77,6 +79,11 @@ type ComputingObject struct { Inputs []string `json:"inputs"` Outputs []string `json:"outputs"` + Image string `json:"image,omitempty"` + Command string `json:"command,omitempty"` + Arguments []string `json:"arguments,omitempty"` + Environment []string `json:"environment,omitempty"` + Ports []string `json:"ports,omitempty"` DataCenterID string `json:"datacenterID" description:"Datacenter where the computing will be executed"` } @@ -174,19 +181,45 @@ func PostOneComputing(obj ComputingNEWModel) (ID string, err error) { return postOneResource(obj, rtype.COMPUTING) } -func (obj ComputingModel) AddUserInput(inputs map[string]interface{} ){ +func (obj *ComputingObject) AddUserInput(inputs []xml.Attr){ + + logs.Alert("AddUserInput() is going to throw some alerts while mxGraph GUI is not updated to adapt the inputs to the componant") + // So far only a few input to handle so a switch with a case for each type of attribute // is enough, to prevent too much complexity - for key, value := range inputs { - switch strings.ToLower(key) { + + for _, j := range(inputs){ + setting, _ := structtomap.Convert(j) + // fmt.Println(strings.ToLower(setting["Name"])) + name := setting["Name"].(xml.Name).Local + value := setting["Value"] + switch name { case "command": obj.Command = value.(string) - case "arguments": - obj.Arguments = value.([]string) + case "args": + empty, sliced_arguments := getSliceSettings(value.(string)) + if (!empty){ + obj.Arguments = sliced_arguments + } case "env" : - obj.Environment = value.([]string) + empty, sliced_arguments := getSliceSettings(value.(string)) + if (!empty){ + obj.Environment = sliced_arguments + } default: - logs.Alert(fmt.Printf("%s is not an attribute of storage componants", key)) + logs.Alert(fmt.Printf("%s is not an attribute of computing componants", name)) } + } + + +} + +func getSliceSettings(string_to_parse string)(empty bool, sliced_string []string){ + if len(string_to_parse) == 0 { + return true, nil + } + empty = false + sliced_string = strings.Split(string_to_parse," ") + return } \ No newline at end of file diff --git a/models/data.go b/models/data.go index d812d83..6efefa9 100644 --- a/models/data.go +++ b/models/data.go @@ -22,19 +22,6 @@ type DataNEWModel struct { Location string `json:"location" required:"true" validate:"required"` } -type DataModel struct { - ID string `json:"ID" bson:"_id" required:"true" validate:"required"` - DataNEWModel `bson:",inline"` -} - -func (obj DataModel) getRtype() rtype.Rtype { - return rtype.DATA -} - -func (model DataModel) getName() string { - return model.Name -} - type DataIO struct { Counter uint `description:"Incremental number starting from 0"` } @@ -43,6 +30,18 @@ type DataObject struct { ReferenceID primitive.ObjectID `json:"referenceID" description:"Data model ID"` } +type DataModel struct { + ID string `json:"ID" bson:"_id" required:"true" validate:"required"` + DataNEWModel `bson:",inline"` +} + +func (obj DataModel) getRtype() rtype.Rtype { + return rtype.DATA +} + +func (model DataModel) getName() string { + return model.Name +} func (obj DataObject) getHost() *string { return nil // Host is DC only attribute } diff --git a/models/mxgraph.go b/models/mxgraph.go index 7f227fc..fec9773 100644 --- a/models/mxgraph.go +++ b/models/mxgraph.go @@ -8,8 +8,9 @@ type MxGraphModel struct { XMLName xml.Name `xml:"mxGraphModel"` Root struct { - XMLName xml.Name `xml:"root"` - MxCell []MxCell `xml:"mxCell"` + XMLName xml.Name `xml:"root"` + MxCell []MxCell `xml:"mxCell"` + MxObject *[]MxObject `xml:"object"` } } @@ -20,6 +21,15 @@ type MxCell struct { RID *string `xml:"rID,attr"` Source *string `xml:"source,attr"` Target *string `xml:"target,attr"` + Rtype *string `xml:"rType,attr"` +} + + +type MxObject struct { + XMLName xml.Name `xml:"object"` + ID string `xml:"id,attr"` + Settings []xml.Attr `xml:",any,attr"` + MxCell MxCell `xml:"mxCell"` } type mxissue struct { @@ -33,3 +43,4 @@ func (m *mxissue) Error() string { func newMxIssue(message string) error { return &mxissue{message} } + diff --git a/models/workflow.go b/models/workflow.go index b883a24..f8bb70e 100644 --- a/models/workflow.go +++ b/models/workflow.go @@ -4,6 +4,8 @@ import ( "context" "encoding/xml" "errors" + "net/url" + "os" "sort" "time" @@ -71,18 +73,25 @@ type ResourceObject interface { addLink(direction LinkingState, rObjID string) } +// This type allows to process computing and storage component +// which can get input from the user +type EditableResourceObject interface{ + ResourceObject + addUserInput(map[string]interface{}) +} + // Get a sum of all execution requirements attached to a DC obj -func (w Workflow) GetExecutionRequirements(dcIDobj string) (ret ExecutionRequirementsModel, err error) { +func (wf Workflow) GetExecutionRequirements(dcIDobj string) (ret ExecutionRequirementsModel, err error) { // Find the id of the DC obj - if _, ok := w.Datacenter[dcIDobj]; !ok { + if _, ok := wf.Datacenter[dcIDobj]; !ok { return ExecutionRequirementsModel{}, errors.New("DC obj" + dcIDobj + " doesn't exist in the Workflow") } // Get all elements that are attached to the DC - for _, computingObj := range w.Computing { + for _, computingObj := range wf.Computing { if computingObj.DataCenterID == dcIDobj { mymodel, err := computingObj.getModel() if err != nil { @@ -159,6 +168,7 @@ func (w *Workflow) CreateResourceObject(rt rtype.Rtype) ResourceObject { default: res = nil } + return res } @@ -510,6 +520,14 @@ func ParseMxGraph(username, workflowName, xmlData string) (err error, mxissues [ //return errors.New("Can't modify a booked workflow"), nil } + decodedValue, err := url.QueryUnescape(xmlData) + if err != nil { + return err, nil + } + + // TEMPORARY test the xml created + os.WriteFile("graph.xml", []byte(decodedValue), 0660) + var xmlModel MxGraphModel // logs.Debug(xmlData) @@ -518,13 +536,17 @@ func ParseMxGraph(username, workflowName, xmlData string) (err error, mxissues [ return err, nil } + // Move the attribute of the object's tags into the mxCell's for an easier processing + + // currentWorkflow.extractMxCell(xmlModel) + targetWorkspaceWorkflow, err, mxissues := userWorkspace.ConsumeMxGraphModel(xmlModel) if err != nil { return err, nil } targetWorkspaceWorkflow.MxgraphXML = xmlData - targetWorkspaceWorkflow.Schedules = currentWorkflow.Schedules //TODO: Probably we should move schudles outside the workflow + targetWorkspaceWorkflow.Schedules = currentWorkflow.Schedules //TODO: Probably we should move schedules outside the workflow _, err = services.MngoCollWorkspace.UpdateOne(services.MngoCtx, primitive.M{"_id": username}, @@ -564,7 +586,8 @@ func FindSliceInSlice(slice1 []string, slice2 []string) (int, int, bool) { return -1, -1, false } -func (w Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Workflow, err error, issues []error) { +// TODO : correct this method to suppport mxcells with settings +func (ws Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Workflow, err error, issues []error) { returned_wf = &Workflow{} @@ -574,11 +597,13 @@ func (w Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Work return xmlmodel.Root.MxCell[i].RID != nil }) + + // For each cell of the xml graph, - // in the case cell has a rID retrieve its rType from the value of rID of the componant in the worfklow - // retrieve the componant's type + // in the case cell has a rID retrieve its rType from the value of rID of the component in the worfklow + // retrieve the component's type // create an object from the rType - // update the existing workflow with the new componant + // update the existing workflow with the new component // or by defautlt : the cell represents an arrow // if the source or the target of the arrow is a datacenter // define which end of the arrow is the DC @@ -586,30 +611,39 @@ func (w Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Work // create a computing object // attach the DC to it // update the workflow with the object : create the list of this type of component or update the list with the id of the component with the object + + for _, object := range *xmlmodel.Root.MxObject{ + + resObj, err, mxissues := returned_wf.mxCellToComponent(object.MxCell,ws) + if err != nil { + issues = append(issues, mxissues...) + } + + // add the component to the worflow's attribute that stores + // all components in a map[string]Component where the key + // is the component's ID in the mxGraph and the value the Component object + returned_wf.UpdateObj(resObj,object.ID) + + // Construct the object corresponding to the componant's type and use its addUserInput method + if(resObj.getRtype() == rtype.COMPUTING){ + comp_obj := returned_wf.GetResource(&object.ID).(*ComputingObject) + comp_obj.AddUserInput(object.Settings) + returned_wf.UpdateObj(comp_obj,object.ID) + } + // if(resObj.getRtype() == rtype.DATA){ + // } + + } + for _, cell := range xmlmodel.Root.MxCell { switch { case cell.RID != nil: - // Case of a Resource - rType := w.getRtype(*cell.RID) - - if rType == rtype.INVALID { - return nil, - errors.New("Refering to a rID that is not in the workflow"), - nil - } - - // Generate ObjectID for the reference ID - rIDObj, err := primitive.ObjectIDFromHex(*cell.RID) + resObj, err, mxissues := returned_wf.mxCellToComponent(cell,ws) if err != nil { - return nil, - errors.New("Bad ID format: " + *cell.RID), - nil + issues = append(issues, mxissues...) } - resObj := returned_wf.CreateResourceObject(rType) - resObj.setReference(rIDObj) - returned_wf.UpdateObj(resObj, cell.ID) case cell.ID == "0" || cell.ID == "1": @@ -677,7 +711,7 @@ func (w Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Work // datalist := make(map[string]bool) - // Test wether the computing componants are linked with a DC + // 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")) @@ -1005,9 +1039,49 @@ func CheckAndBookWorkflowSchedule(username, workflowName string, book bool) (myR SchedulesDB: ¤tWorkflow.Schedules}}, ) - if err != nil { + if err != nil { logs.Critical("Internal error when updating in DB: " + err.Error()) } return myRet, nil } + +// Not sure if this method handles error propagation well +func (wf Workflow) mxCellToComponent(cell MxCell, ws Workspace) (resObj ResourceObject,err error, issues []error){ + rType := ws.getRtype(*cell.RID) + + if rType == rtype.INVALID { + return nil, + errors.New("Refering to a rID that is not in the workflow"), + nil + } + + // Generate ObjectID for the reference ID + rIDObj, err := primitive.ObjectIDFromHex(*cell.RID) + if err != nil { + return nil, + errors.New("Bad ID format: " + *cell.RID), + nil + } + + resObj = wf.CreateResourceObject(rType) + resObj.setReference(rIDObj) + + return +} + +// func (ws Workspace) extractMxCell(xmlModel MxGraphModel){ +// // Iterate through all objects of the MxGraph +// graphObjects := xmlModel.Root.MxObject +// for _, object := range(*graphObjects){ +// current_obj_id, _ := strconv.Atoi(object.ID) +// inside_cell_id := strconv.Itoa(current_obj_id + 1) + +// cell := ws.GetResource(&inside_cell_id) +// // component := w.GetResource(cell.RID) +// fmt.Print(cell) +// } +// // Extract the mxCell object +// // Invoke the addParameter method from the component +// // Edit the ID to get the object's one +// }