|
|
|
|
@@ -8,14 +8,13 @@ import (
|
|
|
|
|
"fmt"
|
|
|
|
|
. "oc-monitord/models"
|
|
|
|
|
"os"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
oclib "cloud.o-forge.io/core/oc-lib"
|
|
|
|
|
"cloud.o-forge.io/core/oc-lib/models/common/enum"
|
|
|
|
|
"cloud.o-forge.io/core/oc-lib/models/resources"
|
|
|
|
|
w "cloud.o-forge.io/core/oc-lib/models/workflow"
|
|
|
|
|
"cloud.o-forge.io/core/oc-lib/models/workflow/graph"
|
|
|
|
|
"github.com/nwtgck/go-fakelish"
|
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
|
@@ -39,14 +38,6 @@ type Workflow struct {
|
|
|
|
|
Spec Spec `yaml:"spec,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Workflow) setDag(dag *Dag) {
|
|
|
|
|
for _, t := range b.Spec.Templates {
|
|
|
|
|
if t.Name == "dag" {
|
|
|
|
|
t.Dag = dag
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *Workflow) getDag() *Dag {
|
|
|
|
|
for _, t := range b.Spec.Templates {
|
|
|
|
|
if t.Name == "dag" {
|
|
|
|
|
@@ -65,8 +56,10 @@ type Spec struct {
|
|
|
|
|
Timeout int `yaml:"activeDeadlineSeconds,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: found on a processing instance linked to storage
|
|
|
|
|
// add s3, gcs, azure, etc if needed on a link between processing and storage
|
|
|
|
|
func (b *ArgoBuilder) CreateDAG(write bool) (string, int, []string, []string, error) {
|
|
|
|
|
|
|
|
|
|
fmt.Println("Creating DAG", b.OriginWorkflow.Graph.Items)
|
|
|
|
|
// handle services by checking if there is only one processing with hostname and port
|
|
|
|
|
firstItems, lastItems, volumes := b.createTemplates()
|
|
|
|
|
b.createVolumes(volumes)
|
|
|
|
|
@@ -104,14 +97,17 @@ func (b *ArgoBuilder) createTemplates() ([]string, []string, []VolumeMount) {
|
|
|
|
|
volumes := []VolumeMount{}
|
|
|
|
|
firstItems := []string{}
|
|
|
|
|
lastItems := []string{}
|
|
|
|
|
for _, comp := range b.OriginWorkflow.ProcessingResources {
|
|
|
|
|
if comp.Container != nil {
|
|
|
|
|
volumes, firstItems, lastItems = b.createArgoTemplates(
|
|
|
|
|
comp.UUID, comp, volumes, firstItems, lastItems)
|
|
|
|
|
} else {
|
|
|
|
|
logger.Error().Msg("Not enough configuration setup, template can't be created : " + comp.GetName())
|
|
|
|
|
items := b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsProcessing)
|
|
|
|
|
fmt.Println("Creating templates", len(items))
|
|
|
|
|
for _, item := range b.OriginWorkflow.GetGraphItems(b.OriginWorkflow.Graph.IsProcessing) {
|
|
|
|
|
instance := item.Processing.GetSelectedInstance()
|
|
|
|
|
fmt.Println("Creating template for", item.Processing.GetName(), instance)
|
|
|
|
|
if instance == nil || instance.(*resources.ProcessingInstance).Access == nil && instance.(*resources.ProcessingInstance).Access.Container != nil {
|
|
|
|
|
logger.Error().Msg("Not enough configuration setup, template can't be created : " + item.Processing.GetName())
|
|
|
|
|
return firstItems, lastItems, volumes
|
|
|
|
|
}
|
|
|
|
|
volumes, firstItems, lastItems = b.createArgoTemplates(
|
|
|
|
|
item.ID, item.Processing, volumes, firstItems, lastItems)
|
|
|
|
|
}
|
|
|
|
|
firstWfTasks := map[string][]string{}
|
|
|
|
|
latestWfTasks := map[string][]string{}
|
|
|
|
|
@@ -187,6 +183,7 @@ func (b *ArgoBuilder) createArgoTemplates(id string,
|
|
|
|
|
lastItems []string) ([]VolumeMount, []string, []string) {
|
|
|
|
|
_, firstItems, lastItems = b.addTaskToArgo(b.Workflow.getDag(), id, processing, firstItems, lastItems)
|
|
|
|
|
template := &Template{Name: getArgoName(processing.GetName(), id)}
|
|
|
|
|
fmt.Println("Creating template for", template.Name)
|
|
|
|
|
template.CreateContainer(processing, b.Workflow.getDag())
|
|
|
|
|
// get datacenter from the processing
|
|
|
|
|
if processing.IsService {
|
|
|
|
|
@@ -194,17 +191,39 @@ func (b *ArgoBuilder) createArgoTemplates(id string,
|
|
|
|
|
template.Metadata.Labels = make(map[string]string)
|
|
|
|
|
template.Metadata.Labels["app"] = "oc-service-" + processing.GetName() // Construct the template for the k8s service and add a link in graph between k8s service and processing
|
|
|
|
|
}
|
|
|
|
|
storages := b.OriginWorkflow.GetByRelatedProcessing(id, b.OriginWorkflow.IsStorage)
|
|
|
|
|
for _, storage := range storages {
|
|
|
|
|
if storage.(*resources.StorageResource).SelectedInstanceIndex < 0 {
|
|
|
|
|
continue
|
|
|
|
|
related := b.OriginWorkflow.GetByRelatedProcessing(id, b.OriginWorkflow.Graph.IsStorage)
|
|
|
|
|
for _, r := range related {
|
|
|
|
|
storage := r.Node.(*resources.StorageResource)
|
|
|
|
|
for _, linkToStorage := range r.Links {
|
|
|
|
|
for _, rw := range linkToStorage.StorageLinkInfos {
|
|
|
|
|
art := Artifact{Path: template.ReplacePerEnv(rw.Source, linkToStorage.Env)}
|
|
|
|
|
if rw.Write {
|
|
|
|
|
art.Name = storage.GetName() + "-" + rw.Destination + "-input-write"
|
|
|
|
|
} else {
|
|
|
|
|
art.Name = storage.GetName() + "-" + rw.Destination + "-input-read"
|
|
|
|
|
}
|
|
|
|
|
if storage.StorageType == enum.S3 {
|
|
|
|
|
art.S3 = &Key{
|
|
|
|
|
Key: template.ReplacePerEnv(rw.Destination+"/"+rw.FileName, linkToStorage.Env),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if rw.Write {
|
|
|
|
|
template.Outputs.Artifacts = append(template.Inputs.Artifacts, art)
|
|
|
|
|
} else {
|
|
|
|
|
template.Inputs.Artifacts = append(template.Outputs.Artifacts, art)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s := storage.(*resources.StorageResource).Instances[storage.(*resources.StorageResource).SelectedInstanceIndex]
|
|
|
|
|
index := 0
|
|
|
|
|
if storage.SelectedInstanceIndex != nil && (*storage.SelectedInstanceIndex) >= 0 {
|
|
|
|
|
index = *storage.SelectedInstanceIndex
|
|
|
|
|
}
|
|
|
|
|
s := storage.Instances[index]
|
|
|
|
|
if s.Local {
|
|
|
|
|
volumes = template.Container.AddVolumeMount(VolumeMount{
|
|
|
|
|
Name: strings.ReplaceAll(strings.ToLower(storage.GetName()), " ", "-"),
|
|
|
|
|
MountPath: s.Source,
|
|
|
|
|
Storage: storage.(*resources.StorageResource),
|
|
|
|
|
Storage: storage,
|
|
|
|
|
}, volumes)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -215,11 +234,24 @@ func (b *ArgoBuilder) addTaskToArgo(dag *Dag, graphItemID string, processing *re
|
|
|
|
|
firstItems []string, lastItems []string) (*Dag, []string, []string) {
|
|
|
|
|
unique_name := getArgoName(processing.GetName(), graphItemID)
|
|
|
|
|
step := Task{Name: unique_name, Template: unique_name}
|
|
|
|
|
if processing.Container != nil {
|
|
|
|
|
for name, value := range processing.Container.Env {
|
|
|
|
|
instance := processing.GetSelectedInstance()
|
|
|
|
|
if instance != nil {
|
|
|
|
|
for _, value := range instance.(*resources.ProcessingInstance).Env {
|
|
|
|
|
step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{
|
|
|
|
|
Name: name,
|
|
|
|
|
Value: b.affectVariableEnv(value, b.OriginWorkflow.Graph),
|
|
|
|
|
Name: value.Name,
|
|
|
|
|
Value: value.Value,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
for _, value := range instance.(*resources.ProcessingInstance).Inputs {
|
|
|
|
|
step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{
|
|
|
|
|
Name: value.Name,
|
|
|
|
|
Value: value.Value,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
for _, value := range instance.(*resources.ProcessingInstance).Outputs {
|
|
|
|
|
step.Arguments.Parameters = append(step.Arguments.Parameters, Parameter{
|
|
|
|
|
Name: value.Name,
|
|
|
|
|
Value: value.Value,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -241,32 +273,13 @@ func (b *ArgoBuilder) addTaskToArgo(dag *Dag, graphItemID string, processing *re
|
|
|
|
|
return dag, firstItems, lastItems
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *ArgoBuilder) affectVariableEnv(envVar string, graph *graph.Graph) string {
|
|
|
|
|
var myExp = regexp.MustCompile(`(\{\{.*\}\})`) // regex to find all the variables in the command
|
|
|
|
|
matches := myExp.FindAllString(envVar, -1) // find all the variables in the command
|
|
|
|
|
for _, match := range matches { // for each variable in the command
|
|
|
|
|
splitted := strings.Split( // split the variable to get the inout and the vars only
|
|
|
|
|
strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(match, "{{", ""), "}}", ""), " ", ""), "_")
|
|
|
|
|
if len(splitted) < 3 { // if the variable is not well formatted, we skip it
|
|
|
|
|
logger.Error().Msgf("The variable %v is not well formatted", match)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
graphItemID := splitted[1] // graphitemid is the id of the object
|
|
|
|
|
vars := splitted[2] // vars is the name of the variable of the object
|
|
|
|
|
_, obj := graph.GetResource(graphItemID)
|
|
|
|
|
if obj != nil {
|
|
|
|
|
envVar = strings.ReplaceAll(envVar, match, fmt.Sprintf("%v", obj.Serialize(obj)[vars]))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return envVar
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *ArgoBuilder) createVolumes(volumes []VolumeMount) { // TODO : one think about remote volume but TG
|
|
|
|
|
for _, volume := range volumes {
|
|
|
|
|
if volume.Storage.SelectedInstanceIndex < 0 {
|
|
|
|
|
continue
|
|
|
|
|
index := 0
|
|
|
|
|
if volume.Storage.SelectedInstanceIndex != nil && (*volume.Storage.SelectedInstanceIndex) >= 0 {
|
|
|
|
|
index = *volume.Storage.SelectedInstanceIndex
|
|
|
|
|
}
|
|
|
|
|
storage := volume.Storage.Instances[volume.Storage.SelectedInstanceIndex]
|
|
|
|
|
storage := volume.Storage.Instances[index]
|
|
|
|
|
new_volume := VolumeClaimTemplate{}
|
|
|
|
|
new_volume.Metadata.Name = strings.ReplaceAll(strings.ToLower(volume.Name), " ", "-")
|
|
|
|
|
new_volume.Spec.AccessModes = []string{"ReadWriteOnce"}
|
|
|
|
|
@@ -295,6 +308,10 @@ func (b *ArgoBuilder) isArgoDependancy(id string) (bool, []string) {
|
|
|
|
|
|
|
|
|
|
func (b *ArgoBuilder) getArgoDependencies(id string) (dependencies []string) {
|
|
|
|
|
for _, link := range b.OriginWorkflow.Graph.Links {
|
|
|
|
|
if _, ok := b.OriginWorkflow.Graph.Items[link.Source.ID]; !ok {
|
|
|
|
|
fmt.Println("Could not find the source of the link", link.Source.ID)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
source := b.OriginWorkflow.Graph.Items[link.Source.ID].Processing
|
|
|
|
|
if id == link.Destination.ID && source != nil {
|
|
|
|
|
dependency_name := getArgoName(source.GetName(), link.Source.ID)
|
|
|
|
|
|