diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 913f8b52e8bc..51959f84eacb 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -467,6 +467,12 @@ type WorkflowSpec struct { // ArtifactGC describes the strategy to use when deleting artifacts from completed or deleted workflows (applies to all output Artifacts // unless Artifact.ArtifactGC is specified, which overrides this) ArtifactGC *WorkflowLevelArtifactGC `json:"artifactGC,omitempty" protobuf:"bytes,43,opt,name=artifactGC"` + + // DisableRetry prevents manual retry of this workflow once it has completed. + DisableRetry bool `json:"disableRetry,omitempty" protobuf:"varint,44,opt,name=disableRetry"` + + // DisableResubmit prevents resubmission of this workflow once it has completed. + DisableResubmit bool `json:"disableResubmit,omitempty" protobuf:"varint,45,opt,name=disableResubmit"` } type LabelValueFrom struct { diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 7a68127e1456..72df888d0b62 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -487,6 +487,10 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor return nil, sutils.ToStatusError(err, codes.InvalidArgument) } + if wf.Spec.DisableRetry { + return nil, status.Errorf(codes.FailedPrecondition, "retry is disabled for workflow %s", wf.Name) + } + err = s.hydrator.Hydrate(ctx, wf) if err != nil { return nil, sutils.ToStatusError(err, codes.Internal) @@ -543,6 +547,10 @@ func (s *workflowServer) ResubmitWorkflow(ctx context.Context, req *workflowpkg. return nil, sutils.ToStatusError(err, codes.InvalidArgument) } + if wf.Spec.DisableResubmit { + return nil, status.Errorf(codes.FailedPrecondition, "resubmit is disabled for workflow %s", wf.Name) + } + newWF, err := util.FormulateResubmitWorkflow(ctx, wf, req.Memoized, req.Parameters) if err != nil { return nil, sutils.ToStatusError(err, codes.Internal) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 4c7722caebc1..e651433ab033 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -216,6 +216,10 @@ func (w *archivedWorkflowServer) ResubmitArchivedWorkflow(ctx context.Context, r return nil, sutils.ToStatusError(err, codes.Internal) } + if wf.Spec.DisableResubmit { + return nil, status.Errorf(codes.FailedPrecondition, "resubmit is disabled for workflow %s", wf.Name) + } + newWF, err := util.FormulateResubmitWorkflow(ctx, wf, req.Memoized, req.Parameters) if err != nil { return nil, sutils.ToStatusError(err, codes.Internal) @@ -245,6 +249,11 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req if err != nil { return nil, sutils.ToStatusError(err, codes.Internal) } + + if wf.Spec.DisableRetry { + return nil, status.Errorf(codes.FailedPrecondition, "retry is disabled for workflow %s", wf.Name) + } + oriUID := wf.UID _, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Get(ctx, wf.Name, metav1.GetOptions{}) diff --git a/ui/src/shared/models/workflows.ts b/ui/src/shared/models/workflows.ts index bd43e1917967..de211dd9ade0 100644 --- a/ui/src/shared/models/workflows.ts +++ b/ui/src/shared/models/workflows.ts @@ -888,6 +888,16 @@ export interface WorkflowSpec { * workflowTemplateRef is the reference to the workflow template resource to execute. */ workflowTemplateRef?: WorkflowTemplateRef; + + /** + * DisableRetry prevents manual retry of this workflow once it has completed. + */ + disableRetry?: boolean; + + /** + * DisableResubmit prevents resubmission of this workflow once it has completed. + */ + disableResubmit?: boolean; } export interface WorkflowTemplateRef { diff --git a/ui/src/shared/workflow-operations-map.ts b/ui/src/shared/workflow-operations-map.ts index 0707a8f76bd1..e2ca04854e47 100644 --- a/ui/src/shared/workflow-operations-map.ts +++ b/ui/src/shared/workflow-operations-map.ts @@ -26,6 +26,9 @@ export const WorkflowOperationsMap: WorkflowOperations = { title: 'RETRY', iconClassName: 'fa fa-undo', disabled: (wf: Workflow) => { + if (wf?.spec?.disableRetry) { + return true; + } const workflowPhase: NodePhase = wf && wf.status ? wf.status.phase : undefined; return workflowPhase === undefined || !(workflowPhase === 'Failed' || workflowPhase === 'Error'); }, @@ -34,7 +37,7 @@ export const WorkflowOperationsMap: WorkflowOperations = { RESUBMIT: { title: 'RESUBMIT', iconClassName: 'fa fa-plus-circle', - disabled: () => false, + disabled: (wf: Workflow) => wf?.spec?.disableResubmit === true, action: (wf: Workflow) => services.workflows.resubmit(wf.metadata.name, wf.metadata.namespace, null) }, SUSPEND: {