From 5e7c5ba8889ae79454566de1410adb03f03cb6bf Mon Sep 17 00:00:00 2001 From: Andrey Melnikov Date: Sat, 19 Dec 2020 20:52:52 -0800 Subject: [PATCH] feat: add workflow template and updated workspace template parameter logic to replace select.nodepool values with runtime values. --- pkg/workflow_template.go | 96 +++++++++++++++++++++++++++++ pkg/workspace_template.go | 6 ++ server/workflow_template_server.go | 28 +++++++++ server/workspace_template_server.go | 3 +- 4 files changed, 131 insertions(+), 2 deletions(-) diff --git a/pkg/workflow_template.go b/pkg/workflow_template.go index fd16341..3700b71 100644 --- a/pkg/workflow_template.go +++ b/pkg/workflow_template.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/onepanelio/core/pkg/util/ptr" "github.com/onepanelio/core/pkg/util/request" pagination "github.com/onepanelio/core/pkg/util/request/pagination" "strconv" @@ -32,6 +33,38 @@ func (wt *WorkflowTemplateFilter) GetLabels() []*Label { return wt.Labels } +// replaceSysNodePoolOptions replaces a select.nodepool parameter with the nodePool options in the systemConfig +// and returns the new parameters with the change. +func (c *Client) replaceSysNodePoolOptions(parameters []Parameter) (result []Parameter, err error) { + nodePoolOptions, err := c.systemConfig.NodePoolOptions() + if err != nil { + return result, err + } + + nodePoolParameterOptions := make([]*ParameterOption, 0) + for _, option := range nodePoolOptions { + nodePoolParameterOptions = append(nodePoolParameterOptions, &ParameterOption{ + Name: option.Name, + Value: option.Value, + }) + } + + for i := range parameters { + param := parameters[i] + if param.Type == "select.nodepool" { + param.Options = nodePoolParameterOptions + + if param.Value != nil && *param.Value == "default" { + param.Value = ptr.String(param.Options[0].Value) + } + } + + result = append(result, param) + } + + return +} + func applyWorkflowTemplateFilter(sb sq.SelectBuilder, request *request.Request) (sq.SelectBuilder, error) { if !request.HasFilter() { return sb, nil @@ -390,6 +423,30 @@ func (c *Client) getWorkflowTemplate(namespace, uid string, version int64) (work } workflowTemplate.Parameters = wtv.Parameters + + nodePoolOptions, err := c.systemConfig.NodePoolOptions() + if err != nil { + return nil, err + } + nodePoolParameterOptions := make([]*ParameterOption, 0) + for _, option := range nodePoolOptions { + nodePoolParameterOptions = append(nodePoolParameterOptions, &ParameterOption{ + Name: option.Name, + Value: option.Value, + }) + } + + for i := range workflowTemplate.Parameters { + param := &workflowTemplate.Parameters[i] + if param.Type == "select.nodepool" { + param.Options = nodePoolParameterOptions + + if param.Value != nil && *param.Value == "default" { + param.Value = ptr.String(param.Options[0].Value) + } + } + } + return workflowTemplate, nil } @@ -1061,3 +1118,42 @@ func (c *Client) GetWorkflowTemplateLabels(namespace, name, prefix string, versi return } + +// GenerateWorkflowTemplate replaces any special parameters with runtime values +func (c *Client) GenerateWorkflowTemplateManifest(manifest string) (string, error) { + manifestObject := make(map[string]interface{}) + if err := yaml.Unmarshal([]byte(manifest), &manifestObject); err != nil { + return "", util.NewUserError(codes.InvalidArgument, "Invalid yaml") + } + + argumentsRaw := manifestObject["arguments"] + arguments, ok := argumentsRaw.(map[string]interface{}) + if !ok { + return "", fmt.Errorf("unable to parse arguments") + } + + jsonParameters, err := json.Marshal(arguments["parameters"]) + if err != nil { + return "", err + } + + parameters := make([]Parameter, 0) + if err := json.Unmarshal(jsonParameters, ¶meters); err != nil { + return "", err + } + + parameters, err = c.replaceSysNodePoolOptions(parameters) + if err != nil { + return "", err + } + + arguments["parameters"] = parameters + manifestObject["arguments"] = arguments + + finalManifest, err := yaml.Marshal(manifestObject) + if err != nil { + return "", err + } + + return string(finalManifest), err +} diff --git a/pkg/workspace_template.go b/pkg/workspace_template.go index bcea6d7..06cbad4 100644 --- a/pkg/workspace_template.go +++ b/pkg/workspace_template.go @@ -945,6 +945,12 @@ func (c *Client) generateWorkspaceTemplateWorkflowTemplate(workspaceTemplate *Wo return nil, util.NewUserError(codes.InvalidArgument, err.Error()) } + modifiedParameters, err := c.replaceSysNodePoolOptions(workspaceSpec.Arguments.Parameters) + if err != nil { + return nil, err + } + workspaceSpec.Arguments.Parameters = modifiedParameters + if err = generateArguments(workspaceSpec, config); err != nil { return nil, err } diff --git a/server/workflow_template_server.go b/server/workflow_template_server.go index 4f39e1c..69c6219 100644 --- a/server/workflow_template_server.go +++ b/server/workflow_template_server.go @@ -47,6 +47,34 @@ func apiWorkflowTemplate(wft *v1.WorkflowTemplate) *api.WorkflowTemplate { return res } +// GenerateWorkflowTemplate generates a workflow template, applying any modifications based on the content of the manifest +func (s *WorkflowTemplateServer) GenerateWorkflowTemplate(ctx context.Context, req *api.GenerateWorkflowTemplateRequest) (*api.WorkflowTemplate, error) { + client := getClient(ctx) + allowed, err := auth.IsAuthorized(client, req.Namespace, "get", "argoproj.io", "workflowtemplates", "") + if err != nil || !allowed { + return nil, err + } + + if req.WorkflowTemplate.Manifest == "" { + return &api.WorkflowTemplate{ + Manifest: "", + }, nil + } + + finalManifest, err := client.GenerateWorkflowTemplateManifest(req.WorkflowTemplate.Manifest) + if err != nil { + return &api.WorkflowTemplate{ + Manifest: "", + }, err + } + + workflowTemplate := &v1.WorkflowTemplate{ + Manifest: finalManifest, + } + + return apiWorkflowTemplate(workflowTemplate), nil +} + // CreateWorkflowTemplate creates a workflow template and the initial version func (s *WorkflowTemplateServer) CreateWorkflowTemplate(ctx context.Context, req *api.CreateWorkflowTemplateRequest) (*api.WorkflowTemplate, error) { client := getClient(ctx) diff --git a/server/workspace_template_server.go b/server/workspace_template_server.go index d391042..6f1f0b8 100644 --- a/server/workspace_template_server.go +++ b/server/workspace_template_server.go @@ -61,8 +61,7 @@ func (s WorkspaceTemplateServer) GenerateWorkspaceTemplateWorkflowTemplate(ctx c Manifest: req.WorkspaceTemplate.Manifest, } workflowTemplate, err := client.GenerateWorkspaceTemplateWorkflowTemplate(workspaceTemplate) - - if workflowTemplate == nil { + if err != nil || workflowTemplate == nil { return &api.WorkflowTemplate{ Manifest: "", }, err