Compare commits

..
1 Commits
162 changed files with 1714 additions and 4329 deletions

No files matched your search

+2 -3
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>timely-analytics</artifactId>
<!--
@@ -68,7 +68,6 @@
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerId>jdt</compilerId>
@@ -77,7 +76,7 @@
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-compiler-jdt</artifactId>
<version>1.4.0</version>
<version>0.21.0</version>
</dependency>
</dependencies>
</plugin>
@@ -67,7 +67,7 @@ public class SummarizationJob {
})
.name("Metric Windows")
.addSink(
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
new MetricHistogram(), 2, true) {
private final Logger LOG = LoggerFactory
+4 -3
View File
@@ -27,14 +27,15 @@ 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}
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative*.jar META-INF/native/libnetty_tcnative.${TCNATIVE_SUFFIX}
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-transport-native-epoll*.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="-Xmx1G -Xms1G -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS}"
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}/libnetty-${TCNATIVE_SUFFIX}"
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
+2 -5
View File
@@ -46,12 +46,9 @@
<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: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">
-3
View File
@@ -8,8 +8,6 @@ timely-balancer:
assignmentFile: /timely/balancer/assignments.csv
security:
session-max-age: 86400
cache-expiration-minutes: 60
cache-refresh-minutes: 5
allow-anonymous-http-access: true
allow-anonymous-ws-access: true
serverSsl:
@@ -111,7 +109,6 @@ timely-balancer:
flush-interval-seconds: 30
scanner-read-ahead: 1
subscription-batch-size: 5000
incomingBufferSize: 50000000
wsClientPool:
minIdlePerKey: 0
maxIdlePerKey: 40
+39 -3
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>timely-balancer</artifactId>
<dependencies>
@@ -161,7 +161,9 @@
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<artifactId>netty-tcnative</artifactId>
<version>${version.netty-tcnative}</version>
<classifier>${os.detected.classifier}</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
@@ -245,8 +247,9 @@
<artifactItems>
<artifactItem>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<artifactId>netty-tcnative</artifactId>
<version>${version.netty-tcnative}</version>
<classifier>${os.detected.classifier}</classifier>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/native</outputDirectory>
@@ -288,4 +291,37 @@
</extension>
</extensions>
</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>
@@ -25,7 +25,6 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
@@ -65,7 +64,6 @@ import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
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;
@@ -145,7 +143,7 @@ public class Balancer {
}
protected static ConfigurableApplicationContext initializeConfiguration(String[] args) {
return new SpringApplicationBuilder(SpringBootstrap.class).web(WebApplicationType.NONE).run(args);
return new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(args);
}
private void shutdownHook() {
@@ -365,7 +363,7 @@ public class Balancer {
curatorFramework.start();
ensureZkPaths(curatorFramework, zkPaths);
AuthCache.configure(balancerConfig.getSecurity());
AuthCache.setSessionMaxAge(balancerConfig.getSecurity());
final boolean useEpoll = useEpoll();
Class<? extends ServerSocketChannel> channelClass;
Class<? extends Channel> datagramChannelClass;
@@ -451,9 +449,10 @@ public class Balancer {
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
wsServer.option(ChannelOption.SO_BACKLOG, 128);
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
/* Not sure if next two lines are necessary */
/* Not sure if next three lines are necessary */
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
wsServer.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(620145, 838860));
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
@@ -511,7 +510,7 @@ public class Balancer {
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
ch.pipeline().addLast("compressor", new HttpContentCompressor());
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
ch.pipeline().addLast("queryDecoder", new timely.netty.http.HttpRequestDecoder(
balancerConfig.getSecurity(), balancerConfig.getHttp()));
@@ -532,7 +531,7 @@ public class Balancer {
ch.pipeline().addLast("logger", new LoggingHandler());
ch.pipeline().addLast("packetDecoder", new UdpPacketToByteBuf());
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("putDecoder", new UdpDecoder());
ch.pipeline().addLast("udpRelayHandler", new UdpRelayHandler(metricResolver, udpClientPool));
}
@@ -545,7 +544,7 @@ public class Balancer {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("putDecoder", new TcpDecoder());
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPools));
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
@@ -561,13 +560,13 @@ public class Balancer {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast("httpServer", new HttpServerCodec());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("sessionExtractor", new WebSocketFullRequestHandler());
ch.pipeline().addLast("idle-handler",
new IdleStateHandler(balancerConfig.getWebsocket().getTimeout(), 0, 0));
ch.pipeline().addLast("ws-protocol",
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, false, true));
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, true));
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(balancerConfig.getSecurity()));
ch.pipeline().addLast("httpRelay", new WsRelayHandler(balancerConfig, metricResolver, wsClientPool));
ch.pipeline().addLast("error", new WSTimelyExceptionHandler());
@@ -5,10 +5,8 @@ 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.configuration.Cache;
@Validated
@Component
@ConfigurationProperties(prefix = "timely-balancer")
public class BalancerConfiguration {
@@ -3,7 +3,6 @@ package timely.balancer.configuration;
import javax.validation.Valid;
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import timely.configuration.Http;
@@ -11,9 +10,9 @@ public class BalancerHttp extends Http {
@Valid
@NestedConfigurationProperty
private GenericKeyedObjectPoolConfig<CloseableHttpClient> httpClientPool = new GenericKeyedObjectPoolConfig<>();
private GenericKeyedObjectPoolConfig httpClientPool = new GenericKeyedObjectPoolConfig();
public GenericKeyedObjectPoolConfig<CloseableHttpClient> getHttpClientPool() {
public GenericKeyedObjectPoolConfig getHttpClientPool() {
return httpClientPool;
}
}
@@ -4,29 +4,27 @@ import javax.validation.Valid;
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import timely.client.tcp.TcpClient;
import timely.client.udp.UdpClient;
import timely.configuration.Server;
public class BalancerServer extends Server {
@Valid
@NestedConfigurationProperty
private GenericKeyedObjectPoolConfig<UdpClient> udpClientPool = new GenericKeyedObjectPoolConfig<>();
private GenericKeyedObjectPoolConfig udpClientPool = new GenericKeyedObjectPoolConfig();
@Valid
@NestedConfigurationProperty
private GenericKeyedObjectPoolConfig<TcpClient> tcpClientPool = new GenericKeyedObjectPoolConfig<>();
private GenericKeyedObjectPoolConfig tcpClientPool = new GenericKeyedObjectPoolConfig();
private int numTcpPools = 1;
private int tcpBufferSize = -1;
public GenericKeyedObjectPoolConfig<UdpClient> getUdpClientPool() {
public GenericKeyedObjectPoolConfig getUdpClientPool() {
return udpClientPool;
}
public GenericKeyedObjectPoolConfig<TcpClient> getTcpClientPool() {
public GenericKeyedObjectPoolConfig getTcpClientPool() {
return tcpClientPool;
}
@@ -4,26 +4,15 @@ import javax.validation.Valid;
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
import timely.configuration.Websocket;
public class BalancerWebsocket extends Websocket {
@Valid
@NestedConfigurationProperty
private GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> wsClientPool = new GenericKeyedObjectPoolConfig<>();
private GenericKeyedObjectPoolConfig wsClientPool = new GenericKeyedObjectPoolConfig();
public GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> getWsClientPool() {
public GenericKeyedObjectPoolConfig getWsClientPool() {
return wsClientPool;
}
public int incomingBufferSize = 50000000;
public int getIncomingBufferSize() {
return incomingBufferSize;
}
public void setIncomingBufferSize(int incomingBufferSize) {
this.incomingBufferSize = incomingBufferSize;
}
}
@@ -5,6 +5,7 @@ import javax.net.ssl.SSLContext;
import org.apache.commons.pool2.KeyedPooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import timely.balancer.configuration.BalancerSecurity;
import timely.balancer.connection.TimelyBalancedHost;
@@ -21,8 +22,8 @@ public class HttpClientFactory implements KeyedPooledObjectFactory<TimelyBalance
@Override
public PooledObject<CloseableHttpClient> makeObject(TimelyBalancedHost k) throws Exception {
// disable cookie management because we are sharing connections
return new DefaultPooledObject<>(timely.client.http.HttpClient.get(this.sslContext, null,
BasicCookieStore cookieJar = new BasicCookieStore();
return new DefaultPooledObject<>(timely.client.http.HttpClient.get(this.sslContext, cookieJar,
security.getClientSsl().isHostVerificationEnabled(), security.getClientSsl().isUseClientCert()));
}
@@ -4,12 +4,16 @@ import javax.net.ssl.SSLContext;
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.balancer.configuration.BalancerHttp;
import timely.balancer.configuration.BalancerSecurity;
import timely.balancer.connection.TimelyBalancedHost;
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());
}
@@ -22,7 +22,7 @@ public class WsClientFactory implements KeyedPooledObjectFactory<TimelyBalancedH
@Override
public PooledObject<WebSocketSubscriptionClient> makeObject(TimelyBalancedHost k) throws Exception {
int bufferSize = balancerConfig.getWebsocket().getIncomingBufferSize();
int bufferSize = balancerConfig.getWebsocket().getSubscriptionBatchSize() * 500;
WebSocketSubscriptionClient client = new WebSocketSubscriptionClient(sslContext, k.getHost(), k.getHttpPort(),
k.getWsPort(), balancerConfig.getSecurity().getClientSsl().isUseClientCert(),
balancerConfig.isLoginRequired(), "", "",
@@ -1,6 +1,6 @@
package timely.balancer.netty.http;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import java.io.ByteArrayOutputStream;
import java.net.URLEncoder;
@@ -67,7 +67,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
try {
try {
request = msg.getHttpRequest();
String originalURI = request.uri();
String originalURI = request.getUri();
originalURI = encodeURI(originalURI);
String metric = null;
@@ -101,7 +101,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
List<Header> relayedHeaderList = new ArrayList<>();
for (Map.Entry<String, String> h : headers.entries()) {
if (!h.getKey().equals(CONTENT_LENGTH.toString())) {
if (!h.getKey().equals(CONTENT_LENGTH)) {
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
}
}
@@ -109,14 +109,14 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
relayedHeaderList.toArray(headerArray);
String relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
if (request.method().equals(HttpMethod.GET)) {
if (request.getMethod().equals(HttpMethod.GET)) {
HttpUriRequest relayedRequest = new HttpGet(relayURI);
if (headerArray.length > 0) {
relayedRequest.setHeaders(headerArray);
}
relayedResponse = client.execute(relayedRequest);
} else if (request.method().equals(HttpMethod.POST)) {
} else if (request.getMethod().equals(HttpMethod.POST)) {
HttpPost relayedRequest = new HttpPost(relayURI);
String content = request.content().toString(StandardCharsets.UTF_8);
@@ -170,7 +170,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
if (client != null && k != null) {
httpClientPool.returnObject(k, client);
} else {
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().getUri());
}
}
}
@@ -45,7 +45,7 @@ public class WsClientHandler extends ClientHandler {
Multimap<String, String> proxyRequestHeaders = HashMultimap.create();
ProxiedEntityUtils.addProxyHeaders(proxyRequestHeaders, token.getClientCert());
for (String s : proxyRequestHeaders.keySet()) {
headers.put(s, new ArrayList<>(proxyRequestHeaders.get(s)));
headers.put(s, new ArrayList(proxyRequestHeaders.get(s)));
}
}
@@ -53,7 +53,7 @@ public class WsClientHandler extends ClientHandler {
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)));
headers.put(s, new ArrayList(originalRequestHeaders.get(s)));
}
}
}
@@ -122,7 +122,8 @@ public class BalancedMetricResolver implements MetricResolver {
}
};
try (TreeCache assignmentTreeCache = new TreeCache(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH)) {
try {
TreeCache assignmentTreeCache = new TreeCache(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH);
assignmentTreeCache.getListenable().addListener(assignmentListener);
assignmentTreeCache.start();
} catch (Exception e) {
@@ -143,7 +144,8 @@ public class BalancedMetricResolver implements MetricResolver {
}
};
try (TreeCache nonCachedMetricsTreeCache = new TreeCache(curatorFramework, NON_CACHED_METRICS)) {
try {
TreeCache nonCachedMetricsTreeCache = new TreeCache(curatorFramework, NON_CACHED_METRICS);
nonCachedMetricsTreeCache.getListenable().addListener(nonCachedMetricsListener);
nonCachedMetricsTreeCache.start();
} catch (Exception e) {
@@ -199,10 +201,7 @@ public class BalancedMetricResolver implements MetricResolver {
Set<String> currentNonCachedMetricsDistributed = new TreeSet<>();
try {
boolean acquired = false;
while (!acquired) {
acquired = nonCachedMetricsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
}
nonCachedMetricsIPRWLock.readLock().acquire();
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
if (currentNonCachedMetricsDistributedBytes != null) {
try {
@@ -266,15 +265,15 @@ public class BalancedMetricResolver implements MetricResolver {
private void startServiceListener(CuratorFramework curatorFramework) {
try {
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
ServiceDiscovery discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
.basePath(SERVICE_DISCOVERY_PATH).build();
discovery.start();
Collection<ServiceInstance<ServerDetails>> instances = discovery.queryForInstances("timely-server");
Collection<ServiceInstance> instances = discovery.queryForInstances("timely-server");
balancerLock.writeLock().lock();
try {
for (ServiceInstance<ServerDetails> si : instances) {
ServerDetails pl = si.getPayload();
for (ServiceInstance si : instances) {
ServerDetails pl = (ServerDetails) si.getPayload();
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(), pl.getHttpPort(),
pl.getWsPort(), pl.getUdpPort());
LOG.info("adding service {} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}", si.getId(),
@@ -287,8 +286,7 @@ public class BalancedMetricResolver implements MetricResolver {
balancerLock.writeLock().unlock();
}
final ServiceCache<ServerDetails> serviceCache = discovery.serviceCacheBuilder().name("timely-server")
.build();
final ServiceCache serviceCache = discovery.serviceCacheBuilder().name("timely-server").build();
ServiceCacheListener listener = new ServiceCacheListener() {
@Override
@@ -296,9 +294,9 @@ public class BalancedMetricResolver implements MetricResolver {
boolean rebalanceNeeded = false;
balancerLock.writeLock().lock();
try {
List<ServiceInstance<ServerDetails>> instances = serviceCache.getInstances();
List<ServiceInstance> instances = serviceCache.getInstances();
Set<TimelyBalancedHost> availableHosts = new HashSet<>();
for (ServiceInstance<ServerDetails> si : instances) {
for (ServiceInstance si : instances) {
ServerDetails pl = (ServerDetails) si.getPayload();
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(),
pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort());
@@ -644,10 +642,7 @@ public class BalancedMetricResolver implements MetricResolver {
}
try {
boolean acquired = false;
while (!acquired) {
acquired = nonCachedMetricsIPRWLock.writeLock().acquire(60, TimeUnit.SECONDS);
}
nonCachedMetricsIPRWLock.writeLock().acquire();
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
Set<String> currentNonCachedMetricsIP;
if (currentNonCachedMetricsDistributedBytes == null) {
@@ -883,10 +878,7 @@ public class BalancedMetricResolver implements MetricResolver {
Map<String, TimelyBalancedHost> assignedMetricToHostMap = new TreeMap<>();
try {
boolean acquired = false;
while (!acquired) {
acquired = assignmentsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
}
assignmentsIPRWLock.readLock().acquire();
balancerLock.writeLock().lock();
Configuration configuration = new Configuration();
FileSystem fs = FileSystem.get(configuration);
@@ -955,10 +947,7 @@ public class BalancedMetricResolver implements MetricResolver {
CsvWriter writer = null;
try {
boolean acquired = false;
while (!acquired) {
acquired = assignmentsIPRWLock.writeLock().acquire(60, TimeUnit.SECONDS);
}
assignmentsIPRWLock.writeLock().acquire();
balancerLock.readLock().lock();
nonCachedMetricsLocalLock.readLock().lock();
try {
+2 -3
View File
@@ -4,13 +4,12 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>timely-client</artifactId>
<properties>
<!-- PEP 440 compliant version gets substituted into src/main/python/template/setup.py -->
<!-- use .dev0 instead of -SNAPSHOT -->
<python.client.version>1.2.5</python.client.version>
<python.client.version>1.1.1.dev0</python.client.version>
</properties>
<dependencies>
<dependency>
@@ -46,21 +46,15 @@ public class HttpClient {
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled,
boolean clientAuth) {
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
HostnameVerifier hostnameVerifier;
if (hostVerificationEnabled) {
hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
} else {
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);
}
HttpClientBuilder builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore)
.setDefaultRequestConfig(defaultRequestConfig).setSSLHostnameVerifier(hostnameVerifier);
if (clientAuth) {
SSLConnectionSocketFactory sslCSF = new SSLConnectionSocketFactory(ssl,
@@ -1,8 +1,7 @@
package timely.client.tcp;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import org.slf4j.Logger;
@@ -15,7 +14,7 @@ public class TcpClient implements AutoCloseable {
private final String host;
private final int port;
private Socket sock = null;
private BufferedWriter out = null;
private PrintWriter out = null;
private long connectTime = 0L;
private long backoff = 2000;
private int bufferSize = -1;
@@ -48,6 +47,7 @@ public class TcpClient implements AutoCloseable {
*
* @param metric
* newline terminated string representation of Timely metric
* @throws IOException
*/
public synchronized void write(String metric) throws IOException {
if (connect() != 0) {
@@ -60,7 +60,7 @@ public class TcpClient implements AutoCloseable {
}
}
public synchronized void flush() throws IOException {
public synchronized void flush() {
if (null != out) {
out.flush();
writesSinceFlush = 0;
@@ -94,12 +94,12 @@ public class TcpClient implements AutoCloseable {
}
private synchronized int connect() {
if (null == sock || !sock.isConnected()) {
if (null == sock || !sock.isConnected() || out.checkError()) {
if (System.currentTimeMillis() > (connectTime + backoff)) {
try {
connectTime = System.currentTimeMillis();
sock = new Socket(host, port);
out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
out = new PrintWriter(sock.getOutputStream(), false);
backoff = 2000;
LOG.trace("Connected to Timely at {}:{}", host, port);
} catch (IOException e) {
@@ -62,6 +62,7 @@ public interface ObjectSizeOf {
* ObjectSizeOf interface and if implemented on the object will use that.
* Otherwise it will do a simple navigation of the fields using reflection.
*
* @param o
* @return an approximation of the object size
*/
public static long getObjectSize(Object o, boolean useSizeInBytesMethod, boolean debug) {
@@ -77,6 +77,8 @@ public class Tag implements Comparable<Tag>, Serializable {
/**
* Joins key and value into key=value
*
* @return
*/
public String join() {
return tagParser.combine(this);
@@ -47,6 +47,7 @@ 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
* tags
*
* @param tags
* @return string representation
*/
public String combine(Map<String, String> tags) {
-5
View File
@@ -5,9 +5,4 @@
<Method name="connect" />
<Class name="timely.client.tcp.TcpClient"/>
</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>
@@ -47,9 +47,9 @@ public class SerializationTest {
testSerialization(remove);
}
@SuppressWarnings("unchecked")
private <T> void testSerialization(T o) throws Exception {
String ser = mapper.writeValueAsString(o);
@SuppressWarnings("unchecked")
T des = mapper.readValue(ser, (Class<T>) o.getClass());
Assert.assertEquals(o, des);
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>collectd-nsq-plugin</artifactId>
<dependencies>
@@ -10,7 +10,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.collectd.api.OConfigItem;
public class PooledCloseableHttpClientFactory implements PooledObjectFactory<CloseableHttpClient> {
public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
private int connectionRequestTimeout = 10000; // 10 seconds in milliseconds
private int connectTimeout = 30000; // 30 seconds in milliseconds
@@ -43,19 +43,19 @@ public class PooledCloseableHttpClientFactory implements PooledObjectFactory<Clo
}
@Override
public PooledObject<CloseableHttpClient> makeObject() throws Exception {
public PooledObject makeObject() throws Exception {
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout)
.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestConfig);
builder.setConnectionTimeToLive(connectionTimeToLive, TimeUnit.MILLISECONDS);
return new DefaultPooledObject<>(builder.build());
return new DefaultPooledObject(builder.build());
}
@Override
public void destroyObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
public void destroyObject(PooledObject pooledObject) throws Exception {
try {
pooledObject.getObject().close();
((CloseableHttpClient) pooledObject.getObject()).close();
} catch (Exception e) {
// do nothing
} finally {
@@ -65,17 +65,17 @@ public class PooledCloseableHttpClientFactory implements PooledObjectFactory<Clo
}
@Override
public boolean validateObject(PooledObject<CloseableHttpClient> pooledObject) {
public boolean validateObject(PooledObject pooledObject) {
return pooledObject.getObject() != null;
}
@Override
public void activateObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
public void activateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
@Override
public void passivateObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
public void passivateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
@@ -47,7 +47,6 @@ public class WriteNSQPlugin extends CollectDPluginParent
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
}
@Override
public int write(ValueList vl) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
@@ -111,17 +110,15 @@ public class WriteNSQPlugin extends CollectDPluginParent
}
}
@Override
public int shutdown() {
Collectd.logInfo("Shutting down connection to NSQ at " + host + ":" + port);
clientPool.close();
return 0;
}
@Override
public int config(OConfigItem config) {
super.config(config);
GenericObjectPoolConfig<CloseableHttpClient> poolConfig = new GenericObjectPoolConfig<>();
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
// use max size for maxTotal and maxIdle
// no need to activate or passivate
poolConfig.setMaxTotal(POOL_MAX_SIZE);
@@ -159,7 +156,7 @@ public class WriteNSQPlugin extends CollectDPluginParent
Collectd.logError("NSQ host, port, and topic must be configured");
return -1;
}
this.clientPool = new GenericObjectPool<>(pooledCloseableHttpClientFactory, poolConfig);
this.clientPool = new GenericObjectPool(pooledCloseableHttpClientFactory, poolConfig);
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
return 0;
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>collectd-plugin-parent</artifactId>
<dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>collectd-timely-plugin</artifactId>
<dependencies>
@@ -8,7 +8,7 @@ import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.collectd.api.Collectd;
import org.collectd.api.OConfigItem;
public class PooledSocketFactory implements PooledObjectFactory<Socket> {
public class PooledSocketFactory implements PooledObjectFactory {
private String host = null;
private int port = 0;
@@ -81,12 +81,12 @@ public class PooledSocketFactory implements PooledObjectFactory<Socket> {
}
@Override
public PooledObject<Socket> makeObject() throws Exception {
return new DefaultPooledObject<>(connect());
public PooledObject makeObject() throws Exception {
return new DefaultPooledObject(connect());
}
@Override
public void destroyObject(PooledObject<Socket> pooledObject) throws Exception {
public void destroyObject(PooledObject pooledObject) throws Exception {
try {
Collectd.logDebug("Shutting down connection to Timely at " + host + ":" + port);
Socket socket = (Socket) pooledObject.getObject();
@@ -103,7 +103,7 @@ public class PooledSocketFactory implements PooledObjectFactory<Socket> {
}
@Override
public boolean validateObject(PooledObject<Socket> pooledObject) {
public boolean validateObject(PooledObject pooledObject) {
if (connectionTimeToLive > -1) {
if (System.currentTimeMillis() > pooledObject.getCreateTime() + connectionTimeToLive) {
return false;
@@ -114,12 +114,12 @@ public class PooledSocketFactory implements PooledObjectFactory<Socket> {
}
@Override
public void activateObject(PooledObject<Socket> pooledObject) throws Exception {
public void activateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
@Override
public void passivateObject(PooledObject<Socket> pooledObject) throws Exception {
public void passivateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
}
@@ -86,13 +86,13 @@ public class WriteTimelyPlugin extends CollectDPluginParent
PooledSocketFactory socketFactory = new PooledSocketFactory();
retval = socketFactory.config(config);
if (retval == 0) {
GenericObjectPoolConfig<Socket> poolConfig = new GenericObjectPoolConfig<>();
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
// use max size for maxTotal and maxIdle
// no need to activate and passivate
poolConfig.setMaxTotal(POOL_MAX_SIZE);
poolConfig.setMaxIdle(POOL_MAX_SIZE);
poolConfig.setTestOnReturn(true);
socketPool = new GenericObjectPool<>(socketFactory, poolConfig);
socketPool = new GenericObjectPool(socketFactory, poolConfig);
}
return retval;
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>timely-common</artifactId>
<dependencies>
+4 -3
View File
@@ -27,14 +27,15 @@ 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}
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative*.jar META-INF/native/libnetty_tcnative.${TCNATIVE_SUFFIX}
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-transport-native-epoll*.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="-Xmx1G -Xms1G -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS}"
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}/libnetty-${TCNATIVE_SUFFIX}"
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
-2
View File
@@ -4,8 +4,6 @@ grafana-auth:
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:
+2 -5
View File
@@ -46,12 +46,9 @@
<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: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">
+39 -3
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>grafana-auth</artifactId>
<dependencies>
@@ -165,7 +165,9 @@
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<artifactId>netty-tcnative</artifactId>
<version>${version.netty-tcnative}</version>
<classifier>${os.detected.classifier}</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
@@ -249,8 +251,9 @@
<artifactItems>
<artifactItem>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<artifactId>netty-tcnative</artifactId>
<version>${version.netty-tcnative}</version>
<classifier>${os.detected.classifier}</classifier>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/native</outputDirectory>
@@ -292,4 +295,37 @@
</extension>
</extensions>
</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>
-1
View File
@@ -20,7 +20,6 @@
<outputDirectory>lib</outputDirectory>
<includes>
<include>timely*.jar</include>
<include>grafana*.jar</include>
</includes>
</fileSet>
<fileSet>
@@ -43,7 +43,6 @@ 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;
@@ -82,7 +81,7 @@ public class GrafanaAuth {
}
protected static ConfigurableApplicationContext initializeConfiguration(String[] args) {
return new SpringApplicationBuilder(SpringBootstrap.class).web(WebApplicationType.NONE).run(args);
return new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(args);
}
private void shutdownHook() {
@@ -226,7 +225,7 @@ public class GrafanaAuth {
public void run() throws Exception {
AuthCache.configure(grafanaAuthConfig.getSecurity());
AuthCache.setSessionMaxAge(grafanaAuthConfig.getSecurity());
final boolean useEpoll = useEpoll();
Class<? extends ServerSocketChannel> channelClass;
if (useEpoll) {
@@ -305,9 +304,7 @@ public class GrafanaAuth {
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("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
ch.pipeline().addLast("grafanaDecoder",
new GrafanaRequestDecoder(config.getSecurity(), config.getHttp()));
@@ -4,29 +4,12 @@ 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;
}
}
@@ -5,11 +5,9 @@ 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 {
@@ -24,7 +22,7 @@ public class GrafanaAuthConfiguration {
@Valid
@NestedConfigurationProperty
private Grafana grafana = new Grafana();
private Grafana grafana;
private Integer shutdownQuietPeriod = 5;
@@ -43,6 +41,8 @@ public class GrafanaAuthConfiguration {
/**
* Time to wait (in seconds) for connections to finish and to make sure no new
* connections happen before shutting down Netty event loop groups.
*
* @return
*/
public int getShutdownQuietPeriod() {
return this.shutdownQuietPeriod;
@@ -1,10 +1,9 @@
package timely.grafana.auth.netty.http;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.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;
@@ -16,20 +15,13 @@ 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.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.slf4j.Logger;
@@ -67,11 +59,10 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
FullHttpRequest request = null;
GrafanaRequest grafanaRequest;
TimelyBalancedHost k = null;
String relayURI = null;
try {
try {
request = msg.getHttpRequest();
String originalURI = request.uri();
String originalURI = request.getUri();
originalURI = encodeURI(originalURI);
if (msg instanceof GrafanaRequest) {
@@ -84,7 +75,6 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
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);
@@ -92,67 +82,32 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
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");
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);
int equalsIndex = subjectDn.indexOf('=');
int endIndex = subjectDn.lastIndexOf(' ');
String loginName = DnUtils.getShortName(subjectDn);
headers.put("x-webauth-user", loginName);
headers.put("x-webauth-name", userName);
String userName = equalsIndex > -1 ? subjectDn.substring(equalsIndex + 1, endIndex) : 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())) {
if (!h.getKey().equals(CONTENT_LENGTH)) {
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);
String relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
HttpUriRequest relayedRequest = new HttpGet(relayURI);
if (headerArray.length > 0) {
relayedRequest.setHeaders(headerArray);
}
relayedResponse = client.execute(relayedRequest);
} catch (Exception e) {
String message = e.getMessage();
if (message == null) {
@@ -174,22 +129,16 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
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());
}
ByteArrayOutputStream baos = new MyByteArrayOutputStream();
StreamUtils.copy(relayedResponse.getEntity().getContent(), baos);
response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.valueOf(relayedResponse.getStatusLine().getStatusCode()),
Unpooled.copiedBuffer(baos.toByteArray()));
for (Header h : relayedResponse.getAllHeaders()) {
response.headers().add(h.getName(), h.getValue());
}
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
} finally {
@@ -199,11 +148,15 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
if (client != null && k != null) {
httpClientPool.returnObject(k, client);
} else {
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().getUri());
}
}
}
private boolean userHasAccount(String username) {
return false;
}
static public class MyByteArrayOutputStream extends ByteArrayOutputStream {
public MyByteArrayOutputStream() {
@@ -8,7 +8,9 @@ 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.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import org.apache.commons.lang3.StringUtils;
@@ -47,7 +49,7 @@ public class GrafanaRequestDecoder extends MessageToMessageDecoder<FullHttpReque
public static String getSessionId(FullHttpRequest msg) {
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(msg.headers());
Collection<String> cookies = headers.get(HttpHeaderNames.COOKIE.toString());
Collection<String> cookies = headers.get(Names.COOKIE);
final StringBuilder buf = new StringBuilder();
cookies.forEach(h -> {
ServerCookieDecoder.STRICT.decode(h).forEach(c -> {
@@ -70,7 +72,7 @@ public class GrafanaRequestDecoder extends MessageToMessageDecoder<FullHttpReque
LOG.trace(LOG_RECEIVED_REQUEST, msg);
final String uri = msg.uri();
final String uri = msg.getUri();
final QueryStringDecoder decoder = new QueryStringDecoder(uri);
if (decoder.path().equals(nonSecureRedirectAddress)) {
out.add(new StrictTransportResponse());
@@ -82,7 +84,16 @@ public class GrafanaRequestDecoder extends MessageToMessageDecoder<FullHttpReque
HttpRequest request;
try {
request = new GrafanaRequest();
if (msg.getMethod().equals(HttpMethod.GET)) {
request = new GrafanaRequest();
} else {
TimelyException e = new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
"unhandled method type", "");
e.addResponseHeader(Names.ALLOW, HttpMethod.GET.name() + "," + HttpMethod.POST.name());
LOG.warn("Unhandled HTTP request type {}", msg.getMethod());
throw e;
}
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(msg.headers());
((AuthenticatedRequest) request).addHeaders(headers);
X509Certificate clientCert = AuthenticationService.getClientCertificate(ctx);
@@ -5,10 +5,9 @@ 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 {
public class GrafanaRequest extends AuthenticatedRequest implements HttpGetRequest {
private FullHttpRequest httpRequest = null;
@@ -17,11 +16,6 @@ public class GrafanaRequest extends AuthenticatedRequest implements HttpGetReque
return new GrafanaRequest();
}
@Override
public HttpPostRequest parseBody(String content) throws Exception {
return new GrafanaRequest();
}
public void setHttpRequest(FullHttpRequest httpRequest) {
this.httpRequest = httpRequest;
}
+15
View File
@@ -0,0 +1,15 @@
<?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">
<parent>
<artifactId>timely</artifactId>
<groupId>timely</groupId>
<version>1.1.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>grafana-authentication</artifactId>
</project>
@@ -0,0 +1,576 @@
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.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.Bootstrap;
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.EpollChannelOption;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
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.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
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.handler.timeout.IdleStateHandler;
import io.netty.util.NettyRuntime;
import io.netty.util.internal.SystemPropertyUtil;
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.LoggerFactory;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import timely.auth.AuthCache;
import timely.balancer.configuration.BalancerConfiguration;
import timely.balancer.configuration.ClientSsl;
import timely.balancer.configuration.SpringBootstrap;
import timely.balancer.connection.http.HttpClientPool;
import timely.balancer.connection.tcp.TcpClientPool;
import timely.balancer.connection.udp.UdpClientPool;
import timely.balancer.connection.ws.WsClientPool;
import timely.balancer.healthcheck.HealthChecker;
import timely.balancer.netty.http.HttpRelayHandler;
import timely.balancer.netty.tcp.TcpRelayHandler;
import timely.balancer.netty.udp.UdpRelayHandler;
import timely.balancer.netty.ws.WsRelayHandler;
import timely.balancer.resolver.BalancedMetricResolver;
import timely.balancer.resolver.MetricResolver;
import timely.client.http.HttpClient;
import timely.configuration.ServerSsl;
import timely.netty.http.HttpStaticFileServerHandler;
import timely.netty.http.NonSslRedirectHandler;
import timely.netty.http.TimelyExceptionHandler;
import timely.netty.http.auth.X509LoginRequestHandler;
import timely.netty.tcp.MetricsBufferDecoder;
import timely.netty.tcp.TcpDecoder;
import timely.netty.tcp.TcpVersionHandler;
import timely.netty.udp.UdpDecoder;
import timely.netty.udp.UdpPacketToByteBuf;
import timely.netty.websocket.WebSocketFullRequestHandler;
import timely.netty.websocket.WebSocketRequestDecoder;
import timely.netty.websocket.subscription.WSTimelyExceptionHandler;
public class Balancer {
final public static String LEADER_LATCH_PATH = "/timely/balancer/leader";
final public static String ASSIGNMENTS_LOCK_PATH = "/timely/balancer/assignments/lock";
final public static String ASSIGNMENTS_LAST_UPDATED_PATH = "/timely/balancer/assignments/lastUpdated";
private static final Logger LOG = LoggerFactory.getLogger(Balancer.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";
private static final String WS_PATH = "/websocket";
protected static final CountDownLatch LATCH = new CountDownLatch(1);
static ConfigurableApplicationContext applicationContext;
private final BalancerConfiguration balancerConfig;
private EventLoopGroup tcpWorkerGroup = null;
private EventLoopGroup tcpBossGroup = null;
private EventLoopGroup httpWorkerGroup = null;
private EventLoopGroup httpBossGroup = null;
private EventLoopGroup wsWorkerGroup = null;
private EventLoopGroup wsBossGroup = null;
private EventLoopGroup udpBossGroup = null;
private EventLoopGroup udpWorkerGroup = null;
private MetricResolver metricResolver;
protected Channel tcpChannelHandle = null;
protected Channel httpChannelHandle = null;
protected Channel wsChannelHandle = null;
protected List<Channel> udpChannelHandleList = new ArrayList<>();
private CuratorFramework curatorFramework;
protected volatile boolean shutdown = false;
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 {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1,
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
}
public Balancer(BalancerConfiguration balancerConf) throws Exception {
this.balancerConfig = balancerConf;
}
protected static ConfigurableApplicationContext initializeConfiguration(String[] args) {
return new SpringApplicationBuilder(SpringBootstrap.class).web(false).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 (tcpChannelHandle != null) {
LOG.info("Closing tcpChannelHandle");
channelFutures.add(tcpChannelHandle.close());
}
if (httpChannelHandle != null) {
LOG.info("Closing httpChannelHandle");
channelFutures.add(httpChannelHandle.close());
}
if (wsChannelHandle != null) {
LOG.info("Closing wsChannelHandle");
channelFutures.add(wsChannelHandle.close());
}
for (Channel c : udpChannelHandleList) {
LOG.info("Closing udpChannelHandle");
channelFutures.add(c.close());
}
// wait for the channels to shutdown
channelFutures.forEach(f -> {
try {
f.get();
} catch (final Exception e) {
LOG.error("Error while shutting down channel: {}", f.channel().config());
LOG.error("{}", e.getMessage());
e.printStackTrace();
}
});
Integer quietPeriod = balancerConfig.getServer().getShutdownQuietPeriod();
List<Future<?>> groupFutures = new ArrayList<>();
if (tcpBossGroup != null) {
LOG.info("Shutting down tcpBossGroup");
groupFutures.add(tcpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
}
if (tcpWorkerGroup != null) {
LOG.info("Shutting down tcpWorkerGroup");
groupFutures.add(tcpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
}
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));
}
if (wsBossGroup != null) {
LOG.info("Shutting down wsBossGroup");
groupFutures.add(wsBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
}
if (wsWorkerGroup != null) {
LOG.info("Shutting down wsWorkerGroup");
groupFutures.add(wsWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
}
if (udpBossGroup != null) {
LOG.info("Shutting down udpBossGroup");
groupFutures.add(udpBossGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
}
if (udpWorkerGroup != null) {
LOG.info("Shutting down udpWorkerGroup");
groupFutures.add(udpWorkerGroup.shutdownGracefully(quietPeriod, 10, TimeUnit.SECONDS));
}
groupFutures.parallelStream().forEach(f -> {
try {
f.get();
} catch (final Exception e) {
LOG.error("Error while shutting down group: {}", f.toString());
LOG.error("{}", e.getMessage());
e.printStackTrace();
}
});
try {
LOG.info("Closing WebSocketRequestDecoder");
WebSocketRequestDecoder.close();
} catch (Exception e) {
LOG.error("Error closing WebSocketRequestDecoder during shutdown", e);
}
if (applicationContext != null) {
LOG.info("Closing applicationContext");
applicationContext.close();
}
if (curatorFramework != null) {
curatorFramework.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(BalancerConfiguration 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(BalancerConfiguration config) throws Exception {
ClientSsl ssl = config.getSecurity().getClientSsl();
return HttpClient.getSSLContext(ssl.getTrustStoreFile(), ssl.getTrustStoreType(), ssl.getTrustStorePassword(),
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 {
// start curator framework
RetryPolicy retryPolicy = new RetryForever(1000);
curatorFramework = CuratorFrameworkFactory.newClient(balancerConfig.getZooKeeper().getServers(), 30000, 1000,
retryPolicy);
curatorFramework.start();
ensureZkPaths(curatorFramework, zkPaths);
AuthCache.setSessionMaxAge(balancerConfig.getSecurity());
final boolean useEpoll = useEpoll();
Class<? extends ServerSocketChannel> channelClass;
Class<? extends Channel> datagramChannelClass;
if (useEpoll) {
tcpWorkerGroup = new EpollEventLoopGroup();
tcpBossGroup = new EpollEventLoopGroup();
httpWorkerGroup = new EpollEventLoopGroup();
httpBossGroup = new EpollEventLoopGroup();
wsWorkerGroup = new EpollEventLoopGroup();
wsBossGroup = new EpollEventLoopGroup();
udpWorkerGroup = new EpollEventLoopGroup();
udpBossGroup = new EpollEventLoopGroup();
channelClass = EpollServerSocketChannel.class;
datagramChannelClass = EpollDatagramChannel.class;
} else {
tcpWorkerGroup = new NioEventLoopGroup();
tcpBossGroup = new NioEventLoopGroup();
httpWorkerGroup = new NioEventLoopGroup();
httpBossGroup = new NioEventLoopGroup();
wsWorkerGroup = new NioEventLoopGroup();
wsBossGroup = new NioEventLoopGroup();
udpWorkerGroup = new NioEventLoopGroup();
udpBossGroup = new NioEventLoopGroup();
channelClass = NioServerSocketChannel.class;
datagramChannelClass = NioDatagramChannel.class;
}
LOG.info("Using channel class {}", channelClass.getSimpleName());
List<TcpClientPool> tcpClientPools = new ArrayList<>();
for (int x = 0; x < balancerConfig.getServer().getNumTcpPools(); x++) {
tcpClientPools.add(new TcpClientPool(this.balancerConfig));
}
HealthChecker healthChecker = new HealthChecker(this.balancerConfig, tcpClientPools.get(0));
this.metricResolver = new BalancedMetricResolver(curatorFramework, this.balancerConfig, healthChecker);
final ServerBootstrap tcpServer = new ServerBootstrap();
tcpServer.group(tcpBossGroup, tcpWorkerGroup);
tcpServer.channel(channelClass);
tcpServer.handler(new LoggingHandler());
tcpServer.childHandler(setupTcpChannel(metricResolver, tcpClientPools));
tcpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
tcpServer.option(ChannelOption.SO_BACKLOG, 128);
tcpServer.option(ChannelOption.SO_KEEPALIVE, true);
final int tcpPort = balancerConfig.getServer().getTcpPort();
final String tcpIp = balancerConfig.getServer().getIp();
tcpChannelHandle = tcpServer.bind(tcpIp, tcpPort).sync().channel();
final String tcpAddress = ((InetSocketAddress) tcpChannelHandle.localAddress()).getAddress().getHostAddress();
final int httpPort = balancerConfig.getHttp().getPort();
final String httpIp = balancerConfig.getHttp().getIp();
SslContext sslCtx = createSSLContext(balancerConfig);
if (sslCtx instanceof OpenSslServerContext) {
OpenSslServerContext openssl = (OpenSslServerContext) sslCtx;
String application = "Timely_" + httpPort;
OpenSslServerSessionContext opensslCtx = openssl.sessionContext();
opensslCtx.setSessionCacheEnabled(true);
opensslCtx.setSessionCacheSize(128);
opensslCtx.setSessionIdContext(application.getBytes(StandardCharsets.UTF_8));
opensslCtx.setSessionTimeout(balancerConfig.getSecurity().getSessionMaxAge());
}
SSLContext clientSSLContext = createSSLClientContext(balancerConfig);
final ServerBootstrap httpServer = new ServerBootstrap();
httpServer.group(httpBossGroup, httpWorkerGroup);
httpServer.channel(channelClass);
httpServer.handler(new LoggingHandler());
HttpClientPool httpClientPool = new HttpClientPool(balancerConfig, clientSSLContext);
httpServer.childHandler(setupHttpChannel(balancerConfig, sslCtx, metricResolver, 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();
final int wsPort = balancerConfig.getWebsocket().getPort();
final String wsIp = balancerConfig.getWebsocket().getIp();
final ServerBootstrap wsServer = new ServerBootstrap();
wsServer.group(wsBossGroup, wsWorkerGroup);
wsServer.channel(channelClass);
wsServer.handler(new LoggingHandler());
WsClientPool wsClientPool = new WsClientPool(balancerConfig, clientSSLContext);
wsServer.childHandler(setupWSChannel(balancerConfig, sslCtx, metricResolver, wsClientPool));
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
wsServer.option(ChannelOption.SO_BACKLOG, 128);
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
/* Not sure if next three lines are necessary */
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
final int udpPort = balancerConfig.getServer().getUdpPort();
final String udpIp = balancerConfig.getServer().getIp();
UdpClientPool udpClientPool = new UdpClientPool(balancerConfig);
for (int n = 1; n < DEFAULT_EVENT_LOOP_THREADS; n++) {
final Bootstrap udpServer = new Bootstrap();
udpServer.group(udpBossGroup);
udpServer.channel(datagramChannelClass);
udpServer.handler(setupUdpChannel(metricResolver, udpClientPool));
udpServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
udpServer.option(EpollChannelOption.SO_REUSEADDR, true);
udpServer.option(EpollChannelOption.SO_REUSEPORT, true);
udpChannelHandleList.add(udpServer.bind(udpIp, udpPort).sync().channel());
}
shutdownHook();
LOG.info(
"Server started. Listening on {}:{} for TCP traffic, {}:{} for HTTP traffic, {}:{} for WebSocket traffic, and {}:{} for UDP traffic",
tcpAddress, tcpPort, httpAddress, httpPort, wsAddress, wsPort, wsAddress, udpPort);
}
public static void main(String[] args) throws Exception {
Balancer.applicationContext = Balancer.initializeConfiguration(args);
BalancerConfiguration balancerConf = applicationContext.getBean(BalancerConfiguration.class);
Balancer b = new Balancer(balancerConf);
try {
b.run();
LATCH.await();
} catch (final InterruptedException e) {
LOG.info("Server shutting down.");
} catch (Exception e) {
LOG.error("Error running server.", e);
} finally {
try {
b.shutdown();
} catch (Exception e) {
System.exit(1);
}
}
}
protected ChannelHandler setupHttpChannel(BalancerConfiguration balancerConfig, SslContext sslCtx,
MetricResolver metricResolver, HttpClientPool httpClientPool) {
return new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("ssl", new NonSslRedirectHandler(balancerConfig.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());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
ch.pipeline().addLast("queryDecoder", new timely.netty.http.HttpRequestDecoder(
balancerConfig.getSecurity(), balancerConfig.getHttp()));
ch.pipeline().addLast("fileServer", new HttpStaticFileServerHandler());
ch.pipeline().addLast("login",
new X509LoginRequestHandler(balancerConfig.getSecurity(), balancerConfig.getHttp()));
ch.pipeline().addLast("httpRelay",
new HttpRelayHandler(balancerConfig, metricResolver, httpClientPool));
ch.pipeline().addLast("error", new TimelyExceptionHandler());
}
};
}
protected ChannelHandler setupUdpChannel(MetricResolver metricResolver, UdpClientPool udpClientPool) {
return new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel ch) throws Exception {
ch.pipeline().addLast("logger", new LoggingHandler());
ch.pipeline().addLast("packetDecoder", new UdpPacketToByteBuf());
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("putDecoder", new UdpDecoder());
ch.pipeline().addLast("udpRelayHandler", new UdpRelayHandler(metricResolver, udpClientPool));
}
};
}
protected ChannelHandler setupTcpChannel(MetricResolver metricResolver, List<TcpClientPool> tcpClientPools) {
return new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("putDecoder", new TcpDecoder());
ch.pipeline().addLast("tcpRelayHandler", new TcpRelayHandler(metricResolver, tcpClientPools));
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
}
};
}
protected ChannelHandler setupWSChannel(BalancerConfiguration balancerConfig, SslContext sslCtx,
MetricResolver metricResolver, WsClientPool wsClientPool) {
return new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast("httpServer", new HttpServerCodec());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("sessionExtractor", new WebSocketFullRequestHandler());
ch.pipeline().addLast("idle-handler",
new IdleStateHandler(balancerConfig.getWebsocket().getTimeout(), 0, 0));
ch.pipeline().addLast("ws-protocol",
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, true));
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(balancerConfig.getSecurity()));
ch.pipeline().addLast("httpRelay", new WsRelayHandler(balancerConfig, metricResolver, wsClientPool));
ch.pipeline().addLast("error", new WSTimelyExceptionHandler());
}
};
}
}
@@ -0,0 +1,121 @@
package timely.balancer.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 timely.configuration.Cache;
@Component
@ConfigurationProperties(prefix = "timely-balancer")
public class BalancerConfiguration {
@Valid
@NestedConfigurationProperty
private BalancerServer server = new BalancerServer();
@Valid
@NestedConfigurationProperty
private BalancerHttp http = new BalancerHttp();
@Valid
@NestedConfigurationProperty
private BalancerWebsocket websocket = new BalancerWebsocket();
@Valid
@NestedConfigurationProperty
private ZooKeeper zooKeeper = new ZooKeeper();
@Valid
@NestedConfigurationProperty
private BalancerSecurity security = new BalancerSecurity();
@Valid
@NestedConfigurationProperty
private Cache cache = new Cache();
private boolean loginRequired = false;
private String assignmentFile;
private Double controlBandPercentage = 0.05;
private long checkServerHealthInterval = 10000;
private int serverFailuresBeforeDown = 3;
private int serverSuccessesBeforeUp = 3;
public ZooKeeper getZooKeeper() {
return zooKeeper;
}
public void setLoginRequired(boolean loginRequired) {
this.loginRequired = loginRequired;
}
public boolean isLoginRequired() {
return loginRequired;
}
public String getAssignmentFile() {
return assignmentFile;
}
public void setAssignmentFile(String assignmentFile) {
this.assignmentFile = assignmentFile;
}
public void setControlBandPercentage(Double controlBandPercentage) {
this.controlBandPercentage = controlBandPercentage;
}
public Double getControlBandPercentage() {
return controlBandPercentage;
}
public BalancerSecurity getSecurity() {
return security;
}
public BalancerServer getServer() {
return server;
}
public BalancerHttp getHttp() {
return http;
}
public BalancerWebsocket getWebsocket() {
return websocket;
}
public Cache getCache() {
return cache;
}
public void setCheckServerHealthInterval(long checkServerHealthInterval) {
this.checkServerHealthInterval = checkServerHealthInterval;
}
public long getCheckServerHealthInterval() {
return checkServerHealthInterval;
}
public int getServerFailuresBeforeDown() {
return serverFailuresBeforeDown;
}
public void setServerFailuresBeforeDown(int serverFailuresBeforeDown) {
this.serverFailuresBeforeDown = serverFailuresBeforeDown;
}
public int getServerSuccessesBeforeUp() {
return serverSuccessesBeforeUp;
}
public void setServerSuccessesBeforeUp(int serverSuccessesBeforeUp) {
this.serverSuccessesBeforeUp = serverSuccessesBeforeUp;
}
}
@@ -0,0 +1,7 @@
package timely.balancer.configuration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackageClasses = { SpringBootstrap.class })
public class SpringBootstrap {
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>timely-app</artifactId>
<packaging>pom</packaging>
+2 -2
View File
@@ -23,8 +23,8 @@
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
],
"version": "1.2.5",
"updated": "2019-08-22"
"version": "1.1.0",
"updated": "2019-01-15"
},
"includes": [
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "timely-app",
"private": true,
"version": "1.2.5",
"version": "1.1.0",
"description": "",
"main": "index.js",
"scripts": {
+2 -2
View File
@@ -23,8 +23,8 @@
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
],
"version": "1.2.5",
"updated": "2019-08-22"
"version": "1.1.0",
"updated": "2019-01-15"
},
"includes": [
+42 -71
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Timely</name>
<description>A secure and scalable time series database based on Apache Accumulo</description>
@@ -41,50 +41,50 @@
<os.detection.classifierWithLikes>fedora</os.detection.classifierWithLikes>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<version.accumulo>1.9.3</version.accumulo>
<version.accumulo>1.9.2</version.accumulo>
<version.buildnumber-maven>1.4</version.buildnumber-maven>
<version.caffeine>2.6.2</version.caffeine>
<version.caffeine>2.3.3</version.caffeine>
<version.collectd>5.7.1</version.collectd>
<version.commons-collections4>4.3</version.commons-collections4>
<version.commons-lang3>3.8.1</version.commons-lang3>
<version.commons-pool2>2.6.1</version.commons-pool2>
<version.curator>4.1.0</version.curator>
<version.disruptor>3.4.2</version.disruptor>
<version.easymock>4.0.2</version.easymock>
<version.commons-collections4>4.1</version.commons-collections4>
<version.commons-configuration>1.10</version.commons-configuration>
<version.commons-io>2.6</version.commons-io>
<version.commons-lang3>3.5</version.commons-lang3>
<version.commons-pool2>2.6.0</version.commons-pool2>
<version.curator>2.11.1</version.curator>
<version.disruptor>3.3.6</version.disruptor>
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
<version.fast-classpath-scanner>3.1.13</version.fast-classpath-scanner>
<version.fast-classpath-scanner>2.0.5</version.fast-classpath-scanner>
<version.flink>1.1.4</version.flink>
<version.google-flatbuffers>1.10.0</version.google-flatbuffers>
<version.guava>27.1-jre</version.guava>
<version.hadoop>2.7.7</version.hadoop>
<version.httpcomponents>4.5.6</version.httpcomponents>
<version.impsort>1.3.0</version.impsort>
<version.jackson>2.9.9</version.jackson>
<version.jackson.databind>2.9.9.3</version.jackson.databind>
<version.jacoco>0.8.4</version.jacoco>
<version.guava>19.0</version.guava>
<version.hadoop>2.7.3</version.hadoop>
<version.httpcomponents>4.5.2</version.httpcomponents>
<version.impsort>1.2.0</version.impsort>
<version.jackson>2.9.8</version.jackson>
<version.jacoco>0.7.6.201602180812</version.jacoco>
<version.javacsv>2.0</version.javacsv>
<version.javassist>3.24.1-GA</version.javassist>
<version.javassist>3.21.0-GA</version.javassist>
<version.jcip-annotations>1.0</version.jcip-annotations>
<version.jsoup>1.11.3</version.jsoup>
<version.jsoup>1.9.2</version.jsoup>
<version.junit>4.12</version.junit>
<version.log4j>2.11.2</version.log4j>
<version.maven-assembly>3.1.1</version.maven-assembly>
<version.maven-build-helper>3.0.0</version.maven-build-helper>
<version.maven-compiler>3.8.1</version.maven-compiler>
<version.maven-dependency>3.1.1</version.maven-dependency>
<version.maven-jar>3.1.2</version.maven-jar>
<version.maven-pmd>3.12.0</version.maven-pmd>
<version.maven-rpm>2.2.0</version.maven-rpm>
<version.maven-shade>3.2.1</version.maven-shade>
<version.maven-surefire>3.0.0-M3</version.maven-surefire>
<version.netty>4.1.35.Final</version.netty>
<version.netty-tcnative>2.0.25.Final</version.netty-tcnative>
<version.log4j>2.6.2</version.log4j>
<version.maven-assembly>2.6</version.maven-assembly>
<version.maven-build-helper>1.12</version.maven-build-helper>
<version.maven-compiler>3.3</version.maven-compiler>
<version.maven-dependency>2.10</version.maven-dependency>
<version.maven-jar>3.0.1</version.maven-jar>
<version.maven-pmd>3.6</version.maven-pmd>
<version.maven-rpm>2.1.4</version.maven-rpm>
<version.maven-shade>2.4.2</version.maven-shade>
<version.maven-surefire>2.19.1</version.maven-surefire>
<version.netty>4.0.56.Final</version.netty>
<version.netty-tcnative>2.0.7.Final</version.netty-tcnative>
<version.os-maven>1.5.0.Final</version.os-maven>
<version.powermock>1.6.4</version.powermock>
<version.slf4j>1.7.26</version.slf4j>
<version.spotbugs-maven>3.1.12.1</version.spotbugs-maven>
<version.spring-boot>2.1.3.RELEASE</version.spring-boot>
<version.tyrus>1.15</version.tyrus>
<version.slf4j>1.7.21</version.slf4j>
<version.spotbugs-maven>3.1.7</version.spotbugs-maven>
<version.spring-boot>1.4.1.RELEASE</version.spring-boot>
<version.tyrus>1.13</version.tyrus>
</properties>
<dependencyManagement>
<dependencies>
@@ -101,7 +101,7 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${version.jackson.databind}</version>
<version>${version.jackson}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
@@ -141,18 +141,13 @@
<dependency>
<groupId>io.github.lukehutch</groupId>
<artifactId>fast-classpath-scanner</artifactId>
<version>${version.fast-classpath-scanner}</version>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${version.netty}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>${version.netty-tcnative}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.javacsv</groupId>
<artifactId>javacsv</artifactId>
@@ -162,12 +157,6 @@
<groupId>org.apache.accumulo</groupId>
<artifactId>accumulo-core</artifactId>
<version>${version.accumulo}</version>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.accumulo</groupId>
@@ -398,12 +387,6 @@
<version>${version.jcip-annotations}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>${version.easymock}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
@@ -419,7 +402,7 @@
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>2.10.0</version>
<version>2.8.0</version>
<configuration>
<compilerCompliance>${maven.compiler.source}</compilerCompliance>
<compilerSource>${maven.compiler.source}</compilerSource>
@@ -437,7 +420,7 @@
<plugin>
<groupId>com.github.ekryd.sortpom</groupId>
<artifactId>sortpom-maven-plugin</artifactId>
<version>2.10.0</version>
<version>2.8.0</version>
<configuration>
<predefinedSortOrder>recommended_2008_06</predefinedSortOrder>
<createBackupFile>false</createBackupFile>
@@ -469,7 +452,7 @@
<artifactId>maven-failsafe-plugin</artifactId>
<version>${version.maven-surefire}</version>
<configuration>
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty_tcnative_linux_x86_64.so -Dzookeeper.sasl.client=false</argLine>
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<includes>
<include>**/*.java</include>
</includes>
@@ -512,7 +495,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>${version.maven-surefire}</version>
<configuration>
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative_linux_x86_64.so -Dzookeeper.sasl.client=false</argLine>
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
@@ -581,7 +564,7 @@
<configuration>
<rules>
<requireMavenVersion>
<version>3.5.0</version>
<version>3.0.5</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[${maven.compiler.target},)</version>
@@ -752,9 +735,6 @@
<name>m2e.version</name>
</property>
</activation>
<properties>
<maven.compiler.release>8</maven.compiler.release>
</properties>
<build>
<pluginManagement>
<plugins>
@@ -815,14 +795,5 @@
</pluginManagement>
</build>
</profile>
<profile>
<id>jdk-release-flag</id>
<activation>
<jdk>[9,)</jdk>
</activation>
<properties>
<maven.compiler.release>8</maven.compiler.release>
</properties>
</profile>
</profiles>
</project>
-21
View File
@@ -1,21 +0,0 @@
#!/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
+5 -4
View File
@@ -27,14 +27,15 @@ 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}
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative*.jar META-INF/native/libnetty_tcnative.${TCNATIVE_SUFFIX}
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-transport-native-epoll*.jar META-INF/native/libnetty_transport_native_epoll_x86_64.${TCNATIVE_SUFFIX}
popd
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*:${HADOOP_CONF_DIR}"
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-spring.xml"
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS}"
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}/libnetty-${TCNATIVE_SUFFIX}"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server --spring.config.name=timely"
$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server --spring.config.name=timely
+10 -6
View File
@@ -2,12 +2,17 @@
if [[ `uname` == "Darwin" ]]; then
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
TCNATIVE_SUFFIX="jnilib"
TCNATIVE_SUFFIX="tcnative.jnilib"
else
THIS_SCRIPT=`readlink -f $0`
TCNATIVE_SUFFIX="so"
TCNATIVE_SUFFIX="tcnative.so"
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%/*}"
NATIVE_DIR="${THIS_DIR}/META-INF/native"
BASE_DIR=${THIS_DIR}/..
@@ -27,12 +32,11 @@ 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}
$JAVA_HOME/bin/jar xf ${LIB_DIR}/netty-tcnative*.jar META-INF/native/libnetty-${TCNATIVE_SUFFIX}
popd
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*:${HADOOP_CONF_DIR}"
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-spring.xml"
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS}"
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
# for debugging
+2 -5
View File
@@ -46,12 +46,9 @@
<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: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">
+4 -6
View File
@@ -18,11 +18,9 @@ timely:
max-downsample-memory: 10000000
security:
session-max-age: 86400
cache-expiration-minutes: 60
cache-refresh-minutes: 5
allow-anonymous-http-access: true
allow-anonymous-ws-access: true
server-ssl:
ssl:
certificate-file: /timely-server-src/server/pki/timely.csr
key-file: /timely-server-src/server/pki/timely-pkcs8.key
key-password: password
@@ -52,9 +50,9 @@ timely:
timeout: 60
subscription-lag: 120
meta-cache:
expiration-minutes: 1440
cache-refresh-minutes: 60
max-tag-values: 100
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
visibility-cache:
expiration-minutes: 60
initial-capacity: 2000
+4 -8
View File
@@ -3,8 +3,6 @@ timely:
meta-table: timely.meta
metric-age-off-days:
default: 7
cache:
enabled: false
metrics-report-ignored-tags:
accumulo:
instance-name: TimelyStandalone
@@ -20,11 +18,9 @@ timely:
max-downsample-memory: 10000000
security:
session-max-age: 86400
cache-expiration-minutes: 60
cache-refresh-minutes: 5
allow-anonymous-http-access: true
allow-anonymous-ws-access: true
server-ssl:
ssl:
certificate-file:
key-file:
key-password: timely
@@ -58,9 +54,9 @@ timely:
scanner-read-ahead: 1
subscription-batch-size: 5000
meta-cache:
expiration-minutes: 1440
cache-refresh-minutes: 60
max-tag-values: 100
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
visibility-cache:
expiration-minutes: 60
initial-capacity: 2000
+6 -8
View File
@@ -8,7 +8,6 @@ timely:
age-off-hours:
default: 26
metrics-report-ignored-tags:
defaultVisibility:
accumulo:
instance-name: accumulo
zookeepers: localhost:2181
@@ -23,11 +22,9 @@ timely:
max-downsample-memory: 10000000
security:
session-max-age: 86400
cache-expiration-minutes: 60
cache-refresh-minutes: 5
allow-anonymous-http-access: true
allow-anonymous-ws-access: true
server-ssl:
serverSsl:
certificate-file:
key-file:
key-password:
@@ -62,9 +59,10 @@ timely:
scanner-read-ahead: 1
subscription-batch-size: 5000
meta-cache:
expiration-minutes: 1440
cache-refresh-minutes: 60
max-tag-values: 100
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
visibility-cache:
expiration-minutes: 60
initial-capacity: 2000
max-capacity: 10000
+39 -14
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>1.2.5</version>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>timely-server</artifactId>
<dependencies>
@@ -149,7 +149,9 @@
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<artifactId>netty-tcnative</artifactId>
<version>${version.netty-tcnative}</version>
<classifier>${os.detected.classifier}</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
@@ -177,22 +179,11 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<classifier>full</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
@@ -249,8 +240,9 @@
<artifactItems>
<artifactItem>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<artifactId>netty-tcnative</artifactId>
<version>${version.netty-tcnative}</version>
<classifier>${os.detected.classifier}</classifier>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/native</outputDirectory>
@@ -292,4 +284,37 @@
</extension>
</extensions>
</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>
+17 -19
View File
@@ -24,7 +24,6 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
@@ -45,7 +44,6 @@ import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpServerCodec;
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.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LoggingHandler;
@@ -72,7 +70,6 @@ import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
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.api.response.TimelyException;
@@ -211,13 +208,13 @@ public class Server {
payload.setWsPort(config.getWebsocket().getPort());
payload.setUdpPort(config.getServer().getUdpPort());
ServiceInstanceBuilder<ServerDetails> builder = ServiceInstance.builder();
ServiceInstanceBuilder builder = ServiceInstance.builder();
String serviceName = host + ":" + config.getServer().getTcpPort();
ServiceInstance<ServerDetails> serviceInstance = builder.id(serviceName).name("timely-server")
ServiceInstance serviceInstance = builder.id(serviceName).name("timely-server")
.address(config.getServer().getIp()).port(config.getServer().getTcpPort()).payload(payload).build();
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
ServiceDiscovery discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
.basePath(SERVICE_DISCOVERY_PATH).build();
discovery.start();
discovery.registerService(serviceInstance);
@@ -253,7 +250,7 @@ public class Server {
}
protected static Configuration initializeConfiguration(String[] args) {
applicationContext = new SpringApplicationBuilder(SpringBootstrap.class).web(WebApplicationType.NONE).run(args);
applicationContext = new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(args);
return applicationContext.getBean(Configuration.class);
}
@@ -433,7 +430,7 @@ public class Server {
// Initialize the MetaCache
MetaCacheFactory.getCache(config);
// initialize the auth cache
AuthCache.configure(config.getSecurity());
AuthCache.setSessionMaxAge(config.getSecurity());
// Initialize the VisibilityCache
VisibilityCache.init(config);
final boolean useEpoll = useEpoll();
@@ -510,9 +507,10 @@ public class Server {
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
wsServer.option(ChannelOption.SO_BACKLOG, 128);
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
/* Not sure if next two lines are necessary */
/* Not sure if next three lines are necessary */
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
wsServer.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(620145, 838860));
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
@@ -589,14 +587,14 @@ public class Server {
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
ch.pipeline().addLast("compressor", new HttpContentCompressor());
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
final Cors corsCfg = config.getHttp().getCors();
final CorsConfigBuilder ccb;
final CorsConfig.Builder ccb;
if (corsCfg.isAllowAnyOrigin()) {
ccb = CorsConfigBuilder.forAnyOrigin();
ccb = new CorsConfig.Builder();
} else {
ccb = CorsConfigBuilder.forOrigins(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
ccb = new CorsConfig.Builder(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
}
if (corsCfg.isAllowNullOrigin()) {
ccb.allowNullOrigin();
@@ -637,7 +635,7 @@ public class Server {
ch.pipeline().addLast("logger", new LoggingHandler());
ch.pipeline().addLast("packetDecoder", new UdpPacketToByteBuf());
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("putDecoder", new UdpDecoder());
ch.pipeline().addLast("putHandler", new TcpPutHandler(dataStore));
}
@@ -650,7 +648,7 @@ public class Server {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("buffer", new MetricsBufferDecoder());
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(65536, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("frame", new DelimiterBasedFrameDecoder(8192, true, Delimiters.lineDelimiter()));
ch.pipeline().addLast("putDecoder", new TcpDecoder());
ch.pipeline().addLast("putHandler", new TcpPutHandler(dataStore));
ch.pipeline().addLast("versionHandler", new TcpVersionHandler());
@@ -665,11 +663,11 @@ public class Server {
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast("httpServer", new HttpServerCodec());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
ch.pipeline().addLast("sessionExtractor", new WebSocketFullRequestHandler());
ch.pipeline().addLast("idle-handler", new IdleStateHandler(conf.getWebsocket().getTimeout(), 0, 0));
ch.pipeline().addLast("ws-protocol",
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, false, true));
new WebSocketServerProtocolHandler(WS_PATH, null, true, 65536, true));
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(config.getSecurity()));
ch.pipeline().addLast("aggregators", new WSAggregatorsRequestHandler());
ch.pipeline().addLast("metrics", new WSMetricsRequestHandler(config));
@@ -1,39 +0,0 @@
package timely.adapter.accumulo;
import org.apache.accumulo.core.data.Key;
import timely.api.model.Meta;
import timely.model.Metric;
/**
* Creates Accumulo data structures from {@link Metric}
*/
public class MetaAdapter {
public static Key createMetricKey(String metricName, Long timestamp) {
return new Key(Meta.METRIC_PREFIX + metricName, "", "", timestamp);
}
public static Key createTagKey(String metricName, String tagName, Long timestamp) {
return new Key(Meta.TAG_PREFIX + metricName, tagName, "", timestamp);
}
public static Key createValueKey(String metricName, String tagName, String tagValue, Long timestamp) {
return new Key(Meta.VALUE_PREFIX + metricName, tagName, tagValue, timestamp);
}
public static Meta parse(Key key) {
String row = key.getRow().toString();
if (row.startsWith(Meta.METRIC_PREFIX)) {
return Meta.parse(key, null, Meta.METRIC_PREFIX);
} else if (row.startsWith(Meta.TAG_PREFIX)) {
return Meta.parse(key, null, Meta.TAG_PREFIX);
} else if (row.startsWith(Meta.VALUE_PREFIX)) {
return Meta.parse(key, null, Meta.VALUE_PREFIX);
}
throw new IllegalStateException("Invalid key in meta " + key.toString());
}
public static String decodeRowKey(Key key) {
return parse(key).getMetric();
}
}
+47 -65
View File
@@ -5,10 +5,6 @@ import java.util.List;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Meta implements Comparable<Meta> {
@@ -53,79 +49,60 @@ public class Meta implements Comparable<Meta> {
public List<Key> toKeys() {
List<Key> keys = new ArrayList<>();
if (StringUtils.isNotBlank(metric)) {
keys.add(new Key(METRIC_PREFIX + metric));
}
if (StringUtils.isNotBlank(tagKey)) {
keys.add(new Key(TAG_PREFIX + metric, tagKey));
}
if (StringUtils.isNotBlank(tagKey) && StringUtils.isNotBlank(tagValue)) {
keys.add(new Key(VALUE_PREFIX + metric, tagKey, tagValue));
}
keys.add(new Key(METRIC_PREFIX + metric));
keys.add(new Key(TAG_PREFIX + metric, tagKey));
keys.add(new Key(VALUE_PREFIX + metric, tagKey, tagValue));
return keys;
}
public static String prefix(Key key) {
String row = key.getRow().toString();
if (row.startsWith(Meta.METRIC_PREFIX)) {
return Meta.METRIC_PREFIX;
} else if (row.startsWith(Meta.TAG_PREFIX)) {
return Meta.TAG_PREFIX;
} else if (row.startsWith(Meta.VALUE_PREFIX)) {
return Meta.VALUE_PREFIX;
}
throw new IllegalStateException("Invalid key in meta " + key.toString());
}
public static Meta parse(Key key) {
return parse(key, null);
}
public static Meta parse(Key key, Value value) {
String row = key.getRow().toString();
if (row.startsWith(Meta.METRIC_PREFIX)) {
return Meta.parse(key, value, Meta.METRIC_PREFIX);
} else if (row.startsWith(Meta.TAG_PREFIX)) {
return Meta.parse(key, value, Meta.TAG_PREFIX);
} else if (row.startsWith(Meta.VALUE_PREFIX)) {
return Meta.parse(key, value, Meta.VALUE_PREFIX);
}
throw new IllegalStateException("Invalid key in meta " + key.toString());
}
public static Meta parse(Key k, Value v, String prefix) {
public static Meta parse(Key k, Value v) {
if (k.getColumnQualifier().getLength() > 0) {
return new Meta(k.getRow().toString().substring(prefix.length()), k.getColumnFamily().toString(),
return new Meta(k.getRow().toString().substring(METRIC_PREFIX.length()), k.getColumnFamily().toString(),
k.getColumnQualifier().toString());
} else if (k.getColumnFamily().getLength() > 0) {
return new Meta(k.getRow().toString().substring(prefix.length()), k.getColumnFamily().toString(), null);
return new Meta(k.getRow().toString().substring(METRIC_PREFIX.length()), k.getColumnFamily().toString(),
null);
} else {
return new Meta(k.getRow().toString().substring(prefix.length()), null, null);
return new Meta(k.getRow().toString().substring(METRIC_PREFIX.length()), null, null);
}
}
@Override
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder();
builder.append(metric);
builder.append(tagKey);
builder.append(tagValue);
return builder.toHashCode();
final int prime = 31;
int result = 1;
result = prime * result + ((metric == null) ? 0 : metric.hashCode());
result = prime * result + ((tagKey == null) ? 0 : tagKey.hashCode());
result = prime * result + ((tagValue == null) ? 0 : tagValue.hashCode());
return result;
}
@Override
public boolean equals(Object o) {
if (o instanceof Meta) {
Meta obj = (Meta) o;
EqualsBuilder builder = new EqualsBuilder();
builder.append(this.metric, obj.metric);
builder.append(this.tagKey, obj.tagKey);
builder.append(this.tagValue, obj.tagValue);
return builder.isEquals();
} else {
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
}
if (getClass() != obj.getClass())
return false;
Meta other = (Meta) obj;
if (metric == null) {
if (other.metric != null)
return false;
} else if (!metric.equals(other.metric))
return false;
if (tagKey == null) {
if (other.tagKey != null)
return false;
} else if (!tagKey.equals(other.tagKey))
return false;
if (tagValue == null) {
if (other.tagValue != null)
return false;
} else if (!tagValue.equals(other.tagValue))
return false;
return true;
}
@Override
@@ -135,10 +112,15 @@ public class Meta implements Comparable<Meta> {
@Override
public int compareTo(Meta o) {
CompareToBuilder builder = new CompareToBuilder();
builder.append(this.metric, o.metric);
builder.append(this.tagKey, o.tagKey);
builder.append(this.tagValue, o.tagValue);
return builder.toComparison();
int result = metric.compareTo(o.metric);
if (result != 0) {
return result;
}
result = tagKey.compareTo(o.tagKey);
if (result != 0) {
return result;
}
return tagValue.compareTo(o.tagValue);
}
}
@@ -4,6 +4,8 @@ public interface TcpRequest extends Request {
/**
* Parse a line of text received and populate this object
*
* @param line
*/
public void parse(String line);
@@ -4,6 +4,8 @@ public interface UdpRequest {
/**
* Parse a line of text received and populate this object
*
* @param line
*/
public void parse(String line);
@@ -18,7 +18,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
@@ -129,8 +129,8 @@ public class MetricsResponse {
}
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(buf));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, responseType);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, responseType);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
return response;
}
@@ -156,10 +156,8 @@ public class MetricsResponse {
b.append(TR_END);
String prevMetric = null;
StringBuilder tags = new StringBuilder();
Map<String, Long> tagMap = new HashMap<>();
for (Meta m : tree) {
if (prevMetric != null && !m.getMetric().equals(prevMetric)) {
tagMap.clear();
b.append(TR_START);
b.append(TD_START).append(prevMetric).append(TD_END);
b.append(TD_START).append(tags.toString()).append(TD_END);
@@ -170,12 +168,8 @@ public class MetricsResponse {
if (prevMetric == null) {
prevMetric = m.getMetric();
}
long numValues = tagMap.getOrDefault(m.getTagKey(), 0l);
if (!(this.ignoredTags.contains(m.getTagKey()))) {
if (numValues <= conf.getMetaCache().getMaxTagValues()) {
tags.append(m.getTagKey()).append("=").append(m.getTagValue()).append(" ");
tagMap.put(m.getTagKey(), ++numValues);
}
tags.append(m.getTagKey()).append("=").append(m.getTagValue()).append(" ");
}
}
b.append(TR_START);
@@ -23,67 +23,32 @@ public class AuthCache {
private static final Logger LOG = LoggerFactory.getLogger(AuthCache.class);
private static Cache<String, TimelyPrincipal> CACHE = null;
private static int cacheExpirationMinutes = -1;
private static int cacheRefreshMinutes = -1;
private static int sessionMaxAge = -1;
/**
* For tests only
*/
public static void resetConfiguration() {
cacheExpirationMinutes = -1;
cacheRefreshMinutes = -1;
public static void resetSessionMaxAge() {
sessionMaxAge = -1;
}
public static void configure(Security security) {
if (-1 != cacheExpirationMinutes || -1 != cacheRefreshMinutes) {
throw new IllegalStateException("Cache already configured.");
public static void setSessionMaxAge(Security security) {
if (-1 != sessionMaxAge) {
throw new IllegalStateException("Cache session max age already configured.");
}
cacheExpirationMinutes = security.getCacheExpirationMinutes();
cacheRefreshMinutes = security.getCacheRefreshMinutes();
sessionMaxAge = security.getSessionMaxAge();
}
private static Cache<String, TimelyPrincipal> getCache() {
if (-1 == cacheExpirationMinutes) {
if (-1 == sessionMaxAge) {
throw new IllegalStateException("Cache session max age not configured.");
}
if (null == CACHE) {
Caffeine<Object, Object> caffeine = Caffeine.newBuilder();
caffeine.expireAfterWrite(cacheExpirationMinutes, TimeUnit.MINUTES);
if (cacheRefreshMinutes > 0) {
caffeine.refreshAfterWrite(cacheRefreshMinutes, TimeUnit.MINUTES);
CACHE = caffeine.build(key -> getTimelyPrincipal(key));
} else {
CACHE = caffeine.build();
}
CACHE = Caffeine.newBuilder().expireAfterAccess(sessionMaxAge, TimeUnit.SECONDS).build();
}
return CACHE;
}
private static TimelyPrincipal getTimelyPrincipal(String key) {
LOG.debug("Refreshing TimelyPrincipal {}", key);
TimelyPrincipal timelyPrincipal = null;
String[] dnArray = key.split(" -> ");
if (dnArray.length == 1) {
SubjectIssuerDNPair pair = SubjectIssuerDNPair.parse(dnArray[0]);
TimelyAuthenticationToken token = AuthenticationService.getAuthenticationToken(new Object(),
pair.subjectDN(), pair.issuerDN());
timelyPrincipal = AuthenticationService.authenticate(token, pair, token.getTimelyPrincipal().getName(),
false);
} else if (dnArray.length > 1) {
Collection<TimelyUser> timelyUsers = new ArrayList<>();
for (String s : dnArray) {
SubjectIssuerDNPair pair = SubjectIssuerDNPair.parse(s);
TimelyAuthenticationToken token = AuthenticationService.getAuthenticationToken(new Object(),
pair.subjectDN(), pair.issuerDN());
TimelyPrincipal p = AuthenticationService.authenticate(token, pair,
token.getTimelyPrincipal().getName(), false);
timelyUsers.addAll(p.getProxiedUsers());
}
timelyPrincipal = new TimelyPrincipal(timelyUsers);
}
return timelyPrincipal;
}
public static boolean containsKey(String key) {
return getCache().getIfPresent(key) != null;
}
@@ -23,6 +23,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
import timely.api.request.AuthenticatedRequest;
import timely.api.response.TimelyException;
import timely.auth.util.DnUtils;
@@ -34,6 +35,7 @@ public class AuthenticationService {
private static final Logger LOG = LoggerFactory.getLogger(AuthenticationService.class);
private static ApplicationContext springContext = null;
private static AuthenticationManager authManager = null;
private static SubjectDnX509PrincipalExtractor x509 = null;
private static ConcurrentHashMap<String, Object> fetchingEntity = new ConcurrentHashMap<>();
private static ConcurrentHashMap<String, Object> fetchingPrincipal = new ConcurrentHashMap<>();
private static Collection<String> requiredRoles;
@@ -43,13 +45,10 @@ public class AuthenticationService {
try {
springContext = new ClassPathXmlApplicationContext("security.xml");
authManager = springContext.getBean("authenticationManager", AuthenticationManager.class);
@SuppressWarnings("unchecked")
List<String> uncheckedRoles = springContext.getBean("requiredRoles", List.class);
requiredRoles = uncheckedRoles;
x509 = springContext.getBean("x509PrincipalExtractor", SubjectDnX509PrincipalExtractor.class);
requiredRoles = springContext.getBean("requiredRoles", List.class);
requiredRoles.removeIf(String::isEmpty);
@SuppressWarnings("unchecked")
List<String> uncheckedAuths = springContext.getBean("requiredAuths", List.class);
requiredAuths = uncheckedAuths;
requiredAuths = springContext.getBean("requiredAuths", List.class);
requiredAuths.removeIf(String::isEmpty);
} catch (BeansException e) {
throw new ServiceConfigurationError("Error setting up Authentication objects: " + e.getMessage(),
@@ -66,17 +65,9 @@ public class AuthenticationService {
}
public static TimelyPrincipal authenticate(Authentication authentication, SubjectIssuerDNPair pair, String entity) {
return authenticate(authentication, pair, entity, true);
}
public static TimelyPrincipal authenticate(Authentication authentication, SubjectIssuerDNPair pair, String entity,
boolean useCache) {
// only one thread should call the authenticationManager for a given entity
TimelyPrincipal principal = null;
if (useCache) {
principal = AuthCache.get(entity);
}
TimelyPrincipal principal = AuthCache.get(entity);
// once an entity is in the AuthCache, we can bypass all of this
if (principal == null) {
Object newObj = new Object();
@@ -88,16 +79,12 @@ public class AuthenticationService {
synchronized (o) {
// if multiple threads are waiting on this synchronized, then the 2nd and all
// others will get the principal here
if (useCache) {
principal = AuthCache.get(entity);
}
principal = AuthCache.get(entity);
if (principal == null) {
Authentication token = getAuthenticationManager().authenticate(authentication);
principal = getTimelyPrincipal(token, pair);
LOG.trace("Got entity principal for {} from AuthenticationManager", entity);
if (useCache) {
AuthCache.put(entity, principal);
}
AuthCache.put(entity, principal);
} else {
LOG.trace("Got entity principal for {} from AuthCache on 2nd attempt", entity);
}
@@ -245,7 +232,7 @@ public class AuthenticationService {
return authenticationToken;
}
public static TimelyAuthenticationToken getAuthenticationToken(Object clientCert, String subjectDn,
public static TimelyAuthenticationToken getAuthenticationToken(X509Certificate clientCert, String subjectDn,
String issuerDn) {
TimelyAuthenticationToken authenticationToken = null;
try {
@@ -16,6 +16,8 @@ import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.data.thrift.IterInfo;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.hadoop.io.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A simple wrapper around a {@link ScannerBase} that overrides the methods that
@@ -25,6 +27,7 @@ import org.apache.hadoop.io.Text;
*/
public class ScannerBaseDelegate implements ScannerBase {
private static final Logger log = LoggerFactory.getLogger(ScannerBaseDelegate.class);
private static final String SYSTEM_ITERATOR_NAME_PREFIX = "sys_";
protected final ScannerBase delegate;
@@ -136,11 +139,10 @@ public class ScannerBaseDelegate implements ScannerBase {
@Override
public void clearScanIterators() {
if (delegate instanceof ScannerOptions) {
try (ScannerOptionsHelper opts = new ScannerOptionsHelper((ScannerOptions) delegate)) {
for (IteratorSetting iteratorSetting : opts.getIterators()) {
if (!iteratorSetting.getName().startsWith(SYSTEM_ITERATOR_NAME_PREFIX)) {
delegate.removeScanIterator(iteratorSetting.getName());
}
ScannerOptionsHelper opts = new ScannerOptionsHelper((ScannerOptions) delegate);
for (IteratorSetting iteratorSetting : opts.getIterators()) {
if (!iteratorSetting.getName().startsWith(SYSTEM_ITERATOR_NAME_PREFIX)) {
delegate.removeScanIterator(iteratorSetting.getName());
}
}
} else {
@@ -13,7 +13,6 @@ import timely.auth.util.ProxiedEntityUtils;
*/
public class SubjectIssuerDNPair implements Serializable {
private static final long serialVersionUID = 1L;
private final String subjectDN;
private final String issuerDN;
@@ -29,7 +29,6 @@ import timely.auth.util.DnUtils;
@XmlAccessorType(XmlAccessType.NONE)
public class TimelyPrincipal implements Principal, Serializable {
private static final long serialVersionUID = 1L;
private final String username;
private final TimelyUser primaryUser;
@XmlElement
@@ -104,7 +103,7 @@ public class TimelyPrincipal implements Principal, Serializable {
public Set<String> getProxyServers() {
// @formatter:off
// @formatter:off
Set<String> proxyServers = getProxiedUsers().stream()
.filter(u -> u.getUserType() == TimelyUser.UserType.SERVER)
.map(TimelyUser::getDn)
@@ -20,8 +20,6 @@ import timely.auth.util.DnUtils;
*/
public class TimelyUser implements Serializable {
private static final long serialVersionUID = 1L;
public enum UserType {
USER, SERVER
}
@@ -13,9 +13,7 @@ public class HttpHeaderUtils {
Multimap<String, String> headerMultimap = HashMultimap.create();
if (headers != null) {
for (Map.Entry<String, String> e : headers.entries()) {
// lower case for HTTP/2 compatibility; even for HTTP/1, these were always
// case-insensitive
headerMultimap.put(e.getKey().toLowerCase(), e.getValue());
headerMultimap.put(e.getKey(), e.getValue());
}
}
return headerMultimap;
@@ -24,9 +22,6 @@ public class HttpHeaderUtils {
public static String getSingleHeader(Multimap<String, String> headers, String headerName, boolean enforceOneValue)
throws IllegalArgumentException {
String value = null;
// lower case for HTTP/2 compatibility; even for HTTP/1, these were always
// case-insensitive
headerName = headerName.toLowerCase();
Collection<String> values = (headers == null) ? null : headers.get(headerName);
if (values != null && !values.isEmpty()) {
if (values.size() > 1 && enforceOneValue) {
@@ -1,8 +1,8 @@
package timely.configuration;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
public class Accumulo {
@@ -9,9 +9,7 @@ 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;
@Validated
@Component
@ConfigurationProperties(prefix = "timely")
public class Configuration {
@@ -21,7 +19,6 @@ public class Configuration {
private HashMap<String, Integer> metricAgeOffDays = new HashMap<>();
private List<String> metricsReportIgnoredTags = new ArrayList<>();
private String instance = null;
private String defaultVisibility = null;
@Valid
@NestedConfigurationProperty
@@ -74,14 +71,6 @@ public class Configuration {
return instance;
}
public String getDefaultVisibility() {
return defaultVisibility;
}
public void setDefaultVisibility(String defaultVisibility) {
this.defaultVisibility = defaultVisibility;
}
public HashMap<String, Integer> getMetricAgeOffDays() {
return metricAgeOffDays;
}
@@ -1,9 +1,9 @@
package timely.configuration;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
public class Http {
@@ -2,9 +2,9 @@ package timely.configuration;
public class MetaCache {
private long expirationMinutes = 1440;
private int cacheRefreshMinutes = -1;
private long maxTagValues = 100;
private long expirationMinutes = 60;
private int initialCapacity = 2000;
private long maxCapacity = 10000;
public long getExpirationMinutes() {
return expirationMinutes;
@@ -14,19 +14,19 @@ public class MetaCache {
this.expirationMinutes = expirationMinutes;
}
public void setCacheRefreshMinutes(int cacheRefreshMinutes) {
this.cacheRefreshMinutes = cacheRefreshMinutes;
public int getInitialCapacity() {
return initialCapacity;
}
public int getCacheRefreshMinutes() {
return cacheRefreshMinutes;
public void setInitialCapacity(int initialCapacity) {
this.initialCapacity = initialCapacity;
}
public long getMaxTagValues() {
return maxTagValues;
public long getMaxCapacity() {
return maxCapacity;
}
public void setMaxTagValues(long maxTagValues) {
this.maxTagValues = maxTagValues;
public void setMaxCapacity(long maxCapacity) {
this.maxCapacity = maxCapacity;
}
}
@@ -9,8 +9,6 @@ public class Security {
private boolean allowAnonymousHttpAccess = false;
private boolean allowAnonymousWsAccess = false;
private int sessionMaxAge = 86400;
private int cacheExpirationMinutes = 60;
private int cacheRefreshMinutes = 5;
@Valid
@NestedConfigurationProperty
private ServerSsl serverSsl = new ServerSsl();
@@ -39,22 +37,6 @@ public class Security {
this.sessionMaxAge = sessionMaxAge;
}
public void setCacheExpirationMinutes(int cacheExpirationMinutes) {
this.cacheExpirationMinutes = cacheExpirationMinutes;
}
public int getCacheExpirationMinutes() {
return cacheExpirationMinutes;
}
public void setCacheRefreshMinutes(int cacheRefreshMinutes) {
this.cacheRefreshMinutes = cacheRefreshMinutes;
}
public int getCacheRefreshMinutes() {
return cacheRefreshMinutes;
}
public ServerSsl getServerSsl() {
return serverSsl;
}
@@ -1,8 +1,9 @@
package timely.configuration;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
public class Server {
@NotBlank
@@ -41,6 +42,8 @@ public class Server {
/**
* Time to wait (in seconds) for connections to finish and to make sure no new
* connections happen before shutting down Netty event loop groups.
*
* @return
*/
public int getShutdownQuietPeriod() {
return this.shutdownQuietPeriod;
@@ -1,8 +1,9 @@
package timely.configuration;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
public class Websocket {
@NotBlank
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import timely.api.request.CacheRequest;
@@ -35,8 +35,8 @@ public class HttpCacheRequestHandler extends SimpleChannelInboundHandler<CacheRe
}
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(buf));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.slf4j.Logger;
@@ -35,8 +35,8 @@ public class HttpMetricPutHandler extends SimpleChannelInboundHandler<MetricRequ
}
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.EMPTY_BUFFER);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -10,7 +10,7 @@ import io.netty.buffer.ByteBuf;
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.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.QueryStringDecoder;
@@ -52,7 +52,7 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
public static String getSessionId(FullHttpRequest msg) {
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(msg.headers());
Collection<String> cookies = headers.get(HttpHeaderNames.COOKIE.toString());
Collection<String> cookies = headers.get(Names.COOKIE);
final StringBuilder buf = new StringBuilder();
cookies.forEach(h -> {
ServerCookieDecoder.STRICT.decode(h).forEach(c -> {
@@ -75,7 +75,7 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
LOG.trace(LOG_RECEIVED_REQUEST, msg);
final String uri = msg.uri();
final String uri = msg.getUri();
final QueryStringDecoder decoder = new QueryStringDecoder(uri);
if (decoder.path().equals(nonSecureRedirectAddress)) {
out.add(new StrictTransportResponse());
@@ -87,10 +87,10 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
HttpRequest request;
try {
if (msg.method().equals(HttpMethod.GET)) {
if (msg.getMethod().equals(HttpMethod.GET)) {
HttpGetRequest get = AnnotationResolver.getClassForHttpGet(decoder.path());
request = get.parseQueryParameters(decoder);
} else if (msg.method().equals(HttpMethod.POST)) {
} else if (msg.getMethod().equals(HttpMethod.POST)) {
HttpPostRequest post = AnnotationResolver.getClassForHttpPost(decoder.path());
String content = "";
ByteBuf body = msg.content();
@@ -101,9 +101,8 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
} else {
TimelyException e = new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
"unhandled method type", "");
e.addResponseHeader(HttpHeaderNames.ALLOW.toString(),
HttpMethod.GET.name() + "," + HttpMethod.POST.name());
LOG.warn("Unhandled HTTP request type {}", msg.method());
e.addResponseHeader(Names.ALLOW, HttpMethod.GET.name() + "," + HttpMethod.POST.name());
LOG.warn("Unhandled HTTP request type {}", msg.getMethod());
throw e;
}
if (request instanceof AuthenticatedRequest) {
@@ -15,14 +15,14 @@
*/
package timely.netty.http;
import static io.netty.handler.codec.http.HttpHeaderNames.CACHE_CONTROL;
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaderNames.DATE;
import static io.netty.handler.codec.http.HttpHeaderNames.EXPIRES;
import static io.netty.handler.codec.http.HttpHeaderNames.IF_MODIFIED_SINCE;
import static io.netty.handler.codec.http.HttpHeaderNames.LAST_MODIFIED;
import static io.netty.handler.codec.http.HttpHeaderNames.LOCATION;
import static io.netty.handler.codec.http.HttpHeaders.Names.CACHE_CONTROL;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpHeaders.Names.DATE;
import static io.netty.handler.codec.http.HttpHeaders.Names.EXPIRES;
import static io.netty.handler.codec.http.HttpHeaders.Names.IF_MODIFIED_SINCE;
import static io.netty.handler.codec.http.HttpHeaders.Names.LAST_MODIFIED;
import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION;
import static io.netty.handler.codec.http.HttpMethod.GET;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
@@ -59,10 +59,9 @@ import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpChunkedInput;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.SystemPropertyUtil;
@@ -95,7 +94,7 @@ import timely.netty.Constants;
* Request #1 Headers
* ===================
* GET /file1.txt HTTP/1.1
*
*
* Response #1 Headers
* ===================
* HTTP/1.1 200 OK
@@ -103,12 +102,12 @@ import timely.netty.Constants;
* Last-Modified: Wed, 30 Jun 2010 21:36:48 GMT
* Expires: Tue, 01 Mar 2012 22:44:26 GMT
* Cache-Control: private, max-age=31536000
*
*
* Request #2 Headers
* ===================
* GET /file1.txt HTTP/1.1
* If-Modified-Since: Wed, 30 Jun 2010 21:36:48 GMT
*
*
* Response #2 Headers
* ===================
* HTTP/1.1 304 Not Modified
@@ -126,17 +125,17 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
@Override
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
if (!request.decoderResult().isSuccess()) {
if (!request.getDecoderResult().isSuccess()) {
sendError(ctx, BAD_REQUEST);
return;
}
if (request.method() != GET) {
if (request.getMethod() != GET) {
sendError(ctx, METHOD_NOT_ALLOWED);
return;
}
String uri = request.uri();
String uri = request.getUri();
if (uri.startsWith("/favicon.ico")) {
uri = uri.replaceFirst("\\/", "/webapp/");
}
@@ -202,12 +201,12 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
long fileLength = raf.length();
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
HttpUtil.setContentLength(response, fileLength);
HttpHeaders.setContentLength(response, fileLength);
setContentTypeHeader(response, file);
setDateAndCacheHeaders(response, file);
HttpUtil.setTransferEncodingChunked(response, true);
if (HttpUtil.isKeepAlive(request)) {
response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
HttpHeaders.setTransferEncodingChunked(response);
if (HttpHeaders.isKeepAlive(request)) {
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}
// Write the initial line and the header.
@@ -7,7 +7,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import timely.api.request.VersionRequest;
@@ -20,8 +20,8 @@ public class HttpVersionRequestHandler extends SimpleChannelInboundHandler<Versi
protected void channelRead0(ChannelHandlerContext ctx, VersionRequest v) throws Exception {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(VersionRequest.VERSION.getBytes(StandardCharsets.UTF_8)));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.TEXT_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.TEXT_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -6,7 +6,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
@@ -51,7 +51,7 @@ public class NonSslRedirectHandler extends OptionalSslHandler implements TimelyH
LOG.trace("Received non-SSL request, returning redirect");
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.MOVED_PERMANENTLY, Unpooled.EMPTY_BUFFER);
response.headers().set(HttpHeaderNames.LOCATION, redirectAddress);
response.headers().set(Names.LOCATION, redirectAddress);
LOG.trace(Constants.LOG_RETURNING_RESPONSE, response);
encoder.write(ctx, response, ctx.voidPromise());
ctx.flush();
@@ -6,7 +6,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.slf4j.Logger;
@@ -25,8 +25,8 @@ public interface TimelyHttpHandler {
.writeValueAsBytes("ResponseCode: " + e.getCode() + " Message: " + e.getMessage());
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.valueOf(e.getCode()), Unpooled.copiedBuffer(buf));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
e.getResponseHeaders().entrySet().forEach(entry -> response.headers().set(entry.getKey(), entry.getValue()));
// Send the error response
sendResponse(ctx, response);
@@ -17,26 +17,24 @@ import timely.auth.util.HttpHeaderUtils;
public class TimelyAuthenticationToken extends PreAuthenticatedAuthenticationToken {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(TimelyAuthenticationToken.class);
public static final String PROXIED_ENTITIES_HEADER = "x-proxiedentitieschain";
public static final String PROXIED_ISSUERS_HEADER = "x-proxiedissuerschain";
public static final String PROXIED_ENTITIES_HEADER = "X-ProxiedEntitiesChain";
public static final String PROXIED_ISSUERS_HEADER = "X-ProxiedIssuersChain";
private Multimap<String, String> httpHeaders = null;
private X509Certificate clientCert = null;
private X509Certificate clientCert;
private TimelyPrincipal timelyPrincipal;
public TimelyAuthenticationToken(String subjectDn, Object clientCert, Multimap<String, String> httpHeaders) {
public TimelyAuthenticationToken(String subjectDn, X509Certificate clientCert,
Multimap<String, String> httpHeaders) {
super(subjectDn, clientCert);
if (httpHeaders == null) {
this.httpHeaders = HashMultimap.create();
} else {
this.httpHeaders = httpHeaders;
}
if (clientCert instanceof X509Certificate) {
this.clientCert = (X509Certificate) clientCert;
}
String issuerDn = clientCert == null ? null : this.clientCert.getIssuerDN().getName();
this.clientCert = clientCert;
String issuerDn = clientCert == null ? null : clientCert.getIssuerDN().getName();
String proxiedEntities;
String proxiedIssuers;
try {
@@ -63,11 +61,9 @@ public class TimelyAuthenticationToken extends PreAuthenticatedAuthenticationTok
LOG.trace("Created TimelyAuthenticationToken: {}", timelyPrincipal.getName());
}
public TimelyAuthenticationToken(String subjectDn, String issuerDn, Object clientCert) {
public TimelyAuthenticationToken(String subjectDn, String issuerDn, X509Certificate clientCert) {
super(subjectDn, clientCert);
if (clientCert instanceof X509Certificate) {
this.clientCert = (X509Certificate) clientCert;
}
this.clientCert = clientCert;
TimelyUser.UserType userType = DnUtils.isServerDN(subjectDn) ? TimelyUser.UserType.SERVER
: TimelyUser.UserType.USER;
TimelyUser timelyUser = new TimelyUser(SubjectIssuerDNPair.of(subjectDn, issuerDn), userType, null, null, null,
@@ -8,7 +8,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.cookie.DefaultCookie;
@@ -43,22 +43,22 @@ public abstract class TimelyLoginRequestHandler<T> extends SimpleChannelInboundH
principal.getPrimaryUser().getDn().subjectDN());
String sessionIdEncoded = URLEncoder.encode(sessionId, StandardCharsets.UTF_8.name());
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
DefaultCookie cookie = new DefaultCookie(Constants.COOKIE_NAME, sessionIdEncoded);
cookie.setDomain(domain);
cookie.setMaxAge(maxAge);
cookie.setPath("/");
cookie.setHttpOnly(true);
cookie.setSecure(true);
response.headers().set(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie));
response.headers().set(Names.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie));
sendResponse(ctx, response);
} catch (Exception e) {
LOG.error("Login failure", e);
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.UNAUTHORIZED);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import timely.api.request.timeseries.AggregatorsRequest;
@@ -22,8 +22,8 @@ public class HttpAggregatorsRequestHandler extends SimpleChannelInboundHandler<A
byte[] buf = JsonUtil.getObjectMapper().writeValueAsBytes(AggregatorsResponse.RESPONSE);
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(buf));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -2,7 +2,7 @@ package timely.netty.http.timeseries;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import timely.api.request.timeseries.MetricsRequest;
import timely.api.response.timeseries.MetricsResponse;
import timely.configuration.Configuration;
@@ -20,7 +20,7 @@ public class HttpMetricsRequestHandler extends SimpleChannelInboundHandler<Metri
@Override
protected void channelRead0(ChannelHandlerContext ctx, MetricsRequest msg) throws Exception {
MetricsResponse r = new MetricsResponse(conf);
String acceptHeader = msg.getRequestHeader(HttpHeaderNames.ACCEPT.toString());
String acceptHeader = msg.getRequestHeader(Names.ACCEPT);
sendResponse(ctx, r.toHttpResponse(acceptHeader));
}
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.slf4j.Logger;
@@ -42,8 +42,8 @@ public class HttpQueryRequestHandler extends SimpleChannelInboundHandler<QueryRe
}
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(buf));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.slf4j.Logger;
@@ -39,8 +39,8 @@ public class HttpSearchLookupRequestHandler extends SimpleChannelInboundHandler<
}
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(buf));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders.Names;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import org.slf4j.Logger;
@@ -39,8 +39,8 @@ public class HttpSuggestRequestHandler extends SimpleChannelInboundHandler<Sugge
}
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(buf));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
sendResponse(ctx, response);
}
@@ -37,6 +37,7 @@ public class AggregationIterator extends WrappingIterator {
private Set<Tag> tags;
private Key last;
@SuppressWarnings("unchecked")
@Override
public void init(SortedKeyValueIterator<Key, Value> source, Map<String, String> options, IteratorEnvironment env)
throws IOException {
@@ -44,10 +45,7 @@ public class AggregationIterator extends WrappingIterator {
String aggClassname = options.get(AGGCLASS);
Class<? extends Aggregator> aggClass = null;
try {
@SuppressWarnings("unchecked")
Class<? extends Aggregator> uncheckedAggClass = (Class<? extends Aggregator>) this.getClass()
.getClassLoader().loadClass(aggClassname);
aggClass = uncheckedAggClass;
aggClass = (Class<? extends Aggregator>) this.getClass().getClassLoader().loadClass(aggClassname);
tags = new HashSet<>(new TagListParser().parse(options.get(TAGS)));
aggregation = new Aggregation(aggClass.newInstance());
} catch (ClassNotFoundException e) {
@@ -121,11 +119,10 @@ public class AggregationIterator extends WrappingIterator {
is.addOption(AGGCLASS, classname);
}
@SuppressWarnings("unchecked")
public static Map<Set<Tag>, Aggregation> decodeValue(Value value) throws IOException, ClassNotFoundException {
ByteArrayInputStream bis = new ByteArrayInputStream(value.get());
ObjectInputStream ois = new ObjectInputStream(bis);
@SuppressWarnings("unchecked")
Map<Set<Tag>, Aggregation> unchecked = (Map<Set<Tag>, Aggregation>) ois.readObject();
return unchecked;
return (Map<Set<Tag>, Aggregation>) ois.readObject();
}
}
@@ -51,6 +51,7 @@ public class DownsampleIterator extends WrappingIterator {
private DownsampleMemoryEstimator memoryEstimator = null;
@SuppressWarnings("unchecked")
@Override
public void init(SortedKeyValueIterator<Key, Value> source, Map<String, String> options, IteratorEnvironment env)
throws IOException {
@@ -72,9 +73,7 @@ public class DownsampleIterator extends WrappingIterator {
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
@SuppressWarnings("unchecked")
Class<? extends Aggregator> uncheckedAggClass = (Class<? extends Aggregator>) aggClass;
factory = new DownsampleFactory(start, end, period, uncheckedAggClass);
factory = new DownsampleFactory(start, end, period, (Class<? extends Aggregator>) aggClass);
}
@Override
@@ -155,12 +154,11 @@ public class DownsampleIterator extends WrappingIterator {
is.addOption(AGGCLASS, classname);
}
@SuppressWarnings("unchecked")
public static Map<Set<Tag>, Downsample> decodeValue(Value value) throws IOException, ClassNotFoundException {
ByteArrayInputStream bis = new ByteArrayInputStream(value.get());
ObjectInputStream ois = new ObjectInputStream(bis);
@SuppressWarnings("unchecked")
Map<Set<Tag>, Downsample> unchecked = (Map<Set<Tag>, Downsample>) ois.readObject();
return unchecked;
return (Map<Set<Tag>, Downsample>) ois.readObject();
}
public static long getDownsamplePeriod(QueryRequest.SubQuery query) {
@@ -2,7 +2,6 @@ package timely.store;
import static org.apache.accumulo.core.conf.AccumuloConfiguration.getMemoryInBytes;
import static org.apache.accumulo.core.conf.AccumuloConfiguration.getTimeInMillis;
import static timely.adapter.accumulo.MetricAdapter.VISIBILITY_TAG;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -19,7 +18,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.Timer;
@@ -48,18 +46,12 @@ import org.apache.accumulo.core.client.TableExistsException;
import org.apache.accumulo.core.client.TableNotFoundException;
import org.apache.accumulo.core.client.ZooKeeperInstance;
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Mutation;
import org.apache.accumulo.core.data.PartialKey;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.data.*;
import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope;
import org.apache.accumulo.core.iterators.user.RegExFilter;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.accumulo.core.security.VisibilityEvaluator;
import org.apache.accumulo.core.util.Pair;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.configuration.BaseConfiguration;
import org.apache.hadoop.io.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -138,16 +130,15 @@ public class DataStoreImpl implements DataStore {
private final Map<String, String> ageOff;
private final long defaultAgeOffMilliSec;
private DataStoreCache cache = null;
private final String defaultVisibility;
public DataStoreImpl(Configuration conf, int numWriteThreads) throws TimelyException {
try {
final Map<String, String> properties = new HashMap<>();
final BaseConfiguration apacheConf = new BaseConfiguration();
Accumulo accumuloConf = conf.getAccumulo();
properties.put("instance.name", accumuloConf.getInstanceName());
properties.put("instance.zookeeper.host", accumuloConf.getZookeepers());
final ClientConfiguration aconf = ClientConfiguration.fromMap(properties);
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
final Instance instance = new ZooKeeperInstance(aconf);
connector = instance.getConnector(accumuloConf.getUsername(),
new PasswordToken(accumuloConf.getPassword()));
@@ -158,31 +149,6 @@ public class DataStoreImpl implements DataStore {
scannerThreads = accumuloConf.getScan().getThreads();
maxDownsampleMemory = accumuloConf.getScan().getMaxDownsampleMemory();
security = conf.getSecurity();
defaultVisibility = conf.getDefaultVisibility();
if (StringUtils.isNotBlank(defaultVisibility)) {
ColumnVisibility vis;
try {
// validate visibility
vis = new ColumnVisibility(defaultVisibility);
LOG.info("Using defaultVisibility: {}", vis.toString());
} catch (RuntimeException e) {
LOG.error("Error validating defaultVisibility " + defaultVisibility + " " + e.getMessage(), e);
throw e;
}
try {
String whoami = connector.whoami();
Authorizations auths = connector.securityOperations().getUserAuthorizations(whoami);
VisibilityEvaluator eval = new VisibilityEvaluator(auths);
if (!eval.evaluate(vis)) {
throw new IllegalArgumentException("Accumulo user " + whoami + " with authorization "
+ auths.toString() + " can not see data with defaultVisibility " + vis.toString());
}
} catch (RuntimeException e) {
LOG.error(e.getMessage(), e);
throw e;
}
}
metricsTable = conf.getMetricsTable();
if (metricsTable.contains(".")) {
@@ -211,7 +177,7 @@ public class DataStoreImpl implements DataStore {
}
try {
this.removeAgeOffIterators(connector, metricsTable);
this.applyMetricAgeOffIterator(connector, metricsTable);
this.applyAgeOffIterator(connector, metricsTable, true);
} catch (Exception e1) {
Throwable cause = e1.getCause();
if (cause.getMessage().contains("conflict")) {
@@ -232,7 +198,7 @@ public class DataStoreImpl implements DataStore {
}
try {
this.removeAgeOffIterators(connector, metaTable);
this.applyMetaAgeOffIterator(connector, metaTable);
this.applyAgeOffIterator(connector, metaTable, false);
} catch (Exception e1) {
Throwable cause = e1.getCause();
if (cause.getMessage().contains("conflict")) {
@@ -285,15 +251,13 @@ public class DataStoreImpl implements DataStore {
}
}
private void applyMetricAgeOffIterator(Connector con, String tableName) throws Exception {
IteratorSetting ageOffIteratorSettings = new IteratorSetting(100, "ageoffmetrics", MetricAgeOffIterator.class,
this.ageOff);
connector.tableOperations().attachIterator(tableName, ageOffIteratorSettings, AGEOFF_SCOPES);
}
private void applyMetaAgeOffIterator(Connector con, String tableName) throws Exception {
IteratorSetting ageOffIteratorSettings = new IteratorSetting(100, "ageoffmeta", MetaAgeOffIterator.class,
this.ageOff);
private void applyAgeOffIterator(Connector con, String tableName, boolean useIterator) throws Exception {
IteratorSetting ageOffIteratorSettings = null;
if (useIterator) {
ageOffIteratorSettings = new IteratorSetting(100, "ageoff", MetricAgeOffIterator.class, this.ageOff);
} else {
ageOffIteratorSettings = new IteratorSetting(100, "ageoff", MetricAgeOffFilter.class, this.ageOff);
}
connector.tableOperations().attachIterator(tableName, ageOffIteratorSettings, AGEOFF_SCOPES);
}
@@ -315,17 +279,6 @@ public class DataStoreImpl implements DataStore {
public void store(Metric metric, boolean cacheEnabled) {
LOG.trace("Received Store Request for: {}", metric);
// if default visibility is configured and current metric does not contain a
// visibility
// add it here, so that the cache and accumulo stores both have the correct
// visibility
if (StringUtils.isNotBlank(defaultVisibility)) {
Optional<Tag> visTag = metric.getTags().stream().filter(t -> t.getKey().equals(VISIBILITY_TAG)).findFirst();
if (!visTag.isPresent()) {
metric.addTag(new Tag(VISIBILITY_TAG, defaultVisibility));
}
}
if (cache != null && cacheEnabled) {
cache.store(metric);
}
@@ -354,7 +307,10 @@ public class DataStoreImpl implements DataStore {
internalMetrics.incrementMetricsReceived(1);
List<Meta> toCache = new ArrayList<>(metric.getTags().size());
for (final Tag tag : metric.getTags()) {
toCache.add(new Meta(metric.getName(), tag.getKey(), tag.getValue()));
Meta key = new Meta(metric.getName(), tag.getKey(), tag.getValue());
if (!metaCache.contains(key)) {
toCache.add(key);
}
}
if (!toCache.isEmpty()) {
final Set<Mutation> muts = new TreeSet<>(new Comparator<Mutation>() {
@@ -375,7 +331,7 @@ public class DataStoreImpl implements DataStore {
MetaKeySet mks = new MetaKeySet();
toCache.forEach(m -> mks.addAll(m.toKeys()));
internalMetrics.incrementMetaKeysInserted(mks.size());
muts.addAll(mks.toMutations(metric.getValue().getTimestamp()));
muts.addAll(mks.toMutations());
try {
metaWriter.get().addMutations(muts);
} catch (MutationsRejectedException e) {
@@ -440,7 +396,6 @@ public class DataStoreImpl implements DataStore {
@Override
public SuggestResponse suggest(SuggestRequest request) throws TimelyException {
SuggestResponse result = new SuggestResponse();
Scanner scanner = null;
try {
if (request.getType().equals("metrics")) {
Range range;
@@ -460,7 +415,7 @@ public class DataStoreImpl implements DataStore {
end.append(lastBytes, 0, lastBytes.length);
range = new Range(start, end);
}
scanner = connector.createScanner(metaTable, Authorizations.EMPTY);
Scanner scanner = connector.createScanner(metaTable, Authorizations.EMPTY);
scanner.setRange(range);
List<String> metrics = new ArrayList<>();
for (Entry<Key, Value> metric : scanner) {
@@ -475,10 +430,6 @@ public class DataStoreImpl implements DataStore {
LOG.error("Error during suggest: " + ex.getMessage(), ex);
throw new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(),
"Error during suggest: " + ex.getMessage(), ex.getMessage(), ex);
} finally {
if (scanner != null) {
scanner.close();
}
}
return result;
}
@@ -513,34 +464,28 @@ public class DataStoreImpl implements DataStore {
tagPatterns.put(k, Pattern.compile(v));
});
try {
final Scanner scanner = connector.createScanner(metaTable, Authorizations.EMPTY);
try {
List<Result> resultField = new ArrayList<>();
Key start = new Key(Meta.VALUE_PREFIX + msg.getQuery());
Key end = start.followingKey(PartialKey.ROW);
Range range = new Range(start, end);
scanner.setRange(range);
tags.keySet().forEach(k -> scanner.fetchColumnFamily(new Text(k)));
int total = 0;
for (Entry<Key, Value> entry : scanner) {
Meta metaEntry = Meta.parse(entry.getKey(), entry.getValue());
if (matches(metaEntry.getTagKey(), metaEntry.getTagValue(), tagPatterns)) {
if (resultField.size() < msg.getLimit()) {
Result r = new Result();
r.putTag(metaEntry.getTagKey(), metaEntry.getTagValue());
resultField.add(r);
}
total++;
List<Result> resultField = new ArrayList<>();
Scanner scanner = connector.createScanner(metaTable, Authorizations.EMPTY);
Key start = new Key(Meta.VALUE_PREFIX + msg.getQuery());
Key end = start.followingKey(PartialKey.ROW);
Range range = new Range(start, end);
scanner.setRange(range);
tags.keySet().forEach(k -> scanner.fetchColumnFamily(new Text(k)));
int total = 0;
for (Entry<Key, Value> entry : scanner) {
Meta metaEntry = Meta.parse(entry.getKey(), entry.getValue());
if (matches(metaEntry.getTagKey(), metaEntry.getTagValue(), tagPatterns)) {
if (resultField.size() < msg.getLimit()) {
Result r = new Result();
r.putTag(metaEntry.getTagKey(), metaEntry.getTagValue());
resultField.add(r);
}
}
result.setResults(resultField);
result.setTotalResults(total);
result.setTime((int) (System.currentTimeMillis() - startMillis));
} finally {
if (scanner != null) {
scanner.close();
total++;
}
}
result.setResults(resultField);
result.setTotalResults(total);
result.setTime((int) (System.currentTimeMillis() - startMillis));
} catch (Exception ex) {
LOG.error("Error during lookup: " + ex.getMessage(), ex);
throw new TimelyException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(),
@@ -809,80 +754,72 @@ public class DataStoreImpl implements DataStore {
return !REGEX_TEST.matcher(value).matches();
}
@Override
public Set<Tag> getColumnFamilies(String metric, Map<String, String> requestedTags) throws TableNotFoundException {
Scanner meta = null;
try {
Map<String, String> tags = (requestedTags == null) ? new LinkedHashMap<>() : requestedTags;
LOG.trace("Looking for requested tags: {}", tags);
meta = connector.createScanner(metaTable, Authorizations.EMPTY);
Text start = new Text(Meta.VALUE_PREFIX + metric);
Text end = new Text(Meta.VALUE_PREFIX + metric + "\\x0000");
end.append(new byte[] { (byte) 0xff }, 0, 1);
meta.setRange(new Range(start, end));
// Only look for the meta entries that match our tags, if any
boolean onlyFirstRow = false;
Entry<String, String> first = null;
// Set the columns on the meta scanner based on the first tag
// in the set of tags passed in the query. If no tags are present
// then we are only going to return the first tag name present in the
// meta table.
Iterator<Entry<String, String>> tagIter = tags.entrySet().iterator();
if (tagIter.hasNext()) {
first = tagIter.next();
if (isTagValueRegex(first.getValue())) {
meta.fetchColumnFamily(new Text(first.getKey()));
} else {
meta.fetchColumn(new Text(first.getKey()), new Text(first.getValue()));
}
Map<String, String> tags = (requestedTags == null) ? new LinkedHashMap<>() : requestedTags;
LOG.trace("Looking for requested tags: {}", tags);
Scanner meta = connector.createScanner(metaTable, Authorizations.EMPTY);
Text start = new Text(Meta.VALUE_PREFIX + metric);
Text end = new Text(Meta.VALUE_PREFIX + metric + "\\x0000");
end.append(new byte[] { (byte) 0xff }, 0, 1);
meta.setRange(new Range(start, end));
// Only look for the meta entries that match our tags, if any
boolean onlyFirstRow = false;
Entry<String, String> first = null;
// Set the columns on the meta scanner based on the first tag
// in the set of tags passed in the query. If no tags are present
// then we are only going to return the first tag name present in the
// meta table.
Iterator<Entry<String, String>> tagIter = tags.entrySet().iterator();
if (tagIter.hasNext()) {
first = tagIter.next();
if (isTagValueRegex(first.getValue())) {
meta.fetchColumnFamily(new Text(first.getKey()));
} else {
// grab all of the values found for the first tag for the metric
onlyFirstRow = true;
}
final boolean ONLY_RETURN_FIRST_TAG = onlyFirstRow;
Iterator<Entry<Key, Value>> iter = meta.iterator();
Iterator<Pair<String, String>> knownKeyValues = new Iterator<Pair<String, String>>() {
Text firstTag = null;
Text tagName = null;
Text tagValue = null;
@Override
public boolean hasNext() {
if (iter.hasNext()) {
Entry<Key, Value> metaEntry = iter.next();
if (null == firstTag) {
firstTag = metaEntry.getKey().getColumnFamily();
}
tagName = metaEntry.getKey().getColumnFamily();
tagValue = metaEntry.getKey().getColumnQualifier();
LOG.trace("Found tag entry {}={}", tagName, tagValue);
if (ONLY_RETURN_FIRST_TAG && !tagName.equals(firstTag)) {
return false;
}
return true;
}
return false;
}
@Override
public Pair<String, String> next() {
LOG.trace("Returning tag {}={}", tagName, tagValue);
return new Pair<>(tagName.toString(), tagValue.toString());
}
};
// Expand the list of tags in the meta table for this metric that
// matches
// the pattern of the first tag in the query. The resulting set of tags
// will be used to fetch specific columns from the metric table.
return expandTagValues(first, knownKeyValues);
} finally {
if (meta != null) {
meta.close();
meta.fetchColumn(new Text(first.getKey()), new Text(first.getValue()));
}
} else {
// grab all of the values found for the first tag for the metric
onlyFirstRow = true;
}
final boolean ONLY_RETURN_FIRST_TAG = onlyFirstRow;
Iterator<Entry<Key, Value>> iter = meta.iterator();
Iterator<Pair<String, String>> knownKeyValues = new Iterator<Pair<String, String>>() {
Text firstTag = null;
Text tagName = null;
Text tagValue = null;
@Override
public boolean hasNext() {
if (iter.hasNext()) {
Entry<Key, Value> metaEntry = iter.next();
if (null == firstTag) {
firstTag = metaEntry.getKey().getColumnFamily();
}
tagName = metaEntry.getKey().getColumnFamily();
tagValue = metaEntry.getKey().getColumnQualifier();
LOG.trace("Found tag entry {}={}", tagName, tagValue);
if (ONLY_RETURN_FIRST_TAG && !tagName.equals(firstTag)) {
return false;
}
return true;
}
return false;
}
@Override
public Pair<String, String> next() {
LOG.trace("Returning tag {}={}", tagName, tagValue);
return new Pair<>(tagName.toString(), tagValue.toString());
}
};
// Expand the list of tags in the meta table for this metric that
// matches
// the pattern of the first tag in the query. The resulting set of tags
// will be used to fetch specific columns from the metric table.
return expandTagValues(first, knownKeyValues);
}
private void setQueryColumns(ScannerBase scanner, String metric, Map<String, String> tags, Set<Tag> colFamValues)
@@ -953,7 +890,6 @@ public class DataStoreImpl implements DataStore {
return result;
}
@Override
public List<Range> getQueryRanges(String metric, long start, long end, Set<Tag> colFamValues) {
List<Range> ranges = new ArrayList<>();
long beginRangeRounded = MetricAdapter.roundTimestampToLastHour(start);
@@ -1016,7 +952,6 @@ public class DataStoreImpl implements DataStore {
return AuthCache.getAuthorizations(request, security);
}
@Override
public long getAgeOffForMetric(String metricName) {
String age = this.ageOff.get(MetricAgeOffIterator.AGE_OFF_PREFIX + metricName);
if (null == age) {
@@ -1026,7 +961,6 @@ public class DataStoreImpl implements DataStore {
}
}
@Override
public Scanner createScannerForMetric(AuthenticatedRequest request, String metric, Map<String, String> tags,
int scannerBatchSize, int scannerReadAhead) throws TimelyException {
try {
@@ -1,116 +0,0 @@
package timely.store;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.iterators.IteratorEnvironment;
import org.apache.accumulo.core.iterators.OptionDescriber;
import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
import org.apache.accumulo.core.iterators.WrappingIterator;
import org.apache.commons.collections4.trie.PatriciaTrie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.model.Meta;
public class MetaAgeOffIterator extends WrappingIterator implements OptionDescriber {
private static final Logger LOG = LoggerFactory.getLogger(MetaAgeOffIterator.class);
public static final String AGE_OFF_PREFIX = "ageoff.";
public static final String DEFAULT_AGEOFF_KEY = "default";
/* set in init */
private PatriciaTrie<Long> ageoffs = null;
private Long currentTime = 0L;
private Long defaultAgeOff = 0L;
private Long minAgeOff = Long.MAX_VALUE;
private Long maxAgeOff = Long.MIN_VALUE;
@Override
public SortedKeyValueIterator<Key, Value> deepCopy(IteratorEnvironment env) {
MetaAgeOffIterator iter = new MetaAgeOffIterator();
iter.ageoffs = this.ageoffs;
iter.defaultAgeOff = this.defaultAgeOff;
iter.currentTime = this.currentTime;
iter.minAgeOff = this.minAgeOff;
iter.maxAgeOff = this.maxAgeOff;
return iter;
}
@Override
public void init(SortedKeyValueIterator<Key, Value> source, Map<String, String> options, IteratorEnvironment env)
throws IOException {
super.init(source, options, env);
validateOptions(options);
ageoffs = new PatriciaTrie<>();
options.forEach((k, v) -> {
if (k.startsWith(AGE_OFF_PREFIX)) {
String name = k.substring(AGE_OFF_PREFIX.length());
LOG.trace("Adding {} to Trie with value {}", name, Long.parseLong(v));
long ageoff = Long.parseLong(v);
this.minAgeOff = Math.min(this.minAgeOff, ageoff);
this.maxAgeOff = Math.max(this.maxAgeOff, ageoff);
ageoffs.put(name, ageoff);
}
});
defaultAgeOff = ageoffs.get(DEFAULT_AGEOFF_KEY);
currentTime = System.currentTimeMillis();
}
@Override
public void next() throws IOException {
super.next();
skipExpiredData();
}
@Override
public void seek(Range range, Collection<ByteSequence> columnFamilies, boolean inclusive) throws IOException {
super.seek(range, columnFamilies, inclusive);
skipExpiredData();
}
private void skipExpiredData() throws IOException {
boolean done = false;
while (!done && super.hasTop()) {
Key top = super.getTopKey();
long dataAge = this.currentTime - top.getTimestamp();
// If less than any configured ageoff, then we want to return this K,V
if (dataAge < this.minAgeOff) {
done = true;
} else {
String metricName = Meta.parse(top).getMetric();
long metaAgeOff = ageoffs.getOrDefault(metricName, defaultAgeOff);
if (dataAge > metaAgeOff) {
// data beyond ageOff, so skip
super.next();
} else {
done = true;
}
}
}
}
@Override
public IteratorOptions describeOptions() {
return new IteratorOptions("meta-age-off", "Iterator that ages off meta entries for Timely metrics",
Collections.singletonMap(AGE_OFF_PREFIX + DEFAULT_AGEOFF_KEY, "default age off days"),
Collections.singletonList("Additional meta age off properties where the value is specified as "
+ AGE_OFF_PREFIX
+ " the metric name and the value is an integer representing the number of days to keep"));
}
@Override
public boolean validateOptions(Map<String, String> options) {
if (null == options.get(AGE_OFF_PREFIX + DEFAULT_AGEOFF_KEY)) {
throw new IllegalArgumentException(DEFAULT_AGEOFF_KEY + " must be configured for MetaAgeOffFilter");
}
return true;
}
}
@@ -1,125 +1,27 @@
package timely.store;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
import org.apache.accumulo.core.client.ClientConfiguration;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.Instance;
import org.apache.accumulo.core.client.Scanner;
import org.apache.accumulo.core.client.TableNotFoundException;
import org.apache.accumulo.core.client.ZooKeeperInstance;
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Range;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.Authorizations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.model.Meta;
import timely.configuration.Accumulo;
import timely.configuration.Configuration;
public class MetaCacheImpl implements MetaCache {
private static Logger LOG = LoggerFactory.getLogger(MetaCacheImpl.class);
private static final Object DUMMY = new Object();
private volatile boolean closed = false;
private Cache<Meta, Object> cache = null;
private Configuration configuration;
private Timer timer = new Timer("MetaCacheImpl", true);
@Override
public void init(Configuration config) {
configuration = config;
cache = Caffeine.newBuilder().initialCapacity(1000).build();
long cacheRefreshMinutes = configuration.getMetaCache().getCacheRefreshMinutes();
if (cacheRefreshMinutes > 0) {
timer.schedule(new TimerTask() {
@Override
public void run() {
refreshCache(config.getMetaCache().getExpirationMinutes());
}
}, 60000, cacheRefreshMinutes * 60 * 1000);
}
}
private void refreshCache(long expirationMinutes) {
long oldestTimestamp = System.currentTimeMillis() - (expirationMinutes * 60 * 1000);
Map<String, String> properties = new HashMap<>();
Accumulo accumuloConf = configuration.getAccumulo();
properties.put("instance.name", accumuloConf.getInstanceName());
properties.put("instance.zookeeper.host", accumuloConf.getZookeepers());
final ClientConfiguration aConf = ClientConfiguration.fromMap(properties);
String metaTable = configuration.getMetaTable();
Map<String, Map<String, Long>> metricMap = new HashMap<>();
Scanner scanner = null;
try {
Map<Meta, Object> newCache = new HashMap<>();
final Instance instance = new ZooKeeperInstance(aConf);
Connector connector = instance.getConnector(accumuloConf.getUsername(),
new PasswordToken(accumuloConf.getPassword()));
scanner = connector.createScanner(metaTable, Authorizations.EMPTY);
LOG.debug("Begin scanning " + metaTable);
Range metricRange = new Range(new Key(Meta.METRIC_PREFIX), true, new Key(Meta.METRIC_PREFIX + '\0'), false);
scanner.setRange(metricRange);
Set<String> allMetrics = new TreeSet<>();
for (Map.Entry<Key, Value> entry : scanner) {
Meta meta = Meta.parse(entry.getKey(), entry.getValue(), Meta.METRIC_PREFIX);
allMetrics.add(meta.getMetric());
}
for (String currMetric : allMetrics) {
Key begin = new Key(Meta.VALUE_PREFIX + currMetric);
Key end = new Key(Meta.VALUE_PREFIX + currMetric + '\0');
Range range = new Range(begin, true, end, false);
scanner.setRange(range);
Iterator<Map.Entry<Key, Value>> itr = scanner.iterator();
boolean maxedOutValues = false;
while (itr.hasNext() && !maxedOutValues) {
Map.Entry<Key, Value> entry = itr.next();
Meta meta = Meta.parse(entry.getKey(), entry.getValue(), Meta.VALUE_PREFIX);
String metric = meta.getMetric();
String tagKey = meta.getTagKey();
Map<String, Long> tagMap = metricMap.get(metric);
if (tagMap == null) {
tagMap = new HashMap<>();
metricMap.put(metric, tagMap);
}
long numTagValues = tagMap.getOrDefault(tagKey, 0l);
if (entry.getKey().getTimestamp() > oldestTimestamp) {
tagMap.put(tagKey, ++numTagValues);
if (numTagValues <= configuration.getMetaCache().getMaxTagValues()) {
newCache.put(meta, DUMMY);
} else {
// found maxTagValues on this refresh
maxedOutValues = true;
}
}
}
}
synchronized (cache) {
cache.invalidateAll();
cache.putAll(newCache);
}
LOG.debug("Finished scanning " + metaTable);
} catch (AccumuloException | AccumuloSecurityException | TableNotFoundException e) {
LOG.error(e.getMessage(), e);
} finally {
if (scanner != null) {
scanner.close();
}
}
long expirationMinutes = config.getMetaCache().getExpirationMinutes();
int initialCapacity = config.getMetaCache().getInitialCapacity();
long maxCapacity = config.getMetaCache().getMaxCapacity();
cache = Caffeine.newBuilder().expireAfterAccess(expirationMinutes, TimeUnit.MINUTES)
.initialCapacity(initialCapacity).maximumSize(maxCapacity).build();
}
@Override
@@ -151,4 +53,5 @@ public class MetaCacheImpl implements MetaCache {
public boolean isClosed() {
return closed;
}
}
Loaded 100 of 162 files, more files were not shown because too many files have changed in this diff. Show more