Skip to content

Commit

Permalink
Merge pull request #53 from haydenhw/deprecate-monitor.sh
Browse files Browse the repository at this point in the history
Deprecate monitor.sh
  • Loading branch information
bennlich authored Jan 5, 2020
2 parents b6c19e8 + 78d8a09 commit 92ac6b3
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 107 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

To help monitor network health.

Exit nodes periodically execute [monitor.sh](./monitor.sh) and [post-routing-table.sh](./post-routing-table.sh), hitting two API endpoints at https://peoplesopen.herokuapp.com/api/v0/. This relays information about the number of active routes, active gateways, and the full contents of the exit node's routing table. If an exit node hasn't checked in in more than 2 minutes, it is assumed to be down.
Exit nodes periodically execute [post-routing-table.sh](./post-routing-table.sh), hitting an API endpoint at https://peoplesopen.herokuapp.com/api/v0/nodes. This relays information about the number of active routes, active gateways, and the full contents of the exit node's routing table. If an exit node hasn't checked in in more than 2 minutes, it is assumed to be down.

Uses memcache/memjs, and mongo db. Deployed to heroku.

Expand Down
14 changes: 0 additions & 14 deletions monitor.sh

This file was deleted.

28 changes: 2 additions & 26 deletions spec/httpSpec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const supertest = require('supertest');
const MonitorApp = require('../src/app').MonitorApp
const MonitorApp = require('../src/app').MonitorApp;
const getDBConnection = require('../src/db');
const exitnodeIPs = require('../src/exitnodeIPs');

describe('HTTP tests', function() {

Expand Down Expand Up @@ -31,27 +30,4 @@ describe('HTTP tests', function() {
.expect(404, done);
});
});

describe('POST /api/v0/monitor', function () {
it('error on non-exit node', function (done) {
supertest(MonitorApp({db}))
.post('/api/v0/monitor')
.accept('Content-Type', 'application/json')
.expect({ "error": "You aren\'t an exit node."})
.expect(403, done);
});
});

