Skip to content

Commit

Permalink
feat(ui): resume on selected node. Fixes #5763 (#6885)
Browse files Browse the repository at this point in the history
Signed-off-by: Tianchu Zhao <evantczhao@gmail.com>
  • Loading branch information
tczhao committed Apr 26, 2022
1 parent 3ae8f7e commit a081477
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 4 deletions.
7 changes: 5 additions & 2 deletions ui/src/app/shared/services/workflows-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,11 @@ export class WorkflowsService {
return requests.put(`api/v1/workflows/${namespace}/${name}/suspend`).then(res => res.body as Workflow);
}

public resume(name: string, namespace: string) {
return requests.put(`api/v1/workflows/${namespace}/${name}/resume`).then(res => res.body as Workflow);
public resume(name: string, namespace: string, nodeFieldSelector: string) {
return requests
.put(`api/v1/workflows/${namespace}/${name}/resume`)
.send({nodeFieldSelector})
.then(res => res.body as Workflow);
}

public stop(name: string, namespace: string) {
Expand Down
2 changes: 1 addition & 1 deletion ui/src/app/shared/workflow-operations-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const WorkflowOperationsMap: WorkflowOperations = {
title: 'RESUME',
iconClassName: 'fa fa-play',
disabled: (wf: Workflow) => !Utils.isWorkflowSuspended(wf),
action: (wf: Workflow) => services.workflows.resume(wf.metadata.name, wf.metadata.namespace)
action: (wf: Workflow) => services.workflows.resume(wf.metadata.name, wf.metadata.namespace, null)
},
STOP: {
title: 'STOP',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,14 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
}
};

const renderResumePopup = () => {
return popup.confirm('Confirm', `Are you sure you want to resume node: ${nodeId}?`).then(yes => {
if (yes) {
services.workflows.resume(workflow.metadata.name, workflow.metadata.namespace, 'id=' + nodeId).catch(setError);
}
});
};

const selectedNode = workflow && workflow.status && workflow.status.nodes && workflow.status.nodes[nodeId];
return (
<Page
Expand Down Expand Up @@ -283,6 +291,7 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps<
onShowEvents={() => setSidePanel(`events:${nodeId}`)}
onShowYaml={() => setSidePanel(`yaml:${nodeId}`)}
archived={false}
onResume={() => renderResumePopup()}
/>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ interface Props {
onShowYaml?: (nodeId: string) => any;
onTabSelected?: (tabSelected: string) => void;
selectedTabKey?: string;
onResume?: () => void;
}

const AttributeRow = (attr: {title: string; value: any}) => (
Expand Down Expand Up @@ -149,12 +150,16 @@ const WorkflowNodeSummary = (props: Props) => {
value: <ResourcesDuration resourcesDuration={props.node.resourcesDuration} />
});
}

const showLogs = (x = 'main') => props.onShowContainerLogs(props.node.id, x);
return (
<div className='white-box'>
<div className='white-box__details'>{<AttributeRows attributes={attributes} />}</div>
<div>
{props.node.type === 'Suspend' && props.onResume && (
<Button icon='play' onClick={() => props.onResume()}>
RESUME
</Button>
)}{' '}
{props.node.type !== 'Container' && props.onShowYaml && <Button onClick={() => props.onShowYaml(props.node.id)}>MANIFEST</Button>}{' '}
{props.node.type === 'Pod' && props.onShowContainerLogs && (
<DropDownButton
Expand Down
1 change: 1 addition & 0 deletions workflow/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ func SelectorMatchesNode(selector fields.Selector, node wfv1.NodeStatus) bool {
"templateName": node.TemplateName,
"phase": string(node.Phase),
"name": node.Name,
"id": node.ID,
}
if node.TemplateRef != nil {
nodeFields["templateRef.name"] = node.TemplateRef.Name
Expand Down
61 changes: 61 additions & 0 deletions workflow/util/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/fields"
kubefake "k8s.io/client-go/kubernetes/fake"
"sigs.k8s.io/yaml"

Expand Down Expand Up @@ -484,6 +485,66 @@ func TestUpdateSuspendedNode(t *testing.T) {
}
}

func TestSelectorMatchesNode(t *testing.T) {
tests := map[string]struct {
selector string
outcome bool
}{
"idFound": {
selector: "id=123",
outcome: true,
},
"idNotFound": {
selector: "id=321",
outcome: false,
},
"nameFound": {
selector: "name=failed-node",
outcome: true,
},
"phaseFound": {
selector: "phase=Failed",
outcome: true,
},
"randomNotFound": {
selector: "foo=Failed",
outcome: false,
},
"templateFound": {
selector: "templateRef.name=templateName",
outcome: true,
},
"inputFound": {
selector: "inputs.parameters.myparam.value=abc",
outcome: true,
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
node := wfv1.NodeStatus{ID: "123", Name: "failed-node", Phase: wfv1.NodeFailed, TemplateRef: &wfv1.TemplateRef{
Name: "templateName",
Template: "template",
},
Inputs: &wfv1.Inputs{
Parameters: []wfv1.Parameter{
{
Name: "myparam",
Value: wfv1.AnyStringPtr("abc"),
},
},
},
}
selector, err := fields.ParseSelector(tc.selector)
assert.NoError(t, err)
if tc.outcome {
assert.True(t, SelectorMatchesNode(selector, node))
} else {
assert.False(t, SelectorMatchesNode(selector, node))
}
})
}
}

func TestGetNodeType(t *testing.T) {
t.Run("getNodeType", func(t *testing.T) {
assert.Equal(t, wfv1.NodeTypePod, GetNodeType(&wfv1.Template{Script: &wfv1.ScriptTemplate{}}))
Expand Down

0 comments on commit a081477

Please sign in to comment.