-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Update Template Resolution Logic #1744
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
59c7b22
079a6d5
f26ccaa
4c1d8a0
e4b9c2e
32a06bf
229d0cd
cf3f170
2390abe
18e7c8f
6ceb655
2687507
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,6 +69,7 @@ type TemplateGetter interface { | |
GetName() string | ||
GroupVersionKind() schema.GroupVersionKind | ||
GetTemplateByName(name string) *Template | ||
GetTemplateScope() string | ||
} | ||
|
||
// TemplateHolder is an interface for holders of templates. | ||
|
@@ -78,6 +79,12 @@ type TemplateHolder interface { | |
IsResolvable() bool | ||
} | ||
|
||
// TemplateStorage is an interface of template storage getter and setter. | ||
type TemplateStorage interface { | ||
GetStoredTemplate(templateScope string, holder TemplateHolder) *Template | ||
SetStoredTemplate(templateScope string, holder TemplateHolder, tmpl *Template) (bool, error) | ||
} | ||
|
||
// Workflow is the definition of a workflow resource | ||
// +genclient | ||
// +genclient:noStatus | ||
|
@@ -98,6 +105,7 @@ type WorkflowList struct { | |
} | ||
|
||
var _ TemplateGetter = &Workflow{} | ||
var _ TemplateStorage = &Workflow{} | ||
|
||
// WorkflowSpec is the specification of a Workflow. | ||
type WorkflowSpec struct { | ||
|
@@ -762,11 +770,16 @@ type NodeStatus struct { | |
TemplateRef *TemplateRef `json:"templateRef,omitempty" protobuf:"bytes,6,opt,name=templateRef"` | ||
|
||
// StoredTemplateID is the ID of stored template. | ||
// DEPRECATED: This value is not used anymore. | ||
StoredTemplateID string `json:"storedTemplateID,omitempty" protobuf:"bytes,18,opt,name=storedTemplateID"` | ||
|
||
// WorkflowTemplateName is the WorkflowTemplate resource name on which the resolved template of this node is retrieved. | ||
// DEPRECATED: This value is not used anymore. | ||
WorkflowTemplateName string `json:"workflowTemplateName,omitempty" protobuf:"bytes,19,opt,name=workflowTemplateName"` | ||
|
||
// TemplateScope is the template scope in which the template of this node was retrieved. | ||
TemplateScope string `json:"templateScope,omitempty" protobuf:"bytes,20,opt,name=templateScope"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the use of this field? I can see failed node status has workflow-template-retry-with-steps-8ddk4-3945074098:
boundaryID: workflow-template-retry-with-steps-8ddk4
displayName: hello2a(0)
finishedAt: "2019-11-25T21:38:27Z"
id: workflow-template-retry-with-steps-8ddk4-3945074098
message: failed with exit code 1
name: workflow-template-retry-with-steps-8ddk4[1].hello2a(0)
phase: Failed
startedAt: "2019-11-25T21:38:23Z"
templateRef:
name: workflow-template-random-fail-template
template: random-fail-template
templateScope: workflow-template-random-fail-template
type: Pod There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still not fully understand the need for this. |
||
|
||
// Phase a simple, high-level summary of where the node is in its lifecycle. | ||
// Can be used as a state machine. | ||
Phase NodePhase `json:"phase,omitempty" protobuf:"bytes,7,opt,name=phase,casttype=NodePhase"` | ||
|
@@ -858,6 +871,20 @@ func (n NodeStatus) CanRetry() bool { | |
return n.Completed() && !n.Successful() | ||
} | ||
|
||
var _ TemplateHolder = &NodeStatus{} | ||
|
||
func (n *NodeStatus) GetTemplateName() string { | ||
return n.TemplateName | ||
} | ||
|
||
func (n *NodeStatus) GetTemplateRef() *TemplateRef { | ||
return n.TemplateRef | ||
} | ||
|
||
func (n *NodeStatus) IsResolvable() bool { | ||
return true | ||
} | ||
|
||
// S3Bucket contains the access information required for interfacing with an S3 bucket | ||
type S3Bucket struct { | ||
// Endpoint is the hostname of the bucket endpoint | ||
|
@@ -1271,6 +1298,11 @@ func (wf *Workflow) GetTemplateByName(name string) *Template { | |
return nil | ||
} | ||
|
||
// GetTemplateScope returns the template scope of workflow. | ||
func (wf *Workflow) GetTemplateScope() string { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really need this function? |
||
return "" | ||
} | ||
|
||
// NodeID creates a deterministic node ID based on a node name | ||
func (wf *Workflow) NodeID(name string) string { | ||
if name == wf.ObjectMeta.Name { | ||
|
@@ -1281,34 +1313,47 @@ func (wf *Workflow) NodeID(name string) string { | |
return fmt.Sprintf("%s-%v", wf.ObjectMeta.Name, h.Sum32()) | ||
} | ||
|
||
// GetStoredTemplate gets a resolved template from stored data. | ||
func (wf *Workflow) GetStoredTemplate(node *NodeStatus) *Template { | ||
id := node.StoredTemplateID | ||
if id == "" { | ||
// GetStoredTemplate retrieves a template from stored templates of the workflow. | ||
func (wf *Workflow) GetStoredTemplate(templateScope string, holder TemplateHolder) *Template { | ||
tmplID := wf.getStoredTemplateName(templateScope, holder) | ||
if tmplID == "" { | ||
return nil | ||
} | ||
tmpl, ok := wf.Status.StoredTemplates[id] | ||
if ok { | ||
return &tmpl | ||
tmpl, ok := wf.Status.StoredTemplates[tmplID] | ||
if !ok { | ||
return nil | ||
} | ||
return nil | ||
return &tmpl | ||
} | ||
|
||
// GetStoredOrLocalTemplate gets a resolved template from stored data or local template. | ||
func (wf *Workflow) GetStoredOrLocalTemplate(node *NodeStatus) *Template { | ||
// Try to find a template from stored data. | ||
tmpl := wf.GetStoredTemplate(node) | ||
if tmpl != nil { | ||
return tmpl | ||
// SetStoredTemplate stores a new template in stored templates of the workflow. | ||
func (wf *Workflow) SetStoredTemplate(templateScope string, holder TemplateHolder, tmpl *Template) (bool, error) { | ||
tmplID := wf.getStoredTemplateName(templateScope, holder) | ||
if tmplID == "" { | ||
return false, nil | ||
} | ||
// Try to get template from Workflow. | ||
if node.WorkflowTemplateName == "" && node.TemplateName != "" { | ||
tmpl := wf.GetTemplateByName(node.TemplateName) | ||
if tmpl != nil { | ||
return tmpl | ||
_, ok := wf.Status.StoredTemplates[tmplID] | ||
if !ok { | ||
if wf.Status.StoredTemplates == nil { | ||
wf.Status.StoredTemplates = map[string]Template{} | ||
} | ||
wf.Status.StoredTemplates[tmplID] = *tmpl | ||
return true, nil | ||
} | ||
return false, nil | ||
} | ||
|
||
// getStoredTemplateName returns the stored template name of a given template holder on the template scope. | ||
func (wf *Workflow) getStoredTemplateName(templateScope string, holder TemplateHolder) string { | ||
tmplRef := holder.GetTemplateRef() | ||
if tmplRef != nil { | ||
return fmt.Sprintf("%s/%s", tmplRef.Name, tmplRef.Template) | ||
} else if templateScope != "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same as above comments |
||
return fmt.Sprintf("%s/%s", templateScope, holder.GetTemplateName()) | ||
} else { | ||
// Do not store workflow-local templates. | ||
return "" | ||
} | ||
return nil | ||
} | ||
|
||
// ContinueOn defines if a workflow should continue even if a task or step fails/errors. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sure I'm missing something obvious, but could you help me understand why this is implemented in both
Workflow
andwfOperationCtx
? It seems like all the implementation forwfOperationCtx
does is call the implementation of theWorkflow
:Why do you not pass the
Workflow
as theTemplateStorage
instead of thewfOperationCtx
inoperator.go
:Like you do in
validate.go
:Sorry if this is an obvious question.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because I wanted to let the operator save the workflow.
https://github.com/argoproj/argo/blob/fae7382686d917d78e3909d1f6db79c272a1aa11/workflow/controller/operator.go#L381-L384
Need to flag
woc.updated
if new stored templates are saved.