describe('POST /api/v0/monitor', function () {
it('error on malformed exit node', function (done) {
let app = MonitorApp({db});
supertest(app)
.post('/api/v0/monitor')
.set('x-forwarded-for', exitnodeIPs[0])
.accept('Content-Type', 'application/json')
.expect({ error: 'Bad request' })
.expect(400, done);
});
});

});
});
55 changes: 27 additions & 28 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,28 @@ function MonitorApp ({
return JSON.parse(value);
}

async function getMonitorUpdates() {
return await Promise.all(exitnodeIPs.map(async ip => {
let d = await getCacheData(`alive-${ip}`);
d = d ? d : { error: util.noCheckInMessage(ip) };
d.ip = ip;
return d;
function countActiveRoutesByExitnode() {
// Report a count of unique nodes and gateways connected to exitnodes
// If an exitnode has not checked in in the last two minutes, report an error message
return Promise.all(exitnodeIPs.map(async ip => {
const twoMinutesAgo = new Date(new Date() - 2 * 60 * 1000);
const [mostRecentLog] = await db.collection('routeLog')
.find({
exitnodeIP: ip,
timestamp: { $gt: twoMinutesAgo }
})
.sort({ timestamp: -1 })
.limit(1)
.toArray();

if (!mostRecentLog)
return { error: util.noCheckInMessage(ip) };

return {
exitnodeIP: ip,
numberOfRoutes: _.unique(mostRecentLog.routes.map(r => r.nodeIP)).length,
numberOfGateways: _.unique(mostRecentLog.routes.map(r => r.gatewayIP)).length
};
}));
}

Expand All @@ -87,8 +103,8 @@ function MonitorApp ({

// Home Page
app.get('/', asyncMiddleware(async function(req, res, next) {
let updates = await getMonitorUpdates();
let exitnodes = await getRoutingTableUpdates();
const routeCounts = await countActiveRoutesByExitnode();
const exitnodes = await getRoutingTableUpdates();

exitnodes.forEach(exitnode => {
if (exitnode.routingTable) {
Expand All @@ -105,7 +121,7 @@ function MonitorApp ({
});

res.render('index', {
updates: updates,
routeCounts,
nodes: exitnodes,
timeAgo: util.timeAgo
});
Expand All @@ -116,26 +132,9 @@ function MonitorApp ({
//

app.get('/api/v0/monitor', asyncMiddleware(async function(req, res, next) {
res.json(await getMonitorUpdates());
res.json(await countActiveRoutesByExitnode());
}));

app.post('/api/v0/monitor', ipAuthMiddleware(exitnodeIPs), function(req, res) {
let ip = util.getRequestIP(req);
const key = `alive-${ip}`;
let handleErr = function(err) {
if (err) {
return res.status(502).json({ error: 'Could not set key, because of [' + err + '].' });
}
return res.json({ message: 'Set attached values', result: processed });
};
const processed = util.processUpdate(req);
if (processed.error) {
return res.status(400).json(processed);
} else {
mjs.set(key, JSON.stringify(processed), {expires: 120}, handleErr);
}
});

app.get('/api/v0/nodes', asyncMiddleware(async function(req, res) {
let data = await getRoutingTableUpdates();
res.json(data);
Expand Down Expand Up @@ -214,7 +213,7 @@ function MonitorApp ({
mjs.set(key, JSON.stringify(newRoutes), {}, handleErr);

}));

app.get('/api/v0/numNodesTimeseries', asyncMiddleware(async function(req, res) {
let now = new Date();
let yesterday = new Date(now - 1000 * 60 * 60 * 24);
Expand Down
34 changes: 0 additions & 34 deletions tools/simulate-activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ if (require.main === module) {

async function main() {
await Promise.all([
simulateMonitorRequest({"numberOfGateways": 15, "numberOfRoutes": 21}, exitnodeIPs[0]),
simulateMonitorRequest({"numberOfGateways": 15, "numberOfRoutes": 29}, exitnodeIPs[1]),
simulateRoutingTableRequest('134.0.0.0/26,134.0.0.1|132.0.0.0/26,132.0.0.1|131.0.0.0/26,131.0.0.1|129.0.0.0/26,129.0.0.1|127.0.0.0/26,127.0.0.1|128.0.0.0/26,128.0.0.1|127.0.0.10/26,127.0.0.1|', exitnodeIPs[0]),
simulateRoutingTableRequest('134.0.0.0/26,134.0.0.1|132.0.0.0/26,132.0.0.1|131.0.0.0/26,131.0.0.1|125.0.0.0/26,124.0.0.1|121.0.0.0/26,121.0.0.1|123.0.0.0/26,123.0.0.1', exitnodeIPs[1]),
simulateRoutingTableRequest('', exitnodeIPs[2]) // simulate an empty POST
Expand All @@ -27,8 +25,6 @@ async function main() {
setTimeout(async () => {
// omit one routing table request to simulate a delay between posts
await Promise.all([
simulateMonitorRequest({"numberOfGateways": 15, "numberOfRoutes": 21}, exitnodeIPs[0]),
simulateMonitorRequest({"numberOfGateways": 15, "numberOfRoutes": 29}, exitnodeIPs[1]),
simulateRoutingTableRequest('134.0.0.0/26,134.0.0.1|132.0.0.0/26,132.0.0.1|131.0.0.0/26,131.0.0.1|129.0.0.0/26,129.0.0.1|127.0.0.0/26,127.0.0.1|128.0.0.0/26,128.0.0.1|127.0.0.10/26,127.0.0.1|', exitnodeIPs[0]),
simulateRoutingTableRequest('', exitnodeIPs[2]) // simulate an empty POST
])
Expand All @@ -37,36 +33,6 @@ async function main() {
})
}

async function simulateMonitorRequest(data, exitnodeIP) {
const response = await monitorRequest(data, exitnodeIP)
switch (response.statusCode) {
case 200:
console.info(`Successful /monitor request`)
break;
default:
throw new Error(`Unexpected statusCode from simulated monitor request: ${response.statusCode}`)
}
}

async function monitorRequest(data, exitnodeIP) {
return new Promise((resolve, reject) => {
var options = {
url: `http://localhost:${process.env.PORT}/api/v0/monitor`,
// the server authenticates the request by looking at
// its source ip or x-forwarded-for header
headers: {
'x-forwarded-for': exitnodeIP,
'content-type': 'application/json'
},
body: (typeof data === 'object') ? JSON.stringify(data) : data
};
request.post(options, (error, response) => {
if (error) return reject(error)
return resolve(response)
})
})
}

async function simulateRoutingTableRequest(body, exitnodeIP) {
const response = await routingTableRequest(body, exitnodeIP)
switch (response.statusCode) {
Expand Down
8 changes: 4 additions & 4 deletions views/index.jade
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ block content
p Please help make this page better at
a(href='https://github.com/sudomesh/monitor') https://github.com/sudomesh/monitor.

each update in updates
if update.error
p.monitor-warning #{update.error}
each count in routeCounts
if count.error
p.monitor-warning #{count.error}
else
p #{update.ip} is connecting [#{update.numberOfRoutes}] nodes via [#{update.numberOfGateways}] gateways.
p #{count.exitnodeIP} is connecting [#{count.numberOfRoutes}] nodes via [#{count.numberOfGateways}] gateways.

h3="node history"
p A plot of the number of nodes connected to our exitnodes in the last 24 hours.
Expand Down

0 comments on commit 92ac6b3

Please sign in to comment.