Merge branch 'bugfix/settings_handling'

This commit is contained in:
pb 2024-04-11 16:46:22 +02:00
commit 9ebd5cd5b0
7 changed files with 626 additions and 52 deletions

View File

@ -63,4 +63,37 @@ This script should be updated to be ran from anywhere.
# More documentation # More documentation
[Visit the docs/ directory](/docs/) [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.

View File

@ -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

View File

@ -0,0 +1,347 @@
@startuml
namespace models {
class ComputingModel << (S,Aquamarine) >> {
+ ID string
- getRtype() rtype.Rtype
- getName() string
+ AddUserInput(inputs <font color=blue>map</font>[string]<font color=blue>interface</font>{})
}
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 <font color=blue>struct</font>{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 <font color=blue>map</font>[string]<font color=blue>interface</font>{})
}
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 <font color=blue>map</font>[string]DataObject
+ Computing <font color=blue>map</font>[string]ComputingObject
+ Storage <font color=blue>map</font>[string]StorageObject
+ Datacenter <font color=blue>map</font>[string]DatacenterObject
+ Schedules WorkflowSchedule
+ MxgraphXML string
+ GetExecutionRequirements(dcIDobj string) (ExecutionRequirementsModel, error)
+ GetResource(rObjID *string) ResourceObject
+ GetResourceMapByRtype(rt rtype.Rtype) <font color=blue>interface</font>{}
+ 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 <font color=blue>map</font>[string]Workflow
+ Data []string
+ Computing []string
+ Datacenter []string
+ Storage []string
- getRtype(rID string) rtype.Rtype
- updateDB() error
+ ConsumeMxGraphModel(xmlmodel MxGraphModel) (*Workflow, error, []error)
+ GetResources() <font color=blue>map</font>[rtype.Rtype][]string
+ GetWorkflow(workflowName string) *Workflow
+ GetWorkflows() []string
+ NewResource(rID string, rType string) error
+ GetAllWorkspacesProjects() <font color=blue>chan</font> *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

View File

@ -1,11 +1,13 @@
package models package models
import ( import (
"encoding/xml"
"fmt" "fmt"
"strings" "strings"
"cloud.o-forge.io/core/oc-catalog/models/rtype" "cloud.o-forge.io/core/oc-catalog/models/rtype"
"cloud.o-forge.io/core/oc-catalog/services" "cloud.o-forge.io/core/oc-catalog/services"
structtomap "github.com/Klathmon/StructToMap"
"github.com/beego/beego/v2/core/logs" "github.com/beego/beego/v2/core/logs"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
) )
@ -35,7 +37,7 @@ type ComputingNEWModel struct {
ShortDescription string `json:"short_description,omitempty" required:"true" validate:"required"` ShortDescription string `json:"short_description,omitempty" required:"true" validate:"required"`
Logo string `json:"logo,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"` Owner string `json:"owner,omitempty"`
License string `json:"license,omitempty"` License string `json:"license,omitempty"`
Price uint `json:"price,omitempty"` Price uint `json:"price,omitempty"`
@ -49,7 +51,7 @@ type ComputingNEWModel struct {
Command string `json:"command,omitempty"` Command string `json:"command,omitempty"`
Arguments []string `json:"arguments,omitempty"` Arguments []string `json:"arguments,omitempty"`
Environment []string `json:"environment,omitempty"` Environment []string `json:"environment,omitempty"`
// Ports []string `json:"ports,omitempty"` Ports []string `json:"ports,omitempty"`
// CustomDeployment string `json:"custom_deployment,omitempty"` // CustomDeployment string `json:"custom_deployment,omitempty"`
@ -77,6 +79,11 @@ type ComputingObject struct {
Inputs []string `json:"inputs"` Inputs []string `json:"inputs"`
Outputs []string `json:"outputs"` 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"` 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) 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 // 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 // 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": case "command":
obj.Command = value.(string) obj.Command = value.(string)
case "arguments": case "args":
obj.Arguments = value.([]string) empty, sliced_arguments := getSliceSettings(value.(string))
if (!empty){
obj.Arguments = sliced_arguments
}
case "env" : case "env" :
obj.Environment = value.([]string) empty, sliced_arguments := getSliceSettings(value.(string))
if (!empty){
obj.Environment = sliced_arguments
}
default: 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
} }

View File

@ -22,19 +22,6 @@ type DataNEWModel struct {
Location string `json:"location" required:"true" validate:"required"` 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 { type DataIO struct {
Counter uint `description:"Incremental number starting from 0"` Counter uint `description:"Incremental number starting from 0"`
} }
@ -43,6 +30,18 @@ type DataObject struct {
ReferenceID primitive.ObjectID `json:"referenceID" description:"Data model ID"` 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 { func (obj DataObject) getHost() *string {
return nil // Host is DC only attribute return nil // Host is DC only attribute
} }

View File

@ -8,8 +8,9 @@ type MxGraphModel struct {
XMLName xml.Name `xml:"mxGraphModel"` XMLName xml.Name `xml:"mxGraphModel"`
Root struct { Root struct {
XMLName xml.Name `xml:"root"` XMLName xml.Name `xml:"root"`
MxCell []MxCell `xml:"mxCell"` MxCell []MxCell `xml:"mxCell"`
MxObject *[]MxObject `xml:"object"`
} }
} }
@ -20,6 +21,15 @@ type MxCell struct {
RID *string `xml:"rID,attr"` RID *string `xml:"rID,attr"`
Source *string `xml:"source,attr"` Source *string `xml:"source,attr"`
Target *string `xml:"target,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 { type mxissue struct {
@ -33,3 +43,4 @@ func (m *mxissue) Error() string {
func newMxIssue(message string) error { func newMxIssue(message string) error {
return &mxissue{message} return &mxissue{message}
} }

View File

@ -4,6 +4,8 @@ import (
"context" "context"
"encoding/xml" "encoding/xml"
"errors" "errors"
"net/url"
"os"
"sort" "sort"
"time" "time"
@ -71,18 +73,25 @@ type ResourceObject interface {
addLink(direction LinkingState, rObjID string) 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 // 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 // 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") return ExecutionRequirementsModel{}, errors.New("DC obj" + dcIDobj + " doesn't exist in the Workflow")
} }
// Get all elements that are attached to the DC // Get all elements that are attached to the DC
for _, computingObj := range w.Computing { for _, computingObj := range wf.Computing {
if computingObj.DataCenterID == dcIDobj { if computingObj.DataCenterID == dcIDobj {
mymodel, err := computingObj.getModel() mymodel, err := computingObj.getModel()
if err != nil { if err != nil {
@ -159,6 +168,7 @@ func (w *Workflow) CreateResourceObject(rt rtype.Rtype) ResourceObject {
default: default:
res = nil res = nil
} }
return res 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 //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 var xmlModel MxGraphModel
// logs.Debug(xmlData) // logs.Debug(xmlData)
@ -518,13 +536,17 @@ func ParseMxGraph(username, workflowName, xmlData string) (err error, mxissues [
return err, nil 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) targetWorkspaceWorkflow, err, mxissues := userWorkspace.ConsumeMxGraphModel(xmlModel)
if err != nil { if err != nil {
return err, nil return err, nil
} }
targetWorkspaceWorkflow.MxgraphXML = xmlData 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, _, err = services.MngoCollWorkspace.UpdateOne(services.MngoCtx,
primitive.M{"_id": username}, primitive.M{"_id": username},
@ -564,7 +586,8 @@ func FindSliceInSlice(slice1 []string, slice2 []string) (int, int, bool) {
return -1, -1, false 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{} returned_wf = &Workflow{}
@ -574,11 +597,13 @@ func (w Workspace) ConsumeMxGraphModel(xmlmodel MxGraphModel) (returned_wf *Work
return xmlmodel.Root.MxCell[i].RID != nil return xmlmodel.Root.MxCell[i].RID != nil
}) })
// For each cell of the xml graph, // 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 // in the case cell has a rID retrieve its rType from the value of rID of the component in the worfklow
// retrieve the componant's type // retrieve the component's type
// create an object from the rType // 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 // or by defautlt : the cell represents an arrow
// if the source or the target of the arrow is a datacenter // if the source or the target of the arrow is a datacenter
// define which end of the arrow is the DC // 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 // create a computing object
// attach the DC to it // 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 // 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 { for _, cell := range xmlmodel.Root.MxCell {
switch { switch {
case cell.RID != nil: case cell.RID != nil:
// Case of a Resource resObj, err, mxissues := returned_wf.mxCellToComponent(cell,ws)
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)
if err != nil { if err != nil {
return nil, issues = append(issues, mxissues...)
errors.New("Bad ID format: " + *cell.RID),
nil
} }
resObj := returned_wf.CreateResourceObject(rType)
resObj.setReference(rIDObj)
returned_wf.UpdateObj(resObj, cell.ID) returned_wf.UpdateObj(resObj, cell.ID)
case cell.ID == "0" || cell.ID == "1": 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) // 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 { for _, comp := range returned_wf.Computing {
if comp.DataCenterID == "" { if comp.DataCenterID == "" {
issues = append(issues, errors.New("Computing "+*comp.getName()+" without a Datacenter")) issues = append(issues, errors.New("Computing "+*comp.getName()+" without a Datacenter"))
@ -1005,9 +1039,49 @@ func CheckAndBookWorkflowSchedule(username, workflowName string, book bool) (myR
SchedulesDB: &currentWorkflow.Schedules}}, SchedulesDB: &currentWorkflow.Schedules}},
) )
if err != nil { if err != nil {
logs.Critical("Internal error when updating in DB: " + err.Error()) logs.Critical("Internal error when updating in DB: " + err.Error())
} }
return myRet, nil 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
// }