797 lines
26 KiB
JavaScript
797 lines
26 KiB
JavaScript
|
const express = require('express');
|
||
|
const readline = require('readline');
|
||
|
var os = require('os');
|
||
|
const e = require('express');
|
||
|
|
||
|
const app = express();
|
||
|
const mgmtApp = express();
|
||
|
const port = 999;
|
||
|
const mgmtPort = 998;
|
||
|
var pointsdb = [];
|
||
|
var lastUserAgent = '';
|
||
|
var chunked = false;
|
||
|
var delay = 0;
|
||
|
var permanentError = 0;
|
||
|
const prefix = '';
|
||
|
var server = undefined;
|
||
|
|
||
|
mgmtApp.use (function(req, res, next) {
|
||
|
var data='';
|
||
|
req.setEncoding('utf8');
|
||
|
req.on('data', function(chunk) {
|
||
|
data += chunk;
|
||
|
});
|
||
|
|
||
|
req.on('end', function() {
|
||
|
req.body = data;
|
||
|
next();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
mgmtApp.get('/start', (req,res) => {
|
||
|
if(server === undefined) {
|
||
|
console.log('Starting server');
|
||
|
server = app.listen(port);
|
||
|
server.on('close',function() {
|
||
|
pointsdb = [];
|
||
|
server = undefined;
|
||
|
console.log('Server closed');
|
||
|
});
|
||
|
server.on('clientError', (err, socket) => {
|
||
|
console.log("client error", err);
|
||
|
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
||
|
});
|
||
|
res.status(201).send(`Listening on http://${server.address().address}:${server.address().port}`);
|
||
|
} else {
|
||
|
server.
|
||
|
res.status(204).end();
|
||
|
};
|
||
|
});
|
||
|
|
||
|
mgmtApp.get('/stop', (req,res) => {
|
||
|
if(server === undefined) {
|
||
|
res.status(404).end();
|
||
|
} else {
|
||
|
console.log('Shutting down server');
|
||
|
server.close();
|
||
|
res.status(200).end();
|
||
|
};
|
||
|
});
|
||
|
mgmtApp.get('/status', (req,res) => {
|
||
|
if(server === undefined) {
|
||
|
res.status(404).send("stopped");
|
||
|
} else {
|
||
|
res.status(200).send("running");
|
||
|
}
|
||
|
});
|
||
|
|
||
|
mgmtApp.post('/log', (req,res) => {
|
||
|
console.log('===' + req.body + '=====');
|
||
|
res.status(204).end();
|
||
|
})
|
||
|
|
||
|
|
||
|
app.use (function(req, res, next) {
|
||
|
var data='';
|
||
|
req.setEncoding('utf8');
|
||
|
req.on('data', function(chunk) {
|
||
|
data += chunk;
|
||
|
});
|
||
|
|
||
|
req.on('end', function() {
|
||
|
req.body = data;
|
||
|
next();
|
||
|
});
|
||
|
});
|
||
|
app.get(prefix + '/test/user-agent', (req,res) => {
|
||
|
res.status(200).send(lastUserAgent);
|
||
|
})
|
||
|
app.get(prefix + '/ready', (req,res) => {
|
||
|
lastUserAgent = req.get('User-Agent');
|
||
|
res.status(200).send("<html><body><h1>OK</h1></body></html>");
|
||
|
})
|
||
|
app.get(prefix + '/health', (req,res) => {
|
||
|
lastUserAgent = req.get('User-Agent');
|
||
|
res.status(200).send("<html><body><h1>OK</h1></body></html>");
|
||
|
})
|
||
|
|
||
|
app.get(prefix + '/ping', (req,res) => {
|
||
|
lastUserAgent = req.get('User-Agent');
|
||
|
if(req.query['verbose'] == 'true') {
|
||
|
res.status(200).send("<html><body><h1>OK</h1></body></html>");
|
||
|
} else {
|
||
|
res.status(204).end();
|
||
|
}
|
||
|
})
|
||
|
|
||
|
|
||
|
app.post(prefix + '/api/v2/write', (req,res) => {
|
||
|
chunked = false;
|
||
|
if(checkWriteParams(req, res) && handleAuthentication(req, res)) {
|
||
|
//console.log('Write');
|
||
|
//console.log(req.body);
|
||
|
var points = parsePoints(req.body);
|
||
|
if(permanentError > 0) {
|
||
|
console.log('Pernament error ' + permanentError);
|
||
|
res.status(permanentError).send("Internal server error");
|
||
|
}
|
||
|
if(Array.isArray(points) && points.length > 0) {
|
||
|
var point = points[0];
|
||
|
if(point.tags.hasOwnProperty('direction')) {
|
||
|
if(permanentError > 0) {
|
||
|
if(point.tags.direction == 'permanent-unset' ) {
|
||
|
permanentError = 0;
|
||
|
}
|
||
|
} else {
|
||
|
switch(point.tags.direction) {
|
||
|
case '429-1':
|
||
|
console.log('Limit exceeded');
|
||
|
res.set("Retry-After","10");
|
||
|
console.log('Retry-After 10');
|
||
|
res.status(429).send("Limit exceeded");
|
||
|
break;
|
||
|
case '429-2':
|
||
|
console.log('Limit exceeded');
|
||
|
console.log('Retry-After default');
|
||
|
res.status(429).send("Limit exceeded");
|
||
|
break;
|
||
|
case '503-1':
|
||
|
res.set("Retry-After","10");
|
||
|
console.log('Server overloaded');
|
||
|
console.log('Retry-After 10');
|
||
|
res.status(503).send("Server overloaded");
|
||
|
break;
|
||
|
case '503-2':
|
||
|
console.log('Server overloaded');
|
||
|
console.log('Retry-After default');
|
||
|
res.status(503).send("Server overloaded");
|
||
|
break;
|
||
|
case 'delete-all':
|
||
|
pointsdb = [];
|
||
|
res.status(204).end();
|
||
|
break;
|
||
|
case 'status':
|
||
|
points = [];
|
||
|
const code = parseInt(point.tags['x-code']);
|
||
|
console.log("Set code: " + code);
|
||
|
res.status(code).send("bad request");
|
||
|
break;
|
||
|
case 'chunked':
|
||
|
chunked = true;
|
||
|
console.log("Set chunked = true");
|
||
|
break;
|
||
|
case 'timeout':
|
||
|
delay = parseInt(point.tags.timeout)*1000;
|
||
|
console.log("Set delay: " + delay);
|
||
|
break;
|
||
|
case 'permanent-set':
|
||
|
permanentError = parseInt(point.tags['x-code']);
|
||
|
console.log("Set permanentError: " + permanentError);
|
||
|
res.status(permanentError).send("bad request");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
points.shift();
|
||
|
}
|
||
|
console.log("write " + points.length + ' points');
|
||
|
points.forEach((item, index) => {
|
||
|
pointsdb.push(item);
|
||
|
})
|
||
|
if(res.statusCode < 299) {
|
||
|
res.status(204).end();
|
||
|
}
|
||
|
} else {
|
||
|
res.status(204).end();
|
||
|
}
|
||
|
}
|
||
|
if(res.statusCode != 204) {
|
||
|
console.log('Responded with ' + res.statusCode);
|
||
|
}
|
||
|
})
|
||
|
|
||
|
app.post(prefix + '/write', (req,res) => {
|
||
|
if(checkWriteParamsV1(req, res) ) {
|
||
|
var points = parsePoints(req.body);
|
||
|
if(Array.isArray(points) && points.length > 0) {
|
||
|
var point = points[0];
|
||
|
if(point.tags.hasOwnProperty('direction')) {
|
||
|
switch(point.tags.direction) {
|
||
|
case 'delete-all':
|
||
|
pointsdb = [];
|
||
|
buckets = [];
|
||
|
res.status(204).end();
|
||
|
break;
|
||
|
case '400':
|
||
|
points = [];
|
||
|
res.status(400).send("bad request");
|
||
|
break;
|
||
|
case '500':
|
||
|
points = [];
|
||
|
res.status(500).send("internal server error");
|
||
|
break;
|
||
|
}
|
||
|
points.shift();
|
||
|
}
|
||
|
console.log("write " + points.length + ' points');
|
||
|
points.forEach((item, index) => {
|
||
|
pointsdb.push(item);
|
||
|
})
|
||
|
if(res.statusCode < 299) {
|
||
|
res.status(204).end();
|
||
|
}
|
||
|
} else {
|
||
|
res.status(204).end();
|
||
|
}
|
||
|
}
|
||
|
if(res.statusCode != 204) {
|
||
|
console.log('Responded with ' + res.statusCode);
|
||
|
}
|
||
|
})
|
||
|
|
||
|
app.post(prefix + '/api/v2/delete', (req,res) => {
|
||
|
console.log('Deleteting points');
|
||
|
pointsdb = [];
|
||
|
buckets = [];
|
||
|
res.status(204).end();
|
||
|
});
|
||
|
|
||
|
var queryRes = {
|
||
|
"singleTable":`#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
|
||
|
#group,false,false,true,true,false,false,true,true,true,true
|
||
|
#default,_result,,,,,,,,,
|
||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,1.4,f,test,1,adsfasdf
|
||
|
,,1,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,6.6,f,test,3,adsfasdf
|
||
|
\r
|
||
|
`,
|
||
|
"nil-value": `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
|
||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,,f,test,1,adsfasdf
|
||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,6.6,f,test,,adsfasdf
|
||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:11:32.225467895Z,1122.45,f,test,3,
|
||
|
\r
|
||
|
`,
|
||
|
"multiTables":`#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,unsignedLong,string,string,string,string
|
||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||
|
,_result,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,14,f,test,1,adsfasdf
|
||
|
,_result,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,66,f,test,1,adsfasdf
|
||
|
\r
|
||
|
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,long,string,string,string,string
|
||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||
|
,_result1,1,2020-02-16T22:19:49.747562847Z,2020-02-17T22:19:49.747562847Z,2020-02-17T10:34:08.135814545Z,-4,i,test,1,adsfasdf
|
||
|
,_result1,1,2020-02-16T22:19:49.747562847Z,2020-02-17T22:19:49.747562847Z,2020-02-16T22:08:44.850214724Z,-1,i,test,1,adsfasdf
|
||
|
\r
|
||
|
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,boolean,string,string,string,string
|
||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||
|
,_result2,2,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,false,b,test,0,brtfgh
|
||
|
,_result2,2,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.969100374Z,true,b,test,0,brtfgh
|
||
|
\r
|
||
|
#datatype,string,long,dateTime:RFC3339Nano,dateTime:RFC3339Nano,dateTime:RFC3339Nano,duration,string,string,string,base64Binary
|
||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||
|
,_result3,3,2020-02-10T22:19:49.747562847Z,2020-02-12T22:19:49.747562847Z,2020-02-11T10:34:08.135814545Z,1d2h3m4s,d,test,0,eHh4eHhjY2NjY2NkZGRkZA==
|
||
|
,_result3,3,2020-02-10T22:19:49.747562847Z,2020-02-12T22:19:49.747562847Z,2020-02-12T22:08:44.969100374Z,22h52s,d,test,0,ZGF0YWluYmFzZTY0
|
||
|
\r
|
||
|
`,
|
||
|
"diffNum-data":`#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,long,string,duration,base64Binary,dateTime:RFC3339
|
||
|
,result,table,_start,_stop,_time,deviceId,sensor,elapsed,note,start
|
||
|
,,0,2020-04-28T12:36:50.990018157Z,2020-04-28T12:51:50.990018157Z,2020-04-28T12:38:11.480545389Z,1467463,BME280,1m1s,ZGF0YWluYmFzZTY0,2020-04-27T00:00:00Z,2345234
|
||
|
\r
|
||
|
`,
|
||
|
"diffNum-type-vs-header":`#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,long,string,duration,base64Binary,dateTime:RFC3339
|
||
|
,result,table,_start,_stop,_time,deviceId,sensor,elapsed,note
|
||
|
,,0,2020-04-28T12:36:50.990018157Z,2020-04-28T12:51:50.990018157Z,2020-04-28T12:38:11.480545389Z,1467463,BME280,1m1s,ZGF0YWluYmFzZTY0,2020-04-27T00:00:00Z
|
||
|
\r
|
||
|
`,
|
||
|
"flux-error":`{"code":"invalid","message":"compilation failed: loc 4:17-4:86: expected an operator between two expressions"}`,
|
||
|
"invalid-datatype":`#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,int,string,duration,base64Binary,dateTime:RFC3339
|
||
|
,result,table,_start,_stop,_time,deviceId,sensor,elapsed,note,start
|
||
|
,,0,2020-04-28T12:36:50.990018157Z,2020-04-28T12:51:50.990018157Z,2020-04-28T12:38:11.480545389Z,1467463,BME280,1m1s,ZGF0YWluYmFzZTY0,2020-04-27T00:00:00Z
|
||
|
,,0,2020-04-28T12:36:50.990018157Z,2020-04-28T12:51:50.990018157Z,2020-04-28T12:39:36.330153686Z,1467463,BME280,1h20m30.13245s,eHh4eHhjY2NjY2NkZGRkZA==,2020-04-28T00:00:00Z
|
||
|
\r
|
||
|
`,
|
||
|
"missing-datatype":`,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||
|
,_result3,3,2020-02-10T22:19:49.747562847Z,2020-02-12T22:19:49.747562847Z,2020-02-11T10:34:08.135814545Z,1d2h3m4s,d,test,0,eHh4eHhjY2NjY2NkZGRkZA==
|
||
|
,_result3,3,2020-02-10T22:19:49.747562847Z,2020-02-12T22:19:49.747562847Z,2020-02-12T22:08:44.969100374Z,22h52s,d,test,0,eHh4eHhjY2NjY2NkZGRkZA==
|
||
|
\r
|
||
|
`,
|
||
|
"error-it-row-full":`#datatype,string,string
|
||
|
,error,reference
|
||
|
,failed to create physical plan: invalid time bounds from procedure from: bounds contain zero time,897
|
||
|
\r
|
||
|
`,
|
||
|
"error-it-row-no-reference":`#datatype,string,string
|
||
|
,error,reference
|
||
|
,failed to create physical plan: invalid time bounds from procedure from: bounds contain zero time,
|
||
|
\r
|
||
|
`,
|
||
|
"error-it-row-no-message":`#datatype,string,string
|
||
|
,error,reference
|
||
|
,,
|
||
|
\r
|
||
|
`,
|
||
|
"empty":``
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
function sleep(milliseconds) {
|
||
|
const date = Date.now();
|
||
|
let currentDate = null;
|
||
|
do {
|
||
|
currentDate = Date.now();
|
||
|
} while (currentDate - date < milliseconds);
|
||
|
}
|
||
|
|
||
|
app.post(prefix+'/api/v2/query', (req,res) => {
|
||
|
//console.log("Query with: " + req.body);
|
||
|
if(checkQueryParams(req, res) && handleAuthentication(req, res)) {
|
||
|
var queryObj = JSON.parse(req.body);
|
||
|
var data = '';
|
||
|
var status = 200;
|
||
|
if (queryObj["query"].startsWith('testquery-')) {
|
||
|
var qi = queryObj["query"].substring(10) ;
|
||
|
console.log('query: ' + qi + ' dataset');
|
||
|
if(qi.endsWith('error')) {
|
||
|
status = 400;
|
||
|
}
|
||
|
data = queryRes[qi];
|
||
|
} else if(queryObj["query"] === 'echo') {
|
||
|
status = 444;
|
||
|
data = JSON.stringify(queryObj);
|
||
|
} else if(pointsdb.length > 0) {
|
||
|
console.log('query: ' + pointsdb.length + ' points');
|
||
|
data = convertToCSV(pointsdb);
|
||
|
}
|
||
|
if(data.length > 0) {
|
||
|
if(delay) {
|
||
|
sleep(delay);
|
||
|
delay = 0;
|
||
|
}
|
||
|
//console.log(data);
|
||
|
|
||
|
if(chunked) {
|
||
|
var i = data.length/3;
|
||
|
res.set("Transfer-Encoding","chunked");
|
||
|
res.status(status);
|
||
|
res.write(data.substring(0, i+1));
|
||
|
res.write(data.substring(i+1, 2*i+1));
|
||
|
res.write(data.substring(2*i+1));
|
||
|
res.end();
|
||
|
chunked = false;
|
||
|
} else {
|
||
|
res.status(status).send(data);
|
||
|
}
|
||
|
} else {
|
||
|
res.status(status).end();
|
||
|
}
|
||
|
} else {
|
||
|
res.status(400).send('invalid query request');
|
||
|
}
|
||
|
});
|
||
|
|
||
|
const orgID = `e2e2d84ffb3c4f85`;
|
||
|
const orgName = `my-org`;
|
||
|
|
||
|
var buckets = []
|
||
|
|
||
|
function bucketResp(bucket) {
|
||
|
return `{
|
||
|
"id": "${bucket.id}",
|
||
|
"orgID": "${bucket.orgID}",
|
||
|
"type": "user",
|
||
|
"name": "${bucket.name}",
|
||
|
"retentionRules": [
|
||
|
{
|
||
|
"type": "expire",
|
||
|
"everySeconds": ${bucket.expire},
|
||
|
"shardGroupDurationSeconds": 604800
|
||
|
}
|
||
|
],
|
||
|
"createdAt": "2021-08-24T07:53:17.2525733Z",
|
||
|
"updatedAt": "2021-08-24T07:53:17.2525734Z",
|
||
|
"links": {
|
||
|
"labels": "/api/v2/buckets/3eae77843acbebee/labels",
|
||
|
"members": "/api/v2/buckets/3eae77843acbebee/members",
|
||
|
"org": "/api/v2/orgs/e2e2d84ffb3c4f85",
|
||
|
"owners": "/api/v2/buckets/3eae77843acbebee/owners",
|
||
|
"self": "/api/v2/buckets/3eae77843acbebee",
|
||
|
"write": "/api/v2/write?org=e2e2d84ffb3c4f85\u0026bucket=3eae77843acbebee"
|
||
|
},
|
||
|
"labels": []
|
||
|
}
|
||
|
`
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
function bucketsResp(buckets){
|
||
|
return `{
|
||
|
"links": {
|
||
|
"self": "/api/v2/buckets?descending=false\u0026limit=20\u0026offset=0"
|
||
|
},
|
||
|
"buckets": [
|
||
|
${buckets}
|
||
|
]
|
||
|
}
|
||
|
`
|
||
|
}
|
||
|
|
||
|
const invalidIDResp = `{
|
||
|
"code": "invalid",
|
||
|
"message": "id must have a length of 16 bytes"
|
||
|
}
|
||
|
`
|
||
|
|
||
|
const notfoundResp = `{
|
||
|
"code": "not found",
|
||
|
"message": "bucket not found"
|
||
|
}`
|
||
|
|
||
|
const orgNotFoundReps= `{
|
||
|
"code": "not found",
|
||
|
"message": "organization not found"
|
||
|
}`
|
||
|
|
||
|
app.get(prefix+'/api/v2/buckets', (req,res) => {
|
||
|
if(handleAuthentication(req, res)) {
|
||
|
var name = req.query['name'];
|
||
|
var id = req.query['id'];
|
||
|
res.set("Content-Type","application/json");
|
||
|
res.status(200);
|
||
|
if(name) { //filter by name
|
||
|
console.log("GET buckets name: " + name)
|
||
|
let b = buckets.find((value)=> {
|
||
|
return value.name === name
|
||
|
})
|
||
|
if(b) {
|
||
|
res.send(bucketResp(b))
|
||
|
} else { //invalid name
|
||
|
res.send(bucketsResp(''))
|
||
|
}
|
||
|
} else if(id) { //filter by id
|
||
|
console.log("GET buckets id: " + id)
|
||
|
if(id.length != 16) { //invalid name
|
||
|
res.status(400)
|
||
|
res.send(invalidIDResp)
|
||
|
return
|
||
|
}
|
||
|
let b = buckets.find((value)=> {
|
||
|
return value.id === id
|
||
|
})
|
||
|
if(b) {
|
||
|
res.send(bucketResp(b))
|
||
|
} else {
|
||
|
res.status(404)
|
||
|
res.send(notfoundResp)
|
||
|
}
|
||
|
} else { //return all buckets
|
||
|
console.log("GET all buckets")
|
||
|
bucketsJson = buckets.reduce((total, value, index) => {
|
||
|
return total + (index > 0?",\n":"") + bucketResp(value)
|
||
|
},'')
|
||
|
res.send(bucketsResp(bucketsJson))
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
|
||
|
function invalidJSONResp(err) {
|
||
|
return `{
|
||
|
"code": "invalid",
|
||
|
"message": "${err}"
|
||
|
}`
|
||
|
}
|
||
|
|
||
|
function conflictBucketResp(bucket) {
|
||
|
return `{
|
||
|
"code": "conflict",
|
||
|
"message": "bucket with name ${bucket} already exists"
|
||
|
}`
|
||
|
}
|
||
|
|
||
|
const idBase = '0123456789abcdef'
|
||
|
|
||
|
function genID() {
|
||
|
let result = '';
|
||
|
for ( let i = 0; i < 16; i++ ) {
|
||
|
result += idBase.charAt(Math.floor(Math.random() * 16));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
app.post(prefix+'/api/v2/buckets', (req,res) => {
|
||
|
console.log('Post buckets')
|
||
|
if(handleAuthentication(req, res)) {
|
||
|
let newBucket = undefined
|
||
|
try {
|
||
|
newBucket = JSON.parse(req.body)
|
||
|
} catch(err) {
|
||
|
res.status(400).send(invalidJSONResp(err))
|
||
|
return
|
||
|
}
|
||
|
if(newBucket.orgID !== orgID ) {
|
||
|
res.status(404).send(orgNotFoundReps)
|
||
|
return
|
||
|
}
|
||
|
//console.log('Finding name ' + newBucket.name)
|
||
|
let b = buckets.find((value)=> {
|
||
|
//console.log(' testing ', value)
|
||
|
return value.name?value.name === newBucket.name: false;
|
||
|
})
|
||
|
if(b) {
|
||
|
res.status(422).send(conflictBucketResp(newBucket.name ))
|
||
|
return
|
||
|
}
|
||
|
expire = 0
|
||
|
if(newBucket.retentionRules && newBucket.retentionRules.length > 0) {
|
||
|
expire = newBucket.retentionRules[0].everySeconds
|
||
|
}
|
||
|
let bucket = {
|
||
|
"name": newBucket.name,
|
||
|
"orgID": orgID,
|
||
|
"expire": expire,
|
||
|
"id": genID()
|
||
|
}
|
||
|
buckets.push(bucket)
|
||
|
res.status(201).send(bucketResp(bucket))
|
||
|
}
|
||
|
})
|
||
|
|
||
|
app.delete(prefix+'/api/v2/buckets/:id', (req,res) => {
|
||
|
console.log('Delete buckets')
|
||
|
if(handleAuthentication(req, res)) {
|
||
|
let id = req.params['id']
|
||
|
if(!id) {
|
||
|
res.sendStatus(405)
|
||
|
return
|
||
|
}
|
||
|
//console.log('Finding id ' + id)
|
||
|
let i = buckets.findIndex((value)=> {
|
||
|
//console.log(' testing ', value)
|
||
|
return value.id?value.id === id:false
|
||
|
})
|
||
|
if(i<0) {
|
||
|
res.status(404).send(notfoundResp)
|
||
|
return
|
||
|
}
|
||
|
buckets.splice(i,1)
|
||
|
res.sendStatus(204)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
function orgsResp(orgs) {
|
||
|
return `{
|
||
|
"links": {
|
||
|
"self": "/api/v2/orgs"
|
||
|
},
|
||
|
"orgs": [
|
||
|
${orgs}
|
||
|
]
|
||
|
}`
|
||
|
}
|
||
|
|
||
|
const orgResp = `{
|
||
|
"links": {
|
||
|
"buckets": "/api/v2/buckets?org=my-org",
|
||
|
"dashboards": "/api/v2/dashboards?org=my-org",
|
||
|
"labels": "/api/v2/orgs/e2e2d84ffb3c4f85/labels",
|
||
|
"logs": "/api/v2/orgs/e2e2d84ffb3c4f85/logs",
|
||
|
"members": "/api/v2/orgs/e2e2d84ffb3c4f85/members",
|
||
|
"owners": "/api/v2/orgs/e2e2d84ffb3c4f85/owners",
|
||
|
"secrets": "/api/v2/orgs/e2e2d84ffb3c4f85/secrets",
|
||
|
"self": "/api/v2/orgs/e2e2d84ffb3c4f85",
|
||
|
"tasks": "/api/v2/tasks?org=my-org"
|
||
|
},
|
||
|
"id": "${orgID}",
|
||
|
"name": "${orgName}",
|
||
|
"description": "",
|
||
|
"createdAt": "2021-08-18T06:24:02.427946Z",
|
||
|
"updatedAt": "2021-08-18T06:24:02.427946Z"
|
||
|
}`
|
||
|
|
||
|
app.get(prefix+'/api/v2/orgs', (req,res) => {
|
||
|
if(handleAuthentication(req, res)) {
|
||
|
var name = req.query['org'];
|
||
|
if(name){
|
||
|
if(name === orgName) {
|
||
|
res.status(200).send(orgsResp(orgResp))
|
||
|
} else {
|
||
|
res.status(200).send(orgsResp(""))
|
||
|
}
|
||
|
} else {
|
||
|
res.status(200).send(orgsResp(orgResp))
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
|
||
|
function parsePoints(data) {
|
||
|
var lines = data.split("\n");
|
||
|
var points = [];
|
||
|
lines.forEach((line, index) => {
|
||
|
var parts = line.split(" ");
|
||
|
if (parts.length > 1) {
|
||
|
var measTags = parts[0];
|
||
|
var fields = parts[1].split(",");
|
||
|
var point = {};
|
||
|
var keys = measTags.split(",");
|
||
|
point.measurement = keys[0];
|
||
|
point.tags = {};
|
||
|
point.fields = {};
|
||
|
if (keys.length > 1) {
|
||
|
for (var i = 1; i < keys.length; i++) {
|
||
|
var keyval = keys[i].split("=");
|
||
|
point.tags[keyval[0]] = keyval[1];
|
||
|
}
|
||
|
}
|
||
|
for (var i = 0; i < fields.length; i++) {
|
||
|
var keyval = fields[i].split("=");
|
||
|
var value = keyval[1];
|
||
|
if (typeof value === 'string' && value.endsWith("i")) {
|
||
|
value = value.substring(0, value.length - 1);
|
||
|
}
|
||
|
point.fields[keyval[0]] = value;
|
||
|
}
|
||
|
if(parts.length>2) {
|
||
|
point.timestamp = parts[2];
|
||
|
}
|
||
|
points.push(point);
|
||
|
}
|
||
|
});
|
||
|
if (points.length > 0) {
|
||
|
return points;
|
||
|
}
|
||
|
else {
|
||
|
return data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const AuthToken = "Token my-token";
|
||
|
function handleAuthentication(req, res) {
|
||
|
var auth = req.get('Authorization');
|
||
|
if(auth && auth != AuthToken) {
|
||
|
res.status(401).send(`{"code":"unauthorized","message":"unauthorized access"}`);
|
||
|
return false;
|
||
|
}
|
||
|
let u = req.query['u']
|
||
|
let p = req.query['p']
|
||
|
if(u && p && (p != "my secret password" || u != "user")) {
|
||
|
res.status(401).send(`{"code":"unauthorized","message":"invalid user or password"}`);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
const AllowedPrecisions = ['ns','us','ms','s'];
|
||
|
function checkWriteParams(req, res) {
|
||
|
var bucket = req.query['bucket'];
|
||
|
var precision = req.query['precision'];
|
||
|
if(!checkOrg(req, res)) {
|
||
|
return false;
|
||
|
} else if(bucket != 'my-bucket') {
|
||
|
res.status(404).send(`{"code":"not found","message":"bucket \"${bucket}\" not found"}`);
|
||
|
return false;
|
||
|
} else if(typeof precision !== 'undefined' && AllowedPrecisions.indexOf(precision)==-1) {
|
||
|
res.status(400).send(`{"code":"bad request ","message":"precision \"${precision}\" is not valid"}`);
|
||
|
return false;
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const AllowedPrecisionsV1 = ['ns','u','ms','s'];
|
||
|
function checkWriteParamsV1(req, res) {
|
||
|
var db = req.query['db'];
|
||
|
var user = req.query['u'];
|
||
|
var pass = req.query['p'];
|
||
|
var precision = req.query['precision'];
|
||
|
if(db != 'my-db') {
|
||
|
res.status(404).send(`{"code":"not found","message":"database \"${db}\" not found"}`);
|
||
|
return false;
|
||
|
} else if(typeof precision !== 'undefined' && AllowedPrecisionsV1.indexOf(precision)==-1) {
|
||
|
res.status(400).send(`precision \"${precision}\" is not valid`);
|
||
|
return false;
|
||
|
} else if (user !== 'user' && pass != 'my secret pass') {
|
||
|
res.status(401).send("unauthorized")
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function checkQueryParams(req, res) {
|
||
|
let org = req.query['org']
|
||
|
if(org) {
|
||
|
return checkOrg(req, res);
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
function checkOrg(req, res) {
|
||
|
var org = req.query['org'];
|
||
|
if(org !== 'my-org') {
|
||
|
res.status(404).send(`{"code":"not found","message":"organization name \"${org}\" not found"}`);
|
||
|
return false;
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function objectToCSV(obj, type, level) {
|
||
|
var line = '';
|
||
|
if(level == 1) line = type==0?'#datatype,':',';
|
||
|
var i = 0;
|
||
|
for (var index in obj) {
|
||
|
if (i>0) line += ',';
|
||
|
if(typeof obj[index] == 'object') {
|
||
|
line += objectToCSV(obj[index], type, level+1);
|
||
|
} else if(type == 0) { //datatype header
|
||
|
line += 'string';
|
||
|
} else if(type == 1) {
|
||
|
line += index;
|
||
|
} else {
|
||
|
line += obj[index];
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
return line;
|
||
|
}
|
||
|
|
||
|
function convertToCSV(objArray) {
|
||
|
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
|
||
|
var str = '';
|
||
|
|
||
|
if(array.length > 0) {
|
||
|
str = objectToCSV(array[0], 0, 1) + '\r\n';
|
||
|
str += objectToCSV(array[0], 1, 1) + '\r\n';
|
||
|
}
|
||
|
|
||
|
for (var i = 0; i < array.length; i++) {
|
||
|
var line = '';
|
||
|
line = objectToCSV(array[i], 2, 1);
|
||
|
|
||
|
str += line + '\r\n';
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
var mgmtServer = mgmtApp.listen(mgmtPort)
|
||
|
|
||
|
var rl = readline.createInterface(process.stdin, process.stdout);
|
||
|
|
||
|
rl.on('line', function(line) {
|
||
|
rl.close();
|
||
|
}).on('close',function(){
|
||
|
if(server !== undefined) {
|
||
|
server.close();
|
||
|
}
|
||
|
mgmtServer.close();
|
||
|
process.exit(0);
|
||
|
});
|
||
|
|
||
|
|
||
|
var ifaces = os.networkInterfaces();
|
||
|
|
||
|
console.log("Available interfaces:")
|
||
|
Object.keys(ifaces).forEach(function (ifname) {
|
||
|
var alias = 0;
|
||
|
|
||
|
ifaces[ifname].forEach(function (iface) {
|
||
|
if ('IPv4' !== iface.family || iface.internal !== false) {
|
||
|
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (alias >= 1) {
|
||
|
// this single interface has multiple ipv4 addresses
|
||
|
console.log(' ', ifname + ':' + alias, iface.address);
|
||
|
} else {
|
||
|
// this interface has only one ipv4 adress
|
||
|
console.log(' ', ifname, iface.address);
|
||
|
}
|
||
|
++alias;
|
||
|
});
|
||
|
});
|
||
|
console.log(`Listening on http://${mgmtServer.address().address}:${mgmtServer.address().port}`)
|
||
|
console.log(`Press Enter to exit`)
|