Compare commits

..
7 Commits
Author SHA1 Message Date
Jim Klucar d18b5bc46d commit to switch to my laptop 2016-08-25 16:02:23 -04:00
Jim Klucar ba60f9ef00 Merge branch 'master' into wamp 2016-08-25 14:19:58 -04:00
Jim Klucar 49a8d970fe minor pom consistency tweaks 2016-08-25 14:18:55 -04:00
Jim Klucar 345f4b7006 merge of spring config changes 2016-08-25 14:07:51 -04:00
Jim Klucar b81783f7ea initial WAMP setup 2016-08-25 13:48:41 -04:00
brianloss 1be6f24676 Use Spring Configuration (#68)
* Initial pass at converting timely configuration to Spring Boot for type-safe config that is a lot more flexible than standard properties file configuration.

* Change banner color to red.

* Update Configuration class to support fluent API.

* Re-work configuration to group properties in a more sensible manner.

* Use NotBlank everywhere instead of NotEmpty for validations.
2016-08-25 13:19:59 -04:00
Dave Marion 82b94f1a71 fixes #40 - add regex support for lookup requests 2016-08-23 09:26:56 -04:00
73 changed files with 1875 additions and 1573 deletions

No files matched your search

+1
View File
@@ -4,3 +4,4 @@
target/
.idea/
*.iml
logs/
+1
View File
@@ -3,3 +3,4 @@ Eric Newton ([email protected])
Jim Klucar ([email protected])
Charlie Williams ([email protected])
Drew Farris ([email protected])
Brian Loss ([email protected])
+3 -8
View File
@@ -108,7 +108,9 @@ System.register(['lodash'], function (_export, _context) {
switch (response.status) {
case 200:
console.log(this.getCookie('TSESSIONID'));
var cookie = (document.cookie.match(/^(?:.*;)?TSESSIONID=([^;]+)(?:.*)?$/) || [, null])[1];
console.log(cookie);
console.log(document.cookie);
this.fetching.status = 'success';
this.fetching.title = 'Login successful';
@@ -124,13 +126,6 @@ System.register(['lodash'], function (_export, _context) {
if (r.readyState != 4 || r.status != 200) return;
alert("Success: " + r.getResponseHeader('Set-Cookie'));
}
}, {
key: 'getCookie',
value: function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
}, {
key: '_getURI',
value: function _getURI(jsonData) {
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/components/auths.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAO,O;;;;;;;;;;;;;;;;;;;;;2BAEM,S;AAEX,2BAAY,UAAZ,EAAwB,UAAxB,EAAoC,QAApC,EAA6C;AAAA;;AAC3C,eAAK,UAAL,GAAkB,UAAlB;AACA,eAAK,QAAL,GAAgB,QAAhB;AACA,eAAK,UAAL,GAAkB,UAAlB;AACD;;;;gCAEK,U,EAAW;AACf,iBAAK,QAAL,GAAgB,EAAhB;AACA,iBAAK,QAAL,CAAc,IAAd,GAAqB,KAArB;AACA,iBAAK,QAAL,CAAc,IAAd,GAAqB,IAArB;AACA,iBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,iBAAK,QAAL,CAAc,KAAd,GAAsB,mBAAtB;;AAEA;AACA;AACA;;AAEA,gBAAI,MAAM,KAAK,OAAL,CAAa,WAAW,QAAxB,CAAV;;AAEA,gBAAG,WAAW,QAAX,CAAoB,UAAvB,EAAkC;AAChC,kBAAI,KAAK,aAAL,IAAsB,KAAK,iBAA/B,EAAiD;AAC/C,oBAAI,WAAW,EAAC,UAAU,KAAK,aAAhB,EAA+B,UAAU,KAAK,iBAA9C,EAAf;AACA,qBAAK,WAAL,CAAiB,GAAjB,EAAsB,QAAtB;AACD,eAHD,MAGO;AACL,qBAAK,UAAL,CAAgB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,WAAW,IAAZ,EAAkB,wBAAlB,CAA1C;AACA,qBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,qBAAK,QAAL,CAAc,KAAd,GAAsB,wBAAtB;;AAEA;AACD;AACF,aAXD,MAWO;AACL,mBAAK,UAAL,CAAgB,GAAhB;AACD;AAEF;;;sCAEW,G,EAAK,Q,EAAS;AACxB,iBAAK,KAAL,CAAW,MAAX,EAAmB,GAAnB,EAAwB,QAAxB;AACD;;;qCAEU,G,EAAI;AACb,iBAAK,KAAL,CAAW,KAAX,EAAkB,GAAlB;AACD;;;gCAEK,I,EAAM,G,EAAK,I,EAAK;AACpB,gBAAI,CAAC,IAAL,EAAU;AACR,qBAAO,EAAP;AACD;AACD,gBAAI,IAAI,IAAI,cAAJ,EAAR;AACA,cAAE,IAAF,CAAO,IAAP,EAAa,GAAb,EAAkB,IAAlB;AACA,cAAE,eAAF,GAAoB,IAApB;AACA,cAAE,gBAAF,CAAmB,cAAnB,EAAmC,kBAAnC;AACA,cAAE,kBAAF,GAAuB,YAAY;AACjC,mBAAK,iBAAL,CAAuB,CAAvB;AACD,aAFsB,CAErB,IAFqB,CAEhB,IAFgB,CAAvB;AAGA,cAAE,IAAF,CAAO,KAAK,SAAL,CAAe,IAAf,CAAP;AACD;;;4CAEiB,Q,EAAS;AACzB;AACA,gBAAI,SAAS,UAAT,IAAuB,CAA3B,EAA8B;;AAE9B,iBAAK,QAAL,CAAc,IAAd,GAAqB,IAArB;;AAEA,oBAAO,SAAS,MAAhB;AACE,mBAAK,GAAL;AACE,wBAAQ,GAAR,CAAY,KAAK,SAAL,CAAe,YAAf,CAAZ;;AAEA,qBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,qBAAK,QAAL,CAAc,KAAd,GAAsB,kBAAtB;AACA,qBAAK,UAAL,CAAgB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,SAAD,EAAY,EAAZ,CAA1C;AACA;AACF;AACE,qBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,qBAAK,QAAL,CAAc,KAAd,GAAsB,SAAS,UAA/B;AACA,qBAAK,UAAL,CAAgB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,SAAS,MAAT,GAAgB,IAAhB,GAAqB,SAAS,UAA/B,EAA0C,EAA1C,CAA1C;AACA;AAZJ;;AAeA,gBAAI,EAAE,UAAF,IAAgB,CAAhB,IAAqB,EAAE,MAAF,IAAY,GAArC,EAA0C;AAC1C,kBAAM,cAAc,EAAE,iBAAF,CAAoB,YAApB,CAApB;AACD;;;oCAES,I,EAAM;AACd,gBAAI,QAAQ,OAAO,SAAS,MAA5B;AACA,gBAAI,QAAQ,MAAM,KAAN,CAAY,OAAO,IAAP,GAAc,GAA1B,CAAZ;AACA,gBAAI,MAAM,MAAN,IAAgB,CAApB,EAAuB,OAAO,MAAM,GAAN,GAAY,KAAZ,CAAkB,GAAlB,EAAuB,KAAvB,EAAP;AACxB;;;kCAEO,Q,EAAS;AACf,mBAAO,aAAW,SAAS,UAApB,GAA+B,GAA/B,GAAmC,SAAS,SAA5C,GAAsD,QAA7D;AACD;;;yCAEa,CAEb","file":"auths.js","sourcesContent":["import _ from 'lodash';\n\nexport class AuthsCtrl {\n\n constructor(backendSrv, $rootScope, $timeout){\n this.$rootScope = $rootScope;\n this.$timeout = $timeout;\n this.backendSrv = backendSrv;\n }\n\n login(datasource){\n this.fetching = {};\n this.fetching.done = false;\n this.fetching.show = true;\n this.fetching.status = 'warning';\n this.fetching.title = 'Fetching auths...';\n\n //this.$rootScope.appEvent('alert-success', ['Authorization Cookie Received', '']);\n //this.$rootScope.appEvent('alert-error', ['Authorization Failed', '']);\n //this.$rootScope.appEvent('alert-warning', ['Fetching Authorizations', '']);\n\n var uri = this._getURI(datasource.jsonData);\n\n if(datasource.jsonData.basicAuths){\n if( this.basicAuthUser && this.basicAuthPassword){\n var authBlob = {username: this.basicAuthUser, password: this.basicAuthPassword};\n this.doPostLogin(uri, authBlob);\n } else {\n this.$rootScope.appEvent('alert-warning', [datasource.name, 'requires User/Password']);\n this.fetching.status = 'warning';\n this.fetching.title = 'User/Password required';\n\n return;\n }\n } else {\n this.doGetLogin(uri);\n }\n\n }\n\n doPostLogin(uri, authBlob){\n this.doXHR('POST', uri, authBlob);\n }\n\n doGetLogin(uri){\n this.doXHR('GET', uri)\n }\n\n doXHR(verb, uri, data){\n if( !data){\n data = \"\";\n }\n var r = new XMLHttpRequest();\n r.open(verb, uri, true);\n r.withCredentials = true;\n r.setRequestHeader('Content-Type', 'application/json');\n r.onreadystatechange = function () {\n this.handleLoginResult(r);\n }.bind(this);\n r.send(JSON.stringify(data));\n }\n\n handleLoginResult(response){\n // wait for readyState to be '4 => done'\n if (response.readyState != 4) return;\n\n this.fetching.done = true;\n\n switch(response.status){\n case 200:\n console.log(this.getCookie('TSESSIONID'))\n\n this.fetching.status = 'success';\n this.fetching.title = 'Login successful';\n this.$rootScope.appEvent('alert-success', ['Success', '']);\n break;\n default:\n this.fetching.status = 'warning';\n this.fetching.title = response.statusText;\n this.$rootScope.appEvent('alert-warning', [response.status+': '+response.statusText,'']);\n break;\n }\n\n if (r.readyState != 4 || r.status != 200) return;\n alert(\"Success: \" + r.getResponseHeader('Set-CookiLine truncated
{"version":3,"sources":["../../src/components/auths.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAO,O;;;;;;;;;;;;;;;;;;;;;2BAEM,S;AAEX,2BAAY,UAAZ,EAAwB,UAAxB,EAAoC,QAApC,EAA6C;AAAA;;AAC3C,eAAK,UAAL,GAAkB,UAAlB;AACA,eAAK,QAAL,GAAgB,QAAhB;AACA,eAAK,UAAL,GAAkB,UAAlB;AACD;;;;gCAEK,U,EAAW;AACf,iBAAK,QAAL,GAAgB,EAAhB;AACA,iBAAK,QAAL,CAAc,IAAd,GAAqB,KAArB;AACA,iBAAK,QAAL,CAAc,IAAd,GAAqB,IAArB;AACA,iBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,iBAAK,QAAL,CAAc,KAAd,GAAsB,mBAAtB;;AAEA;AACA;AACA;;AAEA,gBAAI,MAAM,KAAK,OAAL,CAAa,WAAW,QAAxB,CAAV;;AAEA,gBAAG,WAAW,QAAX,CAAoB,UAAvB,EAAkC;AAChC,kBAAI,KAAK,aAAL,IAAsB,KAAK,iBAA/B,EAAiD;AAC/C,oBAAI,WAAW,EAAC,UAAU,KAAK,aAAhB,EAA+B,UAAU,KAAK,iBAA9C,EAAf;AACA,qBAAK,WAAL,CAAiB,GAAjB,EAAsB,QAAtB;AACD,eAHD,MAGO;AACL,qBAAK,UAAL,CAAgB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,WAAW,IAAZ,EAAkB,wBAAlB,CAA1C;AACA,qBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,qBAAK,QAAL,CAAc,KAAd,GAAsB,wBAAtB;;AAEA;AACD;AACF,aAXD,MAWO;AACL,mBAAK,UAAL,CAAgB,GAAhB;AACD;AAEF;;;sCAEW,G,EAAK,Q,EAAS;AACxB,iBAAK,KAAL,CAAW,MAAX,EAAmB,GAAnB,EAAwB,QAAxB;AACD;;;qCAEU,G,EAAI;AACb,iBAAK,KAAL,CAAW,KAAX,EAAkB,GAAlB;AACD;;;gCAEK,I,EAAM,G,EAAK,I,EAAK;AACpB,gBAAI,CAAC,IAAL,EAAU;AACR,qBAAO,EAAP;AACD;AACD,gBAAI,IAAI,IAAI,cAAJ,EAAR;AACA,cAAE,IAAF,CAAO,IAAP,EAAa,GAAb,EAAkB,IAAlB;AACA,cAAE,eAAF,GAAoB,IAApB;AACA,cAAE,gBAAF,CAAmB,cAAnB,EAAmC,kBAAnC;AACA,cAAE,kBAAF,GAAuB,YAAY;AACjC,mBAAK,iBAAL,CAAuB,CAAvB;AACD,aAFsB,CAErB,IAFqB,CAEhB,IAFgB,CAAvB;AAGA,cAAE,IAAF,CAAO,KAAK,SAAL,CAAe,IAAf,CAAP;AACD;;;4CAEiB,Q,EAAS;AACzB;AACA,gBAAI,SAAS,UAAT,IAAuB,CAA3B,EAA8B;;AAE9B,iBAAK,QAAL,CAAc,IAAd,GAAqB,IAArB;;AAEA,oBAAO,SAAS,MAAhB;AACE,mBAAK,GAAL;AACE,oBAAI,SAAS,CAAC,SAAS,MAAT,CAAgB,KAAhB,CAAsB,qCAAtB,KAA8D,GAAE,IAAF,CAA/D,EAAwE,CAAxE,CAAb;AACA,wBAAQ,GAAR,CAAY,MAAZ;AACA,wBAAQ,GAAR,CAAY,SAAS,MAArB;;AAEA,qBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,qBAAK,QAAL,CAAc,KAAd,GAAsB,kBAAtB;AACA,qBAAK,UAAL,CAAgB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,SAAD,EAAY,EAAZ,CAA1C;AACA;AACF;AACE,qBAAK,QAAL,CAAc,MAAd,GAAuB,SAAvB;AACA,qBAAK,QAAL,CAAc,KAAd,GAAsB,SAAS,UAA/B;AACA,qBAAK,UAAL,CAAgB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,SAAS,MAAT,GAAgB,IAAhB,GAAqB,SAAS,UAA/B,EAA0C,EAA1C,CAA1C;AACA;AAdJ;;AAiBA,gBAAI,EAAE,UAAF,IAAgB,CAAhB,IAAqB,EAAE,MAAF,IAAY,GAArC,EAA0C;AAC1C,kBAAM,cAAc,EAAE,iBAAF,CAAoB,YAApB,CAApB;AACD;;;kCAEO,Q,EAAS;AACf,mBAAO,aAAW,SAAS,UAApB,GAA+B,GAA/B,GAAmC,SAAS,SAA5C,GAAsD,QAA7D;AACD;;;yCAEa,CAEb","file":"auths.js","sourcesContent":["import _ from 'lodash';\n\nexport class AuthsCtrl {\n\n constructor(backendSrv, $rootScope, $timeout){\n this.$rootScope = $rootScope;\n this.$timeout = $timeout;\n this.backendSrv = backendSrv;\n }\n\n login(datasource){\n this.fetching = {};\n this.fetching.done = false;\n this.fetching.show = true;\n this.fetching.status = 'warning';\n this.fetching.title = 'Fetching auths...';\n\n //this.$rootScope.appEvent('alert-success', ['Authorization Cookie Received', '']);\n //this.$rootScope.appEvent('alert-error', ['Authorization Failed', '']);\n //this.$rootScope.appEvent('alert-warning', ['Fetching Authorizations', '']);\n\n var uri = this._getURI(datasource.jsonData);\n\n if(datasource.jsonData.basicAuths){\n if( this.basicAuthUser && this.basicAuthPassword){\n var authBlob = {username: this.basicAuthUser, password: this.basicAuthPassword};\n this.doPostLogin(uri, authBlob);\n } else {\n this.$rootScope.appEvent('alert-warning', [datasource.name, 'requires User/Password']);\n this.fetching.status = 'warning';\n this.fetching.title = 'User/Password required';\n\n return;\n }\n } else {\n this.doGetLogin(uri);\n }\n\n }\n\n doPostLogin(uri, authBlob){\n this.doXHR('POST', uri, authBlob);\n }\n\n doGetLogin(uri){\n this.doXHR('GET', uri)\n }\n\n doXHR(verb, uri, data){\n if( !data){\n data = \"\";\n }\n var r = new XMLHttpRequest();\n r.open(verb, uri, true);\n r.withCredentials = true;\n r.setRequestHeader('Content-Type', 'application/json');\n r.onreadystatechange = function () {\n this.handleLoginResult(r);\n }.bind(this);\n r.send(JSON.stringify(data));\n }\n\n handleLoginResult(response){\n // wait for readyState to be '4 => done'\n if (response.readyState != 4) return;\n\n this.fetching.done = true;\n\n switch(response.status){\n case 200:\n var cookie = (document.cookie.match(/^(?:.*;)?TSESSIONID=([^;]+)(?:.*)?$/)||[,null])[1]\n console.log(cookie);\n console.log(document.cookie);\n \n this.fetching.status = 'success';\n this.fetching.title = 'Login successful';\n this.$rootScope.appEvent('alert-success', ['Success', '']);\n break;\n default:\n this.fetching.status = 'warning';\n this.fetching.title = response.statusText;\n this.$rootScope.appEvent('alert-warning', [response.status+': '+response.statusText,'']);\n break;\n }\n\n if (r.readyState != 4 || r.status != 200) return;\n alert(\"Success: \" + r.Line truncated
-67
View File
@@ -1,67 +0,0 @@
<div class="page-header">
<h1>Websocket Test</h1>
</div>
<div ng-hide="ctrl.websocketSupported" >
<h4>WebSockets are not suppported in this browser.</h4>
</div>
<div class="gf-box" ng-show="ctrl.websocketSupported">
<div class="gf-box-header">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-label width-7 p-y-1 p-x-1">Metric</span>
<div class="gf-form-select-wrapper gf-form-select-wrapper--has-help-icon max-width-24">
<input type="text" class="gf-form-input"
spellcheck='false'
data-min-length=0
data-items=100
ng-model="metricName"
placeholder="sys.">
<info-popover mode="right-absolute">
Type a Metric name<br>
</info-popover>
<div ng-hide="ctrl.fetching" class="gf-row">
<button type="submit" class="btn btn-success" ng-click="ctrl.start(metricName)">
Start
</button>
</div>
<div ng-show="ctrl.fetching" class="gf-row">
<button type="submit" class="btn btn-warning" ng-click="ctrl.stop(metricName)">
Stop
</button>
</div>
</div>
</div>
</div>
</div>
<div class="gf-box-body">
<div class="grafana-options-table">
<p>{{ctrl.metric_count}}</p>
<table>
<tr>
<th>Metric</th>
<th>Tags</th>
<th>Values</th>
</tr>
<tr>
<td>{{ctrl.metric['metric']}}</td>
<!--td class="p-x-1" ng-repeat="tag in ctrl.metric.tags">
{{tag.key}} = {{tag.value}}
</td -->
<td>{{ctrl.metric.timestamp}} -> {{ctrl.metric.value}}</td>
</tr>
</table>
</div>
</div>
</div>
-164
View File
@@ -1,164 +0,0 @@
'use strict';
System.register(['plugins/timely-app/components/authspage'], function (_export, _context) {
"use strict";
var AuthsPageCtrl, _createClass, WebsocketCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [function (_pluginsTimelyAppComponentsAuthspage) {
AuthsPageCtrl = _pluginsTimelyAppComponentsAuthspage.AuthsPageCtrl;
}],
execute: function () {
_createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
_export('WebsocketCtrl', WebsocketCtrl = function () {
function WebsocketCtrl($scope, $timeout, backendSrv, datasourceSrv) {
_classCallCheck(this, WebsocketCtrl);
this.$scope = $scope;
this.$timeout = $timeout;
var actrl = new AuthsPageCtrl(backendSrv, datasourceSrv);
var datasources = actrl.getTimelyDatasources();
this.datasource = datasources[0].jsonData;
this.websocketSupported = false;
if (window.WebSocket) {
this.websocketSupported = true;
}
this.metric_count = 0;
this.metric = { 'metric': 'empty',
'tags': [],
'timestamp': 0,
'value': 0.0
};
this.fetching = false;
}
_createClass(WebsocketCtrl, [{
key: 'start',
value: function start(metric) {
this.fetching = true;
var addr = this._getWebsocketAddress();
this.sock = new WebSocket(addr);
this.sock.onmessage = this._handleMessage.bind(this);
this.sock.onopen = this._handleOpen.bind(this);
this.sock.onclose = this._handleClose.bind(this);
}
}, {
key: 'stop',
value: function stop(metric) {
this.fetching = false;
this.sock.close();
}
}, {
key: '_handleMessage',
value: function _handleMessage(message) {
//console.log('handleMessage');
var metric = JSON.parse(message.data);
this.metric.metric = metric.metric;
this.metric.timestamp = metric.timestamp;
this.metric.value = metric.value;
this.metric.tags = metric.tags;
this.metric_count = this.metric_count + 1;
this.$scope.$digest();
//if( this.metrics.length >= 16){
// this.metrics.shift();
//}
//this.$scope.$apply( function(){
// this.metrics.push(metric);
// this.metric_count = this.metric_count + 1;
// }.bind(this));
}
}, {
key: '_handleOpen',
value: function _handleOpen() {
var create = {
"operation": "create",
"subscriptionId": "12345"
};
this.sock.send(JSON.stringify(create));
var m1 = {
"operation": "add",
"subscriptionId": "12345",
"metric": "sys.cpu.user"
};
this.sock.send(JSON.stringify(m1));
// var m2 = {
// "operation" : "add",
// "subscriptionId" : "12345",
// "metric" : "timely.keys.metric.inserted"
// }
// this.sock.send(JSON.stringify(m2));
}
}, {
key: '_handleClose',
value: function _handleClose() {
console.log("Websocket Closed");
}
}, {
key: '_getWebsocketAddress',
value: function _getWebsocketAddress() {
return "wss://" + this.datasource.timelyHost + ":" + this.datasource.wsPort + "/websocket";
}
}]);
return WebsocketCtrl;
}());
_export('WebsocketCtrl', WebsocketCtrl);
WebsocketCtrl.templateUrl = 'components/websocket.html';
// example metric message
//{
// "metric" : "sys.cpu.user",
// "timestamp":1469028728091,
// "value":1.0,
// "tags":
// [
// {
// "key":"rack",
// "value":"r1"
// },{
// "key":"tag3",
// "value":"value3"
// },{
// "key":"tag4",
// "value":"value4"
// }
// ],
// "subscriptionId":"<unique id>"
//}
}
};
});
//# sourceMappingURL=websocket.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["../../src/components/websocket.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AACQ,mB,wCAAA,a;;;;;;;;;;;;;;;;;;;;;+BAGK,a;AAEX,+BAAY,MAAZ,EAAoB,QAApB,EAA8B,UAA9B,EAA0C,aAA1C,EAAyD;AAAA;;AACvD,eAAK,MAAL,GAAc,MAAd;AACA,eAAK,QAAL,GAAgB,QAAhB;;AAEA,cAAI,QAAQ,IAAI,aAAJ,CAAkB,UAAlB,EAA8B,aAA9B,CAAZ;;AAEA,cAAI,cAAc,MAAM,oBAAN,EAAlB;AACA,eAAK,UAAL,GAAkB,YAAY,CAAZ,EAAe,QAAjC;;AAEA,eAAK,kBAAL,GAA0B,KAA1B;AACA,cAAI,OAAO,SAAX,EAAsB;AAClB,iBAAK,kBAAL,GAA0B,IAA1B;AACH;AACD,eAAK,YAAL,GAAoB,CAApB;AACA,eAAK,MAAL,GAAc,EAAE,UAAU,OAAZ;AACE,oBAAO,EADT;AAEE,yBAAa,CAFf;AAGE,qBAAS;AAHX,WAAd;;AAMA,eAAK,QAAL,GAAgB,KAAhB;AACD;;;;gCAEK,M,EAAO;AACX,iBAAK,QAAL,GAAgB,IAAhB;AACA,gBAAI,OAAO,KAAK,oBAAL,EAAX;AACA,iBAAK,IAAL,GAAY,IAAI,SAAJ,CAAc,IAAd,CAAZ;AACA,iBAAK,IAAL,CAAU,SAAV,GAAsB,KAAK,cAAL,CAAoB,IAApB,CAAyB,IAAzB,CAAtB;AACA,iBAAK,IAAL,CAAU,MAAV,GAAmB,KAAK,WAAL,CAAiB,IAAjB,CAAsB,IAAtB,CAAnB;AACA,iBAAK,IAAL,CAAU,OAAV,GAAoB,KAAK,YAAL,CAAkB,IAAlB,CAAuB,IAAvB,CAApB;AACD;;;+BAEI,M,EAAQ;AACX,iBAAK,QAAL,GAAgB,KAAhB;AACA,iBAAK,IAAL,CAAU,KAAV;AACD;;;yCAEc,O,EAAQ;AACrB;AACA,gBAAI,SAAS,KAAK,KAAL,CAAW,QAAQ,IAAnB,CAAb;;AAEA,iBAAK,MAAL,CAAY,MAAZ,GAAqB,OAAO,MAA5B;AACA,iBAAK,MAAL,CAAY,SAAZ,GAAwB,OAAO,SAA/B;AACA,iBAAK,MAAL,CAAY,KAAZ,GAAoB,OAAO,KAA3B;AACA,iBAAK,MAAL,CAAY,IAAZ,GAAmB,OAAO,IAA1B;AACA,iBAAK,YAAL,GAAoB,KAAK,YAAL,GAAkB,CAAtC;AACA,iBAAK,MAAL,CAAY,OAAZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACD;;;wCAEY;AACX,gBAAI,SAAS;AACX,2BAAc,QADH;AAEX,gCAAmB;AAFR,aAAb;AAIA,iBAAK,IAAL,CAAU,IAAV,CAAe,KAAK,SAAL,CAAe,MAAf,CAAf;;AAEA,gBAAI,KAAK;AACP,2BAAc,KADP;AAEP,gCAAmB,OAFZ;AAGP,wBAAW;AAHJ,aAAT;AAKA,iBAAK,IAAL,CAAU,IAAV,CAAe,KAAK,SAAL,CAAe,EAAf,CAAf;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACG;;;yCAEa;AACZ,oBAAQ,GAAR,CAAY,kBAAZ;AACD;;;iDAEqB;AACpB,mBAAO,WAAW,KAAK,UAAL,CAAgB,UAA3B,GAAwC,GAAxC,GAA8C,KAAK,UAAL,CAAgB,MAA9D,GAAuE,YAA9E;AACD;;;;;;;;AAGH,oBAAc,WAAd,GAA4B,2BAA5B;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"websocket.js","sourcesContent":["\nimport {AuthsPageCtrl} from 'plugins/timely-app/components/authspage'\n\n\nexport class WebsocketCtrl {\n\n constructor($scope, $timeout, backendSrv, datasourceSrv) {\n this.$scope = $scope;\n this.$timeout = $timeout;\n\n var actrl = new AuthsPageCtrl(backendSrv, datasourceSrv);\n\n var datasources = actrl.getTimelyDatasources();\n this.datasource = datasources[0].jsonData;\n\n this.websocketSupported = false;\n if( window.WebSocket ){\n this.websocketSupported = true;\n }\n this.metric_count = 0;\n this.metric = { 'metric': 'empty',\n 'tags':[],\n 'timestamp': 0,\n 'value': 0.0\n };\n\n this.fetching = false;\n }\n\n start(metric){\n this.fetching = true;\n var addr = this._getWebsocketAddress();\n this.sock = new WebSocket(addr);\n this.sock.onmessage = this._handleMessage.bind(this);\n this.sock.onopen = this._handleOpen.bind(this);\n this.sock.onclose = this._handleClose.bind(this);\n }\n\n stop(metric) {\n this.fetching = false;\n this.sock.close();\n }\n\n _handleMessage(message){\n //console.log('handleMessage');\n var metric = JSON.parse(message.data);\n\n this.metric.metric = metric.metric;\n this.metric.timestamp = metric.timestamp;\n this.metric.value = metric.value;\n this.metric.tags = metric.tags;\n this.metric_count = this.metric_count+1;\n this.$scope.$digest();\n //if( this.metrics.length >= 16){\n // this.metrics.shift();\n //}\n //this.$scope.$apply( function(){\n // this.metrics.push(metric);\n // this.metric_count = this.metric_count + 1;\n // }.bind(this));\n }\n\n _handleOpen(){\n var create = {\n \"operation\" : \"create\",\n \"subscriptionId\" : \"12345\"\n }\n this.sock.send(JSON.stringify(create));\n\n var m1 = {\n \"operation\" : \"add\",\n \"subscriptionId\" : \"12345\",\n \"metric\" : \"sys.cpu.user\"\n }\n this.sock.send(JSON.stringify(m1));\n\n// var m2 = {\n// \"operation\" : \"add\",\n// \"subscriptionId\" : \"12345\",\n// \"metric\" : \"timely.keys.metric.inserted\"\n// }\n// this.sock.send(JSON.stringify(m2));\n }\n\n _handleClose(){\n console.log(\"Websocket Closed\")\n }\n\n _getWebsocketAddress(){\n return \"wss://\" + this.datasource.timelyHost + \":\" + this.datasource.wsPort + \"/websocket\";\n }\n\n}\nWebsocketCtrl.templateUrl = 'components/websocket.html';\n\n\n// example metric message\n//{\n// \"metric\" : \"sys.cpu.user\",\n// \"timestamp\":1469028728091,\n// \"value\":1.0,\n// \"tags\":\n// [\n// {\n// \"key\":\"rack\",\n// \"value\":\"r1\"\n// },{\n// \"key\":\"tag3\",\n// \"value\":\"value3\"\n// },{\n// \"key\":\"tag4\",\n// \"value\":\"value4\"\n// }\n// ],\n// \"subscriptionId\":\"<unique id>\"\n//}\n"]}
@@ -1,39 +1,15 @@
{
"__inputs": [
{
"name": "DS_TIMELY",
"label": "Timely",
"description": "",
"name": "DS_NAME",
"type": "datasource",
"pluginId": "timely-datasource",
"pluginName": "Timely"
}
],
"__requires": [
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": ""
},
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "3.1.1"
},
{
"type": "datasource",
"id": "timely-datasource",
"name": "Timely",
"version": "1.0.0"
"pluginId": "timely-datasource"
}
],
"id": null,
"title": "Timely Standalone Demo",
"tags": [
"imported"
],
"originalTitle": "Timely Standalone Demo",
"tags": ["imported"],
"style": "dark",
"timezone": "browser",
"editable": true,
@@ -48,7 +24,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -123,7 +99,6 @@
"tooltip": {
"msResolution": true,
"shared": false,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -159,7 +134,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -171,94 +146,6 @@
},
"id": 2,
"isNew": true,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "$tag_host $tag_instance",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"refId": "A",
"tags": {
"host": ".*",
"instance": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CPU User by Instance",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 1,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 5,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
@@ -292,7 +179,7 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"host": ".*"
@@ -303,9 +190,8 @@
"timeShift": null,
"title": "CPU User by Host",
"tooltip": {
"msResolution": true,
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -334,7 +220,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -379,7 +265,7 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"rack": ".*"
@@ -390,9 +276,8 @@
"timeShift": null,
"title": "CPU User by Rack",
"tooltip": {
"msResolution": true,
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -421,7 +306,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -466,7 +351,7 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {}
}
@@ -475,9 +360,8 @@
"timeShift": null,
"title": "Cumulative CPU",
"tooltip": {
"msResolution": true,
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -545,7 +429,6 @@
},
"refresh": "5s",
"schemaVersion": 12,
"version": 0,
"links": [],
"gnetId": null
}
"version": 1,
"links": []
}
+2 -6
View File
@@ -1,9 +1,9 @@
'use strict';
System.register(['./components/config', './components/metrics', './components/authspage', './components/websocket'], function (_export, _context) {
System.register(['./components/config', './components/metrics', './components/authspage'], function (_export, _context) {
"use strict";
var TimelyAppConfigCtrl, MetricsPageCtrl, AuthsPageCtrl, WebsocketCtrl;
var TimelyAppConfigCtrl, MetricsPageCtrl, AuthsPageCtrl;
return {
setters: [function (_componentsConfig) {
TimelyAppConfigCtrl = _componentsConfig.TimelyAppConfigCtrl;
@@ -11,8 +11,6 @@ System.register(['./components/config', './components/metrics', './components/au
MetricsPageCtrl = _componentsMetrics.MetricsPageCtrl;
}, function (_componentsAuthspage) {
AuthsPageCtrl = _componentsAuthspage.AuthsPageCtrl;
}, function (_componentsWebsocket) {
WebsocketCtrl = _componentsWebsocket.WebsocketCtrl;
}],
execute: function () {
_export('ConfigCtrl', TimelyAppConfigCtrl);
@@ -20,8 +18,6 @@ System.register(['./components/config', './components/metrics', './components/au
_export('MetricsPageCtrl', MetricsPageCtrl);
_export('AuthsPageCtrl', AuthsPageCtrl);
_export('WebsocketPageCtrl', WebsocketCtrl);
}
};
});
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../src/module.js"],"names":[],"mappings":";;;;;;;;AAAQ,yB,qBAAA,mB;;AACA,qB,sBAAA,e;;AACA,mB,wBAAA,a;;AACA,mB,wBAAA,a;;;4BAGN,mB;;iCACA,e;;+BACA,a;;mCACA,a","file":"module.js","sourcesContent":["import {TimelyAppConfigCtrl} from './components/config';\nimport {MetricsPageCtrl} from './components/metrics';\nimport {AuthsPageCtrl} from './components/authspage';\nimport {WebsocketCtrl} from './components/websocket';\n\nexport {\n TimelyAppConfigCtrl as ConfigCtrl,\n MetricsPageCtrl,\n AuthsPageCtrl,\n WebsocketCtrl as WebsocketPageCtrl\n};\n"]}
{"version":3,"sources":["../src/module.js"],"names":[],"mappings":";;;;;;;;AAAQ,yB,qBAAA,mB;;AACA,qB,sBAAA,e;;AACA,mB,wBAAA,a;;;4BAGN,mB;;iCACA,e;;+BACA,a","file":"module.js","sourcesContent":["import {TimelyAppConfigCtrl} from './components/config';\nimport {MetricsPageCtrl} from './components/metrics';\nimport {AuthsPageCtrl} from './components/authspage';\n\nexport {\n TimelyAppConfigCtrl as ConfigCtrl,\n MetricsPageCtrl,\n AuthsPageCtrl\n};\n"]}
+1 -3
View File
@@ -30,9 +30,7 @@
"includes": [
{"type": "datasource", "name": "Timely"},
{ "type": "page", "name": "Login", "component": "AuthsPageCtrl", "role": "Viewer", "addToNav": true},
{ "type": "page", "name": "Metrics", "component": "MetricsPageCtrl", "role": "Viewer", "addToNav": true},
{ "type": "page", "name": "WebSocket", "component": "WebsocketPageCtrl", "role": "Viewer", "addToNav": true}
{ "type": "page", "name": "Metrics", "component": "MetricsPageCtrl", "role": "Viewer", "addToNav": true}
],
"dependencies": {
+1 -3
View File
@@ -30,9 +30,7 @@
"includes": [
{"type": "datasource", "name": "Timely"},
{ "type": "page", "name": "Login", "component": "AuthsPageCtrl", "role": "Viewer", "addToNav": true},
{ "type": "page", "name": "Metrics", "component": "MetricsPageCtrl", "role": "Viewer", "addToNav": true},
{ "type": "page", "name": "WebSocket", "component": "WebsocketPageCtrl", "role": "Viewer", "addToNav": true}
{ "type": "page", "name": "Metrics", "component": "MetricsPageCtrl", "role": "Viewer", "addToNav": true}
],
"dependencies": {
+4 -8
View File
@@ -68,8 +68,10 @@ export class AuthsCtrl {
switch(response.status){
case 200:
console.log(this.getCookie('TSESSIONID'))
var cookie = (document.cookie.match(/^(?:.*;)?TSESSIONID=([^;]+)(?:.*)?$/)||[,null])[1]
console.log(cookie);
console.log(document.cookie);
this.fetching.status = 'success';
this.fetching.title = 'Login successful';
this.$rootScope.appEvent('alert-success', ['Success', '']);
@@ -85,12 +87,6 @@ export class AuthsCtrl {
alert("Success: " + r.getResponseHeader('Set-Cookie'));
}
getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
_getURI(jsonData){
return 'https://'+jsonData.timelyHost+':'+jsonData.httpsPort+'/login'
}
@@ -1,67 +0,0 @@
<div class="page-header">
<h1>Websocket Test</h1>
</div>
<div ng-hide="ctrl.websocketSupported" >
<h4>WebSockets are not suppported in this browser.</h4>
</div>
<div class="gf-box" ng-show="ctrl.websocketSupported">
<div class="gf-box-header">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-label width-7 p-y-1 p-x-1">Metric</span>
<div class="gf-form-select-wrapper gf-form-select-wrapper--has-help-icon max-width-24">
<input type="text" class="gf-form-input"
spellcheck='false'
data-min-length=0
data-items=100
ng-model="metricName"
placeholder="sys.">
<info-popover mode="right-absolute">
Type a Metric name<br>
</info-popover>
<div ng-hide="ctrl.fetching" class="gf-row">
<button type="submit" class="btn btn-success" ng-click="ctrl.start(metricName)">
Start
</button>
</div>
<div ng-show="ctrl.fetching" class="gf-row">
<button type="submit" class="btn btn-warning" ng-click="ctrl.stop(metricName)">
Stop
</button>
</div>
</div>
</div>
</div>
</div>
<div class="gf-box-body">
<div class="grafana-options-table">
<p>{{ctrl.metric_count}}</p>
<table>
<tr>
<th>Metric</th>
<th>Tags</th>
<th>Values</th>
</tr>
<tr>
<td>{{ctrl.metric['metric']}}</td>
<!--td class="p-x-1" ng-repeat="tag in ctrl.metric.tags">
{{tag.key}} = {{tag.value}}
</td -->
<td>{{ctrl.metric.timestamp}} -> {{ctrl.metric.value}}</td>
</tr>
</table>
</div>
</div>
</div>
@@ -1,116 +0,0 @@
import {AuthsPageCtrl} from 'plugins/timely-app/components/authspage'
export class WebsocketCtrl {
constructor($scope, $timeout, backendSrv, datasourceSrv) {
this.$scope = $scope;
this.$timeout = $timeout;
var actrl = new AuthsPageCtrl(backendSrv, datasourceSrv);
var datasources = actrl.getTimelyDatasources();
this.datasource = datasources[0].jsonData;
this.websocketSupported = false;
if( window.WebSocket ){
this.websocketSupported = true;
}
this.metric_count = 0;
this.metric = { 'metric': 'empty',
'tags':[],
'timestamp': 0,
'value': 0.0
};
this.fetching = false;
}
start(metric){
this.fetching = true;
var addr = this._getWebsocketAddress();
this.sock = new WebSocket(addr);
this.sock.onmessage = this._handleMessage.bind(this);
this.sock.onopen = this._handleOpen.bind(this);
this.sock.onclose = this._handleClose.bind(this);
}
stop(metric) {
this.fetching = false;
this.sock.close();
}
_handleMessage(message){
//console.log('handleMessage');
var metric = JSON.parse(message.data);
this.metric.metric = metric.metric;
this.metric.timestamp = metric.timestamp;
this.metric.value = metric.value;
this.metric.tags = metric.tags;
this.metric_count = this.metric_count+1;
this.$scope.$digest();
//if( this.metrics.length >= 16){
// this.metrics.shift();
//}
//this.$scope.$apply( function(){
// this.metrics.push(metric);
// this.metric_count = this.metric_count + 1;
// }.bind(this));
}
_handleOpen(){
var create = {
"operation" : "create",
"subscriptionId" : "12345"
}
this.sock.send(JSON.stringify(create));
var m1 = {
"operation" : "add",
"subscriptionId" : "12345",
"metric" : "sys.cpu.user"
}
this.sock.send(JSON.stringify(m1));
// var m2 = {
// "operation" : "add",
// "subscriptionId" : "12345",
// "metric" : "timely.keys.metric.inserted"
// }
// this.sock.send(JSON.stringify(m2));
}
_handleClose(){
console.log("Websocket Closed")
}
_getWebsocketAddress(){
return "wss://" + this.datasource.timelyHost + ":" + this.datasource.wsPort + "/websocket";
}
}
WebsocketCtrl.templateUrl = 'components/websocket.html';
// example metric message
//{
// "metric" : "sys.cpu.user",
// "timestamp":1469028728091,
// "value":1.0,
// "tags":
// [
// {
// "key":"rack",
// "value":"r1"
// },{
// "key":"tag3",
// "value":"value3"
// },{
// "key":"tag4",
// "value":"value4"
// }
// ],
// "subscriptionId":"<unique id>"
//}
@@ -1,39 +1,15 @@
{
"__inputs": [
{
"name": "DS_TIMELY",
"label": "Timely",
"description": "",
"name": "DS_NAME",
"type": "datasource",
"pluginId": "timely-datasource",
"pluginName": "Timely"
}
],
"__requires": [
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": ""
},
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "3.1.1"
},
{
"type": "datasource",
"id": "timely-datasource",
"name": "Timely",
"version": "1.0.0"
"pluginId": "timely-datasource"
}
],
"id": null,
"title": "Timely Standalone Demo",
"tags": [
"imported"
],
"originalTitle": "Timely Standalone Demo",
"tags": ["imported"],
"style": "dark",
"timezone": "browser",
"editable": true,
@@ -48,7 +24,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -123,7 +99,6 @@
"tooltip": {
"msResolution": true,
"shared": false,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -159,7 +134,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -171,94 +146,6 @@
},
"id": 2,
"isNew": true,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "$tag_host $tag_instance",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"refId": "A",
"tags": {
"host": ".*",
"instance": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CPU User by Instance",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 1,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 5,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
@@ -292,7 +179,7 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"host": ".*"
@@ -303,9 +190,8 @@
"timeShift": null,
"title": "CPU User by Host",
"tooltip": {
"msResolution": true,
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -334,7 +220,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -379,7 +265,7 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"rack": ".*"
@@ -390,9 +276,8 @@
"timeShift": null,
"title": "CPU User by Rack",
"tooltip": {
"msResolution": true,
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -421,7 +306,7 @@
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"datasource": "${DS_NAME}",
"editable": true,
"error": false,
"fill": 1,
@@ -466,7 +351,7 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu.user",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {}
}
@@ -475,9 +360,8 @@
"timeShift": null,
"title": "Cumulative CPU",
"tooltip": {
"msResolution": true,
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
@@ -545,7 +429,6 @@
},
"refresh": "5s",
"schemaVersion": 12,
"version": 0,
"links": [],
"gnetId": null
}
"version": 1,
"links": []
}
+1 -3
View File
@@ -1,11 +1,9 @@
import {TimelyAppConfigCtrl} from './components/config';
import {MetricsPageCtrl} from './components/metrics';
import {AuthsPageCtrl} from './components/authspage';
import {WebsocketCtrl} from './components/websocket';
export {
TimelyAppConfigCtrl as ConfigCtrl,
MetricsPageCtrl,
AuthsPageCtrl,
WebsocketCtrl as WebsocketPageCtrl
AuthsPageCtrl
};
+25 -12
View File
@@ -51,12 +51,11 @@
<version.jackson>2.6.1</version.jackson>
<version.javassist>3.20.0-GA</version.javassist>
<version.jcip-annotations>1.0</version.jcip-annotations>
<version.junit>4.11</version.junit>
<version.junit>4.12</version.junit>
<version.log4j>2.5</version.log4j>
<version.netty>4.0.38.Final</version.netty>
<version.netty-tcnative>1.1.33.Fork18</version.netty-tcnative>
<version.powermock>1.6.4</version.powermock>
<version.security>4.0.4.RELEASE</version.security>
<version.slf4j>1.7.12</version.slf4j>
<!-- plugin versions -->
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
@@ -72,6 +71,8 @@
<version.maven-rpm>2.1.4</version.maven-rpm>
<version.maven-shade>2.4.2</version.maven-shade>
<version.maven-surefire>2.19.1</version.maven-surefire>
<version.jawampa>0.4.2</version.jawampa>
<version.spring.boot>1.4.0.RELEASE</version.spring.boot>
</properties>
<dependencyManagement>
<dependencies>
@@ -113,6 +114,11 @@
<version>${version.disruptor}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
@@ -264,21 +270,28 @@
<classifier>full</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${version.security}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${version.security}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${version.slf4j}</version>
</dependency>
<dependency>
<groupId>ws.wamp.jawampa</groupId>
<artifactId>jawampa-core</artifactId>
<version>${version.jawampa}</version>
</dependency>
<dependency>
<groupId>ws.wamp.jawampa</groupId>
<artifactId>jawampa-netty</artifactId>
<version>${version.jawampa}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${version.spring.boot}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
+2 -2
View File
@@ -9,9 +9,9 @@ RUN yum -y update && \
yum -y install java-1.8.0-openjdk-devel maven openssl apr && \
mkdir -p /timely/bin
ENV JAVA_HOME /usr/lib/jvm/jre-1.8.0-openjdk
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.91-1.b14.el7_2.x86_64
EXPOSE 9804 54321 54322 54323
EXPOSE 9804 54321 54322
ENV TIMELY_VERSION 0.0.3-SNAPSHOT
+3 -3
View File
@@ -27,7 +27,7 @@
#################################### Server ####################################
[server]
# Protocol (http or https)
protocol = http
protocol = https
# The ip address to bind to, empty will bind to all interfaces
;http_addr =
@@ -55,8 +55,8 @@ http_port = 3000
;enable_gzip = false
# https certs & key file
;cert_file = /etc/grafana/pki/timely-cert.pem
;cert_key = /etc/grafana/pki/timely-key.pem
cert_file = /etc/grafana/pki/timely-cert.pem
cert_key = /etc/grafana/pki/timely-key.pem
#################################### Database ####################################
[database]
+429
View File
@@ -0,0 +1,429 @@
{"dashboard":
{
"id": null,
"title": "StandaloneTest",
"originalTitle": "StandaloneTest",
"tags": [],
"style": "dark",
"timezone": "browser",
"editable": true,
"hideControls": false,
"sharedCrosshair": false,
"rows": [
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "Timely",
"editable": true,
"error": false,
"fill": 1,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)",
"thresholdLine": false
},
"id": 1,
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": true,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"disableDownsampling": false,
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "",
"errors": {},
"isCounter": false,
"metric": "timely.metrics.received",
"refId": "A",
"shouldComputeRate": false
},
{
"aggregator": "sum",
"disableDownsampling": false,
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "",
"errors": {},
"metric": "timely.keys.meta.inserted",
"refId": "B"
},
{
"aggregator": "sum",
"disableDownsampling": false,
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "",
"errors": {},
"metric": "timely.keys.metric.inserted",
"refId": "C"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Timely Status",
"tooltip": {
"msResolution": true,
"shared": false,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": "Keys",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": false
}
]
}
],
"title": "Row"
},
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "Timely",
"editable": true,
"error": false,
"fill": 1,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 2,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "$tag_host",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CPU User by Host",
"tooltip": {
"msResolution": false,
"shared": true,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"datasource": "Timely",
"editable": true,
"error": false,
"fill": 1,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 3,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "$tag_rack",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"rack": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CPU User by Rack",
"tooltip": {
"msResolution": false,
"shared": true,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
},
{
"aliasColors": {},
"bars": false,
"datasource": "Timely",
"editable": true,
"error": false,
"fill": 1,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 4,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {}
}
],
"timeFrom": null,
"timeShift": null,
"title": "Cumulative CPU",
"tooltip": {
"msResolution": false,
"shared": true,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"title": "New row"
}
],
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"templating": {
"list": []
},
"annotations": {
"list": []
},
"refresh": "5s",
"schemaVersion": 12,
"version": 1,
"links": []
}
}
+2 -3
View File
@@ -9,12 +9,11 @@ fi
THIS_DIR="${THIS_SCRIPT%/*}"
BASE_DIR=${THIS_DIR}/..
CONF_DIR="${BASE_DIR}/conf"
CONF_FILE="${CONF_DIR}/timely.properties"
LIB_DIR="${BASE_DIR}/lib"
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
JVM_ARGS="-Xmx256m -Xms128m -Dlog4j.configurationFile=${THIS_DIR}/log4j2.xml"
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints "${CONF_FILE}""
$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints "${CONF_FILE}"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints --spring.config.name=timely"
$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints --spring.config.name=timely
-2
View File
@@ -8,8 +8,6 @@ fi
THIS_DIR="${THIS_SCRIPT%/*}"
BASE_DIR=${THIS_DIR}/..
CONF_DIR="${BASE_DIR}/conf"
CONF_FILE="${CONF_DIR}/timely.properties"
LIB_DIR="${BASE_DIR}/lib"
NUM_SERVER_THREADS=4
-2
View File
@@ -8,8 +8,6 @@ fi
THIS_DIR="${THIS_SCRIPT%/*}"
BASE_DIR=${THIS_DIR}/..
CONF_DIR="${BASE_DIR}/conf"
CONF_FILE="${CONF_DIR}/timely.properties"
LIB_DIR="${BASE_DIR}/lib"
NUM_SERVER_THREADS=4
+2 -3
View File
@@ -18,7 +18,6 @@ NATIVE_DIR="${THIS_DIR}/META-INF/native"
BASE_DIR=${THIS_DIR}/..
TMP_DIR="${BASE_DIR}/tmp"
CONF_DIR="${BASE_DIR}/conf"
CONF_FILE="${CONF_DIR}/timely.properties"
LIB_DIR="${BASE_DIR}/lib"
NUM_SERVER_THREADS=4
@@ -41,6 +40,6 @@ JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -D
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}/libnetty-${TCNATIVE_SUFFIX}"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server "${CONF_FILE}""
$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server "${CONF_FILE}"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server --spring.config.name=timely"
$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server --spring.config.name=timely
+2 -3
View File
@@ -18,7 +18,6 @@ NATIVE_DIR="${THIS_DIR}/META-INF/native"
BASE_DIR=${THIS_DIR}/..
TMP_DIR="${BASE_DIR}/tmp"
CONF_DIR="${BASE_DIR}/conf"
CONF_FILE="${CONF_DIR}/timely-standalone.properties"
LIB_DIR="${BASE_DIR}/lib"
NUM_SERVER_THREADS=4
@@ -43,6 +42,6 @@ JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
# for debugging
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,address=54323,server=y,suspend=y"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${CONF_FILE}" "${TMP_DIR}""
$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${CONF_FILE}" "${TMP_DIR}"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${TMP_DIR}" --spring.config.name=timely --spring.profiles.active=standalone"
$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${TMP_DIR}" --spring.config.name=timely --spring.profiles.active=standalone
-38
View File
@@ -1,38 +0,0 @@
timely.ip=0.0.0.0
timely.port.put=54321
timely.port.query=54322
timely.port.websocket=54323
timely.instance_name=TimelyStandalone
timely.zookeepers=127.0.0.1:9804
timely.username=root
timely.password=secret
timely.table=timely.metrics
timely.meta=timely.meta
timely.write.latency=5s
timely.write.threads=3
timely.write.buffer.size=52428800
timely.metric.age.off.days=7
timely.cors.allow.any.origin=true
timely.cors.allow.null.origin=false
timely.cors.allowed.origins=
timely.cors.allowed.methods=DELETE,GET,HEAD,OPTIONS,PUT,POST
timely.cors.allowed.headers=content-type
timely.cors.allow.credentials=true
timely.scanner.threads=4
timely.metrics.report.tags.ignored=
timely.meta.cache.expiration.minutes=60
timely.meta.cache.initial.capacity=2000
timely.meta.cache.max.capacity=10000
#timely.ssl.certificate.file=/timely-server-src/bin/docker/grafana/pki/timely-cert.pem
#timely.ssl.key.file=/timely-server-src/bin/docker/grafana/pki/timely-pkcs8-key.pem
#timely.ssl.key.pass=timely
timely.ssl.use.generated.keypair=true
#timely.ssl.trust.store.file=/timely-server-src/bin/docker/grafana/pki/timely-ca.pem
timely.ssl.use.openssl=true
#timely.ssl.use.ciphers=
timely.session.max.age=86400
timely.http.host=localhost
timely.allow.anonymous.access=true
timely.web.socket.timeout=60
timely.ws.subscription.lag=1
timely.hsts.max.age=608400
+55
View File
@@ -0,0 +1,55 @@
timely:
metrics-table: timely.metrics
meta-table: timely.meta
metric-age-off-days: 7
metrics-report-ignored-tags:
accumulo:
instance-name: TimelyStandalone
zookeepers: 127.0.0.1:9804
username: root
password: secret
write:
latency: 5s
threads: 3
bufferSize: 52428800
scan:
threads: 4
security:
session-max-age: 86400
allow-anonymous-access: true
ssl:
certificate-file:
key-file:
key-password: timely
use-generated-keypair: true
trust-store-file:
use-openssl: false
server:
ip: 0.0.0.0
tcp-port: 54321
http:
ip: 0.0.0.0
port: 54322
host: localhost
redirect-path: /secure-me
strict-transport-max-age: 608400
cors:
allow-any-origin: true
allow-null-origin: false
allow-credentials: true
allowed-origins:
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
allowed-header: content-type
websocket:
ip: 0.0.0.0
port: 54323
timeout: 60
subscription-lag: 120
meta-cache:
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
visibility-cache:
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
-38
View File
@@ -1,38 +0,0 @@
timely.ip=
timely.port.put=
timely.port.query=
timely.port.websocket=
timely.instance_name=
timely.zookeepers=
timely.username=
timely.password=
timely.table=timely.metrics
timely.meta=timely.meta
timely.write.latency=5s
timely.write.threads=3
timely.write.buffer.size=52428800
timely.metric.age.off.days=7
timely.cors.allow.any.origin=false
timely.cors.allow.null.origin=false
timely.cors.allowed.origins=
timely.cors.allowed.methods=DELETE,GET,HEAD,OPTIONS,PUT,POST
timely.cors.allowed.headers=content-type
timely.cors.allow.credentials=true
timely.scanner.threads=4
timely.metrics.report.tags.ignored=
timely.meta.cache.expiration.minutes=60
timely.meta.cache.initial.capacity=2000
timely.meta.cache.max.capacity=10000
timely.ssl.certificate.file=
timely.ssl.key.file=
timely.ssl.key.pass=
timely.ssl.use.generated.keypair=false
timely.ssl.trust.store.file=
timely.ssl.use.openssl=true
timely.ssl.use.ciphers=
timely.session.max.age=86400
timely.http.host=
timely.allow.anonymous.access=false
timely.web.socket.timeout=60
timely.ws.subscription.lag=120
timely.hsts.max.age=608400
+56
View File
@@ -0,0 +1,56 @@
timely:
metrics-table: timely.metrics
meta-table: timely.meta
metric-age-off-days: 7
metrics-report-ignored-tags:
accumulo:
instance-name:
zookeepers:
username:
password:
write:
latency: 5s
threads: 3
bufferSize: 52428800
scan:
threads: 4
security:
session-max-age: 86400
allow-anonymous-access: false
ssl:
certificate-file:
key-file:
key-password:
use-generated-keypair: false
trust-store-file:
use-openssl: true
#use-ciphers:
server:
ip:
tcp-port:
http:
host:
ip:
port:
redirect-path: /secure-me
strict-transport-max-age: 608400
cors:
allow-any-origin: false
allow-null-origin: false
allow-credentials: true
allowed-origins:
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
allowed-headers: content-type
websocket:
ip:
port:
timeout: 60
subscription-lag: 120
meta-cache:
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
visibility-cache:
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
-1
View File
@@ -7,7 +7,6 @@ services:
- "9804:9804" # standalone zookeeper
- "54321:54321" # timely put
- "54322:54322" # timely query
- "54323:54323" # timely ws
volumes:
- ${PWD}/:/timely-server-src
command: /timely-server-src/bin/docker/deploy-startup-standalone.sh
+43 -3
View File
@@ -32,6 +32,10 @@
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
@@ -52,6 +56,12 @@
<classifier>${os.detected.classifier}</classifier>
<!-- Eclipse doesn't like this, but it works on the cmd line -->
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>${version.netty-tcnative}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -113,6 +123,29 @@
<artifactId>javassist</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
@@ -125,6 +158,14 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ws.wamp.jawampa</groupId>
<artifactId>jawampa-core</artifactId>
</dependency>
<dependency>
<groupId>ws.wamp.jawampa</groupId>
<artifactId>jawampa-netty</artifactId>
</dependency>
</dependencies>
<build>
<extensions>
@@ -197,7 +238,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.dir}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<includes>
<include>**/*.java</include>
</includes>
@@ -245,7 +286,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.dir}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
@@ -390,7 +431,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>${version.maven-pmd}</version>
<configuration>
<targetJdk>1.8</targetJdk>
</configuration>
+580 -169
View File
@@ -1,196 +1,607 @@
package timely;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import com.google.common.collect.Lists;
import org.apache.accumulo.core.client.BatchWriterConfig;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.stereotype.Component;
import timely.validator.NotEmptyIfFieldSet;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Component
@ConfigurationProperties(prefix = "timely")
public class Configuration {
public static final String IP = "timely.ip";
public static final String PUT_PORT = "timely.port.put";
public static final String QUERY_PORT = "timely.port.query";
public static final String WEBSOCKET_PORT = "timely.port.websocket";
public static final String ZOOKEEPERS = "timely.zookeepers";
public static final String INSTANCE_NAME = "timely.instance_name";
public static final String USERNAME = "timely.username";
public static final String PASSWORD = "timely.password";
public static final String METRICS_TABLE = "timely.table";
private static final String METRICS_TABLE_DEFAULT = "timely.metrics";
public static final String META_TABLE = "timely.meta";
private static final String META_TABLE_DEFAULT = "timely.meta";
public static final String METRICS_AGEOFF_DAYS = "timely.metric.age.off.days";
private static final String METRICS_AGEOFF_DAYS_DEFAULT = "7";
private String metricsTable = "timely.metrics";
private String metaTable = "timely.meta";
private int metricAgeOffDays = 7;
private List<String> metricsReportIgnoredTags = new ArrayList<>();
public static final String MAX_LATENCY = "timely.write.latency";
private static final String MAX_LATENCY_DEFAULT = "5s";
public static final String WRITE_THREADS = "timely.write.threads";
public static final String WRITE_BUFFER_SIZE = "timely.write.buffer.size";
public static final String SCANNER_THREADS = "timely.scanner.threads";
public static final String CORS_ALLOW_ANY_ORIGIN = "timely.cors.allow.any.origin";
private static final String CORS_ALLOW_ANY_ORIGIN_DEFAULT = "false";
public static final String CORS_ALLOW_NULL_ORIGIN = "timely.cors.allow.null.origin";
private static final String CORS_ALLOW_NULL_ORIGIN_DEFAULT = "false";
public static final String CORS_ALLOWED_ORIGINS = "timely.cors.allowed.origins";
private static final String CORS_ALLOWED_ORIGINS_DEFAULT = "";
public static final String CORS_ALLOWED_METHODS = "timely.cors.allowed.methods";
private static final String CORS_ALLOWED_METHODS_DEFAULT = "DELETE,GET,HEAD,OPTIONS,PUT,POST";
public static final String CORS_ALLOWED_HEADERS = "timely.cors.allowed.headers";
private static final String CORS_ALLOWED_HEADERS_DEFAULT = "content-type";
public static final String CORS_ALLOW_CREDENTIALS = "timely.cors.allow.credentials";
private static final String CORS_ALLOW_CREDENTIALS_DEFAULT = "true";
public static final String METRICS_IGNORED_TAGS = "timely.metrics.report.tags.ignored";
public static final String META_CACHE_EXPIRATION = "timely.meta.cache.expiration.minutes";
public static final Long META_CACHE_EXPIRATION_DEFAULT = 60L;
public static final String META_CACHE_INITIAL_CAPACITY = "timely.meta.cache.initial.capacity";
public static final Integer META_CACHE_INITIAL_CAPACITY_DEFAULT = 2000;
public static final String META_CACHE_MAX_CAPACITY = "timely.meta.cache.max.capacity";
public static final Integer META_CACHE_MAX_CAPACITY_DEFAULT = 10000;
public static final String VISIBILITY_CACHE_EXPIRATION = "timely.visibility.cache.expiration.minutes";
public static final Long VISIBILITY_EXPIRATION_DEFAULT = 60L;
public static final String VISIBILITY_CACHE_INITIAL_CAPACITY = "timely.visibility.cache.initial.capacity";
public static final Integer VISIBILITY_CACHE_INITIAL_CAPACITY_DEFAULT = 2000;
public static final String VISIBILITY_CACHE_MAX_CAPACITY = "timely.visibility.cache.max.capacity";
public static final Integer VISIBILITY_CACHE_MAX_CAPACITY_DEFAULT = 10000;
/** Security properties */
public static final String SSL_CERTIFICATE_FILE = "timely.ssl.certificate.file";
public static final String SSL_PRIVATE_KEY_FILE = "timely.ssl.key.file";
public static final String SSL_PRIVATE_KEY_PASS = "timely.ssl.key.pass";
public static final String SSL_USE_GENERATED_KEYPAIR = "timely.ssl.use.generated.keypair";
private static final String SSL_USE_GENERATED_KEYPAIR_DEFAULT = "false";
public static final String SSL_TRUST_STORE_FILE = "timely.ssl.trust.store.file";
public static final String SSL_USE_OPENSSL = "timely.ssl.use.openssl";
private static final String SSL_USE_OPENSSL_DEFAULT = "true";
public static final String SSL_USE_CIPHERS = "timely.ssl.use.ciphers";
private static final String SSL_USE_CIPHERS_DEFAULT = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:"
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:"
+ "TLS_RSA_WITH_AES_128_CBC_SHA:SSL_RSA_WITH_3DES_EDE_CBC_SHA";
public static final String SESSION_MAX_AGE = "timely.session.max.age";
public static final long SESSION_MAX_AGE_DEFAULT = 86400;
public static final String TIMELY_HTTP_HOST = "timely.http.host";
public static final String ALLOW_ANONYMOUS_ACCESS = "timely.allow.anonymous.access";
private static final String ALLOW_ANONYMOUS_ACCESS_DEFAULT = "false";
public static final String WS_TIMEOUT_SECONDS = "timely.web.socket.timeout";
private static final String WS_TIMEOUT_SECONDS_DEFAULT = "60";
public static final String WS_SUBSCRIPTION_LAG = "timely.ws.subscription.lag";
private static final String WS_SUBSCRIPTION_LAG_DEFAULT = "120";
public static final String NON_SECURE_REDIRECT_PATH = "timely.http.redirect.path";
private static final String NON_SECURE_REDIRECT_PATH_DEFAULT = "/secure-me";
public static final String STRICT_TRANSPORT_MAX_AGE = "timely.hsts.max.age";
private static final String STRICT_TRANSPORT_MAX_AGE_DEFAULT = "604800";
private static final List<String> REQUIRED_PROPERTIES = new ArrayList<>();
static {
REQUIRED_PROPERTIES.add(IP);
REQUIRED_PROPERTIES.add(PUT_PORT);
REQUIRED_PROPERTIES.add(QUERY_PORT);
REQUIRED_PROPERTIES.add(WEBSOCKET_PORT);
REQUIRED_PROPERTIES.add(ZOOKEEPERS);
REQUIRED_PROPERTIES.add(INSTANCE_NAME);
REQUIRED_PROPERTIES.add(USERNAME);
REQUIRED_PROPERTIES.add(PASSWORD);
REQUIRED_PROPERTIES.add(TIMELY_HTTP_HOST);
};
private final Properties props = new Properties();
public Configuration(Path path) throws IOException {
org.apache.hadoop.conf.Configuration hadoopConf = new org.apache.hadoop.conf.Configuration();
try (FileSystem fs = FileSystem.get(hadoopConf)) {
try (InputStream inputStream = fs.open(path)) {
init(inputStream);
}
}
@Valid
@NestedConfigurationProperty
private Accumulo accumulo = new Accumulo();
@Valid
@NestedConfigurationProperty
private Security security = new Security();
@Valid
@NestedConfigurationProperty
private Server server = new Server();
@Valid
@NestedConfigurationProperty
private Http http = new Http();
@Valid
@NestedConfigurationProperty
private MetaCache metaCache = new MetaCache();
@Valid
@NestedConfigurationProperty
private VisibilityCache visibilityCache = new VisibilityCache();
@Valid
@NestedConfigurationProperty
private Websocket websocket = new Websocket();
public String getMetricsTable() {
return metricsTable;
}
public Configuration(File conf) throws IOException {
try (InputStream inputStream = new FileInputStream(conf)) {
init(inputStream);
public Configuration setMetricsTable(String metricsTable) {
this.metricsTable = metricsTable;
return this;
}
public String getMetaTable() {
return metaTable;
}
public Configuration setMetaTable(String metaTable) {
this.metaTable = metaTable;
return this;
}
public int getMetricAgeOffDays() {
return metricAgeOffDays;
}
public Configuration setMetricAgeOffDays(int metricAgeOffDays) {
this.metricAgeOffDays = metricAgeOffDays;
return this;
}
public List<String> getMetricsReportIgnoredTags() {
return metricsReportIgnoredTags;
}
public Configuration setMetricsReportIgnoredTags(List<String> metricsReportIgnoredTags) {
this.metricsReportIgnoredTags = metricsReportIgnoredTags;
return this;
}
public Accumulo getAccumulo() {
return accumulo;
}
public Security getSecurity() {
return security;
}
public Server getServer() {
return server;
}
public Http getHttp() {
return http;
}
public Websocket getWebsocket() {
return websocket;
}
public MetaCache getMetaCache() {
return metaCache;
}
public VisibilityCache getVisibilityCache() {
return visibilityCache;
}
public class Accumulo {
@NotBlank
private String zookeepers;
@NotBlank
private String instanceName;
@NotBlank
private String username;
@NotBlank
private String password;
@Valid
@NestedConfigurationProperty
private Write write = new Write();
@Valid
@NestedConfigurationProperty
private Scan scan = new Scan();
public String getInstanceName() {
return instanceName;
}
public String getZookeepers() {
return zookeepers;
}
public Configuration setZookeepers(String zookeepers) {
this.zookeepers = zookeepers;
return Configuration.this;
}
public Write getWrite() {
return write;
}
public Scan getScan() {
return scan;
}
public Configuration setInstanceName(String instanceName) {
this.instanceName = instanceName;
return Configuration.this;
}
public String getUsername() {
return username;
}
public Configuration setUsername(String username) {
this.username = username;
return Configuration.this;
}
public String getPassword() {
return password;
}
public Configuration setPassword(String password) {
this.password = password;
return Configuration.this;
}
}
private void init(InputStream configStream) throws IOException {
// Add defaults
props.setProperty(METRICS_TABLE, METRICS_TABLE_DEFAULT);
props.setProperty(META_TABLE, META_TABLE_DEFAULT);
props.setProperty(MAX_LATENCY, MAX_LATENCY_DEFAULT);
props.setProperty(METRICS_AGEOFF_DAYS, METRICS_AGEOFF_DAYS_DEFAULT);
final BatchWriterConfig defaults = new BatchWriterConfig();
props.setProperty(WRITE_BUFFER_SIZE, "" + defaults.getMaxMemory());
props.setProperty(WRITE_THREADS, "" + defaults.getMaxWriteThreads());
props.setProperty(SCANNER_THREADS, "" + 4);
props.setProperty(CORS_ALLOW_ANY_ORIGIN, CORS_ALLOW_ANY_ORIGIN_DEFAULT);
props.setProperty(CORS_ALLOW_NULL_ORIGIN, CORS_ALLOW_NULL_ORIGIN_DEFAULT);
props.setProperty(CORS_ALLOWED_ORIGINS, CORS_ALLOWED_ORIGINS_DEFAULT);
props.setProperty(CORS_ALLOWED_METHODS, CORS_ALLOWED_METHODS_DEFAULT);
props.setProperty(CORS_ALLOWED_HEADERS, CORS_ALLOWED_HEADERS_DEFAULT);
props.setProperty(CORS_ALLOW_CREDENTIALS, CORS_ALLOW_CREDENTIALS_DEFAULT);
props.setProperty(META_CACHE_EXPIRATION, "" + META_CACHE_EXPIRATION_DEFAULT);
props.setProperty(META_CACHE_INITIAL_CAPACITY, "" + META_CACHE_INITIAL_CAPACITY_DEFAULT);
props.setProperty(META_CACHE_MAX_CAPACITY, "" + META_CACHE_MAX_CAPACITY_DEFAULT);
props.setProperty(SSL_USE_GENERATED_KEYPAIR, SSL_USE_GENERATED_KEYPAIR_DEFAULT);
props.setProperty(SSL_USE_OPENSSL, SSL_USE_OPENSSL_DEFAULT);
props.setProperty(SSL_USE_CIPHERS, SSL_USE_CIPHERS_DEFAULT);
props.setProperty(ALLOW_ANONYMOUS_ACCESS, ALLOW_ANONYMOUS_ACCESS_DEFAULT);
props.setProperty(SESSION_MAX_AGE, SESSION_MAX_AGE_DEFAULT + "");
public class Write {
props.setProperty(VISIBILITY_CACHE_EXPIRATION, VISIBILITY_EXPIRATION_DEFAULT + "");
props.setProperty(VISIBILITY_CACHE_INITIAL_CAPACITY, VISIBILITY_CACHE_INITIAL_CAPACITY_DEFAULT + "");
props.setProperty(VISIBILITY_CACHE_MAX_CAPACITY, VISIBILITY_CACHE_MAX_CAPACITY_DEFAULT + "");
private String latency = "5s";
private int threads;
private String bufferSize;
props.setProperty(WS_TIMEOUT_SECONDS, WS_TIMEOUT_SECONDS_DEFAULT);
props.setProperty(WS_SUBSCRIPTION_LAG, WS_SUBSCRIPTION_LAG_DEFAULT);
public Write() {
BatchWriterConfig config = new BatchWriterConfig();
threads = config.getMaxWriteThreads();
bufferSize = Long.toString(config.getMaxMemory());
}
props.setProperty(NON_SECURE_REDIRECT_PATH, NON_SECURE_REDIRECT_PATH_DEFAULT);
props.setProperty(STRICT_TRANSPORT_MAX_AGE, STRICT_TRANSPORT_MAX_AGE_DEFAULT);
public String getLatency() {
return latency;
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(configStream, StandardCharsets.UTF_8))) {
props.load(reader);
validate();
public Configuration setLatency(String latency) {
this.latency = latency;
return Configuration.this;
}
public int getThreads() {
return threads;
}
public Configuration setThreads(int threads) {
this.threads = threads;
return Configuration.this;
}
public String getBufferSize() {
return bufferSize;
}
public Configuration setBufferSize(String bufferSize) {
this.bufferSize = bufferSize;
return Configuration.this;
}
}
protected void validate() {
REQUIRED_PROPERTIES.forEach(p -> {
if (!props.containsKey(p) || StringUtils.isEmpty(props.getProperty(p))) {
throw new IllegalArgumentException("Required property " + p + " must be specified.");
}
});
if (!getBoolean(Configuration.SSL_USE_GENERATED_KEYPAIR)) {
if (StringUtils.isEmpty(get(Configuration.SSL_CERTIFICATE_FILE))) {
throw new IllegalArgumentException(Configuration.SSL_CERTIFICATE_FILE + "must be specified.");
}
if (StringUtils.isEmpty(get(Configuration.SSL_PRIVATE_KEY_FILE))) {
throw new IllegalArgumentException(Configuration.SSL_PRIVATE_KEY_FILE + "must be specified.");
}
public class Scan {
private int threads = 4;
public int getThreads() {
return threads;
}
public Configuration setThreads(int threads) {
this.threads = threads;
return Configuration.this;
}
}
public String get(String property) {
return props.getProperty(property);
public class Security {
private boolean allowAnonymousAccess = false;
private int sessionMaxAge = 86400;
@Valid
@NestedConfigurationProperty
private Ssl ssl = new Ssl();
public boolean isAllowAnonymousAccess() {
return allowAnonymousAccess;
}
public Configuration setAllowAnonymousAccess(boolean allowAnonymousAccess) {
this.allowAnonymousAccess = allowAnonymousAccess;
return Configuration.this;
}
public int getSessionMaxAge() {
return sessionMaxAge;
}
public Configuration setSessionMaxAge(int sessionMaxAge) {
this.sessionMaxAge = sessionMaxAge;
return Configuration.this;
}
public Ssl getSsl() {
return ssl;
}
}
public boolean getBoolean(String property) {
return Boolean.parseBoolean(get(property));
@NotEmptyIfFieldSet.List({
@NotEmptyIfFieldSet(fieldName = "useGeneratedKeypair", fieldValue = "false", notNullFieldName = "certificateFile", message = "must be set if timely.security.ssl.use-generated-keypair is false"),
@NotEmptyIfFieldSet(fieldName = "useGeneratedKeypair", fieldValue = "false", notNullFieldName = "keyFile", message = "must be set if timely.security.ssl.use-generated-keypair is false") })
public class Ssl {
private String certificateFile;
private String keyFile;
private String keyPassword;
private String trustStoreFile;
private boolean useGeneratedKeypair = false;
private boolean useOpenssl = true;
private List<String> useCiphers = Lists.newArrayList("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA");
public String getCertificateFile() {
return certificateFile;
}
public Configuration setCertificateFile(String certificateFile) {
this.certificateFile = certificateFile;
return Configuration.this;
}
public String getKeyFile() {
return keyFile;
}
public Configuration setKeyFile(String keyFile) {
this.keyFile = keyFile;
return Configuration.this;
}
public String getKeyPassword() {
return keyPassword;
}
public Configuration setKeyPassword(String keyPassword) {
this.keyPassword = keyPassword;
return Configuration.this;
}
public String getTrustStoreFile() {
return trustStoreFile;
}
public Configuration setTrustStoreFile(String trustStoreFile) {
this.trustStoreFile = trustStoreFile;
return Configuration.this;
}
public boolean isUseGeneratedKeypair() {
return useGeneratedKeypair;
}
public Configuration setUseGeneratedKeypair(boolean useGeneratedKeypair) {
this.useGeneratedKeypair = useGeneratedKeypair;
return Configuration.this;
}
public boolean isUseOpenssl() {
return useOpenssl;
}
public Configuration setUseOpenssl(boolean useOpenssl) {
this.useOpenssl = useOpenssl;
return Configuration.this;
}
public List<String> getUseCiphers() {
return useCiphers;
}
public Configuration setUseCiphers(List<String> useCiphers) {
this.useCiphers = useCiphers;
return Configuration.this;
}
}
public class Server {
@NotBlank
private String ip;
@NotNull
private Integer tcpPort;
@NotNull
public String getIp() {
return ip;
}
public Configuration setIp(String ip) {
this.ip = ip;
return Configuration.this;
}
public int getTcpPort() {
return tcpPort;
}
public Configuration setTcpPort(int tcpPort) {
this.tcpPort = tcpPort;
return Configuration.this;
}
}
public class Http {
@NotBlank
private String ip;
@NotNull
private Integer port;
@NotNull
private String host;
private String redirectPath = "/secure-me";
private long strictTransportMaxAge = 604800;
@Valid
@NestedConfigurationProperty
private Cors cors = new Cors();
public String getIp() {
return ip;
}
public Configuration setIp(String ip) {
this.ip = ip;
return Configuration.this;
}
public int getPort() {
return port;
}
public Configuration setPort(int port) {
this.port = port;
return Configuration.this;
}
public String getHost() {
return host;
}
public Configuration setHost(String host) {
this.host = host;
return Configuration.this;
}
public String getRedirectPath() {
return redirectPath;
}
public Configuration setRedirectPath(String redirectPath) {
this.redirectPath = redirectPath;
return Configuration.this;
}
public long getStrictTransportMaxAge() {
return strictTransportMaxAge;
}
public Configuration setStrictTransportMaxAge(long strictTransportMaxAge) {
this.strictTransportMaxAge = strictTransportMaxAge;
return Configuration.this;
}
public Cors getCors() {
return cors;
}
}
public class Cors {
private boolean allowAnyOrigin = false;
private boolean allowNullOrigin = false;
private Set<String> allowedOrigins = new HashSet<>();
private List<String> allowedMethods = Lists.newArrayList("DELETE", "GET", "HEAD", "OPTIONS", "PUT", "POST");
private List<String> allowedHeaders = Lists.newArrayList("content-type");
private boolean allowCredentials = true;
public boolean isAllowAnyOrigin() {
return allowAnyOrigin;
}
public Configuration setAllowAnyOrigin(boolean allowAnyOrigin) {
this.allowAnyOrigin = allowAnyOrigin;
return Configuration.this;
}
public boolean isAllowNullOrigin() {
return allowNullOrigin;
}
public Configuration setAllowNullOrigin(boolean allowNullOrigin) {
this.allowNullOrigin = allowNullOrigin;
return Configuration.this;
}
public Set<String> getAllowedOrigins() {
return allowedOrigins;
}
public Configuration setAllowedOrigins(Set<String> allowedOrigins) {
this.allowedOrigins = allowedOrigins;
return Configuration.this;
}
public List<String> getAllowedMethods() {
return allowedMethods;
}
public Configuration setAllowedMethods(List<String> allowedMethods) {
this.allowedMethods = allowedMethods;
return Configuration.this;
}
public List<String> getAllowedHeaders() {
return allowedHeaders;
}
public Configuration setAllowedHeaders(List<String> allowedHeaders) {
this.allowedHeaders = allowedHeaders;
return Configuration.this;
}
public boolean isAllowCredentials() {
return allowCredentials;
}
public Configuration setAllowCredentials(boolean allowCredentials) {
this.allowCredentials = allowCredentials;
return Configuration.this;
}
}
public class Websocket {
@NotBlank
private String ip;
@NotNull
private Integer port;
public int timeout = 60;
public int subscriptionLag = 120;
public String getIp() {
return ip;
}
public Configuration setIp(String ip) {
this.ip = ip;
return Configuration.this;
}
public int getPort() {
return port;
}
public Configuration setPort(int port) {
this.port = port;
return Configuration.this;
}
public int getTimeout() {
return timeout;
}
public Configuration setTimeout(int timeout) {
this.timeout = timeout;
return Configuration.this;
}
public int getSubscriptionLag() {
return subscriptionLag;
}
public Configuration setSubscriptionLag(int subscriptionLag) {
this.subscriptionLag = subscriptionLag;
return Configuration.this;
}
}
public class MetaCache {
private long expirationMinutes = 60;
private int initialCapacity = 2000;
private long maxCapacity = 10000;
public long getExpirationMinutes() {
return expirationMinutes;
}
public Configuration setExpirationMinutes(long expirationMinutes) {
this.expirationMinutes = expirationMinutes;
return Configuration.this;
}
public int getInitialCapacity() {
return initialCapacity;
}
public Configuration setInitialCapacity(int initialCapacity) {
this.initialCapacity = initialCapacity;
return Configuration.this;
}
public long getMaxCapacity() {
return maxCapacity;
}
public Configuration setMaxCapacity(long maxCapacity) {
this.maxCapacity = maxCapacity;
return Configuration.this;
}
}
public class VisibilityCache {
private long expirationMinutes = 60;
private int initialCapacity = 2000;
private long maxCapacity = 10000;
public long getExpirationMinutes() {
return expirationMinutes;
}
public Configuration setExpirationMinutes(long expirationMinutes) {
this.expirationMinutes = expirationMinutes;
return Configuration.this;
}
public int getInitialCapacity() {
return initialCapacity;
}
public Configuration setInitialCapacity(int initialCapacity) {
this.initialCapacity = initialCapacity;
return Configuration.this;
}
public long getMaxCapacity() {
return maxCapacity;
}
public Configuration setMaxCapacity(long maxCapacity) {
this.maxCapacity = maxCapacity;
return Configuration.this;
}
}
}
+96 -61
View File
@@ -40,14 +40,16 @@ import io.netty.util.internal.SystemPropertyUtil;
import java.io.File;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import timely.api.response.TimelyException;
import timely.auth.AuthCache;
import timely.auth.VisibilityCache;
@@ -83,6 +85,13 @@ import timely.netty.websocket.timeseries.WSSuggestRequestHandler;
import timely.store.DataStore;
import timely.store.DataStoreFactory;
import timely.store.MetaCacheFactory;
import timely.wamp.StateObserver;
import timely.wamp.VersionObserver;
import ws.wamp.jawampa.*;
import ws.wamp.jawampa.connection.IWampConnectorProvider;
import ws.wamp.jawampa.transport.netty.NettyWampClientConnectorProvider;
import ws.wamp.jawampa.transport.netty.NettyWampConnectionConfig;
import ws.wamp.jawampa.transport.netty.WampServerWebsocketHandler;
public class Server {
@@ -93,10 +102,12 @@ public class Server {
private static final String OS_NAME = "os.name";
private static final String OS_VERSION = "os.version";
private static final String WS_PATH = "/websocket";
private static final String WAMP_PATH = "/wamp";
protected static final CountDownLatch LATCH = new CountDownLatch(1);
static ConfigurableApplicationContext applicationContext;
private Configuration config = null;
private final Configuration config;
private EventLoopGroup tcpWorkerGroup = null;
private EventLoopGroup tcpBossGroup = null;
private EventLoopGroup httpWorkerGroup = null;
@@ -108,6 +119,8 @@ public class Server {
protected Channel wsChannelHandle = null;
protected DataStore dataStore = null;
protected volatile boolean shutdown = false;
private WampRouter wampRouter = null;
private WampClient wampClient;
private static boolean useEpoll() {
@@ -126,11 +139,7 @@ public class Server {
return true;
} else if (minor == EPOLL_MIN_MINOR_VERSION) {
final int patch = Integer.parseInt(version[2].substring(0, 2));
if (patch >= EPOLL_MIN_PATCH_VERSION) {
return true;
} else {
return false;
}
return patch >= EPOLL_MIN_PATCH_VERSION;
} else {
return false;
}
@@ -142,11 +151,6 @@ public class Server {
}
}
private static String usage() {
return "Server <configFile>";
}
public static void fatal(String msg, Throwable t) {
LOG.error(msg, t);
LATCH.countDown();
@@ -154,13 +158,8 @@ public class Server {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println(usage());
}
final File conf = new File(args[0]);
if (!conf.canRead()) {
throw new RuntimeException("Configuration file does not exist or cannot be read");
}
Configuration conf = initializeConfiguration(args);
Server s = new Server(conf);
try {
LATCH.await();
@@ -171,15 +170,16 @@ public class Server {
}
}
protected static Configuration initializeConfiguration(String[] args) {
applicationContext = new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(args);
return applicationContext.getBean(Configuration.class);
}
private void shutdownHook() {
final Runnable shutdownRunner = new Runnable() {
@Override
public void run() {
if (!shutdown) {
shutdown();
}
final Runnable shutdownRunner = () -> {
if (!shutdown) {
shutdown();
}
};
final Thread hook = new Thread(shutdownRunner, "shutdown-hook-thread");
@@ -237,15 +237,23 @@ public class Server {
} catch (TimelyException e) {
LOG.error("Error flushing to server during shutdown", e);
}
LOG.info("Shutting down WAMP Router");
wampClient.close().toBlocking().last();
wampRouter.close().toBlocking().last(); // Blocks until router is fully
// shut down
MetaCacheFactory.close();
WebSocketRequestDecoder.close();
if (applicationContext != null) {
applicationContext.close();
}
this.shutdown = true;
LOG.info("Server shut down.");
}
public Server(File conf) throws Exception {
public Server(Configuration conf) throws Exception {
this.config = conf;
config = new Configuration(conf);
int nettyThreads = Math.max(1,
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
dataStore = DataStoreFactory.create(config, nettyThreads);
@@ -256,7 +264,7 @@ public class Server {
// Initialize the VisibilityCache
VisibilityCache.init(config);
final boolean useEpoll = useEpoll();
Class<? extends ServerSocketChannel> channelClass = null;
Class<? extends ServerSocketChannel> channelClass;
if (useEpoll) {
tcpWorkerGroup = new EpollEventLoopGroup();
tcpBossGroup = new EpollEventLoopGroup();
@@ -284,11 +292,11 @@ public class Server {
putServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
putServer.option(ChannelOption.SO_BACKLOG, 128);
putServer.option(ChannelOption.SO_KEEPALIVE, true);
final int putPort = Integer.parseInt(config.get(Configuration.PUT_PORT));
final int putPort = config.getServer().getTcpPort();
putChannelHandle = putServer.bind(putPort).sync().channel();
final String putAddress = ((InetSocketAddress) putChannelHandle.localAddress()).getAddress().getHostAddress();
final int queryPort = Integer.parseInt(config.get(Configuration.QUERY_PORT));
final int queryPort = config.getHttp().getPort();
SslContext sslCtx = createSSLContext(config);
if (sslCtx instanceof OpenSslServerContext) {
OpenSslServerContext openssl = (OpenSslServerContext) sslCtx;
@@ -297,7 +305,7 @@ public class Server {
opensslCtx.setSessionCacheEnabled(true);
opensslCtx.setSessionCacheSize(128);
opensslCtx.setSessionIdContext(application.getBytes(StandardCharsets.UTF_8));
opensslCtx.setSessionTimeout(Integer.parseInt(config.get(Configuration.SESSION_MAX_AGE)));
opensslCtx.setSessionTimeout(config.getSecurity().getSessionMaxAge());
}
final ServerBootstrap queryServer = new ServerBootstrap();
queryServer.group(httpBossGroup, httpWorkerGroup);
@@ -311,8 +319,9 @@ public class Server {
final String queryAddress = ((InetSocketAddress) queryChannelHandle.localAddress()).getAddress()
.getHostAddress();
final int wsPort = Integer.parseInt(config.get(Configuration.WEBSOCKET_PORT));
final int wsPort = config.getWebsocket().getPort();
final ServerBootstrap wsServer = new ServerBootstrap();
setupWampRouter();
wsServer.group(wsBossGroup, wsWorkerGroup);
wsServer.channel(channelClass);
wsServer.handler(new LoggingHandler());
@@ -324,6 +333,9 @@ public class Server {
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
shutdownHook();
setupWampClient(wsAddress, wsPort);
LOG.info(
"Server started. Listening on {}:{} for TCP traffic, {}:{} for HTTP traffic, and {}:{} for WebSocket traffic",
putAddress, putPort, queryAddress, queryPort, wsAddress, wsPort);
@@ -331,8 +343,9 @@ public class Server {
protected SslContext createSSLContext(Configuration config) throws Exception {
Boolean generate = config.getBoolean(Configuration.SSL_USE_GENERATED_KEYPAIR);
SslContextBuilder ssl = null;
Configuration.Ssl sslCfg = config.getSecurity().getSsl();
Boolean generate = sslCfg.isUseGeneratedKeypair();
SslContextBuilder ssl;
if (generate) {
LOG.warn("Using generated self signed server certificate");
Date begin = new Date();
@@ -340,28 +353,27 @@ public class Server {
SelfSignedCertificate ssc = new SelfSignedCertificate("localhost", begin, end);
ssl = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey());
} else {
String cert = config.get(Configuration.SSL_CERTIFICATE_FILE);
String key = config.get(Configuration.SSL_PRIVATE_KEY_FILE);
String keyPass = config.get(Configuration.SSL_PRIVATE_KEY_PASS);
String cert = sslCfg.getCertificateFile();
String key = sslCfg.getKeyFile();
String keyPass = sslCfg.getKeyPassword();
if (null == cert || null == key) {
throw new IllegalArgumentException("Check your SSL properties, something is wrong.");
}
ssl = SslContextBuilder.forServer(new File(cert), new File(key), keyPass);
}
String ciphers = config.get(Configuration.SSL_USE_CIPHERS);
ssl.ciphers(Arrays.asList(ciphers.split(":")));
ssl.ciphers(sslCfg.getUseCiphers());
// Can't set to REQUIRE because the CORS pre-flight requests will fail.
ssl.clientAuth(ClientAuth.OPTIONAL);
Boolean useOpenSSL = config.getBoolean(Configuration.SSL_USE_OPENSSL);
Boolean useOpenSSL = sslCfg.isUseOpenssl();
if (useOpenSSL) {
ssl.sslProvider(SslProvider.OPENSSL);
} else {
ssl.sslProvider(SslProvider.JDK);
}
String trustStore = config.get(Configuration.SSL_TRUST_STORE_FILE);
String trustStore = sslCfg.getTrustStoreFile();
if (null != trustStore) {
if (!trustStore.isEmpty()) {
ssl.trustManager(new File(trustStore));
@@ -385,30 +397,21 @@ public class Server {
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
final Configuration.Cors corsCfg = config.getHttp().getCors();
final CorsConfig.Builder ccb;
if (config.getBoolean(Configuration.CORS_ALLOW_ANY_ORIGIN)) {
if (corsCfg.isAllowAnyOrigin()) {
ccb = new CorsConfig.Builder();
} else {
String origins = config.get(Configuration.CORS_ALLOWED_ORIGINS);
ccb = new CorsConfig.Builder(origins.split(","));
ccb = new CorsConfig.Builder(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
}
if (config.getBoolean(Configuration.CORS_ALLOW_NULL_ORIGIN)) {
if (corsCfg.isAllowNullOrigin()) {
ccb.allowNullOrigin();
}
if (config.getBoolean(Configuration.CORS_ALLOW_CREDENTIALS)) {
if (corsCfg.isAllowCredentials()) {
ccb.allowCredentials();
}
if (!StringUtils.isEmpty(config.get(Configuration.CORS_ALLOWED_METHODS))) {
String[] methods = config.get(Configuration.CORS_ALLOWED_METHODS).split(",");
HttpMethod[] m = new HttpMethod[methods.length];
for (int i = 0; i < methods.length; i++) {
m[i] = HttpMethod.valueOf(methods[i]);
}
ccb.allowedRequestMethods(m);
}
if (!StringUtils.isEmpty(config.get(Configuration.CORS_ALLOWED_HEADERS))) {
ccb.allowedRequestHeaders(config.get(Configuration.CORS_ALLOWED_HEADERS).split(","));
}
corsCfg.getAllowedMethods().stream().map(HttpMethod::valueOf).forEach(ccb::allowedRequestMethods);
corsCfg.getAllowedHeaders().forEach(ccb::allowedRequestHeaders);
CorsConfig cors = ccb.build();
LOG.trace("Cors configuration: {}", cors);
ch.pipeline().addLast("cors", new CorsHandler(cors));
@@ -448,11 +451,11 @@ public class Server {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast("wamp", new WampServerWebsocketHandler(WAMP_PATH, wampRouter));
ch.pipeline().addLast("httpServer", new HttpServerCodec());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("sessionExtractor", new WebSocketHttpCookieHandler(config));
ch.pipeline().addLast("idle-handler",
new IdleStateHandler(Integer.parseInt(conf.get(Configuration.WS_TIMEOUT_SECONDS)), 0, 0));
ch.pipeline().addLast("idle-handler", new IdleStateHandler(conf.getWebsocket().getTimeout(), 0, 0));
ch.pipeline().addLast("ws-protocol", new WebSocketServerProtocolHandler(WS_PATH, null, true));
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(config));
ch.pipeline().addLast("aggregators", new WSAggregatorsRequestHandler());
@@ -472,4 +475,36 @@ public class Server {
}
protected void setupWampRouter() throws ApplicationError {
wampRouter = new WampRouterBuilder().addRealm("default").build();
}
protected void setupWampClient(String wsAddress, int wsPort) throws Exception {
IWampConnectorProvider connectorProvider = new NettyWampClientConnectorProvider();
NettyWampConnectionConfig connectionConfiguration = new NettyWampConnectionConfig.Builder()
.withSslContext(SslContextBuilder.forClient().build())
.build();
// Create a builder and configure the client
WampClientBuilder builder = new WampClientBuilder();
String wampUri = String.format("wss://0.0.0.0:%d%s", wsPort, WAMP_PATH);
System.out.println(wampUri);
builder.withConnectorProvider(connectorProvider)
.withConnectionConfiguration(connectionConfiguration)
.withUri(wampUri)
.withRealm("timely")
.withInfiniteReconnects()
.withReconnectInterval(5, TimeUnit.SECONDS);
// Create a client through the builder. This will not immediately start
// a connection attempt
wampClient = builder.build();
Observable<WampClient.State> stateObservable = wampClient.statusChanged();
stateObservable.subscribe(new StateObserver());
wampClient.open();
Observable<Request> request = wampClient.registerProcedure("timely.version");
request.subscribe(new VersionObserver());
}
}
@@ -0,0 +1,7 @@
package timely;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackageClasses = { Configuration.class })
public class SpringBootstrap {
}
@@ -21,7 +21,7 @@ public class StandaloneServer extends Server {
private static MiniAccumuloCluster mac = null;
public StandaloneServer(File conf) throws Exception {
public StandaloneServer(Configuration conf) throws Exception {
super(conf);
}
@@ -38,22 +38,21 @@ public class StandaloneServer extends Server {
}
private static String usage() {
return "StandaloneServer <configFile> <directory>";
return "StandaloneServer <directory>";
}
public static void main(String[] args) {
if (args.length != 2) {
if (args.length < 1) {
System.err.println(usage());
}
final File conf = new File(args[0]);
if (!conf.canRead()) {
throw new RuntimeException("Configuration file does not exist or cannot be read");
}
File tmp = new File(args[1]);
File tmp = new File(args[0]);
if (!tmp.canWrite()) {
System.err.println("Unable to write to directory: " + tmp);
System.exit(1);
}
Configuration conf = initializeConfiguration(args);
File accumuloDir = new File(tmp, "accumulo");
MiniAccumuloConfig macConfig = new MiniAccumuloConfig(accumuloDir, "secret");
macConfig.setInstanceName("TimelyStandalone");
@@ -95,5 +94,4 @@ public class StandaloneServer extends Server {
LOG.info("Server shutting down.");
}
}
}
@@ -18,7 +18,6 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
@@ -62,20 +61,15 @@ public class MetricsResponse {
private static final String TD_END = "</td>\n";
private Set<String> ignoredTags = Collections.emptySet();
private Configuration conf = null;
private final Configuration conf;
public MetricsResponse() {
conf = null;
}
public MetricsResponse(Configuration conf) {
String tagsToIgnore = conf.get(Configuration.METRICS_IGNORED_TAGS);
if (!StringUtils.isEmpty(tagsToIgnore)) {
this.ignoredTags = new HashSet<>();
for (String tag : tagsToIgnore.split(",")) {
ignoredTags.add(tag);
}
}
this.conf = conf;
ignoredTags = new HashSet<>(conf.getMetricsReportIgnoredTags());
}
public TextWebSocketFrame toWebSocketResponse(String acceptHeader) throws Exception {
@@ -23,20 +23,20 @@ public class AuthCache {
private static Cache<String, Authentication> CACHE = null;
private static Long sessionMaxAge = -1L;
private static int sessionMaxAge = -1;
/**
* For tests only
*/
public static void resetSessionMaxAge() {
sessionMaxAge = -1L;
sessionMaxAge = -1;
}
public static void setSessionMaxAge(Configuration config) {
if (-1 != sessionMaxAge) {
throw new IllegalStateException("Cache session max age already configured.");
}
sessionMaxAge = Long.parseLong(config.get(Configuration.SESSION_MAX_AGE));
sessionMaxAge = config.getSecurity().getSessionMaxAge();
}
public static Cache<String, Authentication> getCache() {
@@ -56,9 +56,7 @@ public class AuthCache {
Collection<? extends GrantedAuthority> authorities = CACHE.asMap().get(sessionId).getAuthorities();
String[] auths = new String[authorities.size()];
final AtomicInteger i = new AtomicInteger(0);
authorities.forEach(a -> {
auths[i.getAndIncrement()] = a.getAuthority();
});
authorities.forEach(a -> auths[i.getAndIncrement()] = a.getAuthority());
return new Authorizations(auths);
} else {
return null;
@@ -69,7 +67,7 @@ public class AuthCache {
}
public static void enforceAccess(Configuration conf, Request r) throws Exception {
if (!conf.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS) && (r instanceof AuthenticatedRequest)) {
if (!conf.getSecurity().isAllowAnonymousAccess() && (r instanceof AuthenticatedRequest)) {
AuthenticatedRequest ar = (AuthenticatedRequest) r;
if (StringUtils.isEmpty(ar.getSessionId())) {
throw new TimelyException(HttpResponseStatus.UNAUTHORIZED.code(), "User must log in",
@@ -11,22 +11,11 @@ public class VisibilityCache {
private static volatile Cache<String, ColumnVisibility> CACHE = null;
/** Used for testing */
public static synchronized void init() {
if (CACHE == null) {
long defaultExpiration = Configuration.VISIBILITY_EXPIRATION_DEFAULT;
int initialCapacity = Configuration.VISIBILITY_CACHE_INITIAL_CAPACITY_DEFAULT;
long maxCapacity = Configuration.VISIBILITY_CACHE_MAX_CAPACITY_DEFAULT;
CACHE = Caffeine.newBuilder().expireAfterAccess(defaultExpiration, TimeUnit.MINUTES)
.initialCapacity(initialCapacity).maximumSize(maxCapacity).build();
}
}
public static synchronized void init(Configuration config) {
if (CACHE == null) {
long expireMinutes = Long.parseLong(config.get(Configuration.VISIBILITY_CACHE_EXPIRATION));
int initialCapacity = Integer.parseInt(config.get(Configuration.VISIBILITY_CACHE_INITIAL_CAPACITY));
long maxCapacity = Long.parseLong(config.get(Configuration.VISIBILITY_CACHE_MAX_CAPACITY));
long expireMinutes = config.getVisibilityCache().getExpirationMinutes();
int initialCapacity = config.getVisibilityCache().getInitialCapacity();
long maxCapacity = config.getVisibilityCache().getMaxCapacity();
CACHE = Caffeine.newBuilder().expireAfterAccess(expireMinutes, TimeUnit.MINUTES)
.initialCapacity(initialCapacity).maximumSize(maxCapacity).build();
}
@@ -40,8 +40,8 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
public HttpRequestDecoder(Configuration config) {
this.conf = config;
this.anonymousAccessAllowed = conf.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS);
this.nonSecureRedirectAddress = conf.get(Configuration.NON_SECURE_REDIRECT_PATH);
this.anonymousAccessAllowed = conf.getSecurity().isAllowAnonymousAccess();
this.nonSecureRedirectAddress = conf.getHttp().getRedirectPath();
}
public static String getSessionId(FullHttpRequest msg, boolean anonymousAccessAllowed) {
@@ -79,7 +79,7 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
final String sessionId = getSessionId(msg, this.anonymousAccessAllowed);
LOG.trace("SessionID: " + sessionId);
Request request = null;
Request request;
try {
if (msg.getMethod().equals(HttpMethod.GET)) {
HttpGetRequest get = AnnotationResolver.getClassForHttpGet(decoder.path());
@@ -22,9 +22,9 @@ public class NonSecureHttpHandler extends ChannelInboundHandlerAdapter implement
private final String redirectAddress;
public NonSecureHttpHandler(Configuration conf) {
String timelyHost = conf.get(Configuration.TIMELY_HTTP_HOST);
String timelyPort = conf.get(Configuration.QUERY_PORT);
String path = conf.get(Configuration.NON_SECURE_REDIRECT_PATH);
String timelyHost = conf.getHttp().getHost();
int timelyPort = conf.getHttp().getPort();
String path = conf.getHttp().getRedirectPath();
redirectAddress = "https://" + timelyHost + ":" + timelyPort + path;
}
@@ -13,7 +13,7 @@ public class StrictTransportHandler extends SimpleChannelInboundHandler<StrictTr
private String hstsMaxAge = "max-age=";
public StrictTransportHandler(Configuration conf) {
String maxAge = conf.get(Configuration.STRICT_TRANSPORT_MAX_AGE);
long maxAge = conf.getHttp().getStrictTransportMaxAge();
hstsMaxAge = "max-age=" + maxAge;
}
@@ -27,15 +27,12 @@ public abstract class TimelyLoginRequestHandler<T> extends SimpleChannelInboundH
private static final Logger LOG = LoggerFactory.getLogger(TimelyLoginRequestHandler.class);
private long maxAge = Configuration.SESSION_MAX_AGE_DEFAULT;
private String domain = null;
private final long maxAge;
private final String domain;
public TimelyLoginRequestHandler(Configuration conf) {
String ma = conf.get(Configuration.SESSION_MAX_AGE);
if (null != ma) {
maxAge = Long.parseLong(ma);
}
domain = conf.get(Configuration.TIMELY_HTTP_HOST);
maxAge = conf.getSecurity().getSessionMaxAge();
domain = conf.getHttp().getHost();
}
@Override
@@ -20,7 +20,7 @@ public class WebSocketHttpCookieHandler extends MessageToMessageCodec<FullHttpRe
public WebSocketHttpCookieHandler(Configuration config) {
super();
this.anonymousAccessAllowed = config.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS);
this.anonymousAccessAllowed = config.getSecurity().isAllowAnonymousAccess();
}
@Override
@@ -1,6 +1,5 @@
package timely.store;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.accumulo.core.conf.AccumuloConfiguration.getMemoryInBytes;
import static org.apache.accumulo.core.conf.AccumuloConfiguration.getTimeInMillis;
import io.netty.handler.codec.http.HttpResponseStatus;
@@ -62,8 +61,8 @@ import org.apache.hadoop.io.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.Configuration;
import timely.Server;
import timely.Configuration;
import timely.api.model.Meta;
import timely.api.model.Metric;
import timely.api.model.Tag;
@@ -113,7 +112,6 @@ public class DataStoreImpl implements DataStore {
}
Configuration conf;
private final Connector connector;
private MetaCache metaCache = null;
private final AtomicLong lastCountTime = new AtomicLong(System.currentTimeMillis());
@@ -133,27 +131,28 @@ public class DataStoreImpl implements DataStore {
try {
final BaseConfiguration apacheConf = new BaseConfiguration();
apacheConf.setProperty("instance.name", conf.get(Configuration.INSTANCE_NAME));
apacheConf.setProperty("instance.zookeeper.host", conf.get(Configuration.ZOOKEEPERS));
Configuration.Accumulo accumuloConf = conf.getAccumulo();
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
final Instance instance = new ZooKeeperInstance(aconf);
final byte[] passwd = conf.get(Configuration.PASSWORD).getBytes(UTF_8);
connector = instance.getConnector(conf.get(Configuration.USERNAME), new PasswordToken(passwd));
connector = instance
.getConnector(accumuloConf.getUsername(), new PasswordToken(accumuloConf.getPassword()));
bwConfig = new BatchWriterConfig();
bwConfig.setMaxLatency(getTimeInMillis(conf.get(Configuration.MAX_LATENCY)), TimeUnit.MILLISECONDS);
bwConfig.setMaxMemory(getMemoryInBytes(conf.get(Configuration.WRITE_BUFFER_SIZE)) / numWriteThreads);
bwConfig.setMaxWriteThreads(Integer.parseInt(conf.get(Configuration.WRITE_THREADS)));
scannerThreads = Integer.parseInt(conf.get(Configuration.SCANNER_THREADS));
anonAccessAllowed = conf.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS);
bwConfig.setMaxLatency(getTimeInMillis(accumuloConf.getWrite().getLatency()), TimeUnit.MILLISECONDS);
bwConfig.setMaxMemory(getMemoryInBytes(accumuloConf.getWrite().getBufferSize()) / numWriteThreads);
bwConfig.setMaxWriteThreads(accumuloConf.getWrite().getThreads());
scannerThreads = accumuloConf.getScan().getThreads();
anonAccessAllowed = conf.getSecurity().isAllowAnonymousAccess();
String ageoff = Long.toString(Integer.parseInt(conf.get(Configuration.METRICS_AGEOFF_DAYS)) * 86400000L);
String ageoff = Long.toString(conf.getMetricAgeOffDays() * 86400000L);
Map<String, String> ageOffOptions = new HashMap<>();
ageOffOptions.put("ttl", ageoff);
IteratorSetting ageOffIteratorSettings = new IteratorSetting(100, "ageoff", AgeOffFilter.class,
ageOffOptions);
EnumSet<IteratorScope> ageOffIteratorScope = EnumSet.allOf(IteratorScope.class);
metricsTable = conf.get(Configuration.METRICS_TABLE);
metricsTable = conf.getMetricsTable();
if (metricsTable.contains(".")) {
final String[] parts = metricsTable.split("\\.", 2);
final String namespace = parts[0];
@@ -184,7 +183,7 @@ public class DataStoreImpl implements DataStore {
}
}
}
metaTable = conf.get(Configuration.META_TABLE);
metaTable = conf.getMetaTable();
if (!tableIdMap.containsKey(metaTable)) {
try {
LOG.info("Creating table " + metaTable);
@@ -392,6 +391,10 @@ public class DataStoreImpl implements DataStore {
}
result.setTags(tags);
result.setLimit(msg.getLimit());
Map<String, Pattern> tagPatterns = new HashMap<>();
tags.forEach((k, v) -> {
tagPatterns.put(k, Pattern.compile(v));
});
try {
List<Result> resultField = new ArrayList<>();
Scanner scanner = connector.createScanner(metaTable, Authorizations.EMPTY);
@@ -399,11 +402,11 @@ public class DataStoreImpl implements DataStore {
Key end = start.followingKey(PartialKey.ROW);
Range range = new Range(start, end);
scanner.setRange(range);
// TODO compute columns to fetch
tags.keySet().forEach(k -> scanner.fetchColumnFamily(new Text(k)));
int total = 0;
for (Entry<Key, Value> entry : scanner) {
Meta metaEntry = Meta.parse(entry.getKey(), entry.getValue());
if (matches(metaEntry.getTagKey(), metaEntry.getTagValue(), tags)) {
if (matches(metaEntry.getTagKey(), metaEntry.getTagValue(), tagPatterns)) {
if (resultField.size() < msg.getLimit()) {
Result r = new Result();
r.putTag(metaEntry.getTagKey(), metaEntry.getTagValue());
@@ -423,12 +426,9 @@ public class DataStoreImpl implements DataStore {
return result;
}
private boolean matches(String tagk, String tagv, Map<String, String> tags) {
// first, match keys...
for (Entry<String, String> entry : tags.entrySet()) {
String k = entry.getKey();
String v = entry.getValue();
if (("*".equals(k) || tagk.equals(k)) && ("*".equals(v) || tagv.equals(v))) {
private boolean matches(String tagk, String tagv, Map<String, Pattern> tags) {
for (Entry<String, Pattern> entry : tags.entrySet()) {
if (tagk.equals(entry.getKey()) && entry.getValue().matcher(tagv).matches()) {
return true;
}
}
@@ -18,10 +18,10 @@ public class MetaCacheImpl implements MetaCache {
@Override
public void init(Configuration config) {
long defaultExpiration = Long.parseLong(config.get(Configuration.META_CACHE_EXPIRATION));
int initialCapacity = Integer.parseInt(config.get(Configuration.META_CACHE_INITIAL_CAPACITY));
long maxCapacity = Long.parseLong(config.get(Configuration.META_CACHE_MAX_CAPACITY));
cache = Caffeine.newBuilder().expireAfterAccess(defaultExpiration, TimeUnit.MINUTES)
long expirationMinutes = config.getMetaCache().getExpirationMinutes();
int initialCapacity = config.getMetaCache().getInitialCapacity();
long maxCapacity = config.getMetaCache().getMaxCapacity();
cache = Caffeine.newBuilder().expireAfterAccess(expirationMinutes, TimeUnit.MINUTES)
.initialCapacity(initialCapacity).maximumSize(maxCapacity).build();
}
@@ -33,16 +33,12 @@ public class Subscription {
this.sessionId = sessionId;
this.store = store;
this.ctx = ctx;
this.lag = Integer.parseInt(conf.get(Configuration.WS_SUBSCRIPTION_LAG));
this.lag = conf.getWebsocket().getSubscriptionLag();
// send a websocket ping at half the timeout interval.
int rate = (Integer.parseInt(conf.get(Configuration.WS_TIMEOUT_SECONDS)) / 2);
this.ping = this.ctx.executor().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
LOG.trace("Sending ping on channel {}", ctx.channel());
ctx.writeAndFlush(new PingWebSocketFrame());
}
int rate = conf.getWebsocket().getTimeout() / 2;
this.ping = this.ctx.executor().scheduleAtFixedRate(() -> {
LOG.trace("Sending ping on channel {}", ctx.channel());
ctx.writeAndFlush(new PingWebSocketFrame());
}, rate, rate, TimeUnit.SECONDS);
}
@@ -1,8 +1,5 @@
package timely.util;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.File;
import java.util.Collections;
import java.util.Map.Entry;
@@ -17,6 +14,9 @@ import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.commons.configuration.BaseConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import timely.SpringBootstrap;
import timely.Configuration;
import timely.api.model.Meta;
@@ -24,33 +24,28 @@ public class GetMetricTableSplitPoints {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("CreateMetricTableSplitPoints <configFile>");
System.exit(1);
}
try (ConfigurableApplicationContext ctx = new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(
args)) {
Configuration conf = ctx.getBean(Configuration.class);
final File f = new File(args[0]);
if (!f.canRead()) {
throw new RuntimeException("Configuration file does not exist or cannot be read");
}
Configuration conf = new Configuration(f);
final BaseConfiguration apacheConf = new BaseConfiguration();
apacheConf.setProperty("instance.name", conf.get(Configuration.INSTANCE_NAME));
apacheConf.setProperty("instance.zookeeper.host", conf.get(Configuration.ZOOKEEPERS));
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
final Instance instance = new ZooKeeperInstance(aconf);
final byte[] passwd = conf.get(Configuration.PASSWORD).getBytes(UTF_8);
Connector con = instance.getConnector(conf.get(Configuration.USERNAME), new PasswordToken(passwd));
Scanner s = con.createScanner(conf.get(Configuration.META_TABLE), con.securityOperations()
.getUserAuthorizations(con.whoami()));
try {
s.setRange(new Range(Meta.METRIC_PREFIX, true, Meta.TAG_PREFIX, false));
for (Entry<Key, Value> e : s) {
System.out.println(e.getKey().getRow().toString().substring(Meta.METRIC_PREFIX.length()));
final BaseConfiguration apacheConf = new BaseConfiguration();
Configuration.Accumulo accumuloConf = conf.getAccumulo();
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
final Instance instance = new ZooKeeperInstance(aconf);
Connector con = instance.getConnector(accumuloConf.getUsername(),
new PasswordToken(accumuloConf.getPassword()));
Scanner s = con.createScanner(conf.getMetaTable(),
con.securityOperations().getUserAuthorizations(con.whoami()));
try {
s.setRange(new Range(Meta.METRIC_PREFIX, true, Meta.TAG_PREFIX, false));
for (Entry<Key, Value> e : s) {
System.out.println(e.getKey().getRow().toString().substring(Meta.METRIC_PREFIX.length()));
}
} finally {
s.close();
}
} finally {
s.close();
}
}
}
@@ -0,0 +1,45 @@
package timely.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.ReportAsSingleViolation;
import javax.validation.constraints.NotNull;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Validates that field {@code notNullFieldName} is not null if
* {@code fieldName} is set to {@code fieldValue}
*/
@Documented
@Constraint(validatedBy = { NotEmptyIfFieldSetValidator.class })
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@ReportAsSingleViolation
@NotNull
public @interface NotEmptyIfFieldSet {
String fieldName();
String fieldValue();
String notNullFieldName();
String message() default "{NotEmptyIfFieldSet.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Documented
@interface List {
NotEmptyIfFieldSet[] value();
}
}
@@ -0,0 +1,47 @@
package timely.validator;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.InvocationTargetException;
/**
* Implementation of {@link NotEmptyIfFieldSet} validator.
*/
public class NotEmptyIfFieldSetValidator implements ConstraintValidator<NotEmptyIfFieldSet, Object> {
private String fieldName;
private String fieldSetValue;
private String notNullFieldName;
@Override
public void initialize(NotEmptyIfFieldSet annotation) {
fieldName = annotation.fieldName();
fieldSetValue = annotation.fieldValue();
notNullFieldName = annotation.notNullFieldName();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
try {
final String fieldValue = BeanUtils.getProperty(value, fieldName);
final String notNullFieldValue = BeanUtils.getProperty(value, notNullFieldName);
if (StringUtils.equals(fieldValue, fieldSetValue) && StringUtils.isEmpty(notNullFieldValue)) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
.addPropertyNode(notNullFieldName).addConstraintViolation();
return false;
}
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
return true;
}
}
@@ -0,0 +1,29 @@
package timely.wamp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observer;
import ws.wamp.jawampa.WampClient;
/**
* Timely Client state observer
*/
public class StateObserver implements Observer<WampClient.State> {
private static final Logger LOG = LoggerFactory.getLogger(StateObserver.class);
@Override
public void onCompleted() {
LOG.info("WAMP state completed");
}
@Override
public void onError(Throwable e) {
LOG.error("Wamp State Error: {}", e);
}
@Override
public void onNext(WampClient.State state) {
LOG.info("WAMP state change: {}", state);
}
}
@@ -0,0 +1,26 @@
package timely.wamp;
import rx.Observer;
import timely.api.request.VersionRequest;
import ws.wamp.jawampa.Request;
/**
* Handles timely.version requests
*/
public class VersionObserver implements Observer<Request> {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Request request) {
request.reply(VersionRequest.VERSION);
}
}
+8
View File
@@ -0,0 +1,8 @@
${AnsiColor.RED} ._____________ _
${AnsiColor.RED} .. __(___ ___) | |
${AnsiColor.RED} ..____ | |(_)_ __ ___ ____ | |_ _
${AnsiColor.RED} .._| || | '_ ' _ \/ /_\ \ | \ / /
${AnsiColor.RED} . ._ | || | | | | | | ____/ |\ \/ /
${AnsiColor.RED} .. ._ ___|_||_|_| |_| |_|_\___,_| \ /${AnsiColor.DEFAULT}
=================================${AnsiColor.RED}__/ /${AnsiColor.DEFAULT}===================
${AnsiColor.YELLOW}:: Timely ::${AnsiColor.DEFAULT} ${AnsiColor.RED}|___/${AnsiColor.DEFAULT} ${AnsiStyle.FAINT}${AnsiColor.WHITE}${application.formatted-version}${AnsiColor.DEFAULT}${AnsiStyle.NORMAL}
@@ -1,78 +1,67 @@
package timely;
import java.io.File;
import java.io.FileWriter;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.After;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class ConfigurationTest {
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@BeforeClass
public static void before() throws Exception {
temp.create();
@After
public void closeContext() {
context.close();
}
@Test
public void testMinimalConfiguration() throws Exception {
File conf = temp.newFile("config.properties");
conf.deleteOnExit();
try (FileWriter writer = new FileWriter(conf)) {
writer.write(Configuration.IP + "=127.0.0.1\n");
writer.write(Configuration.PUT_PORT + "=54321\n");
writer.write(Configuration.QUERY_PORT + "=54322\n");
writer.write(Configuration.WEBSOCKET_PORT + "=54323\n");
writer.write(Configuration.ZOOKEEPERS + "=localhost:2181\n");
writer.write(Configuration.INSTANCE_NAME + "=test\n");
writer.write(Configuration.USERNAME + "=root\n");
writer.write(Configuration.PASSWORD + "=secret\n");
writer.write(Configuration.TIMELY_HTTP_HOST + "=localhost\n");
writer.write(Configuration.SSL_USE_GENERATED_KEYPAIR + "=true\n");
}
new Configuration(conf);
context.register(SpringBootstrap.class);
EnvironmentTestUtils.addEnvironment(this.context, "timely.server.ip:127.0.0.1", "timely.server.tcp-port:54321",
"timely.http.ip:127.0.0.1", "timely.http.port:54322", "timely.websocket.ip:127.0.0.1",
"timely.websocket.port:54323", "timely.accumulo.zookeepers:localhost:2181",
"timely.accumulo.instance-name:test", "timely.accumulo.username:root",
"timely.accumulo.password:secret", "timely.http.host:localhost",
"timely.security.ssl.use-generated-keypair:true");
context.refresh();
Configuration config = this.context.getBean(Configuration.class);
assertEquals("127.0.0.1", config.getServer().getIp());
assertEquals(54321, config.getServer().getTcpPort());
assertEquals(54322, config.getHttp().getPort());
assertEquals(54323, config.getWebsocket().getPort());
assertEquals("localhost:2181", config.getAccumulo().getZookeepers());
assertEquals("test", config.getAccumulo().getInstanceName());
assertEquals("root", config.getAccumulo().getUsername());
assertEquals("secret", config.getAccumulo().getPassword());
assertEquals("localhost", config.getHttp().getHost());
assertTrue(config.getSecurity().getSsl().isUseGeneratedKeypair());
}
@Test(expected = IllegalArgumentException.class)
@Test(expected = BeanCreationException.class)
public void testMissingSSLProperty() throws Exception {
File conf = temp.newFile("config2.properties");
conf.deleteOnExit();
try (FileWriter writer = new FileWriter(conf)) {
writer.write(Configuration.IP + "=127.0.0.1\n");
writer.write(Configuration.PUT_PORT + "=54321\n");
writer.write(Configuration.QUERY_PORT + "=54322\n");
writer.write(Configuration.WEBSOCKET_PORT + "=54323\n");
writer.write(Configuration.ZOOKEEPERS + "=localhost:2181\n");
writer.write(Configuration.INSTANCE_NAME + "=test\n");
writer.write(Configuration.USERNAME + "=root\n");
writer.write(Configuration.PASSWORD + "=secret\n");
writer.write(Configuration.TIMELY_HTTP_HOST + "=localhost\n");
}
new Configuration(conf);
context.register(SpringBootstrap.class);
EnvironmentTestUtils.addEnvironment(this.context, "timely.server.ip:127.0.0.1", "timely.server.tcp-port:54321",
"timely.http.ip:127.0.0.1", "timely.http.port:54322", "timely.websocket.ip:127.0.0.1",
"timely.websocket.port:54323", "timely.accumulo.zookeepers:localhost:2181",
"timely.accumulo.instance-name:test", "timely.accumulo.username:root",
"timely.accumulo.password:secret", "timely.http.host:localhost");
context.refresh();
}
@Test
public void testSSLProperty() throws Exception {
File conf = temp.newFile("config3.properties");
conf.deleteOnExit();
try (FileWriter writer = new FileWriter(conf)) {
writer.write(Configuration.IP + "=127.0.0.1\n");
writer.write(Configuration.PUT_PORT + "=54321\n");
writer.write(Configuration.QUERY_PORT + "=54322\n");
writer.write(Configuration.WEBSOCKET_PORT + "=54323\n");
writer.write(Configuration.ZOOKEEPERS + "=localhost:2181\n");
writer.write(Configuration.INSTANCE_NAME + "=test\n");
writer.write(Configuration.USERNAME + "=root\n");
writer.write(Configuration.PASSWORD + "=secret\n");
writer.write(Configuration.TIMELY_HTTP_HOST + "=localhost\n");
writer.write(Configuration.SSL_CERTIFICATE_FILE + "=/tmp/foo\n");
writer.write(Configuration.SSL_PRIVATE_KEY_FILE + "=/tmp/bar\n");
}
new Configuration(conf);
context.register(SpringBootstrap.class);
EnvironmentTestUtils.addEnvironment(this.context, "timely.server.ip:127.0.0.1", "timely.server.tcp-port:54321",
"timely.http.ip:127.0.0.1", "timely.http.port:54322", "timely.websocket.ip:127.0.0.1",
"timely.websocket.port:54323", "timely.accumulo.zookeepers:localhost:2181",
"timely.accumulo.instance-name:test", "timely.accumulo.username:root",
"timely.accumulo.password:secret", "timely.http.host:localhost",
"timely.security.ssl.certificate-file:/tmp/foo", "timely.security.ssl.key-file:/tmp/bar");
context.refresh();
}
}
+1 -3
View File
@@ -10,8 +10,6 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.ssl.SslContext;
import java.io.File;
import timely.netty.tcp.TcpDecoder;
import timely.test.TestCaptureRequestHandler;
@@ -20,7 +18,7 @@ public class TestServer extends Server {
private TestCaptureRequestHandler tcpRequests = new TestCaptureRequestHandler();
private TestCaptureRequestHandler httpRequests = new TestCaptureRequestHandler();
public TestServer(File conf) throws Exception {
public TestServer(Configuration conf) throws Exception {
super(conf);
}
@@ -15,6 +15,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import timely.Configuration;
import timely.auth.VisibilityCache;
import timely.util.JsonUtil;
@@ -22,7 +23,7 @@ public class MetricTest {
@Before
public void before() {
VisibilityCache.init();
VisibilityCache.init(new Configuration());
}
@Test
@@ -41,7 +42,7 @@ public class MetricTest {
PairLexicoder<String, Long> rowCoder = new PairLexicoder<>(new StringLexicoder(), new LongLexicoder());
DoubleLexicoder valueCoder = new DoubleLexicoder();
byte[] row = rowCoder.encode(new ComparablePair<String, Long>("sys.cpu.user", ts));
byte[] row = rowCoder.encode(new ComparablePair<>("sys.cpu.user", ts));
byte[] value = valueCoder.encode(2.0D);
Assert.assertEquals(rowCoder.decode(row), rowCoder.decode(mut.getRow()));
Assert.assertEquals(3, mut.getUpdates().size());
@@ -1,19 +1,13 @@
package timely.api.response.timeseries;
import java.io.File;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import timely.Configuration;
import timely.api.model.Meta;
import timely.api.response.timeseries.MetricsResponse;
import timely.store.MetaCache;
import timely.store.MetaCacheFactory;
import timely.test.TestConfiguration;
@@ -38,61 +32,37 @@ public class MetricsResponseTest {
}
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static File conf = null;
@BeforeClass
public static void beforeClass() throws Exception {
temp.create();
}
@Test
public void testGenerateHtml() throws Exception {
conf = temp.newFile("config.properties");
try {
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.toConfiguration(conf);
Configuration config = new Configuration(conf);
MetaCache cache = MetaCacheFactory.getCache(config);
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
cache.add(new Meta("sys.cpu.user", "instance", "0"));
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
TestMetricsResponse r = new TestMetricsResponse(config);
String html = r.generateHtml().toString();
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
} finally {
conf.delete();
}
Configuration cfg = TestConfiguration.createMinimalConfigurationForTest();
MetaCache cache = MetaCacheFactory.getCache(cfg);
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
cache.add(new Meta("sys.cpu.user", "instance", "0"));
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
TestMetricsResponse r = new TestMetricsResponse(cfg);
String html = r.generateHtml().toString();
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
}
@Test
public void testGenerateHtmlWithIgnoredTags() throws Exception {
conf = temp.newFile("config.properties");
try {
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.put(Configuration.METRICS_IGNORED_TAGS, "instance");
cfg.toConfiguration(conf);
Configuration config = new Configuration(conf);
MetaCache cache = MetaCacheFactory.getCache(config);
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
cache.add(new Meta("sys.cpu.user", "instance", "0"));
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
TestMetricsResponse r = new TestMetricsResponse(config);
String html = r.generateHtml().toString();
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
} finally {
conf.delete();
}
Configuration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.getMetricsReportIgnoredTags().add("instance");
MetaCache cache = MetaCacheFactory.getCache(cfg);
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
cache.add(new Meta("sys.cpu.user", "instance", "0"));
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
TestMetricsResponse r = new TestMetricsResponse(cfg);
String html = r.generateHtml().toString();
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
}
}
@@ -1,6 +1,5 @@
package timely.auth;
import java.io.File;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@@ -10,9 +9,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@@ -21,19 +18,13 @@ import timely.test.TestConfiguration;
public class AuthCacheTest {
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static Configuration config = null;
private static Configuration config;
private static String cookie = null;
@BeforeClass
public static void before() throws Exception {
File conf = temp.newFile("config.properties");
conf.deleteOnExit();
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.put(Configuration.SESSION_MAX_AGE, "5000");
config = cfg.toConfiguration(conf);
config = TestConfiguration.createMinimalConfigurationForTest();
config.getSecurity().setSessionMaxAge(5000);
cookie = URLEncoder.encode(UUID.randomUUID().toString(), StandardCharsets.UTF_8.name());
}
@@ -8,7 +8,6 @@ import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
import java.io.File;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -21,9 +20,7 @@ import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import timely.Configuration;
@@ -61,9 +58,6 @@ public class HttpRequestDecoderTest {
private static final Long TEST_TIME = System.currentTimeMillis();
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static Configuration config = null;
private static Configuration anonConfig = null;
private TestHttpQueryDecoder decoder = null;
@@ -72,17 +66,9 @@ public class HttpRequestDecoderTest {
@BeforeClass
public static void before() throws Exception {
File conf = temp.newFile("config.properties");
conf.deleteOnExit();
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.toConfiguration(conf);
config = new Configuration(conf);
File conf2 = temp.newFile("anon-config.properties");
conf2.deleteOnExit();
TestConfiguration cfg2 = TestConfiguration.createMinimalConfigurationForTest();
cfg2.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "true");
cfg2.toConfiguration(conf2);
anonConfig = new Configuration(conf2);
config = TestConfiguration.createMinimalConfigurationForTest();
anonConfig = TestConfiguration.createMinimalConfigurationForTest();
anonConfig.getSecurity().setAllowAnonymousAccess(true);
cookie = URLEncoder.encode(UUID.randomUUID().toString(), StandardCharsets.UTF_8.name());
AuthCache.setSessionMaxAge(config);
AuthCache.getCache().put(cookie, new UsernamePasswordAuthenticationToken("test", "test1"));
@@ -11,7 +11,6 @@ import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
import io.netty.handler.codec.http.cookie.Cookie;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -20,9 +19,7 @@ import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import timely.Configuration;
import timely.api.request.auth.BasicAuthLoginRequest;
@@ -48,19 +45,11 @@ public class BasicAuthLoginRequestHandlerTest {
}
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private List<Object> results = new ArrayList<>();
@BeforeClass
public static void before() throws Exception {
File conf = temp.newFile("pre-config.properties");
conf.deleteOnExit();
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.toConfiguration(conf);
Configuration config = new Configuration(conf);
AuthCache.setSessionMaxAge(config);
AuthCache.setSessionMaxAge(TestConfiguration.createMinimalConfigurationForTest());
}
@AfterClass
@@ -75,11 +64,7 @@ public class BasicAuthLoginRequestHandlerTest {
@Test
public void testBasicAuthentication() throws Exception {
File conf = temp.newFile("config.properties");
conf.deleteOnExit();
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.toConfiguration(conf);
Configuration config = new Configuration(conf);
Configuration config = TestConfiguration.createMinimalConfigurationForTest();
// @formatter:off
String form =
@@ -99,7 +84,7 @@ public class BasicAuthLoginRequestHandlerTest {
BasicAuthLoginRequestHandler handler = new BasicAuthLoginRequestHandler(config);
CaptureChannelHandlerContext ctx = new CaptureChannelHandlerContext();
handler.channelRead(ctx, (BasicAuthLoginRequest) result);
handler.channelRead(ctx, result);
Assert.assertNotNull(ctx.msg);
Assert.assertTrue(ctx.msg instanceof DefaultFullHttpResponse);
DefaultFullHttpResponse response = (DefaultFullHttpResponse) ctx.msg;
@@ -118,11 +103,7 @@ public class BasicAuthLoginRequestHandlerTest {
@Test
public void testBasicAuthenticationFailure() throws Exception {
File conf = temp.newFile("config2.properties");
conf.deleteOnExit();
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.toConfiguration(conf);
Configuration config = new Configuration(conf);
Configuration config = TestConfiguration.createMinimalConfigurationForTest();
// @formatter:off
String form =
@@ -142,7 +123,7 @@ public class BasicAuthLoginRequestHandlerTest {
BasicAuthLoginRequestHandler handler = new BasicAuthLoginRequestHandler(config);
CaptureChannelHandlerContext ctx = new CaptureChannelHandlerContext();
handler.channelRead(ctx, (BasicAuthLoginRequest) result);
handler.channelRead(ctx, result);
Assert.assertNotNull(ctx.msg);
Assert.assertTrue(ctx.msg instanceof DefaultFullHttpResponse);
DefaultFullHttpResponse response = (DefaultFullHttpResponse) ctx.msg;
@@ -11,6 +11,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import timely.Configuration;
import timely.api.model.Metric;
import timely.api.model.Tag;
import timely.api.request.VersionRequest;
@@ -22,7 +23,7 @@ public class TcpDecoderTest {
@Before
public void setup() {
VisibilityCache.init();
VisibilityCache.init(new Configuration());
}
@Test
@@ -5,7 +5,6 @@ import io.netty.channel.local.LocalChannel;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import java.io.File;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -16,9 +15,7 @@ import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import timely.Configuration;
@@ -53,9 +50,6 @@ public class WebSocketRequestDecoderTest {
private static final Long TEST_TIME = System.currentTimeMillis();
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static Configuration config = null;
private static Configuration anonConfig = null;
private WebSocketRequestDecoder decoder = null;
@@ -65,17 +59,9 @@ public class WebSocketRequestDecoderTest {
@BeforeClass
public static void before() throws Exception {
File conf = temp.newFile("config.properties");
conf.deleteOnExit();
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
cfg.toConfiguration(conf);
config = new Configuration(conf);
File conf2 = temp.newFile("anon-config.properties");
conf2.deleteOnExit();
TestConfiguration cfg2 = TestConfiguration.createMinimalConfigurationForTest();
cfg2.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "true");
cfg2.toConfiguration(conf2);
anonConfig = new Configuration(conf2);
config = TestConfiguration.createMinimalConfigurationForTest();
anonConfig = TestConfiguration.createMinimalConfigurationForTest();
anonConfig.getSecurity().setAllowAnonymousAccess(true);
cookie = URLEncoder.encode(UUID.randomUUID().toString(), StandardCharsets.UTF_8.name());
AuthCache.setSessionMaxAge(config);
AuthCache.getCache().put(cookie, new UsernamePasswordAuthenticationToken("test", "test1"));
@@ -23,6 +23,7 @@ import org.apache.accumulo.core.iterators.SortedMapIterator;
import org.junit.Before;
import org.junit.Test;
import timely.Configuration;
import timely.api.model.Metric;
import timely.api.model.Tag;
import timely.auth.VisibilityCache;
@@ -37,7 +38,7 @@ public class DownsampleIteratorTest {
@Before
public void before() {
VisibilityCache.init();
VisibilityCache.init(new Configuration());
}
@Before
@@ -1,37 +1,18 @@
package timely.test;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import timely.Configuration;
import com.google.common.io.Files;
public class TestConfiguration {
public class TestConfiguration extends Properties {
private static final long serialVersionUID = 1L;
public static final String TIMELY_HTTP_ADDRESS_DEFAULT = "localhost";
public Configuration toConfiguration(File propertiesFile) throws Exception {
this.store(Files.newWriter(propertiesFile, StandardCharsets.UTF_8), null);
return new Configuration(propertiesFile);
}
public static TestConfiguration createMinimalConfigurationForTest() {
TestConfiguration cfg = new TestConfiguration();
cfg.put(Configuration.IP, "127.0.0.1");
cfg.put(Configuration.PUT_PORT, "54321");
cfg.put(Configuration.QUERY_PORT, "54322");
cfg.put(Configuration.WEBSOCKET_PORT, "54323");
cfg.put(Configuration.ZOOKEEPERS, "localhost:2181");
cfg.put(Configuration.INSTANCE_NAME, "test");
cfg.put(Configuration.USERNAME, "root");
cfg.put(Configuration.PASSWORD, "secret");
cfg.put(Configuration.TIMELY_HTTP_HOST, "localhost");
cfg.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "true");
cfg.put(Configuration.MAX_LATENCY, "2s");
cfg.put(Configuration.WS_TIMEOUT_SECONDS, "20");
public static Configuration createMinimalConfigurationForTest() {
Configuration cfg = new Configuration().getServer().setIp("127.0.0.1").getServer().setTcpPort(54321).getHttp()
.setIp("127.0.0.1").getHttp().setPort(54322).getWebsocket().setIp("127.0.0.1").getWebsocket()
.setPort(54323).getAccumulo().setZookeepers("localhost:2181").getAccumulo().setInstanceName("test")
.getAccumulo().setUsername("root").getAccumulo().setPassword("secret").getHttp().setHost("localhost")
.getSecurity().getSsl().setUseGeneratedKeypair(true).getAccumulo().getWrite().setLatency("2s")
.getWebsocket().setTimeout(20);
return cfg;
}
@@ -11,10 +11,8 @@ import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.io.File;
import java.net.URL;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import org.apache.accumulo.core.client.Connector;
@@ -41,9 +39,9 @@ public class OneWaySSLBase extends QueryBase {
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static MiniAccumuloCluster mac = null;
protected static File conf = null;
private static File clientTrustStoreFile = null;
protected static MiniAccumuloCluster mac = null;
protected static Configuration conf = null;
protected static File clientTrustStoreFile = null;
protected SSLSocketFactory getSSLSocketFactory() throws Exception {
SslContextBuilder builder = SslContextBuilder.forClient();
@@ -57,14 +55,14 @@ public class OneWaySSLBase extends QueryBase {
return jdkSslContext.getSocketFactory();
}
protected static void setupSSL(TestConfiguration config) throws Exception {
protected static void setupSSL(Configuration config) throws Exception {
SelfSignedCertificate serverCert = new SelfSignedCertificate();
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
clientTrustStoreFile = serverCert.certificate().getAbsoluteFile();
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
config.put(Configuration.SSL_USE_OPENSSL, "false");
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "true");
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
config.getSecurity().getSsl().setUseOpenssl(false);
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
config.getSecurity().setAllowAnonymousAccess(true);
}
@Override
@@ -76,28 +74,19 @@ public class OneWaySSLBase extends QueryBase {
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
con.setHostnameVerifier((host, session) -> true);
return con;
}
@BeforeClass
public static void beforeClass() throws Exception {
temp.create();
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
mac = new MiniAccumuloCluster(macConfig);
mac.start();
conf = temp.newFile("config.properties");
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
setupSSL(config);
config.toConfiguration(conf);
conf = TestConfiguration.createMinimalConfigurationForTest();
conf.getAccumulo().setInstanceName(mac.getInstanceName());
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
setupSSL(conf);
}
@AfterClass
@@ -6,15 +6,7 @@ import static org.junit.Assert.assertEquals;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.JdkSslClientContext;
import io.netty.handler.ssl.JdkSslContext;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.io.File;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
@@ -22,27 +14,18 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.minicluster.MiniAccumuloCluster;
import org.apache.accumulo.minicluster.MiniAccumuloConfig;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import timely.Configuration;
import timely.Server;
import timely.api.request.auth.BasicAuthLoginRequest;
import timely.api.request.timeseries.QueryRequest;
@@ -50,7 +33,6 @@ import timely.api.response.timeseries.QueryResponse;
import timely.auth.AuthCache;
import timely.netty.Constants;
import timely.test.IntegrationTest;
import timely.test.TestConfiguration;
import timely.util.JsonUtil;
/**
@@ -64,36 +46,6 @@ public class OneWaySSLBasicAuthAccessIT extends OneWaySSLBase {
private static final Long TEST_TIME = System.currentTimeMillis();
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static MiniAccumuloCluster mac = null;
private static File conf = null;
private static File clientTrustStoreFile = null;
protected SSLSocketFactory getSSLSocketFactory() throws Exception {
SslContextBuilder builder = SslContextBuilder.forClient();
builder.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED);
builder.sslProvider(SslProvider.JDK);
builder.trustManager(clientTrustStoreFile); // Trust the server cert
SslContext ctx = builder.build();
Assert.assertEquals(JdkSslClientContext.class, ctx.getClass());
JdkSslContext jdk = (JdkSslContext) ctx;
SSLContext jdkSslContext = jdk.context();
return jdkSslContext.getSocketFactory();
}
protected static void setupSSL(TestConfiguration config) throws Exception {
SelfSignedCertificate serverCert = new SelfSignedCertificate();
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
clientTrustStoreFile = serverCert.certificate().getAbsoluteFile();
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
config.put(Configuration.SSL_USE_OPENSSL, "false");
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
}
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
// Username and password are set in src/test/resources/security.xml
return getUrlConnection("test", "test1", url);
@@ -103,13 +55,7 @@ public class OneWaySSLBasicAuthAccessIT extends OneWaySSLBase {
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
URL loginURL = new URL(url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + "/login");
HttpsURLConnection con = (HttpsURLConnection) loginURL.openConnection();
con.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
con.setHostnameVerifier((host, session) -> true);
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setRequestProperty("Content-Type", "application/json");
@@ -131,47 +77,25 @@ public class OneWaySSLBasicAuthAccessIT extends OneWaySSLBase {
Assert.assertEquals(Constants.COOKIE_NAME, sessionCookie.name());
con = (HttpsURLConnection) url.openConnection();
con.setRequestProperty(Names.COOKIE, sessionCookie.name() + "=" + sessionCookie.value());
con.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
con.setHostnameVerifier((host, session) -> true);
return con;
}
@BeforeClass
public static void beforeClass() throws Exception {
temp.create();
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
mac = new MiniAccumuloCluster(macConfig);
mac.start();
conf = temp.newFile("config.properties");
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
setupSSL(config);
config.toConfiguration(conf);
OneWaySSLBase.beforeClass();
}
@AfterClass
public static void afterClass() throws Exception {
mac.stop();
OneWaySSLBase.afterClass();
}
@Before
public void setup() throws Exception {
super.setup();
Connector con = mac.getConnector("root", "secret");
con.securityOperations().changeUserAuthorizations("root", new Authorizations("A", "B", "C", "D", "E", "F"));
con.tableOperations().list().forEach(t -> {
if (t.startsWith("timely")) {
try {
con.tableOperations().delete(t);
} catch (Exception e) {
}
}
});
}
@After
@@ -33,8 +33,8 @@ import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import timely.Configuration;
import timely.Server;
import timely.Configuration;
import timely.auth.AuthCache;
import timely.netty.Constants;
import timely.test.TestConfiguration;
@@ -46,7 +46,7 @@ public class TwoWaySSLFailureIT extends QueryBase {
public static final TemporaryFolder temp = new TemporaryFolder();
private static MiniAccumuloCluster mac = null;
private static File conf = null;
private static Configuration conf = null;
private static SelfSignedCertificate serverCert = null;
private static File clientTrustStoreFile = null;
@@ -75,14 +75,14 @@ public class TwoWaySSLFailureIT extends QueryBase {
return jdkSslContext.getSocketFactory();
}
protected static void setupSSL(TestConfiguration config) throws Exception {
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
protected static void setupSSL(Configuration config) throws Exception {
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
// Needed for 2way SSL
config.put(Configuration.SSL_TRUST_STORE_FILE, serverCert.certificate().getAbsolutePath());
config.put(Configuration.SSL_USE_OPENSSL, "false");
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
config.getSecurity().getSsl().setTrustStoreFile(serverCert.certificate().getAbsolutePath());
config.getSecurity().getSsl().setUseOpenssl(false);
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
config.getSecurity().setAllowAnonymousAccess(false);
}
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
@@ -132,12 +132,10 @@ public class TwoWaySSLFailureIT extends QueryBase {
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
mac = new MiniAccumuloCluster(macConfig);
mac.start();
conf = temp.newFile("config.properties");
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
setupSSL(config);
config.toConfiguration(conf);
conf = TestConfiguration.createMinimalConfigurationForTest();
conf.getAccumulo().setInstanceName(mac.getInstanceName());
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
setupSSL(conf);
}
@AfterClass
@@ -18,10 +18,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import org.apache.accumulo.core.client.Connector;
@@ -38,8 +36,8 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import timely.Configuration;
import timely.Server;
import timely.Configuration;
import timely.api.request.timeseries.QueryRequest;
import timely.api.response.timeseries.QueryResponse;
import timely.auth.AuthCache;
@@ -64,7 +62,7 @@ public class TwoWaySSLIT extends QueryBase {
public static final TemporaryFolder temp = new TemporaryFolder();
private static MiniAccumuloCluster mac = null;
private static File conf = null;
private static Configuration conf = null;
protected static SelfSignedCertificate serverCert = null;
protected static File clientTrustStoreFile = null;
@@ -92,14 +90,14 @@ public class TwoWaySSLIT extends QueryBase {
return jdkSslContext.getSocketFactory();
}
protected static void setupSSL(TestConfiguration config) throws Exception {
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
protected static void setupSSL(Configuration config) throws Exception {
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
// Needed for 2way SSL
config.put(Configuration.SSL_TRUST_STORE_FILE, serverCert.certificate().getAbsolutePath());
config.put(Configuration.SSL_USE_OPENSSL, "false");
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
config.getSecurity().getSsl().setTrustStoreFile(serverCert.certificate().getAbsolutePath());
config.getSecurity().getSsl().setUseOpenssl(false);
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
config.getSecurity().setAllowAnonymousAccess(false);
}
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
@@ -111,13 +109,7 @@ public class TwoWaySSLIT extends QueryBase {
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
URL loginURL = new URL(url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + "/login");
HttpsURLConnection con = (HttpsURLConnection) loginURL.openConnection();
con.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
con.setHostnameVerifier((host, session) -> true);
con.setRequestMethod("GET");
con.setDoOutput(true);
con.setRequestProperty("Content-Type", "application/json");
@@ -133,28 +125,19 @@ public class TwoWaySSLIT extends QueryBase {
Assert.assertEquals(Constants.COOKIE_NAME, sessionCookie.name());
con = (HttpsURLConnection) url.openConnection();
con.setRequestProperty(Names.COOKIE, sessionCookie.name() + "=" + sessionCookie.value());
con.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
con.setHostnameVerifier((host, session) -> true);
return con;
}
@BeforeClass
public static void beforeClass() throws Exception {
temp.create();
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
mac = new MiniAccumuloCluster(macConfig);
mac.start();
conf = temp.newFile("config.properties");
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
setupSSL(config);
config.toConfiguration(conf);
conf = TestConfiguration.createMinimalConfigurationForTest();
conf.getAccumulo().setInstanceName(mac.getInstanceName());
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
setupSSL(conf);
}
@AfterClass
@@ -38,8 +38,8 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import timely.Configuration;
import timely.Server;
import timely.Configuration;
import timely.api.request.timeseries.QueryRequest;
import timely.api.response.timeseries.QueryResponse;
import timely.auth.AuthCache;
@@ -65,7 +65,7 @@ public class TwoWaySSLOpenSSLIT extends QueryBase {
public static final TemporaryFolder temp = new TemporaryFolder();
private static MiniAccumuloCluster mac = null;
private static File conf = null;
private static Configuration conf = null;
protected static SelfSignedCertificate serverCert = null;
protected static File clientTrustStoreFile = null;
@@ -93,14 +93,14 @@ public class TwoWaySSLOpenSSLIT extends QueryBase {
return jdkSslContext.getSocketFactory();
}
protected static void setupSSL(TestConfiguration config) throws Exception {
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
protected static void setupSSL(Configuration config) throws Exception {
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
// Needed for 2way SSL
config.put(Configuration.SSL_TRUST_STORE_FILE, serverCert.certificate().getAbsolutePath());
config.put(Configuration.SSL_USE_OPENSSL, "true");
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
config.getSecurity().getSsl().setTrustStoreFile(serverCert.certificate().getAbsolutePath());
config.getSecurity().getSsl().setUseOpenssl(false);
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
config.getSecurity().setAllowAnonymousAccess(false);
}
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
@@ -150,12 +150,10 @@ public class TwoWaySSLOpenSSLIT extends QueryBase {
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
mac = new MiniAccumuloCluster(macConfig);
mac.start();
conf = temp.newFile("config.properties");
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
setupSSL(config);
config.toConfiguration(conf);
conf = TestConfiguration.createMinimalConfigurationForTest();
conf.getAccumulo().setInstanceName(mac.getInstanceName());
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
setupSSL(conf);
}
@AfterClass
@@ -131,20 +131,20 @@ public class HttpApiIT extends OneWaySSLBase {
String suggest = "https://localhost:54322/api/search/lookup?";
// Test a known query
String result = query(suggest + "m=sys.cpu.idle%7Btag3%3D*%7D");
String result = query(suggest + "m=sys.cpu.idle%7Btag3%3D.*%7D");
assertTrue(result, result.indexOf("\"results\":[{\"tags\":{\"tag3\":\"value3\"}") >= 0);
// Test a fail
result = query(suggest + "m=sys.cpu.idle%7Btag3%3Dstupid%7D");
result = query(suggest + "m=sys.cpu.idle%7Btag3%3Dnomatch%7D");
assertTrue(result.indexOf("\"results\":[]") >= 0);
// Test multiple results
result = query(suggest + "m=sys.cpu.idle%7Btag3%3D*,tag4%3D*%7D");
result = query(suggest + "m=sys.cpu.idle%7Btag3%3D.*,tag4%3D.*%7D");
assertTrue(result, result.indexOf("\"results\":[{\"tags\":{\"tag3\":\"value3\"}") >= 0);
assertTrue(result, result.indexOf("{\"tags\":{\"tag4\":\"value4\"}") >= 0);
// Find a tag only in the metric that matches
result = query(suggest + "m=sys.cpu.idle%7Btag1%3D*%7D");
result = query(suggest + "m=sys.cpu.idle%7Btag1%3D.*%7D");
assertTrue(result, result.indexOf("\"results\":[]") >= 0);
} finally {
@@ -6,7 +6,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
@@ -39,9 +38,9 @@ import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.Configuration;
import timely.Server;
import timely.TestServer;
import timely.Configuration;
import timely.api.model.Metric;
import timely.api.model.Tag;
import timely.api.request.VersionRequest;
@@ -62,20 +61,18 @@ public class TimelyTcpIT {
public static final TemporaryFolder temp = new TemporaryFolder();
private static MiniAccumuloCluster mac = null;
private static File conf = null;
private static Configuration conf = null;
@BeforeClass
public static void beforeClass() throws Exception {
temp.create();
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
mac = new MiniAccumuloCluster(macConfig);
mac.start();
conf = temp.newFile("config.properties");
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "true");
config.toConfiguration(conf);
conf = TestConfiguration.createMinimalConfigurationForTest();
conf.getAccumulo().setInstanceName(mac.getInstanceName());
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
conf.getSecurity().getSsl().setUseOpenssl(false);
conf.getSecurity().getSsl().setUseGeneratedKeypair(true);
}
@AfterClass
@@ -0,0 +1,110 @@
package timely.test.integration.websocket;
import io.netty.handler.ssl.SslContextBuilder;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.minicluster.MiniAccumuloCluster;
import org.apache.accumulo.minicluster.MiniAccumuloConfig;
import org.junit.*;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.Observable;
import timely.Configuration;
import timely.TestServer;
import timely.auth.AuthCache;
import timely.test.IntegrationTest;
import timely.test.TestConfiguration;
import ws.wamp.jawampa.Reply;
import ws.wamp.jawampa.WampClient;
import ws.wamp.jawampa.WampClientBuilder;
import ws.wamp.jawampa.connection.IWampConnectorProvider;
import ws.wamp.jawampa.transport.netty.NettyWampClientConnectorProvider;
import ws.wamp.jawampa.transport.netty.NettyWampConnectionConfig;
import java.util.concurrent.TimeUnit;
/**
* Integration tests for the operations available over WAMP
*/
@Category(IntegrationTest.class)
public class WampIT {
private static final Logger LOG = LoggerFactory.getLogger(WampIT.class);
private static final Long TEST_TIME = System.currentTimeMillis();
@ClassRule
public static final TemporaryFolder temp = new TemporaryFolder();
private static MiniAccumuloCluster mac = null;
private static Configuration conf = null;
private static TestServer server = null;
@BeforeClass
public static void beforeClass() throws Exception {
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
mac = new MiniAccumuloCluster(macConfig);
mac.start();
conf = TestConfiguration.createMinimalConfigurationForTest();
conf.getAccumulo().setInstanceName(mac.getInstanceName());
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
conf.getSecurity().getSsl().setUseOpenssl(false);
conf.getSecurity().getSsl().setUseGeneratedKeypair(true);
server = new TestServer(conf);
}
@AfterClass
public static void afterClass() throws Exception {
server.shutdown();
mac.stop();
}
@Before
public void setup() throws Exception {
Connector con = mac.getConnector("root", "secret");
con.tableOperations().list().forEach(t -> {
if (t.startsWith("timely")) {
try {
con.tableOperations().delete(t);
} catch (Exception e) {
}
}
});
}
@After
public void tearDown() throws Exception {
AuthCache.resetSessionMaxAge();
}
@Test
public void testVersion() throws Exception {
//final TestServer m = new TestServer(conf);
final WampClient client;
IWampConnectorProvider connectorProvider = new NettyWampClientConnectorProvider();
NettyWampConnectionConfig connectionConfiguration = new NettyWampConnectionConfig.Builder()
.withSslContext(SslContextBuilder.forClient().build())
.build();
WampClientBuilder builder = new WampClientBuilder();
builder.withConnectorProvider(connectorProvider)
.withConnectionConfiguration(connectionConfiguration)
.withUri("wss://localhost:54323/wamp")
.withRealm("default")
.withInfiniteReconnects()
.withReconnectInterval(5, TimeUnit.SECONDS);
// Create a client through the builder. This will not immediately start
// a connection attempt
client = builder.build();
client.open();
Observable<Reply> oReply = client.call("timely.version");
Reply reply = oReply.toBlocking().last();
System.out.println(reply.toString());
}
}
@@ -573,7 +573,7 @@ public class WebSocketIT extends OneWaySSLBase {
" \"operation\" : \"lookup\","+
" \"metric\" : \"sys.cpu.idle\","+
" \"tags\" : ["+
"\"tag3=*\""+
"\"tag3=.*\""+
"]"+
"}";
// @formatter:on