Skip to content

Commit

Permalink
Display stats for all nodes running stats container
Browse files Browse the repository at this point in the history
  • Loading branch information
bobf committed May 11, 2019
1 parent e7f3e63 commit 26429b7
Show file tree
Hide file tree
Showing 14 changed files with 375 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .Python
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,12 @@

app/.build
stats/.build

linux-metrics
bin/
install/
include/
lib/
pyvenv.cfg
.Python
.env
12 changes: 9 additions & 3 deletions app/files/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ $(function () {

setInterval(function () {
socket.emit('manifest');
}, 1000);
}, 5000);

socket.on('manifest', function(data) {
var manifest = JSON.parse(data);
console.log(manifest);

if (!Skep.dashboard) {
Skep.dashboard = ReactDOM.render(
<Dashboard manifest={manifest}/>,
Expand All @@ -25,6 +25,12 @@ $(function () {

socket.on('stats', function (json) {
var data = JSON.parse(json);
Skep.dashboard.getNode(data.hostname).setState(data);
var node = Skep.dashboard.getNode(data.hostname)
if (!node) {
console.log('Could not find node for stats collection.', data);
return;
}

node.ref.current.setState({ stats: data });
});
});
25 changes: 25 additions & 0 deletions app/files/cpu_stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class CPUStats {
constructor(stats) {
this.stats = stats;
}

label() {
return this.percent();
}

level() {
const percent = 100 - this.stats.cpu_usage.idle;

if (percent < 75) {
return 'success';
} else if (percent < 90) {
return 'warning';
} else {
return 'danger';
}
}

percent() {
return numeral(100 - this.stats.cpu_usage.idle).format('0.00') + '%';
}
}
45 changes: 40 additions & 5 deletions app/files/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,58 @@
class Dashboard extends React.Component {
constructor(props) {
super(props);
this._nodes = [];
}

getNode(hostname) {
return this.props.manifest.nodes.find(node => node.hostname == hostname);
return this._nodes.find(
node => node.hostname === hostname
)
}

nodes() {
return this.props.manifest.nodes.map(
node => this.findOrCreateNode(node)
);
}

findOrCreateNode(props) {
var found = this._nodes.find(node => node.id === props.id);

if (found) {
return found;
}

var node = this.node(props);
this._nodes.push(node);
return node;
}

node(props) {
var ref = React.createRef();
return {
id: props.id,
hostname: props.hostname,
ref: ref,
component: (
<Node key={props.id} ref={ref} node={props} stacks={this.props.manifest.stacks} />
)
}
}

render() {
return (
<div id={'dashboard'}>
<div id={'nodes'}>
<h2>Nodes</h2>
{this.props.manifest.nodes.map(node => (
<Node key={node.id} manifest={node} />
))}
{this.nodes().map(node => node.component)}
</div>

<div id={'stacks'}>
<h2>Stacks</h2>
{this.props.manifest.stacks.map(stack => (
<Stack
key={stack.name}
key={'stack_' + stack.name}
stack={stack}
manifest={this.props.manifest}
/>
Expand Down
36 changes: 36 additions & 0 deletions app/files/memory_stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class MemoryStats {
constructor(stats) {
this.stats = stats;
}

label() {
const free = this.formatNumber(this.free());
const total = this.formatNumber(this.stats.total);

return `${free} / ${total}`;
}

level() {
const percent = 100 * (this.stats.used / this.stats.total);

if (percent < 75) {
return 'success';
} else if (percent < 90) {
return 'warning';
} else {
return 'danger';
}
}

percent() {
return numeral(this.stats.used / this.stats.total).format('0.00%');
}

free() {
return this.stats.total - this.stats.used;
}

formatNumber(number) {
return numeral(number).format('0.00b');
}
}
83 changes: 80 additions & 3 deletions app/files/node.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,87 @@
class Node extends React.Component {
tasks() {
return this.services().map(
service => service.tasks.filter(
task => task.node_id === this.props.node.id
)
).flat(1)
}

services() {
return this.stacks().map(
stack => stack.services.filter(
service => service.tasks.find(
task => task.node_id === this.props.node.id
)
)
).flat(1)
}

stacks() {
return this.props.stacks.filter(
stack => stack.services.filter(
service => service.tasks.find(
task => task.node_id === this.props.node.id
)
)
)
}

stats() {
if (!this.state || !this.state.stats) {
return null;
}

return this.state.stats;
}

roleClass() {
console.log(this.props.node.role);
if (this.props.node.role === 'manager') {
return 'primary';
} else {
return 'info';
}
}

roleBadge() {
if (this.props.node.role === 'manager') {
return (
<span className={'badge badge-primary'}>
Manager
</span>
);
} else {
return (
<span className={'badge badge-info'}>
Worker
</span>
);
}
}

leaderBadge() {
if (!this.props.node.leader) {
return null;
}

return (
<span className={'badge badge-success'}>Leader</span>
);
}

render() {
return (
<div className={'node'}>
<h2>{this.props.manifest.hostname}</h2>
<h3>{this.props.manifest.role}</h3>
<h3>{this.props.manifest.version}</h3>
<h2 alt={'Version: ' + this.props.node.version} className={'hostname'}>{this.props.node.hostname}</h2>

{this.roleBadge()}
{this.leaderBadge()}

<NodeStats
key={'node_' + this.props.node.id + '_stats'}
stats={this.stats()}
/>
</div>
);
}
Expand Down
81 changes: 81 additions & 0 deletions app/files/node_stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
class NodeStats extends React.Component {
constructor(props) {
super(props);
this.initialize(props);
}

initialize(props) {
const { stats } = props;
const { memory, cpu } = (stats || {});

this.memory = memory ? new MemoryStats(memory) : null;
this.cpu = cpu ? new CPUStats(cpu) : null;
}

progress(options) {
const { percent, level, label, className } = options;

return (
<div className={'progress position-relative ' + className}
style={{ height: '2em' }}>
<div className={'progress-bar bg-' + level}
style={{ width: percent }}>
<span className={'label'}>
{label}
</span>
</div>
</div>
);
}

renderMemory() {
if (!this.memory) return null;

return this.progress({
percent: this.memory.percent(),
label: this.memory.label(),
level: this.memory.level(),
className: 'memory'
});
}

renderCPU() {
if (!this.cpu) return null;

return this.progress({
percent: this.cpu.percent(),
label: this.cpu.label(),
level: this.cpu.level(),
className: 'cpu'
});
}

render() {
this.initialize(this.props);

return (
<div className={'node-stats'}>
<table>
<tbody>
<tr>
<th>
{'RAM'}
</th>
<td>
{this.renderMemory()}
</td>
</tr>
<tr>
<th>
{'CPU'}
</th>
<td>
{this.renderCPU()}
</td>
</tr>
</tbody>
</table>
</div>
);
}
}
2 changes: 1 addition & 1 deletion app/files/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Service extends React.Component {
return (
<div className={'service'}>
<h2>{this.props.service.name}</h2>
<div className={'services'}>
<div className={'tasks'}>
{this.props.service.tasks.map(task => (
<Task key={task.id} task={task} manifest={this.props.manifest} />
))}
Expand Down
Loading

0 comments on commit 26429b7

Please sign in to comment.