mirror of
https://github.com/NationalSecurityAgency/timely.git
synced 2026-11-10 03:41:25 -10:00
Compare commits
78
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f4ce0623d | ||
|
|
2aedf9c2e5 | ||
|
|
9ef8758dfb | ||
|
|
489bfcc541 | ||
|
|
cb2679d40e | ||
|
|
cb02950919 | ||
|
|
71cdaec2e4 | ||
|
|
c19e1d8b2f | ||
|
|
cb73e8e75c | ||
|
|
4c508c1a7d | ||
|
|
c6c2c0d41e | ||
|
|
a24cef78b3 | ||
|
|
08f99f6540 | ||
|
|
be11da7d15 | ||
|
|
4bc5753328 | ||
|
|
2ccb89a06d | ||
|
|
dfc3840ad4 | ||
|
|
6235034d8b | ||
|
|
d8de6ac06f | ||
|
|
f381946abe | ||
|
|
48bbe6a561 | ||
|
|
0f6110ea59 | ||
|
|
461b5e7e78 | ||
|
|
4ec7d94c28 | ||
|
|
77e910ae06 | ||
|
|
a4998af887 | ||
|
|
2858549ede | ||
|
|
57f0e1408f | ||
|
|
151adc025a | ||
|
|
5abd9d7200 | ||
|
|
fa2e211c72 | ||
|
|
a21438976e | ||
|
|
ba37047f3a | ||
|
|
9305470c69 | ||
|
|
200233542e | ||
|
|
3cd78dc624 | ||
|
|
9027cac6e3 | ||
|
|
3663b4e6d5 | ||
|
|
64973d0674 | ||
|
|
5512306f1e | ||
|
|
d35ae08188 | ||
|
|
e448657afb | ||
|
|
1dcd893711 | ||
|
|
409f5375d1 | ||
|
|
c5df8139ca | ||
|
|
dcd23d4fc8 | ||
|
|
cc7326fc19 | ||
|
|
0d2b6e61c8 | ||
|
|
b7cd8765c5 | ||
|
|
a9d27d5b1b | ||
|
|
7d67eb218d | ||
|
|
5fb7e3dd2b | ||
|
|
5a89861cec | ||
|
|
a3bc9a01ee | ||
|
|
dba494b06d | ||
|
|
5826884c3c | ||
|
|
f94c731bbc | ||
|
|
4e042bcb94 | ||
|
|
ab7f499134 | ||
|
|
c098f9f3e4 | ||
|
|
94cfcbc0c4 | ||
|
|
674e1b0ab5 | ||
|
|
4eedb84547 | ||
|
|
bef86eac37 | ||
|
|
27bb16e403 | ||
|
|
e2bbe4e212 | ||
|
|
a95d2d7ea1 | ||
|
|
f751175190 | ||
|
|
648199f330 | ||
|
|
fcfc3f7bc0 | ||
|
|
200bc39902 | ||
|
|
f854c9e394 | ||
|
|
73ddae1f8d | ||
|
|
cb7184503e | ||
|
|
3a357b50ef | ||
|
|
689aee0678 | ||
|
|
32f6b9d4c9 | ||
|
|
512f318387 |
No files matched your search
+3
-2
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-analytics</artifactId>
|
<artifactId>timely-analytics</artifactId>
|
||||||
<!--
|
<!--
|
||||||
@@ -68,6 +68,7 @@
|
|||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<compilerId>jdt</compilerId>
|
<compilerId>jdt</compilerId>
|
||||||
@@ -76,7 +77,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.tycho</groupId>
|
<groupId>org.eclipse.tycho</groupId>
|
||||||
<artifactId>tycho-compiler-jdt</artifactId>
|
<artifactId>tycho-compiler-jdt</artifactId>
|
||||||
<version>0.21.0</version>
|
<version>1.4.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
LOG.info("Opening summarization job.");
|
LOG.info("Opening summarization job.");
|
||||||
super.open(parameters);
|
super.open(parameters);
|
||||||
client = new WebSocketSubscriptionClient(jp.getTimelyHostname(), jp.getTimelyHttpsPort(), jp.getTimelyWssPort(),
|
client = new WebSocketSubscriptionClient(jp.getTimelyHostname(), jp.getTimelyHttpsPort(), jp.getTimelyWssPort(),
|
||||||
jp.isDoLogin(), jp.getTimelyUsername(), jp.getTimelyPassword(), jp.getKeyStoreFile(),
|
jp.isClientAuth(), jp.isDoLogin(), jp.getTimelyUsername(), jp.getTimelyPassword(), jp.getKeyStoreFile(),
|
||||||
jp.getKeyStoreType(), jp.getKeyStorePass(), jp.getTrustStoreFile(), jp.getTrustStoreType(),
|
jp.getKeyStoreType(), jp.getKeyStorePass(), jp.getTrustStoreFile(), jp.getTrustStoreType(),
|
||||||
jp.getTrustStorePass(), jp.isHostVerificationEnabled(), jp.getBufferSize());
|
jp.getTrustStorePass(), jp.isHostVerificationEnabled(), jp.getBufferSize());
|
||||||
}
|
}
|
||||||
@@ -96,7 +96,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(Session session, EndpointConfig config) {
|
public void onOpen(Session session, EndpointConfig config) {
|
||||||
session.addMessageHandler(new MessageHandler.Whole<String>() {
|
session.addMessageHandler(String.class, new MessageHandler.Whole<String>() {
|
||||||
|
|
||||||
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
|
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
|
||||||
private long lastWatermarkTime = 0L;
|
private long lastWatermarkTime = 0L;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ public class SummarizationJob {
|
|||||||
})
|
})
|
||||||
.name("Metric Windows")
|
.name("Metric Windows")
|
||||||
.addSink(
|
.addSink(
|
||||||
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
|
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
|
||||||
new MetricHistogram(), 2, true) {
|
new MetricHistogram(), 2, true) {
|
||||||
|
|
||||||
private final Logger LOG = LoggerFactory
|
private final Logger LOG = LoggerFactory
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public class SummarizationJobParameters extends GlobalJobParameters implements S
|
|||||||
private final int timelyTcpPort;
|
private final int timelyTcpPort;
|
||||||
private final int timelyHttpsPort;
|
private final int timelyHttpsPort;
|
||||||
private final int timelyWssPort;
|
private final int timelyWssPort;
|
||||||
|
private final boolean clientAuth;
|
||||||
private final boolean doLogin;
|
private final boolean doLogin;
|
||||||
private final String timelyUsername;
|
private final String timelyUsername;
|
||||||
private final String timelyPassword;
|
private final String timelyPassword;
|
||||||
@@ -40,6 +41,7 @@ public class SummarizationJobParameters extends GlobalJobParameters implements S
|
|||||||
timelyTcpPort = params.getInt("timelyTcpPort", 4241);
|
timelyTcpPort = params.getInt("timelyTcpPort", 4241);
|
||||||
timelyHttpsPort = params.getInt("timelyHttpsPort", 4242);
|
timelyHttpsPort = params.getInt("timelyHttpsPort", 4242);
|
||||||
timelyWssPort = params.getInt("timelyWssPort", 4243);
|
timelyWssPort = params.getInt("timelyWssPort", 4243);
|
||||||
|
clientAuth = params.getBoolean("clientAuth", false);
|
||||||
doLogin = params.getBoolean("doLogin", false);
|
doLogin = params.getBoolean("doLogin", false);
|
||||||
timelyUsername = params.get("timelyUsername", null);
|
timelyUsername = params.get("timelyUsername", null);
|
||||||
timelyPassword = params.get("timelyPassword", null);
|
timelyPassword = params.get("timelyPassword", null);
|
||||||
@@ -69,6 +71,7 @@ public class SummarizationJobParameters extends GlobalJobParameters implements S
|
|||||||
timelyTcpPort = conf.getInteger("timelyTcpPort", 4241);
|
timelyTcpPort = conf.getInteger("timelyTcpPort", 4241);
|
||||||
timelyHttpsPort = conf.getInteger("timelyHttpsPort", 4242);
|
timelyHttpsPort = conf.getInteger("timelyHttpsPort", 4242);
|
||||||
timelyWssPort = conf.getInteger("timelyWssPort", 4243);
|
timelyWssPort = conf.getInteger("timelyWssPort", 4243);
|
||||||
|
clientAuth = conf.getBoolean("clientAuth", false);
|
||||||
doLogin = conf.getBoolean("doLogin", false);
|
doLogin = conf.getBoolean("doLogin", false);
|
||||||
timelyUsername = conf.getString("timelyUsername", null);
|
timelyUsername = conf.getString("timelyUsername", null);
|
||||||
timelyPassword = conf.getString("timelyPassword", null);
|
timelyPassword = conf.getString("timelyPassword", null);
|
||||||
@@ -112,6 +115,10 @@ public class SummarizationJobParameters extends GlobalJobParameters implements S
|
|||||||
return timelyWssPort;
|
return timelyWssPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isClientAuth() {
|
||||||
|
return clientAuth;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isDoLogin() {
|
public boolean isDoLogin() {
|
||||||
return doLogin;
|
return doLogin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash -vx
|
#!/bin/bash
|
||||||
|
|
||||||
if [[ `uname` == "Darwin" ]]; then
|
if [[ `uname` == "Darwin" ]]; then
|
||||||
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
||||||
@@ -8,11 +8,6 @@ else
|
|||||||
TCNATIVE_SUFFIX="so"
|
TCNATIVE_SUFFIX="so"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# netty tcnative file reference
|
|
||||||
#netty-tcnative-1.1.33.Fork18-linux-x86_64-fedora.jar -> libnetty-tcnative.so
|
|
||||||
#netty-tcnative-1.1.33.Fork18-linux-x86_64.jar -> libnetty-tcnative.so
|
|
||||||
#netty-tcnative-1.1.33.Fork18-osx-x86_64.jar -> libnetty-tcnative.jnilib
|
|
||||||
|
|
||||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
||||||
BASE_DIR=${THIS_DIR}/..
|
BASE_DIR=${THIS_DIR}/..
|
||||||
@@ -32,14 +27,15 @@ fi
|
|||||||
mkdir -p ${NATIVE_DIR}
|
mkdir -p ${NATIVE_DIR}
|
||||||
|
|
||||||
pushd ${BASE_DIR}/bin
|
pushd ${BASE_DIR}/bin
|
||||||
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative*.jar META-INF/native/libnetty_tcnative.${NATIVE_SUFFIX}
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative-boringssl-static*.jar META-INF/native/libnetty_tcnative_linux_x86_64.${TCNATIVE_SUFFIX}
|
||||||
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-transport-native-epoll*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${NATIVE_SUFFIX}
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-all*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${TCNATIVE_SUFFIX}
|
||||||
popd
|
popd
|
||||||
|
|
||||||
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
|
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*:${HADOOP_CONF_DIR}"
|
||||||
JVM_ARGS="-Xmx1G -Xms1G -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS}"
|
JVM_ARGS="-Xmx1G -Xms1G -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-spring.xml"
|
||||||
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||||
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||||
|
|
||||||
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
|
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
|
||||||
|
|
||||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.balancer.Balancer --spring.config.name=timely --spring.profiles.active=balancer"
|
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.balancer.Balancer --spring.config.name=timely --spring.profiles.active=balancer"
|
||||||
|
|||||||
@@ -22,5 +22,8 @@
|
|||||||
<AppenderRef ref="Console" level="warn" />
|
<AppenderRef ref="Console" level="warn" />
|
||||||
<AppenderRef ref="Rolling" level="trace" />
|
<AppenderRef ref="Rolling" level="trace" />
|
||||||
</Root>
|
</Root>
|
||||||
|
<Logger name="timely" additivity="false">
|
||||||
|
<AppenderRef ref="Console" level="debug" />
|
||||||
|
</Logger>
|
||||||
</Loggers>
|
</Loggers>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
+39
-17
@@ -11,21 +11,33 @@
|
|||||||
|
|
||||||
<beans:bean id="x509PrincipalExtractor" class="org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor">
|
<beans:bean id="x509PrincipalExtractor" class="org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor">
|
||||||
<beans:property name="subjectDnRegex" value="CN=(.*?)(?:,|$)"/>
|
<beans:property name="subjectDnRegex" value="CN=(.*?)(?:,|$)"/>
|
||||||
</beans:bean>
|
</beans:bean>
|
||||||
|
|
||||||
<beans:bean id="timelyUserDetailsService" class="timely.auth.UserDetailsService">
|
<beans:bean id="timelyUserDetailsService" class="timely.auth.UserDetailsService">
|
||||||
<beans:property name="users">
|
<beans:property name="users">
|
||||||
<util:map key-type="java.lang.String">
|
<util:list>
|
||||||
<beans:entry key="example.com">
|
<beans:bean class="timely.auth.TimelyUser">
|
||||||
<util:list>
|
<beans:constructor-arg name="subjectDn">
|
||||||
<beans:value>D</beans:value>
|
<beans:value>CN=example.com</beans:value>
|
||||||
<beans:value>E</beans:value>
|
</beans:constructor-arg>
|
||||||
<beans:value>F</beans:value>
|
<beans:constructor-arg name="auths">
|
||||||
</util:list>
|
<util:list>
|
||||||
</beans:entry>
|
<beans:value>D</beans:value>
|
||||||
</util:map>
|
<beans:value>E</beans:value>
|
||||||
</beans:property>
|
<beans:value>F</beans:value>
|
||||||
</beans:bean>
|
</util:list>
|
||||||
|
</beans:constructor-arg>
|
||||||
|
<beans:constructor-arg name="roles">
|
||||||
|
<util:list>
|
||||||
|
<beans:value>G</beans:value>
|
||||||
|
<beans:value>H</beans:value>
|
||||||
|
<beans:value>I</beans:value>
|
||||||
|
</util:list>
|
||||||
|
</beans:constructor-arg>
|
||||||
|
</beans:bean>
|
||||||
|
</util:list>
|
||||||
|
</beans:property>
|
||||||
|
</beans:bean>
|
||||||
|
|
||||||
<beans:bean id="x509AuthorizationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
|
<beans:bean id="x509AuthorizationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
|
||||||
<beans:property name="preAuthenticatedUserDetailsService" ref="timelyUserDetailsService" />
|
<beans:property name="preAuthenticatedUserDetailsService" ref="timelyUserDetailsService" />
|
||||||
@@ -34,9 +46,12 @@
|
|||||||
<user-service id="usernamePasswordService">
|
<user-service id="usernamePasswordService">
|
||||||
<user name="test" password="test1" authorities="A,B,C" />
|
<user name="test" password="test1" authorities="A,B,C" />
|
||||||
</user-service>
|
</user-service>
|
||||||
|
|
||||||
<beans:bean id="UserNamePasswordAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
<beans:bean id="noOpPasswordEncoder" class="org.springframework.security.crypto.password.NoOpPasswordEncoder"/>
|
||||||
|
|
||||||
|
<beans:bean id="UserNamePasswordAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||||
<beans:property name="userDetailsService" ref="usernamePasswordService"/>
|
<beans:property name="userDetailsService" ref="usernamePasswordService"/>
|
||||||
|
<beans:property name="passwordEncoder" ref="noOpPasswordEncoder"/>
|
||||||
</beans:bean>
|
</beans:bean>
|
||||||
|
|
||||||
<authentication-manager alias="authenticationManager">
|
<authentication-manager alias="authenticationManager">
|
||||||
@@ -45,5 +60,12 @@
|
|||||||
<!-- Basic authorization provider, validates provided username and password -->
|
<!-- Basic authorization provider, validates provided username and password -->
|
||||||
<authentication-provider ref="UserNamePasswordAuthenticationProvider" />
|
<authentication-provider ref="UserNamePasswordAuthenticationProvider" />
|
||||||
</authentication-manager>
|
</authentication-manager>
|
||||||
|
|
||||||
|
<util:list id="requiredRoles" value-type="java.lang.String">
|
||||||
|
<beans:value></beans:value>
|
||||||
|
</util:list>
|
||||||
|
|
||||||
|
<util:list id="requiredAuths" value-type="java.lang.String">
|
||||||
|
<beans:value></beans:value>
|
||||||
|
</util:list>
|
||||||
</beans:beans>
|
</beans:beans>
|
||||||
@@ -8,12 +8,15 @@ timely-balancer:
|
|||||||
assignmentFile: /timely/balancer/assignments.csv
|
assignmentFile: /timely/balancer/assignments.csv
|
||||||
security:
|
security:
|
||||||
session-max-age: 86400
|
session-max-age: 86400
|
||||||
allow-anonymous-access: true
|
cache-expiration-minutes: 60
|
||||||
|
cache-refresh-minutes: 5
|
||||||
|
allow-anonymous-http-access: true
|
||||||
|
allow-anonymous-ws-access: true
|
||||||
serverSsl:
|
serverSsl:
|
||||||
certificate-file:
|
certificate-file:
|
||||||
key-file:
|
key-file:
|
||||||
#key-password:
|
#key-password:
|
||||||
use-generated-keypair: false
|
use-generated-keypair: true
|
||||||
trust-store-file:
|
trust-store-file:
|
||||||
use-openssl: true
|
use-openssl: true
|
||||||
#use-ciphers:
|
#use-ciphers:
|
||||||
@@ -31,7 +34,7 @@ timely-balancer:
|
|||||||
nonCachedMetrics:
|
nonCachedMetrics:
|
||||||
server:
|
server:
|
||||||
ip: 127.0.0.1
|
ip: 127.0.0.1
|
||||||
tcp-port: 4242
|
tcpPort: 4242
|
||||||
numTcpPools: 1
|
numTcpPools: 1
|
||||||
tcpBufferSize: 100
|
tcpBufferSize: 100
|
||||||
tcpClientPool:
|
tcpClientPool:
|
||||||
@@ -51,7 +54,7 @@ timely-balancer:
|
|||||||
jmxEnabled: true
|
jmxEnabled: true
|
||||||
testOnBorrow: false
|
testOnBorrow: false
|
||||||
testOnReturn: false
|
testOnReturn: false
|
||||||
udp-port: 4245
|
udpPort: 4245
|
||||||
udpClientPool:
|
udpClientPool:
|
||||||
minIdlePerKey: 0
|
minIdlePerKey: 0
|
||||||
maxIdlePerKey: 40
|
maxIdlePerKey: 40
|
||||||
@@ -108,6 +111,7 @@ timely-balancer:
|
|||||||
flush-interval-seconds: 30
|
flush-interval-seconds: 30
|
||||||
scanner-read-ahead: 1
|
scanner-read-ahead: 1
|
||||||
subscription-batch-size: 5000
|
subscription-batch-size: 5000
|
||||||
|
incomingBufferSize: 50000000
|
||||||
wsClientPool:
|
wsClientPool:
|
||||||
minIdlePerKey: 0
|
minIdlePerKey: 0
|
||||||
maxIdlePerKey: 40
|
maxIdlePerKey: 40
|
||||||
|
|||||||
+7
-44
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-balancer</artifactId>
|
<artifactId>timely-balancer</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -108,6 +108,10 @@
|
|||||||
<groupId>org.apache.hadoop</groupId>
|
<groupId>org.apache.hadoop</groupId>
|
||||||
<artifactId>hadoop-minicluster</artifactId>
|
<artifactId>hadoop-minicluster</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.tyrus</groupId>
|
||||||
|
<artifactId>tyrus-client</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
@@ -161,9 +165,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-tcnative</artifactId>
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
<version>${version.netty-tcnative}</version>
|
|
||||||
<classifier>${os.detected.classifier}</classifier>
|
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -201,11 +203,6 @@
|
|||||||
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>timely</groupId>
|
|
||||||
<artifactId>timely-common</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
@@ -252,9 +249,8 @@
|
|||||||
<artifactItems>
|
<artifactItems>
|
||||||
<artifactItem>
|
<artifactItem>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-tcnative</artifactId>
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
<version>${version.netty-tcnative}</version>
|
<version>${version.netty-tcnative}</version>
|
||||||
<classifier>${os.detected.classifier}</classifier>
|
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
<overWrite>false</overWrite>
|
<overWrite>false</overWrite>
|
||||||
<outputDirectory>${project.build.directory}/native</outputDirectory>
|
<outputDirectory>${project.build.directory}/native</outputDirectory>
|
||||||
@@ -296,37 +292,4 @@
|
|||||||
</extension>
|
</extension>
|
||||||
</extensions>
|
</extensions>
|
||||||
</build>
|
</build>
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>native-epoll-linux</id>
|
|
||||||
<activation>
|
|
||||||
<os>
|
|
||||||
<family>!mac</family>
|
|
||||||
</os>
|
|
||||||
</activation>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-transport-native-epoll</artifactId>
|
|
||||||
<version>${version.netty}</version>
|
|
||||||
<classifier>linux-x86_64</classifier>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</profile>
|
|
||||||
<profile>
|
|
||||||
<id>native-epoll</id>
|
|
||||||
<activation>
|
|
||||||
<os>
|
|
||||||
<family>mac</family>
|
|
||||||
</os>
|
|
||||||
</activation>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-transport-native-epoll</artifactId>
|
|
||||||
<version>${version.netty}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
</project>
|
</project>
|
||||||
Vendored
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
<directory>${project.basedir}/bin</directory>
|
<directory>${project.basedir}/bin</directory>
|
||||||
<outputDirectory>bin</outputDirectory>
|
<outputDirectory>bin</outputDirectory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>*</include>
|
<include>**/*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package timely.balancer;
|
package timely.balancer;
|
||||||
|
|
||||||
import java.util.Timer;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.TimerTask;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.AtomicDouble;
|
import com.google.common.util.concurrent.AtomicDouble;
|
||||||
@@ -20,38 +20,26 @@ public class ArrivalRate {
|
|||||||
private AtomicDouble longTermRate = new AtomicDouble(0);
|
private AtomicDouble longTermRate = new AtomicDouble(0);
|
||||||
private AtomicLong longTermLastReset = new AtomicLong(0);
|
private AtomicLong longTermLastReset = new AtomicLong(0);
|
||||||
|
|
||||||
public ArrivalRate(Timer timer) {
|
public ArrivalRate(ScheduledExecutorService arrivalRateExecutor) {
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
shortTermLastReset.set(now);
|
shortTermLastReset.set(now);
|
||||||
mediumTermLastReset.set(now);
|
mediumTermLastReset.set(now);
|
||||||
longTermLastReset.set(now);
|
longTermLastReset.set(now);
|
||||||
|
|
||||||
// 2 minute
|
// 2 minute
|
||||||
timer.schedule(new TimerTask() {
|
arrivalRateExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
resetShort();
|
||||||
@Override
|
}, 2, 2, TimeUnit.MINUTES);
|
||||||
public void run() {
|
|
||||||
resetShort();
|
|
||||||
}
|
|
||||||
}, 120000, 120000);
|
|
||||||
|
|
||||||
// 5 minute
|
// 5 minute
|
||||||
timer.schedule(new TimerTask() {
|
arrivalRateExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
resetMedium();
|
||||||
@Override
|
}, 5, 5, TimeUnit.MINUTES);
|
||||||
public void run() {
|
|
||||||
resetMedium();
|
|
||||||
}
|
|
||||||
}, 300000, 300000);
|
|
||||||
|
|
||||||
// 15 minute
|
// 15 minute
|
||||||
timer.schedule(new TimerTask() {
|
arrivalRateExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
resetLong();
|
||||||
@Override
|
}, 15, 15, TimeUnit.MINUTES);
|
||||||
public void run() {
|
|
||||||
resetLong();
|
|
||||||
}
|
|
||||||
}, 900000, 900000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetShort() {
|
private void resetShort() {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package timely.balancer;
|
package timely.balancer;
|
||||||
|
|
||||||
|
import static timely.Server.SERVICE_DISCOVERY_PATH;
|
||||||
|
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS;
|
||||||
|
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS_LOCK_PATH;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -21,6 +25,7 @@ import io.netty.channel.ChannelHandler;
|
|||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.WriteBufferWaterMark;
|
||||||
import io.netty.channel.epoll.EpollChannelOption;
|
import io.netty.channel.epoll.EpollChannelOption;
|
||||||
import io.netty.channel.epoll.EpollDatagramChannel;
|
import io.netty.channel.epoll.EpollDatagramChannel;
|
||||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||||
@@ -52,10 +57,19 @@ import io.netty.handler.stream.ChunkedWriteHandler;
|
|||||||
import io.netty.handler.timeout.IdleStateHandler;
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
import io.netty.util.NettyRuntime;
|
import io.netty.util.NettyRuntime;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
|
import org.apache.accumulo.core.conf.AccumuloConfiguration;
|
||||||
|
import org.apache.curator.RetryPolicy;
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
|
import org.apache.curator.retry.RetryForever;
|
||||||
|
import org.apache.zookeeper.CreateMode;
|
||||||
|
import org.apache.zookeeper.data.Stat;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.WebApplicationType;
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import timely.auth.AuthCache;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
import timely.balancer.configuration.ClientSsl;
|
import timely.balancer.configuration.ClientSsl;
|
||||||
import timely.balancer.configuration.SpringBootstrap;
|
import timely.balancer.configuration.SpringBootstrap;
|
||||||
@@ -63,7 +77,7 @@ import timely.balancer.connection.http.HttpClientPool;
|
|||||||
import timely.balancer.connection.tcp.TcpClientPool;
|
import timely.balancer.connection.tcp.TcpClientPool;
|
||||||
import timely.balancer.connection.udp.UdpClientPool;
|
import timely.balancer.connection.udp.UdpClientPool;
|
||||||
import timely.balancer.connection.ws.WsClientPool;
|
import timely.balancer.connection.ws.WsClientPool;
|
||||||
import timely.balancer.healthcheck.HealthChecker;
|
import timely.balancer.healthcheck.TcpHealthChecker;
|
||||||
import timely.balancer.netty.http.HttpRelayHandler;
|
import timely.balancer.netty.http.HttpRelayHandler;
|
||||||
import timely.balancer.netty.tcp.TcpRelayHandler;
|
import timely.balancer.netty.tcp.TcpRelayHandler;
|
||||||
import timely.balancer.netty.udp.UdpRelayHandler;
|
import timely.balancer.netty.udp.UdpRelayHandler;
|
||||||
@@ -81,7 +95,7 @@ import timely.netty.tcp.TcpDecoder;
|
|||||||
import timely.netty.tcp.TcpVersionHandler;
|
import timely.netty.tcp.TcpVersionHandler;
|
||||||
import timely.netty.udp.UdpDecoder;
|
import timely.netty.udp.UdpDecoder;
|
||||||
import timely.netty.udp.UdpPacketToByteBuf;
|
import timely.netty.udp.UdpPacketToByteBuf;
|
||||||
import timely.netty.websocket.WebSocketHttpCookieHandler;
|
import timely.netty.websocket.WebSocketFullRequestHandler;
|
||||||
import timely.netty.websocket.WebSocketRequestDecoder;
|
import timely.netty.websocket.WebSocketRequestDecoder;
|
||||||
import timely.netty.websocket.subscription.WSTimelyExceptionHandler;
|
import timely.netty.websocket.subscription.WSTimelyExceptionHandler;
|
||||||
|
|
||||||
@@ -115,9 +129,13 @@ public class Balancer {
|
|||||||
protected Channel httpChannelHandle = null;
|
protected Channel httpChannelHandle = null;
|
||||||
protected Channel wsChannelHandle = null;
|
protected Channel wsChannelHandle = null;
|
||||||
protected List<Channel> udpChannelHandleList = new ArrayList<>();
|
protected List<Channel> udpChannelHandleList = new ArrayList<>();
|
||||||
|
private CuratorFramework curatorFramework;
|
||||||
protected volatile boolean shutdown = false;
|
protected volatile boolean shutdown = false;
|
||||||
private static final int DEFAULT_EVENT_LOOP_THREADS;
|
private static final int DEFAULT_EVENT_LOOP_THREADS;
|
||||||
|
|
||||||
|
private String[] zkPaths = new String[] { LEADER_LATCH_PATH, ASSIGNMENTS_LAST_UPDATED_PATH, ASSIGNMENTS_LOCK_PATH,
|
||||||
|
SERVICE_DISCOVERY_PATH, NON_CACHED_METRICS, NON_CACHED_METRICS_LOCK_PATH };
|
||||||
|
|
||||||
static {
|
static {
|
||||||
DEFAULT_EVENT_LOOP_THREADS = Math.max(1,
|
DEFAULT_EVENT_LOOP_THREADS = Math.max(1,
|
||||||
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
|
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
|
||||||
@@ -127,8 +145,11 @@ public class Balancer {
|
|||||||
this.balancerConfig = balancerConf;
|
this.balancerConfig = balancerConf;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static ConfigurableApplicationContext initializeConfiguration(String[] args) {
|
protected static ConfigurableApplicationContext initializeContext(String[] args) {
|
||||||
return new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(args);
|
SpringApplicationBuilder builder = new SpringApplicationBuilder(SpringBootstrap.class);
|
||||||
|
builder.web(WebApplicationType.NONE);
|
||||||
|
builder.registerShutdownHook(false);
|
||||||
|
return builder.run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdownHook() {
|
private void shutdownHook() {
|
||||||
@@ -160,8 +181,9 @@ public class Balancer {
|
|||||||
channelFutures.add(wsChannelHandle.close());
|
channelFutures.add(wsChannelHandle.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int udpChannel = 1;
|
||||||
for (Channel c : udpChannelHandleList) {
|
for (Channel c : udpChannelHandleList) {
|
||||||
LOG.info("Closing udpChannelHandle");
|
LOG.info("Closing udpChannelHandle #" + udpChannel++);
|
||||||
channelFutures.add(c.close());
|
channelFutures.add(c.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,14 +192,13 @@ public class Balancer {
|
|||||||
try {
|
try {
|
||||||
f.get();
|
f.get();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Error while shutting down channel: {}", f.channel().config());
|
LOG.error("Channel:" + f.channel().config() + " -> " + e.getMessage(), e);
|
||||||
LOG.error("{}", e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Integer quietPeriod = balancerConfig.getServer().getShutdownQuietPeriod();
|
int quietPeriod = balancerConfig.getServer().getShutdownQuietPeriod();
|
||||||
List<Future<?>> groupFutures = new ArrayList<>();
|
List<Future<?>> groupFutures = new ArrayList<>();
|
||||||
|
|
||||||
if (tcpBossGroup != null) {
|
if (tcpBossGroup != null) {
|
||||||
LOG.info("Shutting down tcpBossGroup");
|
LOG.info("Shutting down tcpBossGroup");
|
||||||
groupFutures.add(tcpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(tcpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
@@ -222,9 +243,7 @@ public class Balancer {
|
|||||||
try {
|
try {
|
||||||
f.get();
|
f.get();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Error while shutting down group: {}", f.toString());
|
LOG.error("Group:" + f.toString() + " -> " + e.getMessage(), e);
|
||||||
LOG.error("{}", e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -235,10 +254,29 @@ public class Balancer {
|
|||||||
LOG.error("Error closing WebSocketRequestDecoder during shutdown", e);
|
LOG.error("Error closing WebSocketRequestDecoder during shutdown", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.metricResolver != null) {
|
||||||
|
try {
|
||||||
|
LOG.info("Closing metricResolver");
|
||||||
|
this.metricResolver.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curatorFramework != null) {
|
||||||
|
try {
|
||||||
|
LOG.info("Closing curatorFramework");
|
||||||
|
curatorFramework.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (applicationContext != null) {
|
if (applicationContext != null) {
|
||||||
LOG.info("Closing applicationContext");
|
LOG.info("Closing applicationContext");
|
||||||
applicationContext.close();
|
applicationContext.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.shutdown = true;
|
this.shutdown = true;
|
||||||
LOG.info("Server shut down.");
|
LOG.info("Server shut down.");
|
||||||
}
|
}
|
||||||
@@ -320,8 +358,33 @@ public class Balancer {
|
|||||||
ssl.getKeyFile(), ssl.getKeyType(), ssl.getKeyPassword());
|
ssl.getKeyFile(), ssl.getKeyType(), ssl.getKeyPassword());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensureZkPaths(CuratorFramework curatorFramework, String[] paths) {
|
||||||
|
for (String s : paths) {
|
||||||
|
try {
|
||||||
|
Stat stat = curatorFramework.checkExists().forPath(s);
|
||||||
|
if (stat == null) {
|
||||||
|
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT)
|
||||||
|
.forPath(s);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.info(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
|
|
||||||
|
// start curator framework
|
||||||
|
RetryPolicy retryPolicy = new RetryForever(1000);
|
||||||
|
int timeout = Long.valueOf(AccumuloConfiguration.getTimeInMillis(balancerConfig.getZooKeeper().getTimeout()))
|
||||||
|
.intValue();
|
||||||
|
curatorFramework = CuratorFrameworkFactory.newClient(balancerConfig.getZooKeeper().getServers(), timeout, 10000,
|
||||||
|
retryPolicy);
|
||||||
|
curatorFramework.start();
|
||||||
|
ensureZkPaths(curatorFramework, zkPaths);
|
||||||
|
|
||||||
|
AuthCache.configure(balancerConfig.getSecurity());
|
||||||
final boolean useEpoll = useEpoll();
|
final boolean useEpoll = useEpoll();
|
||||||
Class<? extends ServerSocketChannel> channelClass;
|
Class<? extends ServerSocketChannel> channelClass;
|
||||||
Class<? extends Channel> datagramChannelClass;
|
Class<? extends Channel> datagramChannelClass;
|
||||||
@@ -354,8 +417,9 @@ public class Balancer {
|
|||||||
for (int x = 0; x < balancerConfig.getServer().getNumTcpPools(); x++) {
|
for (int x = 0; x < balancerConfig.getServer().getNumTcpPools(); x++) {
|
||||||
tcpClientPools.add(new TcpClientPool(this.balancerConfig));
|
tcpClientPools.add(new TcpClientPool(this.balancerConfig));
|
||||||
}
|
}
|
||||||
HealthChecker healthChecker = new HealthChecker(this.balancerConfig, tcpClientPools.get(0));
|
TcpHealthChecker healthChecker = new TcpHealthChecker(this.balancerConfig, tcpClientPools.get(0));
|
||||||
this.metricResolver = new BalancedMetricResolver(this.balancerConfig, healthChecker);
|
this.metricResolver = new BalancedMetricResolver(curatorFramework, this.balancerConfig, healthChecker);
|
||||||
|
this.metricResolver.start();
|
||||||
|
|
||||||
final ServerBootstrap tcpServer = new ServerBootstrap();
|
final ServerBootstrap tcpServer = new ServerBootstrap();
|
||||||
tcpServer.group(tcpBossGroup, tcpWorkerGroup);
|
tcpServer.group(tcpBossGroup, tcpWorkerGroup);
|
||||||
@@ -387,7 +451,8 @@ public class Balancer {
|
|||||||
httpServer.group(httpBossGroup, httpWorkerGroup);
|
httpServer.group(httpBossGroup, httpWorkerGroup);
|
||||||
httpServer.channel(channelClass);
|
httpServer.channel(channelClass);
|
||||||
httpServer.handler(new LoggingHandler());
|
httpServer.handler(new LoggingHandler());
|
||||||
HttpClientPool httpClientPool = new HttpClientPool(balancerConfig, clientSSLContext);
|
HttpClientPool httpClientPool = new HttpClientPool(balancerConfig.getSecurity(), balancerConfig.getHttp(),
|
||||||
|
clientSSLContext);
|
||||||
httpServer.childHandler(setupHttpChannel(balancerConfig, sslCtx, metricResolver, httpClientPool));
|
httpServer.childHandler(setupHttpChannel(balancerConfig, sslCtx, metricResolver, httpClientPool));
|
||||||
httpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
httpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
httpServer.option(ChannelOption.SO_BACKLOG, 128);
|
httpServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||||
@@ -406,10 +471,9 @@ public class Balancer {
|
|||||||
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||||
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
||||||
/* Not sure if next three lines are necessary */
|
/* Not sure if next two lines are necessary */
|
||||||
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
||||||
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
|
wsServer.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(620145, 838860));
|
||||||
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
|
|
||||||
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
||||||
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||||
|
|
||||||
@@ -434,12 +498,12 @@ public class Balancer {
|
|||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
Balancer.applicationContext = Balancer.initializeConfiguration(args);
|
Balancer.applicationContext = Balancer.initializeContext(args);
|
||||||
BalancerConfiguration balancerConf = applicationContext.getBean(BalancerConfiguration.class);
|
BalancerConfiguration balancerConf = Balancer.applicationContext.getBean(BalancerConfiguration.class);
|
||||||
|
|
||||||
Balancer b = new Balancer(balancerConf);
|
Balancer balancer = new Balancer(balancerConf);
|
||||||
try {
|
try {
|
||||||
b.run();
|
balancer.run();
|
||||||
LATCH.await();
|
LATCH.await();
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
LOG.info("Server shutting down.");
|
LOG.info("Server shutting down.");
|
||||||
@@ -447,7 +511,7 @@ public class Balancer {
|
|||||||
LOG.error("Error running server.", e);
|
LOG.error("Error running server.", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
b.shutdown();
|
balancer.shutdown();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
@@ -467,16 +531,17 @@ public class Balancer {
|
|||||||
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
|
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
|
||||||
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
||||||
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
||||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
|
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
||||||
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
||||||
ch.pipeline().addLast("queryDecoder", new timely.netty.http.HttpRequestDecoder(
|
ch.pipeline().addLast("queryDecoder", new timely.netty.http.HttpRequestDecoder(
|
||||||
balancerConfig.getSecurity(), balancerConfig.getHttp()));
|
balancerConfig.getSecurity(), balancerConfig.getHttp()));
|
||||||
ch.pipeline().addLast("fileServer", new HttpStaticFileServerHandler());
|
ch.pipeline().addLast("fileServer", new HttpStaticFileServerHandler().setIgnoreSslHandshakeErrors(
|
||||||
|
balancerConfig.getSecurity().getServerSsl().isUseGeneratedKeypair()));
|
||||||
ch.pipeline().addLast("login",
|
ch.pipeline().addLast("login",
|
||||||
new X509LoginRequestHandler(balancerConfig.getSecurity(), balancerConfig.getHttp()));
|
new X509LoginRequestHandler(balancerConfig.getSecurity(), balancerConfig.getHttp()));
|
||||||
ch.pipeline().addLast("httpRelay",
|
ch.pipeline().addLast("httpRelay", new HttpRelayHandler(metricResolver, httpClientPool));
|
||||||
new HttpRelayHandler(balancerConfig, metricResolver, httpClientPool));
|
ch.pipeline().addLast("error", new TimelyExceptionHandler().setIgnoreSslHandshakeErrors(
|
||||||
ch.pipeline().addLast("error", new TimelyExceptionHandler());
|
balancerConfig.getSecurity().getServerSsl().isUseGeneratedKeypair()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -489,7 +554,7 @@ public class Balancer {
|
|||||||
ch.pipeline().addLast("logger", new LoggingHandler());
|
ch.pipeline().addLast("logger", new LoggingHandler());
|
||||||
ch.pipeline().addLast("packetDecoder", new UdpPacketToByteBuf());
|
ch.pipeline().addLast("packetDecoder", new UdpPacketToByteBuf());
|
||||||
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
||||||
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
|
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
|
||||||
ch.pipeline().addLast("putDecoder", new UdpDecoder());
|
ch.pipeline().addLast("putDecoder", new UdpDecoder());
|
||||||
ch.pipeline().addLast("udpRelayHandler", new UdpRelayHandler(metricResolver, udpClientPool));
|
ch.pipeline().addLast("udpRelayHandler", new UdpRelayHandler(metricResolver, udpClientPool));
|
||||||
}
|
}
|
||||||
@@ -502,7 +567,7 @@ public class Balancer {
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(SocketChannel ch) throws Exception {
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
||||||
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
|
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
|
||||||
ch.pipeline().addLast("putDecoder", new TcpDecoder());
|
ch.pipeline().addLast("putDecoder", new TcpDecoder());
|
||||||
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPools));
|
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPools));
|
||||||
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
|
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
|
||||||
@@ -518,13 +583,13 @@ public class Balancer {
|
|||||||
protected void initChannel(SocketChannel ch) throws Exception {
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
||||||
ch.pipeline().addLast("httpServer", new HttpServerCodec());
|
ch.pipeline().addLast("httpServer", new HttpServerCodec());
|
||||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
|
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
||||||
ch.pipeline().addLast("sessionExtractor", new WebSocketHttpCookieHandler(balancerConfig.getSecurity()));
|
ch.pipeline().addLast("sessionExtractor", new WebSocketFullRequestHandler());
|
||||||
|
|
||||||
ch.pipeline().addLast("idle-handler",
|
ch.pipeline().addLast("idle-handler",
|
||||||
new IdleStateHandler(balancerConfig.getWebsocket().getTimeout(), 0, 0));
|
new IdleStateHandler(balancerConfig.getWebsocket().getTimeout(), 0, 0));
|
||||||
ch.pipeline().addLast("ws-protocol",
|
ch.pipeline().addLast("ws-protocol",
|
||||||
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, true));
|
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, false, true));
|
||||||
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(balancerConfig.getSecurity()));
|
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(balancerConfig.getSecurity()));
|
||||||
ch.pipeline().addLast("httpRelay", new WsRelayHandler(balancerConfig, metricResolver, wsClientPool));
|
ch.pipeline().addLast("httpRelay", new WsRelayHandler(balancerConfig, metricResolver, wsClientPool));
|
||||||
ch.pipeline().addLast("error", new WSTimelyExceptionHandler());
|
ch.pipeline().addLast("error", new WSTimelyExceptionHandler());
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import javax.validation.Valid;
|
|||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
import timely.configuration.Cache;
|
import timely.configuration.Cache;
|
||||||
|
|
||||||
|
@Validated
|
||||||
@Component
|
@Component
|
||||||
@ConfigurationProperties(prefix = "timely-balancer")
|
@ConfigurationProperties(prefix = "timely-balancer")
|
||||||
public class BalancerConfiguration {
|
public class BalancerConfiguration {
|
||||||
@@ -47,6 +49,16 @@ public class BalancerConfiguration {
|
|||||||
|
|
||||||
private int serverSuccessesBeforeUp = 3;
|
private int serverSuccessesBeforeUp = 3;
|
||||||
|
|
||||||
|
private String metricAssignmentPersisterType = "HDFS";
|
||||||
|
|
||||||
|
private long balanceDelay = 900000;
|
||||||
|
|
||||||
|
private long balancePeriod = 900000;
|
||||||
|
|
||||||
|
private long persistDelay = 10000;
|
||||||
|
|
||||||
|
private long persistPeriod = 60000;
|
||||||
|
|
||||||
public ZooKeeper getZooKeeper() {
|
public ZooKeeper getZooKeeper() {
|
||||||
return zooKeeper;
|
return zooKeeper;
|
||||||
}
|
}
|
||||||
@@ -118,4 +130,44 @@ public class BalancerConfiguration {
|
|||||||
public void setServerSuccessesBeforeUp(int serverSuccessesBeforeUp) {
|
public void setServerSuccessesBeforeUp(int serverSuccessesBeforeUp) {
|
||||||
this.serverSuccessesBeforeUp = serverSuccessesBeforeUp;
|
this.serverSuccessesBeforeUp = serverSuccessesBeforeUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getMetricAssignmentPersisterType() {
|
||||||
|
return metricAssignmentPersisterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMetricAssignmentPersisterType(String metricAssignmentPersisterType) {
|
||||||
|
this.metricAssignmentPersisterType = metricAssignmentPersisterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBalanceDelay(long balanceDelay) {
|
||||||
|
this.balanceDelay = balanceDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getBalanceDelay() {
|
||||||
|
return balanceDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBalancePeriod(long balancePeriod) {
|
||||||
|
this.balancePeriod = balancePeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getBalancePeriod() {
|
||||||
|
return balancePeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPersistDelay(long persistDelay) {
|
||||||
|
this.persistDelay = persistDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPersistDelay() {
|
||||||
|
return persistDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPersistPeriod(long persistPeriod) {
|
||||||
|
this.persistPeriod = persistPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPersistPeriod() {
|
||||||
|
return persistPeriod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package timely.balancer.configuration;
|
|||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
import timely.configuration.Http;
|
import timely.configuration.Http;
|
||||||
|
|
||||||
@@ -10,9 +11,9 @@ public class BalancerHttp extends Http {
|
|||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@NestedConfigurationProperty
|
@NestedConfigurationProperty
|
||||||
private GenericKeyedObjectPoolConfig httpClientPool = new GenericKeyedObjectPoolConfig();
|
private GenericKeyedObjectPoolConfig<CloseableHttpClient> httpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig getHttpClientPool() {
|
public GenericKeyedObjectPoolConfig<CloseableHttpClient> getHttpClientPool() {
|
||||||
return httpClientPool;
|
return httpClientPool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,27 +4,29 @@ import javax.validation.Valid;
|
|||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import timely.client.tcp.TcpClient;
|
||||||
|
import timely.client.udp.UdpClient;
|
||||||
import timely.configuration.Server;
|
import timely.configuration.Server;
|
||||||
|
|
||||||
public class BalancerServer extends Server {
|
public class BalancerServer extends Server {
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@NestedConfigurationProperty
|
@NestedConfigurationProperty
|
||||||
private GenericKeyedObjectPoolConfig udpClientPool = new GenericKeyedObjectPoolConfig();
|
private GenericKeyedObjectPoolConfig<UdpClient> udpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@NestedConfigurationProperty
|
@NestedConfigurationProperty
|
||||||
private GenericKeyedObjectPoolConfig tcpClientPool = new GenericKeyedObjectPoolConfig();
|
private GenericKeyedObjectPoolConfig<TcpClient> tcpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||||
|
|
||||||
private int numTcpPools = 1;
|
private int numTcpPools = 1;
|
||||||
|
|
||||||
private int tcpBufferSize = -1;
|
private int tcpBufferSize = -1;
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig getUdpClientPool() {
|
public GenericKeyedObjectPoolConfig<UdpClient> getUdpClientPool() {
|
||||||
return udpClientPool;
|
return udpClientPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig getTcpClientPool() {
|
public GenericKeyedObjectPoolConfig<TcpClient> getTcpClientPool() {
|
||||||
return tcpClientPool;
|
return tcpClientPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,26 @@ import javax.validation.Valid;
|
|||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||||
import timely.configuration.Websocket;
|
import timely.configuration.Websocket;
|
||||||
|
|
||||||
public class BalancerWebsocket extends Websocket {
|
public class BalancerWebsocket extends Websocket {
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@NestedConfigurationProperty
|
@NestedConfigurationProperty
|
||||||
private GenericKeyedObjectPoolConfig wsClientPool = new GenericKeyedObjectPoolConfig();
|
private GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> wsClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||||
|
|
||||||
public GenericKeyedObjectPoolConfig getWsClientPool() {
|
public GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> getWsClientPool() {
|
||||||
return wsClientPool;
|
return wsClientPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int incomingBufferSize = 50000000;
|
||||||
|
|
||||||
|
public int getIncomingBufferSize() {
|
||||||
|
return incomingBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIncomingBufferSize(int incomingBufferSize) {
|
||||||
|
this.incomingBufferSize = incomingBufferSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@ public class ClientSsl {
|
|||||||
private String trustStoreFile;
|
private String trustStoreFile;
|
||||||
private String trustStoreType;
|
private String trustStoreType;
|
||||||
private String trustStorePassword;
|
private String trustStorePassword;
|
||||||
|
private boolean useClientCert = true;
|
||||||
|
private boolean hostVerificationEnabled = true;
|
||||||
|
|
||||||
public String getKeyFile() {
|
public String getKeyFile() {
|
||||||
return keyFile;
|
return keyFile;
|
||||||
@@ -55,6 +57,21 @@ public class ClientSsl {
|
|||||||
|
|
||||||
public void setTrustStorePassword(String trustStorePassword) {
|
public void setTrustStorePassword(String trustStorePassword) {
|
||||||
this.trustStorePassword = trustStorePassword;
|
this.trustStorePassword = trustStorePassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseClientCert(boolean useClientCert) {
|
||||||
|
this.useClientCert = useClientCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseClientCert() {
|
||||||
|
return useClientCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHostVerificationEnabled(boolean hostVerificationEnabled) {
|
||||||
|
this.hostVerificationEnabled = hostVerificationEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHostVerificationEnabled() {
|
||||||
|
return hostVerificationEnabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
package timely.balancer.configuration;
|
package timely.balancer.configuration;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
public class ZooKeeper {
|
public class ZooKeeper {
|
||||||
|
|
||||||
private String servers;
|
private String servers;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String timeout = "120s";
|
||||||
|
|
||||||
public String getServers() {
|
public String getServers() {
|
||||||
return servers;
|
return servers;
|
||||||
}
|
}
|
||||||
@@ -11,4 +16,12 @@ public class ZooKeeper {
|
|||||||
public void setServers(String servers) {
|
public void setServers(String servers) {
|
||||||
this.servers = servers;
|
this.servers = servers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTimeout() {
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeout(String timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,12 +8,9 @@ import org.slf4j.LoggerFactory;
|
|||||||
import timely.balancer.ArrivalRate;
|
import timely.balancer.ArrivalRate;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
|
|
||||||
import java.util.Timer;
|
|
||||||
|
|
||||||
public class TimelyBalancedHost {
|
public class TimelyBalancedHost {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TimelyBalancedHost.class);
|
private static final Logger LOG = LoggerFactory.getLogger(TimelyBalancedHost.class);
|
||||||
static private Timer arrivalRateTimer = new Timer("ArrivalRateTimerTBH", true);
|
|
||||||
|
|
||||||
private String host;
|
private String host;
|
||||||
private int tcpPort;
|
private int tcpPort;
|
||||||
@@ -24,34 +21,29 @@ public class TimelyBalancedHost {
|
|||||||
private BalancerConfiguration balancerConfig;
|
private BalancerConfiguration balancerConfig;
|
||||||
private int failures = 0;
|
private int failures = 0;
|
||||||
private int successes = 0;
|
private int successes = 0;
|
||||||
private ArrivalRate arrivalRate = new ArrivalRate(arrivalRateTimer);
|
private ArrivalRate arrivalRate = null;
|
||||||
|
|
||||||
public TimelyBalancedHost() {
|
private TimelyBalancedHost() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelyBalancedHost(String host, int tcpPort, int httpPort, int wsPort, int udpPort) {
|
private TimelyBalancedHost(String host, int tcpPort, int httpPort, int wsPort, int udpPort,
|
||||||
|
ArrivalRate arrivalRate) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.tcpPort = tcpPort;
|
this.tcpPort = tcpPort;
|
||||||
this.httpPort = httpPort;
|
this.httpPort = httpPort;
|
||||||
this.wsPort = wsPort;
|
this.wsPort = wsPort;
|
||||||
this.udpPort = udpPort;
|
this.udpPort = udpPort;
|
||||||
|
this.arrivalRate = arrivalRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelyBalancedHost(String host, int basePort) {
|
static public TimelyBalancedHost of(String host, int tcpPort, int httpPort, int wsPort, int udpPort,
|
||||||
this.host = host;
|
ArrivalRate arrivalRate) {
|
||||||
this.tcpPort = basePort;
|
return new TimelyBalancedHost(host, tcpPort, httpPort, wsPort, udpPort, arrivalRate);
|
||||||
this.httpPort = basePort + 1;
|
|
||||||
this.wsPort = basePort + 2;
|
|
||||||
this.udpPort = basePort + 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static public TimelyBalancedHost of(String host, int tcpPort, int httpPort, int wsPort, int udpPort) {
|
|
||||||
return new TimelyBalancedHost(host, tcpPort, httpPort, wsPort, udpPort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public TimelyBalancedHost of(String host, int basePort) {
|
static public TimelyBalancedHost of(String host, int basePort) {
|
||||||
return new TimelyBalancedHost(host, basePort);
|
return new TimelyBalancedHost(host, basePort, basePort + 1, basePort + 2, basePort + 3, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBalancerConfig(BalancerConfiguration balancerConfig) {
|
public void setBalancerConfig(BalancerConfiguration balancerConfig) {
|
||||||
@@ -141,11 +133,17 @@ public class TimelyBalancedHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void arrived() {
|
public void arrived() {
|
||||||
arrivalRate.arrived();
|
if (this.arrivalRate != null) {
|
||||||
|
this.arrivalRate.arrived();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getArrivalRate() {
|
public double getArrivalRate() {
|
||||||
return arrivalRate.getRate();
|
if (this.arrivalRate == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return this.arrivalRate.getRate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -186,4 +184,11 @@ public class TimelyBalancedHost {
|
|||||||
builder.append(isUp);
|
builder.append(isUp);
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toStringShort(TimelyBalancedHost tbh) {
|
||||||
|
if (tbh == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tbh.host + ":" + tbh.tcpPort;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,22 +5,25 @@ import javax.net.ssl.SSLContext;
|
|||||||
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
import org.apache.commons.pool2.KeyedPooledObjectFactory;
|
||||||
import org.apache.commons.pool2.PooledObject;
|
import org.apache.commons.pool2.PooledObject;
|
||||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
import org.apache.http.impl.client.BasicCookieStore;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import timely.balancer.configuration.BalancerSecurity;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
|
||||||
public class HttpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, CloseableHttpClient> {
|
public class HttpClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, CloseableHttpClient> {
|
||||||
|
|
||||||
private final SSLContext sslContext;
|
private final SSLContext sslContext;
|
||||||
|
private final BalancerSecurity security;
|
||||||
|
|
||||||
public HttpClientFactory(SSLContext sslContext) {
|
public HttpClientFactory(BalancerSecurity security, SSLContext sslContext) {
|
||||||
|
this.security = security;
|
||||||
this.sslContext = sslContext;
|
this.sslContext = sslContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PooledObject<CloseableHttpClient> makeObject(TimelyBalancedHost k) throws Exception {
|
public PooledObject<CloseableHttpClient> makeObject(TimelyBalancedHost k) throws Exception {
|
||||||
BasicCookieStore cookieJar = new BasicCookieStore();
|
// disable cookie management because we are sharing connections
|
||||||
return new DefaultPooledObject<>(timely.client.http.HttpClient.get(this.sslContext, cookieJar, false));
|
return new DefaultPooledObject<>(timely.client.http.HttpClient.get(this.sslContext, null,
|
||||||
|
security.getClientSsl().isHostVerificationEnabled(), security.getClientSsl().isUseClientCert()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,16 +4,13 @@ import javax.net.ssl.SSLContext;
|
|||||||
|
|
||||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.slf4j.Logger;
|
import timely.balancer.configuration.BalancerHttp;
|
||||||
import org.slf4j.LoggerFactory;
|
import timely.balancer.configuration.BalancerSecurity;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
|
||||||
public class HttpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost, CloseableHttpClient> {
|
public class HttpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost, CloseableHttpClient> {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(HttpClientPool.class);
|
public HttpClientPool(BalancerSecurity balancerSecurity, BalancerHttp http, SSLContext sslContext) {
|
||||||
|
super(new HttpClientFactory(balancerSecurity, sslContext), http.getHttpClientPool());
|
||||||
public HttpClientPool(BalancerConfiguration config, SSLContext sslContext) {
|
|
||||||
super(new HttpClientFactory(sslContext), config.getHttp().getHttpClientPool());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,21 +12,21 @@ import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
|||||||
public class WsClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, WebSocketSubscriptionClient> {
|
public class WsClientFactory implements KeyedPooledObjectFactory<TimelyBalancedHost, WebSocketSubscriptionClient> {
|
||||||
|
|
||||||
private final SSLContext sslContext;
|
private final SSLContext sslContext;
|
||||||
private final boolean doLogin;
|
|
||||||
private BalancerConfiguration balancerConfig;
|
private BalancerConfiguration balancerConfig;
|
||||||
|
|
||||||
public WsClientFactory(BalancerConfiguration balancerConfig, SSLContext sslContext) {
|
public WsClientFactory(BalancerConfiguration balancerConfig, SSLContext sslContext) {
|
||||||
this.sslContext = sslContext;
|
|
||||||
this.doLogin = balancerConfig.isLoginRequired();
|
|
||||||
this.balancerConfig = balancerConfig;
|
this.balancerConfig = balancerConfig;
|
||||||
|
this.sslContext = sslContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PooledObject<WebSocketSubscriptionClient> makeObject(TimelyBalancedHost k) throws Exception {
|
public PooledObject<WebSocketSubscriptionClient> makeObject(TimelyBalancedHost k) throws Exception {
|
||||||
|
|
||||||
int bufferSize = balancerConfig.getWebsocket().getSubscriptionBatchSize() * 500;
|
int bufferSize = balancerConfig.getWebsocket().getIncomingBufferSize();
|
||||||
WebSocketSubscriptionClient client = new WebSocketSubscriptionClient(sslContext, k.getHost(), k.getHttpPort(),
|
WebSocketSubscriptionClient client = new WebSocketSubscriptionClient(sslContext, k.getHost(), k.getHttpPort(),
|
||||||
k.getWsPort(), doLogin, "", "", false, bufferSize);
|
k.getWsPort(), balancerConfig.getSecurity().getClientSsl().isUseClientCert(),
|
||||||
|
balancerConfig.isLoginRequired(), "", "",
|
||||||
|
balancerConfig.getSecurity().getClientSsl().isHostVerificationEnabled(), bufferSize);
|
||||||
return new DefaultPooledObject<>(client);
|
return new DefaultPooledObject<>(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,12 @@
|
|||||||
package timely.balancer.healthcheck;
|
package timely.balancer.healthcheck;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.tcp.TcpClientPool;
|
|
||||||
|
|
||||||
public class HealthChecker {
|
public interface HealthChecker {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(HealthChecker.class);
|
public void setTimelyHosts(List<TimelyBalancedHost> timelyHosts);
|
||||||
private List<TimelyBalancedHost> timelyHosts = new ArrayList<>();
|
|
||||||
private Timer timer;
|
|
||||||
final private TCPServerHealthCheck tcpServerHealthCheck;
|
|
||||||
private TimerTask check = new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
public void close() throws Exception;
|
||||||
public void run() {
|
|
||||||
synchronized (timelyHosts) {
|
|
||||||
for (TimelyBalancedHost h : timelyHosts) {
|
|
||||||
try {
|
|
||||||
if (tcpServerHealthCheck.isServerHealthy(h)) {
|
|
||||||
h.reportSuccess();
|
|
||||||
} else {
|
|
||||||
h.reportFailure();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
h.reportFailure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public HealthChecker(BalancerConfiguration config, TcpClientPool tcpClientPool) {
|
|
||||||
this.tcpServerHealthCheck = new TCPServerHealthCheck(tcpClientPool);
|
|
||||||
this.timer = new Timer("HealthCheckerThread", true);
|
|
||||||
this.timer.scheduleAtFixedRate(check, 0, config.getCheckServerHealthInterval());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimelyHosts(List<TimelyBalancedHost> timelyHosts) {
|
|
||||||
synchronized (timelyHosts) {
|
|
||||||
this.timelyHosts.clear();
|
|
||||||
this.timelyHosts.addAll(timelyHosts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package timely.balancer.healthcheck;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.balancer.connection.tcp.TcpClientPool;
|
||||||
|
|
||||||
|
public class TcpHealthChecker implements HealthChecker {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TcpHealthChecker.class);
|
||||||
|
private List<TimelyBalancedHost> timelyHosts = new ArrayList<>();
|
||||||
|
private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
|
||||||
|
final private TCPServerHealthCheck tcpServerHealthCheck;
|
||||||
|
|
||||||
|
public TcpHealthChecker(BalancerConfiguration config, TcpClientPool tcpClientPool) {
|
||||||
|
this.tcpServerHealthCheck = new TCPServerHealthCheck(tcpClientPool);
|
||||||
|
this.executorService.scheduleAtFixedRate(() -> {
|
||||||
|
synchronized (timelyHosts) {
|
||||||
|
for (TimelyBalancedHost h : timelyHosts) {
|
||||||
|
try {
|
||||||
|
if (tcpServerHealthCheck.isServerHealthy(h)) {
|
||||||
|
h.reportSuccess();
|
||||||
|
} else {
|
||||||
|
h.reportFailure();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
h.reportFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0, config.getCheckServerHealthInterval(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTimelyHosts(List<TimelyBalancedHost> timelyHosts) {
|
||||||
|
synchronized (timelyHosts) {
|
||||||
|
this.timelyHosts.clear();
|
||||||
|
this.timelyHosts.addAll(timelyHosts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws Exception {
|
||||||
|
this.executorService.shutdown();
|
||||||
|
try {
|
||||||
|
this.executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!this.executorService.isTerminated()) {
|
||||||
|
this.executorService.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package timely.balancer.netty.http;
|
package timely.balancer.netty.http;
|
||||||
|
|
||||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
|
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -12,6 +11,7 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
@@ -33,26 +33,26 @@ import org.apache.http.message.BasicHeader;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
|
import timely.api.request.AuthenticatedRequest;
|
||||||
import timely.api.request.MetricRequest;
|
import timely.api.request.MetricRequest;
|
||||||
import timely.api.request.timeseries.HttpRequest;
|
import timely.api.request.timeseries.HttpRequest;
|
||||||
import timely.api.request.timeseries.QueryRequest;
|
import timely.api.request.timeseries.QueryRequest;
|
||||||
import timely.api.response.TimelyException;
|
import timely.api.response.TimelyException;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
import timely.auth.util.HttpHeaderUtils;
|
||||||
|
import timely.auth.util.ProxiedEntityUtils;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.http.HttpClientPool;
|
import timely.balancer.connection.http.HttpClientPool;
|
||||||
import timely.balancer.resolver.MetricResolver;
|
import timely.balancer.resolver.MetricResolver;
|
||||||
import timely.netty.http.TimelyHttpHandler;
|
import timely.netty.http.TimelyHttpHandler;
|
||||||
|
import timely.netty.http.auth.TimelyAuthenticationToken;
|
||||||
|
|
||||||
public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> implements TimelyHttpHandler {
|
public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> implements TimelyHttpHandler {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(HttpRelayHandler.class);
|
private static final Logger LOG = LoggerFactory.getLogger(HttpRelayHandler.class);
|
||||||
private final BalancerConfiguration balancerConf;
|
|
||||||
private final HttpClientPool httpClientPool;
|
private final HttpClientPool httpClientPool;
|
||||||
private MetricResolver metricResolver;
|
private MetricResolver metricResolver;
|
||||||
|
|
||||||
public HttpRelayHandler(BalancerConfiguration balancerConf, MetricResolver metricResolver,
|
public HttpRelayHandler(MetricResolver metricResolver, HttpClientPool httpClientPool) {
|
||||||
HttpClientPool httpClientPool) {
|
|
||||||
this.balancerConf = balancerConf;
|
|
||||||
this.metricResolver = metricResolver;
|
this.metricResolver = metricResolver;
|
||||||
this.httpClientPool = httpClientPool;
|
this.httpClientPool = httpClientPool;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
request = msg.getHttpRequest();
|
request = msg.getHttpRequest();
|
||||||
String originalURI = request.getUri();
|
String originalURI = request.uri();
|
||||||
originalURI = encodeURI(originalURI);
|
originalURI = encodeURI(originalURI);
|
||||||
|
|
||||||
String metric = null;
|
String metric = null;
|
||||||
@@ -86,14 +86,22 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
} else {
|
} else {
|
||||||
k = metricResolver.getHostPortKey(null);
|
k = metricResolver.getHostPortKey(null);
|
||||||
}
|
}
|
||||||
k = metricResolver.getHostPortKey(metric);
|
|
||||||
client = httpClientPool.borrowObject(k);
|
client = httpClientPool.borrowObject(k);
|
||||||
|
|
||||||
List<Map.Entry<String, String>> headerList = request.headers().entries();
|
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(request.headers());
|
||||||
List<Header> relayedHeaderList = new ArrayList<>();
|
if (msg instanceof AuthenticatedRequest) {
|
||||||
|
AuthenticatedRequest authenticatedRequest = (AuthenticatedRequest) msg;
|
||||||
|
TimelyAuthenticationToken token = authenticatedRequest.getToken();
|
||||||
|
if (token != null) {
|
||||||
|
if (token.getClientCert() != null) {
|
||||||
|
ProxiedEntityUtils.addProxyHeaders(headers, token.getClientCert());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, String> h : headerList) {
|
List<Header> relayedHeaderList = new ArrayList<>();
|
||||||
if (!h.getKey().equals(CONTENT_LENGTH)) {
|
for (Map.Entry<String, String> h : headers.entries()) {
|
||||||
|
if (!h.getKey().equals(CONTENT_LENGTH.toString())) {
|
||||||
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
|
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,14 +109,14 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
relayedHeaderList.toArray(headerArray);
|
relayedHeaderList.toArray(headerArray);
|
||||||
|
|
||||||
String relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
|
String relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
|
||||||
if (request.getMethod().equals(HttpMethod.GET)) {
|
if (request.method().equals(HttpMethod.GET)) {
|
||||||
HttpUriRequest relayedRequest = new HttpGet(relayURI);
|
HttpUriRequest relayedRequest = new HttpGet(relayURI);
|
||||||
if (headerArray.length > 0) {
|
if (headerArray.length > 0) {
|
||||||
relayedRequest.setHeaders(headerArray);
|
relayedRequest.setHeaders(headerArray);
|
||||||
}
|
}
|
||||||
relayedResponse = client.execute(relayedRequest);
|
relayedResponse = client.execute(relayedRequest);
|
||||||
|
|
||||||
} else if (request.getMethod().equals(HttpMethod.POST)) {
|
} else if (request.method().equals(HttpMethod.POST)) {
|
||||||
HttpPost relayedRequest = new HttpPost(relayURI);
|
HttpPost relayedRequest = new HttpPost(relayURI);
|
||||||
|
|
||||||
String content = request.content().toString(StandardCharsets.UTF_8);
|
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||||
@@ -143,7 +151,6 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
|
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
|
||||||
"Method not allowed", "Method not allowed"));
|
"Method not allowed", "Method not allowed"));
|
||||||
} else {
|
} else {
|
||||||
// buf = JsonUtil.getObjectMapper().writeValueAsBytes(msg);
|
|
||||||
ByteArrayOutputStream baos = new MyByteArrayOutputStream();
|
ByteArrayOutputStream baos = new MyByteArrayOutputStream();
|
||||||
StreamUtils.copy(relayedResponse.getEntity().getContent(), baos);
|
StreamUtils.copy(relayedResponse.getEntity().getContent(), baos);
|
||||||
|
|
||||||
@@ -153,8 +160,6 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
for (Header h : relayedResponse.getAllHeaders()) {
|
for (Header h : relayedResponse.getAllHeaders()) {
|
||||||
response.headers().add(h.getName(), h.getValue());
|
response.headers().add(h.getName(), h.getValue());
|
||||||
}
|
}
|
||||||
// response.headers().set(HttpHeaders.Names.CONTENT_TYPE,
|
|
||||||
// Constants.JSON_TYPE);
|
|
||||||
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
||||||
sendResponse(ctx, response);
|
sendResponse(ctx, response);
|
||||||
}
|
}
|
||||||
@@ -165,7 +170,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
if (client != null && k != null) {
|
if (client != null && k != null) {
|
||||||
httpClientPool.returnObject(k, client);
|
httpClientPool.returnObject(k, client);
|
||||||
} else {
|
} else {
|
||||||
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().getUri());
|
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,13 +202,4 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
String s = "https://127.0.0.1:4243/api/query?start=1356998400000&end=1528398304000&m=sum:rate{false,100,0}:sys.thermal.gauge{class=aws}";
|
|
||||||
URI uri = URI.create(encodeURI(s));
|
|
||||||
|
|
||||||
System.out.println(uri.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
package timely.balancer.netty.ws;
|
package timely.balancer.netty.ws;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
import javax.websocket.MessageHandler;
|
|
||||||
import javax.websocket.Session;
|
import javax.websocket.Session;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
|
||||||
@@ -15,25 +19,48 @@ import io.netty.util.concurrent.ScheduledFuture;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import timely.api.response.TimelyException;
|
import timely.api.response.TimelyException;
|
||||||
|
import timely.auth.util.ProxiedEntityUtils;
|
||||||
import timely.client.websocket.ClientHandler;
|
import timely.client.websocket.ClientHandler;
|
||||||
|
import timely.netty.http.auth.TimelyAuthenticationToken;
|
||||||
|
|
||||||
public class WsClientHandler extends ClientHandler {
|
public class WsClientHandler extends ClientHandler {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(WsClientHandler.class);
|
private static final Logger LOG = LoggerFactory.getLogger(WsClientHandler.class);
|
||||||
private final ChannelHandlerContext ctx;
|
private final ChannelHandlerContext ctx;
|
||||||
|
private final TimelyAuthenticationToken token;
|
||||||
private ScheduledFuture<?> ping;
|
private ScheduledFuture<?> ping;
|
||||||
|
|
||||||
public WsClientHandler(ChannelHandlerContext ctx, int pingRate) {
|
public WsClientHandler(ChannelHandlerContext ctx, TimelyAuthenticationToken token, int pingRate) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
|
this.token = token;
|
||||||
this.ping = this.ctx.executor().scheduleAtFixedRate(() -> {
|
this.ping = this.ctx.executor().scheduleAtFixedRate(() -> {
|
||||||
LOG.trace("Sending ping on channel {}", ctx.channel());
|
LOG.trace("Sending ping on channel {}", ctx.channel());
|
||||||
ctx.writeAndFlush(new PingWebSocketFrame());
|
ctx.writeAndFlush(new PingWebSocketFrame());
|
||||||
}, pingRate, pingRate, TimeUnit.SECONDS);
|
}, pingRate, pingRate, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeRequest(Map<String, List<String>> headers) {
|
||||||
|
if (token.getClientCert() != null) {
|
||||||
|
Multimap<String, String> proxyRequestHeaders = HashMultimap.create();
|
||||||
|
ProxiedEntityUtils.addProxyHeaders(proxyRequestHeaders, token.getClientCert());
|
||||||
|
for (String s : proxyRequestHeaders.keySet()) {
|
||||||
|
headers.put(s, new ArrayList<>(proxyRequestHeaders.get(s)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Multimap<String, String> originalRequestHeaders = token.getHttpHeaders();
|
||||||
|
for (String s : originalRequestHeaders.keySet()) {
|
||||||
|
if (!headers.containsKey(s)) {
|
||||||
|
// add pre-existing values if key does not exist in proxyRequest
|
||||||
|
headers.put(s, new ArrayList<>(originalRequestHeaders.get(s)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(Session session, EndpointConfig config) {
|
public void onOpen(Session session, EndpointConfig config) {
|
||||||
session.addMessageHandler((MessageHandler.Whole<String>) message -> {
|
session.addMessageHandler(String.class, message -> {
|
||||||
ctx.writeAndFlush(new TextWebSocketFrame(message));
|
ctx.writeAndFlush(new TextWebSocketFrame(message));
|
||||||
LOG.debug("Message received on Websocket session {}: {}", session.getId(), message);
|
LOG.debug("Message received on Websocket session {}: {}", session.getId(), message);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
@@ -24,6 +25,7 @@ import timely.api.request.subscription.CreateSubscription;
|
|||||||
import timely.api.request.subscription.RemoveSubscription;
|
import timely.api.request.subscription.RemoveSubscription;
|
||||||
import timely.api.request.subscription.SubscriptionRequest;
|
import timely.api.request.subscription.SubscriptionRequest;
|
||||||
import timely.api.response.TimelyException;
|
import timely.api.response.TimelyException;
|
||||||
|
import timely.auth.util.ProxiedEntityUtils;
|
||||||
import timely.balancer.configuration.BalancerConfiguration;
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.connection.ws.WsClientPool;
|
import timely.balancer.connection.ws.WsClientPool;
|
||||||
@@ -64,6 +66,10 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
String subscriptionId;
|
String subscriptionId;
|
||||||
try {
|
try {
|
||||||
String metric = null;
|
String metric = null;
|
||||||
|
|
||||||
|
Multimap<String, String> headers = msg.getRequestHeaders();
|
||||||
|
ProxiedEntityUtils.addProxyHeaders(headers, msg.getToken().getClientCert());
|
||||||
|
|
||||||
if (msg instanceof CreateSubscription) {
|
if (msg instanceof CreateSubscription) {
|
||||||
CreateSubscription create = (CreateSubscription) msg;
|
CreateSubscription create = (CreateSubscription) msg;
|
||||||
final String currentSubscriptionId = create.getSubscriptionId();
|
final String currentSubscriptionId = create.getSubscriptionId();
|
||||||
@@ -118,7 +124,8 @@ public class WsRelayHandler extends SimpleChannelInboundHandler<SubscriptionRequ
|
|||||||
if (hostClientHolder == null) {
|
if (hostClientHolder == null) {
|
||||||
k = metricResolver.getHostPortKey(metric);
|
k = metricResolver.getHostPortKey(metric);
|
||||||
client = wsClientPool.borrowObject(k);
|
client = wsClientPool.borrowObject(k);
|
||||||
client.open(new WsClientHandler(origContext, (balancerConfig.getWebsocket().getTimeout() / 2)));
|
client.open(new WsClientHandler(origContext, add.getToken(),
|
||||||
|
(balancerConfig.getWebsocket().getTimeout() / 2)));
|
||||||
metricToClientMap.put(metric, new WsClientHolder(k, client));
|
metricToClientMap.put(metric, new WsClientHolder(k, client));
|
||||||
} else {
|
} else {
|
||||||
client = hostClientHolder.getClient();
|
client = hostClientHolder.getClient();
|
||||||
|
|||||||
@@ -4,8 +4,14 @@ import static timely.Server.SERVICE_DISCOVERY_PATH;
|
|||||||
import static timely.balancer.Balancer.ASSIGNMENTS_LAST_UPDATED_PATH;
|
import static timely.balancer.Balancer.ASSIGNMENTS_LAST_UPDATED_PATH;
|
||||||
import static timely.balancer.Balancer.ASSIGNMENTS_LOCK_PATH;
|
import static timely.balancer.Balancer.ASSIGNMENTS_LOCK_PATH;
|
||||||
import static timely.balancer.Balancer.LEADER_LATCH_PATH;
|
import static timely.balancer.Balancer.LEADER_LATCH_PATH;
|
||||||
|
import static timely.balancer.resolver.eventing.MetricAssignedEvent.Reason.ASSIGN_FALLBACK_SEQUENTIAL;
|
||||||
|
import static timely.balancer.resolver.eventing.MetricAssignedEvent.Reason.ASSIGN_ROUND_ROBIN;
|
||||||
|
import static timely.balancer.resolver.eventing.MetricAssignedEvent.Reason.HOST_DOWN_ROUND_ROBIN;
|
||||||
|
import static timely.balancer.resolver.eventing.MetricAssignedEvent.Reason.HOST_REMOVED;
|
||||||
|
import static timely.balancer.resolver.eventing.MetricAssignedEvent.Reason.REBALANCE;
|
||||||
|
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS;
|
||||||
|
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS_LOCK_PATH;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -17,20 +23,19 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
import com.csvreader.CsvReader;
|
|
||||||
import com.csvreader.CsvWriter;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.curator.RetryPolicy;
|
import org.apache.commons.lang3.SerializationUtils;
|
||||||
import org.apache.curator.framework.CuratorFramework;
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
import org.apache.curator.framework.recipes.atomic.DistributedAtomicValue;
|
||||||
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
|
|
||||||
import org.apache.curator.framework.recipes.cache.TreeCache;
|
import org.apache.curator.framework.recipes.cache.TreeCache;
|
||||||
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
|
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
|
||||||
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
|
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
|
||||||
@@ -38,18 +43,13 @@ import org.apache.curator.framework.recipes.leader.LeaderLatch;
|
|||||||
import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
|
import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
|
||||||
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
|
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
|
||||||
import org.apache.curator.framework.state.ConnectionState;
|
import org.apache.curator.framework.state.ConnectionState;
|
||||||
import org.apache.curator.retry.RetryUntilElapsed;
|
import org.apache.curator.retry.RetryForever;
|
||||||
import org.apache.curator.x.discovery.ServiceCache;
|
import org.apache.curator.x.discovery.ServiceCache;
|
||||||
import org.apache.curator.x.discovery.ServiceDiscovery;
|
import org.apache.curator.x.discovery.ServiceDiscovery;
|
||||||
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
|
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
|
||||||
import org.apache.curator.x.discovery.ServiceInstance;
|
import org.apache.curator.x.discovery.ServiceInstance;
|
||||||
import org.apache.curator.x.discovery.details.ServiceCacheListener;
|
import org.apache.curator.x.discovery.details.ServiceCacheListener;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.zookeeper.CreateMode;
|
||||||
import org.apache.hadoop.fs.FSDataInputStream;
|
|
||||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
|
||||||
import org.apache.hadoop.fs.Path;
|
|
||||||
import org.apache.zookeeper.data.Stat;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import timely.ServerDetails;
|
import timely.ServerDetails;
|
||||||
@@ -57,136 +57,184 @@ import timely.balancer.ArrivalRate;
|
|||||||
import timely.balancer.configuration.BalancerConfiguration;
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
import timely.balancer.connection.TimelyBalancedHost;
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
import timely.balancer.healthcheck.HealthChecker;
|
import timely.balancer.healthcheck.HealthChecker;
|
||||||
|
import timely.balancer.resolver.eventing.MetricAssignedCallback;
|
||||||
|
import timely.balancer.resolver.eventing.MetricAssignedEvent;
|
||||||
|
import timely.balancer.resolver.eventing.MetricBalanceCallback;
|
||||||
|
import timely.balancer.resolver.eventing.MetricBalanceEvent;
|
||||||
|
import timely.balancer.resolver.eventing.MetricHostCallback;
|
||||||
|
import timely.balancer.resolver.eventing.MetricHostEvent;
|
||||||
|
|
||||||
public class BalancedMetricResolver implements MetricResolver {
|
public class BalancedMetricResolver implements MetricResolver {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(BalancedMetricResolver.class);
|
private static final Logger LOG = LoggerFactory.getLogger(BalancedMetricResolver.class);
|
||||||
private Map<String, TimelyBalancedHost> metricToHostMap = new TreeMap<>();
|
private Map<String, TimelyBalancedHost> metricToHostMap = new TreeMap<>();
|
||||||
|
private Set<String> unassignedMetrics = new HashSet<>();
|
||||||
private Map<String, ArrivalRate> metricMap = new HashMap<>();
|
private Map<String, ArrivalRate> metricMap = new HashMap<>();
|
||||||
private ReentrantReadWriteLock balancerLock = new ReentrantReadWriteLock();
|
private ReentrantReadWriteLock balancerLock = new ReentrantReadWriteLock();
|
||||||
private List<TimelyBalancedHost> serverList = new ArrayList<>();
|
private List<TimelyBalancedHost> serverList = new ArrayList<>();
|
||||||
private Random r = new Random();
|
private Random r = new Random();
|
||||||
final private HealthChecker healthChecker;
|
private final HealthChecker healthChecker;
|
||||||
private Timer timer = new Timer("RebalanceTimer", true);
|
private ScheduledExecutorService assignmentExecutor = Executors.newScheduledThreadPool(2);
|
||||||
private Timer arrivalRateTimer = new Timer("AriivalRateTimerResolver", true);
|
private ScheduledExecutorService arrivalRateExecutor = Executors.newScheduledThreadPool(2);
|
||||||
private int roundRobinCounter = 0;
|
private int roundRobinCounter = 0;
|
||||||
private Set<String> nonCachedMetrics = new HashSet<>();
|
private Set<String> nonCachedMetrics = new HashSet<>();
|
||||||
private ReentrantReadWriteLock nonCachedMetricsLock = new ReentrantReadWriteLock();
|
private DistributedAtomicValue nonCachedMetricsIP;
|
||||||
private BalancerConfiguration balancerConfig;
|
private ReentrantReadWriteLock nonCachedMetricsLocalLock = new ReentrantReadWriteLock();
|
||||||
private CuratorFramework curatorFramework;
|
private InterProcessReadWriteLock nonCachedMetricsIPRWLock;
|
||||||
private RetryPolicy retryPolicy = new RetryUntilElapsed(60000, 1000);
|
private AtomicLong assignmentsLastUpdatedLocal = new AtomicLong(0);
|
||||||
private LeaderLatch leaderLatch;
|
private LeaderLatch leaderLatch;
|
||||||
private AtomicBoolean isLeader = new AtomicBoolean(false);
|
private AtomicBoolean isLeader = new AtomicBoolean(false);
|
||||||
private InterProcessReadWriteLock assignmentsLock;
|
private InterProcessReadWriteLock assignmentsIPRWLock;
|
||||||
private DistributedAtomicLong assignmentsLastUpdatedInHdfs;
|
private MetricAssignmentPerister assignmentPerister;
|
||||||
private AtomicLong assignmentsLastUpdatedLocal = new AtomicLong(0);
|
|
||||||
|
|
||||||
private String[] zkPaths = new String[] { LEADER_LATCH_PATH, ASSIGNMENTS_LAST_UPDATED_PATH, ASSIGNMENTS_LOCK_PATH,
|
final private BalancerConfiguration balancerConfig;
|
||||||
SERVICE_DISCOVERY_PATH };
|
final private CuratorFramework curatorFramework;
|
||||||
|
|
||||||
private enum BalanceType {
|
private List<MetricAssignedCallback> metricAssignedCallbacks = new ArrayList<>();
|
||||||
|
private List<MetricBalanceCallback> metricBalanceCallbacks = new ArrayList<>();
|
||||||
|
private List<MetricHostCallback> metricHostCallbacks = new ArrayList<>();
|
||||||
|
|
||||||
|
public enum BalanceType {
|
||||||
HIGH_LOW, HIGH_AVG, AVG_LOW;
|
HIGH_LOW, HIGH_AVG, AVG_LOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BalancedMetricResolver(BalancerConfiguration balancerConfig, HealthChecker healthChecker) {
|
public BalancedMetricResolver(CuratorFramework curatorFramework, BalancerConfiguration balancerConfig,
|
||||||
|
HealthChecker healthChecker) {
|
||||||
|
this.curatorFramework = curatorFramework;
|
||||||
this.balancerConfig = balancerConfig;
|
this.balancerConfig = balancerConfig;
|
||||||
this.healthChecker = healthChecker;
|
this.healthChecker = healthChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
assignmentsIPRWLock = new InterProcessReadWriteLock(curatorFramework, ASSIGNMENTS_LOCK_PATH);
|
||||||
|
testIPRWLock(curatorFramework, assignmentsIPRWLock, ASSIGNMENTS_LOCK_PATH);
|
||||||
|
|
||||||
|
this.assignmentPerister = new MetricAssignmentPerister(this, balancerConfig, metricToHostMap, nonCachedMetrics,
|
||||||
|
curatorFramework, assignmentsIPRWLock, nonCachedMetricsLocalLock, assignmentsLastUpdatedLocal,
|
||||||
|
balancerLock);
|
||||||
|
|
||||||
// start curator framework
|
|
||||||
curatorFramework = CuratorFrameworkFactory.newClient(balancerConfig.getZooKeeper().getServers(), 30000, 1000,
|
|
||||||
retryPolicy);
|
|
||||||
curatorFramework.start();
|
|
||||||
ensureZkPaths(curatorFramework, zkPaths);
|
|
||||||
assignmentsLock = new InterProcessReadWriteLock(curatorFramework, ASSIGNMENTS_LOCK_PATH);
|
|
||||||
startLeaderLatch(curatorFramework);
|
startLeaderLatch(curatorFramework);
|
||||||
startServiceListener(curatorFramework);
|
startServiceListener(curatorFramework);
|
||||||
assignmentsLastUpdatedInHdfs = new DistributedAtomicLong(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH,
|
|
||||||
retryPolicy);
|
|
||||||
|
|
||||||
TreeCacheListener listener = new TreeCacheListener() {
|
TreeCacheListener assignmentListener = (curatorFramework1, event) -> {
|
||||||
|
LOG.debug("Handling assignments event {}. assignmentsLastUpdated:{}", event.getType().toString(),
|
||||||
@Override
|
new Date(assignmentPerister.getAssignmentsLastUpdatedByLeader()));
|
||||||
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
|
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
||||||
LOG.info("Handling event {}. assignmentsLastUpdatedInHdfs:{}", event.getType().toString(),
|
assignmentPerister.readAssignments(true);
|
||||||
new Date(assignmentsLastUpdatedInHdfs.get().postValue()));
|
|
||||||
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
|
||||||
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
|
||||||
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
|
||||||
if (lastHdfsUpdate > lastLocalUpdate) {
|
|
||||||
LOG.info("Reading assignments from hdfs lastHdfsUpdate ({}) > lastLocalUpdate ({})",
|
|
||||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
|
||||||
readAssignmentsFromHdfs();
|
|
||||||
} else {
|
|
||||||
LOG.info("Not reading assignments from hdfs lastHdfsUpdate ({}) <= lastLocalUpdate ({})",
|
|
||||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try (TreeCache assignmentTreeCache = new TreeCache(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH)) {
|
||||||
TreeCache treeCache = new TreeCache(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH);
|
assignmentTreeCache.getListenable().addListener(assignmentListener);
|
||||||
treeCache.getListenable().addListener(listener);
|
assignmentTreeCache.start();
|
||||||
treeCache.start();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
nonCachedMetricsLock.writeLock().lock();
|
nonCachedMetricsIPRWLock = new InterProcessReadWriteLock(curatorFramework, NON_CACHED_METRICS_LOCK_PATH);
|
||||||
try {
|
testIPRWLock(curatorFramework, nonCachedMetricsIPRWLock, NON_CACHED_METRICS_LOCK_PATH);
|
||||||
nonCachedMetrics.addAll(balancerConfig.getCache().getNonCachedMetrics());
|
nonCachedMetricsIP = new DistributedAtomicValue(curatorFramework, NON_CACHED_METRICS, new RetryForever(1000));
|
||||||
} finally {
|
TreeCacheListener nonCachedMetricsListener = new TreeCacheListener() {
|
||||||
nonCachedMetricsLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
readAssignmentsFromHdfs();
|
|
||||||
|
|
||||||
timer.schedule(new TimerTask() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent event) throws Exception {
|
||||||
if (isLeader.get()) {
|
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
||||||
try {
|
LOG.debug("Handling nonCachedMetricsIP event {}", event.getType().toString());
|
||||||
balance();
|
readNonCachedMetricsIP();
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 900000, 900000);
|
};
|
||||||
|
|
||||||
timer.schedule(new TimerTask() {
|
try (TreeCache nonCachedMetricsTreeCache = new TreeCache(curatorFramework, NON_CACHED_METRICS)) {
|
||||||
|
nonCachedMetricsTreeCache.getListenable().addListener(nonCachedMetricsListener);
|
||||||
|
nonCachedMetricsTreeCache.start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
nonCachedMetricsLocalLock.writeLock().lock();
|
||||||
public void run() {
|
try {
|
||||||
|
addNonCachedMetrics(balancerConfig.getCache().getNonCachedMetrics());
|
||||||
|
} finally {
|
||||||
|
nonCachedMetricsLocalLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
readNonCachedMetricsIP();
|
||||||
|
|
||||||
|
assignmentPerister.readAssignments(false);
|
||||||
|
|
||||||
|
assignmentExecutor.scheduleAtFixedRate(() -> {
|
||||||
|
if (isLeader.get()) {
|
||||||
try {
|
try {
|
||||||
if (isLeader.get()) {
|
balance();
|
||||||
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
|
||||||
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
|
||||||
if (lastLocalUpdate > lastHdfsUpdate) {
|
|
||||||
LOG.info("Writing assignments to hdfs lastLocalUpdate ({}) > lastHdfsUpdate ({})",
|
|
||||||
new Date(lastLocalUpdate), new Date(lastHdfsUpdate));
|
|
||||||
writeAssigmentsToHdfs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error(e.getMessage(), e);
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 10000, 60000);
|
}, balancerConfig.getBalanceDelay(), balancerConfig.getBalancePeriod(), TimeUnit.MILLISECONDS);
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureZkPaths(CuratorFramework curatorFramework, String[] paths) {
|
assignmentExecutor.scheduleAtFixedRate(() -> {
|
||||||
for (String s : paths) {
|
|
||||||
try {
|
try {
|
||||||
Stat stat = curatorFramework.checkExists().forPath(s);
|
if (isLeader.get()) {
|
||||||
if (stat == null) {
|
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
||||||
curatorFramework.create().creatingParentContainersIfNeeded().forPath(s);
|
long lastUpdateByLeader = assignmentPerister.getAssignmentsLastUpdatedByLeader();
|
||||||
|
if (lastLocalUpdate > lastUpdateByLeader) {
|
||||||
|
LOG.debug("Leader writing assignments lastLocalUpdate ({}) > lastUpdateByLeader ({})",
|
||||||
|
new Date(lastLocalUpdate), new Date(lastUpdateByLeader));
|
||||||
|
assignmentPerister.writeAssignments();
|
||||||
|
} else {
|
||||||
|
LOG.trace("Leader not writing assignments lastLocalUpdate ({}) <= lastUpdateByLeader ({})",
|
||||||
|
new Date(lastLocalUpdate), new Date(lastUpdateByLeader));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assignmentPerister.readAssignments(true);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.info(e.getMessage());
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
}, balancerConfig.getPersistDelay(), balancerConfig.getPersistPeriod(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readNonCachedMetricsIP() {
|
||||||
|
|
||||||
|
Set<String> currentNonCachedMetricsDistributed = new TreeSet<>();
|
||||||
|
try {
|
||||||
|
boolean acquired = false;
|
||||||
|
while (!acquired) {
|
||||||
|
acquired = nonCachedMetricsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
|
||||||
|
if (currentNonCachedMetricsDistributedBytes != null) {
|
||||||
|
try {
|
||||||
|
currentNonCachedMetricsDistributed = SerializationUtils
|
||||||
|
.deserialize(currentNonCachedMetricsDistributedBytes);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
currentNonCachedMetricsDistributed = new TreeSet<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
nonCachedMetricsIPRWLock.readLock().release();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonCachedMetricsLocalLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
if (nonCachedMetrics.containsAll(currentNonCachedMetricsDistributed)) {
|
||||||
|
LOG.debug("local nonCachedMetrics already contains {}", currentNonCachedMetricsDistributed);
|
||||||
|
} else {
|
||||||
|
currentNonCachedMetricsDistributed.removeAll(nonCachedMetrics);
|
||||||
|
LOG.debug("Adding {} to local nonCachedMetrics", currentNonCachedMetricsDistributed);
|
||||||
|
nonCachedMetrics.addAll(currentNonCachedMetricsDistributed);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
nonCachedMetricsLocalLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +249,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
public void isLeader() {
|
public void isLeader() {
|
||||||
LOG.info("this balancer is the leader");
|
LOG.info("this balancer is the leader");
|
||||||
isLeader.set(true);
|
isLeader.set(true);
|
||||||
writeAssigmentsToHdfs();
|
assignmentPerister.writeAssignments();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -217,28 +265,29 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
private void startServiceListener(CuratorFramework curatorFramework) {
|
private void startServiceListener(CuratorFramework curatorFramework) {
|
||||||
try {
|
try {
|
||||||
ServiceDiscovery discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
|
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
|
||||||
.basePath(SERVICE_DISCOVERY_PATH).build();
|
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
||||||
discovery.start();
|
discovery.start();
|
||||||
Collection<ServiceInstance> instances = discovery.queryForInstances("timely-server");
|
Collection<ServiceInstance<ServerDetails>> instances = discovery.queryForInstances("timely-server");
|
||||||
|
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
for (ServiceInstance si : instances) {
|
for (ServiceInstance<ServerDetails> si : instances) {
|
||||||
ServerDetails pl = (ServerDetails) si.getPayload();
|
ServerDetails pl = si.getPayload();
|
||||||
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(), pl.getHttpPort(),
|
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(), pl.getHttpPort(),
|
||||||
pl.getWsPort(), pl.getUdpPort());
|
pl.getWsPort(), pl.getUdpPort(), new ArrivalRate(arrivalRateExecutor));
|
||||||
LOG.info("adding service {} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}", si.getId(),
|
LOG.info("adding service {} host:{}", si.getId(), TimelyBalancedHost.toStringShort(tbh));
|
||||||
pl.getHost(), pl.getTcpPort(), pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort());
|
|
||||||
tbh.setBalancerConfig(balancerConfig);
|
tbh.setBalancerConfig(balancerConfig);
|
||||||
serverList.add(tbh);
|
serverList.add(tbh);
|
||||||
|
metricHostEvent(tbh, MetricHostEvent.ActionType.ADDED);
|
||||||
}
|
}
|
||||||
healthChecker.setTimelyHosts(serverList);
|
healthChecker.setTimelyHosts(serverList);
|
||||||
} finally {
|
} finally {
|
||||||
balancerLock.writeLock().unlock();
|
balancerLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
final ServiceCache serviceCache = discovery.serviceCacheBuilder().name("timely-server").build();
|
final ServiceCache<ServerDetails> serviceCache = discovery.serviceCacheBuilder().name("timely-server")
|
||||||
|
.build();
|
||||||
ServiceCacheListener listener = new ServiceCacheListener() {
|
ServiceCacheListener listener = new ServiceCacheListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -246,12 +295,13 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
boolean rebalanceNeeded = false;
|
boolean rebalanceNeeded = false;
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
List<ServiceInstance> instances = serviceCache.getInstances();
|
List<ServiceInstance<ServerDetails>> instances = serviceCache.getInstances();
|
||||||
Set<TimelyBalancedHost> availableHosts = new HashSet<>();
|
Set<TimelyBalancedHost> availableHosts = new HashSet<>();
|
||||||
for (ServiceInstance si : instances) {
|
for (ServiceInstance<ServerDetails> si : instances) {
|
||||||
ServerDetails pl = (ServerDetails) si.getPayload();
|
ServerDetails pl = (ServerDetails) si.getPayload();
|
||||||
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(),
|
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(),
|
||||||
pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort());
|
pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort(),
|
||||||
|
new ArrivalRate(arrivalRateExecutor));
|
||||||
tbh.setBalancerConfig(balancerConfig);
|
tbh.setBalancerConfig(balancerConfig);
|
||||||
availableHosts.add(tbh);
|
availableHosts.add(tbh);
|
||||||
}
|
}
|
||||||
@@ -265,9 +315,8 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
availableHosts.remove(h);
|
availableHosts.remove(h);
|
||||||
} else {
|
} else {
|
||||||
itr.remove();
|
itr.remove();
|
||||||
LOG.info("removing service {}:{} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}",
|
metricHostEvent(h, MetricHostEvent.ActionType.REMOVED);
|
||||||
h.getHost(), h.getTcpPort(), h.getHost(), h.getTcpPort(), h.getHttpPort(),
|
LOG.info("removing service {}", TimelyBalancedHost.toStringShort(h));
|
||||||
h.getWsPort(), h.getUdpPort());
|
|
||||||
for (Map.Entry<String, TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
for (Map.Entry<String, TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
||||||
if (e.getValue().equals(h)) {
|
if (e.getValue().equals(h)) {
|
||||||
reassignMetrics.add(e.getKey());
|
reassignMetrics.add(e.getKey());
|
||||||
@@ -279,28 +328,33 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
// add new hosts that were not previously known
|
// add new hosts that were not previously known
|
||||||
for (TimelyBalancedHost h : availableHosts) {
|
for (TimelyBalancedHost h : availableHosts) {
|
||||||
LOG.info("adding service {}:{} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}",
|
LOG.info("adding service {}", TimelyBalancedHost.toStringShort(h));
|
||||||
h.getHost(), h.getTcpPort(), h.getHost(), h.getTcpPort(), h.getHttpPort(),
|
|
||||||
h.getWsPort(), h.getUdpPort());
|
|
||||||
serverList.add(h);
|
serverList.add(h);
|
||||||
|
metricHostEvent(h, MetricHostEvent.ActionType.ADDED);
|
||||||
rebalanceNeeded = true;
|
rebalanceNeeded = true;
|
||||||
}
|
}
|
||||||
healthChecker.setTimelyHosts(serverList);
|
healthChecker.setTimelyHosts(serverList);
|
||||||
|
if (!availableHosts.isEmpty()) {
|
||||||
|
reassignMetrics.addAll(unassignedMetrics);
|
||||||
|
unassignedMetrics.clear();
|
||||||
|
}
|
||||||
if (isLeader.get()) {
|
if (isLeader.get()) {
|
||||||
for (String s : reassignMetrics) {
|
for (String s : reassignMetrics) {
|
||||||
TimelyBalancedHost h = getRoundRobinHost(null);
|
TimelyBalancedHost h = getRoundRobinHost(null);
|
||||||
assignMetric(s, h);
|
assignMetric(s, h, HOST_REMOVED);
|
||||||
LOG.debug("Assigned server removed. Assigning {} to server {}:{}", s, h.getTcpPort());
|
LOG.debug("Assigned server removed. Assigning {} to server {}", s,
|
||||||
|
TimelyBalancedHost.toStringShort(h));
|
||||||
}
|
}
|
||||||
writeAssigmentsToHdfs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
balancerLock.writeLock().unlock();
|
balancerLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
if (isLeader.get() && rebalanceNeeded) {
|
if (isLeader.get()) {
|
||||||
balance();
|
if (rebalanceNeeded) {
|
||||||
|
balance();
|
||||||
|
}
|
||||||
|
assignmentPerister.writeAssignments();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,7 +414,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
return tbh;
|
return tbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimelyBalancedHost getRoundRobinHost(TimelyBalancedHost notThisOne) {
|
protected TimelyBalancedHost getRoundRobinHost(TimelyBalancedHost notThisOne) {
|
||||||
TimelyBalancedHost tbh = null;
|
TimelyBalancedHost tbh = null;
|
||||||
balancerLock.readLock().lock();
|
balancerLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -457,21 +511,21 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (highHosts.isEmpty() && lowHosts.isEmpty()) {
|
if (highHosts.isEmpty() && lowHosts.isEmpty()) {
|
||||||
LOG.info("Host's arrival rates are within {} of the average", controlBandPercentage);
|
LOG.debug("Host's arrival rates are within {} of the average", controlBandPercentage);
|
||||||
} else if (!highHosts.isEmpty() && !lowHosts.isEmpty()) {
|
} else if (!highHosts.isEmpty() && !lowHosts.isEmpty()) {
|
||||||
LOG.info("begin rebalancing {}", BalanceType.HIGH_LOW);
|
LOG.debug("begin rebalancing {}", BalanceType.HIGH_LOW);
|
||||||
numReassigned = rebalance(highHosts, lowHosts, calculatedRates, averageArrivalRate,
|
numReassigned = rebalance(highHosts, lowHosts, calculatedRates, averageArrivalRate,
|
||||||
BalanceType.HIGH_LOW);
|
BalanceType.HIGH_LOW);
|
||||||
LOG.info("end rebalancing {} - reassigned {}", BalanceType.HIGH_LOW, numReassigned);
|
LOG.debug("end rebalancing {} - reassigned {}", BalanceType.HIGH_LOW, numReassigned);
|
||||||
} else if (lowHosts.isEmpty()) {
|
} else if (lowHosts.isEmpty()) {
|
||||||
LOG.info("begin rebalancing {}", BalanceType.HIGH_AVG);
|
LOG.debug("begin rebalancing {}", BalanceType.HIGH_AVG);
|
||||||
numReassigned = rebalance(highHosts, avgHosts, calculatedRates, averageArrivalRate,
|
numReassigned = rebalance(highHosts, avgHosts, calculatedRates, averageArrivalRate,
|
||||||
BalanceType.HIGH_AVG);
|
BalanceType.HIGH_AVG);
|
||||||
LOG.info("end rebalancing {} - reassigned {}", BalanceType.HIGH_AVG, numReassigned);
|
LOG.debug("end rebalancing {} - reassigned {}", BalanceType.HIGH_AVG, numReassigned);
|
||||||
} else {
|
} else {
|
||||||
LOG.info("begin rebalancing {}", BalanceType.AVG_LOW);
|
LOG.debug("begin rebalancing {}", BalanceType.AVG_LOW);
|
||||||
numReassigned = rebalance(avgHosts, lowHosts, calculatedRates, averageArrivalRate, BalanceType.AVG_LOW);
|
numReassigned = rebalance(avgHosts, lowHosts, calculatedRates, averageArrivalRate, BalanceType.AVG_LOW);
|
||||||
LOG.info("end rebalancing {} - reassigned {}", BalanceType.AVG_LOW, numReassigned);
|
LOG.debug("end rebalancing {} - reassigned {}", BalanceType.AVG_LOW, numReassigned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return numReassigned;
|
return numReassigned;
|
||||||
@@ -482,8 +536,10 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
|
|
||||||
int numReassigned = 0;
|
int numReassigned = 0;
|
||||||
if (isLeader.get()) {
|
if (isLeader.get()) {
|
||||||
|
metricBalanceEvent(MetricBalanceEvent.ProgressType.BEGIN, balanceType, 0);
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
|
metricBalanceEvent(MetricBalanceEvent.ProgressType.BALANCER_LOCK_ACQUIRED, balanceType, 0);
|
||||||
Map<String, ArrivalRate> tempMetricMap = new HashMap<>();
|
Map<String, ArrivalRate> tempMetricMap = new HashMap<>();
|
||||||
tempMetricMap.putAll(metricMap);
|
tempMetricMap.putAll(metricMap);
|
||||||
|
|
||||||
@@ -513,8 +569,8 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.trace("focusHost {}:{} desiredChange:{} rateSortedMetrics.size():{}", h.getHost(),
|
LOG.trace("focusHost {} desiredChange:{} rateSortedMetrics.size():{}",
|
||||||
h.getTcpPort(), desiredChange, rateSortedMetrics.size());
|
TimelyBalancedHost.toStringShort(h), desiredChange, rateSortedMetrics.size());
|
||||||
|
|
||||||
boolean doneWithHost = false;
|
boolean doneWithHost = false;
|
||||||
while (!doneWithHost) {
|
while (!doneWithHost) {
|
||||||
@@ -543,7 +599,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
} else {
|
} else {
|
||||||
String metric = e.getValue();
|
String metric = e.getValue();
|
||||||
Double metricRate = e.getKey();
|
Double metricRate = e.getKey();
|
||||||
assignMetric(metric, candidateHost);
|
assignMetric(metric, candidateHost, REBALANCE);
|
||||||
numReassigned++;
|
numReassigned++;
|
||||||
calculatedRates.put(candidateHost, calculatedRates.get(candidateHost) + metricRate);
|
calculatedRates.put(candidateHost, calculatedRates.get(candidateHost) + metricRate);
|
||||||
calculatedRates.put(h, calculatedRates.get(h) - metricRate);
|
calculatedRates.put(h, calculatedRates.get(h) - metricRate);
|
||||||
@@ -552,9 +608,9 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
itr.remove();
|
itr.remove();
|
||||||
tempMetricMap.remove(metric);
|
tempMetricMap.remove(metric);
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"rebalancing: reassigning metric:{} rate:{} from server {}:{} to {}:{} remaining delta {}",
|
"rebalancing: reassigning metric:{} rate:{} from server {} to {} remaining delta {}",
|
||||||
metric, metricRate, h.getHost(), h.getTcpPort(), candidateHost.getHost(),
|
metric, metricRate, TimelyBalancedHost.toStringShort(h),
|
||||||
candidateHost.getTcpPort(), desiredChange);
|
TimelyBalancedHost.toStringShort(candidateHost), desiredChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -577,18 +633,94 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
balancerLock.writeLock().unlock();
|
balancerLock.writeLock().unlock();
|
||||||
|
metricBalanceEvent(MetricBalanceEvent.ProgressType.END, balanceType, numReassigned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return numReassigned;
|
return numReassigned;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldCache(String metricName) {
|
private void addNonCachedMetrics(Collection<String> nonCachedMetricsUpdate) {
|
||||||
|
if (!nonCachedMetricsUpdate.isEmpty()) {
|
||||||
|
try {
|
||||||
|
LOG.debug("Adding {} to local nonCachedMetrics", nonCachedMetricsUpdate);
|
||||||
|
nonCachedMetricsLocalLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
nonCachedMetrics.addAll(nonCachedMetricsUpdate);
|
||||||
|
} finally {
|
||||||
|
nonCachedMetricsLocalLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
boolean acquired = false;
|
||||||
|
while (!acquired) {
|
||||||
|
acquired = nonCachedMetricsIPRWLock.writeLock().acquire(60, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
|
||||||
|
Set<String> currentNonCachedMetricsIP;
|
||||||
|
if (currentNonCachedMetricsDistributedBytes == null) {
|
||||||
|
currentNonCachedMetricsIP = new TreeSet<>();
|
||||||
|
} else {
|
||||||
|
currentNonCachedMetricsIP = SerializationUtils
|
||||||
|
.deserialize(currentNonCachedMetricsDistributedBytes);
|
||||||
|
}
|
||||||
|
if (currentNonCachedMetricsIP.containsAll(nonCachedMetricsUpdate)) {
|
||||||
|
LOG.debug("nonCachedMetricsIP already contains {}", nonCachedMetricsUpdate);
|
||||||
|
} else {
|
||||||
|
nonCachedMetricsUpdate.removeAll(currentNonCachedMetricsIP);
|
||||||
|
LOG.debug("Adding {} to nonCachedMetricsIP", nonCachedMetricsUpdate);
|
||||||
|
TreeSet<String> updateSet = new TreeSet<>();
|
||||||
|
updateSet.addAll(currentNonCachedMetricsIP);
|
||||||
|
updateSet.addAll(nonCachedMetricsUpdate);
|
||||||
|
byte[] updateValue = SerializationUtils.serialize(updateSet);
|
||||||
|
nonCachedMetricsIP.trySet(updateValue);
|
||||||
|
if (!nonCachedMetricsIP.get().succeeded()) {
|
||||||
|
nonCachedMetricsIP.forceSet(updateValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
nonCachedMetricsIPRWLock.writeLock().release();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testIPRWLock(CuratorFramework curatorFramework, InterProcessReadWriteLock lock, String path) {
|
||||||
|
try {
|
||||||
|
lock.writeLock().acquire(10, TimeUnit.SECONDS);
|
||||||
|
} catch (Exception e1) {
|
||||||
|
try {
|
||||||
|
curatorFramework.delete().deletingChildrenIfNeeded().forPath(path);
|
||||||
|
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT)
|
||||||
|
.forPath(path);
|
||||||
|
} catch (Exception e2) {
|
||||||
|
LOG.info(e2.getMessage(), e2);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
lock.writeLock().release();
|
||||||
|
} catch (Exception e3) {
|
||||||
|
LOG.error(e3.getMessage(), e3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean shouldCache(String metricName) {
|
||||||
|
|
||||||
if (StringUtils.isBlank(metricName)) {
|
if (StringUtils.isBlank(metricName)) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
balancerLock.readLock().lock();
|
balancerLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
|
nonCachedMetricsLocalLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
if (nonCachedMetrics.contains(metricName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
nonCachedMetricsLocalLock.readLock().unlock();
|
||||||
|
}
|
||||||
if (metricToHostMap.containsKey(metricName)) {
|
if (metricToHostMap.containsKey(metricName)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -596,27 +728,17 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
balancerLock.readLock().unlock();
|
balancerLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
nonCachedMetricsLock.readLock().lock();
|
nonCachedMetricsLocalLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
if (nonCachedMetrics.contains(metricName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String r : nonCachedMetrics) {
|
for (String r : nonCachedMetrics) {
|
||||||
if (metricName.matches(r)) {
|
if (metricName.matches(r)) {
|
||||||
LOG.info("Adding {} to list of non-cached metrics", metricName);
|
LOG.debug("Adding {} to list of non-cached metrics", metricName);
|
||||||
nonCachedMetricsLock.readLock().unlock();
|
addNonCachedMetrics(Collections.singleton(metricName));
|
||||||
nonCachedMetricsLock.writeLock().lock();
|
|
||||||
nonCachedMetrics.add(metricName);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (nonCachedMetricsLock.isWriteLockedByCurrentThread()) {
|
nonCachedMetricsLocalLock.writeLock().unlock();
|
||||||
nonCachedMetricsLock.writeLock().unlock();
|
|
||||||
} else {
|
|
||||||
nonCachedMetricsLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -633,7 +755,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
if (chooseMetricSpecificHost) {
|
if (chooseMetricSpecificHost) {
|
||||||
ArrivalRate rate = metricMap.get(metric);
|
ArrivalRate rate = metricMap.get(metric);
|
||||||
if (rate == null) {
|
if (rate == null) {
|
||||||
rate = new ArrivalRate(arrivalRateTimer);
|
rate = new ArrivalRate(arrivalRateExecutor);
|
||||||
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
||||||
balancerLock.readLock().unlock();
|
balancerLock.readLock().unlock();
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
@@ -646,7 +768,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isBlank(metric)) {
|
if (StringUtils.isBlank(metric)) {
|
||||||
tbh = getRandomHost(null);
|
tbh = getRoundRobinHost(null);
|
||||||
} else {
|
} else {
|
||||||
tbh = metricToHostMap.get(metric);
|
tbh = metricToHostMap.get(metric);
|
||||||
if (tbh == null) {
|
if (tbh == null) {
|
||||||
@@ -655,17 +777,17 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
balancerLock.readLock().unlock();
|
balancerLock.readLock().unlock();
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
}
|
}
|
||||||
assignMetric(metric, tbh);
|
assignMetric(metric, tbh, ASSIGN_ROUND_ROBIN);
|
||||||
} else if (!tbh.isUp()) {
|
} else if (!tbh.isUp()) {
|
||||||
TimelyBalancedHost oldTbh = tbh;
|
TimelyBalancedHost oldTbh = tbh;
|
||||||
tbh = getLeastUsedHost();
|
tbh = getRoundRobinHost(oldTbh);
|
||||||
LOG.info("rebalancing from host that is down: reassigning metric {} from server {}:{} to {}:{}",
|
LOG.debug("rebalancing from host that is down: reassigning metric {} from server {} to {}", metric,
|
||||||
metric, oldTbh.getHost(), oldTbh.getTcpPort(), tbh.getHost(), tbh.getTcpPort());
|
TimelyBalancedHost.toStringShort(oldTbh), TimelyBalancedHost.toStringShort(tbh));
|
||||||
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
||||||
balancerLock.readLock().unlock();
|
balancerLock.readLock().unlock();
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
}
|
}
|
||||||
assignMetric(metric, tbh);
|
assignMetric(metric, tbh, HOST_DOWN_ROUND_ROBIN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,7 +804,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
balancerLock.readLock().unlock();
|
balancerLock.readLock().unlock();
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
}
|
}
|
||||||
assignMetric(metric, tbh);
|
assignMetric(metric, tbh, ASSIGN_FALLBACK_SEQUENTIAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -711,20 +833,23 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
metric = null;
|
metric = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tbh == null || !tbh.isUp()) {
|
if (tbh == null) {
|
||||||
for (int x = 0; tbh == null && x < serverList.size(); x++) {
|
tbh = getRoundRobinHost(null);
|
||||||
tbh = serverList.get(Math.abs(r.nextInt() & Integer.MAX_VALUE) % serverList.size());
|
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
||||||
if (!tbh.isUp()) {
|
balancerLock.readLock().unlock();
|
||||||
tbh = null;
|
balancerLock.writeLock().lock();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (tbh != null && StringUtils.isNotBlank(metric)) {
|
assignMetric(metric, tbh, ASSIGN_ROUND_ROBIN);
|
||||||
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
} else if (!tbh.isUp()) {
|
||||||
balancerLock.readLock().unlock();
|
TimelyBalancedHost oldTbh = tbh;
|
||||||
balancerLock.writeLock().lock();
|
tbh = getRoundRobinHost(oldTbh);
|
||||||
}
|
LOG.debug("rebalancing from host that is down: reassigning metric {} from server {} to {}", metric,
|
||||||
assignMetric(metric, tbh);
|
TimelyBalancedHost.toStringShort(oldTbh), TimelyBalancedHost.toStringShort(tbh));
|
||||||
|
if (!balancerLock.isWriteLockedByCurrentThread()) {
|
||||||
|
balancerLock.readLock().unlock();
|
||||||
|
balancerLock.writeLock().lock();
|
||||||
}
|
}
|
||||||
|
assignMetric(metric, tbh, HOST_DOWN_ROUND_ROBIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if all else fails
|
// if all else fails
|
||||||
@@ -740,7 +865,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
balancerLock.readLock().unlock();
|
balancerLock.readLock().unlock();
|
||||||
balancerLock.writeLock().lock();
|
balancerLock.writeLock().lock();
|
||||||
}
|
}
|
||||||
assignMetric(metric, tbh);
|
assignMetric(metric, tbh, ASSIGN_FALLBACK_SEQUENTIAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -753,7 +878,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
return tbh;
|
return tbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimelyBalancedHost findHost(String host, int tcpPort) {
|
protected TimelyBalancedHost findHost(String host, int tcpPort) {
|
||||||
TimelyBalancedHost tbh = null;
|
TimelyBalancedHost tbh = null;
|
||||||
for (TimelyBalancedHost h : serverList) {
|
for (TimelyBalancedHost h : serverList) {
|
||||||
if (h.getHost().equals(host) && h.getTcpPort() == tcpPort) {
|
if (h.getHost().equals(host) && h.getTcpPort() == tcpPort) {
|
||||||
@@ -764,130 +889,100 @@ public class BalancedMetricResolver implements MetricResolver {
|
|||||||
return tbh;
|
return tbh;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readAssignmentsFromHdfs() {
|
private void assignMetric(String metric, TimelyBalancedHost tbh, MetricAssignedEvent.Reason reason) {
|
||||||
|
|
||||||
Map<String, TimelyBalancedHost> assignedMetricToHostMap = new TreeMap<>();
|
|
||||||
try {
|
|
||||||
assignmentsLock.readLock().acquire();
|
|
||||||
Configuration configuration = new Configuration();
|
|
||||||
FileSystem fs = FileSystem.get(configuration);
|
|
||||||
Path assignmentFile = new Path(balancerConfig.getAssignmentFile());
|
|
||||||
FSDataInputStream iStream = fs.open(assignmentFile);
|
|
||||||
|
|
||||||
CsvReader reader = new CsvReader(iStream, ',', Charset.forName("UTF-8"));
|
|
||||||
reader.setUseTextQualifier(false);
|
|
||||||
|
|
||||||
// skip the headers
|
|
||||||
boolean success = true;
|
|
||||||
success = reader.readHeaders();
|
|
||||||
|
|
||||||
while (success) {
|
|
||||||
success = reader.readRecord();
|
|
||||||
String[] nextLine = reader.getValues();
|
|
||||||
if (nextLine.length >= 3) {
|
|
||||||
String metric = nextLine[0];
|
|
||||||
String host = nextLine[1];
|
|
||||||
int tcpPort = Integer.parseInt(nextLine[2]);
|
|
||||||
TimelyBalancedHost tbh = findHost(host, tcpPort);
|
|
||||||
if (tbh == null) {
|
|
||||||
tbh = getRoundRobinHost(null);
|
|
||||||
} else {
|
|
||||||
LOG.trace("Found assigment: {} to {}:{}", metric, host, tcpPort);
|
|
||||||
}
|
|
||||||
assignedMetricToHostMap.put(metric, tbh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
balancerLock.writeLock().lock();
|
|
||||||
try {
|
|
||||||
metricToHostMap.clear();
|
|
||||||
for (Map.Entry<String, TimelyBalancedHost> e : assignedMetricToHostMap.entrySet()) {
|
|
||||||
if (shouldCache(e.getKey())) {
|
|
||||||
metricToHostMap.put(e.getKey(), e.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
balancerLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
assignmentsLastUpdatedLocal.set(assignmentsLastUpdatedInHdfs.get().postValue());
|
|
||||||
LOG.info("Read {} assignments from hdfs lastHdfsUpdate = lastLocalUpdate ({})", metricToHostMap.size(),
|
|
||||||
new Date(assignmentsLastUpdatedLocal.get()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
assignmentsLock.readLock().release();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeAssigmentsToHdfs() {
|
|
||||||
|
|
||||||
CsvWriter writer = null;
|
|
||||||
try {
|
|
||||||
assignmentsLock.writeLock().acquire();
|
|
||||||
balancerLock.readLock().lock();
|
|
||||||
try {
|
|
||||||
if (!metricToHostMap.isEmpty()) {
|
|
||||||
Configuration configuration = new Configuration();
|
|
||||||
FileSystem fs = FileSystem.get(configuration);
|
|
||||||
Path assignmentFile = new Path(balancerConfig.getAssignmentFile());
|
|
||||||
if (!fs.exists(assignmentFile.getParent())) {
|
|
||||||
fs.mkdirs(assignmentFile.getParent());
|
|
||||||
}
|
|
||||||
FSDataOutputStream oStream = fs.create(assignmentFile, true);
|
|
||||||
writer = new CsvWriter(oStream, ',', Charset.forName("UTF-8"));
|
|
||||||
writer.setUseTextQualifier(false);
|
|
||||||
writer.write("metric");
|
|
||||||
writer.write("host");
|
|
||||||
writer.write("tcpPort");
|
|
||||||
writer.endRecord();
|
|
||||||
for (Map.Entry<String, TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
|
||||||
writer.write(e.getKey());
|
|
||||||
writer.write(e.getValue().getHost());
|
|
||||||
writer.write(Integer.toString(e.getValue().getTcpPort()));
|
|
||||||
writer.endRecord();
|
|
||||||
LOG.trace("Saving assigment: {} to {}:{}", e.getKey(), e.getValue().getHost(),
|
|
||||||
e.getValue().getTcpPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
assignmentsLastUpdatedLocal.set(now);
|
|
||||||
assignmentsLastUpdatedInHdfs.trySet(now);
|
|
||||||
if (!assignmentsLastUpdatedInHdfs.get().succeeded()) {
|
|
||||||
assignmentsLastUpdatedInHdfs.forceSet(now);
|
|
||||||
}
|
|
||||||
LOG.info("Wrote {} assignments to hdfs lastHdfsUpdate = lastLocalUpdate ({})",
|
|
||||||
metricToHostMap.size(), new Date(assignmentsLastUpdatedLocal.get()));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
balancerLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
} finally {
|
|
||||||
if (writer != null) {
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
assignmentsLock.writeLock().release();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assignMetric(String metric, TimelyBalancedHost tbh) {
|
|
||||||
if (isLeader.get()) {
|
if (isLeader.get()) {
|
||||||
balancerLock.writeLock().lock();
|
if (StringUtils.isNotBlank(metric) && tbh != null) {
|
||||||
try {
|
balancerLock.writeLock().lock();
|
||||||
metricToHostMap.put(metric, tbh);
|
try {
|
||||||
assignmentsLastUpdatedLocal.set(System.currentTimeMillis());
|
metricAssignedEvent(metric, metricToHostMap.get(metric), tbh, reason);
|
||||||
} finally {
|
metricToHostMap.put(metric, tbh);
|
||||||
balancerLock.writeLock().unlock();
|
assignmentsLastUpdatedLocal.set(System.currentTimeMillis());
|
||||||
|
} finally {
|
||||||
|
balancerLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unassignedMetrics.add(metric);
|
||||||
|
// Exception e = new IllegalStateException("Bad assignment metric:" + metric + "
|
||||||
|
// host:" + tbh);
|
||||||
|
LOG.warn("Bad assignment metric:" + metric + " host:" + tbh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public void registerCallback(MetricAssignedCallback callback) {
|
||||||
|
this.metricAssignedCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerCallback(MetricBalanceCallback callback) {
|
||||||
|
this.metricBalanceCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerCallback(MetricHostCallback callback) {
|
||||||
|
this.metricHostCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void metricAssignedEvent(String metric, TimelyBalancedHost losing, TimelyBalancedHost gaining,
|
||||||
|
MetricAssignedEvent.Reason reason) {
|
||||||
|
if (!metricAssignedCallbacks.isEmpty()) {
|
||||||
|
MetricAssignedEvent event = new MetricAssignedEvent(metric, losing, gaining, reason);
|
||||||
|
for (MetricAssignedCallback callback : metricAssignedCallbacks) {
|
||||||
|
callback.onEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void metricBalanceEvent(MetricBalanceEvent.ProgressType progressType,
|
||||||
|
BalancedMetricResolver.BalanceType balanceType, long numReassigned) {
|
||||||
|
if (!metricBalanceCallbacks.isEmpty()) {
|
||||||
|
MetricBalanceEvent event = new MetricBalanceEvent(progressType, balanceType, numReassigned);
|
||||||
|
for (MetricBalanceCallback callback : metricBalanceCallbacks) {
|
||||||
|
callback.onEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void metricHostEvent(TimelyBalancedHost host, MetricHostEvent.ActionType actionType) {
|
||||||
|
if (!metricHostCallbacks.isEmpty()) {
|
||||||
|
MetricHostEvent event = new MetricHostEvent(host, actionType);
|
||||||
|
for (MetricHostCallback callback : metricHostCallbacks) {
|
||||||
|
callback.onEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeAssignments(Map<String, TimelyBalancedHost> metricToHostMap) {
|
||||||
|
assignmentPerister.writeAssignments(metricToHostMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
|
||||||
|
this.assignmentExecutor.shutdown();
|
||||||
|
try {
|
||||||
|
this.assignmentExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!this.assignmentExecutor.isTerminated()) {
|
||||||
|
this.assignmentExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.arrivalRateExecutor.shutdown();
|
||||||
|
try {
|
||||||
|
this.arrivalRateExecutor.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!this.arrivalRateExecutor.isTerminated()) {
|
||||||
|
this.arrivalRateExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.healthChecker.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,320 @@
|
|||||||
|
package timely.balancer.resolver;
|
||||||
|
|
||||||
|
import static timely.balancer.Balancer.ASSIGNMENTS_LAST_UPDATED_PATH;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
import com.csvreader.CsvReader;
|
||||||
|
import com.csvreader.CsvWriter;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
|
||||||
|
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
|
||||||
|
import org.apache.curator.retry.RetryForever;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.balancer.resolver.eventing.MetricAssignedEvent;
|
||||||
|
|
||||||
|
public class MetricAssignmentPerister {
|
||||||
|
|
||||||
|
private final Logger LOG = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
private enum PeristerType {
|
||||||
|
HDFS, FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
// passed in through constructor
|
||||||
|
BalancedMetricResolver balancedMetricResolver;
|
||||||
|
private BalancerConfiguration balancerConfig;
|
||||||
|
private Map<String, TimelyBalancedHost> metricToHostMap;
|
||||||
|
private Set<String> nonCachedMetrics;
|
||||||
|
private InterProcessReadWriteLock assignmentsIPRWLock;
|
||||||
|
private ReentrantReadWriteLock nonCachedMetricsLocalLock;
|
||||||
|
private ReentrantReadWriteLock balancerLock;
|
||||||
|
private AtomicLong assignmentsLastUpdatedLocal;
|
||||||
|
|
||||||
|
// local
|
||||||
|
private DistributedAtomicLong assignmentsLastUpdatedInHdfs;
|
||||||
|
|
||||||
|
public MetricAssignmentPerister(BalancedMetricResolver balancedMetricResolver, BalancerConfiguration balancerConfig,
|
||||||
|
Map<String, TimelyBalancedHost> metricToHostMap, Set<String> nonCachedMetrics,
|
||||||
|
CuratorFramework curatorFramework, InterProcessReadWriteLock assignmentsIPRWLock,
|
||||||
|
ReentrantReadWriteLock nonCachedMetricsLocalLock, AtomicLong assignmentsLastUpdatedLocal,
|
||||||
|
ReentrantReadWriteLock balancerLock) {
|
||||||
|
|
||||||
|
this.balancedMetricResolver = balancedMetricResolver;
|
||||||
|
this.balancerConfig = balancerConfig;
|
||||||
|
this.metricToHostMap = metricToHostMap;
|
||||||
|
this.nonCachedMetrics = nonCachedMetrics;
|
||||||
|
this.assignmentsIPRWLock = assignmentsIPRWLock;
|
||||||
|
this.nonCachedMetricsLocalLock = nonCachedMetricsLocalLock;
|
||||||
|
this.assignmentsLastUpdatedLocal = assignmentsLastUpdatedLocal;
|
||||||
|
this.balancerLock = balancerLock;
|
||||||
|
assignmentsLastUpdatedInHdfs = new DistributedAtomicLong(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH,
|
||||||
|
new RetryForever(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getAssignmentsLastUpdatedByLeader() throws Exception {
|
||||||
|
return assignmentsLastUpdatedInHdfs.get().postValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readAssignments(boolean checkIfNecessary) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
||||||
|
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
||||||
|
if (checkIfNecessary) {
|
||||||
|
if (lastHdfsUpdate <= lastLocalUpdate) {
|
||||||
|
LOG.debug("Not reading assignments from storage lastStorageUpdate ({}) <= lastLocalUpdate ({})",
|
||||||
|
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.debug("Reading assignments from storage lastStorageUpdate ({}) > lastLocalUpdate ({})",
|
||||||
|
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// proceed with reading from storage
|
||||||
|
|
||||||
|
try (InputStream inputStream = getInputStream(balancerConfig)) {
|
||||||
|
boolean acquired = false;
|
||||||
|
while (!acquired) {
|
||||||
|
acquired = assignmentsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
balancerLock.writeLock().lock();
|
||||||
|
// get potential new list from implementation
|
||||||
|
Map<String, TimelyBalancedHost> assignedMetricToHostMap = readFromStream(inputStream);
|
||||||
|
metricToHostMap.clear();
|
||||||
|
for (Map.Entry<String, TimelyBalancedHost> e : assignedMetricToHostMap.entrySet()) {
|
||||||
|
if (StringUtils.isNotBlank(e.getKey()) && e.getValue() != null) {
|
||||||
|
if (balancedMetricResolver.shouldCache(e.getKey())) {
|
||||||
|
balancedMetricResolver.metricAssignedEvent(e.getKey(), null, e.getValue(),
|
||||||
|
MetricAssignedEvent.Reason.ASSIGN_FILE);
|
||||||
|
metricToHostMap.put(e.getKey(), e.getValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Exception e1 = new IllegalStateException(
|
||||||
|
"Bad assignment metric:" + e.getKey() + " host:" + e.getValue());
|
||||||
|
LOG.warn(e1.getMessage(), e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nonCachedMetricsLocalLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Iterator<Map.Entry<String, TimelyBalancedHost>> itr = metricToHostMap.entrySet().iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
Map.Entry<String, TimelyBalancedHost> e = itr.next();
|
||||||
|
if (nonCachedMetrics.contains(e.getKey())) {
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
nonCachedMetricsLocalLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
assignmentsLastUpdatedLocal.set(assignmentsLastUpdatedInHdfs.get().postValue());
|
||||||
|
LOG.info("Read {} assignments from storage lastStorageUpdate = lastLocalUpdate ({})",
|
||||||
|
metricToHostMap.size(), new Date(assignmentsLastUpdatedLocal.get()));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
createAssignmentFile();
|
||||||
|
metricToHostMap.clear();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
balancerLock.writeLock().unlock();
|
||||||
|
try {
|
||||||
|
assignmentsIPRWLock.readLock().release();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeAssignments() {
|
||||||
|
writeAssignments(metricToHostMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeAssignments(Map<String, TimelyBalancedHost> metricToHostMap) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
boolean acquired = false;
|
||||||
|
while (!acquired) {
|
||||||
|
acquired = assignmentsIPRWLock.writeLock().acquire(60, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
balancerLock.readLock().lock();
|
||||||
|
nonCachedMetricsLocalLock.readLock().lock();
|
||||||
|
try (OutputStream outputStream = getOutputStream(balancerConfig)) {
|
||||||
|
if (!metricToHostMap.isEmpty()) {
|
||||||
|
writeToStream(outputStream);
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
assignmentsLastUpdatedLocal.set(now);
|
||||||
|
assignmentsLastUpdatedInHdfs.trySet(now);
|
||||||
|
if (!assignmentsLastUpdatedInHdfs.get().succeeded()) {
|
||||||
|
assignmentsLastUpdatedInHdfs.forceSet(now);
|
||||||
|
}
|
||||||
|
LOG.debug("Wrote {} assignments to storage lastStorageUpdate = lastLocalUpdate ({})",
|
||||||
|
metricToHostMap.size(), new Date(assignmentsLastUpdatedLocal.get()));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
nonCachedMetricsLocalLock.readLock().unlock();
|
||||||
|
balancerLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
assignmentsIPRWLock.writeLock().release();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, TimelyBalancedHost> readFromStream(InputStream inputStream) throws IOException {
|
||||||
|
Map<String, TimelyBalancedHost> assignedMetricToHostMap = new TreeMap<>();
|
||||||
|
try {
|
||||||
|
CsvReader reader = new CsvReader(inputStream, ',', Charset.forName("UTF-8"));
|
||||||
|
reader.setUseTextQualifier(false);
|
||||||
|
|
||||||
|
// skip the headers
|
||||||
|
boolean success = true;
|
||||||
|
success = reader.readHeaders();
|
||||||
|
|
||||||
|
while (success) {
|
||||||
|
success = reader.readRecord();
|
||||||
|
String[] nextLine = reader.getValues();
|
||||||
|
if (nextLine.length >= 3) {
|
||||||
|
String metric = nextLine[0];
|
||||||
|
String host = nextLine[1];
|
||||||
|
int tcpPort = Integer.parseInt(nextLine[2]);
|
||||||
|
TimelyBalancedHost tbh = balancedMetricResolver.findHost(host, tcpPort);
|
||||||
|
if (tbh == null) {
|
||||||
|
tbh = balancedMetricResolver.getRoundRobinHost(null);
|
||||||
|
} else {
|
||||||
|
LOG.trace("Found assigment: {} to {}:{}", metric, host, tcpPort);
|
||||||
|
}
|
||||||
|
assignedMetricToHostMap.put(metric, tbh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return assignedMetricToHostMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeToStream(OutputStream outputStream) throws IOException {
|
||||||
|
|
||||||
|
CsvWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new CsvWriter(outputStream, ',', Charset.forName("UTF-8"));
|
||||||
|
writer.setUseTextQualifier(false);
|
||||||
|
writer.write("metric");
|
||||||
|
writer.write("host");
|
||||||
|
writer.write("tcpPort");
|
||||||
|
writer.endRecord();
|
||||||
|
for (Map.Entry<String, TimelyBalancedHost> e : metricToHostMap.entrySet()) {
|
||||||
|
if (!nonCachedMetrics.contains(e.getKey())) {
|
||||||
|
writer.write(e.getKey());
|
||||||
|
writer.write(e.getValue().getHost());
|
||||||
|
writer.write(Integer.toString(e.getValue().getTcpPort()));
|
||||||
|
writer.endRecord();
|
||||||
|
LOG.trace("Saving assigment: {} to {}:{}", e.getKey(), e.getValue().getHost(),
|
||||||
|
e.getValue().getTcpPort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (writer != null) {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createAssignmentFile() {
|
||||||
|
LOG.info("Creating assignment file: " + balancerConfig.getAssignmentFile());
|
||||||
|
PeristerType peristerType = PeristerType.valueOf(balancerConfig.getMetricAssignmentPersisterType());
|
||||||
|
switch (peristerType) {
|
||||||
|
case HDFS:
|
||||||
|
try {
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
FileSystem fs = FileSystem.get(configuration);
|
||||||
|
Path assignmentFile = new Path(balancerConfig.getAssignmentFile());
|
||||||
|
fs.create(assignmentFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FILE:
|
||||||
|
try {
|
||||||
|
File assignmentFile = new File(balancerConfig.getAssignmentFile());
|
||||||
|
String parentPath = assignmentFile.getParent();
|
||||||
|
File directory = new File(parentPath);
|
||||||
|
if (!directory.exists()) {
|
||||||
|
|
||||||
|
directory.mkdirs();
|
||||||
|
}
|
||||||
|
if (!assignmentFile.exists()) {
|
||||||
|
assignmentFile.createNewFile();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream(BalancerConfiguration balancerConfiguration) throws Exception {
|
||||||
|
PeristerType peristerType = PeristerType.valueOf(balancerConfiguration.getMetricAssignmentPersisterType());
|
||||||
|
switch (peristerType) {
|
||||||
|
case HDFS:
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
FileSystem fs = FileSystem.get(configuration);
|
||||||
|
Path assignmentFile = new Path(balancerConfiguration.getAssignmentFile());
|
||||||
|
return fs.open(assignmentFile);
|
||||||
|
case FILE:
|
||||||
|
return new FileInputStream(new File(balancerConfiguration.getAssignmentFile()));
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unknown metricPersisterType " + balancerConfiguration.getMetricAssignmentPersisterType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputStream getOutputStream(BalancerConfiguration balancerConfiguration) throws IOException {
|
||||||
|
PeristerType peristerType = PeristerType.valueOf(balancerConfiguration.getMetricAssignmentPersisterType());
|
||||||
|
switch (peristerType) {
|
||||||
|
case HDFS:
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
FileSystem fs = FileSystem.get(configuration);
|
||||||
|
Path assignmentFile = new Path(balancerConfiguration.getAssignmentFile());
|
||||||
|
if (!fs.exists(assignmentFile.getParent())) {
|
||||||
|
fs.mkdirs(assignmentFile.getParent());
|
||||||
|
}
|
||||||
|
return fs.create(assignmentFile, true);
|
||||||
|
case FILE:
|
||||||
|
return new FileOutputStream(new File(balancerConfiguration.getAssignmentFile()));
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unknown metricPersisterType " + balancerConfiguration.getMetricAssignmentPersisterType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,4 +7,9 @@ public interface MetricResolver {
|
|||||||
public TimelyBalancedHost getHostPortKeyIngest(String metric);
|
public TimelyBalancedHost getHostPortKeyIngest(String metric);
|
||||||
|
|
||||||
public TimelyBalancedHost getHostPortKey(String metric);
|
public TimelyBalancedHost getHostPortKey(String metric);
|
||||||
|
|
||||||
|
public void start();
|
||||||
|
|
||||||
|
public void stop();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package timely.balancer.resolver.eventing;
|
||||||
|
|
||||||
|
public abstract class MetricAssignedCallback {
|
||||||
|
|
||||||
|
public abstract void onEvent(MetricAssignedEvent event);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package timely.balancer.resolver.eventing;
|
||||||
|
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
|
||||||
|
public class MetricAssignedEvent {
|
||||||
|
|
||||||
|
public enum Reason {
|
||||||
|
ASSIGN_ROUND_ROBIN, HOST_DOWN_ROUND_ROBIN, ASSIGN_FALLBACK_SEQUENTIAL, HOST_REMOVED, REBALANCE, ASSIGN_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String metric;
|
||||||
|
private final TimelyBalancedHost losingHost;
|
||||||
|
private final TimelyBalancedHost gainingHost;
|
||||||
|
private final Reason reason;
|
||||||
|
|
||||||
|
public MetricAssignedEvent(String metric, TimelyBalancedHost losingHost, TimelyBalancedHost gainingHost,
|
||||||
|
Reason reason) {
|
||||||
|
this.metric = metric;
|
||||||
|
this.losingHost = losingHost;
|
||||||
|
this.gainingHost = gainingHost;
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMetric() {
|
||||||
|
return metric;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimelyBalancedHost getLosingHost() {
|
||||||
|
return losingHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimelyBalancedHost getGainingHost() {
|
||||||
|
return gainingHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Reason getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package timely.balancer.resolver.eventing;
|
||||||
|
|
||||||
|
public abstract class MetricBalanceCallback {
|
||||||
|
|
||||||
|
public abstract void onEvent(MetricBalanceEvent event);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package timely.balancer.resolver.eventing;
|
||||||
|
|
||||||
|
import timely.balancer.resolver.BalancedMetricResolver;
|
||||||
|
|
||||||
|
public class MetricBalanceEvent {
|
||||||
|
|
||||||
|
public enum ProgressType {
|
||||||
|
BEGIN, BALANCER_LOCK_ACQUIRED, END
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ProgressType progressType;
|
||||||
|
private final BalancedMetricResolver.BalanceType balanceType;
|
||||||
|
private final Long numRessigned;
|
||||||
|
|
||||||
|
public MetricBalanceEvent(ProgressType progressType, BalancedMetricResolver.BalanceType balanceType,
|
||||||
|
long numReassigned) {
|
||||||
|
this.progressType = progressType;
|
||||||
|
this.balanceType = balanceType;
|
||||||
|
this.numRessigned = numReassigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BalancedMetricResolver.BalanceType getBalanceType() {
|
||||||
|
return balanceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressType getProgressType() {
|
||||||
|
return progressType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getNumRessigned() {
|
||||||
|
return numRessigned;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package timely.balancer.resolver.eventing;
|
||||||
|
|
||||||
|
public abstract class MetricHostCallback {
|
||||||
|
|
||||||
|
public abstract void onEvent(MetricHostEvent event);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package timely.balancer.resolver.eventing;
|
||||||
|
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
|
||||||
|
public class MetricHostEvent {
|
||||||
|
|
||||||
|
public enum ActionType {
|
||||||
|
ADDED, REMOVED, SUCCESS, FAILURE
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TimelyBalancedHost timelyBalancedHost;
|
||||||
|
private final ActionType actionType;
|
||||||
|
|
||||||
|
public MetricHostEvent(TimelyBalancedHost timelyBalancedHost, ActionType actionType) {
|
||||||
|
this.timelyBalancedHost = timelyBalancedHost;
|
||||||
|
this.actionType = actionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimelyBalancedHost getTimelyBalancedHost() {
|
||||||
|
return timelyBalancedHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionType getActionType() {
|
||||||
|
return actionType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,4 +10,9 @@
|
|||||||
<Method name="getBuf" />
|
<Method name="getBuf" />
|
||||||
<Bug pattern="EI_EXPOSE_REP" />
|
<Bug pattern="EI_EXPOSE_REP" />
|
||||||
</Match>
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<Class name="timely.balancer.resolver.MetricAssignmentPerister" />
|
||||||
|
<Method name="createAssignmentFile" />
|
||||||
|
<Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE" />
|
||||||
|
</Match>
|
||||||
</FindBugsFilter>
|
</FindBugsFilter>
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package timely.balancer.resolver;
|
||||||
|
|
||||||
|
import static timely.Server.SERVICE_DISCOVERY_PATH;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.x.discovery.ServiceDiscovery;
|
||||||
|
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
|
||||||
|
import org.apache.curator.x.discovery.ServiceInstance;
|
||||||
|
import org.apache.curator.x.discovery.ServiceInstanceBuilder;
|
||||||
|
import org.apache.zookeeper.data.Stat;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import timely.ServerDetails;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
|
||||||
|
public class ServiceRegistry {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ServiceRegistry.class);
|
||||||
|
|
||||||
|
public static void registerService(CuratorFramework curatorFramework, TimelyBalancedHost tbh) {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
Stat stat = curatorFramework.checkExists().forPath(SERVICE_DISCOVERY_PATH);
|
||||||
|
if (stat == null) {
|
||||||
|
curatorFramework.create().creatingParentContainersIfNeeded().forPath(SERVICE_DISCOVERY_PATH);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceInstance<ServerDetails> serviceInstance = serviceInstance(tbh);
|
||||||
|
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
|
||||||
|
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
||||||
|
discovery.start();
|
||||||
|
discovery.registerService(serviceInstance);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unregisterService(CuratorFramework curatorFramework, TimelyBalancedHost tbh) {
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
Stat stat = curatorFramework.checkExists().forPath(SERVICE_DISCOVERY_PATH);
|
||||||
|
if (stat == null) {
|
||||||
|
curatorFramework.create().creatingParentContainersIfNeeded().forPath(SERVICE_DISCOVERY_PATH);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceInstance<ServerDetails> serviceInstance = serviceInstance(tbh);
|
||||||
|
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
|
||||||
|
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
||||||
|
discovery.start();
|
||||||
|
discovery.unregisterService(serviceInstance);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServiceInstance<ServerDetails> serviceInstance(TimelyBalancedHost config) throws Exception {
|
||||||
|
ServerDetails serverDetails = new ServerDetails();
|
||||||
|
serverDetails.setHost(config.getHost());
|
||||||
|
serverDetails.setTcpPort(config.getTcpPort());
|
||||||
|
serverDetails.setHttpPort(config.getHttpPort());
|
||||||
|
serverDetails.setWsPort(config.getWsPort());
|
||||||
|
serverDetails.setUdpPort(config.getUdpPort());
|
||||||
|
|
||||||
|
ServiceInstanceBuilder<ServerDetails> builder = ServiceInstance.builder();
|
||||||
|
String serviceName = config.getHost() + ":" + config.getTcpPort();
|
||||||
|
ServiceInstance<ServerDetails> serviceInstance = builder.id(serviceName).name("timely-server")
|
||||||
|
.address(config.getHost()).port(config.getTcpPort()).payload(serverDetails).build();
|
||||||
|
return serviceInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
package timely.balancer.resolver;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
|
import org.apache.curator.retry.RetryNTimes;
|
||||||
|
import org.apache.zookeeper.server.ServerConfig;
|
||||||
|
import org.apache.zookeeper.server.ZooKeeperServerMain;
|
||||||
|
import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.util.SocketUtils;
|
||||||
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.balancer.resolver.eventing.MetricAssignedCallback;
|
||||||
|
import timely.balancer.resolver.eventing.MetricAssignedEvent;
|
||||||
|
import timely.balancer.resolver.eventing.MetricBalanceCallback;
|
||||||
|
import timely.balancer.resolver.eventing.MetricBalanceEvent;
|
||||||
|
import timely.balancer.resolver.eventing.MetricHostCallback;
|
||||||
|
import timely.balancer.resolver.eventing.MetricHostEvent;
|
||||||
|
|
||||||
|
public class TestBalancedMetricResolver {
|
||||||
|
|
||||||
|
private final Logger LOG = LoggerFactory.getLogger(getClass());
|
||||||
|
private CuratorFramework curatorFramework;
|
||||||
|
private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HHmmss.SSS");
|
||||||
|
private Random r = new Random(System.currentTimeMillis());
|
||||||
|
private List<TimelyBalancedHost> timelyHosts;
|
||||||
|
private Map<MetricAssignedEvent, Integer> metricBalanceEventCounter = new HashMap<>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void startup() {
|
||||||
|
QuorumPeerConfig currentConfig = createZookeeper();
|
||||||
|
InetSocketAddress address = currentConfig.getClientPortAddress();
|
||||||
|
String zkServer = address.getHostName() + ":" + address.getPort();
|
||||||
|
curatorFramework = CuratorFrameworkFactory.newClient(zkServer, 1000, 5000, new RetryNTimes(2, 50));
|
||||||
|
curatorFramework.start();
|
||||||
|
timelyHosts = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void shutdown() {
|
||||||
|
curatorFramework.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private QuorumPeerConfig createZookeeper() {
|
||||||
|
Properties startupProperties = new Properties();
|
||||||
|
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID());
|
||||||
|
file.deleteOnExit();
|
||||||
|
startupProperties.setProperty("dataDir", file.getAbsolutePath());
|
||||||
|
startupProperties.setProperty("clientPort", String.valueOf(SocketUtils.findAvailableTcpPort(3000, 4000)));
|
||||||
|
QuorumPeerConfig quorumConfiguration = new QuorumPeerConfig();
|
||||||
|
|
||||||
|
try {
|
||||||
|
quorumConfiguration.parseProperties(startupProperties);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZooKeeperServerMain zooKeeperServer = new ZooKeeperServerMain();
|
||||||
|
final ServerConfig configuration = new ServerConfig();
|
||||||
|
configuration.readFrom(quorumConfiguration);
|
||||||
|
|
||||||
|
new Thread() {
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
zooKeeperServer.runFromConfig(configuration);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("ZooKeeper Failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
|
||||||
|
return quorumConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BalancerConfiguration getBalancerConfiguration() {
|
||||||
|
BalancerConfiguration balancerConfiguration = new BalancerConfiguration();
|
||||||
|
balancerConfiguration.setMetricAssignmentPersisterType("FILE");
|
||||||
|
File file = new File(System.getProperty("java.io.tmpdir") + File.separator + UUID.randomUUID());
|
||||||
|
file.deleteOnExit();
|
||||||
|
balancerConfiguration.setAssignmentFile(file.getAbsolutePath());
|
||||||
|
balancerConfiguration.setBalanceDelay(0);
|
||||||
|
balancerConfiguration.setBalancePeriod(1000);
|
||||||
|
balancerConfiguration.setPersistDelay(0);
|
||||||
|
balancerConfiguration.setPersistDelay(1000);
|
||||||
|
balancerConfiguration.setCheckServerHealthInterval(10);
|
||||||
|
return balancerConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createTimelyHosts(BalancerConfiguration balancerConfiguration, int numHosts) {
|
||||||
|
for (int port = 1000, x = 0; x < numHosts; x++, port += 10) {
|
||||||
|
TimelyBalancedHost tbh = TimelyBalancedHost.of("localhost", port);
|
||||||
|
tbh.setBalancerConfig(balancerConfiguration);
|
||||||
|
timelyHosts.add(tbh);
|
||||||
|
ServiceRegistry.registerService(curatorFramework, tbh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCallbacks(BalancedMetricResolver resolver) {
|
||||||
|
resolver.registerCallback(new MetricAssignedCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(MetricAssignedEvent event) {
|
||||||
|
LOG.debug(String.format("%s metric:%s lose:%s:%d gain:%s:%d reason:%s",
|
||||||
|
event.getClass().getSimpleName(), event.getMetric(),
|
||||||
|
event.getLosingHost() == null ? null : event.getLosingHost().getHost(),
|
||||||
|
event.getLosingHost() == null ? null : event.getLosingHost().getTcpPort(),
|
||||||
|
event.getGainingHost().getHost(), event.getGainingHost().getTcpPort(), event.getReason()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resolver.registerCallback(new MetricHostCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(MetricHostEvent event) {
|
||||||
|
LOG.debug(String.format("%s host:%s:%d type:%s", event.getClass().getSimpleName(),
|
||||||
|
event.getTimelyBalancedHost().getHost(), event.getTimelyBalancedHost().getTcpPort(),
|
||||||
|
event.getActionType()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resolver.registerCallback(new MetricBalanceCallback() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(MetricBalanceEvent event) {
|
||||||
|
LOG.debug(String.format("%s type:%s progress:%s reassigned:%d", event.getClass().getSimpleName(),
|
||||||
|
event.getBalanceType(), event.getProgressType(), event.getNumRessigned()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private TimelyBalancedHost randomServerDown(TestHealthChecker healthChecker, int numHosts) {
|
||||||
|
TimelyBalancedHost tbh = timelyHosts.get(r.nextInt(numHosts));
|
||||||
|
LOG.debug("Marking server down:" + TimelyBalancedHost.toStringShort(tbh));
|
||||||
|
healthChecker.serverDown(tbh);
|
||||||
|
return tbh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TimelyBalancedHost randomServerToggle(TestHealthChecker healthChecker, int numHosts) {
|
||||||
|
TimelyBalancedHost tbh = timelyHosts.get(r.nextInt(numHosts));
|
||||||
|
LOG.debug("Marking server " + (tbh.isUp() ? "down:" : "up:") + TimelyBalancedHost.toStringShort(tbh));
|
||||||
|
healthChecker.serverToggle(tbh);
|
||||||
|
return tbh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TimelyBalancedHost randomServerUnregister(int numHosts) {
|
||||||
|
TimelyBalancedHost tbh = timelyHosts.get(r.nextInt(numHosts));
|
||||||
|
LOG.debug("Unregistering:" + TimelyBalancedHost.toStringShort(tbh));
|
||||||
|
ServiceRegistry.unregisterService(curatorFramework, tbh);
|
||||||
|
return tbh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
LOG.debug("Configure test");
|
||||||
|
int numHosts = 10;
|
||||||
|
BalancerConfiguration balancerConfiguration = getBalancerConfiguration();
|
||||||
|
createTimelyHosts(balancerConfiguration, numHosts);
|
||||||
|
TestHealthChecker healthChecker = new TestHealthChecker(balancerConfiguration, timelyHosts);
|
||||||
|
BalancedMetricResolver balancedMetricResolver = new BalancedMetricResolver(curatorFramework,
|
||||||
|
balancerConfiguration, healthChecker);
|
||||||
|
registerCallbacks(balancedMetricResolver);
|
||||||
|
LOG.debug("Start balancedMetricResolver");
|
||||||
|
balancedMetricResolver.start();
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
int numMetrics = 100;
|
||||||
|
for (int x = 0; x < numMetrics; x++) {
|
||||||
|
balancedMetricResolver.getHostPortKeyIngest(String.format("metric%03d", x));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug("Begin monitoring");
|
||||||
|
long cycle = 0;
|
||||||
|
List<TimelyBalancedHost> serversUnregistered = new ArrayList<>();
|
||||||
|
while (System.currentTimeMillis() < now + 15000) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
for (int x = 0; x < 10000; x++) {
|
||||||
|
int mNum = r.nextInt(numMetrics);
|
||||||
|
balancedMetricResolver.getHostPortKeyIngest(String.format("metric%03d", mNum));
|
||||||
|
}
|
||||||
|
// if (cycle % 100 == 0) {
|
||||||
|
// randomServerDown(healthChecker, numHosts);
|
||||||
|
// }
|
||||||
|
// if (cycle % 2 == 0) {
|
||||||
|
// randomServerToggle(healthChecker, numHosts);
|
||||||
|
// }
|
||||||
|
if (cycle % 100 == 0) {
|
||||||
|
serversUnregistered.add(randomServerUnregister(numHosts));
|
||||||
|
}
|
||||||
|
if (cycle % 500 == 0) {
|
||||||
|
serversUnregistered.stream().forEach(tbh -> ServiceRegistry.registerService(curatorFramework, tbh));
|
||||||
|
serversUnregistered.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
cycle++;
|
||||||
|
}
|
||||||
|
LOG.debug("Stop balancedMetricResolver");
|
||||||
|
balancedMetricResolver.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
LOG.debug("Configure test");
|
||||||
|
int numHosts = 10;
|
||||||
|
BalancerConfiguration balancerConfiguration = getBalancerConfiguration();
|
||||||
|
createTimelyHosts(balancerConfiguration, numHosts);
|
||||||
|
TestHealthChecker healthChecker = new TestHealthChecker(balancerConfiguration, timelyHosts);
|
||||||
|
BalancedMetricResolver balancedMetricResolver = new BalancedMetricResolver(curatorFramework,
|
||||||
|
balancerConfiguration, healthChecker);
|
||||||
|
registerCallbacks(balancedMetricResolver);
|
||||||
|
LOG.debug("Start balancedMetricResolver");
|
||||||
|
balancedMetricResolver.start();
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
int numMetrics = 100;
|
||||||
|
for (int x = 0; x < numMetrics; x++) {
|
||||||
|
balancedMetricResolver.getHostPortKeyIngest(String.format("metric%03d", x));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug("Begin monitoring");
|
||||||
|
long cycle = 0;
|
||||||
|
List<TimelyBalancedHost> serversUnregistered = new ArrayList<>();
|
||||||
|
while (System.currentTimeMillis() < now + 15000) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
for (int x = 0; x < 10000; x++) {
|
||||||
|
int mNum = r.nextInt(numMetrics);
|
||||||
|
balancedMetricResolver.getHostPortKeyIngest(String.format("metric%03d", mNum));
|
||||||
|
}
|
||||||
|
// if (cycle % 100 == 0) {
|
||||||
|
// randomServerDown(healthChecker, numHosts);
|
||||||
|
// }
|
||||||
|
// if (cycle % 2 == 0) {
|
||||||
|
// randomServerToggle(healthChecker, numHosts);
|
||||||
|
// }
|
||||||
|
if (cycle % 100 == 0) {
|
||||||
|
serversUnregistered.add(randomServerUnregister(numHosts));
|
||||||
|
}
|
||||||
|
if (cycle % 500 == 0) {
|
||||||
|
serversUnregistered.stream().forEach(tbh -> ServiceRegistry.registerService(curatorFramework, tbh));
|
||||||
|
serversUnregistered.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
cycle++;
|
||||||
|
}
|
||||||
|
LOG.debug("Stop balancedMetricResolver");
|
||||||
|
balancedMetricResolver.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package timely.balancer.resolver;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import timely.balancer.configuration.BalancerConfiguration;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.balancer.healthcheck.HealthChecker;
|
||||||
|
import timely.balancer.healthcheck.TcpHealthChecker;
|
||||||
|
|
||||||
|
public class TestHealthChecker implements HealthChecker {
|
||||||
|
|
||||||
|
private final Logger LOG = LoggerFactory.getLogger(TcpHealthChecker.class);
|
||||||
|
private List<TimelyBalancedHost> timelyHosts = new ArrayList<>();
|
||||||
|
private Map<TimelyBalancedHost, Boolean> serverUpMap = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
|
||||||
|
|
||||||
|
public TestHealthChecker(BalancerConfiguration config, List<TimelyBalancedHost> timelyHosts) {
|
||||||
|
setTimelyHosts(timelyHosts);
|
||||||
|
this.executorService.scheduleAtFixedRate(() -> {
|
||||||
|
synchronized (timelyHosts) {
|
||||||
|
for (TimelyBalancedHost h : timelyHosts) {
|
||||||
|
try {
|
||||||
|
if (TestHealthChecker.this.isServerHealthy(h)) {
|
||||||
|
h.reportSuccess();
|
||||||
|
} else {
|
||||||
|
h.reportFailure();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
h.reportFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0, config.getCheckServerHealthInterval(), TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTimelyHosts(List<TimelyBalancedHost> timelyHosts) {
|
||||||
|
synchronized (timelyHosts) {
|
||||||
|
this.timelyHosts.clear();
|
||||||
|
this.timelyHosts.addAll(timelyHosts);
|
||||||
|
for (TimelyBalancedHost h : timelyHosts) {
|
||||||
|
serverUpMap.put(h, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isServerHealthy(TimelyBalancedHost h) {
|
||||||
|
return serverUpMap.get(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serverUp(TimelyBalancedHost h) {
|
||||||
|
serverUpMap.put(h, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serverDown(TimelyBalancedHost h) {
|
||||||
|
serverUpMap.put(h, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serverToggle(TimelyBalancedHost h) {
|
||||||
|
synchronized (serverUpMap) {
|
||||||
|
serverUpMap.put(h, !serverUpMap.get(h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
this.executorService.shutdown();
|
||||||
|
try {
|
||||||
|
this.executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (!this.executorService.isTerminated()) {
|
||||||
|
this.executorService.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration status="WARN">
|
||||||
|
<Appenders>
|
||||||
|
<Console name="CONSOLE" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="%d{yyyyMMdd HHmmss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
|
||||||
|
</Console>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Logger name="org.apache.accumulo.core.client.impl.ThriftTransportPool" level="OFF" additivity="false" />
|
||||||
|
<Logger name="org.apache.accumulo.fate.zookeeper.ZooCache" level="OFF" additivity="false" />
|
||||||
|
<Logger name="org.apache.zookeeper" level="OFF" additivity="false" />
|
||||||
|
<Logger name="timely.balancer.resolver" level="TRACE" additivity="true" />
|
||||||
|
<Logger name="timely.balancer.resolver.TestBalancedMetricResolver" level="DEBUG" additivity="true" />
|
||||||
|
<Root level="ERROR">
|
||||||
|
<AppenderRef ref="CONSOLE"/>
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
+42
-2
@@ -4,12 +4,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-client</artifactId>
|
<artifactId>timely-client</artifactId>
|
||||||
<properties>
|
<properties>
|
||||||
<!-- PEP 440 compliant version gets substituted into src/main/python/template/setup.py -->
|
<!-- PEP 440 compliant version gets substituted into src/main/python/template/setup.py -->
|
||||||
<python.client.version>0.0.7.dev0</python.client.version>
|
<!-- use .dev0 instead of -SNAPSHOT -->
|
||||||
|
<python.client.version>1.2.8.dev0</python.client.version>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -107,4 +108,43 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>python</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>python-dist</id>
|
||||||
|
<goals>
|
||||||
|
<goal>exec</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>package</phase>
|
||||||
|
<configuration>
|
||||||
|
<executable>python</executable>
|
||||||
|
<workingDirectory>${project.basedir}/src/main/python</workingDirectory>
|
||||||
|
<commandlineArgs>setup.py sdist --dist-dir ${project.build.directory}</commandlineArgs>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>python-clean</id>
|
||||||
|
<goals>
|
||||||
|
<goal>exec</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>package</phase>
|
||||||
|
<configuration>
|
||||||
|
<executable>rm</executable>
|
||||||
|
<workingDirectory>${project.basedir}/src/main/python</workingDirectory>
|
||||||
|
<commandlineArgs>-rf timely.egg-info setup.py</commandlineArgs>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package timely.client.http;
|
package timely.client.http;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
import org.apache.http.client.CookieStore;
|
import org.apache.http.client.CookieStore;
|
||||||
import org.apache.http.client.config.CookieSpecs;
|
import org.apache.http.client.config.CookieSpecs;
|
||||||
import org.apache.http.client.config.RequestConfig;
|
import org.apache.http.client.config.RequestConfig;
|
||||||
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
|
||||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||||
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClients;
|
||||||
@@ -40,14 +41,31 @@ public class HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled) {
|
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled) {
|
||||||
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
return get(ssl, cookieStore, hostVerificationEnabled, false);
|
||||||
|
}
|
||||||
|
|
||||||
HttpClientBuilder builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore)
|
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled,
|
||||||
.setDefaultRequestConfig(defaultRequestConfig);
|
boolean clientAuth) {
|
||||||
|
HostnameVerifier hostnameVerifier;
|
||||||
if (hostVerificationEnabled) {
|
if (hostVerificationEnabled) {
|
||||||
builder.setSSLHostnameVerifier(new DefaultHostnameVerifier());
|
hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
|
||||||
} else {
|
} else {
|
||||||
builder.setSSLHostnameVerifier(new NoopHostnameVerifier());
|
hostnameVerifier = new NoopHostnameVerifier();
|
||||||
|
}
|
||||||
|
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
||||||
|
HttpClientBuilder builder;
|
||||||
|
if (cookieStore == null) {
|
||||||
|
builder = HttpClients.custom().setSSLContext(ssl).disableCookieManagement()
|
||||||
|
.setDefaultRequestConfig(defaultRequestConfig).setSSLHostnameVerifier(hostnameVerifier);
|
||||||
|
} else {
|
||||||
|
builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore)
|
||||||
|
.setDefaultRequestConfig(defaultRequestConfig).setSSLHostnameVerifier(hostnameVerifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientAuth) {
|
||||||
|
SSLConnectionSocketFactory sslCSF = new SSLConnectionSocketFactory(ssl,
|
||||||
|
new String[] { "TLSv1.1", "TLSv1.2" }, null, hostnameVerifier);
|
||||||
|
builder.setSSLSocketFactory(sslCSF);
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package timely.client.tcp;
|
package timely.client.tcp;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -14,7 +15,7 @@ public class TcpClient implements AutoCloseable {
|
|||||||
private final String host;
|
private final String host;
|
||||||
private final int port;
|
private final int port;
|
||||||
private Socket sock = null;
|
private Socket sock = null;
|
||||||
private PrintWriter out = null;
|
private BufferedWriter out = null;
|
||||||
private long connectTime = 0L;
|
private long connectTime = 0L;
|
||||||
private long backoff = 2000;
|
private long backoff = 2000;
|
||||||
private int bufferSize = -1;
|
private int bufferSize = -1;
|
||||||
@@ -47,7 +48,6 @@ public class TcpClient implements AutoCloseable {
|
|||||||
*
|
*
|
||||||
* @param metric
|
* @param metric
|
||||||
* newline terminated string representation of Timely metric
|
* newline terminated string representation of Timely metric
|
||||||
* @throws IOException
|
|
||||||
*/
|
*/
|
||||||
public synchronized void write(String metric) throws IOException {
|
public synchronized void write(String metric) throws IOException {
|
||||||
if (connect() != 0) {
|
if (connect() != 0) {
|
||||||
@@ -60,7 +60,7 @@ public class TcpClient implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void flush() {
|
public synchronized void flush() throws IOException {
|
||||||
if (null != out) {
|
if (null != out) {
|
||||||
out.flush();
|
out.flush();
|
||||||
writesSinceFlush = 0;
|
writesSinceFlush = 0;
|
||||||
@@ -94,12 +94,12 @@ public class TcpClient implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized int connect() {
|
private synchronized int connect() {
|
||||||
if (null == sock || !sock.isConnected() || out.checkError()) {
|
if (null == sock || !sock.isConnected()) {
|
||||||
if (System.currentTimeMillis() > (connectTime + backoff)) {
|
if (System.currentTimeMillis() > (connectTime + backoff)) {
|
||||||
try {
|
try {
|
||||||
connectTime = System.currentTimeMillis();
|
connectTime = System.currentTimeMillis();
|
||||||
sock = new Socket(host, port);
|
sock = new Socket(host, port);
|
||||||
out = new PrintWriter(sock.getOutputStream(), false);
|
out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
|
||||||
backoff = 2000;
|
backoff = 2000;
|
||||||
LOG.trace("Connected to Timely at {}:{}", host, port);
|
LOG.trace("Connected to Timely at {}:{}", host, port);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package timely.client.websocket;
|
package timely.client.websocket;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.Endpoint;
|
import javax.websocket.Endpoint;
|
||||||
import javax.websocket.EndpointConfig;
|
import javax.websocket.EndpointConfig;
|
||||||
@@ -35,4 +38,6 @@ public abstract class ClientHandler extends Endpoint {
|
|||||||
LOG.error("Error occurred on Websocket session" + session.getId(), error);
|
LOG.error("Error occurred on Websocket session" + session.getId(), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void beforeRequest(Map<String, List<String>> headers) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,13 +14,15 @@ import org.apache.http.cookie.Cookie;
|
|||||||
public class TimelyEndpointConfig implements ClientEndpointConfig {
|
public class TimelyEndpointConfig implements ClientEndpointConfig {
|
||||||
|
|
||||||
private String sessionCookie = null;
|
private String sessionCookie = null;
|
||||||
|
private final ClientHandler clientEndpoint;
|
||||||
|
|
||||||
private static final String FORMAT = "%s=%s;";
|
private static final String FORMAT = "%s=%s;";
|
||||||
|
|
||||||
public TimelyEndpointConfig(Cookie sessionCookie) {
|
public TimelyEndpointConfig(ClientHandler clientEndpoint, Cookie sessionCookie) {
|
||||||
if (null != sessionCookie) {
|
if (null != sessionCookie) {
|
||||||
this.sessionCookie = String.format(FORMAT, sessionCookie.getName(), sessionCookie.getValue());
|
this.sessionCookie = String.format(FORMAT, sessionCookie.getName(), sessionCookie.getValue());
|
||||||
}
|
}
|
||||||
|
this.clientEndpoint = clientEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -58,6 +60,7 @@ public class TimelyEndpointConfig implements ClientEndpointConfig {
|
|||||||
if (null != sessionCookie) {
|
if (null != sessionCookie) {
|
||||||
headers.put("Cookie", Collections.singletonList(sessionCookie));
|
headers.put("Cookie", Collections.singletonList(sessionCookie));
|
||||||
}
|
}
|
||||||
|
TimelyEndpointConfig.this.clientEndpoint.beforeRequest(headers);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
private final int timelyHttpsPort;
|
private final int timelyHttpsPort;
|
||||||
private final int timelyWssPort;
|
private final int timelyWssPort;
|
||||||
private final boolean doLogin;
|
private final boolean doLogin;
|
||||||
|
private final boolean clientAuth;
|
||||||
private final String timelyUsername;
|
private final String timelyUsername;
|
||||||
private final String timelyPassword;
|
private final String timelyPassword;
|
||||||
private final boolean hostVerificationEnabled;
|
private final boolean hostVerificationEnabled;
|
||||||
@@ -51,13 +52,14 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
protected volatile boolean closed = true;
|
protected volatile boolean closed = true;
|
||||||
|
|
||||||
protected WebSocketClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
protected WebSocketClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
||||||
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
|
boolean clientAuth, boolean doLogin, String timelyUsername, String timelyPassword,
|
||||||
int bufferSize) {
|
boolean hostVerificationEnabled, int bufferSize) {
|
||||||
this.ssl = ssl;
|
this.ssl = ssl;
|
||||||
this.timelyHostname = timelyHostname;
|
this.timelyHostname = timelyHostname;
|
||||||
this.timelyHttpsPort = timelyHttpsPort;
|
this.timelyHttpsPort = timelyHttpsPort;
|
||||||
this.timelyWssPort = timelyWssPort;
|
this.timelyWssPort = timelyWssPort;
|
||||||
this.doLogin = doLogin;
|
this.doLogin = doLogin;
|
||||||
|
this.clientAuth = clientAuth;
|
||||||
this.timelyUsername = timelyUsername;
|
this.timelyUsername = timelyUsername;
|
||||||
this.timelyPassword = timelyPassword;
|
this.timelyPassword = timelyPassword;
|
||||||
this.hostVerificationEnabled = hostVerificationEnabled;
|
this.hostVerificationEnabled = hostVerificationEnabled;
|
||||||
@@ -67,28 +69,28 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
Preconditions.checkNotNull(timelyHttpsPort, "%s must be supplied", "Timely HTTPS port");
|
Preconditions.checkNotNull(timelyHttpsPort, "%s must be supplied", "Timely HTTPS port");
|
||||||
Preconditions.checkNotNull(timelyWssPort, "%s must be supplied", "Timely WSS port");
|
Preconditions.checkNotNull(timelyWssPort, "%s must be supplied", "Timely WSS port");
|
||||||
|
|
||||||
if (doLogin && ((StringUtils.isEmpty(timelyUsername) && !StringUtils.isEmpty(timelyPassword)
|
if (doLogin && !clientAuth) {
|
||||||
|| (!StringUtils.isEmpty(timelyUsername) && StringUtils.isEmpty(timelyPassword))))) {
|
if ((StringUtils.isEmpty(timelyUsername) && !StringUtils.isEmpty(timelyPassword)
|
||||||
throw new IllegalArgumentException("Both Timely username and password must be empty or non-empty");
|
|| (!StringUtils.isEmpty(timelyUsername) && StringUtils.isEmpty(timelyPassword)))) {
|
||||||
|
throw new IllegalArgumentException("Both Timely username and password must be empty or non-empty");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected WebSocketClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
|
protected WebSocketClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean clientAuth,
|
||||||
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType, String keyStorePass,
|
boolean doLogin, String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
|
||||||
String trustStoreFile, String trustStoreType, String trustStorePass, boolean hostVerificationEnabled,
|
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
|
||||||
int bufferSize) {
|
boolean hostVerificationEnabled, int bufferSize) {
|
||||||
this(HttpClient.getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
|
this(HttpClient.getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
|
||||||
keyStorePass), timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
|
keyStorePass), timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, timelyUsername,
|
||||||
hostVerificationEnabled, bufferSize);
|
timelyPassword, hostVerificationEnabled, bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
|
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
|
||||||
|
|
||||||
Cookie sessionCookie = null;
|
Cookie sessionCookie = null;
|
||||||
if (doLogin) {
|
if (doLogin) {
|
||||||
BasicCookieStore cookieJar = new BasicCookieStore();
|
BasicCookieStore cookieJar = new BasicCookieStore();
|
||||||
try (CloseableHttpClient client = HttpClient.get(ssl, cookieJar, hostVerificationEnabled)) {
|
try (CloseableHttpClient client = HttpClient.get(ssl, cookieJar, hostVerificationEnabled, clientAuth)) {
|
||||||
|
|
||||||
String target = "https://" + timelyHostname + ":" + timelyHttpsPort + "/login";
|
String target = "https://" + timelyHostname + ":" + timelyHttpsPort + "/login";
|
||||||
|
|
||||||
@@ -140,8 +142,8 @@ public class WebSocketClient implements AutoCloseable {
|
|||||||
webSocketClient.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
|
webSocketClient.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
|
||||||
webSocketClient.getProperties().put(ClientProperties.INCOMING_BUFFER_SIZE, bufferSize);
|
webSocketClient.getProperties().put(ClientProperties.INCOMING_BUFFER_SIZE, bufferSize);
|
||||||
String wssPath = "wss://" + timelyHostname + ":" + timelyWssPort + "/websocket";
|
String wssPath = "wss://" + timelyHostname + ":" + timelyWssPort + "/websocket";
|
||||||
session = webSocketClient.connectToServer(clientEndpoint, new TimelyEndpointConfig(sessionCookie),
|
session = webSocketClient.connectToServer(clientEndpoint,
|
||||||
new URI(wssPath));
|
new TimelyEndpointConfig(clientEndpoint, sessionCookie), new URI(wssPath));
|
||||||
|
|
||||||
final ByteBuffer pingData = ByteBuffer.allocate(0);
|
final ByteBuffer pingData = ByteBuffer.allocate(0);
|
||||||
webSocketClient.getScheduledExecutorService().scheduleAtFixedRate(() -> {
|
webSocketClient.getScheduledExecutorService().scheduleAtFixedRate(() -> {
|
||||||
|
|||||||
+10
-10
@@ -27,21 +27,21 @@ public class WebSocketSubscriptionClient extends WebSocketClient {
|
|||||||
private final String subscriptionId;
|
private final String subscriptionId;
|
||||||
|
|
||||||
public WebSocketSubscriptionClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
public WebSocketSubscriptionClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
||||||
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
|
boolean clientAuth, boolean doLogin, String timelyUsername, String timelyPassword,
|
||||||
int bufferSize) {
|
boolean hostVerificationEnabled, int bufferSize) {
|
||||||
super(ssl, timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
|
super(ssl, timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, timelyUsername, timelyPassword,
|
||||||
hostVerificationEnabled, bufferSize);
|
hostVerificationEnabled, bufferSize);
|
||||||
subscriptionId = UUID.randomUUID().toString();
|
subscriptionId = UUID.randomUUID().toString();
|
||||||
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebSocketSubscriptionClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
|
public WebSocketSubscriptionClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
||||||
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType, String keyStorePass,
|
boolean clientAuth, boolean doLogin, String timelyUsername, String timelyPassword, String keyStoreFile,
|
||||||
String trustStoreFile, String trustStoreType, String trustStorePass, boolean hostVerificationEnabled,
|
String keyStoreType, String keyStorePass, String trustStoreFile, String trustStoreType,
|
||||||
int bufferSize) {
|
String trustStorePass, boolean hostVerificationEnabled, int bufferSize) {
|
||||||
super(timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword, keyStoreFile,
|
super(timelyHostname, timelyHttpsPort, timelyWssPort, clientAuth, doLogin, timelyUsername, timelyPassword,
|
||||||
keyStoreType, keyStorePass, trustStoreFile, trustStoreType, trustStorePass, hostVerificationEnabled,
|
keyStoreFile, keyStoreType, keyStorePass, trustStoreFile, trustStoreType, trustStorePass,
|
||||||
bufferSize);
|
hostVerificationEnabled, bufferSize);
|
||||||
subscriptionId = UUID.randomUUID().toString();
|
subscriptionId = UUID.randomUUID().toString();
|
||||||
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ public interface ObjectSizeOf {
|
|||||||
* ObjectSizeOf interface and if implemented on the object will use that.
|
* ObjectSizeOf interface and if implemented on the object will use that.
|
||||||
* Otherwise it will do a simple navigation of the fields using reflection.
|
* Otherwise it will do a simple navigation of the fields using reflection.
|
||||||
*
|
*
|
||||||
* @param o
|
|
||||||
* @return an approximation of the object size
|
* @return an approximation of the object size
|
||||||
*/
|
*/
|
||||||
public static long getObjectSize(Object o, boolean useSizeInBytesMethod, boolean debug) {
|
public static long getObjectSize(Object o, boolean useSizeInBytesMethod, boolean debug) {
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ public class Tag implements Comparable<Tag>, Serializable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Joins key and value into key=value
|
* Joins key and value into key=value
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public String join() {
|
public String join() {
|
||||||
return tagParser.combine(this);
|
return tagParser.combine(this);
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag
|
|||||||
* An alternative combiner for a map of string to string instead of a list of
|
* An alternative combiner for a map of string to string instead of a list of
|
||||||
* tags
|
* tags
|
||||||
*
|
*
|
||||||
* @param tags
|
|
||||||
* @return string representation
|
* @return string representation
|
||||||
*/
|
*/
|
||||||
public String combine(Map<String, String> tags) {
|
public String combine(Map<String, String> tags) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def pivot(df, metric, groupByColumn=None):
|
|||||||
return dataFrame
|
return dataFrame
|
||||||
|
|
||||||
|
|
||||||
def resample(df, sample, how='mean'):
|
def resample(df, sample, how='mean', interpolate=True, fill=None):
|
||||||
|
|
||||||
dataFrame = pandas.DataFrame(df, copy=True)
|
dataFrame = pandas.DataFrame(df, copy=True)
|
||||||
if dataFrame is not None:
|
if dataFrame is not None:
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import time
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from datetime import tzinfo
|
from datetime import tzinfo
|
||||||
from pandas.tslib import Timedelta
|
|
||||||
import pandas
|
import pandas
|
||||||
|
|
||||||
class TimeDateError(ValueError):
|
class TimeDateError(ValueError):
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ utc = UTC()
|
|||||||
class TimelyWebSocketClient(WebSocketClient):
|
class TimelyWebSocketClient(WebSocketClient):
|
||||||
|
|
||||||
def __init__(self, hostport, metric, tags, startTime, endTime, connect_timeout=WebSocketClient.DEFAULT_CONNECT_TIMEOUT,
|
def __init__(self, hostport, metric, tags, startTime, endTime, connect_timeout=WebSocketClient.DEFAULT_CONNECT_TIMEOUT,
|
||||||
request_timeout=WebSocketClient.DEFAULT_REQUEST_TIMEOUT):
|
request_timeout=WebSocketClient.DEFAULT_REQUEST_TIMEOUT, client_cert=None, client_key=None, ca_certs=None, validate_cert=False):
|
||||||
|
|
||||||
self.metric = metric
|
self.metric = metric
|
||||||
self.tags = tags
|
self.tags = tags
|
||||||
self.startTime = startTime
|
self.startTime = startTime
|
||||||
self.endTime = endTime
|
self.endTime = endTime
|
||||||
self.subscriptionId = random.randint(1000000000, 9999999999)
|
self.subscriptionId = random.randint(1000000000, 9999999999)
|
||||||
WebSocketClient.__init__(self, hostport, '/websocket', {'metric' : metric}, connect_timeout, request_timeout)
|
WebSocketClient.__init__(self, hostport, '/websocket', {'metric' : metric}, connect_timeout, request_timeout,
|
||||||
|
client_cert=client_cert, client_key=client_key, ca_certs=ca_certs, validate_cert=validate_cert)
|
||||||
|
|
||||||
def _on_message(self, msg):
|
def _on_message(self, msg):
|
||||||
# implement in subclass
|
# implement in subclass
|
||||||
@@ -72,7 +73,8 @@ class TimelyMetric(TimelyWebSocketClient):
|
|||||||
client = None
|
client = None
|
||||||
endtime = None
|
endtime = None
|
||||||
|
|
||||||
def __init__(self, hostport, metric, tags, beginStr, endStr, period, sample):
|
def __init__(self, hostport, metric, tags, beginStr, endStr, period, sample,
|
||||||
|
client_cert=None, client_key=None, ca_certs=None, validate_cert=False):
|
||||||
self.series = pandas.Series()
|
self.series = pandas.Series()
|
||||||
self.metric = metric
|
self.metric = metric
|
||||||
self.tags = tags
|
self.tags = tags
|
||||||
@@ -82,7 +84,8 @@ class TimelyMetric(TimelyWebSocketClient):
|
|||||||
self.data = []
|
self.data = []
|
||||||
self.timeDateRange = TimeDateRange(beginStr, endStr, period)
|
self.timeDateRange = TimeDateRange(beginStr, endStr, period)
|
||||||
|
|
||||||
TimelyWebSocketClient.__init__(self, hostport, metric, tags, self.timeDateRange.getBeginMs(), self.timeDateRange.getEndMs())
|
TimelyWebSocketClient.__init__(self, hostport, metric, tags, self.timeDateRange.getBeginMs(), self.timeDateRange.getEndMs(),
|
||||||
|
client_cert=client_cert, client_key=client_key, ca_certs=ca_certs, validate_cert=validate_cert)
|
||||||
|
|
||||||
def debugOn(self):
|
def debugOn(self):
|
||||||
self.debug = True
|
self.debug = True
|
||||||
|
|||||||
@@ -15,10 +15,14 @@ class WebSocketClient():
|
|||||||
APPLICATION_JSON = 'application/json'
|
APPLICATION_JSON = 'application/json'
|
||||||
|
|
||||||
def __init__(self, hostport, path, params, connect_timeout=DEFAULT_CONNECT_TIMEOUT,
|
def __init__(self, hostport, path, params, connect_timeout=DEFAULT_CONNECT_TIMEOUT,
|
||||||
request_timeout=DEFAULT_REQUEST_TIMEOUT):
|
request_timeout=DEFAULT_REQUEST_TIMEOUT, client_cert=None, client_key=None, ca_certs=None, validate_cert=False):
|
||||||
|
|
||||||
self.connect_timeout = connect_timeout
|
self.connect_timeout = connect_timeout
|
||||||
self.request_timeout = request_timeout
|
self.request_timeout = request_timeout
|
||||||
|
self.client_cert=client_cert
|
||||||
|
self.client_key=client_key
|
||||||
|
self.ca_certs=ca_certs
|
||||||
|
self.validate_cert=validate_cert
|
||||||
self.url = 'wss://' + hostport
|
self.url = 'wss://' + hostport
|
||||||
if (path is not None and len(path) > 0):
|
if (path is not None and len(path) > 0):
|
||||||
if (path.startswith('/')):
|
if (path.startswith('/')):
|
||||||
@@ -39,7 +43,8 @@ class WebSocketClient():
|
|||||||
"""Connect to the server.
|
"""Connect to the server.
|
||||||
:param str url: server URL.
|
:param str url: server URL.
|
||||||
"""
|
"""
|
||||||
request = websocket.httpclient.HTTPRequest(self.url, connect_timeout=self.connect_timeout, request_timeout=self.request_timeout, validate_cert=False)
|
request = websocket.httpclient.HTTPRequest(self.url, connect_timeout=self.connect_timeout, request_timeout=self.request_timeout, validate_cert=self.validate_cert,
|
||||||
|
client_cert=self.client_cert, client_key=self.client_key, ca_certs=self.ca_certs)
|
||||||
websocket.websocket_connect(request, io_loop=ioloop, callback=self._connect_callback)
|
websocket.websocket_connect(request, io_loop=ioloop, callback=self._connect_callback)
|
||||||
|
|
||||||
def send(self, data):
|
def send(self, data):
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ import os
|
|||||||
from timely.TimelyAnalyticConfiguration import TimelyAnalyticConfiguration
|
from timely.TimelyAnalyticConfiguration import TimelyAnalyticConfiguration
|
||||||
|
|
||||||
hostport = "127.0.0.1:5244"
|
hostport = "127.0.0.1:5244"
|
||||||
timelyMetric = timely.TimelyMetric.TimelyMetric(hostport, 'timely.keys.metric.inserted', None, None, None, '24 hours', None).fetch()
|
client_cert = None
|
||||||
|
client_key = None
|
||||||
|
timelyMetric = timely.TimelyMetric.TimelyMetric(hostport, 'timely.keys.metric.inserted', None, None, None, '24 hours', None, client_cert=client_cert, client_key=client_key).fetch()
|
||||||
|
|
||||||
print(timelyMetric.getDataFrame())
|
print(timelyMetric.getDataFrame())
|
||||||
exit()
|
exit()
|
||||||
|
|||||||
@@ -5,4 +5,9 @@
|
|||||||
<Method name="connect" />
|
<Method name="connect" />
|
||||||
<Class name="timely.client.tcp.TcpClient"/>
|
<Class name="timely.client.tcp.TcpClient"/>
|
||||||
</Match>
|
</Match>
|
||||||
|
<Match>
|
||||||
|
<!-- Must ignore these everywhere, because of a javac byte code generation bug -->
|
||||||
|
<!-- https://github.com/spotbugs/spotbugs/issues/756 -->
|
||||||
|
<Bug pattern="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE" />
|
||||||
|
</Match>
|
||||||
</FindBugsFilter>
|
</FindBugsFilter>
|
||||||
@@ -47,9 +47,9 @@ public class SerializationTest {
|
|||||||
testSerialization(remove);
|
testSerialization(remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <T> void testSerialization(T o) throws Exception {
|
private <T> void testSerialization(T o) throws Exception {
|
||||||
String ser = mapper.writeValueAsString(o);
|
String ser = mapper.writeValueAsString(o);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
T des = mapper.readValue(ser, (Class<T>) o.getClass());
|
T des = mapper.readValue(ser, (Class<T>) o.getClass());
|
||||||
Assert.assertEquals(o, des);
|
Assert.assertEquals(o, des);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>collectd-nsq-plugin</artifactId>
|
<artifactId>collectd-nsq-plugin</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
+8
-8
@@ -10,7 +10,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
|||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.collectd.api.OConfigItem;
|
import org.collectd.api.OConfigItem;
|
||||||
|
|
||||||
public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
|
public class PooledCloseableHttpClientFactory implements PooledObjectFactory<CloseableHttpClient> {
|
||||||
|
|
||||||
private int connectionRequestTimeout = 10000; // 10 seconds in milliseconds
|
private int connectionRequestTimeout = 10000; // 10 seconds in milliseconds
|
||||||
private int connectTimeout = 30000; // 30 seconds in milliseconds
|
private int connectTimeout = 30000; // 30 seconds in milliseconds
|
||||||
@@ -43,19 +43,19 @@ public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PooledObject makeObject() throws Exception {
|
public PooledObject<CloseableHttpClient> makeObject() throws Exception {
|
||||||
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout)
|
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout)
|
||||||
.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
|
.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
|
||||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||||
builder.setDefaultRequestConfig(requestConfig);
|
builder.setDefaultRequestConfig(requestConfig);
|
||||||
builder.setConnectionTimeToLive(connectionTimeToLive, TimeUnit.MILLISECONDS);
|
builder.setConnectionTimeToLive(connectionTimeToLive, TimeUnit.MILLISECONDS);
|
||||||
return new DefaultPooledObject(builder.build());
|
return new DefaultPooledObject<>(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroyObject(PooledObject pooledObject) throws Exception {
|
public void destroyObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
|
||||||
try {
|
try {
|
||||||
((CloseableHttpClient) pooledObject.getObject()).close();
|
pooledObject.getObject().close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
} finally {
|
} finally {
|
||||||
@@ -65,17 +65,17 @@ public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateObject(PooledObject pooledObject) {
|
public boolean validateObject(PooledObject<CloseableHttpClient> pooledObject) {
|
||||||
return pooledObject.getObject() != null;
|
return pooledObject.getObject() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateObject(PooledObject pooledObject) throws Exception {
|
public void activateObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void passivateObject(PooledObject pooledObject) throws Exception {
|
public void passivateObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ public class WriteNSQPlugin extends CollectDPluginParent
|
|||||||
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
|
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int write(ValueList vl) {
|
public int write(ValueList vl) {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
DataOutputStream out = new DataOutputStream(baos);
|
DataOutputStream out = new DataOutputStream(baos);
|
||||||
@@ -110,15 +111,17 @@ public class WriteNSQPlugin extends CollectDPluginParent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int shutdown() {
|
public int shutdown() {
|
||||||
Collectd.logInfo("Shutting down connection to NSQ at " + host + ":" + port);
|
Collectd.logInfo("Shutting down connection to NSQ at " + host + ":" + port);
|
||||||
clientPool.close();
|
clientPool.close();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int config(OConfigItem config) {
|
public int config(OConfigItem config) {
|
||||||
super.config(config);
|
super.config(config);
|
||||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
GenericObjectPoolConfig<CloseableHttpClient> poolConfig = new GenericObjectPoolConfig<>();
|
||||||
// use max size for maxTotal and maxIdle
|
// use max size for maxTotal and maxIdle
|
||||||
// no need to activate or passivate
|
// no need to activate or passivate
|
||||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||||
@@ -156,7 +159,7 @@ public class WriteNSQPlugin extends CollectDPluginParent
|
|||||||
Collectd.logError("NSQ host, port, and topic must be configured");
|
Collectd.logError("NSQ host, port, and topic must be configured");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
this.clientPool = new GenericObjectPool(pooledCloseableHttpClientFactory, poolConfig);
|
this.clientPool = new GenericObjectPool<>(pooledCloseableHttpClientFactory, poolConfig);
|
||||||
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
|
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>collectd-plugin-parent</artifactId>
|
<artifactId>collectd-plugin-parent</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>collectd-timely-plugin</artifactId>
|
<artifactId>collectd-timely-plugin</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
+7
-7
@@ -8,7 +8,7 @@ import org.apache.commons.pool2.impl.DefaultPooledObject;
|
|||||||
import org.collectd.api.Collectd;
|
import org.collectd.api.Collectd;
|
||||||
import org.collectd.api.OConfigItem;
|
import org.collectd.api.OConfigItem;
|
||||||
|
|
||||||
public class PooledSocketFactory implements PooledObjectFactory {
|
public class PooledSocketFactory implements PooledObjectFactory<Socket> {
|
||||||
|
|
||||||
private String host = null;
|
private String host = null;
|
||||||
private int port = 0;
|
private int port = 0;
|
||||||
@@ -81,12 +81,12 @@ public class PooledSocketFactory implements PooledObjectFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PooledObject makeObject() throws Exception {
|
public PooledObject<Socket> makeObject() throws Exception {
|
||||||
return new DefaultPooledObject(connect());
|
return new DefaultPooledObject<>(connect());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroyObject(PooledObject pooledObject) throws Exception {
|
public void destroyObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||||
try {
|
try {
|
||||||
Collectd.logDebug("Shutting down connection to Timely at " + host + ":" + port);
|
Collectd.logDebug("Shutting down connection to Timely at " + host + ":" + port);
|
||||||
Socket socket = (Socket) pooledObject.getObject();
|
Socket socket = (Socket) pooledObject.getObject();
|
||||||
@@ -103,7 +103,7 @@ public class PooledSocketFactory implements PooledObjectFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateObject(PooledObject pooledObject) {
|
public boolean validateObject(PooledObject<Socket> pooledObject) {
|
||||||
if (connectionTimeToLive > -1) {
|
if (connectionTimeToLive > -1) {
|
||||||
if (System.currentTimeMillis() > pooledObject.getCreateTime() + connectionTimeToLive) {
|
if (System.currentTimeMillis() > pooledObject.getCreateTime() + connectionTimeToLive) {
|
||||||
return false;
|
return false;
|
||||||
@@ -114,12 +114,12 @@ public class PooledSocketFactory implements PooledObjectFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activateObject(PooledObject pooledObject) throws Exception {
|
public void activateObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void passivateObject(PooledObject pooledObject) throws Exception {
|
public void passivateObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,13 +86,13 @@ public class WriteTimelyPlugin extends CollectDPluginParent
|
|||||||
PooledSocketFactory socketFactory = new PooledSocketFactory();
|
PooledSocketFactory socketFactory = new PooledSocketFactory();
|
||||||
retval = socketFactory.config(config);
|
retval = socketFactory.config(config);
|
||||||
if (retval == 0) {
|
if (retval == 0) {
|
||||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
GenericObjectPoolConfig<Socket> poolConfig = new GenericObjectPoolConfig<>();
|
||||||
// use max size for maxTotal and maxIdle
|
// use max size for maxTotal and maxIdle
|
||||||
// no need to activate and passivate
|
// no need to activate and passivate
|
||||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||||
poolConfig.setMaxIdle(POOL_MAX_SIZE);
|
poolConfig.setMaxIdle(POOL_MAX_SIZE);
|
||||||
poolConfig.setTestOnReturn(true);
|
poolConfig.setTestOnReturn(true);
|
||||||
socketPool = new GenericObjectPool(socketFactory, poolConfig);
|
socketPool = new GenericObjectPool<>(socketFactory, poolConfig);
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-common</artifactId>
|
<artifactId>timely-common</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
Executable
+42
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ `uname` == "Darwin" ]]; then
|
||||||
|
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
||||||
|
TCNATIVE_SUFFIX="jnilib"
|
||||||
|
else
|
||||||
|
THIS_SCRIPT=`readlink -f $0`
|
||||||
|
TCNATIVE_SUFFIX="so"
|
||||||
|
fi
|
||||||
|
|
||||||
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
|
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
||||||
|
BASE_DIR=${THIS_DIR}/..
|
||||||
|
TMP_DIR="${BASE_DIR}/tmp"
|
||||||
|
CONF_DIR="${BASE_DIR}/conf"
|
||||||
|
LIB_DIR="${BASE_DIR}/lib"
|
||||||
|
NUM_SERVER_THREADS=4
|
||||||
|
|
||||||
|
if [[ -e ${TMP_DIR} ]]; then
|
||||||
|
rm -rf ${TMP_DIR}
|
||||||
|
fi
|
||||||
|
mkdir ${TMP_DIR}
|
||||||
|
|
||||||
|
if [[ -e ${NATIVE_DIR} ]]; then
|
||||||
|
rm -rf ${NATIVE_DIR}
|
||||||
|
fi
|
||||||
|
mkdir -p ${NATIVE_DIR}
|
||||||
|
|
||||||
|
pushd ${BASE_DIR}/bin
|
||||||
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative-boringssl-static*.jar META-INF/native/libnetty_tcnative_linux_x86_64.${TCNATIVE_SUFFIX}
|
||||||
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-all*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${TCNATIVE_SUFFIX}
|
||||||
|
popd
|
||||||
|
|
||||||
|
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*:${HADOOP_CONF_DIR}"
|
||||||
|
JVM_ARGS="-Xmx1G -Xms1G -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} Dlog4j.configurationFile=${CONF_DIR}/log4j2-spring.xml"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||||
|
|
||||||
|
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
|
||||||
|
|
||||||
|
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.grafana.auth.GrafanaAuth --spring.config.name=grafana-auth"
|
||||||
|
$JAVA_HOME/bin/java ${JVM_ARGS} timely.grafana.auth.GrafanaAuth --spring.config.name=grafana-auth
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
grafana-auth:
|
||||||
|
grafana:
|
||||||
|
host: localhost
|
||||||
|
port: 3001
|
||||||
|
security:
|
||||||
|
session-max-age: 86400
|
||||||
|
cache-expiration-minutes: 60
|
||||||
|
cache-refresh-minutes: 5
|
||||||
|
allow-anonymous-http-access: true
|
||||||
|
allow-anonymous-ws-access: true
|
||||||
|
serverSsl:
|
||||||
|
certificate-file:
|
||||||
|
key-file:
|
||||||
|
#key-password:
|
||||||
|
use-generated-keypair: true
|
||||||
|
trust-store-file:
|
||||||
|
use-openssl: true
|
||||||
|
#use-ciphers:
|
||||||
|
clientSsl:
|
||||||
|
keyFile:
|
||||||
|
keyType: pkcs12
|
||||||
|
#keyPassword:
|
||||||
|
trustStoreFile:
|
||||||
|
trustStoreType: jks
|
||||||
|
#trustStorePassword:
|
||||||
|
http:
|
||||||
|
host: localhost
|
||||||
|
ip: 127.0.0.1
|
||||||
|
port: 3000
|
||||||
|
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
|
||||||
|
httpClientPool:
|
||||||
|
minIdlePerKey: 0
|
||||||
|
maxIdlePerKey: 40
|
||||||
|
maxTotalPerKey: 40
|
||||||
|
maxTotal: -1
|
||||||
|
lifo: true
|
||||||
|
fairness: false
|
||||||
|
maxWaitMillis: -1
|
||||||
|
minEvictableIdleTimeMillis: 1800000
|
||||||
|
evictorShutdownTimeoutMillis: 10000
|
||||||
|
softMinEvictableIdleTimeMillis: -1
|
||||||
|
numTestsPerEvictionRun: 3
|
||||||
|
timeBetweenEvictionRunsMillis: -1
|
||||||
|
blockWhenExhausted: true
|
||||||
|
jmxEnabled: true
|
||||||
|
testOnBorrow: false
|
||||||
|
testOnReturn: false
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration status="warn" monitorInterval="60">
|
||||||
|
<Appenders>
|
||||||
|
<Console name="Console" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
|
||||||
|
</Console>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Root level="error" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console" level="error" />
|
||||||
|
</Root>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Configuration status="warn" monitorInterval="60">
|
||||||
|
<Properties>
|
||||||
|
<Property name="PID">????</Property>
|
||||||
|
<Property name="LOG_PATTERN">%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%wEx</Property>
|
||||||
|
</Properties>
|
||||||
|
<Appenders>
|
||||||
|
<RollingRandomAccessFile name="Rolling" fileName="/srv/logs/timely/grafana-auth.log"
|
||||||
|
filePattern="/srv/logs/timely/$${date:yyyy-MM}/grafana-auth-%d{MM-dd-yyyy}-%i.log.gz">
|
||||||
|
<PatternLayout pattern="${LOG_PATTERN}"/>
|
||||||
|
<Policies>
|
||||||
|
<SizeBasedTriggeringPolicy size="1024 MB" />
|
||||||
|
</Policies>
|
||||||
|
<DefaultRolloverStrategy max="10" />
|
||||||
|
</RollingRandomAccessFile>
|
||||||
|
<Console name="Console" target="SYSTEM_OUT">
|
||||||
|
<PatternLayout pattern="${LOG_PATTERN}"/>
|
||||||
|
</Console>
|
||||||
|
</Appenders>
|
||||||
|
<Loggers>
|
||||||
|
<Root level="trace" includeLocation="false">
|
||||||
|
<AppenderRef ref="Console" level="warn" />
|
||||||
|
<AppenderRef ref="Rolling" level="trace" />
|
||||||
|
</Root>
|
||||||
|
<Logger name="timely" additivity="false">
|
||||||
|
<AppenderRef ref="Console" level="debug" />
|
||||||
|
</Logger>
|
||||||
|
</Loggers>
|
||||||
|
</Configuration>
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<beans:beans xmlns="http://www.springframework.org/schema/security"
|
||||||
|
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||||
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
|
http://www.springframework.org/schema/security
|
||||||
|
http://www.springframework.org/schema/security/spring-security.xsd
|
||||||
|
http://www.springframework.org/schema/util
|
||||||
|
http://www.springframework.org/schema/util/spring-util.xsd">
|
||||||
|
|
||||||
|
<beans:bean id="x509PrincipalExtractor" class="org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor">
|
||||||
|
<beans:property name="subjectDnRegex" value="CN=(.*?)(?:,|$)"/>
|
||||||
|
</beans:bean>
|
||||||
|
|
||||||
|
<beans:bean id="timelyUserDetailsService" class="timely.auth.UserDetailsService">
|
||||||
|
<beans:property name="users">
|
||||||
|
<util:list>
|
||||||
|
<beans:bean class="timely.auth.TimelyUser">
|
||||||
|
<beans:constructor-arg name="subjectDn">
|
||||||
|
<beans:value>CN=example.com</beans:value>
|
||||||
|
</beans:constructor-arg>
|
||||||
|
<beans:constructor-arg name="auths">
|
||||||
|
<util:list>
|
||||||
|
<beans:value>D</beans:value>
|
||||||
|
<beans:value>E</beans:value>
|
||||||
|
<beans:value>F</beans:value>
|
||||||
|
</util:list>
|
||||||
|
</beans:constructor-arg>
|
||||||
|
<beans:constructor-arg name="roles">
|
||||||
|
<util:list>
|
||||||
|
<beans:value>G</beans:value>
|
||||||
|
<beans:value>H</beans:value>
|
||||||
|
<beans:value>I</beans:value>
|
||||||
|
</util:list>
|
||||||
|
</beans:constructor-arg>
|
||||||
|
</beans:bean>
|
||||||
|
</util:list>
|
||||||
|
</beans:property>
|
||||||
|
</beans:bean>
|
||||||
|
|
||||||
|
<beans:bean id="x509AuthorizationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
|
||||||
|
<beans:property name="preAuthenticatedUserDetailsService" ref="timelyUserDetailsService" />
|
||||||
|
</beans:bean>
|
||||||
|
|
||||||
|
<user-service id="usernamePasswordService">
|
||||||
|
<user name="test" password="test1" authorities="A,B,C" />
|
||||||
|
</user-service>
|
||||||
|
|
||||||
|
<beans:bean id="noOpPasswordEncoder" class="org.springframework.security.crypto.password.NoOpPasswordEncoder"/>
|
||||||
|
|
||||||
|
<beans:bean id="UserNamePasswordAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||||
|
<beans:property name="userDetailsService" ref="usernamePasswordService"/>
|
||||||
|
<beans:property name="passwordEncoder" ref="noOpPasswordEncoder"/>
|
||||||
|
</beans:bean>
|
||||||
|
|
||||||
|
<authentication-manager alias="authenticationManager">
|
||||||
|
<!-- X509 PreAuthenticated authorization provider -->
|
||||||
|
<authentication-provider ref="x509AuthorizationProvider"/>
|
||||||
|
<!-- Basic authorization provider, validates provided username and password -->
|
||||||
|
<authentication-provider ref="UserNamePasswordAuthenticationProvider" />
|
||||||
|
</authentication-manager>
|
||||||
|
|
||||||
|
<util:list id="requiredRoles" value-type="java.lang.String">
|
||||||
|
<beans:value></beans:value>
|
||||||
|
</util:list>
|
||||||
|
|
||||||
|
<util:list id="requiredAuths" value-type="java.lang.String">
|
||||||
|
<beans:value></beans:value>
|
||||||
|
</util:list>
|
||||||
|
</beans:beans>
|
||||||
@@ -0,0 +1,295 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely</artifactId>
|
||||||
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>grafana-auth</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-jdk8</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.flatbuffers</groupId>
|
||||||
|
<artifactId>flatbuffers-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-beanutils</groupId>
|
||||||
|
<artifactId>commons-beanutils</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.lukehutch</groupId>
|
||||||
|
<artifactId>fast-classpath-scanner</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.javacsv</groupId>
|
||||||
|
<artifactId>javacsv</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.accumulo</groupId>
|
||||||
|
<artifactId>accumulo-core</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.accumulo</groupId>
|
||||||
|
<artifactId>accumulo-minicluster</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-collections4</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-pool2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-framework</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-recipes</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.curator</groupId>
|
||||||
|
<artifactId>curator-x-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hadoop</groupId>
|
||||||
|
<artifactId>hadoop-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hadoop</groupId>
|
||||||
|
<artifactId>hadoop-common</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>jdk.tools</groupId>
|
||||||
|
<artifactId>jdk.tools</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.hadoop</groupId>
|
||||||
|
<artifactId>hadoop-minicluster</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-websocket</artifactId>
|
||||||
|
</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.security</groupId>
|
||||||
|
<artifactId>spring-security-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-balancer</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-client</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.lmax</groupId>
|
||||||
|
<artifactId>disruptor</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-api</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-core</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.logging.log4j</groupId>
|
||||||
|
<artifactId>log4j-slf4j-impl</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.javassist</groupId>
|
||||||
|
<artifactId>javassist</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsoup</groupId>
|
||||||
|
<artifactId>jsoup</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>assemble</id>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>package</phase>
|
||||||
|
<configuration>
|
||||||
|
<descriptors>
|
||||||
|
<descriptor>src/main/dist/assembly.xml</descriptor>
|
||||||
|
</descriptors>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-dependencies</id>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>prepare-package</phase>
|
||||||
|
<configuration>
|
||||||
|
<excludeArtifactIds>junit</excludeArtifactIds>
|
||||||
|
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>unpack-native</id>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>process-test-classes</phase>
|
||||||
|
<configuration>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
|
<version>${version.netty-tcnative}</version>
|
||||||
|
<type>jar</type>
|
||||||
|
<overWrite>false</overWrite>
|
||||||
|
<outputDirectory>${project.build.directory}/native</outputDirectory>
|
||||||
|
<includes>**/*.so</includes>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>build-helper-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>add-source</id>
|
||||||
|
<goals>
|
||||||
|
<goal>add-source</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>generate-sources</phase>
|
||||||
|
<configuration>
|
||||||
|
<sources>
|
||||||
|
<source>src/main/generated-java</source>
|
||||||
|
</sources>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
<extensions>
|
||||||
|
<!-- Use os-maven-plugin to initialize the "os.detected" properties -->
|
||||||
|
<extension>
|
||||||
|
<groupId>kr.motd.maven</groupId>
|
||||||
|
<artifactId>os-maven-plugin</artifactId>
|
||||||
|
</extension>
|
||||||
|
</extensions>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
|
||||||
|
<id>dist</id>
|
||||||
|
<formats>
|
||||||
|
<format>tar.gz</format>
|
||||||
|
</formats>
|
||||||
|
<fileSets>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}</directory>
|
||||||
|
<outputDirectory></outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>README*</include>
|
||||||
|
<include>LICENSE*</include>
|
||||||
|
<include>NOTICE*</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.build.directory}</directory>
|
||||||
|
<outputDirectory>lib</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>timely*.jar</include>
|
||||||
|
<include>grafana*.jar</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.build.directory}/lib</directory>
|
||||||
|
<outputDirectory>lib</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>*.jar</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/bin</directory>
|
||||||
|
<outputDirectory>bin</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>**/*</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/conf</directory>
|
||||||
|
<outputDirectory>conf</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>*</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
<fileSet>
|
||||||
|
<directory>${project.basedir}/src/main/resources/webapp</directory>
|
||||||
|
<outputDirectory>bin/webapp</outputDirectory>
|
||||||
|
<includes>
|
||||||
|
<include>*</include>
|
||||||
|
</includes>
|
||||||
|
</fileSet>
|
||||||
|
</fileSets>
|
||||||
|
</assembly>
|
||||||
@@ -0,0 +1,322 @@
|
|||||||
|
package timely.grafana.auth;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||||
|
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.ServerSocketChannel;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||||
|
import io.netty.handler.codec.http.HttpContentCompressor;
|
||||||
|
import io.netty.handler.codec.http.HttpContentDecompressor;
|
||||||
|
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||||
|
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
|
import io.netty.handler.ssl.ClientAuth;
|
||||||
|
import io.netty.handler.ssl.OpenSslServerContext;
|
||||||
|
import io.netty.handler.ssl.OpenSslServerSessionContext;
|
||||||
|
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 io.netty.handler.stream.ChunkedWriteHandler;
|
||||||
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.WebApplicationType;
|
||||||
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import timely.auth.AuthCache;
|
||||||
|
import timely.balancer.configuration.ClientSsl;
|
||||||
|
import timely.balancer.connection.http.HttpClientPool;
|
||||||
|
import timely.client.http.HttpClient;
|
||||||
|
import timely.configuration.ServerSsl;
|
||||||
|
import timely.grafana.auth.configuration.GrafanaAuthConfiguration;
|
||||||
|
import timely.grafana.auth.configuration.SpringBootstrap;
|
||||||
|
import timely.grafana.auth.netty.http.GrafanaRelayHandler;
|
||||||
|
import timely.grafana.auth.netty.http.GrafanaRequestDecoder;
|
||||||
|
import timely.netty.http.HttpStaticFileServerHandler;
|
||||||
|
import timely.netty.http.NonSslRedirectHandler;
|
||||||
|
import timely.netty.http.TimelyExceptionHandler;
|
||||||
|
import timely.netty.http.auth.X509LoginRequestHandler;
|
||||||
|
|
||||||
|
public class GrafanaAuth {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GrafanaAuth.class);
|
||||||
|
private static final int EPOLL_MIN_MAJOR_VERSION = 2;
|
||||||
|
private static final int EPOLL_MIN_MINOR_VERSION = 6;
|
||||||
|
private static final int EPOLL_MIN_PATCH_VERSION = 32;
|
||||||
|
private static final String OS_NAME = "os.name";
|
||||||
|
private static final String OS_VERSION = "os.version";
|
||||||
|
protected static final CountDownLatch LATCH = new CountDownLatch(1);
|
||||||
|
static ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
|
private final GrafanaAuthConfiguration grafanaAuthConfig;
|
||||||
|
private EventLoopGroup httpWorkerGroup = null;
|
||||||
|
private EventLoopGroup httpBossGroup = null;
|
||||||
|
protected Channel httpChannelHandle = null;
|
||||||
|
protected volatile boolean shutdown = false;
|
||||||
|
|
||||||
|
public GrafanaAuth(GrafanaAuthConfiguration grafanaAuthConfig) throws Exception {
|
||||||
|
this.grafanaAuthConfig = grafanaAuthConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static ConfigurableApplicationContext initializeContext(String[] args) {
|
||||||
|
SpringApplicationBuilder builder = new SpringApplicationBuilder(SpringBootstrap.class);
|
||||||
|
builder.web(WebApplicationType.NONE);
|
||||||
|
builder.registerShutdownHook(false);
|
||||||
|
return builder.run(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shutdownHook() {
|
||||||
|
|
||||||
|
final Runnable shutdownRunner = () -> {
|
||||||
|
if (!shutdown) {
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
final Thread hook = new Thread(shutdownRunner, "shutdown-hook-thread");
|
||||||
|
Runtime.getRuntime().addShutdownHook(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() {
|
||||||
|
List<ChannelFuture> channelFutures = new ArrayList<>();
|
||||||
|
|
||||||
|
if (httpChannelHandle != null) {
|
||||||
|
LOG.info("Closing httpChannelHandle");
|
||||||
|
channelFutures.add(httpChannelHandle.close());
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for the channels to shutdown
|
||||||
|
channelFutures.forEach(f -> {
|
||||||
|
try {
|
||||||
|
f.get();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Channel:" + f.channel().config() + " -> " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
int quietPeriod = grafanaAuthConfig.getShutdownQuietPeriod();
|
||||||
|
List<Future<?>> groupFutures = new ArrayList<>();
|
||||||
|
|
||||||
|
if (httpBossGroup != null) {
|
||||||
|
LOG.info("Shutting down httpBossGroup");
|
||||||
|
groupFutures.add(httpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (httpWorkerGroup != null) {
|
||||||
|
LOG.info("Shutting down httpWorkerGroup");
|
||||||
|
groupFutures.add(httpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
|
groupFutures.parallelStream().forEach(f -> {
|
||||||
|
try {
|
||||||
|
f.get();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
LOG.error("Group:" + f.toString() + " -> " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (applicationContext != null) {
|
||||||
|
LOG.info("Closing applicationContext");
|
||||||
|
applicationContext.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shutdown = true;
|
||||||
|
LOG.info("Server shut down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean useEpoll() {
|
||||||
|
|
||||||
|
// Should we just return true if this is Linux and if we get an error
|
||||||
|
// during Epoll
|
||||||
|
// setup handle it there?
|
||||||
|
final String os = SystemPropertyUtil.get(OS_NAME).toLowerCase().trim();
|
||||||
|
final String[] version = SystemPropertyUtil.get(OS_VERSION).toLowerCase().trim().split("\\.");
|
||||||
|
if (os.startsWith("linux") && version.length >= 3) {
|
||||||
|
final int major = Integer.parseInt(version[0]);
|
||||||
|
if (major > EPOLL_MIN_MAJOR_VERSION) {
|
||||||
|
return true;
|
||||||
|
} else if (major == EPOLL_MIN_MAJOR_VERSION) {
|
||||||
|
final int minor = Integer.parseInt(version[1]);
|
||||||
|
if (minor > EPOLL_MIN_MINOR_VERSION) {
|
||||||
|
return true;
|
||||||
|
} else if (minor == EPOLL_MIN_MINOR_VERSION) {
|
||||||
|
final int patch = Integer.parseInt(version[2].substring(0, 2));
|
||||||
|
return patch >= EPOLL_MIN_PATCH_VERSION;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SslContext createSSLContext(GrafanaAuthConfiguration config) throws Exception {
|
||||||
|
|
||||||
|
ServerSsl sslCfg = config.getSecurity().getServerSsl();
|
||||||
|
Boolean generate = sslCfg.isUseGeneratedKeypair();
|
||||||
|
SslContextBuilder ssl;
|
||||||
|
if (generate) {
|
||||||
|
LOG.warn("Using generated self signed server certificate");
|
||||||
|
Date begin = new Date();
|
||||||
|
Date end = new Date(begin.getTime() + 86400000);
|
||||||
|
SelfSignedCertificate ssc = new SelfSignedCertificate("localhost", begin, end);
|
||||||
|
ssl = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey());
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl.ciphers(sslCfg.getUseCiphers());
|
||||||
|
|
||||||
|
// Can't set to REQUIRE because the CORS pre-flight requests will fail.
|
||||||
|
ssl.clientAuth(ClientAuth.OPTIONAL);
|
||||||
|
|
||||||
|
Boolean useOpenSSL = sslCfg.isUseOpenssl();
|
||||||
|
if (useOpenSSL) {
|
||||||
|
ssl.sslProvider(SslProvider.OPENSSL);
|
||||||
|
} else {
|
||||||
|
ssl.sslProvider(SslProvider.JDK);
|
||||||
|
}
|
||||||
|
String trustStore = sslCfg.getTrustStoreFile();
|
||||||
|
if (null != trustStore) {
|
||||||
|
if (!trustStore.isEmpty()) {
|
||||||
|
ssl.trustManager(new File(trustStore));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ssl.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SSLContext createSSLClientContext(GrafanaAuthConfiguration config) throws Exception {
|
||||||
|
|
||||||
|
ClientSsl ssl = config.getSecurity().getClientSsl();
|
||||||
|
return HttpClient.getSSLContext(ssl.getTrustStoreFile(), ssl.getTrustStoreType(), ssl.getTrustStorePassword(),
|
||||||
|
ssl.getKeyFile(), ssl.getKeyType(), ssl.getKeyPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() throws Exception {
|
||||||
|
|
||||||
|
AuthCache.configure(grafanaAuthConfig.getSecurity());
|
||||||
|
final boolean useEpoll = useEpoll();
|
||||||
|
Class<? extends ServerSocketChannel> channelClass;
|
||||||
|
if (useEpoll) {
|
||||||
|
httpWorkerGroup = new EpollEventLoopGroup();
|
||||||
|
httpBossGroup = new EpollEventLoopGroup();
|
||||||
|
channelClass = EpollServerSocketChannel.class;
|
||||||
|
} else {
|
||||||
|
httpWorkerGroup = new NioEventLoopGroup();
|
||||||
|
httpBossGroup = new NioEventLoopGroup();
|
||||||
|
channelClass = NioServerSocketChannel.class;
|
||||||
|
}
|
||||||
|
LOG.info("Using channel class {}", channelClass.getSimpleName());
|
||||||
|
|
||||||
|
final int httpPort = grafanaAuthConfig.getHttp().getPort();
|
||||||
|
final String httpIp = grafanaAuthConfig.getHttp().getIp();
|
||||||
|
SslContext sslCtx = createSSLContext(grafanaAuthConfig);
|
||||||
|
if (sslCtx instanceof OpenSslServerContext) {
|
||||||
|
OpenSslServerContext openssl = (OpenSslServerContext) sslCtx;
|
||||||
|
String application = "GrafanaAuth_" + httpPort;
|
||||||
|
OpenSslServerSessionContext opensslCtx = openssl.sessionContext();
|
||||||
|
opensslCtx.setSessionCacheEnabled(true);
|
||||||
|
opensslCtx.setSessionCacheSize(128);
|
||||||
|
opensslCtx.setSessionIdContext(application.getBytes(StandardCharsets.UTF_8));
|
||||||
|
opensslCtx.setSessionTimeout(grafanaAuthConfig.getSecurity().getSessionMaxAge());
|
||||||
|
}
|
||||||
|
SSLContext clientSSLContext = createSSLClientContext(grafanaAuthConfig);
|
||||||
|
final ServerBootstrap httpServer = new ServerBootstrap();
|
||||||
|
httpServer.group(httpBossGroup, httpWorkerGroup);
|
||||||
|
httpServer.channel(channelClass);
|
||||||
|
httpServer.handler(new LoggingHandler());
|
||||||
|
HttpClientPool httpClientPool = new HttpClientPool(grafanaAuthConfig.getSecurity(), grafanaAuthConfig.getHttp(),
|
||||||
|
clientSSLContext);
|
||||||
|
httpServer.childHandler(setupHttpChannel(grafanaAuthConfig, sslCtx, httpClientPool));
|
||||||
|
httpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
|
httpServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||||
|
httpServer.option(ChannelOption.SO_KEEPALIVE, true);
|
||||||
|
httpChannelHandle = httpServer.bind(httpIp, httpPort).sync().channel();
|
||||||
|
final String httpAddress = ((InetSocketAddress) httpChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||||
|
|
||||||
|
shutdownHook();
|
||||||
|
LOG.info("Server started. Listening on {}:{} for HTTP traffic", httpAddress, httpPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
GrafanaAuth.applicationContext = GrafanaAuth.initializeContext(args);
|
||||||
|
GrafanaAuthConfiguration grafanaAuthConf = GrafanaAuth.applicationContext
|
||||||
|
.getBean(GrafanaAuthConfiguration.class);
|
||||||
|
|
||||||
|
GrafanaAuth grafanaAuth = new GrafanaAuth(grafanaAuthConf);
|
||||||
|
try {
|
||||||
|
grafanaAuth.run();
|
||||||
|
LATCH.await();
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
LOG.info("Server shutting down.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Error running server.", e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
grafanaAuth.shutdown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ChannelHandler setupHttpChannel(GrafanaAuthConfiguration config, SslContext sslCtx,
|
||||||
|
HttpClientPool httpClientPool) {
|
||||||
|
|
||||||
|
return new ChannelInitializer<SocketChannel>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
|
||||||
|
ch.pipeline().addLast("ssl", new NonSslRedirectHandler(config.getHttp(), sslCtx));
|
||||||
|
ch.pipeline().addLast("encoder", new HttpResponseEncoder());
|
||||||
|
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
|
||||||
|
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
||||||
|
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
||||||
|
// high maximum contentLength so that grafana snapshots can be delivered
|
||||||
|
// might not be necessary if inbound chunking (while proxying) is handled
|
||||||
|
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(2097152));
|
||||||
|
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
||||||
|
ch.pipeline().addLast("grafanaDecoder",
|
||||||
|
new GrafanaRequestDecoder(config.getSecurity(), config.getHttp()));
|
||||||
|
ch.pipeline().addLast("fileServer", new HttpStaticFileServerHandler());
|
||||||
|
ch.pipeline().addLast("login", new X509LoginRequestHandler(config.getSecurity(), config.getHttp()));
|
||||||
|
ch.pipeline().addLast("httpRelay", new GrafanaRelayHandler(config, httpClientPool));
|
||||||
|
ch.pipeline().addLast("error", new TimelyExceptionHandler()
|
||||||
|
.setIgnoreSslHandshakeErrors(config.getSecurity().getServerSsl().isUseGeneratedKeypair()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package timely.grafana.auth.configuration;
|
||||||
|
|
||||||
|
public class Grafana {
|
||||||
|
|
||||||
|
private String host = "localhost";
|
||||||
|
private Integer port = 3000;
|
||||||
|
private String protocol = "http";
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(Integer port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProtocol(String protocol) {
|
||||||
|
this.protocol = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package timely.grafana.auth.configuration;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import timely.balancer.configuration.BalancerHttp;
|
||||||
|
import timely.balancer.configuration.BalancerSecurity;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "grafana-auth")
|
||||||
|
public class GrafanaAuthConfiguration {
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private BalancerHttp http = new BalancerHttp();
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private BalancerSecurity security = new BalancerSecurity();
|
||||||
|
|
||||||
|
@Valid
|
||||||
|
@NestedConfigurationProperty
|
||||||
|
private Grafana grafana = new Grafana();
|
||||||
|
|
||||||
|
private Integer shutdownQuietPeriod = 5;
|
||||||
|
|
||||||
|
public BalancerSecurity getSecurity() {
|
||||||
|
return security;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BalancerHttp getHttp() {
|
||||||
|
return http;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Grafana getGrafana() {
|
||||||
|
return grafana;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time to wait (in seconds) for connections to finish and to make sure no new
|
||||||
|
* connections happen before shutting down Netty event loop groups.
|
||||||
|
*/
|
||||||
|
public int getShutdownQuietPeriod() {
|
||||||
|
return this.shutdownQuietPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShutdownQuietPeriod(Integer quietPeriod) {
|
||||||
|
this.shutdownQuietPeriod = quietPeriod;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package timely.grafana.auth.configuration;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication(scanBasePackageClasses = { SpringBootstrap.class })
|
||||||
|
public class SpringBootstrap {
|
||||||
|
}
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
package timely.grafana.auth.netty.http;
|
||||||
|
|
||||||
|
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
|
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.FullHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.FullHttpResponse;
|
||||||
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
import io.netty.handler.codec.http.HttpVersion;
|
||||||
|
import io.netty.util.ReferenceCountUtil;
|
||||||
|
import org.apache.http.Header;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpHead;
|
||||||
|
import org.apache.http.client.methods.HttpOptions;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.message.BasicHeader;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import timely.api.request.timeseries.HttpRequest;
|
||||||
|
import timely.api.response.TimelyException;
|
||||||
|
import timely.auth.TimelyPrincipal;
|
||||||
|
import timely.auth.TimelyUser;
|
||||||
|
import timely.auth.util.DnUtils;
|
||||||
|
import timely.auth.util.HttpHeaderUtils;
|
||||||
|
import timely.balancer.connection.TimelyBalancedHost;
|
||||||
|
import timely.balancer.connection.http.HttpClientPool;
|
||||||
|
import timely.grafana.auth.configuration.GrafanaAuthConfiguration;
|
||||||
|
import timely.grafana.request.GrafanaRequest;
|
||||||
|
import timely.netty.http.TimelyHttpHandler;
|
||||||
|
import timely.netty.http.auth.TimelyAuthenticationToken;
|
||||||
|
|
||||||
|
public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest> implements TimelyHttpHandler {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GrafanaRelayHandler.class);
|
||||||
|
private final HttpClientPool httpClientPool;
|
||||||
|
private GrafanaAuthConfiguration config;
|
||||||
|
|
||||||
|
public GrafanaRelayHandler(GrafanaAuthConfiguration config, HttpClientPool httpClientPool) {
|
||||||
|
this.config = config;
|
||||||
|
this.httpClientPool = httpClientPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelRead0(ChannelHandlerContext ctx, HttpRequest msg) throws Exception {
|
||||||
|
|
||||||
|
CloseableHttpClient client = null;
|
||||||
|
CloseableHttpResponse relayedResponse = null;
|
||||||
|
FullHttpRequest request = null;
|
||||||
|
GrafanaRequest grafanaRequest;
|
||||||
|
TimelyBalancedHost k = null;
|
||||||
|
String relayURI = null;
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
request = msg.getHttpRequest();
|
||||||
|
String originalURI = request.uri();
|
||||||
|
originalURI = encodeURI(originalURI);
|
||||||
|
|
||||||
|
if (msg instanceof GrafanaRequest) {
|
||||||
|
grafanaRequest = (GrafanaRequest) msg;
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Request not supported");
|
||||||
|
}
|
||||||
|
TimelyAuthenticationToken token = grafanaRequest.getToken();
|
||||||
|
if (token == null) {
|
||||||
|
throw new IllegalStateException("No token on grafana request");
|
||||||
|
}
|
||||||
|
|
||||||
|
String protocol = config.getGrafana().getProtocol();
|
||||||
|
String host = config.getGrafana().getHost();
|
||||||
|
Integer port = config.getGrafana().getPort();
|
||||||
|
k = TimelyBalancedHost.of(host, -1, port, -1, -1, null);
|
||||||
|
client = httpClientPool.borrowObject(k);
|
||||||
|
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(request.headers());
|
||||||
|
|
||||||
|
// If incoming user sets these headers, do not relay them
|
||||||
|
headers.removeAll("x-webauth-user");
|
||||||
|
headers.removeAll("x-webauth-name");
|
||||||
|
TimelyPrincipal principal = token.getTimelyPrincipal();
|
||||||
|
TimelyUser user = principal.getPrimaryUser();
|
||||||
|
String subjectDn = user.getDn().subjectDN();
|
||||||
|
String userName = DnUtils.getCommonName(subjectDn);
|
||||||
|
String loginName = DnUtils.getShortName(subjectDn);
|
||||||
|
headers.put("x-webauth-user", loginName);
|
||||||
|
headers.put("x-webauth-name", userName);
|
||||||
|
List<Header> relayedHeaderList = new ArrayList<>();
|
||||||
|
for (Map.Entry<String, String> h : headers.entries()) {
|
||||||
|
if (!h.getKey().equals(CONTENT_LENGTH.toString())) {
|
||||||
|
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Header[] headerArray = new Header[relayedHeaderList.size()];
|
||||||
|
relayedHeaderList.toArray(headerArray);
|
||||||
|
relayURI = protocol + "://" + host + ":" + port + originalURI;
|
||||||
|
if (request.method().equals(HttpMethod.HEAD)) {
|
||||||
|
HttpHead relayedRequest = new HttpHead(relayURI);
|
||||||
|
if (headerArray.length > 0) {
|
||||||
|
relayedRequest.setHeaders(headerArray);
|
||||||
|
}
|
||||||
|
relayedResponse = client.execute(relayedRequest);
|
||||||
|
} else if (request.method().equals(HttpMethod.GET)) {
|
||||||
|
HttpGet relayedRequest = new HttpGet(relayURI);
|
||||||
|
if (headerArray.length > 0) {
|
||||||
|
relayedRequest.setHeaders(headerArray);
|
||||||
|
}
|
||||||
|
relayedResponse = client.execute(relayedRequest);
|
||||||
|
} else if (request.method().equals(HttpMethod.POST)) {
|
||||||
|
HttpPost relayedRequest = new HttpPost(relayURI);
|
||||||
|
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||||
|
StringEntity entity = new StringEntity(content);
|
||||||
|
relayedRequest.setEntity(entity);
|
||||||
|
if (headerArray.length > 0) {
|
||||||
|
relayedRequest.setHeaders(headerArray);
|
||||||
|
}
|
||||||
|
relayedResponse = client.execute(relayedRequest);
|
||||||
|
} else if (request.method().equals(HttpMethod.PUT)) {
|
||||||
|
HttpPut relayedRequest = new HttpPut(relayURI);
|
||||||
|
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||||
|
StringEntity entity = new StringEntity(content);
|
||||||
|
relayedRequest.setEntity(entity);
|
||||||
|
if (headerArray.length > 0) {
|
||||||
|
relayedRequest.setHeaders(headerArray);
|
||||||
|
}
|
||||||
|
relayedResponse = client.execute(relayedRequest);
|
||||||
|
} else if (request.method().equals(HttpMethod.DELETE)) {
|
||||||
|
HttpDelete relayedRequest = new HttpDelete(relayURI);
|
||||||
|
if (headerArray.length > 0) {
|
||||||
|
relayedRequest.setHeaders(headerArray);
|
||||||
|
}
|
||||||
|
relayedResponse = client.execute(relayedRequest);
|
||||||
|
} else if (request.method().equals(HttpMethod.OPTIONS)) {
|
||||||
|
HttpOptions relayedRequest = new HttpOptions(relayURI);
|
||||||
|
if (headerArray.length > 0) {
|
||||||
|
relayedRequest.setHeaders(headerArray);
|
||||||
|
}
|
||||||
|
relayedResponse = client.execute(relayedRequest);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
String message = e.getMessage();
|
||||||
|
if (message == null) {
|
||||||
|
LOG.error("", e);
|
||||||
|
} else {
|
||||||
|
LOG.error(message, e);
|
||||||
|
}
|
||||||
|
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(),
|
||||||
|
e.getMessage(), e.getLocalizedMessage(), e));
|
||||||
|
return;
|
||||||
|
} finally {
|
||||||
|
if (request != null && request instanceof AutoCloseable) {
|
||||||
|
ReferenceCountUtil.release(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FullHttpResponse response = null;
|
||||||
|
if (relayedResponse == null) {
|
||||||
|
this.sendHttpError(ctx, new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
|
||||||
|
"Method not allowed", "Method not allowed"));
|
||||||
|
} else {
|
||||||
|
LOG.debug("RequestURL:{} ResponseCode:{}", relayURI, relayedResponse.getStatusLine().getStatusCode());
|
||||||
|
HttpEntity httpEntity = relayedResponse.getEntity();
|
||||||
|
if (httpEntity == null) {
|
||||||
|
response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
||||||
|
HttpResponseStatus.valueOf(relayedResponse.getStatusLine().getStatusCode()));
|
||||||
|
} else {
|
||||||
|
ByteArrayOutputStream baos = new MyByteArrayOutputStream();
|
||||||
|
StreamUtils.copy(httpEntity.getContent(), baos);
|
||||||
|
response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
||||||
|
HttpResponseStatus.valueOf(relayedResponse.getStatusLine().getStatusCode()),
|
||||||
|
Unpooled.copiedBuffer(baos.toByteArray()));
|
||||||
|
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
|
||||||
|
}
|
||||||
|
for (Header h : relayedResponse.getAllHeaders()) {
|
||||||
|
response.headers().add(h.getName(), h.getValue());
|
||||||
|
}
|
||||||
|
sendResponse(ctx, response);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (relayedResponse != null) {
|
||||||
|
relayedResponse.close();
|
||||||
|
}
|
||||||
|
if (client != null && k != null) {
|
||||||
|
httpClientPool.returnObject(k, client);
|
||||||
|
} else {
|
||||||
|
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public class MyByteArrayOutputStream extends ByteArrayOutputStream {
|
||||||
|
|
||||||
|
public MyByteArrayOutputStream() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyByteArrayOutputStream(int size) {
|
||||||
|
super(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBuf() {
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public String encodeURI(String s) {
|
||||||
|
try {
|
||||||
|
s = s.replaceAll("\\{", URLEncoder.encode("{", "UTF-8"));
|
||||||
|
s = s.replaceAll("\\}", URLEncoder.encode("}", "UTF-8"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package timely.grafana.auth.netty.http;
|
||||||
|
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import io.netty.handler.codec.http.FullHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
|
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||||
|
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import timely.api.request.AuthenticatedRequest;
|
||||||
|
import timely.api.request.timeseries.HttpRequest;
|
||||||
|
import timely.api.response.StrictTransportResponse;
|
||||||
|
import timely.api.response.TimelyException;
|
||||||
|
import timely.auth.AuthCache;
|
||||||
|
import timely.auth.AuthenticationService;
|
||||||
|
import timely.auth.SubjectIssuerDNPair;
|
||||||
|
import timely.auth.TimelyPrincipal;
|
||||||
|
import timely.auth.util.HttpHeaderUtils;
|
||||||
|
import timely.configuration.Http;
|
||||||
|
import timely.configuration.Security;
|
||||||
|
import timely.grafana.request.GrafanaRequest;
|
||||||
|
import timely.netty.Constants;
|
||||||
|
import timely.netty.http.TimelyHttpHandler;
|
||||||
|
import timely.netty.http.auth.TimelyAuthenticationToken;
|
||||||
|
|
||||||
|
public class GrafanaRequestDecoder extends MessageToMessageDecoder<FullHttpRequest> implements TimelyHttpHandler {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(GrafanaRequestDecoder.class);
|
||||||
|
private static final String LOG_RECEIVED_REQUEST = "Received HTTP request {}";
|
||||||
|
private static final String LOG_PARSED_REQUEST = "Parsed request {}";
|
||||||
|
|
||||||
|
private final Security security;
|
||||||
|
private final String nonSecureRedirectAddress;
|
||||||
|
|
||||||
|
public GrafanaRequestDecoder(Security security, Http http) {
|
||||||
|
|
||||||
|
this.security = security;
|
||||||
|
this.nonSecureRedirectAddress = http.getRedirectPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSessionId(FullHttpRequest msg) {
|
||||||
|
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(msg.headers());
|
||||||
|
Collection<String> cookies = headers.get(HttpHeaderNames.COOKIE.toString());
|
||||||
|
final StringBuilder buf = new StringBuilder();
|
||||||
|
cookies.forEach(h -> {
|
||||||
|
ServerCookieDecoder.STRICT.decode(h).forEach(c -> {
|
||||||
|
if (c.name().equals(Constants.COOKIE_NAME)) {
|
||||||
|
if (buf.length() == 0) {
|
||||||
|
buf.append(c.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if (buf.length() == 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, FullHttpRequest msg, List<Object> out) throws Exception {
|
||||||
|
|
||||||
|
LOG.trace(LOG_RECEIVED_REQUEST, msg);
|
||||||
|
|
||||||
|
final String uri = msg.uri();
|
||||||
|
final QueryStringDecoder decoder = new QueryStringDecoder(uri);
|
||||||
|
if (decoder.path().equals(nonSecureRedirectAddress)) {
|
||||||
|
out.add(new StrictTransportResponse());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String sessionId = getSessionId(msg);
|
||||||
|
LOG.trace("SessionID: " + sessionId);
|
||||||
|
|
||||||
|
HttpRequest request;
|
||||||
|
try {
|
||||||
|
request = new GrafanaRequest();
|
||||||
|
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(msg.headers());
|
||||||
|
((AuthenticatedRequest) request).addHeaders(headers);
|
||||||
|
X509Certificate clientCert = AuthenticationService.getClientCertificate(ctx);
|
||||||
|
TimelyAuthenticationToken token;
|
||||||
|
if (StringUtils.isNotBlank(sessionId)) {
|
||||||
|
TimelyPrincipal principal;
|
||||||
|
((AuthenticatedRequest) request).setSessionId(sessionId);
|
||||||
|
if (AuthCache.containsKey(sessionId)) {
|
||||||
|
principal = AuthCache.get(sessionId);
|
||||||
|
} else {
|
||||||
|
principal = TimelyPrincipal.anonymousPrincipal();
|
||||||
|
}
|
||||||
|
SubjectIssuerDNPair dn = principal.getPrimaryUser().getDn();
|
||||||
|
token = AuthenticationService.getAuthenticationToken(null, dn.subjectDN(), dn.issuerDN());
|
||||||
|
} else if (clientCert != null) {
|
||||||
|
token = AuthenticationService.getAuthenticationToken(clientCert, headers);
|
||||||
|
} else {
|
||||||
|
SubjectIssuerDNPair dn = TimelyPrincipal.anonymousPrincipal().getPrimaryUser().getDn();
|
||||||
|
token = AuthenticationService.getAuthenticationToken(null, dn.subjectDN(), dn.issuerDN());
|
||||||
|
}
|
||||||
|
((AuthenticatedRequest) request).setToken(token);
|
||||||
|
request.setHttpRequest(msg.copy());
|
||||||
|
LOG.trace(LOG_PARSED_REQUEST, request);
|
||||||
|
request.validate();
|
||||||
|
out.add(request);
|
||||||
|
} catch (UnsupportedOperationException | NullPointerException e) {
|
||||||
|
// Return the original http request to route to the static file
|
||||||
|
// server
|
||||||
|
msg.retain();
|
||||||
|
out.add(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
AuthenticationService.enforceAccess((AuthenticatedRequest) request);
|
||||||
|
} catch (TimelyException e) {
|
||||||
|
if (!security.isAllowAnonymousHttpAccess()) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
out.clear();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package timely.grafana.request;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.http.FullHttpRequest;
|
||||||
|
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||||
|
import timely.api.annotation.Http;
|
||||||
|
import timely.api.request.AuthenticatedRequest;
|
||||||
|
import timely.api.request.HttpGetRequest;
|
||||||
|
import timely.api.request.HttpPostRequest;
|
||||||
|
|
||||||
|
@Http(path = "/")
|
||||||
|
public class GrafanaRequest extends AuthenticatedRequest implements HttpGetRequest, HttpPostRequest {
|
||||||
|
|
||||||
|
private FullHttpRequest httpRequest = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpGetRequest parseQueryParameters(QueryStringDecoder decoder) throws Exception {
|
||||||
|
return new GrafanaRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpPostRequest parseBody(String content) throws Exception {
|
||||||
|
return new GrafanaRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHttpRequest(FullHttpRequest httpRequest) {
|
||||||
|
this.httpRequest = httpRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FullHttpRequest getHttpRequest() {
|
||||||
|
return httpRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<FindBugsFilter>
|
||||||
|
<Match>
|
||||||
|
<Class name="timely.grafana.auth.netty.http.GrafanaRelayHandler$MyByteArrayOutputStream" />
|
||||||
|
<Method name="getBuf" />
|
||||||
|
<Bug pattern="EI_EXPOSE_REP" />
|
||||||
|
</Match>
|
||||||
|
</FindBugsFilter>
|
||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-app</artifactId>
|
<artifactId>timely-app</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|||||||
+1
-1
@@ -509,7 +509,7 @@ System.register(['lodash', 'angular', '../../../app/core/utils/datemath'], funct
|
|||||||
} else {
|
} else {
|
||||||
return target.metric === metricData.metric && _.every(target.tags, function (tagV, tagK) {
|
return target.metric === metricData.metric && _.every(target.tags, function (tagV, tagK) {
|
||||||
interpolatedTagValue = this.templateSrv.replace(tagV, options.scopedVars, 'pipe');
|
interpolatedTagValue = this.templateSrv.replace(tagV, options.scopedVars, 'pipe');
|
||||||
return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*";
|
return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === ".*";
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
{"version":3,"sources":["../../src/datasource/datasource.js"],"names":["_","angular","dateMath","TimelyDatasource","instanceSettings","$q","backendSrv","templateSrv","contextSrv","type","name","jsonData","httpsPort","timelyHost","wsPort","basicAuths","url","_makeHttpsUrl","withCredentials","basicAuth","supportMetrics","tagKeys","aggregatorsPromise","filterTypesPromise","options","start","convertToTSDBTime","rangeRaw","from","end","to","qs","each","targets","target","metric","push","convertTargetToQuery","bind","queries","compact","isEmpty","d","defer","resolve","data","promise","groupByTags","query","filters","length","val","tagk","tags","key","performTimeSeriesQuery","then","response","metricToTargetMapping","mapMetricsToTargets","result","map","metricData","index","_saveTagKeys","transformMetricData","datasourceRequest","method","status","message","title","eventList","aggregator","annotation","results","annotationObject","annotations","isGlobal","globalAnnotations","event","description","time","Math","floor","startTime","text","notes","when","interpolated","replace","err","reject","responseTransform","value","metrics_regex","tag_names_regex","tag_values_regex","tag_names_suggest_regex","tag_values_suggest_regex","metrics_query","match","_performSuggestQuery","tag_names_query","_performMetricKeyLookup","tag_values_query","_performMetricKeyValueLookup","tag_names_suggest_query","tag_values_suggest_query","msResolution","responsePromises","reqBody","showQuery","_addCredentialOptions","headers","Promise","all","queryResponses","combinedResponse","x","concat","Object","keys","aggregateTags","tag","_get","q","max","keysArray","split","trim","keysQuery","splice","join","m","limit","tagvs","r","indexOf","tagks","tagv","relativeUrl","params","isArray","sort","md","metricLabel","createMetricLabel","dps","v","k","datapoints","alias","scopedVars","clone","label","tagData","toPairs","has","hide","shouldComputeRate","rate","rateOptions","counter","isCounter","counterMax","parseInt","counterResetValue","resetValue","disableDownsampling","interval","downsampleInterval","parseFloat","downsample","downsampleAggregator","downsampleFillPolicy","copy","filter_key","filter","tag_key","metrics","interpolatedTagValue","findIndex","every","tagV","tagK","date","roundUp","parse","valueOf"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;AACAC,a;;AACKC,c;;;;;;;;;;;;;;;;;;;;;kCAECC,gB;;AAEX;AACA,kCAAYC,gBAAZ,EAA8BC,EAA9B,EAAkCC,UAAlC,EAA8CC,WAA9C,EAA2DC,UAA3D,EAAuE;AAAA;;AACrE,eAAKC,IAAL,GAAYL,iBAAiBK,IAA7B;AACA,eAAKC,IAAL,GAAYN,iBAAiBM,IAA7B;;AAEA,eAAKC,QAAL,GAAgBP,iBAAiBO,QAAjB,IAA6B,EAA7C;AACA,eAAKC,SAAL,GAAiBR,iBAAiBO,QAAjB,CAA0BC,SAA3C;AACA,eAAKC,UAAL,GAAkBT,iBAAiBO,QAAjB,CAA0BE,UAA5C;AACA,eAAKC,MAAL,GAAcV,iBAAiBO,QAAjB,CAA0BG,MAAxC;AACA,cAAI,CAACV,iBAAiBO,QAAjB,CAA0BI,UAA/B,EAA0C;AACxCX,6BAAiBO,QAAjB,CAA0BI,UAA1B,GAAuC,KAAvC;AACD;;AAED,eAAKC,GAAL,GAAW,KAAKC,aAAL,EAAX;AACA,eAAKC,eAAL,GAAuB,IAAvB;AACA,eAAKC,SAAL,GAAiB,KAAjB;;AAEA,eAAKC,cAAL,GAAsB,IAAtB;AACA,eAAKC,OAAL,GAAe,EAAf;;AAEA,eAAKhB,EAAL,GAAUA,EAAV;AACA,eAAKC,UAAL,GAAkBA,UAAlB;AACA,eAAKC,WAAL,GAAmBA,WAAnB;AACA,eAAKC,UAAL,GAAkBA,UAAlB;;AAEA,eAAKc,kBAAL,GAA0B,IAA1B;AACA,eAAKC,kBAAL,GAA0B,IAA1B;AAED;;AAED;;;;;gCACMC,O,EAAQ;AACZ,gBAAIC,QAAQ,KAAKC,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBC,IAAxC,EAA8C,KAA9C,CAAZ;AACA,gBAAIC,MAAM,KAAKH,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBG,EAAxC,EAA4C,IAA5C,CAAV;AACA,gBAAIC,KAAK,EAAT;;AAEA/B,cAAEgC,IAAF,CAAOR,QAAQS,OAAf,EAAwB,UAASC,MAAT,EAAiB;AACvC,kBAAI,CAACA,OAAOC,MAAZ,EAAoB;AAAE;AAAS;AAC/BJ,iBAAGK,IAAH,CAAQ,KAAKC,oBAAL,CAA0BH,MAA1B,EAAkCV,OAAlC,CAAR;AACD,aAHuB,CAGtBc,IAHsB,CAGjB,IAHiB,CAAxB;;AAKA,gBAAIC,UAAUvC,EAAEwC,OAAF,CAAUT,EAAV,CAAd;;AAEA;AACA,gBAAI/B,EAAEyC,OAAF,CAAUF,OAAV,CAAJ,EAAwB;AACtB,kBAAIG,IAAI,KAAKrC,EAAL,CAAQsC,KAAR,EAAR;AACAD,gBAAEE,OAAF,CAAU,EAAEC,MAAM,EAAR,EAAV;AACA,qBAAOH,EAAEI,OAAT;AACD;;AAED,gBAAIC,cAAc,EAAlB;AACA/C,cAAEgC,IAAF,CAAOO,OAAP,EAAgB,UAASS,KAAT,EAAgB;AAC9B,kBAAIA,MAAMC,OAAN,IAAiBD,MAAMC,OAAN,CAAcC,MAAd,GAAuB,CAA5C,EAA+C;AAC7ClD,kBAAEgC,IAAF,CAAOgB,MAAMC,OAAb,EAAsB,UAASE,GAAT,EAAc;AAClCJ,8BAAYI,IAAIC,IAAhB,IAAwB,IAAxB;AACD,iBAFD;AAGD,eAJD,MAIO;AACLpD,kBAAEgC,IAAF,CAAOgB,MAAMK,IAAb,EAAmB,UAASF,GAAT,EAAcG,GAAd,EAAmB;AACpCP,8BAAYO,GAAZ,IAAmB,IAAnB;AACD,iBAFD;AAGD;AACF,aAVD;;AAYA,mBAAO,KAAKC,sBAAL,CAA4BhB,OAA5B,EAAqCd,KAArC,EAA4CI,GAA5C,EAAiD2B,IAAjD,CAAsD,UAASC,QAAT,EAAmB;AAC9E,kBAAIC,wBAAwB,KAAKC,mBAAL,CAAyBF,SAASZ,IAAlC,EAAwCrB,OAAxC,CAA5B;AACA,kBAAIoC,SAAS5D,EAAE6D,GAAF,CAAMJ,SAASZ,IAAf,EAAqB,UAASiB,UAAT,EAAqBC,KAArB,EAA4B;AAC5DA,wBAAQL,sBAAsBK,KAAtB,CAAR;AACA,oBAAIA,UAAU,CAAC,CAAf,EAAkB;AAChBA,0BAAQ,CAAR;AACD;AACD,qBAAKC,YAAL,CAAkBF,UAAlB;;AAEA,uBAAO,KAAKG,mBAAL,CAAyBH,UAAzB,EAAqCf,WAArC,EAAkDvB,QAAQS,OAAR,CAAgB8B,KAAhB,CAAlD,EAA0EvC,OAA1E,CAAP;AACD,eARiC,CAQhCc,IARgC,CAQ3B,IAR2B,CAArB,CAAb;AASA,qBAAO,EAAEO,MAAMe,MAAR,EAAP;AACD,aAZ4D,CAY3DtB,IAZ2D,CAYtD,IAZsD,CAAtD,CAAP;AAaD;;;2CAGe;AACd,mBAAO,KAAKhC,UAAL,CAAgB4D,iBAAhB,CAAkC;AACvClD,mBAAK,KAAKA,GAAL,GAAW,UADuB;AAEvCmD,sBAAQ;AAF+B,aAAlC,EAGJX,IAHI,CAGC,oBAAY;AAClB,kBAAIC,SAASW,MAAT,KAAoB,GLine truncated
|
{"version":3,"sources":["../../src/datasource/datasource.js"],"names":["_","angular","dateMath","TimelyDatasource","instanceSettings","$q","backendSrv","templateSrv","contextSrv","type","name","jsonData","httpsPort","timelyHost","wsPort","basicAuths","url","_makeHttpsUrl","withCredentials","basicAuth","supportMetrics","tagKeys","aggregatorsPromise","filterTypesPromise","options","start","convertToTSDBTime","rangeRaw","from","end","to","qs","each","targets","target","metric","push","convertTargetToQuery","bind","queries","compact","isEmpty","d","defer","resolve","data","promise","groupByTags","query","filters","length","val","tagk","tags","key","performTimeSeriesQuery","then","response","metricToTargetMapping","mapMetricsToTargets","result","map","metricData","index","_saveTagKeys","transformMetricData","datasourceRequest","method","status","message","title","eventList","aggregator","annotation","results","annotationObject","annotations","isGlobal","globalAnnotations","event","description","time","Math","floor","startTime","text","notes","when","interpolated","replace","err","reject","responseTransform","value","metrics_regex","tag_names_regex","tag_values_regex","tag_names_suggest_regex","tag_values_suggest_regex","metrics_query","match","_performSuggestQuery","tag_names_query","_performMetricKeyLookup","tag_values_query","_performMetricKeyValueLookup","tag_names_suggest_query","tag_values_suggest_query","msResolution","responsePromises","reqBody","showQuery","_addCredentialOptions","headers","Promise","all","queryResponses","combinedResponse","x","concat","Object","keys","aggregateTags","tag","_get","q","max","keysArray","split","trim","keysQuery","splice","join","m","limit","tagvs","r","indexOf","tagks","tagv","relativeUrl","params","isArray","sort","md","metricLabel","createMetricLabel","dps","v","k","datapoints","alias","scopedVars","clone","label","tagData","toPairs","has","hide","shouldComputeRate","rate","rateOptions","counter","isCounter","counterMax","parseInt","counterResetValue","resetValue","disableDownsampling","interval","downsampleInterval","parseFloat","downsample","downsampleAggregator","downsampleFillPolicy","copy","filter_key","filter","tag_key","metrics","interpolatedTagValue","findIndex","every","tagV","tagK","date","roundUp","parse","valueOf"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;AACAC,a;;AACKC,c;;;;;;;;;;;;;;;;;;;;;kCAECC,gB;;AAEX;AACA,kCAAYC,gBAAZ,EAA8BC,EAA9B,EAAkCC,UAAlC,EAA8CC,WAA9C,EAA2DC,UAA3D,EAAuE;AAAA;;AACrE,eAAKC,IAAL,GAAYL,iBAAiBK,IAA7B;AACA,eAAKC,IAAL,GAAYN,iBAAiBM,IAA7B;;AAEA,eAAKC,QAAL,GAAgBP,iBAAiBO,QAAjB,IAA6B,EAA7C;AACA,eAAKC,SAAL,GAAiBR,iBAAiBO,QAAjB,CAA0BC,SAA3C;AACA,eAAKC,UAAL,GAAkBT,iBAAiBO,QAAjB,CAA0BE,UAA5C;AACA,eAAKC,MAAL,GAAcV,iBAAiBO,QAAjB,CAA0BG,MAAxC;AACA,cAAI,CAACV,iBAAiBO,QAAjB,CAA0BI,UAA/B,EAA0C;AACxCX,6BAAiBO,QAAjB,CAA0BI,UAA1B,GAAuC,KAAvC;AACD;;AAED,eAAKC,GAAL,GAAW,KAAKC,aAAL,EAAX;AACA,eAAKC,eAAL,GAAuB,IAAvB;AACA,eAAKC,SAAL,GAAiB,KAAjB;;AAEA,eAAKC,cAAL,GAAsB,IAAtB;AACA,eAAKC,OAAL,GAAe,EAAf;;AAEA,eAAKhB,EAAL,GAAUA,EAAV;AACA,eAAKC,UAAL,GAAkBA,UAAlB;AACA,eAAKC,WAAL,GAAmBA,WAAnB;AACA,eAAKC,UAAL,GAAkBA,UAAlB;;AAEA,eAAKc,kBAAL,GAA0B,IAA1B;AACA,eAAKC,kBAAL,GAA0B,IAA1B;AAED;;AAED;;;;;gCACMC,O,EAAQ;AACZ,gBAAIC,QAAQ,KAAKC,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBC,IAAxC,EAA8C,KAA9C,CAAZ;AACA,gBAAIC,MAAM,KAAKH,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBG,EAAxC,EAA4C,IAA5C,CAAV;AACA,gBAAIC,KAAK,EAAT;;AAEA/B,cAAEgC,IAAF,CAAOR,QAAQS,OAAf,EAAwB,UAASC,MAAT,EAAiB;AACvC,kBAAI,CAACA,OAAOC,MAAZ,EAAoB;AAAE;AAAS;AAC/BJ,iBAAGK,IAAH,CAAQ,KAAKC,oBAAL,CAA0BH,MAA1B,EAAkCV,OAAlC,CAAR;AACD,aAHuB,CAGtBc,IAHsB,CAGjB,IAHiB,CAAxB;;AAKA,gBAAIC,UAAUvC,EAAEwC,OAAF,CAAUT,EAAV,CAAd;;AAEA;AACA,gBAAI/B,EAAEyC,OAAF,CAAUF,OAAV,CAAJ,EAAwB;AACtB,kBAAIG,IAAI,KAAKrC,EAAL,CAAQsC,KAAR,EAAR;AACAD,gBAAEE,OAAF,CAAU,EAAEC,MAAM,EAAR,EAAV;AACA,qBAAOH,EAAEI,OAAT;AACD;;AAED,gBAAIC,cAAc,EAAlB;AACA/C,cAAEgC,IAAF,CAAOO,OAAP,EAAgB,UAASS,KAAT,EAAgB;AAC9B,kBAAIA,MAAMC,OAAN,IAAiBD,MAAMC,OAAN,CAAcC,MAAd,GAAuB,CAA5C,EAA+C;AAC7ClD,kBAAEgC,IAAF,CAAOgB,MAAMC,OAAb,EAAsB,UAASE,GAAT,EAAc;AAClCJ,8BAAYI,IAAIC,IAAhB,IAAwB,IAAxB;AACD,iBAFD;AAGD,eAJD,MAIO;AACLpD,kBAAEgC,IAAF,CAAOgB,MAAMK,IAAb,EAAmB,UAASF,GAAT,EAAcG,GAAd,EAAmB;AACpCP,8BAAYO,GAAZ,IAAmB,IAAnB;AACD,iBAFD;AAGD;AACF,aAVD;;AAYA,mBAAO,KAAKC,sBAAL,CAA4BhB,OAA5B,EAAqCd,KAArC,EAA4CI,GAA5C,EAAiD2B,IAAjD,CAAsD,UAASC,QAAT,EAAmB;AAC9E,kBAAIC,wBAAwB,KAAKC,mBAAL,CAAyBF,SAASZ,IAAlC,EAAwCrB,OAAxC,CAA5B;AACA,kBAAIoC,SAAS5D,EAAE6D,GAAF,CAAMJ,SAASZ,IAAf,EAAqB,UAASiB,UAAT,EAAqBC,KAArB,EAA4B;AAC5DA,wBAAQL,sBAAsBK,KAAtB,CAAR;AACA,oBAAIA,UAAU,CAAC,CAAf,EAAkB;AAChBA,0BAAQ,CAAR;AACD;AACD,qBAAKC,YAAL,CAAkBF,UAAlB;;AAEA,uBAAO,KAAKG,mBAAL,CAAyBH,UAAzB,EAAqCf,WAArC,EAAkDvB,QAAQS,OAAR,CAAgB8B,KAAhB,CAAlD,EAA0EvC,OAA1E,CAAP;AACD,eARiC,CAQhCc,IARgC,CAQ3B,IAR2B,CAArB,CAAb;AASA,qBAAO,EAAEO,MAAMe,MAAR,EAAP;AACD,aAZ4D,CAY3DtB,IAZ2D,CAYtD,IAZsD,CAAtD,CAAP;AAaD;;;2CAGe;AACd,mBAAO,KAAKhC,UAAL,CAAgB4D,iBAAhB,CAAkC;AACvClD,mBAAK,KAAKA,GAAL,GAAW,UADuB;AAEvCmD,sBAAQ;AAF+B,aAAlC,EAGJX,IAHI,CAGC,oBAAY;AAClB,kBAAIC,SAASW,MAAT,KAAoB,GLine truncated
|
||||||
Vendored
+2
-2
@@ -23,8 +23,8 @@
|
|||||||
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
||||||
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
||||||
],
|
],
|
||||||
"version": "0.0.6-SNAPSHOT",
|
"version": "1.2.8-SNAPSHOT",
|
||||||
"updated": "2017-08-11"
|
"updated": "2020-02-21"
|
||||||
},
|
},
|
||||||
|
|
||||||
"includes": [
|
"includes": [
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "timely-app",
|
"name": "timely-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.2",
|
"version": "1.2.8-SNAPSHOT",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
||||||
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
||||||
],
|
],
|
||||||
"version": "0.0.6-SNAPSHOT",
|
"version": "1.2.8-SNAPSHOT",
|
||||||
"updated": "2017-08-11"
|
"updated": "2020-02-21"
|
||||||
},
|
},
|
||||||
|
|
||||||
"includes": [
|
"includes": [
|
||||||
|
|||||||
@@ -446,7 +446,7 @@ export class TimelyDatasource {
|
|||||||
} else {
|
} else {
|
||||||
return target.metric === metricData.metric && _.every(target.tags, function(tagV, tagK) {
|
return target.metric === metricData.metric && _.every(target.tags, function(tagV, tagK) {
|
||||||
interpolatedTagValue = this.templateSrv.replace(tagV, options.scopedVars, 'pipe');
|
interpolatedTagValue = this.templateSrv.replace(tagV, options.scopedVars, 'pipe');
|
||||||
return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*";
|
return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === ".*";
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>Timely</name>
|
<name>Timely</name>
|
||||||
<description>A secure and scalable time series database based on Apache Accumulo</description>
|
<description>A secure and scalable time series database based on Apache Accumulo</description>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
<module>grafana</module>
|
<module>grafana</module>
|
||||||
<module>analytics</module>
|
<module>analytics</module>
|
||||||
<module>balancer</module>
|
<module>balancer</module>
|
||||||
|
<module>grafana-auth</module>
|
||||||
</modules>
|
</modules>
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:https://github.com/NationalSecurityAgency/timely.git</connection>
|
<connection>scm:git:https://github.com/NationalSecurityAgency/timely.git</connection>
|
||||||
@@ -40,50 +41,50 @@
|
|||||||
<os.detection.classifierWithLikes>fedora</os.detection.classifierWithLikes>
|
<os.detection.classifierWithLikes>fedora</os.detection.classifierWithLikes>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<version.accumulo>1.7.4</version.accumulo>
|
<version.accumulo>1.9.3</version.accumulo>
|
||||||
<version.buildnumber-maven>1.4</version.buildnumber-maven>
|
<version.buildnumber-maven>1.4</version.buildnumber-maven>
|
||||||
<version.caffeine>2.3.3</version.caffeine>
|
<version.caffeine>2.6.2</version.caffeine>
|
||||||
<version.collectd>5.5.1</version.collectd>
|
<version.collectd>5.7.1</version.collectd>
|
||||||
<version.commons-collections4>4.1</version.commons-collections4>
|
<version.commons-collections4>4.3</version.commons-collections4>
|
||||||
<version.commons-configuration>1.10</version.commons-configuration>
|
<version.commons-lang3>3.8.1</version.commons-lang3>
|
||||||
<version.commons-io>2.6</version.commons-io>
|
<version.commons-pool2>2.6.1</version.commons-pool2>
|
||||||
<version.commons-lang3>3.5</version.commons-lang3>
|
<version.curator>4.1.0</version.curator>
|
||||||
<version.commons-pool2>2.6.0</version.commons-pool2>
|
<version.disruptor>3.4.2</version.disruptor>
|
||||||
<version.curator>2.11.1</version.curator>
|
<version.easymock>4.0.2</version.easymock>
|
||||||
<version.disruptor>3.3.6</version.disruptor>
|
|
||||||
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
|
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
|
||||||
<version.fast-classpath-scanner>2.0.5</version.fast-classpath-scanner>
|
<version.fast-classpath-scanner>3.1.13</version.fast-classpath-scanner>
|
||||||
<version.flink>1.1.4</version.flink>
|
<version.flink>1.1.4</version.flink>
|
||||||
<version.google-flatbuffers>1.10.0</version.google-flatbuffers>
|
<version.google-flatbuffers>1.10.0</version.google-flatbuffers>
|
||||||
<version.guava>19.0</version.guava>
|
<version.guava>27.1-jre</version.guava>
|
||||||
<version.hadoop>2.7.3</version.hadoop>
|
<version.hadoop>2.7.7</version.hadoop>
|
||||||
<version.httpcomponents>4.5.2</version.httpcomponents>
|
<version.httpcomponents>4.5.6</version.httpcomponents>
|
||||||
<version.impsort>1.2.0</version.impsort>
|
<version.impsort>1.3.0</version.impsort>
|
||||||
<version.jackson>2.9.7</version.jackson>
|
<version.jackson>2.10.0</version.jackson>
|
||||||
<version.jacoco>0.7.6.201602180812</version.jacoco>
|
<version.jackson.databind>2.10.0</version.jackson.databind>
|
||||||
|
<version.jacoco>0.8.4</version.jacoco>
|
||||||
<version.javacsv>2.0</version.javacsv>
|
<version.javacsv>2.0</version.javacsv>
|
||||||
<version.javassist>3.21.0-GA</version.javassist>
|
<version.javassist>3.24.1-GA</version.javassist>
|
||||||
<version.jcip-annotations>1.0</version.jcip-annotations>
|
<version.jcip-annotations>1.0</version.jcip-annotations>
|
||||||
<version.jsoup>1.9.2</version.jsoup>
|
<version.jsoup>1.11.3</version.jsoup>
|
||||||
<version.junit>4.12</version.junit>
|
<version.junit>4.12</version.junit>
|
||||||
<version.log4j>2.6.2</version.log4j>
|
<version.log4j>2.11.2</version.log4j>
|
||||||
<version.maven-assembly>2.6</version.maven-assembly>
|
<version.maven-assembly>3.1.1</version.maven-assembly>
|
||||||
<version.maven-build-helper>1.12</version.maven-build-helper>
|
<version.maven-build-helper>3.0.0</version.maven-build-helper>
|
||||||
<version.maven-compiler>3.3</version.maven-compiler>
|
<version.maven-compiler>3.8.1</version.maven-compiler>
|
||||||
<version.maven-dependency>2.10</version.maven-dependency>
|
<version.maven-dependency>3.1.1</version.maven-dependency>
|
||||||
<version.maven-jar>3.0.1</version.maven-jar>
|
<version.maven-jar>3.1.2</version.maven-jar>
|
||||||
<version.maven-pmd>3.6</version.maven-pmd>
|
<version.maven-pmd>3.12.0</version.maven-pmd>
|
||||||
<version.maven-rpm>2.1.4</version.maven-rpm>
|
<version.maven-rpm>2.2.0</version.maven-rpm>
|
||||||
<version.maven-shade>2.4.2</version.maven-shade>
|
<version.maven-shade>3.2.1</version.maven-shade>
|
||||||
<version.maven-surefire>2.19.1</version.maven-surefire>
|
<version.maven-surefire>3.0.0-M3</version.maven-surefire>
|
||||||
<version.netty>4.0.56.Final</version.netty>
|
<version.netty>4.1.42.Final</version.netty>
|
||||||
<version.netty-tcnative>2.0.7.Final</version.netty-tcnative>
|
<version.netty-tcnative>2.0.25.Final</version.netty-tcnative>
|
||||||
<version.os-maven>1.5.0.Final</version.os-maven>
|
<version.os-maven>1.5.0.Final</version.os-maven>
|
||||||
<version.powermock>1.6.4</version.powermock>
|
<version.powermock>1.6.4</version.powermock>
|
||||||
<version.slf4j>1.7.21</version.slf4j>
|
<version.slf4j>1.7.26</version.slf4j>
|
||||||
<version.spotbugs-maven>3.1.7</version.spotbugs-maven>
|
<version.spotbugs-maven>3.1.12.1</version.spotbugs-maven>
|
||||||
<version.spring-boot>1.4.1.RELEASE</version.spring-boot>
|
<version.spring-boot>2.1.3.RELEASE</version.spring-boot>
|
||||||
<version.tyrus>1.13</version.tyrus>
|
<version.tyrus>1.15</version.tyrus>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -100,6 +101,11 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>${version.jackson.databind}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-guava</artifactId>
|
||||||
<version>${version.jackson}</version>
|
<version>${version.jackson}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -135,13 +141,18 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.lukehutch</groupId>
|
<groupId>io.github.lukehutch</groupId>
|
||||||
<artifactId>fast-classpath-scanner</artifactId>
|
<artifactId>fast-classpath-scanner</artifactId>
|
||||||
<version>2.0.5</version>
|
<version>${version.fast-classpath-scanner}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-all</artifactId>
|
<artifactId>netty-all</artifactId>
|
||||||
<version>${version.netty}</version>
|
<version>${version.netty}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
|
<version>${version.netty-tcnative}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.sourceforge.javacsv</groupId>
|
<groupId>net.sourceforge.javacsv</groupId>
|
||||||
<artifactId>javacsv</artifactId>
|
<artifactId>javacsv</artifactId>
|
||||||
@@ -151,6 +162,12 @@
|
|||||||
<groupId>org.apache.accumulo</groupId>
|
<groupId>org.apache.accumulo</groupId>
|
||||||
<artifactId>accumulo-core</artifactId>
|
<artifactId>accumulo-core</artifactId>
|
||||||
<version>${version.accumulo}</version>
|
<version>${version.accumulo}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.accumulo</groupId>
|
<groupId>org.apache.accumulo</groupId>
|
||||||
@@ -304,6 +321,11 @@
|
|||||||
<artifactId>collectd-plugin-parent</artifactId>
|
<artifactId>collectd-plugin-parent</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>timely</groupId>
|
||||||
|
<artifactId>timely-balancer</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely-client</artifactId>
|
<artifactId>timely-client</artifactId>
|
||||||
@@ -376,6 +398,12 @@
|
|||||||
<version>${version.jcip-annotations}</version>
|
<version>${version.jcip-annotations}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.easymock</groupId>
|
||||||
|
<artifactId>easymock</artifactId>
|
||||||
|
<version>${version.easymock}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.powermock</groupId>
|
<groupId>org.powermock</groupId>
|
||||||
<artifactId>powermock-easymock-release-full</artifactId>
|
<artifactId>powermock-easymock-release-full</artifactId>
|
||||||
@@ -391,7 +419,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>net.revelc.code.formatter</groupId>
|
<groupId>net.revelc.code.formatter</groupId>
|
||||||
<artifactId>formatter-maven-plugin</artifactId>
|
<artifactId>formatter-maven-plugin</artifactId>
|
||||||
<version>2.8.0</version>
|
<version>2.10.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<compilerCompliance>${maven.compiler.source}</compilerCompliance>
|
<compilerCompliance>${maven.compiler.source}</compilerCompliance>
|
||||||
<compilerSource>${maven.compiler.source}</compilerSource>
|
<compilerSource>${maven.compiler.source}</compilerSource>
|
||||||
@@ -409,7 +437,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.github.ekryd.sortpom</groupId>
|
<groupId>com.github.ekryd.sortpom</groupId>
|
||||||
<artifactId>sortpom-maven-plugin</artifactId>
|
<artifactId>sortpom-maven-plugin</artifactId>
|
||||||
<version>2.8.0</version>
|
<version>2.10.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<predefinedSortOrder>recommended_2008_06</predefinedSortOrder>
|
<predefinedSortOrder>recommended_2008_06</predefinedSortOrder>
|
||||||
<createBackupFile>false</createBackupFile>
|
<createBackupFile>false</createBackupFile>
|
||||||
@@ -441,7 +469,7 @@
|
|||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>${version.maven-surefire}</version>
|
<version>${version.maven-surefire}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.directory}/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_linux_x86_64.so -Dzookeeper.sasl.client=false</argLine>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**/*.java</include>
|
<include>**/*.java</include>
|
||||||
</includes>
|
</includes>
|
||||||
@@ -484,7 +512,7 @@
|
|||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>${version.maven-surefire}</version>
|
<version>${version.maven-surefire}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.directory}/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_linux_x86_64.so -Dzookeeper.sasl.client=false</argLine>
|
||||||
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
|
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
|
||||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -553,7 +581,7 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<rules>
|
<rules>
|
||||||
<requireMavenVersion>
|
<requireMavenVersion>
|
||||||
<version>3.0.5</version>
|
<version>3.5.0</version>
|
||||||
</requireMavenVersion>
|
</requireMavenVersion>
|
||||||
<requireJavaVersion>
|
<requireJavaVersion>
|
||||||
<version>[${maven.compiler.target},)</version>
|
<version>[${maven.compiler.target},)</version>
|
||||||
@@ -724,6 +752,9 @@
|
|||||||
<name>m2e.version</name>
|
<name>m2e.version</name>
|
||||||
</property>
|
</property>
|
||||||
</activation>
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.release>8</maven.compiler.release>
|
||||||
|
</properties>
|
||||||
<build>
|
<build>
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
@@ -784,5 +815,14 @@
|
|||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
</build>
|
</build>
|
||||||
</profile>
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>jdk-release-flag</id>
|
||||||
|
<activation>
|
||||||
|
<jdk>[9,)</jdk>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.release>8</maven.compiler.release>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
Executable
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [[ `uname` == "Darwin" ]]; then
|
||||||
|
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
||||||
|
else
|
||||||
|
THIS_SCRIPT=`readlink -f $0`
|
||||||
|
fi
|
||||||
|
|
||||||
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
|
BASE_DIR=${THIS_DIR}/..
|
||||||
|
CONF_DIR="${BASE_DIR}/conf"
|
||||||
|
LIB_DIR="${BASE_DIR}/lib"
|
||||||
|
|
||||||
|
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
|
||||||
|
JVM_ARGS="-Xmx1024m -Xms128m"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -Dlogging.config=${CONF_DIR}/log4j2-error-console.xml"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-error-console.xml"
|
||||||
|
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||||
|
|
||||||
|
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.store.compaction.util.TabletMetadataConsole --spring.config.name=timely"
|
||||||
|
$JAVA_HOME/bin/java ${JVM_ARGS} timely.store.compaction.util.TabletMetadataConsole --spring.config.name=timely
|
||||||
@@ -8,11 +8,6 @@ else
|
|||||||
TCNATIVE_SUFFIX="so"
|
TCNATIVE_SUFFIX="so"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# netty tcnative file reference
|
|
||||||
#netty-tcnative-1.1.33.Fork18-linux-x86_64-fedora.jar -> libnetty-tcnative.so
|
|
||||||
#netty-tcnative-1.1.33.Fork18-linux-x86_64.jar -> libnetty-tcnative.so
|
|
||||||
#netty-tcnative-1.1.33.Fork18-osx-x86_64.jar -> libnetty-tcnative.jnilib
|
|
||||||
|
|
||||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
||||||
BASE_DIR=${THIS_DIR}/..
|
BASE_DIR=${THIS_DIR}/..
|
||||||
@@ -32,12 +27,12 @@ fi
|
|||||||
mkdir -p ${NATIVE_DIR}
|
mkdir -p ${NATIVE_DIR}
|
||||||
|
|
||||||
pushd ${BASE_DIR}/bin
|
pushd ${BASE_DIR}/bin
|
||||||
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative*.jar META-INF/native/libnetty_tcnative.${NATIVE_SUFFIX}
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative-boringssl-static*.jar META-INF/native/libnetty_tcnative_linux_x86_64.${TCNATIVE_SUFFIX}
|
||||||
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-transport-native-epoll*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${NATIVE_SUFFIX}
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-all*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${TCNATIVE_SUFFIX}
|
||||||
popd
|
popd
|
||||||
|
|
||||||
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
|
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*:${HADOOP_CONF_DIR}"
|
||||||
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS}"
|
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-spring.xml"
|
||||||
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||||
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,12 @@
|
|||||||
|
|
||||||
if [[ `uname` == "Darwin" ]]; then
|
if [[ `uname` == "Darwin" ]]; then
|
||||||
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
||||||
TCNATIVE_SUFFIX="tcnative.jnilib"
|
TCNATIVE_SUFFIX="jnilib"
|
||||||
else
|
else
|
||||||
THIS_SCRIPT=`readlink -f $0`
|
THIS_SCRIPT=`readlink -f $0`
|
||||||
TCNATIVE_SUFFIX="tcnative.so"
|
TCNATIVE_SUFFIX="so"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# netty tcnative file reference
|
|
||||||
#netty-tcnative-1.1.33.Fork18-linux-x86_64-fedora.jar -> libnetty-tcnative.so
|
|
||||||
#netty-tcnative-1.1.33.Fork18-linux-x86_64.jar -> libnetty-tcnative.so
|
|
||||||
#netty-tcnative-1.1.33.Fork18-osx-x86_64.jar -> libnetty-tcnative.jnilib
|
|
||||||
|
|
||||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||||
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
||||||
BASE_DIR=${THIS_DIR}/..
|
BASE_DIR=${THIS_DIR}/..
|
||||||
@@ -32,11 +27,12 @@ fi
|
|||||||
mkdir -p ${NATIVE_DIR}
|
mkdir -p ${NATIVE_DIR}
|
||||||
|
|
||||||
pushd ${BASE_DIR}/bin
|
pushd ${BASE_DIR}/bin
|
||||||
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative*.jar META-INF/native/libnetty-${TCNATIVE_SUFFIX}
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative-boringssl-static*.jar META-INF/native/libnetty_tcnative_linux_x86_64.${TCNATIVE_SUFFIX}
|
||||||
|
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-all*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${TCNATIVE_SUFFIX}
|
||||||
popd
|
popd
|
||||||
|
|
||||||
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
|
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*:${HADOOP_CONF_DIR}"
|
||||||
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS}"
|
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-spring.xml"
|
||||||
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||||
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||||
# for debugging
|
# for debugging
|
||||||
|
|||||||
@@ -26,12 +26,12 @@
|
|||||||
</Console>
|
</Console>
|
||||||
</Appenders>
|
</Appenders>
|
||||||
<Loggers>
|
<Loggers>
|
||||||
<Logger name="timely.subscription" level="trace" additivity="false">
|
<Root level="debug" includeLocation="false">
|
||||||
<AppenderRef ref="Subscription" />
|
|
||||||
</Logger>
|
|
||||||
<Root level="trace" includeLocation="false">
|
|
||||||
<AppenderRef ref="Console" level="warn" />
|
<AppenderRef ref="Console" level="warn" />
|
||||||
<AppenderRef ref="Rolling" level="trace" />
|
<AppenderRef ref="Rolling" level="debug" />
|
||||||
</Root>
|
</Root>
|
||||||
|
<Logger name="timely" additivity="false">
|
||||||
|
<AppenderRef ref="Console" level="debug" />
|
||||||
|
</Logger>
|
||||||
</Loggers>
|
</Loggers>
|
||||||
</Configuration>
|
</Configuration>
|
||||||
+34
-12
@@ -15,15 +15,27 @@
|
|||||||
|
|
||||||
<beans:bean id="timelyUserDetailsService" class="timely.auth.UserDetailsService">
|
<beans:bean id="timelyUserDetailsService" class="timely.auth.UserDetailsService">
|
||||||
<beans:property name="users">
|
<beans:property name="users">
|
||||||
<util:map key-type="java.lang.String">
|
<util:list>
|
||||||
<beans:entry key="example.com">
|
<beans:bean class="timely.auth.TimelyUser">
|
||||||
<util:list>
|
<beans:constructor-arg name="subjectDn">
|
||||||
<beans:value>D</beans:value>
|
<beans:value>CN=example.com</beans:value>
|
||||||
<beans:value>E</beans:value>
|
</beans:constructor-arg>
|
||||||
<beans:value>F</beans:value>
|
<beans:constructor-arg name="auths">
|
||||||
</util:list>
|
<util:list>
|
||||||
</beans:entry>
|
<beans:value>D</beans:value>
|
||||||
</util:map>
|
<beans:value>E</beans:value>
|
||||||
|
<beans:value>F</beans:value>
|
||||||
|
</util:list>
|
||||||
|
</beans:constructor-arg>
|
||||||
|
<beans:constructor-arg name="roles">
|
||||||
|
<util:list>
|
||||||
|
<beans:value>G</beans:value>
|
||||||
|
<beans:value>H</beans:value>
|
||||||
|
<beans:value>I</beans:value>
|
||||||
|
</util:list>
|
||||||
|
</beans:constructor-arg>
|
||||||
|
</beans:bean>
|
||||||
|
</util:list>
|
||||||
</beans:property>
|
</beans:property>
|
||||||
</beans:bean>
|
</beans:bean>
|
||||||
|
|
||||||
@@ -34,9 +46,12 @@
|
|||||||
<user-service id="usernamePasswordService">
|
<user-service id="usernamePasswordService">
|
||||||
<user name="test" password="test1" authorities="A,B,C" />
|
<user name="test" password="test1" authorities="A,B,C" />
|
||||||
</user-service>
|
</user-service>
|
||||||
|
|
||||||
<beans:bean id="UserNamePasswordAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
<beans:bean id="noOpPasswordEncoder" class="org.springframework.security.crypto.password.NoOpPasswordEncoder"/>
|
||||||
|
|
||||||
|
<beans:bean id="UserNamePasswordAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
|
||||||
<beans:property name="userDetailsService" ref="usernamePasswordService"/>
|
<beans:property name="userDetailsService" ref="usernamePasswordService"/>
|
||||||
|
<beans:property name="passwordEncoder" ref="noOpPasswordEncoder"/>
|
||||||
</beans:bean>
|
</beans:bean>
|
||||||
|
|
||||||
<authentication-manager alias="authenticationManager">
|
<authentication-manager alias="authenticationManager">
|
||||||
@@ -45,5 +60,12 @@
|
|||||||
<!-- Basic authorization provider, validates provided username and password -->
|
<!-- Basic authorization provider, validates provided username and password -->
|
||||||
<authentication-provider ref="UserNamePasswordAuthenticationProvider" />
|
<authentication-provider ref="UserNamePasswordAuthenticationProvider" />
|
||||||
</authentication-manager>
|
</authentication-manager>
|
||||||
|
|
||||||
|
<util:list id="requiredRoles" value-type="java.lang.String">
|
||||||
|
<beans:value></beans:value>
|
||||||
|
</util:list>
|
||||||
|
|
||||||
|
<util:list id="requiredAuths" value-type="java.lang.String">
|
||||||
|
<beans:value></beans:value>
|
||||||
|
</util:list>
|
||||||
</beans:beans>
|
</beans:beans>
|
||||||
@@ -18,8 +18,11 @@ timely:
|
|||||||
max-downsample-memory: 10000000
|
max-downsample-memory: 10000000
|
||||||
security:
|
security:
|
||||||
session-max-age: 86400
|
session-max-age: 86400
|
||||||
allow-anonymous-access: true
|
cache-expiration-minutes: 60
|
||||||
ssl:
|
cache-refresh-minutes: 5
|
||||||
|
allow-anonymous-http-access: true
|
||||||
|
allow-anonymous-ws-access: true
|
||||||
|
server-ssl:
|
||||||
certificate-file: /timely-server-src/server/pki/timely.csr
|
certificate-file: /timely-server-src/server/pki/timely.csr
|
||||||
key-file: /timely-server-src/server/pki/timely-pkcs8.key
|
key-file: /timely-server-src/server/pki/timely-pkcs8.key
|
||||||
key-password: password
|
key-password: password
|
||||||
@@ -49,9 +52,9 @@ timely:
|
|||||||
timeout: 60
|
timeout: 60
|
||||||
subscription-lag: 120
|
subscription-lag: 120
|
||||||
meta-cache:
|
meta-cache:
|
||||||
expiration-minutes: 60
|
expiration-minutes: 1440
|
||||||
initial-capacity: 2000
|
cache-refresh-minutes: 60
|
||||||
max-capacity: 10000
|
max-tag-values: 100
|
||||||
visibility-cache:
|
visibility-cache:
|
||||||
expiration-minutes: 60
|
expiration-minutes: 60
|
||||||
initial-capacity: 2000
|
initial-capacity: 2000
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ timely:
|
|||||||
meta-table: timely.meta
|
meta-table: timely.meta
|
||||||
metric-age-off-days:
|
metric-age-off-days:
|
||||||
default: 7
|
default: 7
|
||||||
|
cache:
|
||||||
|
enabled: false
|
||||||
metrics-report-ignored-tags:
|
metrics-report-ignored-tags:
|
||||||
accumulo:
|
accumulo:
|
||||||
instance-name: TimelyStandalone
|
instance-name: TimelyStandalone
|
||||||
@@ -18,8 +20,11 @@ timely:
|
|||||||
max-downsample-memory: 10000000
|
max-downsample-memory: 10000000
|
||||||
security:
|
security:
|
||||||
session-max-age: 86400
|
session-max-age: 86400
|
||||||
allow-anonymous-access: true
|
cache-expiration-minutes: 60
|
||||||
ssl:
|
cache-refresh-minutes: 5
|
||||||
|
allow-anonymous-http-access: true
|
||||||
|
allow-anonymous-ws-access: true
|
||||||
|
server-ssl:
|
||||||
certificate-file:
|
certificate-file:
|
||||||
key-file:
|
key-file:
|
||||||
key-password: timely
|
key-password: timely
|
||||||
@@ -53,9 +58,9 @@ timely:
|
|||||||
scanner-read-ahead: 1
|
scanner-read-ahead: 1
|
||||||
subscription-batch-size: 5000
|
subscription-batch-size: 5000
|
||||||
meta-cache:
|
meta-cache:
|
||||||
expiration-minutes: 60
|
expiration-minutes: 1440
|
||||||
initial-capacity: 2000
|
cache-refresh-minutes: 60
|
||||||
max-capacity: 10000
|
max-tag-values: 100
|
||||||
visibility-cache:
|
visibility-cache:
|
||||||
expiration-minutes: 60
|
expiration-minutes: 60
|
||||||
initial-capacity: 2000
|
initial-capacity: 2000
|
||||||
|
|||||||
+24
-21
@@ -4,14 +4,15 @@ timely:
|
|||||||
metric-age-off-days:
|
metric-age-off-days:
|
||||||
default: 7
|
default: 7
|
||||||
cache:
|
cache:
|
||||||
enabled:
|
enabled: true
|
||||||
age-off-hours:
|
age-off-hours:
|
||||||
default: 30
|
default: 26
|
||||||
metrics-report-ignored-tags:
|
metrics-report-ignored-tags:
|
||||||
|
defaultVisibility:
|
||||||
accumulo:
|
accumulo:
|
||||||
instance-name:
|
instance-name: accumulo
|
||||||
zookeepers:
|
zookeepers: localhost:2181
|
||||||
username:
|
username: root
|
||||||
password:
|
password:
|
||||||
write:
|
write:
|
||||||
latency: 5s
|
latency: 5s
|
||||||
@@ -22,23 +23,26 @@ timely:
|
|||||||
max-downsample-memory: 10000000
|
max-downsample-memory: 10000000
|
||||||
security:
|
security:
|
||||||
session-max-age: 86400
|
session-max-age: 86400
|
||||||
allow-anonymous-access: false
|
cache-expiration-minutes: 60
|
||||||
ssl:
|
cache-refresh-minutes: 5
|
||||||
|
allow-anonymous-http-access: true
|
||||||
|
allow-anonymous-ws-access: true
|
||||||
|
server-ssl:
|
||||||
certificate-file:
|
certificate-file:
|
||||||
key-file:
|
key-file:
|
||||||
key-password:
|
key-password:
|
||||||
use-generated-keypair: false
|
use-generated-keypair: true
|
||||||
trust-store-file:
|
trust-store-file:
|
||||||
use-openssl: true
|
use-openssl: true
|
||||||
#use-ciphers:
|
#use-ciphers:
|
||||||
server:
|
server:
|
||||||
ip:
|
ip: 0.0.0.0
|
||||||
tcp-port:
|
tcp-port: 4242
|
||||||
udp-port:
|
udp-port: 4542
|
||||||
http:
|
http:
|
||||||
host:
|
host: localhost
|
||||||
ip:
|
ip: 0.0.0.0
|
||||||
port:
|
port: 4243
|
||||||
redirect-path: /secure-me
|
redirect-path: /secure-me
|
||||||
strict-transport-max-age: 608400
|
strict-transport-max-age: 608400
|
||||||
cors:
|
cors:
|
||||||
@@ -49,8 +53,8 @@ timely:
|
|||||||
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||||
allowed-headers: content-type
|
allowed-headers: content-type
|
||||||
websocket:
|
websocket:
|
||||||
ip:
|
ip: 0.0.0.0
|
||||||
port:
|
port: 4244
|
||||||
timeout: 60
|
timeout: 60
|
||||||
subscription-lag: 120
|
subscription-lag: 120
|
||||||
scanner-batch-size: 10000
|
scanner-batch-size: 10000
|
||||||
@@ -58,10 +62,9 @@ timely:
|
|||||||
scanner-read-ahead: 1
|
scanner-read-ahead: 1
|
||||||
subscription-batch-size: 5000
|
subscription-batch-size: 5000
|
||||||
meta-cache:
|
meta-cache:
|
||||||
expiration-minutes: 60
|
expiration-minutes: 1440
|
||||||
initial-capacity: 2000
|
cache-refresh-minutes: 60
|
||||||
max-capacity: 10000
|
max-tag-values: 100
|
||||||
visibility-cache:
|
visibility-cache:
|
||||||
expiration-minutes: 60
|
expiration-minutes: 60
|
||||||
initial-capacity: 2000
|
|
||||||
max-capacity: 10000
|
|
||||||
+22
-39
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>timely</groupId>
|
<groupId>timely</groupId>
|
||||||
<artifactId>timely</artifactId>
|
<artifactId>timely</artifactId>
|
||||||
<version>1.0.1-SNAPSHOT</version>
|
<version>1.2.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>timely-server</artifactId>
|
<artifactId>timely-server</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -20,6 +20,10 @@
|
|||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
|
<artifactId>jackson-datatype-guava</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||||
<artifactId>jackson-datatype-jdk8</artifactId>
|
<artifactId>jackson-datatype-jdk8</artifactId>
|
||||||
@@ -104,6 +108,10 @@
|
|||||||
<groupId>org.apache.hadoop</groupId>
|
<groupId>org.apache.hadoop</groupId>
|
||||||
<artifactId>hadoop-minicluster</artifactId>
|
<artifactId>hadoop-minicluster</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.glassfish.tyrus</groupId>
|
||||||
|
<artifactId>tyrus-client</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
@@ -145,9 +153,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-tcnative</artifactId>
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
<version>${version.netty-tcnative}</version>
|
|
||||||
<classifier>${os.detected.classifier}</classifier>
|
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -175,11 +181,22 @@
|
|||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.easymock</groupId>
|
||||||
|
<artifactId>easymock</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.powermock</groupId>
|
||||||
|
<artifactId>powermock-easymock-release-full</artifactId>
|
||||||
|
<classifier>full</classifier>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||||
@@ -236,9 +253,8 @@
|
|||||||
<artifactItems>
|
<artifactItems>
|
||||||
<artifactItem>
|
<artifactItem>
|
||||||
<groupId>io.netty</groupId>
|
<groupId>io.netty</groupId>
|
||||||
<artifactId>netty-tcnative</artifactId>
|
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||||
<version>${version.netty-tcnative}</version>
|
<version>${version.netty-tcnative}</version>
|
||||||
<classifier>${os.detected.classifier}</classifier>
|
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
<overWrite>false</overWrite>
|
<overWrite>false</overWrite>
|
||||||
<outputDirectory>${project.build.directory}/native</outputDirectory>
|
<outputDirectory>${project.build.directory}/native</outputDirectory>
|
||||||
@@ -280,37 +296,4 @@
|
|||||||
</extension>
|
</extension>
|
||||||
</extensions>
|
</extensions>
|
||||||
</build>
|
</build>
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>native-epoll-linux</id>
|
|
||||||
<activation>
|
|
||||||
<os>
|
|
||||||
<family>!mac</family>
|
|
||||||
</os>
|
|
||||||
</activation>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-transport-native-epoll</artifactId>
|
|
||||||
<version>${version.netty}</version>
|
|
||||||
<classifier>linux-x86_64</classifier>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</profile>
|
|
||||||
<profile>
|
|
||||||
<id>native-epoll</id>
|
|
||||||
<activation>
|
|
||||||
<os>
|
|
||||||
<family>mac</family>
|
|
||||||
</os>
|
|
||||||
</activation>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.netty</groupId>
|
|
||||||
<artifactId>netty-transport-native-epoll</artifactId>
|
|
||||||
<version>${version.netty}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
</project>
|
</project>
|
||||||
Vendored
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
<directory>${project.basedir}/bin</directory>
|
<directory>${project.basedir}/bin</directory>
|
||||||
<outputDirectory>bin</outputDirectory>
|
<outputDirectory>bin</outputDirectory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>*</include>
|
<include>**/*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
package timely;
|
package timely;
|
||||||
|
|
||||||
|
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS;
|
||||||
|
import static timely.store.cache.DataStoreCache.NON_CACHED_METRICS_LOCK_PATH;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@@ -21,6 +24,7 @@ import io.netty.channel.ChannelHandler;
|
|||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelOption;
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.WriteBufferWaterMark;
|
||||||
import io.netty.channel.epoll.EpollChannelOption;
|
import io.netty.channel.epoll.EpollChannelOption;
|
||||||
import io.netty.channel.epoll.EpollDatagramChannel;
|
import io.netty.channel.epoll.EpollDatagramChannel;
|
||||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||||
@@ -41,6 +45,7 @@ import io.netty.handler.codec.http.HttpRequestDecoder;
|
|||||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||||
import io.netty.handler.codec.http.HttpServerCodec;
|
import io.netty.handler.codec.http.HttpServerCodec;
|
||||||
import io.netty.handler.codec.http.cors.CorsConfig;
|
import io.netty.handler.codec.http.cors.CorsConfig;
|
||||||
|
import io.netty.handler.codec.http.cors.CorsConfigBuilder;
|
||||||
import io.netty.handler.codec.http.cors.CorsHandler;
|
import io.netty.handler.codec.http.cors.CorsHandler;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||||
import io.netty.handler.logging.LoggingHandler;
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
@@ -55,6 +60,7 @@ import io.netty.handler.stream.ChunkedWriteHandler;
|
|||||||
import io.netty.handler.timeout.IdleStateHandler;
|
import io.netty.handler.timeout.IdleStateHandler;
|
||||||
import io.netty.util.NettyRuntime;
|
import io.netty.util.NettyRuntime;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
|
import org.apache.accumulo.core.conf.AccumuloConfiguration;
|
||||||
import org.apache.curator.RetryPolicy;
|
import org.apache.curator.RetryPolicy;
|
||||||
import org.apache.curator.framework.CuratorFramework;
|
import org.apache.curator.framework.CuratorFramework;
|
||||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||||
@@ -63,12 +69,13 @@ import org.apache.curator.x.discovery.ServiceDiscovery;
|
|||||||
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
|
import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
|
||||||
import org.apache.curator.x.discovery.ServiceInstance;
|
import org.apache.curator.x.discovery.ServiceInstance;
|
||||||
import org.apache.curator.x.discovery.ServiceInstanceBuilder;
|
import org.apache.curator.x.discovery.ServiceInstanceBuilder;
|
||||||
|
import org.apache.zookeeper.CreateMode;
|
||||||
import org.apache.zookeeper.data.Stat;
|
import org.apache.zookeeper.data.Stat;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.boot.WebApplicationType;
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import timely.api.response.TimelyException;
|
|
||||||
import timely.auth.AuthCache;
|
import timely.auth.AuthCache;
|
||||||
import timely.auth.VisibilityCache;
|
import timely.auth.VisibilityCache;
|
||||||
import timely.configuration.Configuration;
|
import timely.configuration.Configuration;
|
||||||
@@ -97,7 +104,7 @@ import timely.netty.udp.UdpDecoder;
|
|||||||
import timely.netty.udp.UdpPacketToByteBuf;
|
import timely.netty.udp.UdpPacketToByteBuf;
|
||||||
import timely.netty.websocket.WSMetricPutHandler;
|
import timely.netty.websocket.WSMetricPutHandler;
|
||||||
import timely.netty.websocket.WSVersionRequestHandler;
|
import timely.netty.websocket.WSVersionRequestHandler;
|
||||||
import timely.netty.websocket.WebSocketHttpCookieHandler;
|
import timely.netty.websocket.WebSocketFullRequestHandler;
|
||||||
import timely.netty.websocket.WebSocketRequestDecoder;
|
import timely.netty.websocket.WebSocketRequestDecoder;
|
||||||
import timely.netty.websocket.subscription.WSAddSubscriptionRequestHandler;
|
import timely.netty.websocket.subscription.WSAddSubscriptionRequestHandler;
|
||||||
import timely.netty.websocket.subscription.WSCloseSubscriptionRequestHandler;
|
import timely.netty.websocket.subscription.WSCloseSubscriptionRequestHandler;
|
||||||
@@ -125,6 +132,7 @@ public class Server {
|
|||||||
private static final String OS_VERSION = "os.version";
|
private static final String OS_VERSION = "os.version";
|
||||||
private static final String WS_PATH = "/websocket";
|
private static final String WS_PATH = "/websocket";
|
||||||
|
|
||||||
|
private CuratorFramework curatorFramework;
|
||||||
protected static final CountDownLatch LATCH = new CountDownLatch(1);
|
protected static final CountDownLatch LATCH = new CountDownLatch(1);
|
||||||
static ConfigurableApplicationContext applicationContext;
|
static ConfigurableApplicationContext applicationContext;
|
||||||
|
|
||||||
@@ -146,6 +154,9 @@ public class Server {
|
|||||||
protected volatile boolean shutdown = false;
|
protected volatile boolean shutdown = false;
|
||||||
private final int DEFAULT_EVENT_LOOP_THREADS;
|
private final int DEFAULT_EVENT_LOOP_THREADS;
|
||||||
|
|
||||||
|
private String[] zkPaths = new String[] { SERVICE_DISCOVERY_PATH, NON_CACHED_METRICS,
|
||||||
|
NON_CACHED_METRICS_LOCK_PATH };
|
||||||
|
|
||||||
private static boolean useEpoll() {
|
private static boolean useEpoll() {
|
||||||
|
|
||||||
// Should we just return true if this is Linux and if we get an error
|
// Should we just return true if this is Linux and if we get an error
|
||||||
@@ -175,13 +186,8 @@ public class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerService() {
|
public void registerService(CuratorFramework curatorFramework) {
|
||||||
try {
|
try {
|
||||||
RetryPolicy retryPolicy = new RetryForever(1000);
|
|
||||||
CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient(config.getAccumulo().getZookeepers(),
|
|
||||||
30000, 10000, retryPolicy);
|
|
||||||
curatorFramework.start();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Stat stat = curatorFramework.checkExists().forPath(SERVICE_DISCOVERY_PATH);
|
Stat stat = curatorFramework.checkExists().forPath(SERVICE_DISCOVERY_PATH);
|
||||||
if (stat == null) {
|
if (stat == null) {
|
||||||
@@ -205,13 +211,13 @@ public class Server {
|
|||||||
payload.setWsPort(config.getWebsocket().getPort());
|
payload.setWsPort(config.getWebsocket().getPort());
|
||||||
payload.setUdpPort(config.getServer().getUdpPort());
|
payload.setUdpPort(config.getServer().getUdpPort());
|
||||||
|
|
||||||
ServiceInstanceBuilder builder = ServiceInstance.builder();
|
ServiceInstanceBuilder<ServerDetails> builder = ServiceInstance.builder();
|
||||||
String serviceName = host + ":" + config.getServer().getTcpPort();
|
String serviceName = host + ":" + config.getServer().getTcpPort();
|
||||||
ServiceInstance serviceInstance = builder.id(serviceName).name("timely-server")
|
ServiceInstance<ServerDetails> serviceInstance = builder.id(serviceName).name("timely-server")
|
||||||
.address(config.getServer().getIp()).port(config.getServer().getTcpPort()).payload(payload).build();
|
.address(config.getServer().getIp()).port(config.getServer().getTcpPort()).payload(payload).build();
|
||||||
|
|
||||||
ServiceDiscovery discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
|
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
|
||||||
.basePath(SERVICE_DISCOVERY_PATH).build();
|
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
||||||
discovery.start();
|
discovery.start();
|
||||||
discovery.registerService(serviceInstance);
|
discovery.registerService(serviceInstance);
|
||||||
|
|
||||||
@@ -227,11 +233,12 @@ public class Server {
|
|||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
Configuration conf = initializeConfiguration(args);
|
Server.applicationContext = initializeContext(args);
|
||||||
|
Configuration conf = Server.applicationContext.getBean(Configuration.class);
|
||||||
|
|
||||||
Server s = new Server(conf);
|
Server server = new Server(conf);
|
||||||
try {
|
try {
|
||||||
s.run();
|
server.run();
|
||||||
LATCH.await();
|
LATCH.await();
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
LOG.info("Server shutting down.");
|
LOG.info("Server shutting down.");
|
||||||
@@ -239,16 +246,18 @@ public class Server {
|
|||||||
LOG.error("Error running server.", e);
|
LOG.error("Error running server.", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
s.shutdown();
|
server.shutdown();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Configuration initializeConfiguration(String[] args) {
|
protected static ConfigurableApplicationContext initializeContext(String[] args) {
|
||||||
applicationContext = new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(args);
|
SpringApplicationBuilder builder = new SpringApplicationBuilder(SpringBootstrap.class);
|
||||||
return applicationContext.getBean(Configuration.class);
|
builder.web(WebApplicationType.NONE);
|
||||||
|
builder.registerShutdownHook(false);
|
||||||
|
return builder.run(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdownHook() {
|
private void shutdownHook() {
|
||||||
@@ -263,6 +272,8 @@ public class Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
LOG.warn("Server shutdown 1");
|
||||||
|
|
||||||
List<ChannelFuture> channelFutures = new ArrayList<>();
|
List<ChannelFuture> channelFutures = new ArrayList<>();
|
||||||
|
|
||||||
if (tcpChannelHandle != null) {
|
if (tcpChannelHandle != null) {
|
||||||
@@ -280,8 +291,9 @@ public class Server {
|
|||||||
channelFutures.add(wsChannelHandle.close());
|
channelFutures.add(wsChannelHandle.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int udpChannel = 1;
|
||||||
for (Channel c : udpChannelHandleList) {
|
for (Channel c : udpChannelHandleList) {
|
||||||
LOG.info("Closing udpChannelHandle");
|
LOG.info("Closing udpChannelHandle #" + udpChannel++);
|
||||||
channelFutures.add(c.close());
|
channelFutures.add(c.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,14 +302,15 @@ public class Server {
|
|||||||
try {
|
try {
|
||||||
f.get();
|
f.get();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Error while shutting down channel: {}", f.channel().config());
|
LOG.error("Channel:" + f.channel().config() + " -> " + e.getMessage(), e);
|
||||||
LOG.error("{}", e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Integer quietPeriod = config.getServer().getShutdownQuietPeriod();
|
LOG.warn("Server shutdown 2");
|
||||||
|
|
||||||
|
int quietPeriod = config.getServer().getShutdownQuietPeriod();
|
||||||
List<Future<?>> groupFutures = new ArrayList<>();
|
List<Future<?>> groupFutures = new ArrayList<>();
|
||||||
|
|
||||||
if (tcpBossGroup != null) {
|
if (tcpBossGroup != null) {
|
||||||
LOG.info("Shutting down tcpBossGroup");
|
LOG.info("Shutting down tcpBossGroup");
|
||||||
groupFutures.add(tcpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(tcpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
@@ -333,6 +346,8 @@ public class Server {
|
|||||||
groupFutures.add(udpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(udpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG.warn("Server shutdown 3");
|
||||||
|
|
||||||
if (udpWorkerGroup != null) {
|
if (udpWorkerGroup != null) {
|
||||||
LOG.info("Shutting down udpWorkerGroup");
|
LOG.info("Shutting down udpWorkerGroup");
|
||||||
groupFutures.add(udpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
groupFutures.add(udpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
|
||||||
@@ -342,37 +357,70 @@ public class Server {
|
|||||||
try {
|
try {
|
||||||
f.get();
|
f.get();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
LOG.error("Error while shutting down group: {}", f.toString());
|
LOG.error("Group:" + f.toString() + " -> " + e.getMessage(), e);
|
||||||
LOG.error("{}", e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
LOG.warn("Server shutdown 4");
|
||||||
LOG.info("Flushing datastore.");
|
|
||||||
dataStore.flush();
|
|
||||||
} catch (TimelyException e) {
|
|
||||||
LOG.error("Error flushing to server during shutdown", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOG.info("Closing MetaCacheFactory");
|
LOG.info("Closing dataStore");
|
||||||
|
dataStore.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.warn("Server shutdown 5");
|
||||||
|
|
||||||
|
if (dataStoreCache != null) {
|
||||||
|
try {
|
||||||
|
LOG.info("Closing dataStoreCache");
|
||||||
|
dataStoreCache.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.warn("Server shutdown 6");
|
||||||
|
|
||||||
|
try {
|
||||||
|
LOG.info("Closing metaCacheFactory");
|
||||||
MetaCacheFactory.close();
|
MetaCacheFactory.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error closing MetaCacheFactory during shutdown", e);
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG.warn("Server shutdown 7");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LOG.info("Closing WebSocketRequestDecoder");
|
LOG.info("Closing webSocketRequestDecoder subscriptions");
|
||||||
WebSocketRequestDecoder.close();
|
WebSocketRequestDecoder.close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error closing WebSocketRequestDecoder during shutdown", e);
|
LOG.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (applicationContext != null) {
|
LOG.warn("Server shutdown 8");
|
||||||
LOG.info("Closing applicationContext");
|
|
||||||
applicationContext.close();
|
if (curatorFramework != null) {
|
||||||
|
try {
|
||||||
|
LOG.info("Closing curatorFramework");
|
||||||
|
curatorFramework.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG.warn("Server shutdown 9");
|
||||||
|
|
||||||
|
if (applicationContext != null) {
|
||||||
|
try {
|
||||||
|
LOG.info("Closing applicationContext");
|
||||||
|
applicationContext.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.warn("Server shutdown 10");
|
||||||
this.shutdown = true;
|
this.shutdown = true;
|
||||||
LOG.info("Server shut down.");
|
LOG.info("Server shut down.");
|
||||||
}
|
}
|
||||||
@@ -390,20 +438,42 @@ public class Server {
|
|||||||
this.config = conf;
|
this.config = conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensureZkPaths(CuratorFramework curatorFramework, String[] paths) {
|
||||||
|
for (String s : paths) {
|
||||||
|
try {
|
||||||
|
Stat stat = curatorFramework.checkExists().forPath(s);
|
||||||
|
if (stat == null) {
|
||||||
|
curatorFramework.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT)
|
||||||
|
.forPath(s);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.info(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
|
|
||||||
|
RetryPolicy retryPolicy = new RetryForever(1000);
|
||||||
|
int timeout = Long.valueOf(AccumuloConfiguration.getTimeInMillis(config.getAccumulo().getZookeeperTimeout()))
|
||||||
|
.intValue();
|
||||||
|
curatorFramework = CuratorFrameworkFactory.newClient(config.getAccumulo().getZookeepers(), timeout, 10000,
|
||||||
|
retryPolicy);
|
||||||
|
curatorFramework.start();
|
||||||
|
ensureZkPaths(curatorFramework, zkPaths);
|
||||||
|
|
||||||
int nettyThreads = Math.max(1,
|
int nettyThreads = Math.max(1,
|
||||||
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
|
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
|
||||||
dataStore = DataStoreFactory.create(config, nettyThreads);
|
dataStore = DataStoreFactory.create(config, nettyThreads);
|
||||||
if (config.getCache().isEnabled()) {
|
if (config.getCache().isEnabled()) {
|
||||||
dataStoreCache = new DataStoreCache(config);
|
dataStoreCache = new DataStoreCache(curatorFramework, config);
|
||||||
dataStoreCache.setInternalMetrics(dataStore.getInternalMetrics());
|
dataStoreCache.setInternalMetrics(dataStore.getInternalMetrics());
|
||||||
dataStore.setCache(dataStoreCache);
|
dataStore.setCache(dataStoreCache);
|
||||||
}
|
}
|
||||||
// Initialize the MetaCache
|
// Initialize the MetaCache
|
||||||
MetaCacheFactory.getCache(config);
|
MetaCacheFactory.getCache(config);
|
||||||
// initialize the auth cache
|
// initialize the auth cache
|
||||||
AuthCache.setSessionMaxAge(config);
|
AuthCache.configure(config.getSecurity());
|
||||||
// Initialize the VisibilityCache
|
// Initialize the VisibilityCache
|
||||||
VisibilityCache.init(config);
|
VisibilityCache.init(config);
|
||||||
final boolean useEpoll = useEpoll();
|
final boolean useEpoll = useEpoll();
|
||||||
@@ -480,10 +550,9 @@ public class Server {
|
|||||||
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||||
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||||
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
||||||
/* Not sure if next three lines are necessary */
|
/* Not sure if next two lines are necessary */
|
||||||
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
||||||
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
|
wsServer.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(620145, 838860));
|
||||||
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
|
|
||||||
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
||||||
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||||
|
|
||||||
@@ -500,7 +569,7 @@ public class Server {
|
|||||||
udpServer.option(EpollChannelOption.SO_REUSEPORT, true);
|
udpServer.option(EpollChannelOption.SO_REUSEPORT, true);
|
||||||
udpChannelHandleList.add(udpServer.bind(udpIp, udpPort).sync().channel());
|
udpChannelHandleList.add(udpServer.bind(udpIp, udpPort).sync().channel());
|
||||||
}
|
}
|
||||||
registerService();
|
registerService(curatorFramework);
|
||||||
shutdownHook();
|
shutdownHook();
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Server started. Listening on {}:{} for TCP traffic, {}:{} for HTTP traffic, {}:{} for WebSocket traffic, and {}:{} for UDP traffic",
|
"Server started. Listening on {}:{} for TCP traffic, {}:{} for HTTP traffic, {}:{} for WebSocket traffic, and {}:{} for UDP traffic",
|
||||||
@@ -515,7 +584,7 @@ public class Server {
|
|||||||
if (generate) {
|
if (generate) {
|
||||||
LOG.warn("Using generated self signed server certificate");
|
LOG.warn("Using generated self signed server certificate");
|
||||||
Date begin = new Date();
|
Date begin = new Date();
|
||||||
Date end = new Date(begin.getTime() + 86400000);
|
Date end = new Date(begin.getTime() + TimeUnit.DAYS.toMillis(7));
|
||||||
SelfSignedCertificate ssc = new SelfSignedCertificate("localhost", begin, end);
|
SelfSignedCertificate ssc = new SelfSignedCertificate("localhost", begin, end);
|
||||||
ssl = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey());
|
ssl = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey());
|
||||||
} else {
|
} else {
|
||||||
@@ -560,14 +629,14 @@ public class Server {
|
|||||||
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
|
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
|
||||||
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
||||||
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
||||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
|
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
||||||
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
||||||
final Cors corsCfg = config.getHttp().getCors();
|
final Cors corsCfg = config.getHttp().getCors();
|
||||||
final CorsConfig.Builder ccb;
|
final CorsConfigBuilder ccb;
|
||||||
if (corsCfg.isAllowAnyOrigin()) {
|
if (corsCfg.isAllowAnyOrigin()) {
|
||||||
ccb = new CorsConfig.Builder();
|
ccb = CorsConfigBuilder.forAnyOrigin();
|
||||||
} else {
|
} else {
|
||||||
ccb = new CorsConfig.Builder(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
|
ccb = CorsConfigBuilder.forOrigins(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
|
||||||
}
|
}
|
||||||
if (corsCfg.isAllowNullOrigin()) {
|
if (corsCfg.isAllowNullOrigin()) {
|
||||||
ccb.allowNullOrigin();
|
ccb.allowNullOrigin();
|
||||||
@@ -582,7 +651,8 @@ public class Server {
|
|||||||
ch.pipeline().addLast("cors", new CorsHandler(cors));
|
ch.pipeline().addLast("cors", new CorsHandler(cors));
|
||||||
ch.pipeline().addLast("queryDecoder",
|
ch.pipeline().addLast("queryDecoder",
|
||||||
new timely.netty.http.HttpRequestDecoder(config.getSecurity(), config.getHttp()));
|
new timely.netty.http.HttpRequestDecoder(config.getSecurity(), config.getHttp()));
|
||||||
ch.pipeline().addLast("fileServer", new HttpStaticFileServerHandler());
|
ch.pipeline().addLast("fileServer", new HttpStaticFileServerHandler()
|
||||||
|
.setIgnoreSslHandshakeErrors(config.getSecurity().getServerSsl().isUseGeneratedKeypair()));
|
||||||
ch.pipeline().addLast("strict", new StrictTransportHandler(config));
|
ch.pipeline().addLast("strict", new StrictTransportHandler(config));
|
||||||
ch.pipeline().addLast("login", new X509LoginRequestHandler(config.getSecurity(), config.getHttp()));
|
ch.pipeline().addLast("login", new X509LoginRequestHandler(config.getSecurity(), config.getHttp()));
|
||||||
ch.pipeline().addLast("doLogin",
|
ch.pipeline().addLast("doLogin",
|
||||||
@@ -595,7 +665,9 @@ public class Server {
|
|||||||
ch.pipeline().addLast("version", new HttpVersionRequestHandler());
|
ch.pipeline().addLast("version", new HttpVersionRequestHandler());
|
||||||
ch.pipeline().addLast("cache", new HttpCacheRequestHandler(dataStoreCache));
|
ch.pipeline().addLast("cache", new HttpCacheRequestHandler(dataStoreCache));
|
||||||
ch.pipeline().addLast("put", new HttpMetricPutHandler(dataStore));
|
ch.pipeline().addLast("put", new HttpMetricPutHandler(dataStore));
|
||||||
ch.pipeline().addLast("error", new TimelyExceptionHandler());
|
ch.pipeline().addLast("error", new TimelyExceptionHandler()
|
||||||
|
.setIgnoreSslHandshakeErrors(config.getSecurity().getServerSsl().isUseGeneratedKeypair()));
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -608,7 +680,7 @@ public class Server {
|
|||||||
ch.pipeline().addLast("logger", new LoggingHandler());
|
ch.pipeline().addLast("logger", new LoggingHandler());
|
||||||
ch.pipeline().addLast("packetDecoder", new UdpPacketToByteBuf());
|
ch.pipeline().addLast("packetDecoder", new UdpPacketToByteBuf());
|
||||||
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
||||||
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
|
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
|
||||||
ch.pipeline().addLast("putDecoder", new UdpDecoder());
|
ch.pipeline().addLast("putDecoder", new UdpDecoder());
|
||||||
ch.pipeline().addLast("putHandler", new TcpPutHandler(dataStore));
|
ch.pipeline().addLast("putHandler", new TcpPutHandler(dataStore));
|
||||||
}
|
}
|
||||||
@@ -621,7 +693,7 @@ public class Server {
|
|||||||
@Override
|
@Override
|
||||||
protected void initChannel(SocketChannel ch) throws Exception {
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
|
||||||
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
|
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
|
||||||
ch.pipeline().addLast("putDecoder", new TcpDecoder());
|
ch.pipeline().addLast("putDecoder", new TcpDecoder());
|
||||||
ch.pipeline().addLast("putHandler", new TcpPutHandler(dataStore));
|
ch.pipeline().addLast("putHandler", new TcpPutHandler(dataStore));
|
||||||
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
|
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
|
||||||
@@ -636,11 +708,11 @@ public class Server {
|
|||||||
protected void initChannel(SocketChannel ch) throws Exception {
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
||||||
ch.pipeline().addLast("httpServer", new HttpServerCodec());
|
ch.pipeline().addLast("httpServer", new HttpServerCodec());
|
||||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
|
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
||||||
ch.pipeline().addLast("sessionExtractor", new WebSocketHttpCookieHandler(config.getSecurity()));
|
ch.pipeline().addLast("sessionExtractor", new WebSocketFullRequestHandler());
|
||||||
ch.pipeline().addLast("idle-handler", new IdleStateHandler(conf.getWebsocket().getTimeout(), 0, 0));
|
ch.pipeline().addLast("idle-handler", new IdleStateHandler(conf.getWebsocket().getTimeout(), 0, 0));
|
||||||
ch.pipeline().addLast("ws-protocol",
|
ch.pipeline().addLast("ws-protocol",
|
||||||
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, true));
|
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, false, true));
|
||||||
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(config.getSecurity()));
|
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(config.getSecurity()));
|
||||||
ch.pipeline().addLast("aggregators", new WSAggregatorsRequestHandler());
|
ch.pipeline().addLast("aggregators", new WSAggregatorsRequestHandler());
|
||||||
ch.pipeline().addLast("metrics", new WSMetricsRequestHandler(config));
|
ch.pipeline().addLast("metrics", new WSMetricsRequestHandler(config));
|
||||||
@@ -649,7 +721,8 @@ public class Server {
|
|||||||
ch.pipeline().addLast("suggest", new WSSuggestRequestHandler(dataStore));
|
ch.pipeline().addLast("suggest", new WSSuggestRequestHandler(dataStore));
|
||||||
ch.pipeline().addLast("version", new WSVersionRequestHandler());
|
ch.pipeline().addLast("version", new WSVersionRequestHandler());
|
||||||
ch.pipeline().addLast("put", new WSMetricPutHandler(dataStore));
|
ch.pipeline().addLast("put", new WSMetricPutHandler(dataStore));
|
||||||
ch.pipeline().addLast("create", new WSCreateSubscriptionRequestHandler(dataStore, config));
|
ch.pipeline().addLast("create",
|
||||||
|
new WSCreateSubscriptionRequestHandler(dataStore, dataStoreCache, config));
|
||||||
ch.pipeline().addLast("add", new WSAddSubscriptionRequestHandler());
|
ch.pipeline().addLast("add", new WSAddSubscriptionRequestHandler());
|
||||||
ch.pipeline().addLast("remove", new WSRemoveSubscriptionRequestHandler());
|
ch.pipeline().addLast("remove", new WSRemoveSubscriptionRequestHandler());
|
||||||
ch.pipeline().addLast("close", new WSCloseSubscriptionRequestHandler());
|
ch.pipeline().addLast("close", new WSCloseSubscriptionRequestHandler());
|
||||||
|
|||||||
Loaded 100 of 231 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user