Skip to content

Commit

Permalink
feat(controller): adds Kubernetes node name to workflow node detail i…
Browse files Browse the repository at this point in the history
…n web UI and CLI output. Implements argoproj#2540 (argoproj#2732)
  • Loading branch information
aistein committed Apr 22, 2020
1 parent 52fa5fd commit 8de5728
Show file tree
Hide file tree
Showing 12 changed files with 490 additions and 409 deletions.
4 changes: 4 additions & 0 deletions api/openapi-spec/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -2484,6 +2484,10 @@
"title": "Time at which this node completed",
"$ref": "#/definitions/io.k8s.api.core.v1.Time"
},
"hostNodeName": {
"type": "string",
"title": "HostNodeName name of the Kubernetes node on which the Pod is running, if applicable"
},
"id": {
"type": "string",
"title": "ID is a unique identifier of a node within the worklow\nIt is implemented as a hash of the node name, which makes the ID deterministic"
Expand Down
20 changes: 12 additions & 8 deletions cmd/argo/commands/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func printWorkflowHelper(wf *wfv1.Workflow, getArgs getFlags) {
fmt.Println()
// apply a dummy FgDefault format to align tab writer with the rest of the columns
if getArgs.output == "wide" {
_, _ = fmt.Fprintf(w, "%s\tTEMPLATE\tPODNAME\tDURATION\tARTIFACTS\tMESSAGE\tRESOURCESDURATION\n", ansiFormat("STEP", FgDefault))
_, _ = fmt.Fprintf(w, "%s\tTEMPLATE\tPODNAME\tDURATION\tARTIFACTS\tMESSAGE\tRESOURCESDURATION\tNODENAME\n", ansiFormat("STEP", FgDefault))
} else {
_, _ = fmt.Fprintf(w, "%s\tTEMPLATE\tPODNAME\tDURATION\tMESSAGE\n", ansiFormat("STEP", FgDefault))
}
Expand Down Expand Up @@ -447,17 +447,21 @@ func printNode(w *tabwriter.Writer, node wfv1.NodeStatus, nodePrefix string, get
var args []interface{}
duration := humanize.RelativeDurationShort(node.StartedAt.Time, node.FinishedAt.Time)
if node.Type == wfv1.NodeTypePod {
args = []interface{}{nodePrefix, nodeName, templateName, node.ID, duration, node.Message}
args = []interface{}{nodePrefix, nodeName, templateName, node.ID, duration, node.Message, ""}
} else {
args = []interface{}{nodePrefix, nodeName, templateName, "", "", node.Message}
args = []interface{}{nodePrefix, nodeName, templateName, "", "", node.Message, ""}
}
if getArgs.output == "wide" {
msg := args[len(args)-1]
args[len(args)-1] = getArtifactsString(node)
args = append(args, msg, node.ResourcesDuration)
_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\t%s\t%s\n", args...)
msg := args[len(args)-2]
args[len(args)-2] = getArtifactsString(node)
args[len(args)-1] = msg
args = append(args, node.ResourcesDuration, "")
if node.Type == wfv1.NodeTypePod {
args[len(args)-1] = node.HostNodeName
}
_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", args...)
} else {
_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\n", args...)
_, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\t%s\n", args...)
}
}

Expand Down
15 changes: 10 additions & 5 deletions cmd/argo/commands/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func testPrintNodeImpl(t *testing.T, expected string, node wfv1.NodeStatus, node
// TestPrintNode
func TestPrintNode(t *testing.T) {
nodeName := "testNode"
kubernetesNodeName := "testKnodeName"
nodePrefix := ""
nodeTemplateName := "testTemplate"
nodeTemplateRefName := "testTemplateRef"
Expand All @@ -47,22 +48,26 @@ func TestPrintNode(t *testing.T) {
FinishedAt: timestamp,
Message: nodeMessage,
}
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s\t%s\t%s\t%s\n", jobStatusIconMap[wfv1.NodeRunning], nodeName, "", nodeID, "0s", nodeMessage), node, nodePrefix, getArgs)
node.HostNodeName = kubernetesNodeName
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s\t%s\t%s\t%s\t%s\n", jobStatusIconMap[wfv1.NodeRunning], nodeName, "", nodeID, "0s", nodeMessage, ""), node, nodePrefix, getArgs)

node.TemplateName = nodeTemplateName
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s\t%s\t%s\t%s\n", jobStatusIconMap[wfv1.NodeRunning], nodeName, nodeTemplateName, nodeID, "0s", nodeMessage), node, nodePrefix, getArgs)
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s\t%s\t%s\t%s\t%s\n", jobStatusIconMap[wfv1.NodeRunning], nodeName, nodeTemplateName, nodeID, "0s", nodeMessage, ""), node, nodePrefix, getArgs)

node.Type = wfv1.NodeTypeSuspend
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s\t%s\t%s\t%s\n", nodeTypeIconMap[wfv1.NodeTypeSuspend], nodeName, nodeTemplateName, "", "", nodeMessage), node, nodePrefix, getArgs)
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s\t%s\t%s\t%s\t%s\n", nodeTypeIconMap[wfv1.NodeTypeSuspend], nodeName, nodeTemplateName, "", "", nodeMessage, ""), node, nodePrefix, getArgs)

node.TemplateRef = &wfv1.TemplateRef{
Name: nodeTemplateRefName,
Template: nodeTemplateRefName,
}
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s/%s\t%s\t%s\t%s\n", nodeTypeIconMap[wfv1.NodeTypeSuspend], nodeName, nodeTemplateRefName, nodeTemplateRefName, "", "", nodeMessage), node, nodePrefix, getArgs)
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s/%s\t%s\t%s\t%s\t%s\n", nodeTypeIconMap[wfv1.NodeTypeSuspend], nodeName, nodeTemplateRefName, nodeTemplateRefName, "", "", nodeMessage, ""), node, nodePrefix, getArgs)

getArgs.output = "wide"
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s/%s\t%s\t%s\t%s\t%s\t\n", nodeTypeIconMap[wfv1.NodeTypeSuspend], nodeName, nodeTemplateRefName, nodeTemplateRefName, "", "", getArtifactsString(node), nodeMessage), node, nodePrefix, getArgs)
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s/%s\t%s\t%s\t%s\t%s\t%s\t\n", nodeTypeIconMap[wfv1.NodeTypeSuspend], nodeName, nodeTemplateRefName, nodeTemplateRefName, "", "", getArtifactsString(node), nodeMessage, ""), node, nodePrefix, getArgs)

node.Type = wfv1.NodeTypePod
testPrintNodeImpl(t, fmt.Sprintf("%s %s\t%s/%s\t%s\t%s\t%s\t%s\t%s\t%s\n", jobStatusIconMap[wfv1.NodeRunning], nodeName, nodeTemplateRefName, nodeTemplateRefName, nodeID, "0s", getArtifactsString(node), nodeMessage, "", kubernetesNodeName), node, nodePrefix, getArgs)

getArgs.status = "foobar"
testPrintNodeImpl(t, "", node, nodePrefix, getArgs)
Expand Down
1 change: 1 addition & 0 deletions docs/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,7 @@ NodeStatus contains status information about an individual node in the workflow
|`daemoned`|`boolean`|Daemoned tracks whether or not this node was daemoned and need to be terminated|
|`displayName`|`string`|DisplayName is a human readable representation of the node. Unique within a template boundary|
|`finishedAt`|[`Time`](#time)|Time at which this node completed|
|`hostNodeName`|`string`|HostNodeName name of the Kubernetes node on which the Pod is running, if applicable|
|`id`|`string`|ID is a unique identifier of a node within the worklowIt is implemented as a hash of the node name, which makes the ID deterministic|
|`inputs`|[`Inputs`](#inputs)|Inputs captures input parameter values and artifact locations supplied to this template invocation|
|`message`|`string`|A human readable message indicating details about why the node is in this condition.|
Expand Down
4 changes: 4 additions & 0 deletions pkg/apiclient/workflow/workflow.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,10 @@
"type": "string"
},
"description": "OutboundNodes tracks the node IDs which are considered \"outbound\" nodes to a template invocation.\nFor every invocation of a template, there are nodes which we considered as \"outbound\". Essentially,\nthese are last nodes in the execution sequence to run, before the template is considered completed.\nThese nodes are then connected as parents to a following step.\n\nIn the case of single pod steps (i.e. container, script, resource templates), this list will be nil\nsince the pod itself is already considered the \"outbound\" node.\nIn the case of DAGs, outbound nodes are the \"target\" tasks (tasks with no children).\nIn the case of steps, outbound nodes are all the containers involved in the last step group.\nNOTE: since templates are composable, the list of outbound nodes are carried upwards when\na DAG/steps template invokes another DAG/steps template. In other words, the outbound nodes of\na template, will be a superset of the outbound nodes of its last children."
},
"hostNodeName": {
"type": "string",
"title": "HostNodeName name of the Kubernetes node on which the Pod is running, if applicable"
}
},
"title": "NodeStatus contains status information about an individual node in the workflow"
Expand Down
4 changes: 4 additions & 0 deletions pkg/apiclient/workflowarchive/workflow-archive.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,10 @@
"type": "string"
},
"description": "OutboundNodes tracks the node IDs which are considered \"outbound\" nodes to a template invocation.\nFor every invocation of a template, there are nodes which we considered as \"outbound\". Essentially,\nthese are last nodes in the execution sequence to run, before the template is considered completed.\nThese nodes are then connected as parents to a following step.\n\nIn the case of single pod steps (i.e. container, script, resource templates), this list will be nil\nsince the pod itself is already considered the \"outbound\" node.\nIn the case of DAGs, outbound nodes are the \"target\" tasks (tasks with no children).\nIn the case of steps, outbound nodes are all the containers involved in the last step group.\nNOTE: since templates are composable, the list of outbound nodes are carried upwards when\na DAG/steps template invokes another DAG/steps template. In other words, the outbound nodes of\na template, will be a superset of the outbound nodes of its last children."
},
"hostNodeName": {
"type": "string",
"title": "HostNodeName name of the Kubernetes node on which the Pod is running, if applicable"
}
},
"title": "NodeStatus contains status information about an individual node in the workflow"
Expand Down
Loading

0 comments on commit 8de5728

Please sign in to comment.