thingsboard-aplcache
Changes
common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistry.java 25(+19 -6)
common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/IntervalRegistryLogger.java 2(+1 -1)
common/transport/src/test/java/org/thingsboard/server/common/transport/quota/HostRequestsQuotaServiceTest.java 16(+14 -2)
Details
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index da35c6c..a2ae7e2 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -110,11 +110,20 @@ coap:
#Quota parameters
quota:
host:
+ # Max allowed number of API requests in interval for single host
limit: "${QUOTA_HOST_LIMIT:10000}"
+ # Interval duration
intervalMs: "${QUOTA_HOST_INTERVAL_MS:60000}"
+ # Maximum silence duration for host after which Host removed from QuotaService. Must be bigger than intervalMs
ttlMs: "${QUOTA_HOST_TTL_MS:60000}"
+ # Interval for scheduled task that cleans expired records. TTL is used for expiring
cleanPeriodMs: "${QUOTA_HOST_CLEAN_PERIOD_MS:300000}"
+ # Enable Host API Limits
enabled: "${QUOTA_HOST_ENABLED:false}"
+ # Array of whitelist hosts
+ whitelist: "${QUOTA_HOST_WHITELIST:localhost,127.0.0.1}"
+ # Array of blacklist hosts
+ blacklist: "${QUOTA_HOST_BLACKLIST:}"
log:
topSize: 10
intervalMin: 2
diff --git a/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistry.java b/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistry.java
index 9f8f946..4db6ff0 100644
--- a/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistry.java
+++ b/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistry.java
@@ -1,12 +1,12 @@
/**
* Copyright © 2016-2017 The Thingsboard Authors
- *
+ * <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,12 +15,15 @@
*/
package org.thingsboard.server.common.transport.quota.inmemory;
+import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@@ -35,11 +38,17 @@ public class HostRequestIntervalRegistry {
private final Map<String, IntervalCount> hostCounts = new ConcurrentHashMap<>();
private final long intervalDurationMs;
private final long ttlMs;
+ private final Set<String> whiteList;
+ private final Set<String> blackList;
public HostRequestIntervalRegistry(@Value("${quota.host.intervalMs}") long intervalDurationMs,
- @Value("${quota.host.ttlMs}") long ttlMs) {
+ @Value("${quota.host.ttlMs}") long ttlMs,
+ @Value("${quota.host.whitelist}") String whiteList,
+ @Value("${quota.host.blacklist}") String blackList) {
this.intervalDurationMs = intervalDurationMs;
this.ttlMs = ttlMs;
+ this.whiteList = Sets.newHashSet(StringUtils.split(whiteList, ','));
+ this.blackList = Sets.newHashSet(StringUtils.split(blackList, ','));
}
@PostConstruct
@@ -47,11 +56,15 @@ public class HostRequestIntervalRegistry {
if (ttlMs < intervalDurationMs) {
log.warn("TTL for IntervalRegistry [{}] smaller than interval duration [{}]", ttlMs, intervalDurationMs);
}
+ log.info("Start Host Quota Service with whitelist {}", whiteList);
+ log.info("Start Host Quota Service with blacklist {}", blackList);
}
public long tick(String clientHostId) {
- if ("localhost".equals(clientHostId) || "127.0.0.1".equals(clientHostId)) {
+ if (whiteList.contains(clientHostId)) {
return 0;
+ } else if (blackList.contains(clientHostId)) {
+ return Long.MAX_VALUE;
}
IntervalCount intervalCount = hostCounts.computeIfAbsent(clientHostId, s -> new IntervalCount(intervalDurationMs));
return intervalCount.resetIfExpiredAndTick();
diff --git a/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/IntervalRegistryLogger.java b/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/IntervalRegistryLogger.java
index 91797d4..3f660fc 100644
--- a/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/IntervalRegistryLogger.java
+++ b/common/transport/src/main/java/org/thingsboard/server/common/transport/quota/inmemory/IntervalRegistryLogger.java
@@ -80,7 +80,7 @@ public class IntervalRegistryLogger {
private void log(Map<String, Long> top) {
StringBuilder builder = new StringBuilder("Quota Statistic : ");
for (Map.Entry<String, Long> host : top.entrySet()) {
- builder.append(host.getKey()).append(" : ").append(host.getValue());
+ builder.append(host.getKey()).append(" : ").append(host.getValue()).append(" ; ");
}
log.info(builder.toString());
diff --git a/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/HostRequestsQuotaServiceTest.java b/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/HostRequestsQuotaServiceTest.java
index 475fccc..b8c9284 100644
--- a/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/HostRequestsQuotaServiceTest.java
+++ b/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/HostRequestsQuotaServiceTest.java
@@ -44,9 +44,9 @@ public class HostRequestsQuotaServiceTest {
}
@Test
- public void hostQuotaValidated() {
+ public void quotaExceededIfRequestCountBiggerThanAllowed() {
when(requestRegistry.tick("key")).thenReturn(10L);
- when(requestsPolicy.isValid(10L)).thenReturn(true);
+ when(requestsPolicy.isValid(10L)).thenReturn(false);
assertTrue(quotaService.isQuotaExceeded("key"));
@@ -56,6 +56,18 @@ public class HostRequestsQuotaServiceTest {
}
@Test
+ public void quotaNotExceededIfRequestCountLessThanAllowed() {
+ when(requestRegistry.tick("key")).thenReturn(10L);
+ when(requestsPolicy.isValid(10L)).thenReturn(true);
+
+ assertFalse(quotaService.isQuotaExceeded("key"));
+
+ verify(requestRegistry).tick("key");
+ verify(requestsPolicy).isValid(10L);
+ verifyNoMoreInteractions(requestRegistry, requestsPolicy);
+ }
+
+ @Test
public void serviceCanBeDisabled() {
quotaService = new HostRequestsQuotaService(requestRegistry, requestsPolicy, registryCleaner, registryLogger, false);
assertFalse(quotaService.isQuotaExceeded("key"));
diff --git a/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistryTest.java b/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistryTest.java
index cb21cce..ff1e525 100644
--- a/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistryTest.java
+++ b/common/transport/src/test/java/org/thingsboard/server/common/transport/quota/inmemory/HostRequestIntervalRegistryTest.java
@@ -15,9 +15,12 @@
*/
package org.thingsboard.server.common.transport.quota.inmemory;
+import com.google.common.collect.Sets;
import org.junit.Before;
import org.junit.Test;
+import java.util.Collections;
+
import static org.junit.Assert.assertEquals;
/**
@@ -30,7 +33,7 @@ public class HostRequestIntervalRegistryTest {
@Before
public void init() {
- registry = new HostRequestIntervalRegistry(10000L, 100L);
+ registry = new HostRequestIntervalRegistry(10000L, 100L,"g1,g2", "b1");
}
@Test
@@ -54,4 +57,29 @@ public class HostRequestIntervalRegistryTest {
assertEquals(1L, registry.tick("aaa"));
assertEquals(2L, registry.tick("bbb"));
}
+
+ @Test
+ public void domainFromWhitelistNotCounted(){
+ assertEquals(0L, registry.tick("g1"));
+ assertEquals(0L, registry.tick("g1"));
+ assertEquals(0L, registry.tick("g2"));
+ }
+
+ @Test
+ public void domainFromBlackListReturnMaxValue(){
+ assertEquals(Long.MAX_VALUE, registry.tick("b1"));
+ assertEquals(Long.MAX_VALUE, registry.tick("b1"));
+ }
+
+ @Test
+ public void emptyWhitelistParsedOk(){
+ registry = new HostRequestIntervalRegistry(10000L, 100L,"", "b1");
+ assertEquals(1L, registry.tick("aaa"));
+ }
+
+ @Test
+ public void emptyBlacklistParsedOk(){
+ registry = new HostRequestIntervalRegistry(10000L, 100L,"", "");
+ assertEquals(1L, registry.tick("aaa"));
+ }
}
\ No newline at end of file
diff --git a/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
index 2ffbf05..958c4a7 100644
--- a/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
+++ b/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
@@ -75,7 +75,6 @@ public class CoapTransportResource extends CoapResource {
@Override
public void handleGET(CoapExchange exchange) {
if(quotaService.isQuotaExceeded(exchange.getSourceAddress().getHostAddress())) {
- log.warn("Missing feature type parameter");
log.warn("COAP Quota exceeded for [{}:{}] . Disconnect", exchange.getSourceAddress().getHostAddress(), exchange.getSourcePort());
exchange.respond(ResponseCode.BAD_REQUEST);
return;