mirror of
https://github.com/NationalSecurityAgency/timely.git
synced 2026-11-10 03:41:25 -10:00
Compare commits
7
Commits
ws_grafana
...
wamp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d18b5bc46d | ||
|
|
ba60f9ef00 | ||
|
|
49a8d970fe | ||
|
|
345f4b7006 | ||
|
|
b81783f7ea | ||
|
|
1be6f24676 | ||
|
|
82b94f1a71 |
No files matched your search
@@ -4,3 +4,4 @@
|
||||
target/
|
||||
.idea/
|
||||
*.iml
|
||||
logs/
|
||||
@@ -3,3 +3,4 @@ Eric Newton ([email protected])
|
||||
Jim Klucar ([email protected])
|
||||
Charlie Williams ([email protected])
|
||||
Drew Farris ([email protected])
|
||||
Brian Loss ([email protected])
|
||||
@@ -51,12 +51,11 @@
|
||||
<version.jackson>2.6.1</version.jackson>
|
||||
<version.javassist>3.20.0-GA</version.javassist>
|
||||
<version.jcip-annotations>1.0</version.jcip-annotations>
|
||||
<version.junit>4.11</version.junit>
|
||||
<version.junit>4.12</version.junit>
|
||||
<version.log4j>2.5</version.log4j>
|
||||
<version.netty>4.0.38.Final</version.netty>
|
||||
<version.netty-tcnative>1.1.33.Fork18</version.netty-tcnative>
|
||||
<version.powermock>1.6.4</version.powermock>
|
||||
<version.security>4.0.4.RELEASE</version.security>
|
||||
<version.slf4j>1.7.12</version.slf4j>
|
||||
<!-- plugin versions -->
|
||||
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
|
||||
@@ -72,6 +71,8 @@
|
||||
<version.maven-rpm>2.1.4</version.maven-rpm>
|
||||
<version.maven-shade>2.4.2</version.maven-shade>
|
||||
<version.maven-surefire>2.19.1</version.maven-surefire>
|
||||
<version.jawampa>0.4.2</version.jawampa>
|
||||
<version.spring.boot>1.4.0.RELEASE</version.spring.boot>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -113,6 +114,11 @@
|
||||
<version>${version.disruptor}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>LATEST</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
@@ -264,21 +270,28 @@
|
||||
<classifier>full</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
<version>${version.security}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
<version>${version.security}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${version.slf4j}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ws.wamp.jawampa</groupId>
|
||||
<artifactId>jawampa-core</artifactId>
|
||||
<version>${version.jawampa}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ws.wamp.jawampa</groupId>
|
||||
<artifactId>jawampa-netty</artifactId>
|
||||
<version>${version.jawampa}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${version.spring.boot}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<build>
|
||||
|
||||
@@ -9,12 +9,11 @@ fi
|
||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||
BASE_DIR=${THIS_DIR}/..
|
||||
CONF_DIR="${BASE_DIR}/conf"
|
||||
CONF_FILE="${CONF_DIR}/timely.properties"
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
|
||||
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
|
||||
JVM_ARGS="-Xmx256m -Xms128m -Dlog4j.configurationFile=${THIS_DIR}/log4j2.xml"
|
||||
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||
|
||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints "${CONF_FILE}""
|
||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints "${CONF_FILE}"
|
||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints --spring.config.name=timely"
|
||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints --spring.config.name=timely
|
||||
@@ -8,8 +8,6 @@ fi
|
||||
|
||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||
BASE_DIR=${THIS_DIR}/..
|
||||
CONF_DIR="${BASE_DIR}/conf"
|
||||
CONF_FILE="${CONF_DIR}/timely.properties"
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
NUM_SERVER_THREADS=4
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ fi
|
||||
|
||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||
BASE_DIR=${THIS_DIR}/..
|
||||
CONF_DIR="${BASE_DIR}/conf"
|
||||
CONF_FILE="${CONF_DIR}/timely.properties"
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
NUM_SERVER_THREADS=4
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
||||
BASE_DIR=${THIS_DIR}/..
|
||||
TMP_DIR="${BASE_DIR}/tmp"
|
||||
CONF_DIR="${BASE_DIR}/conf"
|
||||
CONF_FILE="${CONF_DIR}/timely.properties"
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
NUM_SERVER_THREADS=4
|
||||
|
||||
@@ -41,6 +40,6 @@ JVM_ARGS="-Xmx256m -Xms256m -Dio.netty.eventLoopThreads=${NUM_SERVER_THREADS} -D
|
||||
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||
JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}/libnetty-${TCNATIVE_SUFFIX}"
|
||||
|
||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server "${CONF_FILE}""
|
||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server "${CONF_FILE}"
|
||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server --spring.config.name=timely"
|
||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.Server --spring.config.name=timely
|
||||
|
||||
@@ -18,7 +18,6 @@ NATIVE_DIR="${THIS_DIR}/META-INF/native"
|
||||
BASE_DIR=${THIS_DIR}/..
|
||||
TMP_DIR="${BASE_DIR}/tmp"
|
||||
CONF_DIR="${BASE_DIR}/conf"
|
||||
CONF_FILE="${CONF_DIR}/timely-standalone.properties"
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
NUM_SERVER_THREADS=4
|
||||
|
||||
@@ -43,6 +42,6 @@ JVM_ARGS="${JVM_ARGS} -Djava.library.path=${NATIVE_DIR}"
|
||||
# for debugging
|
||||
#JVM_ARGS="${JVM_ARGS} -agentlib:jdwp=transport=dt_socket,address=54323,server=y,suspend=y"
|
||||
|
||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${CONF_FILE}" "${TMP_DIR}""
|
||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${CONF_FILE}" "${TMP_DIR}"
|
||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${TMP_DIR}" --spring.config.name=timely --spring.profiles.active=standalone"
|
||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.StandaloneServer "${TMP_DIR}" --spring.config.name=timely --spring.profiles.active=standalone
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
timely.ip=0.0.0.0
|
||||
timely.port.put=54321
|
||||
timely.port.query=54322
|
||||
timely.port.websocket=54323
|
||||
timely.instance_name=TimelyStandalone
|
||||
timely.zookeepers=127.0.0.1:9804
|
||||
timely.username=root
|
||||
timely.password=secret
|
||||
timely.table=timely.metrics
|
||||
timely.meta=timely.meta
|
||||
timely.write.latency=5s
|
||||
timely.write.threads=3
|
||||
timely.write.buffer.size=52428800
|
||||
timely.metric.age.off.days=7
|
||||
timely.cors.allow.any.origin=true
|
||||
timely.cors.allow.null.origin=false
|
||||
timely.cors.allowed.origins=
|
||||
timely.cors.allowed.methods=DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||
timely.cors.allowed.headers=content-type
|
||||
timely.cors.allow.credentials=true
|
||||
timely.scanner.threads=4
|
||||
timely.metrics.report.tags.ignored=
|
||||
timely.meta.cache.expiration.minutes=60
|
||||
timely.meta.cache.initial.capacity=2000
|
||||
timely.meta.cache.max.capacity=10000
|
||||
timely.ssl.certificate.file=/timely-server-src/bin/docker/grafana/pki/timely-cert.pem
|
||||
timely.ssl.key.file=/timely-server-src/bin/docker/grafana/pki/timely-pkcs8-key.pem
|
||||
timely.ssl.key.pass=timely
|
||||
timely.ssl.use.generated.keypair=false
|
||||
timely.ssl.trust.store.file=/timely-server-src/bin/docker/grafana/pki/timely-ca.pem
|
||||
timely.ssl.use.openssl=true
|
||||
#timely.ssl.use.ciphers=
|
||||
timely.session.max.age=86400
|
||||
timely.http.host=localhost
|
||||
timely.allow.anonymous.access=true
|
||||
timely.web.socket.timeout=60
|
||||
timely.ws.subscription.lag=120
|
||||
timely.http.redirect.path=/secure-me
|
||||
timely.hsts.max.age=608400
|
||||
@@ -0,0 +1,55 @@
|
||||
timely:
|
||||
metrics-table: timely.metrics
|
||||
meta-table: timely.meta
|
||||
metric-age-off-days: 7
|
||||
metrics-report-ignored-tags:
|
||||
accumulo:
|
||||
instance-name: TimelyStandalone
|
||||
zookeepers: 127.0.0.1:9804
|
||||
username: root
|
||||
password: secret
|
||||
write:
|
||||
latency: 5s
|
||||
threads: 3
|
||||
bufferSize: 52428800
|
||||
scan:
|
||||
threads: 4
|
||||
security:
|
||||
session-max-age: 86400
|
||||
allow-anonymous-access: true
|
||||
ssl:
|
||||
certificate-file:
|
||||
key-file:
|
||||
key-password: timely
|
||||
use-generated-keypair: true
|
||||
trust-store-file:
|
||||
use-openssl: false
|
||||
server:
|
||||
ip: 0.0.0.0
|
||||
tcp-port: 54321
|
||||
http:
|
||||
ip: 0.0.0.0
|
||||
port: 54322
|
||||
host: localhost
|
||||
redirect-path: /secure-me
|
||||
strict-transport-max-age: 608400
|
||||
cors:
|
||||
allow-any-origin: true
|
||||
allow-null-origin: false
|
||||
allow-credentials: true
|
||||
allowed-origins:
|
||||
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||
allowed-header: content-type
|
||||
websocket:
|
||||
ip: 0.0.0.0
|
||||
port: 54323
|
||||
timeout: 60
|
||||
subscription-lag: 120
|
||||
meta-cache:
|
||||
expiration-minutes: 60
|
||||
initial-capacity: 2000
|
||||
max-capacity: 10000
|
||||
visibility-cache:
|
||||
expiration-minutes: 60
|
||||
initial-capacity: 2000
|
||||
max-capacity: 10000
|
||||
@@ -1,39 +0,0 @@
|
||||
timely.ip=
|
||||
timely.port.put=
|
||||
timely.port.query=
|
||||
timely.port.websocket=
|
||||
timely.instance_name=
|
||||
timely.zookeepers=
|
||||
timely.username=
|
||||
timely.password=
|
||||
timely.table=timely.metrics
|
||||
timely.meta=timely.meta
|
||||
timely.write.latency=5s
|
||||
timely.write.threads=3
|
||||
timely.write.buffer.size=52428800
|
||||
timely.metric.age.off.days=7
|
||||
timely.cors.allow.any.origin=false
|
||||
timely.cors.allow.null.origin=false
|
||||
timely.cors.allowed.origins=
|
||||
timely.cors.allowed.methods=DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||
timely.cors.allowed.headers=content-type
|
||||
timely.cors.allow.credentials=true
|
||||
timely.scanner.threads=4
|
||||
timely.metrics.report.tags.ignored=
|
||||
timely.meta.cache.expiration.minutes=60
|
||||
timely.meta.cache.initial.capacity=2000
|
||||
timely.meta.cache.max.capacity=10000
|
||||
timely.ssl.certificate.file=
|
||||
timely.ssl.key.file=
|
||||
timely.ssl.key.pass=
|
||||
timely.ssl.use.generated.keypair=false
|
||||
timely.ssl.trust.store.file=
|
||||
timely.ssl.use.openssl=true
|
||||
timely.ssl.use.ciphers=
|
||||
timely.session.max.age=86400
|
||||
timely.http.host=
|
||||
timely.allow.anonymous.access=false
|
||||
timely.web.socket.timeout=60
|
||||
timely.ws.subscription.lag=120
|
||||
timely.http.redirect.path=/secure-me
|
||||
timely.hsts.max.age=608400
|
||||
@@ -0,0 +1,56 @@
|
||||
timely:
|
||||
metrics-table: timely.metrics
|
||||
meta-table: timely.meta
|
||||
metric-age-off-days: 7
|
||||
metrics-report-ignored-tags:
|
||||
accumulo:
|
||||
instance-name:
|
||||
zookeepers:
|
||||
username:
|
||||
password:
|
||||
write:
|
||||
latency: 5s
|
||||
threads: 3
|
||||
bufferSize: 52428800
|
||||
scan:
|
||||
threads: 4
|
||||
security:
|
||||
session-max-age: 86400
|
||||
allow-anonymous-access: false
|
||||
ssl:
|
||||
certificate-file:
|
||||
key-file:
|
||||
key-password:
|
||||
use-generated-keypair: false
|
||||
trust-store-file:
|
||||
use-openssl: true
|
||||
#use-ciphers:
|
||||
server:
|
||||
ip:
|
||||
tcp-port:
|
||||
http:
|
||||
host:
|
||||
ip:
|
||||
port:
|
||||
redirect-path: /secure-me
|
||||
strict-transport-max-age: 608400
|
||||
cors:
|
||||
allow-any-origin: false
|
||||
allow-null-origin: false
|
||||
allow-credentials: true
|
||||
allowed-origins:
|
||||
allowed-methods: DELETE,GET,HEAD,OPTIONS,PUT,POST
|
||||
allowed-headers: content-type
|
||||
websocket:
|
||||
ip:
|
||||
port:
|
||||
timeout: 60
|
||||
subscription-lag: 120
|
||||
meta-cache:
|
||||
expiration-minutes: 60
|
||||
initial-capacity: 2000
|
||||
max-capacity: 10000
|
||||
visibility-cache:
|
||||
expiration-minutes: 60
|
||||
initial-capacity: 2000
|
||||
max-capacity: 10000
|
||||
+43
-3
@@ -32,6 +32,10 @@
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lmax</groupId>
|
||||
<artifactId>disruptor</artifactId>
|
||||
@@ -52,6 +56,12 @@
|
||||
<classifier>${os.detected.classifier}</classifier>
|
||||
<!-- Eclipse doesn't like this, but it works on the cmd line -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||
<version>${version.netty-tcnative}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
@@ -113,6 +123,29 @@
|
||||
<artifactId>javassist</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
@@ -125,6 +158,14 @@
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ws.wamp.jawampa</groupId>
|
||||
<artifactId>jawampa-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ws.wamp.jawampa</groupId>
|
||||
<artifactId>jawampa-netty</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<extensions>
|
||||
@@ -197,7 +238,7 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.dir}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
|
||||
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
|
||||
<includes>
|
||||
<include>**/*.java</include>
|
||||
</includes>
|
||||
@@ -245,7 +286,7 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.dir}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
|
||||
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
|
||||
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
@@ -390,7 +431,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<version>${version.maven-pmd}</version>
|
||||
<configuration>
|
||||
<targetJdk>1.8</targetJdk>
|
||||
</configuration>
|
||||
|
||||
@@ -1,196 +1,607 @@
|
||||
package timely;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.accumulo.core.client.BatchWriterConfig;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hadoop.fs.FileSystem;
|
||||
import org.apache.hadoop.fs.Path;
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
import timely.validator.NotEmptyIfFieldSet;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "timely")
|
||||
public class Configuration {
|
||||
|
||||
public static final String IP = "timely.ip";
|
||||
public static final String PUT_PORT = "timely.port.put";
|
||||
public static final String QUERY_PORT = "timely.port.query";
|
||||
public static final String WEBSOCKET_PORT = "timely.port.websocket";
|
||||
public static final String ZOOKEEPERS = "timely.zookeepers";
|
||||
public static final String INSTANCE_NAME = "timely.instance_name";
|
||||
public static final String USERNAME = "timely.username";
|
||||
public static final String PASSWORD = "timely.password";
|
||||
public static final String METRICS_TABLE = "timely.table";
|
||||
private static final String METRICS_TABLE_DEFAULT = "timely.metrics";
|
||||
public static final String META_TABLE = "timely.meta";
|
||||
private static final String META_TABLE_DEFAULT = "timely.meta";
|
||||
public static final String METRICS_AGEOFF_DAYS = "timely.metric.age.off.days";
|
||||
private static final String METRICS_AGEOFF_DAYS_DEFAULT = "7";
|
||||
private String metricsTable = "timely.metrics";
|
||||
private String metaTable = "timely.meta";
|
||||
private int metricAgeOffDays = 7;
|
||||
private List<String> metricsReportIgnoredTags = new ArrayList<>();
|
||||
|
||||
public static final String MAX_LATENCY = "timely.write.latency";
|
||||
private static final String MAX_LATENCY_DEFAULT = "5s";
|
||||
public static final String WRITE_THREADS = "timely.write.threads";
|
||||
public static final String WRITE_BUFFER_SIZE = "timely.write.buffer.size";
|
||||
public static final String SCANNER_THREADS = "timely.scanner.threads";
|
||||
|
||||
public static final String CORS_ALLOW_ANY_ORIGIN = "timely.cors.allow.any.origin";
|
||||
private static final String CORS_ALLOW_ANY_ORIGIN_DEFAULT = "false";
|
||||
public static final String CORS_ALLOW_NULL_ORIGIN = "timely.cors.allow.null.origin";
|
||||
private static final String CORS_ALLOW_NULL_ORIGIN_DEFAULT = "false";
|
||||
public static final String CORS_ALLOWED_ORIGINS = "timely.cors.allowed.origins";
|
||||
private static final String CORS_ALLOWED_ORIGINS_DEFAULT = "";
|
||||
public static final String CORS_ALLOWED_METHODS = "timely.cors.allowed.methods";
|
||||
private static final String CORS_ALLOWED_METHODS_DEFAULT = "DELETE,GET,HEAD,OPTIONS,PUT,POST";
|
||||
public static final String CORS_ALLOWED_HEADERS = "timely.cors.allowed.headers";
|
||||
private static final String CORS_ALLOWED_HEADERS_DEFAULT = "content-type";
|
||||
public static final String CORS_ALLOW_CREDENTIALS = "timely.cors.allow.credentials";
|
||||
private static final String CORS_ALLOW_CREDENTIALS_DEFAULT = "true";
|
||||
|
||||
public static final String METRICS_IGNORED_TAGS = "timely.metrics.report.tags.ignored";
|
||||
|
||||
public static final String META_CACHE_EXPIRATION = "timely.meta.cache.expiration.minutes";
|
||||
public static final Long META_CACHE_EXPIRATION_DEFAULT = 60L;
|
||||
public static final String META_CACHE_INITIAL_CAPACITY = "timely.meta.cache.initial.capacity";
|
||||
public static final Integer META_CACHE_INITIAL_CAPACITY_DEFAULT = 2000;
|
||||
public static final String META_CACHE_MAX_CAPACITY = "timely.meta.cache.max.capacity";
|
||||
public static final Integer META_CACHE_MAX_CAPACITY_DEFAULT = 10000;
|
||||
|
||||
public static final String VISIBILITY_CACHE_EXPIRATION = "timely.visibility.cache.expiration.minutes";
|
||||
public static final Long VISIBILITY_EXPIRATION_DEFAULT = 60L;
|
||||
public static final String VISIBILITY_CACHE_INITIAL_CAPACITY = "timely.visibility.cache.initial.capacity";
|
||||
public static final Integer VISIBILITY_CACHE_INITIAL_CAPACITY_DEFAULT = 2000;
|
||||
public static final String VISIBILITY_CACHE_MAX_CAPACITY = "timely.visibility.cache.max.capacity";
|
||||
public static final Integer VISIBILITY_CACHE_MAX_CAPACITY_DEFAULT = 10000;
|
||||
|
||||
/** Security properties */
|
||||
public static final String SSL_CERTIFICATE_FILE = "timely.ssl.certificate.file";
|
||||
public static final String SSL_PRIVATE_KEY_FILE = "timely.ssl.key.file";
|
||||
public static final String SSL_PRIVATE_KEY_PASS = "timely.ssl.key.pass";
|
||||
public static final String SSL_USE_GENERATED_KEYPAIR = "timely.ssl.use.generated.keypair";
|
||||
private static final String SSL_USE_GENERATED_KEYPAIR_DEFAULT = "false";
|
||||
public static final String SSL_TRUST_STORE_FILE = "timely.ssl.trust.store.file";
|
||||
public static final String SSL_USE_OPENSSL = "timely.ssl.use.openssl";
|
||||
private static final String SSL_USE_OPENSSL_DEFAULT = "true";
|
||||
public static final String SSL_USE_CIPHERS = "timely.ssl.use.ciphers";
|
||||
private static final String SSL_USE_CIPHERS_DEFAULT = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:"
|
||||
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_RSA_WITH_AES_128_GCM_SHA256:"
|
||||
+ "TLS_RSA_WITH_AES_128_CBC_SHA:SSL_RSA_WITH_3DES_EDE_CBC_SHA";
|
||||
|
||||
public static final String SESSION_MAX_AGE = "timely.session.max.age";
|
||||
public static final long SESSION_MAX_AGE_DEFAULT = 86400;
|
||||
public static final String TIMELY_HTTP_HOST = "timely.http.host";
|
||||
public static final String ALLOW_ANONYMOUS_ACCESS = "timely.allow.anonymous.access";
|
||||
private static final String ALLOW_ANONYMOUS_ACCESS_DEFAULT = "false";
|
||||
|
||||
public static final String WS_TIMEOUT_SECONDS = "timely.web.socket.timeout";
|
||||
private static final String WS_TIMEOUT_SECONDS_DEFAULT = "60";
|
||||
public static final String WS_SUBSCRIPTION_LAG = "timely.ws.subscription.lag";
|
||||
private static final String WS_SUBSCRIPTION_LAG_DEFAULT = "120";
|
||||
|
||||
public static final String NON_SECURE_REDIRECT_PATH = "timely.http.redirect.path";
|
||||
private static final String NON_SECURE_REDIRECT_PATH_DEFAULT = "/secure-me";
|
||||
public static final String STRICT_TRANSPORT_MAX_AGE = "timely.hsts.max.age";
|
||||
private static final String STRICT_TRANSPORT_MAX_AGE_DEFAULT = "604800";
|
||||
|
||||
private static final List<String> REQUIRED_PROPERTIES = new ArrayList<>();
|
||||
static {
|
||||
REQUIRED_PROPERTIES.add(IP);
|
||||
REQUIRED_PROPERTIES.add(PUT_PORT);
|
||||
REQUIRED_PROPERTIES.add(QUERY_PORT);
|
||||
REQUIRED_PROPERTIES.add(WEBSOCKET_PORT);
|
||||
REQUIRED_PROPERTIES.add(ZOOKEEPERS);
|
||||
REQUIRED_PROPERTIES.add(INSTANCE_NAME);
|
||||
REQUIRED_PROPERTIES.add(USERNAME);
|
||||
REQUIRED_PROPERTIES.add(PASSWORD);
|
||||
REQUIRED_PROPERTIES.add(TIMELY_HTTP_HOST);
|
||||
};
|
||||
|
||||
private final Properties props = new Properties();
|
||||
|
||||
public Configuration(Path path) throws IOException {
|
||||
org.apache.hadoop.conf.Configuration hadoopConf = new org.apache.hadoop.conf.Configuration();
|
||||
try (FileSystem fs = FileSystem.get(hadoopConf)) {
|
||||
try (InputStream inputStream = fs.open(path)) {
|
||||
init(inputStream);
|
||||
}
|
||||
}
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Accumulo accumulo = new Accumulo();
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Security security = new Security();
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Server server = new Server();
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Http http = new Http();
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private MetaCache metaCache = new MetaCache();
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private VisibilityCache visibilityCache = new VisibilityCache();
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Websocket websocket = new Websocket();
|
||||
|
||||
public String getMetricsTable() {
|
||||
return metricsTable;
|
||||
}
|
||||
|
||||
public Configuration(File conf) throws IOException {
|
||||
try (InputStream inputStream = new FileInputStream(conf)) {
|
||||
init(inputStream);
|
||||
public Configuration setMetricsTable(String metricsTable) {
|
||||
this.metricsTable = metricsTable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMetaTable() {
|
||||
return metaTable;
|
||||
}
|
||||
|
||||
public Configuration setMetaTable(String metaTable) {
|
||||
this.metaTable = metaTable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getMetricAgeOffDays() {
|
||||
return metricAgeOffDays;
|
||||
}
|
||||
|
||||
public Configuration setMetricAgeOffDays(int metricAgeOffDays) {
|
||||
this.metricAgeOffDays = metricAgeOffDays;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<String> getMetricsReportIgnoredTags() {
|
||||
return metricsReportIgnoredTags;
|
||||
}
|
||||
|
||||
public Configuration setMetricsReportIgnoredTags(List<String> metricsReportIgnoredTags) {
|
||||
this.metricsReportIgnoredTags = metricsReportIgnoredTags;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Accumulo getAccumulo() {
|
||||
return accumulo;
|
||||
}
|
||||
|
||||
public Security getSecurity() {
|
||||
return security;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public Http getHttp() {
|
||||
return http;
|
||||
}
|
||||
|
||||
public Websocket getWebsocket() {
|
||||
return websocket;
|
||||
}
|
||||
|
||||
public MetaCache getMetaCache() {
|
||||
return metaCache;
|
||||
}
|
||||
|
||||
public VisibilityCache getVisibilityCache() {
|
||||
return visibilityCache;
|
||||
}
|
||||
|
||||
public class Accumulo {
|
||||
|
||||
@NotBlank
|
||||
private String zookeepers;
|
||||
@NotBlank
|
||||
private String instanceName;
|
||||
@NotBlank
|
||||
private String username;
|
||||
@NotBlank
|
||||
private String password;
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Write write = new Write();
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Scan scan = new Scan();
|
||||
|
||||
public String getInstanceName() {
|
||||
return instanceName;
|
||||
}
|
||||
|
||||
public String getZookeepers() {
|
||||
return zookeepers;
|
||||
}
|
||||
|
||||
public Configuration setZookeepers(String zookeepers) {
|
||||
this.zookeepers = zookeepers;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public Write getWrite() {
|
||||
return write;
|
||||
}
|
||||
|
||||
public Scan getScan() {
|
||||
return scan;
|
||||
}
|
||||
|
||||
public Configuration setInstanceName(String instanceName) {
|
||||
this.instanceName = instanceName;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public Configuration setUsername(String username) {
|
||||
this.username = username;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public Configuration setPassword(String password) {
|
||||
this.password = password;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
private void init(InputStream configStream) throws IOException {
|
||||
// Add defaults
|
||||
props.setProperty(METRICS_TABLE, METRICS_TABLE_DEFAULT);
|
||||
props.setProperty(META_TABLE, META_TABLE_DEFAULT);
|
||||
props.setProperty(MAX_LATENCY, MAX_LATENCY_DEFAULT);
|
||||
props.setProperty(METRICS_AGEOFF_DAYS, METRICS_AGEOFF_DAYS_DEFAULT);
|
||||
final BatchWriterConfig defaults = new BatchWriterConfig();
|
||||
props.setProperty(WRITE_BUFFER_SIZE, "" + defaults.getMaxMemory());
|
||||
props.setProperty(WRITE_THREADS, "" + defaults.getMaxWriteThreads());
|
||||
props.setProperty(SCANNER_THREADS, "" + 4);
|
||||
props.setProperty(CORS_ALLOW_ANY_ORIGIN, CORS_ALLOW_ANY_ORIGIN_DEFAULT);
|
||||
props.setProperty(CORS_ALLOW_NULL_ORIGIN, CORS_ALLOW_NULL_ORIGIN_DEFAULT);
|
||||
props.setProperty(CORS_ALLOWED_ORIGINS, CORS_ALLOWED_ORIGINS_DEFAULT);
|
||||
props.setProperty(CORS_ALLOWED_METHODS, CORS_ALLOWED_METHODS_DEFAULT);
|
||||
props.setProperty(CORS_ALLOWED_HEADERS, CORS_ALLOWED_HEADERS_DEFAULT);
|
||||
props.setProperty(CORS_ALLOW_CREDENTIALS, CORS_ALLOW_CREDENTIALS_DEFAULT);
|
||||
props.setProperty(META_CACHE_EXPIRATION, "" + META_CACHE_EXPIRATION_DEFAULT);
|
||||
props.setProperty(META_CACHE_INITIAL_CAPACITY, "" + META_CACHE_INITIAL_CAPACITY_DEFAULT);
|
||||
props.setProperty(META_CACHE_MAX_CAPACITY, "" + META_CACHE_MAX_CAPACITY_DEFAULT);
|
||||
props.setProperty(SSL_USE_GENERATED_KEYPAIR, SSL_USE_GENERATED_KEYPAIR_DEFAULT);
|
||||
props.setProperty(SSL_USE_OPENSSL, SSL_USE_OPENSSL_DEFAULT);
|
||||
props.setProperty(SSL_USE_CIPHERS, SSL_USE_CIPHERS_DEFAULT);
|
||||
props.setProperty(ALLOW_ANONYMOUS_ACCESS, ALLOW_ANONYMOUS_ACCESS_DEFAULT);
|
||||
props.setProperty(SESSION_MAX_AGE, SESSION_MAX_AGE_DEFAULT + "");
|
||||
public class Write {
|
||||
|
||||
props.setProperty(VISIBILITY_CACHE_EXPIRATION, VISIBILITY_EXPIRATION_DEFAULT + "");
|
||||
props.setProperty(VISIBILITY_CACHE_INITIAL_CAPACITY, VISIBILITY_CACHE_INITIAL_CAPACITY_DEFAULT + "");
|
||||
props.setProperty(VISIBILITY_CACHE_MAX_CAPACITY, VISIBILITY_CACHE_MAX_CAPACITY_DEFAULT + "");
|
||||
private String latency = "5s";
|
||||
private int threads;
|
||||
private String bufferSize;
|
||||
|
||||
props.setProperty(WS_TIMEOUT_SECONDS, WS_TIMEOUT_SECONDS_DEFAULT);
|
||||
props.setProperty(WS_SUBSCRIPTION_LAG, WS_SUBSCRIPTION_LAG_DEFAULT);
|
||||
public Write() {
|
||||
BatchWriterConfig config = new BatchWriterConfig();
|
||||
threads = config.getMaxWriteThreads();
|
||||
bufferSize = Long.toString(config.getMaxMemory());
|
||||
}
|
||||
|
||||
props.setProperty(NON_SECURE_REDIRECT_PATH, NON_SECURE_REDIRECT_PATH_DEFAULT);
|
||||
props.setProperty(STRICT_TRANSPORT_MAX_AGE, STRICT_TRANSPORT_MAX_AGE_DEFAULT);
|
||||
public String getLatency() {
|
||||
return latency;
|
||||
}
|
||||
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(configStream, StandardCharsets.UTF_8))) {
|
||||
props.load(reader);
|
||||
validate();
|
||||
public Configuration setLatency(String latency) {
|
||||
this.latency = latency;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getThreads() {
|
||||
return threads;
|
||||
}
|
||||
|
||||
public Configuration setThreads(int threads) {
|
||||
this.threads = threads;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getBufferSize() {
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
public Configuration setBufferSize(String bufferSize) {
|
||||
this.bufferSize = bufferSize;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
protected void validate() {
|
||||
REQUIRED_PROPERTIES.forEach(p -> {
|
||||
if (!props.containsKey(p) || StringUtils.isEmpty(props.getProperty(p))) {
|
||||
throw new IllegalArgumentException("Required property " + p + " must be specified.");
|
||||
}
|
||||
});
|
||||
if (!getBoolean(Configuration.SSL_USE_GENERATED_KEYPAIR)) {
|
||||
if (StringUtils.isEmpty(get(Configuration.SSL_CERTIFICATE_FILE))) {
|
||||
throw new IllegalArgumentException(Configuration.SSL_CERTIFICATE_FILE + "must be specified.");
|
||||
}
|
||||
if (StringUtils.isEmpty(get(Configuration.SSL_PRIVATE_KEY_FILE))) {
|
||||
throw new IllegalArgumentException(Configuration.SSL_PRIVATE_KEY_FILE + "must be specified.");
|
||||
}
|
||||
public class Scan {
|
||||
|
||||
private int threads = 4;
|
||||
|
||||
public int getThreads() {
|
||||
return threads;
|
||||
}
|
||||
|
||||
public Configuration setThreads(int threads) {
|
||||
this.threads = threads;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public String get(String property) {
|
||||
return props.getProperty(property);
|
||||
public class Security {
|
||||
|
||||
private boolean allowAnonymousAccess = false;
|
||||
private int sessionMaxAge = 86400;
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Ssl ssl = new Ssl();
|
||||
|
||||
public boolean isAllowAnonymousAccess() {
|
||||
return allowAnonymousAccess;
|
||||
}
|
||||
|
||||
public Configuration setAllowAnonymousAccess(boolean allowAnonymousAccess) {
|
||||
this.allowAnonymousAccess = allowAnonymousAccess;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getSessionMaxAge() {
|
||||
return sessionMaxAge;
|
||||
}
|
||||
|
||||
public Configuration setSessionMaxAge(int sessionMaxAge) {
|
||||
this.sessionMaxAge = sessionMaxAge;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public Ssl getSsl() {
|
||||
return ssl;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getBoolean(String property) {
|
||||
return Boolean.parseBoolean(get(property));
|
||||
@NotEmptyIfFieldSet.List({
|
||||
@NotEmptyIfFieldSet(fieldName = "useGeneratedKeypair", fieldValue = "false", notNullFieldName = "certificateFile", message = "must be set if timely.security.ssl.use-generated-keypair is false"),
|
||||
@NotEmptyIfFieldSet(fieldName = "useGeneratedKeypair", fieldValue = "false", notNullFieldName = "keyFile", message = "must be set if timely.security.ssl.use-generated-keypair is false") })
|
||||
public class Ssl {
|
||||
|
||||
private String certificateFile;
|
||||
private String keyFile;
|
||||
private String keyPassword;
|
||||
private String trustStoreFile;
|
||||
private boolean useGeneratedKeypair = false;
|
||||
private boolean useOpenssl = true;
|
||||
private List<String> useCiphers = Lists.newArrayList("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA");
|
||||
|
||||
public String getCertificateFile() {
|
||||
return certificateFile;
|
||||
}
|
||||
|
||||
public Configuration setCertificateFile(String certificateFile) {
|
||||
this.certificateFile = certificateFile;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getKeyFile() {
|
||||
return keyFile;
|
||||
}
|
||||
|
||||
public Configuration setKeyFile(String keyFile) {
|
||||
this.keyFile = keyFile;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getKeyPassword() {
|
||||
return keyPassword;
|
||||
}
|
||||
|
||||
public Configuration setKeyPassword(String keyPassword) {
|
||||
this.keyPassword = keyPassword;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getTrustStoreFile() {
|
||||
return trustStoreFile;
|
||||
}
|
||||
|
||||
public Configuration setTrustStoreFile(String trustStoreFile) {
|
||||
this.trustStoreFile = trustStoreFile;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public boolean isUseGeneratedKeypair() {
|
||||
return useGeneratedKeypair;
|
||||
}
|
||||
|
||||
public Configuration setUseGeneratedKeypair(boolean useGeneratedKeypair) {
|
||||
this.useGeneratedKeypair = useGeneratedKeypair;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public boolean isUseOpenssl() {
|
||||
return useOpenssl;
|
||||
}
|
||||
|
||||
public Configuration setUseOpenssl(boolean useOpenssl) {
|
||||
this.useOpenssl = useOpenssl;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public List<String> getUseCiphers() {
|
||||
return useCiphers;
|
||||
}
|
||||
|
||||
public Configuration setUseCiphers(List<String> useCiphers) {
|
||||
this.useCiphers = useCiphers;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public class Server {
|
||||
|
||||
@NotBlank
|
||||
private String ip;
|
||||
@NotNull
|
||||
private Integer tcpPort;
|
||||
|
||||
@NotNull
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public Configuration setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getTcpPort() {
|
||||
return tcpPort;
|
||||
}
|
||||
|
||||
public Configuration setTcpPort(int tcpPort) {
|
||||
this.tcpPort = tcpPort;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public class Http {
|
||||
|
||||
@NotBlank
|
||||
private String ip;
|
||||
@NotNull
|
||||
private Integer port;
|
||||
@NotNull
|
||||
private String host;
|
||||
private String redirectPath = "/secure-me";
|
||||
private long strictTransportMaxAge = 604800;
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private Cors cors = new Cors();
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public Configuration setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public Configuration setPort(int port) {
|
||||
this.port = port;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public Configuration setHost(String host) {
|
||||
this.host = host;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public String getRedirectPath() {
|
||||
return redirectPath;
|
||||
}
|
||||
|
||||
public Configuration setRedirectPath(String redirectPath) {
|
||||
this.redirectPath = redirectPath;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public long getStrictTransportMaxAge() {
|
||||
return strictTransportMaxAge;
|
||||
}
|
||||
|
||||
public Configuration setStrictTransportMaxAge(long strictTransportMaxAge) {
|
||||
this.strictTransportMaxAge = strictTransportMaxAge;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public Cors getCors() {
|
||||
return cors;
|
||||
}
|
||||
}
|
||||
|
||||
public class Cors {
|
||||
|
||||
private boolean allowAnyOrigin = false;
|
||||
private boolean allowNullOrigin = false;
|
||||
private Set<String> allowedOrigins = new HashSet<>();
|
||||
private List<String> allowedMethods = Lists.newArrayList("DELETE", "GET", "HEAD", "OPTIONS", "PUT", "POST");
|
||||
private List<String> allowedHeaders = Lists.newArrayList("content-type");
|
||||
private boolean allowCredentials = true;
|
||||
|
||||
public boolean isAllowAnyOrigin() {
|
||||
return allowAnyOrigin;
|
||||
}
|
||||
|
||||
public Configuration setAllowAnyOrigin(boolean allowAnyOrigin) {
|
||||
this.allowAnyOrigin = allowAnyOrigin;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public boolean isAllowNullOrigin() {
|
||||
return allowNullOrigin;
|
||||
}
|
||||
|
||||
public Configuration setAllowNullOrigin(boolean allowNullOrigin) {
|
||||
this.allowNullOrigin = allowNullOrigin;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public Set<String> getAllowedOrigins() {
|
||||
return allowedOrigins;
|
||||
}
|
||||
|
||||
public Configuration setAllowedOrigins(Set<String> allowedOrigins) {
|
||||
this.allowedOrigins = allowedOrigins;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public List<String> getAllowedMethods() {
|
||||
return allowedMethods;
|
||||
}
|
||||
|
||||
public Configuration setAllowedMethods(List<String> allowedMethods) {
|
||||
this.allowedMethods = allowedMethods;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public List<String> getAllowedHeaders() {
|
||||
return allowedHeaders;
|
||||
}
|
||||
|
||||
public Configuration setAllowedHeaders(List<String> allowedHeaders) {
|
||||
this.allowedHeaders = allowedHeaders;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public boolean isAllowCredentials() {
|
||||
return allowCredentials;
|
||||
}
|
||||
|
||||
public Configuration setAllowCredentials(boolean allowCredentials) {
|
||||
this.allowCredentials = allowCredentials;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public class Websocket {
|
||||
|
||||
@NotBlank
|
||||
private String ip;
|
||||
@NotNull
|
||||
private Integer port;
|
||||
public int timeout = 60;
|
||||
public int subscriptionLag = 120;
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
public Configuration setIp(String ip) {
|
||||
this.ip = ip;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public Configuration setPort(int port) {
|
||||
this.port = port;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public Configuration setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getSubscriptionLag() {
|
||||
return subscriptionLag;
|
||||
}
|
||||
|
||||
public Configuration setSubscriptionLag(int subscriptionLag) {
|
||||
this.subscriptionLag = subscriptionLag;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public class MetaCache {
|
||||
|
||||
private long expirationMinutes = 60;
|
||||
private int initialCapacity = 2000;
|
||||
private long maxCapacity = 10000;
|
||||
|
||||
public long getExpirationMinutes() {
|
||||
return expirationMinutes;
|
||||
}
|
||||
|
||||
public Configuration setExpirationMinutes(long expirationMinutes) {
|
||||
this.expirationMinutes = expirationMinutes;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getInitialCapacity() {
|
||||
return initialCapacity;
|
||||
}
|
||||
|
||||
public Configuration setInitialCapacity(int initialCapacity) {
|
||||
this.initialCapacity = initialCapacity;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public long getMaxCapacity() {
|
||||
return maxCapacity;
|
||||
}
|
||||
|
||||
public Configuration setMaxCapacity(long maxCapacity) {
|
||||
this.maxCapacity = maxCapacity;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public class VisibilityCache {
|
||||
|
||||
private long expirationMinutes = 60;
|
||||
private int initialCapacity = 2000;
|
||||
private long maxCapacity = 10000;
|
||||
|
||||
public long getExpirationMinutes() {
|
||||
return expirationMinutes;
|
||||
}
|
||||
|
||||
public Configuration setExpirationMinutes(long expirationMinutes) {
|
||||
this.expirationMinutes = expirationMinutes;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getInitialCapacity() {
|
||||
return initialCapacity;
|
||||
}
|
||||
|
||||
public Configuration setInitialCapacity(int initialCapacity) {
|
||||
this.initialCapacity = initialCapacity;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public long getMaxCapacity() {
|
||||
return maxCapacity;
|
||||
}
|
||||
|
||||
public Configuration setMaxCapacity(long maxCapacity) {
|
||||
this.maxCapacity = maxCapacity;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,14 +40,16 @@ import io.netty.util.internal.SystemPropertyUtil;
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import rx.Observable;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import timely.api.response.TimelyException;
|
||||
import timely.auth.AuthCache;
|
||||
import timely.auth.VisibilityCache;
|
||||
@@ -83,6 +85,13 @@ import timely.netty.websocket.timeseries.WSSuggestRequestHandler;
|
||||
import timely.store.DataStore;
|
||||
import timely.store.DataStoreFactory;
|
||||
import timely.store.MetaCacheFactory;
|
||||
import timely.wamp.StateObserver;
|
||||
import timely.wamp.VersionObserver;
|
||||
import ws.wamp.jawampa.*;
|
||||
import ws.wamp.jawampa.connection.IWampConnectorProvider;
|
||||
import ws.wamp.jawampa.transport.netty.NettyWampClientConnectorProvider;
|
||||
import ws.wamp.jawampa.transport.netty.NettyWampConnectionConfig;
|
||||
import ws.wamp.jawampa.transport.netty.WampServerWebsocketHandler;
|
||||
|
||||
public class Server {
|
||||
|
||||
@@ -93,10 +102,12 @@ public class Server {
|
||||
private static final String OS_NAME = "os.name";
|
||||
private static final String OS_VERSION = "os.version";
|
||||
private static final String WS_PATH = "/websocket";
|
||||
private static final String WAMP_PATH = "/wamp";
|
||||
|
||||
protected static final CountDownLatch LATCH = new CountDownLatch(1);
|
||||
static ConfigurableApplicationContext applicationContext;
|
||||
|
||||
private Configuration config = null;
|
||||
private final Configuration config;
|
||||
private EventLoopGroup tcpWorkerGroup = null;
|
||||
private EventLoopGroup tcpBossGroup = null;
|
||||
private EventLoopGroup httpWorkerGroup = null;
|
||||
@@ -108,6 +119,8 @@ public class Server {
|
||||
protected Channel wsChannelHandle = null;
|
||||
protected DataStore dataStore = null;
|
||||
protected volatile boolean shutdown = false;
|
||||
private WampRouter wampRouter = null;
|
||||
private WampClient wampClient;
|
||||
|
||||
private static boolean useEpoll() {
|
||||
|
||||
@@ -126,11 +139,7 @@ public class Server {
|
||||
return true;
|
||||
} else if (minor == EPOLL_MIN_MINOR_VERSION) {
|
||||
final int patch = Integer.parseInt(version[2].substring(0, 2));
|
||||
if (patch >= EPOLL_MIN_PATCH_VERSION) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return patch >= EPOLL_MIN_PATCH_VERSION;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -142,11 +151,6 @@ public class Server {
|
||||
}
|
||||
}
|
||||
|
||||
private static String usage() {
|
||||
|
||||
return "Server <configFile>";
|
||||
}
|
||||
|
||||
public static void fatal(String msg, Throwable t) {
|
||||
LOG.error(msg, t);
|
||||
LATCH.countDown();
|
||||
@@ -154,13 +158,8 @@ public class Server {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (args.length != 1) {
|
||||
System.err.println(usage());
|
||||
}
|
||||
final File conf = new File(args[0]);
|
||||
if (!conf.canRead()) {
|
||||
throw new RuntimeException("Configuration file does not exist or cannot be read");
|
||||
}
|
||||
Configuration conf = initializeConfiguration(args);
|
||||
|
||||
Server s = new Server(conf);
|
||||
try {
|
||||
LATCH.await();
|
||||
@@ -171,15 +170,16 @@ public class Server {
|
||||
}
|
||||
}
|
||||
|
||||
protected static Configuration initializeConfiguration(String[] args) {
|
||||
applicationContext = new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(args);
|
||||
return applicationContext.getBean(Configuration.class);
|
||||
}
|
||||
|
||||
private void shutdownHook() {
|
||||
|
||||
final Runnable shutdownRunner = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!shutdown) {
|
||||
shutdown();
|
||||
}
|
||||
final Runnable shutdownRunner = () -> {
|
||||
if (!shutdown) {
|
||||
shutdown();
|
||||
}
|
||||
};
|
||||
final Thread hook = new Thread(shutdownRunner, "shutdown-hook-thread");
|
||||
@@ -237,15 +237,23 @@ public class Server {
|
||||
} catch (TimelyException e) {
|
||||
LOG.error("Error flushing to server during shutdown", e);
|
||||
}
|
||||
LOG.info("Shutting down WAMP Router");
|
||||
wampClient.close().toBlocking().last();
|
||||
wampRouter.close().toBlocking().last(); // Blocks until router is fully
|
||||
// shut down
|
||||
MetaCacheFactory.close();
|
||||
WebSocketRequestDecoder.close();
|
||||
if (applicationContext != null) {
|
||||
applicationContext.close();
|
||||
}
|
||||
this.shutdown = true;
|
||||
LOG.info("Server shut down.");
|
||||
}
|
||||
|
||||
public Server(File conf) throws Exception {
|
||||
public Server(Configuration conf) throws Exception {
|
||||
|
||||
this.config = conf;
|
||||
|
||||
config = new Configuration(conf);
|
||||
int nettyThreads = Math.max(1,
|
||||
SystemPropertyUtil.getInt("io.netty.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
|
||||
dataStore = DataStoreFactory.create(config, nettyThreads);
|
||||
@@ -256,7 +264,7 @@ public class Server {
|
||||
// Initialize the VisibilityCache
|
||||
VisibilityCache.init(config);
|
||||
final boolean useEpoll = useEpoll();
|
||||
Class<? extends ServerSocketChannel> channelClass = null;
|
||||
Class<? extends ServerSocketChannel> channelClass;
|
||||
if (useEpoll) {
|
||||
tcpWorkerGroup = new EpollEventLoopGroup();
|
||||
tcpBossGroup = new EpollEventLoopGroup();
|
||||
@@ -284,11 +292,11 @@ public class Server {
|
||||
putServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||
putServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||
putServer.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
final int putPort = Integer.parseInt(config.get(Configuration.PUT_PORT));
|
||||
final int putPort = config.getServer().getTcpPort();
|
||||
putChannelHandle = putServer.bind(putPort).sync().channel();
|
||||
final String putAddress = ((InetSocketAddress) putChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||
|
||||
final int queryPort = Integer.parseInt(config.get(Configuration.QUERY_PORT));
|
||||
final int queryPort = config.getHttp().getPort();
|
||||
SslContext sslCtx = createSSLContext(config);
|
||||
if (sslCtx instanceof OpenSslServerContext) {
|
||||
OpenSslServerContext openssl = (OpenSslServerContext) sslCtx;
|
||||
@@ -297,7 +305,7 @@ public class Server {
|
||||
opensslCtx.setSessionCacheEnabled(true);
|
||||
opensslCtx.setSessionCacheSize(128);
|
||||
opensslCtx.setSessionIdContext(application.getBytes(StandardCharsets.UTF_8));
|
||||
opensslCtx.setSessionTimeout(Integer.parseInt(config.get(Configuration.SESSION_MAX_AGE)));
|
||||
opensslCtx.setSessionTimeout(config.getSecurity().getSessionMaxAge());
|
||||
}
|
||||
final ServerBootstrap queryServer = new ServerBootstrap();
|
||||
queryServer.group(httpBossGroup, httpWorkerGroup);
|
||||
@@ -311,8 +319,9 @@ public class Server {
|
||||
final String queryAddress = ((InetSocketAddress) queryChannelHandle.localAddress()).getAddress()
|
||||
.getHostAddress();
|
||||
|
||||
final int wsPort = Integer.parseInt(config.get(Configuration.WEBSOCKET_PORT));
|
||||
final int wsPort = config.getWebsocket().getPort();
|
||||
final ServerBootstrap wsServer = new ServerBootstrap();
|
||||
setupWampRouter();
|
||||
wsServer.group(wsBossGroup, wsWorkerGroup);
|
||||
wsServer.channel(channelClass);
|
||||
wsServer.handler(new LoggingHandler());
|
||||
@@ -324,6 +333,9 @@ public class Server {
|
||||
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||
|
||||
shutdownHook();
|
||||
|
||||
setupWampClient(wsAddress, wsPort);
|
||||
|
||||
LOG.info(
|
||||
"Server started. Listening on {}:{} for TCP traffic, {}:{} for HTTP traffic, and {}:{} for WebSocket traffic",
|
||||
putAddress, putPort, queryAddress, queryPort, wsAddress, wsPort);
|
||||
@@ -331,8 +343,9 @@ public class Server {
|
||||
|
||||
protected SslContext createSSLContext(Configuration config) throws Exception {
|
||||
|
||||
Boolean generate = config.getBoolean(Configuration.SSL_USE_GENERATED_KEYPAIR);
|
||||
SslContextBuilder ssl = null;
|
||||
Configuration.Ssl sslCfg = config.getSecurity().getSsl();
|
||||
Boolean generate = sslCfg.isUseGeneratedKeypair();
|
||||
SslContextBuilder ssl;
|
||||
if (generate) {
|
||||
LOG.warn("Using generated self signed server certificate");
|
||||
Date begin = new Date();
|
||||
@@ -340,28 +353,27 @@ public class Server {
|
||||
SelfSignedCertificate ssc = new SelfSignedCertificate("localhost", begin, end);
|
||||
ssl = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey());
|
||||
} else {
|
||||
String cert = config.get(Configuration.SSL_CERTIFICATE_FILE);
|
||||
String key = config.get(Configuration.SSL_PRIVATE_KEY_FILE);
|
||||
String keyPass = config.get(Configuration.SSL_PRIVATE_KEY_PASS);
|
||||
String cert = sslCfg.getCertificateFile();
|
||||
String key = sslCfg.getKeyFile();
|
||||
String keyPass = sslCfg.getKeyPassword();
|
||||
if (null == cert || null == key) {
|
||||
throw new IllegalArgumentException("Check your SSL properties, something is wrong.");
|
||||
}
|
||||
ssl = SslContextBuilder.forServer(new File(cert), new File(key), keyPass);
|
||||
}
|
||||
|
||||
String ciphers = config.get(Configuration.SSL_USE_CIPHERS);
|
||||
ssl.ciphers(Arrays.asList(ciphers.split(":")));
|
||||
ssl.ciphers(sslCfg.getUseCiphers());
|
||||
|
||||
// Can't set to REQUIRE because the CORS pre-flight requests will fail.
|
||||
ssl.clientAuth(ClientAuth.OPTIONAL);
|
||||
|
||||
Boolean useOpenSSL = config.getBoolean(Configuration.SSL_USE_OPENSSL);
|
||||
Boolean useOpenSSL = sslCfg.isUseOpenssl();
|
||||
if (useOpenSSL) {
|
||||
ssl.sslProvider(SslProvider.OPENSSL);
|
||||
} else {
|
||||
ssl.sslProvider(SslProvider.JDK);
|
||||
}
|
||||
String trustStore = config.get(Configuration.SSL_TRUST_STORE_FILE);
|
||||
String trustStore = sslCfg.getTrustStoreFile();
|
||||
if (null != trustStore) {
|
||||
if (!trustStore.isEmpty()) {
|
||||
ssl.trustManager(new File(trustStore));
|
||||
@@ -385,30 +397,21 @@ public class Server {
|
||||
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
|
||||
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
||||
final Configuration.Cors corsCfg = config.getHttp().getCors();
|
||||
final CorsConfig.Builder ccb;
|
||||
if (config.getBoolean(Configuration.CORS_ALLOW_ANY_ORIGIN)) {
|
||||
if (corsCfg.isAllowAnyOrigin()) {
|
||||
ccb = new CorsConfig.Builder();
|
||||
} else {
|
||||
String origins = config.get(Configuration.CORS_ALLOWED_ORIGINS);
|
||||
ccb = new CorsConfig.Builder(origins.split(","));
|
||||
ccb = new CorsConfig.Builder(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
|
||||
}
|
||||
if (config.getBoolean(Configuration.CORS_ALLOW_NULL_ORIGIN)) {
|
||||
if (corsCfg.isAllowNullOrigin()) {
|
||||
ccb.allowNullOrigin();
|
||||
}
|
||||
if (config.getBoolean(Configuration.CORS_ALLOW_CREDENTIALS)) {
|
||||
if (corsCfg.isAllowCredentials()) {
|
||||
ccb.allowCredentials();
|
||||
}
|
||||
if (!StringUtils.isEmpty(config.get(Configuration.CORS_ALLOWED_METHODS))) {
|
||||
String[] methods = config.get(Configuration.CORS_ALLOWED_METHODS).split(",");
|
||||
HttpMethod[] m = new HttpMethod[methods.length];
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
m[i] = HttpMethod.valueOf(methods[i]);
|
||||
}
|
||||
ccb.allowedRequestMethods(m);
|
||||
}
|
||||
if (!StringUtils.isEmpty(config.get(Configuration.CORS_ALLOWED_HEADERS))) {
|
||||
ccb.allowedRequestHeaders(config.get(Configuration.CORS_ALLOWED_HEADERS).split(","));
|
||||
}
|
||||
corsCfg.getAllowedMethods().stream().map(HttpMethod::valueOf).forEach(ccb::allowedRequestMethods);
|
||||
corsCfg.getAllowedHeaders().forEach(ccb::allowedRequestHeaders);
|
||||
CorsConfig cors = ccb.build();
|
||||
LOG.trace("Cors configuration: {}", cors);
|
||||
ch.pipeline().addLast("cors", new CorsHandler(cors));
|
||||
@@ -448,11 +451,11 @@ public class Server {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
||||
ch.pipeline().addLast("wamp", new WampServerWebsocketHandler(WAMP_PATH, wampRouter));
|
||||
ch.pipeline().addLast("httpServer", new HttpServerCodec());
|
||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
|
||||
ch.pipeline().addLast("sessionExtractor", new WebSocketHttpCookieHandler(config));
|
||||
ch.pipeline().addLast("idle-handler",
|
||||
new IdleStateHandler(Integer.parseInt(conf.get(Configuration.WS_TIMEOUT_SECONDS)), 0, 0));
|
||||
ch.pipeline().addLast("idle-handler", new IdleStateHandler(conf.getWebsocket().getTimeout(), 0, 0));
|
||||
ch.pipeline().addLast("ws-protocol", new WebSocketServerProtocolHandler(WS_PATH, null, true));
|
||||
ch.pipeline().addLast("wsDecoder", new WebSocketRequestDecoder(config));
|
||||
ch.pipeline().addLast("aggregators", new WSAggregatorsRequestHandler());
|
||||
@@ -472,4 +475,36 @@ public class Server {
|
||||
|
||||
}
|
||||
|
||||
protected void setupWampRouter() throws ApplicationError {
|
||||
wampRouter = new WampRouterBuilder().addRealm("default").build();
|
||||
}
|
||||
|
||||
protected void setupWampClient(String wsAddress, int wsPort) throws Exception {
|
||||
IWampConnectorProvider connectorProvider = new NettyWampClientConnectorProvider();
|
||||
NettyWampConnectionConfig connectionConfiguration = new NettyWampConnectionConfig.Builder()
|
||||
.withSslContext(SslContextBuilder.forClient().build())
|
||||
.build();
|
||||
|
||||
// Create a builder and configure the client
|
||||
WampClientBuilder builder = new WampClientBuilder();
|
||||
String wampUri = String.format("wss://0.0.0.0:%d%s", wsPort, WAMP_PATH);
|
||||
System.out.println(wampUri);
|
||||
builder.withConnectorProvider(connectorProvider)
|
||||
.withConnectionConfiguration(connectionConfiguration)
|
||||
.withUri(wampUri)
|
||||
.withRealm("timely")
|
||||
.withInfiniteReconnects()
|
||||
.withReconnectInterval(5, TimeUnit.SECONDS);
|
||||
// Create a client through the builder. This will not immediately start
|
||||
// a connection attempt
|
||||
wampClient = builder.build();
|
||||
Observable<WampClient.State> stateObservable = wampClient.statusChanged();
|
||||
stateObservable.subscribe(new StateObserver());
|
||||
|
||||
wampClient.open();
|
||||
|
||||
Observable<Request> request = wampClient.registerProcedure("timely.version");
|
||||
request.subscribe(new VersionObserver());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package timely;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication(scanBasePackageClasses = { Configuration.class })
|
||||
public class SpringBootstrap {
|
||||
}
|
||||
@@ -21,7 +21,7 @@ public class StandaloneServer extends Server {
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
|
||||
public StandaloneServer(File conf) throws Exception {
|
||||
public StandaloneServer(Configuration conf) throws Exception {
|
||||
super(conf);
|
||||
}
|
||||
|
||||
@@ -38,22 +38,21 @@ public class StandaloneServer extends Server {
|
||||
}
|
||||
|
||||
private static String usage() {
|
||||
return "StandaloneServer <configFile> <directory>";
|
||||
return "StandaloneServer <directory>";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 2) {
|
||||
if (args.length < 1) {
|
||||
System.err.println(usage());
|
||||
}
|
||||
final File conf = new File(args[0]);
|
||||
if (!conf.canRead()) {
|
||||
throw new RuntimeException("Configuration file does not exist or cannot be read");
|
||||
}
|
||||
File tmp = new File(args[1]);
|
||||
File tmp = new File(args[0]);
|
||||
if (!tmp.canWrite()) {
|
||||
System.err.println("Unable to write to directory: " + tmp);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
Configuration conf = initializeConfiguration(args);
|
||||
|
||||
File accumuloDir = new File(tmp, "accumulo");
|
||||
MiniAccumuloConfig macConfig = new MiniAccumuloConfig(accumuloDir, "secret");
|
||||
macConfig.setInstanceName("TimelyStandalone");
|
||||
@@ -95,5 +94,4 @@ public class StandaloneServer extends Server {
|
||||
LOG.info("Server shutting down.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -62,20 +61,15 @@ public class MetricsResponse {
|
||||
private static final String TD_END = "</td>\n";
|
||||
|
||||
private Set<String> ignoredTags = Collections.emptySet();
|
||||
private Configuration conf = null;
|
||||
private final Configuration conf;
|
||||
|
||||
public MetricsResponse() {
|
||||
conf = null;
|
||||
}
|
||||
|
||||
public MetricsResponse(Configuration conf) {
|
||||
String tagsToIgnore = conf.get(Configuration.METRICS_IGNORED_TAGS);
|
||||
if (!StringUtils.isEmpty(tagsToIgnore)) {
|
||||
this.ignoredTags = new HashSet<>();
|
||||
for (String tag : tagsToIgnore.split(",")) {
|
||||
ignoredTags.add(tag);
|
||||
}
|
||||
}
|
||||
this.conf = conf;
|
||||
ignoredTags = new HashSet<>(conf.getMetricsReportIgnoredTags());
|
||||
}
|
||||
|
||||
public TextWebSocketFrame toWebSocketResponse(String acceptHeader) throws Exception {
|
||||
|
||||
@@ -23,20 +23,20 @@ public class AuthCache {
|
||||
|
||||
private static Cache<String, Authentication> CACHE = null;
|
||||
|
||||
private static Long sessionMaxAge = -1L;
|
||||
private static int sessionMaxAge = -1;
|
||||
|
||||
/**
|
||||
* For tests only
|
||||
*/
|
||||
public static void resetSessionMaxAge() {
|
||||
sessionMaxAge = -1L;
|
||||
sessionMaxAge = -1;
|
||||
}
|
||||
|
||||
public static void setSessionMaxAge(Configuration config) {
|
||||
if (-1 != sessionMaxAge) {
|
||||
throw new IllegalStateException("Cache session max age already configured.");
|
||||
}
|
||||
sessionMaxAge = Long.parseLong(config.get(Configuration.SESSION_MAX_AGE));
|
||||
sessionMaxAge = config.getSecurity().getSessionMaxAge();
|
||||
}
|
||||
|
||||
public static Cache<String, Authentication> getCache() {
|
||||
@@ -56,9 +56,7 @@ public class AuthCache {
|
||||
Collection<? extends GrantedAuthority> authorities = CACHE.asMap().get(sessionId).getAuthorities();
|
||||
String[] auths = new String[authorities.size()];
|
||||
final AtomicInteger i = new AtomicInteger(0);
|
||||
authorities.forEach(a -> {
|
||||
auths[i.getAndIncrement()] = a.getAuthority();
|
||||
});
|
||||
authorities.forEach(a -> auths[i.getAndIncrement()] = a.getAuthority());
|
||||
return new Authorizations(auths);
|
||||
} else {
|
||||
return null;
|
||||
@@ -69,7 +67,7 @@ public class AuthCache {
|
||||
}
|
||||
|
||||
public static void enforceAccess(Configuration conf, Request r) throws Exception {
|
||||
if (!conf.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS) && (r instanceof AuthenticatedRequest)) {
|
||||
if (!conf.getSecurity().isAllowAnonymousAccess() && (r instanceof AuthenticatedRequest)) {
|
||||
AuthenticatedRequest ar = (AuthenticatedRequest) r;
|
||||
if (StringUtils.isEmpty(ar.getSessionId())) {
|
||||
throw new TimelyException(HttpResponseStatus.UNAUTHORIZED.code(), "User must log in",
|
||||
|
||||
@@ -11,22 +11,11 @@ public class VisibilityCache {
|
||||
|
||||
private static volatile Cache<String, ColumnVisibility> CACHE = null;
|
||||
|
||||
/** Used for testing */
|
||||
public static synchronized void init() {
|
||||
if (CACHE == null) {
|
||||
long defaultExpiration = Configuration.VISIBILITY_EXPIRATION_DEFAULT;
|
||||
int initialCapacity = Configuration.VISIBILITY_CACHE_INITIAL_CAPACITY_DEFAULT;
|
||||
long maxCapacity = Configuration.VISIBILITY_CACHE_MAX_CAPACITY_DEFAULT;
|
||||
CACHE = Caffeine.newBuilder().expireAfterAccess(defaultExpiration, TimeUnit.MINUTES)
|
||||
.initialCapacity(initialCapacity).maximumSize(maxCapacity).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void init(Configuration config) {
|
||||
if (CACHE == null) {
|
||||
long expireMinutes = Long.parseLong(config.get(Configuration.VISIBILITY_CACHE_EXPIRATION));
|
||||
int initialCapacity = Integer.parseInt(config.get(Configuration.VISIBILITY_CACHE_INITIAL_CAPACITY));
|
||||
long maxCapacity = Long.parseLong(config.get(Configuration.VISIBILITY_CACHE_MAX_CAPACITY));
|
||||
long expireMinutes = config.getVisibilityCache().getExpirationMinutes();
|
||||
int initialCapacity = config.getVisibilityCache().getInitialCapacity();
|
||||
long maxCapacity = config.getVisibilityCache().getMaxCapacity();
|
||||
CACHE = Caffeine.newBuilder().expireAfterAccess(expireMinutes, TimeUnit.MINUTES)
|
||||
.initialCapacity(initialCapacity).maximumSize(maxCapacity).build();
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
|
||||
public HttpRequestDecoder(Configuration config) {
|
||||
this.conf = config;
|
||||
this.anonymousAccessAllowed = conf.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS);
|
||||
this.nonSecureRedirectAddress = conf.get(Configuration.NON_SECURE_REDIRECT_PATH);
|
||||
this.anonymousAccessAllowed = conf.getSecurity().isAllowAnonymousAccess();
|
||||
this.nonSecureRedirectAddress = conf.getHttp().getRedirectPath();
|
||||
}
|
||||
|
||||
public static String getSessionId(FullHttpRequest msg, boolean anonymousAccessAllowed) {
|
||||
@@ -79,7 +79,7 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
final String sessionId = getSessionId(msg, this.anonymousAccessAllowed);
|
||||
LOG.trace("SessionID: " + sessionId);
|
||||
|
||||
Request request = null;
|
||||
Request request;
|
||||
try {
|
||||
if (msg.getMethod().equals(HttpMethod.GET)) {
|
||||
HttpGetRequest get = AnnotationResolver.getClassForHttpGet(decoder.path());
|
||||
|
||||
@@ -22,9 +22,9 @@ public class NonSecureHttpHandler extends ChannelInboundHandlerAdapter implement
|
||||
private final String redirectAddress;
|
||||
|
||||
public NonSecureHttpHandler(Configuration conf) {
|
||||
String timelyHost = conf.get(Configuration.TIMELY_HTTP_HOST);
|
||||
String timelyPort = conf.get(Configuration.QUERY_PORT);
|
||||
String path = conf.get(Configuration.NON_SECURE_REDIRECT_PATH);
|
||||
String timelyHost = conf.getHttp().getHost();
|
||||
int timelyPort = conf.getHttp().getPort();
|
||||
String path = conf.getHttp().getRedirectPath();
|
||||
redirectAddress = "https://" + timelyHost + ":" + timelyPort + path;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public class StrictTransportHandler extends SimpleChannelInboundHandler<StrictTr
|
||||
private String hstsMaxAge = "max-age=";
|
||||
|
||||
public StrictTransportHandler(Configuration conf) {
|
||||
String maxAge = conf.get(Configuration.STRICT_TRANSPORT_MAX_AGE);
|
||||
long maxAge = conf.getHttp().getStrictTransportMaxAge();
|
||||
hstsMaxAge = "max-age=" + maxAge;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,15 +27,12 @@ public abstract class TimelyLoginRequestHandler<T> extends SimpleChannelInboundH
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TimelyLoginRequestHandler.class);
|
||||
|
||||
private long maxAge = Configuration.SESSION_MAX_AGE_DEFAULT;
|
||||
private String domain = null;
|
||||
private final long maxAge;
|
||||
private final String domain;
|
||||
|
||||
public TimelyLoginRequestHandler(Configuration conf) {
|
||||
String ma = conf.get(Configuration.SESSION_MAX_AGE);
|
||||
if (null != ma) {
|
||||
maxAge = Long.parseLong(ma);
|
||||
}
|
||||
domain = conf.get(Configuration.TIMELY_HTTP_HOST);
|
||||
maxAge = conf.getSecurity().getSessionMaxAge();
|
||||
domain = conf.getHttp().getHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,7 @@ public class WebSocketHttpCookieHandler extends MessageToMessageCodec<FullHttpRe
|
||||
|
||||
public WebSocketHttpCookieHandler(Configuration config) {
|
||||
super();
|
||||
this.anonymousAccessAllowed = config.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS);
|
||||
this.anonymousAccessAllowed = config.getSecurity().isAllowAnonymousAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package timely.store;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.apache.accumulo.core.conf.AccumuloConfiguration.getMemoryInBytes;
|
||||
import static org.apache.accumulo.core.conf.AccumuloConfiguration.getTimeInMillis;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
@@ -62,8 +61,8 @@ import org.apache.hadoop.io.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.Server;
|
||||
import timely.Configuration;
|
||||
import timely.api.model.Meta;
|
||||
import timely.api.model.Metric;
|
||||
import timely.api.model.Tag;
|
||||
@@ -113,7 +112,6 @@ public class DataStoreImpl implements DataStore {
|
||||
|
||||
}
|
||||
|
||||
Configuration conf;
|
||||
private final Connector connector;
|
||||
private MetaCache metaCache = null;
|
||||
private final AtomicLong lastCountTime = new AtomicLong(System.currentTimeMillis());
|
||||
@@ -133,27 +131,28 @@ public class DataStoreImpl implements DataStore {
|
||||
|
||||
try {
|
||||
final BaseConfiguration apacheConf = new BaseConfiguration();
|
||||
apacheConf.setProperty("instance.name", conf.get(Configuration.INSTANCE_NAME));
|
||||
apacheConf.setProperty("instance.zookeeper.host", conf.get(Configuration.ZOOKEEPERS));
|
||||
Configuration.Accumulo accumuloConf = conf.getAccumulo();
|
||||
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
|
||||
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
|
||||
final Instance instance = new ZooKeeperInstance(aconf);
|
||||
final byte[] passwd = conf.get(Configuration.PASSWORD).getBytes(UTF_8);
|
||||
connector = instance.getConnector(conf.get(Configuration.USERNAME), new PasswordToken(passwd));
|
||||
connector = instance
|
||||
.getConnector(accumuloConf.getUsername(), new PasswordToken(accumuloConf.getPassword()));
|
||||
bwConfig = new BatchWriterConfig();
|
||||
bwConfig.setMaxLatency(getTimeInMillis(conf.get(Configuration.MAX_LATENCY)), TimeUnit.MILLISECONDS);
|
||||
bwConfig.setMaxMemory(getMemoryInBytes(conf.get(Configuration.WRITE_BUFFER_SIZE)) / numWriteThreads);
|
||||
bwConfig.setMaxWriteThreads(Integer.parseInt(conf.get(Configuration.WRITE_THREADS)));
|
||||
scannerThreads = Integer.parseInt(conf.get(Configuration.SCANNER_THREADS));
|
||||
anonAccessAllowed = conf.getBoolean(Configuration.ALLOW_ANONYMOUS_ACCESS);
|
||||
bwConfig.setMaxLatency(getTimeInMillis(accumuloConf.getWrite().getLatency()), TimeUnit.MILLISECONDS);
|
||||
bwConfig.setMaxMemory(getMemoryInBytes(accumuloConf.getWrite().getBufferSize()) / numWriteThreads);
|
||||
bwConfig.setMaxWriteThreads(accumuloConf.getWrite().getThreads());
|
||||
scannerThreads = accumuloConf.getScan().getThreads();
|
||||
anonAccessAllowed = conf.getSecurity().isAllowAnonymousAccess();
|
||||
|
||||
String ageoff = Long.toString(Integer.parseInt(conf.get(Configuration.METRICS_AGEOFF_DAYS)) * 86400000L);
|
||||
String ageoff = Long.toString(conf.getMetricAgeOffDays() * 86400000L);
|
||||
Map<String, String> ageOffOptions = new HashMap<>();
|
||||
ageOffOptions.put("ttl", ageoff);
|
||||
IteratorSetting ageOffIteratorSettings = new IteratorSetting(100, "ageoff", AgeOffFilter.class,
|
||||
ageOffOptions);
|
||||
EnumSet<IteratorScope> ageOffIteratorScope = EnumSet.allOf(IteratorScope.class);
|
||||
|
||||
metricsTable = conf.get(Configuration.METRICS_TABLE);
|
||||
metricsTable = conf.getMetricsTable();
|
||||
if (metricsTable.contains(".")) {
|
||||
final String[] parts = metricsTable.split("\\.", 2);
|
||||
final String namespace = parts[0];
|
||||
@@ -184,7 +183,7 @@ public class DataStoreImpl implements DataStore {
|
||||
}
|
||||
}
|
||||
}
|
||||
metaTable = conf.get(Configuration.META_TABLE);
|
||||
metaTable = conf.getMetaTable();
|
||||
if (!tableIdMap.containsKey(metaTable)) {
|
||||
try {
|
||||
LOG.info("Creating table " + metaTable);
|
||||
@@ -392,6 +391,10 @@ public class DataStoreImpl implements DataStore {
|
||||
}
|
||||
result.setTags(tags);
|
||||
result.setLimit(msg.getLimit());
|
||||
Map<String, Pattern> tagPatterns = new HashMap<>();
|
||||
tags.forEach((k, v) -> {
|
||||
tagPatterns.put(k, Pattern.compile(v));
|
||||
});
|
||||
try {
|
||||
List<Result> resultField = new ArrayList<>();
|
||||
Scanner scanner = connector.createScanner(metaTable, Authorizations.EMPTY);
|
||||
@@ -399,11 +402,11 @@ public class DataStoreImpl implements DataStore {
|
||||
Key end = start.followingKey(PartialKey.ROW);
|
||||
Range range = new Range(start, end);
|
||||
scanner.setRange(range);
|
||||
// TODO compute columns to fetch
|
||||
tags.keySet().forEach(k -> scanner.fetchColumnFamily(new Text(k)));
|
||||
int total = 0;
|
||||
for (Entry<Key, Value> entry : scanner) {
|
||||
Meta metaEntry = Meta.parse(entry.getKey(), entry.getValue());
|
||||
if (matches(metaEntry.getTagKey(), metaEntry.getTagValue(), tags)) {
|
||||
if (matches(metaEntry.getTagKey(), metaEntry.getTagValue(), tagPatterns)) {
|
||||
if (resultField.size() < msg.getLimit()) {
|
||||
Result r = new Result();
|
||||
r.putTag(metaEntry.getTagKey(), metaEntry.getTagValue());
|
||||
@@ -423,12 +426,9 @@ public class DataStoreImpl implements DataStore {
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean matches(String tagk, String tagv, Map<String, String> tags) {
|
||||
// first, match keys...
|
||||
for (Entry<String, String> entry : tags.entrySet()) {
|
||||
String k = entry.getKey();
|
||||
String v = entry.getValue();
|
||||
if (("*".equals(k) || tagk.equals(k)) && ("*".equals(v) || tagv.equals(v))) {
|
||||
private boolean matches(String tagk, String tagv, Map<String, Pattern> tags) {
|
||||
for (Entry<String, Pattern> entry : tags.entrySet()) {
|
||||
if (tagk.equals(entry.getKey()) && entry.getValue().matcher(tagv).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ public class MetaCacheImpl implements MetaCache {
|
||||
|
||||
@Override
|
||||
public void init(Configuration config) {
|
||||
long defaultExpiration = Long.parseLong(config.get(Configuration.META_CACHE_EXPIRATION));
|
||||
int initialCapacity = Integer.parseInt(config.get(Configuration.META_CACHE_INITIAL_CAPACITY));
|
||||
long maxCapacity = Long.parseLong(config.get(Configuration.META_CACHE_MAX_CAPACITY));
|
||||
cache = Caffeine.newBuilder().expireAfterAccess(defaultExpiration, TimeUnit.MINUTES)
|
||||
long expirationMinutes = config.getMetaCache().getExpirationMinutes();
|
||||
int initialCapacity = config.getMetaCache().getInitialCapacity();
|
||||
long maxCapacity = config.getMetaCache().getMaxCapacity();
|
||||
cache = Caffeine.newBuilder().expireAfterAccess(expirationMinutes, TimeUnit.MINUTES)
|
||||
.initialCapacity(initialCapacity).maximumSize(maxCapacity).build();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,16 +33,12 @@ public class Subscription {
|
||||
this.sessionId = sessionId;
|
||||
this.store = store;
|
||||
this.ctx = ctx;
|
||||
this.lag = Integer.parseInt(conf.get(Configuration.WS_SUBSCRIPTION_LAG));
|
||||
this.lag = conf.getWebsocket().getSubscriptionLag();
|
||||
// send a websocket ping at half the timeout interval.
|
||||
int rate = (Integer.parseInt(conf.get(Configuration.WS_TIMEOUT_SECONDS)) / 2);
|
||||
this.ping = this.ctx.executor().scheduleAtFixedRate(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOG.trace("Sending ping on channel {}", ctx.channel());
|
||||
ctx.writeAndFlush(new PingWebSocketFrame());
|
||||
}
|
||||
int rate = conf.getWebsocket().getTimeout() / 2;
|
||||
this.ping = this.ctx.executor().scheduleAtFixedRate(() -> {
|
||||
LOG.trace("Sending ping on channel {}", ctx.channel());
|
||||
ctx.writeAndFlush(new PingWebSocketFrame());
|
||||
}, rate, rate, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package timely.util;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -17,6 +14,9 @@ import org.apache.accumulo.core.data.Range;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.commons.configuration.BaseConfiguration;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import timely.SpringBootstrap;
|
||||
import timely.Configuration;
|
||||
import timely.api.model.Meta;
|
||||
|
||||
@@ -24,33 +24,28 @@ public class GetMetricTableSplitPoints {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (args.length != 1) {
|
||||
System.err.println("CreateMetricTableSplitPoints <configFile>");
|
||||
System.exit(1);
|
||||
}
|
||||
try (ConfigurableApplicationContext ctx = new SpringApplicationBuilder(SpringBootstrap.class).web(false).run(
|
||||
args)) {
|
||||
Configuration conf = ctx.getBean(Configuration.class);
|
||||
|
||||
final File f = new File(args[0]);
|
||||
if (!f.canRead()) {
|
||||
throw new RuntimeException("Configuration file does not exist or cannot be read");
|
||||
}
|
||||
|
||||
Configuration conf = new Configuration(f);
|
||||
final BaseConfiguration apacheConf = new BaseConfiguration();
|
||||
apacheConf.setProperty("instance.name", conf.get(Configuration.INSTANCE_NAME));
|
||||
apacheConf.setProperty("instance.zookeeper.host", conf.get(Configuration.ZOOKEEPERS));
|
||||
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
|
||||
final Instance instance = new ZooKeeperInstance(aconf);
|
||||
final byte[] passwd = conf.get(Configuration.PASSWORD).getBytes(UTF_8);
|
||||
Connector con = instance.getConnector(conf.get(Configuration.USERNAME), new PasswordToken(passwd));
|
||||
Scanner s = con.createScanner(conf.get(Configuration.META_TABLE), con.securityOperations()
|
||||
.getUserAuthorizations(con.whoami()));
|
||||
try {
|
||||
s.setRange(new Range(Meta.METRIC_PREFIX, true, Meta.TAG_PREFIX, false));
|
||||
for (Entry<Key, Value> e : s) {
|
||||
System.out.println(e.getKey().getRow().toString().substring(Meta.METRIC_PREFIX.length()));
|
||||
final BaseConfiguration apacheConf = new BaseConfiguration();
|
||||
Configuration.Accumulo accumuloConf = conf.getAccumulo();
|
||||
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
|
||||
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
|
||||
final Instance instance = new ZooKeeperInstance(aconf);
|
||||
Connector con = instance.getConnector(accumuloConf.getUsername(),
|
||||
new PasswordToken(accumuloConf.getPassword()));
|
||||
Scanner s = con.createScanner(conf.getMetaTable(),
|
||||
con.securityOperations().getUserAuthorizations(con.whoami()));
|
||||
try {
|
||||
s.setRange(new Range(Meta.METRIC_PREFIX, true, Meta.TAG_PREFIX, false));
|
||||
for (Entry<Key, Value> e : s) {
|
||||
System.out.println(e.getKey().getRow().toString().substring(Meta.METRIC_PREFIX.length()));
|
||||
}
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package timely.validator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import javax.validation.ReportAsSingleViolation;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Validates that field {@code notNullFieldName} is not null if
|
||||
* {@code fieldName} is set to {@code fieldValue}
|
||||
*/
|
||||
@Documented
|
||||
@Constraint(validatedBy = { NotEmptyIfFieldSetValidator.class })
|
||||
@Target({ TYPE, ANNOTATION_TYPE })
|
||||
@Retention(RUNTIME)
|
||||
@ReportAsSingleViolation
|
||||
@NotNull
|
||||
public @interface NotEmptyIfFieldSet {
|
||||
|
||||
String fieldName();
|
||||
|
||||
String fieldValue();
|
||||
|
||||
String notNullFieldName();
|
||||
|
||||
String message() default "{NotEmptyIfFieldSet.message}";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
|
||||
@Target({ TYPE, ANNOTATION_TYPE })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@interface List {
|
||||
|
||||
NotEmptyIfFieldSet[] value();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package timely.validator;
|
||||
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Implementation of {@link NotEmptyIfFieldSet} validator.
|
||||
*/
|
||||
public class NotEmptyIfFieldSetValidator implements ConstraintValidator<NotEmptyIfFieldSet, Object> {
|
||||
|
||||
private String fieldName;
|
||||
private String fieldSetValue;
|
||||
private String notNullFieldName;
|
||||
|
||||
@Override
|
||||
public void initialize(NotEmptyIfFieldSet annotation) {
|
||||
fieldName = annotation.fieldName();
|
||||
fieldSetValue = annotation.fieldValue();
|
||||
notNullFieldName = annotation.notNullFieldName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
final String fieldValue = BeanUtils.getProperty(value, fieldName);
|
||||
final String notNullFieldValue = BeanUtils.getProperty(value, notNullFieldName);
|
||||
if (StringUtils.equals(fieldValue, fieldSetValue) && StringUtils.isEmpty(notNullFieldValue)) {
|
||||
context.disableDefaultConstraintViolation();
|
||||
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
|
||||
.addPropertyNode(notNullFieldName).addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package timely.wamp;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import rx.Observer;
|
||||
import ws.wamp.jawampa.WampClient;
|
||||
|
||||
/**
|
||||
* Timely Client state observer
|
||||
*/
|
||||
public class StateObserver implements Observer<WampClient.State> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StateObserver.class);
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
LOG.info("WAMP state completed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
LOG.error("Wamp State Error: {}", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(WampClient.State state) {
|
||||
LOG.info("WAMP state change: {}", state);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package timely.wamp;
|
||||
|
||||
import rx.Observer;
|
||||
import timely.api.request.VersionRequest;
|
||||
import ws.wamp.jawampa.Request;
|
||||
|
||||
/**
|
||||
* Handles timely.version requests
|
||||
*/
|
||||
public class VersionObserver implements Observer<Request> {
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(Request request) {
|
||||
request.reply(VersionRequest.VERSION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
${AnsiColor.RED} ._____________ _
|
||||
${AnsiColor.RED} .. __(___ ___) | |
|
||||
${AnsiColor.RED} ..____ | |(_)_ __ ___ ____ | |_ _
|
||||
${AnsiColor.RED} .._| || | '_ ' _ \/ /_\ \ | \ / /
|
||||
${AnsiColor.RED} . ._ | || | | | | | | ____/ |\ \/ /
|
||||
${AnsiColor.RED} .. ._ ___|_||_|_| |_| |_|_\___,_| \ /${AnsiColor.DEFAULT}
|
||||
=================================${AnsiColor.RED}__/ /${AnsiColor.DEFAULT}===================
|
||||
${AnsiColor.YELLOW}:: Timely ::${AnsiColor.DEFAULT} ${AnsiColor.RED}|___/${AnsiColor.DEFAULT} ${AnsiStyle.FAINT}${AnsiColor.WHITE}${application.formatted-version}${AnsiColor.DEFAULT}${AnsiStyle.NORMAL}
|
||||
@@ -1,78 +1,67 @@
|
||||
package timely;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ConfigurationTest {
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@BeforeClass
|
||||
public static void before() throws Exception {
|
||||
temp.create();
|
||||
@After
|
||||
public void closeContext() {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinimalConfiguration() throws Exception {
|
||||
File conf = temp.newFile("config.properties");
|
||||
conf.deleteOnExit();
|
||||
try (FileWriter writer = new FileWriter(conf)) {
|
||||
writer.write(Configuration.IP + "=127.0.0.1\n");
|
||||
writer.write(Configuration.PUT_PORT + "=54321\n");
|
||||
writer.write(Configuration.QUERY_PORT + "=54322\n");
|
||||
writer.write(Configuration.WEBSOCKET_PORT + "=54323\n");
|
||||
writer.write(Configuration.ZOOKEEPERS + "=localhost:2181\n");
|
||||
writer.write(Configuration.INSTANCE_NAME + "=test\n");
|
||||
writer.write(Configuration.USERNAME + "=root\n");
|
||||
writer.write(Configuration.PASSWORD + "=secret\n");
|
||||
writer.write(Configuration.TIMELY_HTTP_HOST + "=localhost\n");
|
||||
writer.write(Configuration.SSL_USE_GENERATED_KEYPAIR + "=true\n");
|
||||
}
|
||||
new Configuration(conf);
|
||||
context.register(SpringBootstrap.class);
|
||||
EnvironmentTestUtils.addEnvironment(this.context, "timely.server.ip:127.0.0.1", "timely.server.tcp-port:54321",
|
||||
"timely.http.ip:127.0.0.1", "timely.http.port:54322", "timely.websocket.ip:127.0.0.1",
|
||||
"timely.websocket.port:54323", "timely.accumulo.zookeepers:localhost:2181",
|
||||
"timely.accumulo.instance-name:test", "timely.accumulo.username:root",
|
||||
"timely.accumulo.password:secret", "timely.http.host:localhost",
|
||||
"timely.security.ssl.use-generated-keypair:true");
|
||||
context.refresh();
|
||||
Configuration config = this.context.getBean(Configuration.class);
|
||||
assertEquals("127.0.0.1", config.getServer().getIp());
|
||||
assertEquals(54321, config.getServer().getTcpPort());
|
||||
assertEquals(54322, config.getHttp().getPort());
|
||||
assertEquals(54323, config.getWebsocket().getPort());
|
||||
assertEquals("localhost:2181", config.getAccumulo().getZookeepers());
|
||||
assertEquals("test", config.getAccumulo().getInstanceName());
|
||||
assertEquals("root", config.getAccumulo().getUsername());
|
||||
assertEquals("secret", config.getAccumulo().getPassword());
|
||||
assertEquals("localhost", config.getHttp().getHost());
|
||||
assertTrue(config.getSecurity().getSsl().isUseGeneratedKeypair());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void testMissingSSLProperty() throws Exception {
|
||||
File conf = temp.newFile("config2.properties");
|
||||
conf.deleteOnExit();
|
||||
try (FileWriter writer = new FileWriter(conf)) {
|
||||
writer.write(Configuration.IP + "=127.0.0.1\n");
|
||||
writer.write(Configuration.PUT_PORT + "=54321\n");
|
||||
writer.write(Configuration.QUERY_PORT + "=54322\n");
|
||||
writer.write(Configuration.WEBSOCKET_PORT + "=54323\n");
|
||||
writer.write(Configuration.ZOOKEEPERS + "=localhost:2181\n");
|
||||
writer.write(Configuration.INSTANCE_NAME + "=test\n");
|
||||
writer.write(Configuration.USERNAME + "=root\n");
|
||||
writer.write(Configuration.PASSWORD + "=secret\n");
|
||||
writer.write(Configuration.TIMELY_HTTP_HOST + "=localhost\n");
|
||||
}
|
||||
new Configuration(conf);
|
||||
context.register(SpringBootstrap.class);
|
||||
EnvironmentTestUtils.addEnvironment(this.context, "timely.server.ip:127.0.0.1", "timely.server.tcp-port:54321",
|
||||
"timely.http.ip:127.0.0.1", "timely.http.port:54322", "timely.websocket.ip:127.0.0.1",
|
||||
"timely.websocket.port:54323", "timely.accumulo.zookeepers:localhost:2181",
|
||||
"timely.accumulo.instance-name:test", "timely.accumulo.username:root",
|
||||
"timely.accumulo.password:secret", "timely.http.host:localhost");
|
||||
context.refresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSSLProperty() throws Exception {
|
||||
File conf = temp.newFile("config3.properties");
|
||||
conf.deleteOnExit();
|
||||
try (FileWriter writer = new FileWriter(conf)) {
|
||||
writer.write(Configuration.IP + "=127.0.0.1\n");
|
||||
writer.write(Configuration.PUT_PORT + "=54321\n");
|
||||
writer.write(Configuration.QUERY_PORT + "=54322\n");
|
||||
writer.write(Configuration.WEBSOCKET_PORT + "=54323\n");
|
||||
writer.write(Configuration.ZOOKEEPERS + "=localhost:2181\n");
|
||||
writer.write(Configuration.INSTANCE_NAME + "=test\n");
|
||||
writer.write(Configuration.USERNAME + "=root\n");
|
||||
writer.write(Configuration.PASSWORD + "=secret\n");
|
||||
writer.write(Configuration.TIMELY_HTTP_HOST + "=localhost\n");
|
||||
writer.write(Configuration.SSL_CERTIFICATE_FILE + "=/tmp/foo\n");
|
||||
writer.write(Configuration.SSL_PRIVATE_KEY_FILE + "=/tmp/bar\n");
|
||||
}
|
||||
new Configuration(conf);
|
||||
context.register(SpringBootstrap.class);
|
||||
EnvironmentTestUtils.addEnvironment(this.context, "timely.server.ip:127.0.0.1", "timely.server.tcp-port:54321",
|
||||
"timely.http.ip:127.0.0.1", "timely.http.port:54322", "timely.websocket.ip:127.0.0.1",
|
||||
"timely.websocket.port:54323", "timely.accumulo.zookeepers:localhost:2181",
|
||||
"timely.accumulo.instance-name:test", "timely.accumulo.username:root",
|
||||
"timely.accumulo.password:secret", "timely.http.host:localhost",
|
||||
"timely.security.ssl.certificate-file:/tmp/foo", "timely.security.ssl.key-file:/tmp/bar");
|
||||
context.refresh();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,8 +10,6 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import timely.netty.tcp.TcpDecoder;
|
||||
import timely.test.TestCaptureRequestHandler;
|
||||
|
||||
@@ -20,7 +18,7 @@ public class TestServer extends Server {
|
||||
private TestCaptureRequestHandler tcpRequests = new TestCaptureRequestHandler();
|
||||
private TestCaptureRequestHandler httpRequests = new TestCaptureRequestHandler();
|
||||
|
||||
public TestServer(File conf) throws Exception {
|
||||
public TestServer(Configuration conf) throws Exception {
|
||||
super(conf);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.auth.VisibilityCache;
|
||||
import timely.util.JsonUtil;
|
||||
|
||||
@@ -22,7 +23,7 @@ public class MetricTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
VisibilityCache.init();
|
||||
VisibilityCache.init(new Configuration());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -41,7 +42,7 @@ public class MetricTest {
|
||||
|
||||
PairLexicoder<String, Long> rowCoder = new PairLexicoder<>(new StringLexicoder(), new LongLexicoder());
|
||||
DoubleLexicoder valueCoder = new DoubleLexicoder();
|
||||
byte[] row = rowCoder.encode(new ComparablePair<String, Long>("sys.cpu.user", ts));
|
||||
byte[] row = rowCoder.encode(new ComparablePair<>("sys.cpu.user", ts));
|
||||
byte[] value = valueCoder.encode(2.0D);
|
||||
Assert.assertEquals(rowCoder.decode(row), rowCoder.decode(mut.getRow()));
|
||||
Assert.assertEquals(3, mut.getUpdates().size());
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
package timely.api.response.timeseries;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.api.model.Meta;
|
||||
import timely.api.response.timeseries.MetricsResponse;
|
||||
import timely.store.MetaCache;
|
||||
import timely.store.MetaCacheFactory;
|
||||
import timely.test.TestConfiguration;
|
||||
@@ -38,61 +32,37 @@ public class MetricsResponseTest {
|
||||
|
||||
}
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static File conf = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
temp.create();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateHtml() throws Exception {
|
||||
conf = temp.newFile("config.properties");
|
||||
try {
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.toConfiguration(conf);
|
||||
Configuration config = new Configuration(conf);
|
||||
MetaCache cache = MetaCacheFactory.getCache(config);
|
||||
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.user", "instance", "0"));
|
||||
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
|
||||
TestMetricsResponse r = new TestMetricsResponse(config);
|
||||
String html = r.generateHtml().toString();
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
|
||||
} finally {
|
||||
conf.delete();
|
||||
}
|
||||
Configuration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
MetaCache cache = MetaCacheFactory.getCache(cfg);
|
||||
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.user", "instance", "0"));
|
||||
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
|
||||
TestMetricsResponse r = new TestMetricsResponse(cfg);
|
||||
String html = r.generateHtml().toString();
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost instance=0 </td>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateHtmlWithIgnoredTags() throws Exception {
|
||||
conf = temp.newFile("config.properties");
|
||||
try {
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.put(Configuration.METRICS_IGNORED_TAGS, "instance");
|
||||
cfg.toConfiguration(conf);
|
||||
Configuration config = new Configuration(conf);
|
||||
MetaCache cache = MetaCacheFactory.getCache(config);
|
||||
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.user", "instance", "0"));
|
||||
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
|
||||
TestMetricsResponse r = new TestMetricsResponse(config);
|
||||
String html = r.generateHtml().toString();
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
|
||||
} finally {
|
||||
conf.delete();
|
||||
}
|
||||
Configuration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.getMetricsReportIgnoredTags().add("instance");
|
||||
MetaCache cache = MetaCacheFactory.getCache(cfg);
|
||||
cache.add(new Meta("sys.cpu.user", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.user", "instance", "0"));
|
||||
cache.add(new Meta("sys.cpu.idle", "host", "localhost"));
|
||||
cache.add(new Meta("sys.cpu.idle", "instance", "0"));
|
||||
TestMetricsResponse r = new TestMetricsResponse(cfg);
|
||||
String html = r.generateHtml().toString();
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.idle</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
|
||||
Assert.assertTrue(html.contains("<td>sys.cpu.user</td>"));
|
||||
Assert.assertTrue(html.contains("<td>host=localhost </td>"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package timely.auth;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
@@ -10,9 +9,7 @@ import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
@@ -21,19 +18,13 @@ import timely.test.TestConfiguration;
|
||||
|
||||
public class AuthCacheTest {
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static Configuration config = null;
|
||||
private static Configuration config;
|
||||
private static String cookie = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void before() throws Exception {
|
||||
File conf = temp.newFile("config.properties");
|
||||
conf.deleteOnExit();
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.put(Configuration.SESSION_MAX_AGE, "5000");
|
||||
config = cfg.toConfiguration(conf);
|
||||
config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
config.getSecurity().setSessionMaxAge(5000);
|
||||
cookie = URLEncoder.encode(UUID.randomUUID().toString(), StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.cookie.ClientCookieEncoder;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
@@ -21,9 +20,7 @@ import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import timely.Configuration;
|
||||
@@ -61,9 +58,6 @@ public class HttpRequestDecoderTest {
|
||||
|
||||
private static final Long TEST_TIME = System.currentTimeMillis();
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static Configuration config = null;
|
||||
private static Configuration anonConfig = null;
|
||||
private TestHttpQueryDecoder decoder = null;
|
||||
@@ -72,17 +66,9 @@ public class HttpRequestDecoderTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void before() throws Exception {
|
||||
File conf = temp.newFile("config.properties");
|
||||
conf.deleteOnExit();
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.toConfiguration(conf);
|
||||
config = new Configuration(conf);
|
||||
File conf2 = temp.newFile("anon-config.properties");
|
||||
conf2.deleteOnExit();
|
||||
TestConfiguration cfg2 = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg2.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "true");
|
||||
cfg2.toConfiguration(conf2);
|
||||
anonConfig = new Configuration(conf2);
|
||||
config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
anonConfig = TestConfiguration.createMinimalConfigurationForTest();
|
||||
anonConfig.getSecurity().setAllowAnonymousAccess(true);
|
||||
cookie = URLEncoder.encode(UUID.randomUUID().toString(), StandardCharsets.UTF_8.name());
|
||||
AuthCache.setSessionMaxAge(config);
|
||||
AuthCache.getCache().put(cookie, new UsernamePasswordAuthenticationToken("test", "test1"));
|
||||
|
||||
@@ -11,7 +11,6 @@ import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@@ -20,9 +19,7 @@ import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.api.request.auth.BasicAuthLoginRequest;
|
||||
@@ -48,19 +45,11 @@ public class BasicAuthLoginRequestHandlerTest {
|
||||
|
||||
}
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private List<Object> results = new ArrayList<>();
|
||||
|
||||
@BeforeClass
|
||||
public static void before() throws Exception {
|
||||
File conf = temp.newFile("pre-config.properties");
|
||||
conf.deleteOnExit();
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.toConfiguration(conf);
|
||||
Configuration config = new Configuration(conf);
|
||||
AuthCache.setSessionMaxAge(config);
|
||||
AuthCache.setSessionMaxAge(TestConfiguration.createMinimalConfigurationForTest());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@@ -75,11 +64,7 @@ public class BasicAuthLoginRequestHandlerTest {
|
||||
|
||||
@Test
|
||||
public void testBasicAuthentication() throws Exception {
|
||||
File conf = temp.newFile("config.properties");
|
||||
conf.deleteOnExit();
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.toConfiguration(conf);
|
||||
Configuration config = new Configuration(conf);
|
||||
Configuration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
|
||||
// @formatter:off
|
||||
String form =
|
||||
@@ -99,7 +84,7 @@ public class BasicAuthLoginRequestHandlerTest {
|
||||
|
||||
BasicAuthLoginRequestHandler handler = new BasicAuthLoginRequestHandler(config);
|
||||
CaptureChannelHandlerContext ctx = new CaptureChannelHandlerContext();
|
||||
handler.channelRead(ctx, (BasicAuthLoginRequest) result);
|
||||
handler.channelRead(ctx, result);
|
||||
Assert.assertNotNull(ctx.msg);
|
||||
Assert.assertTrue(ctx.msg instanceof DefaultFullHttpResponse);
|
||||
DefaultFullHttpResponse response = (DefaultFullHttpResponse) ctx.msg;
|
||||
@@ -118,11 +103,7 @@ public class BasicAuthLoginRequestHandlerTest {
|
||||
|
||||
@Test
|
||||
public void testBasicAuthenticationFailure() throws Exception {
|
||||
File conf = temp.newFile("config2.properties");
|
||||
conf.deleteOnExit();
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.toConfiguration(conf);
|
||||
Configuration config = new Configuration(conf);
|
||||
Configuration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
|
||||
// @formatter:off
|
||||
String form =
|
||||
@@ -142,7 +123,7 @@ public class BasicAuthLoginRequestHandlerTest {
|
||||
|
||||
BasicAuthLoginRequestHandler handler = new BasicAuthLoginRequestHandler(config);
|
||||
CaptureChannelHandlerContext ctx = new CaptureChannelHandlerContext();
|
||||
handler.channelRead(ctx, (BasicAuthLoginRequest) result);
|
||||
handler.channelRead(ctx, result);
|
||||
Assert.assertNotNull(ctx.msg);
|
||||
Assert.assertTrue(ctx.msg instanceof DefaultFullHttpResponse);
|
||||
DefaultFullHttpResponse response = (DefaultFullHttpResponse) ctx.msg;
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.api.model.Metric;
|
||||
import timely.api.model.Tag;
|
||||
import timely.api.request.VersionRequest;
|
||||
@@ -22,7 +23,7 @@ public class TcpDecoderTest {
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
VisibilityCache.init();
|
||||
VisibilityCache.init(new Configuration());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -5,7 +5,6 @@ import io.netty.channel.local.LocalChannel;
|
||||
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
@@ -16,9 +15,7 @@ import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import timely.Configuration;
|
||||
@@ -53,9 +50,6 @@ public class WebSocketRequestDecoderTest {
|
||||
|
||||
private static final Long TEST_TIME = System.currentTimeMillis();
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static Configuration config = null;
|
||||
private static Configuration anonConfig = null;
|
||||
private WebSocketRequestDecoder decoder = null;
|
||||
@@ -65,17 +59,9 @@ public class WebSocketRequestDecoderTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void before() throws Exception {
|
||||
File conf = temp.newFile("config.properties");
|
||||
conf.deleteOnExit();
|
||||
TestConfiguration cfg = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg.toConfiguration(conf);
|
||||
config = new Configuration(conf);
|
||||
File conf2 = temp.newFile("anon-config.properties");
|
||||
conf2.deleteOnExit();
|
||||
TestConfiguration cfg2 = TestConfiguration.createMinimalConfigurationForTest();
|
||||
cfg2.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "true");
|
||||
cfg2.toConfiguration(conf2);
|
||||
anonConfig = new Configuration(conf2);
|
||||
config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
anonConfig = TestConfiguration.createMinimalConfigurationForTest();
|
||||
anonConfig.getSecurity().setAllowAnonymousAccess(true);
|
||||
cookie = URLEncoder.encode(UUID.randomUUID().toString(), StandardCharsets.UTF_8.name());
|
||||
AuthCache.setSessionMaxAge(config);
|
||||
AuthCache.getCache().put(cookie, new UsernamePasswordAuthenticationToken("test", "test1"));
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.apache.accumulo.core.iterators.SortedMapIterator;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.api.model.Metric;
|
||||
import timely.api.model.Tag;
|
||||
import timely.auth.VisibilityCache;
|
||||
@@ -37,7 +38,7 @@ public class DownsampleIteratorTest {
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
VisibilityCache.init();
|
||||
VisibilityCache.init(new Configuration());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
||||
@@ -1,37 +1,18 @@
|
||||
package timely.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Properties;
|
||||
|
||||
import timely.Configuration;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
public class TestConfiguration {
|
||||
|
||||
public class TestConfiguration extends Properties {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
public static final String TIMELY_HTTP_ADDRESS_DEFAULT = "localhost";
|
||||
|
||||
public Configuration toConfiguration(File propertiesFile) throws Exception {
|
||||
this.store(Files.newWriter(propertiesFile, StandardCharsets.UTF_8), null);
|
||||
return new Configuration(propertiesFile);
|
||||
}
|
||||
|
||||
public static TestConfiguration createMinimalConfigurationForTest() {
|
||||
TestConfiguration cfg = new TestConfiguration();
|
||||
cfg.put(Configuration.IP, "127.0.0.1");
|
||||
cfg.put(Configuration.PUT_PORT, "54321");
|
||||
cfg.put(Configuration.QUERY_PORT, "54322");
|
||||
cfg.put(Configuration.WEBSOCKET_PORT, "54323");
|
||||
cfg.put(Configuration.ZOOKEEPERS, "localhost:2181");
|
||||
cfg.put(Configuration.INSTANCE_NAME, "test");
|
||||
cfg.put(Configuration.USERNAME, "root");
|
||||
cfg.put(Configuration.PASSWORD, "secret");
|
||||
cfg.put(Configuration.TIMELY_HTTP_HOST, "localhost");
|
||||
cfg.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "true");
|
||||
cfg.put(Configuration.MAX_LATENCY, "2s");
|
||||
cfg.put(Configuration.WS_TIMEOUT_SECONDS, "20");
|
||||
public static Configuration createMinimalConfigurationForTest() {
|
||||
Configuration cfg = new Configuration().getServer().setIp("127.0.0.1").getServer().setTcpPort(54321).getHttp()
|
||||
.setIp("127.0.0.1").getHttp().setPort(54322).getWebsocket().setIp("127.0.0.1").getWebsocket()
|
||||
.setPort(54323).getAccumulo().setZookeepers("localhost:2181").getAccumulo().setInstanceName("test")
|
||||
.getAccumulo().setUsername("root").getAccumulo().setPassword("secret").getHttp().setHost("localhost")
|
||||
.getSecurity().getSsl().setUseGeneratedKeypair(true).getAccumulo().getWrite().setLatency("2s")
|
||||
.getWebsocket().setTimeout(20);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,8 @@ import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.apache.accumulo.core.client.Connector;
|
||||
@@ -41,9 +39,9 @@ public class OneWaySSLBase extends QueryBase {
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
protected static File conf = null;
|
||||
private static File clientTrustStoreFile = null;
|
||||
protected static MiniAccumuloCluster mac = null;
|
||||
protected static Configuration conf = null;
|
||||
protected static File clientTrustStoreFile = null;
|
||||
|
||||
protected SSLSocketFactory getSSLSocketFactory() throws Exception {
|
||||
SslContextBuilder builder = SslContextBuilder.forClient();
|
||||
@@ -57,14 +55,14 @@ public class OneWaySSLBase extends QueryBase {
|
||||
return jdkSslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
protected static void setupSSL(TestConfiguration config) throws Exception {
|
||||
protected static void setupSSL(Configuration config) throws Exception {
|
||||
SelfSignedCertificate serverCert = new SelfSignedCertificate();
|
||||
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
|
||||
clientTrustStoreFile = serverCert.certificate().getAbsoluteFile();
|
||||
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
|
||||
config.put(Configuration.SSL_USE_OPENSSL, "false");
|
||||
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
|
||||
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "true");
|
||||
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setUseOpenssl(false);
|
||||
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
|
||||
config.getSecurity().setAllowAnonymousAccess(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,28 +74,19 @@ public class OneWaySSLBase extends QueryBase {
|
||||
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
|
||||
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
con.setHostnameVerifier(new HostnameVerifier() {
|
||||
|
||||
@Override
|
||||
public boolean verify(String arg0, SSLSession arg1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
con.setHostnameVerifier((host, session) -> true);
|
||||
return con;
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
temp.create();
|
||||
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
|
||||
mac = new MiniAccumuloCluster(macConfig);
|
||||
mac.start();
|
||||
conf = temp.newFile("config.properties");
|
||||
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
|
||||
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
|
||||
setupSSL(config);
|
||||
config.toConfiguration(conf);
|
||||
conf = TestConfiguration.createMinimalConfigurationForTest();
|
||||
conf.getAccumulo().setInstanceName(mac.getInstanceName());
|
||||
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
|
||||
setupSSL(conf);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
||||
@@ -6,15 +6,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.cookie.ClientCookieDecoder;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import io.netty.handler.ssl.ApplicationProtocolConfig;
|
||||
import io.netty.handler.ssl.JdkSslClientContext;
|
||||
import io.netty.handler.ssl.JdkSslContext;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
@@ -22,27 +14,18 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.apache.accumulo.core.client.Connector;
|
||||
import org.apache.accumulo.core.security.Authorizations;
|
||||
import org.apache.accumulo.minicluster.MiniAccumuloCluster;
|
||||
import org.apache.accumulo.minicluster.MiniAccumuloConfig;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.Server;
|
||||
import timely.api.request.auth.BasicAuthLoginRequest;
|
||||
import timely.api.request.timeseries.QueryRequest;
|
||||
@@ -50,7 +33,6 @@ import timely.api.response.timeseries.QueryResponse;
|
||||
import timely.auth.AuthCache;
|
||||
import timely.netty.Constants;
|
||||
import timely.test.IntegrationTest;
|
||||
import timely.test.TestConfiguration;
|
||||
import timely.util.JsonUtil;
|
||||
|
||||
/**
|
||||
@@ -64,36 +46,6 @@ public class OneWaySSLBasicAuthAccessIT extends OneWaySSLBase {
|
||||
|
||||
private static final Long TEST_TIME = System.currentTimeMillis();
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
private static File conf = null;
|
||||
|
||||
private static File clientTrustStoreFile = null;
|
||||
|
||||
protected SSLSocketFactory getSSLSocketFactory() throws Exception {
|
||||
SslContextBuilder builder = SslContextBuilder.forClient();
|
||||
builder.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED);
|
||||
builder.sslProvider(SslProvider.JDK);
|
||||
builder.trustManager(clientTrustStoreFile); // Trust the server cert
|
||||
SslContext ctx = builder.build();
|
||||
Assert.assertEquals(JdkSslClientContext.class, ctx.getClass());
|
||||
JdkSslContext jdk = (JdkSslContext) ctx;
|
||||
SSLContext jdkSslContext = jdk.context();
|
||||
return jdkSslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
protected static void setupSSL(TestConfiguration config) throws Exception {
|
||||
SelfSignedCertificate serverCert = new SelfSignedCertificate();
|
||||
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
clientTrustStoreFile = serverCert.certificate().getAbsoluteFile();
|
||||
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
|
||||
config.put(Configuration.SSL_USE_OPENSSL, "false");
|
||||
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
|
||||
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
|
||||
}
|
||||
|
||||
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
|
||||
// Username and password are set in src/test/resources/security.xml
|
||||
return getUrlConnection("test", "test1", url);
|
||||
@@ -103,13 +55,7 @@ public class OneWaySSLBasicAuthAccessIT extends OneWaySSLBase {
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
|
||||
URL loginURL = new URL(url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + "/login");
|
||||
HttpsURLConnection con = (HttpsURLConnection) loginURL.openConnection();
|
||||
con.setHostnameVerifier(new HostnameVerifier() {
|
||||
|
||||
@Override
|
||||
public boolean verify(String arg0, SSLSession arg1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
con.setHostnameVerifier((host, session) -> true);
|
||||
con.setRequestMethod("POST");
|
||||
con.setDoOutput(true);
|
||||
con.setRequestProperty("Content-Type", "application/json");
|
||||
@@ -131,47 +77,25 @@ public class OneWaySSLBasicAuthAccessIT extends OneWaySSLBase {
|
||||
Assert.assertEquals(Constants.COOKIE_NAME, sessionCookie.name());
|
||||
con = (HttpsURLConnection) url.openConnection();
|
||||
con.setRequestProperty(Names.COOKIE, sessionCookie.name() + "=" + sessionCookie.value());
|
||||
con.setHostnameVerifier(new HostnameVerifier() {
|
||||
|
||||
@Override
|
||||
public boolean verify(String arg0, SSLSession arg1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
con.setHostnameVerifier((host, session) -> true);
|
||||
return con;
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
temp.create();
|
||||
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
|
||||
mac = new MiniAccumuloCluster(macConfig);
|
||||
mac.start();
|
||||
conf = temp.newFile("config.properties");
|
||||
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
|
||||
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
|
||||
setupSSL(config);
|
||||
config.toConfiguration(conf);
|
||||
OneWaySSLBase.beforeClass();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
mac.stop();
|
||||
OneWaySSLBase.afterClass();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
super.setup();
|
||||
Connector con = mac.getConnector("root", "secret");
|
||||
con.securityOperations().changeUserAuthorizations("root", new Authorizations("A", "B", "C", "D", "E", "F"));
|
||||
con.tableOperations().list().forEach(t -> {
|
||||
if (t.startsWith("timely")) {
|
||||
try {
|
||||
con.tableOperations().delete(t);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
|
||||
@@ -33,8 +33,8 @@ import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.Server;
|
||||
import timely.Configuration;
|
||||
import timely.auth.AuthCache;
|
||||
import timely.netty.Constants;
|
||||
import timely.test.TestConfiguration;
|
||||
@@ -46,7 +46,7 @@ public class TwoWaySSLFailureIT extends QueryBase {
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
private static File conf = null;
|
||||
private static Configuration conf = null;
|
||||
|
||||
private static SelfSignedCertificate serverCert = null;
|
||||
private static File clientTrustStoreFile = null;
|
||||
@@ -75,14 +75,14 @@ public class TwoWaySSLFailureIT extends QueryBase {
|
||||
return jdkSslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
protected static void setupSSL(TestConfiguration config) throws Exception {
|
||||
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
|
||||
protected static void setupSSL(Configuration config) throws Exception {
|
||||
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
|
||||
// Needed for 2way SSL
|
||||
config.put(Configuration.SSL_TRUST_STORE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
config.put(Configuration.SSL_USE_OPENSSL, "false");
|
||||
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
|
||||
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
|
||||
config.getSecurity().getSsl().setTrustStoreFile(serverCert.certificate().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setUseOpenssl(false);
|
||||
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
|
||||
config.getSecurity().setAllowAnonymousAccess(false);
|
||||
}
|
||||
|
||||
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
|
||||
@@ -132,12 +132,10 @@ public class TwoWaySSLFailureIT extends QueryBase {
|
||||
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
|
||||
mac = new MiniAccumuloCluster(macConfig);
|
||||
mac.start();
|
||||
conf = temp.newFile("config.properties");
|
||||
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
|
||||
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
|
||||
setupSSL(config);
|
||||
config.toConfiguration(conf);
|
||||
conf = TestConfiguration.createMinimalConfigurationForTest();
|
||||
conf.getAccumulo().setInstanceName(mac.getInstanceName());
|
||||
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
|
||||
setupSSL(conf);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
||||
@@ -18,10 +18,8 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import org.apache.accumulo.core.client.Connector;
|
||||
@@ -38,8 +36,8 @@ import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.Server;
|
||||
import timely.Configuration;
|
||||
import timely.api.request.timeseries.QueryRequest;
|
||||
import timely.api.response.timeseries.QueryResponse;
|
||||
import timely.auth.AuthCache;
|
||||
@@ -64,7 +62,7 @@ public class TwoWaySSLIT extends QueryBase {
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
private static File conf = null;
|
||||
private static Configuration conf = null;
|
||||
|
||||
protected static SelfSignedCertificate serverCert = null;
|
||||
protected static File clientTrustStoreFile = null;
|
||||
@@ -92,14 +90,14 @@ public class TwoWaySSLIT extends QueryBase {
|
||||
return jdkSslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
protected static void setupSSL(TestConfiguration config) throws Exception {
|
||||
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
|
||||
protected static void setupSSL(Configuration config) throws Exception {
|
||||
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
|
||||
// Needed for 2way SSL
|
||||
config.put(Configuration.SSL_TRUST_STORE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
config.put(Configuration.SSL_USE_OPENSSL, "false");
|
||||
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
|
||||
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
|
||||
config.getSecurity().getSsl().setTrustStoreFile(serverCert.certificate().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setUseOpenssl(false);
|
||||
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
|
||||
config.getSecurity().setAllowAnonymousAccess(false);
|
||||
}
|
||||
|
||||
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
|
||||
@@ -111,13 +109,7 @@ public class TwoWaySSLIT extends QueryBase {
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLSocketFactory());
|
||||
URL loginURL = new URL(url.getProtocol() + "://" + url.getHost() + ":" + url.getPort() + "/login");
|
||||
HttpsURLConnection con = (HttpsURLConnection) loginURL.openConnection();
|
||||
con.setHostnameVerifier(new HostnameVerifier() {
|
||||
|
||||
@Override
|
||||
public boolean verify(String arg0, SSLSession arg1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
con.setHostnameVerifier((host, session) -> true);
|
||||
con.setRequestMethod("GET");
|
||||
con.setDoOutput(true);
|
||||
con.setRequestProperty("Content-Type", "application/json");
|
||||
@@ -133,28 +125,19 @@ public class TwoWaySSLIT extends QueryBase {
|
||||
Assert.assertEquals(Constants.COOKIE_NAME, sessionCookie.name());
|
||||
con = (HttpsURLConnection) url.openConnection();
|
||||
con.setRequestProperty(Names.COOKIE, sessionCookie.name() + "=" + sessionCookie.value());
|
||||
con.setHostnameVerifier(new HostnameVerifier() {
|
||||
|
||||
@Override
|
||||
public boolean verify(String arg0, SSLSession arg1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
con.setHostnameVerifier((host, session) -> true);
|
||||
return con;
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
temp.create();
|
||||
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
|
||||
mac = new MiniAccumuloCluster(macConfig);
|
||||
mac.start();
|
||||
conf = temp.newFile("config.properties");
|
||||
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
|
||||
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
|
||||
setupSSL(config);
|
||||
config.toConfiguration(conf);
|
||||
conf = TestConfiguration.createMinimalConfigurationForTest();
|
||||
conf.getAccumulo().setInstanceName(mac.getInstanceName());
|
||||
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
|
||||
setupSSL(conf);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
||||
@@ -38,8 +38,8 @@ import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.Server;
|
||||
import timely.Configuration;
|
||||
import timely.api.request.timeseries.QueryRequest;
|
||||
import timely.api.response.timeseries.QueryResponse;
|
||||
import timely.auth.AuthCache;
|
||||
@@ -65,7 +65,7 @@ public class TwoWaySSLOpenSSLIT extends QueryBase {
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
private static File conf = null;
|
||||
private static Configuration conf = null;
|
||||
|
||||
protected static SelfSignedCertificate serverCert = null;
|
||||
protected static File clientTrustStoreFile = null;
|
||||
@@ -93,14 +93,14 @@ public class TwoWaySSLOpenSSLIT extends QueryBase {
|
||||
return jdkSslContext.getSocketFactory();
|
||||
}
|
||||
|
||||
protected static void setupSSL(TestConfiguration config) throws Exception {
|
||||
config.put(Configuration.SSL_CERTIFICATE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
config.put(Configuration.SSL_PRIVATE_KEY_FILE, serverCert.privateKey().getAbsolutePath());
|
||||
protected static void setupSSL(Configuration config) throws Exception {
|
||||
config.getSecurity().getSsl().setCertificateFile(serverCert.certificate().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setKeyFile(serverCert.privateKey().getAbsolutePath());
|
||||
// Needed for 2way SSL
|
||||
config.put(Configuration.SSL_TRUST_STORE_FILE, serverCert.certificate().getAbsolutePath());
|
||||
config.put(Configuration.SSL_USE_OPENSSL, "true");
|
||||
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "false");
|
||||
config.put(Configuration.ALLOW_ANONYMOUS_ACCESS, "false");
|
||||
config.getSecurity().getSsl().setTrustStoreFile(serverCert.certificate().getAbsolutePath());
|
||||
config.getSecurity().getSsl().setUseOpenssl(false);
|
||||
config.getSecurity().getSsl().setUseGeneratedKeypair(false);
|
||||
config.getSecurity().setAllowAnonymousAccess(false);
|
||||
}
|
||||
|
||||
protected HttpsURLConnection getUrlConnection(URL url) throws Exception {
|
||||
@@ -150,12 +150,10 @@ public class TwoWaySSLOpenSSLIT extends QueryBase {
|
||||
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
|
||||
mac = new MiniAccumuloCluster(macConfig);
|
||||
mac.start();
|
||||
conf = temp.newFile("config.properties");
|
||||
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
|
||||
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
|
||||
setupSSL(config);
|
||||
config.toConfiguration(conf);
|
||||
conf = TestConfiguration.createMinimalConfigurationForTest();
|
||||
conf.getAccumulo().setInstanceName(mac.getInstanceName());
|
||||
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
|
||||
setupSSL(conf);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
||||
@@ -131,20 +131,20 @@ public class HttpApiIT extends OneWaySSLBase {
|
||||
String suggest = "https://localhost:54322/api/search/lookup?";
|
||||
|
||||
// Test a known query
|
||||
String result = query(suggest + "m=sys.cpu.idle%7Btag3%3D*%7D");
|
||||
String result = query(suggest + "m=sys.cpu.idle%7Btag3%3D.*%7D");
|
||||
assertTrue(result, result.indexOf("\"results\":[{\"tags\":{\"tag3\":\"value3\"}") >= 0);
|
||||
|
||||
// Test a fail
|
||||
result = query(suggest + "m=sys.cpu.idle%7Btag3%3Dstupid%7D");
|
||||
result = query(suggest + "m=sys.cpu.idle%7Btag3%3Dnomatch%7D");
|
||||
assertTrue(result.indexOf("\"results\":[]") >= 0);
|
||||
|
||||
// Test multiple results
|
||||
result = query(suggest + "m=sys.cpu.idle%7Btag3%3D*,tag4%3D*%7D");
|
||||
result = query(suggest + "m=sys.cpu.idle%7Btag3%3D.*,tag4%3D.*%7D");
|
||||
assertTrue(result, result.indexOf("\"results\":[{\"tags\":{\"tag3\":\"value3\"}") >= 0);
|
||||
assertTrue(result, result.indexOf("{\"tags\":{\"tag4\":\"value4\"}") >= 0);
|
||||
|
||||
// Find a tag only in the metric that matches
|
||||
result = query(suggest + "m=sys.cpu.idle%7Btag1%3D*%7D");
|
||||
result = query(suggest + "m=sys.cpu.idle%7Btag1%3D.*%7D");
|
||||
assertTrue(result, result.indexOf("\"results\":[]") >= 0);
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -6,7 +6,6 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
@@ -39,9 +38,9 @@ import org.junit.rules.TemporaryFolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.Server;
|
||||
import timely.TestServer;
|
||||
import timely.Configuration;
|
||||
import timely.api.model.Metric;
|
||||
import timely.api.model.Tag;
|
||||
import timely.api.request.VersionRequest;
|
||||
@@ -62,20 +61,18 @@ public class TimelyTcpIT {
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
private static File conf = null;
|
||||
private static Configuration conf = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
temp.create();
|
||||
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
|
||||
mac = new MiniAccumuloCluster(macConfig);
|
||||
mac.start();
|
||||
conf = temp.newFile("config.properties");
|
||||
TestConfiguration config = TestConfiguration.createMinimalConfigurationForTest();
|
||||
config.put(Configuration.INSTANCE_NAME, mac.getInstanceName());
|
||||
config.put(Configuration.ZOOKEEPERS, mac.getZooKeepers());
|
||||
config.put(Configuration.SSL_USE_GENERATED_KEYPAIR, "true");
|
||||
config.toConfiguration(conf);
|
||||
conf = TestConfiguration.createMinimalConfigurationForTest();
|
||||
conf.getAccumulo().setInstanceName(mac.getInstanceName());
|
||||
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
|
||||
conf.getSecurity().getSsl().setUseOpenssl(false);
|
||||
conf.getSecurity().getSsl().setUseGeneratedKeypair(true);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package timely.test.integration.websocket;
|
||||
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import org.apache.accumulo.core.client.Connector;
|
||||
import org.apache.accumulo.minicluster.MiniAccumuloCluster;
|
||||
import org.apache.accumulo.minicluster.MiniAccumuloConfig;
|
||||
import org.junit.*;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import rx.Observable;
|
||||
import timely.Configuration;
|
||||
import timely.TestServer;
|
||||
import timely.auth.AuthCache;
|
||||
import timely.test.IntegrationTest;
|
||||
import timely.test.TestConfiguration;
|
||||
import ws.wamp.jawampa.Reply;
|
||||
import ws.wamp.jawampa.WampClient;
|
||||
import ws.wamp.jawampa.WampClientBuilder;
|
||||
import ws.wamp.jawampa.connection.IWampConnectorProvider;
|
||||
import ws.wamp.jawampa.transport.netty.NettyWampClientConnectorProvider;
|
||||
import ws.wamp.jawampa.transport.netty.NettyWampConnectionConfig;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Integration tests for the operations available over WAMP
|
||||
*/
|
||||
@Category(IntegrationTest.class)
|
||||
public class WampIT {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WampIT.class);
|
||||
private static final Long TEST_TIME = System.currentTimeMillis();
|
||||
|
||||
@ClassRule
|
||||
public static final TemporaryFolder temp = new TemporaryFolder();
|
||||
|
||||
private static MiniAccumuloCluster mac = null;
|
||||
private static Configuration conf = null;
|
||||
private static TestServer server = null;
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
final MiniAccumuloConfig macConfig = new MiniAccumuloConfig(temp.newFolder("mac"), "secret");
|
||||
mac = new MiniAccumuloCluster(macConfig);
|
||||
mac.start();
|
||||
conf = TestConfiguration.createMinimalConfigurationForTest();
|
||||
conf.getAccumulo().setInstanceName(mac.getInstanceName());
|
||||
conf.getAccumulo().setZookeepers(mac.getZooKeepers());
|
||||
conf.getSecurity().getSsl().setUseOpenssl(false);
|
||||
conf.getSecurity().getSsl().setUseGeneratedKeypair(true);
|
||||
|
||||
server = new TestServer(conf);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
server.shutdown();
|
||||
mac.stop();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
Connector con = mac.getConnector("root", "secret");
|
||||
con.tableOperations().list().forEach(t -> {
|
||||
if (t.startsWith("timely")) {
|
||||
try {
|
||||
con.tableOperations().delete(t);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
AuthCache.resetSessionMaxAge();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion() throws Exception {
|
||||
//final TestServer m = new TestServer(conf);
|
||||
|
||||
final WampClient client;
|
||||
IWampConnectorProvider connectorProvider = new NettyWampClientConnectorProvider();
|
||||
NettyWampConnectionConfig connectionConfiguration = new NettyWampConnectionConfig.Builder()
|
||||
.withSslContext(SslContextBuilder.forClient().build())
|
||||
.build();
|
||||
|
||||
WampClientBuilder builder = new WampClientBuilder();
|
||||
builder.withConnectorProvider(connectorProvider)
|
||||
.withConnectionConfiguration(connectionConfiguration)
|
||||
.withUri("wss://localhost:54323/wamp")
|
||||
.withRealm("default")
|
||||
.withInfiniteReconnects()
|
||||
.withReconnectInterval(5, TimeUnit.SECONDS);
|
||||
// Create a client through the builder. This will not immediately start
|
||||
// a connection attempt
|
||||
client = builder.build();
|
||||
client.open();
|
||||
|
||||
Observable<Reply> oReply = client.call("timely.version");
|
||||
Reply reply = oReply.toBlocking().last();
|
||||
System.out.println(reply.toString());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -573,7 +573,7 @@ public class WebSocketIT extends OneWaySSLBase {
|
||||
" \"operation\" : \"lookup\","+
|
||||
" \"metric\" : \"sys.cpu.idle\","+
|
||||
" \"tags\" : ["+
|
||||
"\"tag3=*\""+
|
||||
"\"tag3=.*\""+
|
||||
"]"+
|
||||
"}";
|
||||
// @formatter:on
|
||||
|
||||
Reference in new issue
Block a user