2023-10-18 17:08:53 +02:00
package main
import (
"encoding/json"
"fmt"
"net/url"
"os"
"strings"
"cloud.o-forge.io/core/oc-catalog/models"
2024-04-09 11:20:08 +02:00
"github.com/beego/beego/v2/core/logs"
2023-10-18 17:08:53 +02:00
"github.com/sbabiv/xml2map"
"github.com/tidwall/gjson"
)
type Link struct {
Src string
Dst string
}
type Graph struct {
Links [ ] Link
Datas [ ] models . DataModel
Computings [ ] models . ComputingModel
Datacenters [ ] models . DatacenterModel
Storages [ ] models . StorageModel
ws HttpQuery
}
2024-04-04 12:31:12 +02:00
// Create a dictionnaries with each each existing workflow from a workspace, associated to the JSON representation of its content
2023-10-18 17:08:53 +02:00
func ( g * Graph ) GetGraphList ( apiurl string ) ( map [ string ] string , error ) {
g . ws . Init ( apiurl )
body , err := g . ws . Get ( "v1/workspace/list" )
if err != nil {
return nil , err
}
workspaces := make ( map [ string ] string )
result := gjson . Get ( string ( body ) , "Workflows" )
result . ForEach ( func ( key , value gjson . Result ) bool {
workspaces [ key . Str ] = value . String ( )
return true // keep iterating
} )
return workspaces , nil
}
2024-04-04 12:31:12 +02:00
// Create the objects from the mxgraphxml stored in the workflow given as a parameter
2023-10-18 17:08:53 +02:00
func ( g * Graph ) LoadFrom ( workspace string ) error {
2024-04-04 12:31:12 +02:00
// Extract the xmlgraph from the given workspace
2023-10-18 17:08:53 +02:00
xml := gjson . Get ( workspace , "MxgraphXML" ) . String ( )
decodedValue , err := url . QueryUnescape ( xml )
if err != nil {
return err
}
2024-04-04 12:31:12 +02:00
2023-10-18 17:08:53 +02:00
os . WriteFile ( "graph.xml" , [ ] byte ( decodedValue ) , 0660 )
decoder := xml2map . NewDecoder ( strings . NewReader ( decodedValue ) )
result , err := decoder . Decode ( )
if err != nil {
return err
}
2024-04-04 12:31:12 +02:00
// Retrieve the content of mxcell and object elements
2023-10-18 17:08:53 +02:00
cells := result [ "mxGraphModel" ] . ( map [ string ] interface { } ) [ "root" ] . ( map [ string ] interface { } ) [ "mxCell" ] . ( [ ] map [ string ] interface { } )
obj := result [ "mxGraphModel" ] . ( map [ string ] interface { } ) [ "root" ] . ( map [ string ] interface { } ) [ "object" ]
2024-04-04 12:31:12 +02:00
// Append the content of obj to cells depending on if it's a single key/value pair or a list of it
2023-10-18 17:08:53 +02:00
switch v := obj . ( type ) {
2024-04-04 12:31:12 +02:00
2023-10-18 17:08:53 +02:00
case map [ string ] interface { } :
cells = append ( cells , obj . ( map [ string ] interface { } ) )
2024-04-04 12:31:12 +02:00
_ = v
// fmt.Printf("One: %v", v)
2023-10-18 17:08:53 +02:00
case [ ] map [ string ] interface { } :
cells = append ( cells , obj . ( [ ] map [ string ] interface { } ) ... )
2024-04-04 12:31:12 +02:00
// fmt.Printf("Many: %v", v)
2023-10-18 17:08:53 +02:00
}
2024-04-04 12:31:12 +02:00
2023-10-18 17:08:53 +02:00
dictionnary := make ( map [ string ] string )
var idlinks [ ] Link
2024-04-04 12:31:12 +02:00
g . GetWorkflowComponents ( workspace )
2024-04-09 14:38:52 +02:00
for _ , element := range cells {
// id := element["@id"].(string)
// // Case MXCell
// if _, ok := element["@style"]; ok {
// if _, ok2 := element["@rID"]; ok2 {
// // Resolve elements
// // fmt.Print(id + ": ")
// // fmt.Println(element["@rID"], element["@rType"])
// // fmt.Println(element)
// dictionnary[id] = element["@rID"].(string)
// g.addElementByType(element)
// }
// } else {
// // Case object : contains user's input through the GUI
// if _, ok := element["mxCell"]; ok {
// // Attribute values
// // Extracts the cell ids
// element = element["mxCell"].(map[string]interface{})
// if _, ok := element["@style"]; ok {
// if _, ok2 := element["@rID"]; ok2 {
// // Resolve elements
// // fmt.Print(id + ": ")
// // fmt.Println(element["@rID"], element["@rType"])
// // fmt.Println(element)
// dictionnary[id] = element["@rID"].(string)
// g.addElementByType(element)
// }
// }
// }
// }
// register links
if src , ok := element [ "@source" ] ; ok {
//src = element["@source"].(string)
idlinks = append ( idlinks , Link { Src : src . ( string ) , Dst : element [ "@target" ] . ( string ) } )
// fmt.Println("Link: " + src.(string) + " " + element["@target"].(string))
}
}
2023-10-18 17:08:53 +02:00
// translate links
for _ , link := range idlinks {
g . Links = append ( g . Links , Link { Src : dictionnary [ link . Src ] , Dst : dictionnary [ link . Dst ] } )
fmt . Println ( "Link: " + link . Src + " " + link . Dst + " : " + dictionnary [ link . Src ] + " " + dictionnary [ link . Dst ] )
}
return nil
}
2024-04-09 14:38:52 +02:00
// func (g *Graph) addElementByType(element map[string]interface{}) {
// if element["@rType"] == "data" {
// g.AddDataModel(element["@rID"].(string))
// }
// if element["@rType"] == "datacenter" {
// g.AddDatacenterModel(element["@rID"].(string))
// }
// if element["@rType"] == "computing" {
// g.AddComputingModel(element["@rID"].(string))
// }
// if element["@rType"] == "storage" {
// g.AddStorageModel(element["@rID"].(string))
// }
// }
2024-04-04 12:31:12 +02:00
2024-04-09 11:20:08 +02:00
// TODO : extract all the JSON/data processing to a new object that takes
// the current graph as an attribute and deals with adding new objects
// to it, depending on their type
// Create the objects that correspond to each component
// in a workflow, combining the user input and the base components attributes
func ( g * Graph ) GetWorkflowComponents ( workflow string ) {
types := [ ] string { "computing" , "datacenter" , "data" , "storage" } // create a constant for more maintainability OR even better get the list of all component's type for this WF
for _ , component_type := range types {
// Retrieve the dict of component for a specific type in the workflow
result := gjson . Get ( workflow , component_type )
if ( result . Type != gjson . Null ) {
result . ForEach ( func ( id , value gjson . Result ) bool {
2024-04-09 14:38:52 +02:00
comp_id := value . Get ( "referenceID" ) . Str
2024-04-09 11:20:08 +02:00
if ( comp_id != "" ) {
switch component_type {
case "computing" :
2024-04-09 15:03:12 +02:00
g . AddComputingModel ( comp_id , value , id . Str )
2024-04-09 11:20:08 +02:00
case "data" :
2024-04-09 15:03:12 +02:00
g . AddDataModel ( comp_id , value , id . Str )
2024-04-09 11:20:08 +02:00
case "datacenter" :
2024-04-09 15:03:12 +02:00
g . AddDatacenterModel ( comp_id , value , id . Str )
2024-04-09 11:20:08 +02:00
case "storage" :
2024-04-09 15:03:12 +02:00
g . AddStorageModel ( comp_id , value , id . Str )
2024-04-09 11:20:08 +02:00
default :
logs . Critical ( "Component type doesn't match a know type : " + component_type )
}
}
return true
} )
}
}
}
2024-04-04 12:31:12 +02:00
2024-04-09 15:03:12 +02:00
func ( g * Graph ) AddDataModel ( id string , user_input gjson . Result , wf_id string ) error {
2023-10-18 17:08:53 +02:00
var d models . DataModel
resp , err := g . ws . Get ( "v1/data/" + id )
if err != nil {
return err
}
json . Unmarshal ( resp , & d )
2024-04-09 14:38:52 +02:00
json . Unmarshal ( [ ] byte ( user_input . Raw ) , & d . DataNEWModel )
2024-04-09 15:03:12 +02:00
d . ID = wf_id
2023-10-18 17:08:53 +02:00
g . Datas = append ( g . Datas , d )
return nil
}
2024-04-09 15:03:12 +02:00
func ( g * Graph ) AddDatacenterModel ( id string , user_input gjson . Result , wf_id string ) error {
2023-10-18 17:08:53 +02:00
var d models . DatacenterModel
resp , err := g . ws . Get ( "v1/datacenter/" + id )
if err != nil {
return err
}
json . Unmarshal ( resp , & d )
2024-04-09 14:38:52 +02:00
json . Unmarshal ( [ ] byte ( user_input . Raw ) , & d . DatacenterNEWModel )
2024-04-09 15:03:12 +02:00
d . ID = wf_id
2023-10-18 17:08:53 +02:00
g . Datacenters = append ( g . Datacenters , d )
return nil
}
2024-04-09 15:03:12 +02:00
func ( g * Graph ) AddComputingModel ( id string , user_input gjson . Result , wf_id string ) error {
2023-10-18 17:08:53 +02:00
var c models . ComputingModel
resp , err := g . ws . Get ( "v1/computing/" + id )
if err != nil {
return err
}
json . Unmarshal ( resp , & c )
2024-04-09 14:38:52 +02:00
json . Unmarshal ( [ ] byte ( user_input . Raw ) , & c . ComputingNEWModel )
2024-04-09 15:03:12 +02:00
c . ID = wf_id
2023-10-18 17:08:53 +02:00
g . Computings = append ( g . Computings , c )
return nil
}
2024-04-09 15:03:12 +02:00
func ( g * Graph ) AddStorageModel ( id string , user_input gjson . Result , wf_id string ) error {
2023-10-18 17:08:53 +02:00
var s models . StorageModel
resp , err := g . ws . Get ( "v1/data/" + id )
if err != nil {
return err
}
json . Unmarshal ( resp , & s )
2024-04-09 14:38:52 +02:00
json . Unmarshal ( [ ] byte ( user_input . Raw ) , & s . StorageNEWModel )
2024-04-09 15:03:12 +02:00
s . ID = wf_id
2023-10-18 17:08:53 +02:00
g . Storages = append ( g . Storages , s )
return nil
}
func ( g * Graph ) ExportToArgo ( id string ) error {
return nil
}
func ( g * Graph ) ExportToHelm ( id string ) error {
return nil
}
2024-04-04 12:31:12 +02:00