Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate monitor.sh #53

Merged
merged 4 commits into from
Jan 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
});
});

});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yesssssssssssss

});
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);
}
});

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yessssssssssss :-)

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)
})
})
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yessssssssssss.

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