NIFI-4481:

- Adding support for visualizing if a component is scheduled for primary node only.
This closes #2210.
This commit is contained in:
Matt Gilman 2017-10-12 13:58:50 -04:00 committed by Mark Payne
parent b8a3862078
commit 53e63eaf7c
8 changed files with 111 additions and 9 deletions

View File

@ -16,6 +16,8 @@
*/ */
package org.apache.nifi.controller.status; package org.apache.nifi.controller.status;
import org.apache.nifi.scheduling.ExecutionNode;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -29,6 +31,7 @@ public class ProcessorStatus implements Cloneable {
private String name; private String name;
private String type; private String type;
private RunStatus runStatus; private RunStatus runStatus;
private ExecutionNode executionNode;
private int inputCount; private int inputCount;
private long inputBytes; private long inputBytes;
private int outputCount; private int outputCount;
@ -90,6 +93,14 @@ public class ProcessorStatus implements Cloneable {
this.runStatus = runStatus; this.runStatus = runStatus;
} }
public ExecutionNode getExecutionNode() {
return executionNode;
}
public void setExecutionNode(ExecutionNode executionNode) {
this.executionNode = executionNode;
}
public void setInputCount(final int inputCount) { public void setInputCount(final int inputCount) {
this.inputCount = inputCount; this.inputCount = inputCount;
} }
@ -244,6 +255,7 @@ public class ProcessorStatus implements Cloneable {
clonedObj.averageLineageDuration = averageLineageDuration; clonedObj.averageLineageDuration = averageLineageDuration;
clonedObj.flowFilesRemoved = flowFilesRemoved; clonedObj.flowFilesRemoved = flowFilesRemoved;
clonedObj.runStatus = runStatus; clonedObj.runStatus = runStatus;
clonedObj.executionNode = executionNode;
clonedObj.type = type; clonedObj.type = type;
clonedObj.counters = counters == null ? null : new HashMap<>(counters); clonedObj.counters = counters == null ? null : new HashMap<>(counters);
return clonedObj; return clonedObj;
@ -262,6 +274,8 @@ public class ProcessorStatus implements Cloneable {
builder.append(type); builder.append(type);
builder.append(", runStatus="); builder.append(", runStatus=");
builder.append(runStatus); builder.append(runStatus);
builder.append(", executionNode=");
builder.append(executionNode);
builder.append(", inputCount="); builder.append(", inputCount=");
builder.append(inputCount); builder.append(inputCount);
builder.append(", inputBytes="); builder.append(", inputBytes=");

View File

@ -31,6 +31,7 @@ public class ProcessorStatusSnapshotDTO implements Cloneable {
private String name; private String name;
private String type; private String type;
private String runStatus; private String runStatus;
private String executionNode;
private Long bytesRead = 0L; private Long bytesRead = 0L;
private Long bytesWritten = 0L; private Long bytesWritten = 0L;
@ -103,6 +104,18 @@ public class ProcessorStatusSnapshotDTO implements Cloneable {
this.runStatus = runStatus; this.runStatus = runStatus;
} }
@ApiModelProperty(
value = "Indicates the node where the process will execute.",
allowableValues = "ALL, PRIMARY"
)
public String getExecutionNode() {
return executionNode;
}
public void setExecutionNode(String executionNode) {
this.executionNode = executionNode;
}
/** /**
* @return The total count and size of flow files that have been accepted in the last five minutes * @return The total count and size of flow files that have been accepted in the last five minutes
*/ */
@ -280,6 +293,7 @@ public class ProcessorStatusSnapshotDTO implements Cloneable {
other.setType(getType()); other.setType(getType());
other.setRunStatus(getRunStatus()); other.setRunStatus(getRunStatus());
other.setExecutionNode(getExecutionNode());
other.setBytesRead(getBytesRead()); other.setBytesRead(getBytesRead());
other.setBytesWritten(getBytesWritten()); other.setBytesWritten(getBytesWritten());
other.setFlowFilesIn(getFlowFilesIn()); other.setFlowFilesIn(getFlowFilesIn());

View File

@ -2976,6 +2976,7 @@ public class FlowController implements EventAccess, ControllerServiceProvider, R
status.setRunStatus(RunStatus.Stopped); status.setRunStatus(RunStatus.Stopped);
} }
status.setExecutionNode(procNode.getExecutionNode());
status.setActiveThreadCount(processScheduler.getActiveThreadCount(procNode)); status.setActiveThreadCount(processScheduler.getActiveThreadCount(procNode));
return status; return status;

View File

@ -1106,6 +1106,7 @@ public final class DtoFactory {
// determine the run status // determine the run status
snapshot.setRunStatus(procStatus.getRunStatus().toString()); snapshot.setRunStatus(procStatus.getRunStatus().toString());
snapshot.setExecutionNode(procStatus.getExecutionNode().toString());
snapshot.setActiveThreadCount(procStatus.getActiveThreadCount()); snapshot.setActiveThreadCount(procStatus.getActiveThreadCount());
snapshot.setType(procStatus.getType()); snapshot.setType(procStatus.getType());

View File

@ -66,7 +66,6 @@ g.component rect.body.unauthorized {
fill: #f4f6f7; fill: #f4f6f7;
} }
g.component rect.border { g.component rect.border {
stroke: rgba(0,0,0,0.25); stroke: rgba(0,0,0,0.25);
stroke-width: 1; stroke-width: 1;
@ -187,7 +186,7 @@ text.processor-icon {
font-size: 30px; font-size: 30px;
} }
circle.restricted-background { circle.restricted-background, circle.is-primary-background {
visibility: hidden; visibility: hidden;
fill: rgba(255, 255, 255, 0.90); fill: rgba(255, 255, 255, 0.90);
} }
@ -199,6 +198,12 @@ text.restricted {
fill: #ba554a; fill: #ba554a;
} }
text.is-primary {
visibility: hidden;
font-size: 12px;
font-weight: bold;
}
text.run-status-icon { text.run-status-icon {
font-size: 13px; font-size: 13px;
} }

View File

@ -103,6 +103,23 @@ input.search-nodes {
color: #888; color: #888;
} }
div.is-primary-icon {
color: #000;
font-family: Roboto;
font-size: 10px;
font-weight: bold;
line-height: 14px;
width: 14px;
height: 14px;
background-color: rgba(255, 255, 255, 0.9);
border: 1px solid #aaa;
border-radius: 7px;
margin-right: 3px;
margin-top: 3px;
float: left;
text-align: center;
}
/* system diagnostics dialog */ /* system diagnostics dialog */
#system-diagnostics-refresh-container{ #system-diagnostics-refresh-container{

