Move ping code to own file

This commit is contained in:
Zaid Abdulla committed 2019-10-21 22:58:22 -07:00
1 parent 0e02b7c7ea
commit 77563fc85e
4 files changed
+104 -49

No files matched your search

+3 -8
View File
@@ -21,14 +21,13 @@ import * as url from "url";
import * as mongodb from "mongodb";
import * as querystring from "querystring";
import * as vm from "vm";
import { exec } from "child_process";
import * as config from "./config";
import * as db from "./db";
import * as query from "./query";
import * as apiFunctions from "./api-functions";
import * as cache from "./cache";
import { version as VERSION } from "../package.json";
import * as os from "os";
import { ping } from "./ping";
const DEVICE_TASKS_REGEX = /^\/devices\/([a-zA-Z0-9\-_%]+)\/tasks\/?$/;
const TASKS_REGEX = /^\/tasks\/([a-zA-Z0-9\-_%]+)(\/[a-zA-Z_]*)?$/;
@@ -43,10 +42,6 @@ const PROVISIONS_REGEX = /^\/provisions\/([a-zA-Z0-9\-_%]+)\/?$/;
const VIRTUAL_PARAMETERS_REGEX = /^\/virtual_parameters\/([a-zA-Z0-9\-_%]+)\/?$/;
const FAULTS_REGEX = /^\/faults\/([a-zA-Z0-9\-_%:]+)\/?$/;
function pingVariant(): string {
return os.platform() === "freebsd" ? "-t 1 -c 3" : "-w 1 -i 0.2 -c 3";
}
function throwError(err, httpResponse?): never {
if (httpResponse) {
httpResponse.writeHead(500, { Connection: "close" });
@@ -596,9 +591,9 @@ export function listener(request, response): void {
}
} else if (PING_REGEX.test(urlParts.pathname)) {
const host = querystring.unescape(PING_REGEX.exec(urlParts.pathname)[1]);
const pingArgs = pingVariant();
exec(`ping ${pingArgs} ${host}`, (err, stdout) => {
ping(host, (err, res, stdout) => {
if (err) {
if (!res) throwError(err, response);
response.writeHead(404, { "Cache-Control": "no-cache" });
response.end(`${err.name}: ${err.message}`);
return;
+89
View File
@@ -0,0 +1,89 @@
/**
* Copyright 2013-2019 GenieACS Inc.
*
* This file is part of GenieACS.
*
* GenieACS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* GenieACS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
*/
import { platform } from "os";
import { exec } from "child_process";
interface Ping {
packetsTransmitted: number;
packetsReceived: number;
packetLoss: number;
min: number;
avg: number;
max: number;
mdev: number;
}
export function ping(
host: string,
callback: (err, res?, stdout?) => void
): void {
let cmd: string, parseRegExp1: RegExp, parseRegExp2: RegExp;
switch (platform()) {
case "linux":
cmd = `ping -w 1 -i 0.2 -c 3 ${host}`;
parseRegExp1 = /(\d+) packets transmitted, (\d+) received, ([\d.]+)% packet loss[^]*([\d.]+)\/([\d.]+)\/([\d.]+)\/([\d.]+)/;
parseRegExp2 = /(\d+) packets transmitted, (\d+) received, ([\d.]+)% packet loss/;
break;
case "freebsd":
// Send a single packet because on FreeBSD only superuser can send
// packets that are only 200 ms apart.
cmd = `ping -t 1 -c 3 ${host}`;
parseRegExp1 = /(\d+) packets transmitted, (\d+) packets received, ([\d.]+)% packet loss\nround-trip min\/avg\/max\/stddev = ([\d.]+)\/([\d.]+)\/([\d.]+)\/([\d.]+) ms/;
parseRegExp2 = /(\d+) packets transmitted, (\d+) packets received, ([\d.]+)% packet loss/;
break;
default:
return callback(new Error("Platform not supported"));
}
exec(cmd, (err, stdout) => {
let parsed: Ping;
if (stdout) {
const m1 = stdout.match(parseRegExp1);
if (m1) {
parsed = {
packetsTransmitted: +m1[1],
packetsReceived: +m1[2],
packetLoss: +m1[3],
min: +m1[4],
avg: +m1[5],
max: +m1[6],
mdev: +m1[7]
};
} else {
const m2 = stdout.match(parseRegExp2);
if (m2) {
parsed = {
packetsTransmitted: +m2[1],
packetsReceived: +m2[2],
packetLoss: +m2[3],
min: null,
avg: null,
max: null,
mdev: null
};
}
}
}
callback(err, parsed, stdout);
});
}
-34
View File
@@ -17,7 +17,6 @@
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
*/
import { exec } from "child_process";
import { ObjectID } from "mongodb";
import * as db from "./db";
import { del } from "../cache";
@@ -29,17 +28,6 @@ import {
connectionRequest,
deleteDevice
} from "../api-functions";
import * as os from "os";
function pingVariant(): string {
return os.platform() === "freebsd" ? "-t 1 -c 3" : "-w 1 -i 0.2 -c 3";
}
function pingOutRegex(): RegExp {
return os.platform() === "freebsd"
? /(\d) packets transmitted, (\d) packets received, ([\d.%]+) packet loss\nround-trip min\/avg\/max\/stddev = ([\d.]+)\/([\d.]+)\/([\d.]+)\/([\d.]+) ms/
: /(\d) packets transmitted, (\d) received, ([\d.%]+) packet loss[^]*([\d.]+)\/([\d.]+)\/([\d.]+)\/([\d.]+)/;
}
async function deleteFault(id): Promise<void> {
const deviceId = id.split(":", 1)[0];
@@ -160,28 +148,6 @@ interface PingResponse {
mdev: number;
}
export function ping(host): Promise<PingResponse> {
return new Promise((resolve, reject) => {
const pingArgs = pingVariant();
exec(`ping ${pingArgs} ${host}`, (err, stdout) => {
if (err) return void reject(err);
const m = stdout.match(pingOutRegex());
if (!m) return void reject(new Error("Could not parse ping response"));
resolve({
packetsTransmitted: +m[1],
packetsReceived: +m[2],
packetLoss: m[3],
min: +m[4],
avg: +m[5],
max: +m[6],
mdev: +m[7]
});
});
});
}
export async function putResource(resource, id, data): Promise<void> {
if (resource === "presets") {
await db.putPreset(id, data);
+12 -7
View File
@@ -29,6 +29,7 @@ import { QueryOptions, Expression } from "../types";
import { generateSalt, hashPassword } from "../auth";
import { del } from "../cache";
import Authorizer from "../common/authorizer";
import { ping } from "../ping";
const router = new Router();
export default router;
@@ -551,13 +552,17 @@ router.post("/devices/:id/tags", async (ctx, next) => {
});
router.get("/ping/:host", async ctx => {
try {
ctx.body = await apiFunctions.ping(ctx.params.host);
} catch (err) {
ctx.status = 404;
ctx.response.headers["Cache-Control"] = "no-cache";
ctx.body = `${err.name}: ${err.message}`;
}
return new Promise(resolve => {
ping(ctx.params.host, (err, parsed) => {
if (parsed) {
ctx.body = parsed;
} else {
ctx.status = 500;
ctx.body = `${err.name}: ${err.message}`;
}
resolve();
});
});
});
router.put("/users/:id/password", async (ctx, next) => {