View File

@ -23,9 +23,10 @@
'd3', 'd3',
'nf.Common', 'nf.Common',
'nf.Client', 'nf.Client',
'nf.ClusterSummary',
'nf.CanvasUtils'], 'nf.CanvasUtils'],
function ($, d3, nfCommon, nfClient, nfCanvasUtils) { function ($, d3, nfCommon, nfClient, nfClusterSummary, nfCanvasUtils) {
return (nf.Processor = factory($, d3, nfCommon, nfClient, nfCanvasUtils)); return (nf.Processor = factory($, d3, nfCommon, nfClient, nfClusterSummary, nfCanvasUtils));
}); });
} else if (typeof exports === 'object' && typeof module === 'object') { } else if (typeof exports === 'object' && typeof module === 'object') {
module.exports = (nf.Processor = module.exports = (nf.Processor =
@ -33,15 +34,17 @@
require('d3'), require('d3'),
require('nf.Common'), require('nf.Common'),
require('nf.Client'), require('nf.Client'),
require('nf.ClusterSummary'),
require('nf.CanvasUtils'))); require('nf.CanvasUtils')));
} else { } else {
nf.Processor = factory(root.$, nf.Processor = factory(root.$,
root.d3, root.d3,
root.nf.Common, root.nf.Common,
root.nf.Client, root.nf.Client,
root.nf.ClusterSummary,
root.nf.CanvasUtils); root.nf.CanvasUtils);
} }
}(this, function ($, d3, nfCommon, nfClient, nfCanvasUtils) { }(this, function ($, d3, nfCommon, nfClient, nfClusterSummary, nfCanvasUtils) {
'use strict'; 'use strict';
var nfConnectable; var nfConnectable;
@ -181,6 +184,27 @@
}) })
.text('\uf132'); .text('\uf132');
// is primary icon background
processor.append('circle')
.attr({
'r': 9,
'cx': 38,
'cy': 36,
'class': 'is-primary-background'
});
// is primary icon
processor.append('text')
.attr({
'x': 34.75,
'y': 40,
'class': 'is-primary'
})
.text('P')
.append('title').text(function (d) {
return 'This component is only scheduled to execute on the Primary Node';
});
// make processors selectable // make processors selectable
processor.call(nfSelectable.activate).call(nfContextMenu.activate).call(nfQuickSelect.activate); processor.call(nfSelectable.activate).call(nfContextMenu.activate).call(nfQuickSelect.activate);
}; };
@ -686,11 +710,15 @@
// restricted component indicator // restricted component indicator
processor.select('circle.restricted-background').style('visibility', showRestricted); processor.select('circle.restricted-background').style('visibility', showRestricted);
processor.select('text.restricted').style('visibility', showRestricted); processor.select('text.restricted').style('visibility', showRestricted);
// is primary component indicator
processor.select('circle.is-primary-background').style('visibility', showIsPrimary);
processor.select('text.is-primary').style('visibility', showIsPrimary);
}); });
}; };
/** /**
* Returns whether the resticted indicator should be shown for a given * Returns whether the resticted indicator should be shown for a given component
* @param d * @param d
* @returns {*} * @returns {*}
*/ */
@ -700,7 +728,16 @@
} }
return d.component.restricted ? 'visible' : 'hidden'; return d.component.restricted ? 'visible' : 'hidden';
} };
/**
* Returns whether the is primary indicator should be shown for a given component
* @param d
* @returns {*}
*/
var showIsPrimary = function (d) {
return nfClusterSummary.isClustered() && d.status.aggregateSnapshot.executionNode === 'PRIMARY' ? 'visible' : 'hidden';
};
/** /**
* Updates the stats for the processors in the specified selection. * Updates the stats for the processors in the specified selection.

View File

@ -276,6 +276,19 @@
return markup; return markup;
}; };
// formatter for name
var nameFormatter = function (row, cell, value, columnDef, dataContext) {
var markup = '';
if (isClustered && dataContext.executionNode === 'PRIMARY') {
markup += '<div class="is-primary-icon" title="This component is only scheduled to execute on the Primary Node">P</div>';
}
markup += nfCommon.escapeHtml(value);
return markup;
};
// formatter for io // formatter for io
var ioFormatter = function (row, cell, value, columnDef, dataContext) { var ioFormatter = function (row, cell, value, columnDef, dataContext) {
return nfCommon.escapeHtml(dataContext.read) + ' / ' + nfCommon.escapeHtml(dataContext.written); return nfCommon.escapeHtml(dataContext.read) + ' / ' + nfCommon.escapeHtml(dataContext.written);
@ -326,9 +339,9 @@
id: 'name', id: 'name',
field: 'name', field: 'name',
name: 'Name', name: 'Name',
formatter: nameFormatter,
sortable: true, sortable: true,
resizable: true, resizable: true
formatter: nfCommon.genericValueFormatter
}; };
var runStatusColumn = { var runStatusColumn = {
id: 'runStatus', id: 'runStatus',