Browse Source

Merge with master

pull/5623/head
Andrii Shvaika 5 years ago
parent
commit
c51ade482a
  1. 3
      application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java
  2. 5
      application/src/main/java/org/thingsboard/server/actors/stats/StatsPersistMsg.java
  3. 2
      application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java
  4. 3
      application/src/main/java/org/thingsboard/server/controller/CustomerController.java
  5. 3
      application/src/main/java/org/thingsboard/server/controller/DashboardController.java
  6. 7
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java
  7. 34
      application/src/main/resources/thingsboard.yml
  8. 69
      application/src/test/java/org/thingsboard/server/actors/stats/StatsActorTest.java
  9. 38
      application/src/test/java/org/thingsboard/server/actors/stats/StatsPersistMsgTest.java
  10. 2
      common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java
  11. 2
      common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java
  12. 1
      common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java
  13. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  14. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  15. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  16. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java
  17. 156
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  18. 18
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java
  19. 2
      common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java
  20. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java
  21. 2
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  22. 8
      k8s/.env
  23. 130
      k8s/README.md
  24. 26
      k8s/basic/tb-node-cache-configmap.yml
  25. 181
      k8s/basic/thirdparty.yml
  26. 164
      k8s/common/cassandra.yml
  27. 43
      k8s/common/database-setup.yml
  28. 102
      k8s/common/postgres.yml
  29. 65
      k8s/common/tb-coap-transport-configmap.yml
  30. 65
      k8s/common/tb-http-transport-configmap.yml
  31. 65
      k8s/common/tb-mqtt-transport-configmap.yml
  32. 22
      k8s/common/tb-namespace.yml
  33. 67
      k8s/common/tb-node-configmap.yml
  34. 32
      k8s/common/tb-node-hybrid-configmap.yml
  35. 30
      k8s/common/tb-node-postgres-configmap.yml
  36. 98
      k8s/common/tb-node.yml
  37. 451
      k8s/common/thingsboard.yml
  38. 27
      k8s/high-availability/tb-node-cache-configmap.yml
  39. 301
      k8s/high-availability/thirdparty.yml
  40. 20
      k8s/k8s-delete-all.sh
  41. 25
      k8s/k8s-delete-resources.sh
  42. 23
      k8s/k8s-delete-thirdparty.sh
  43. 30
      k8s/k8s-deploy-resources.sh
  44. 45
      k8s/k8s-deploy-thirdparty.sh
  45. 106
      k8s/k8s-install-tb.sh
  46. 43
      k8s/k8s-upgrade-tb.sh
  47. 1
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java
  48. 2
      rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js
  49. 2
      transport/coap/src/main/resources/tb-coap-transport.yml
  50. 2
      transport/http/src/main/resources/tb-http-transport.yml
  51. 4
      transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml
  52. 6
      transport/mqtt/src/main/resources/tb-mqtt-transport.yml
  53. 3
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html
  54. 2
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts
  55. 17
      ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html
  56. 1
      ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.scss
  57. 44
      ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts
  58. 14
      ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw
  59. 3
      ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html
  60. 2
      ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts
  61. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

3
application/src/main/java/org/thingsboard/server/actors/stats/StatsActor.java

@ -51,6 +51,9 @@ public class StatsActor extends ContextAwareActor {
}
public void onStatsPersistMsg(StatsPersistMsg msg) {
if (msg.isEmpty()) {
return;
}
Event event = new Event();
event.setEntityId(msg.getEntityId());
event.setTenantId(msg.getTenantId());

5
application/src/main/java/org/thingsboard/server/actors/stats/StatsPersistMsg.java

@ -37,4 +37,9 @@ public final class StatsPersistMsg implements TbActorMsg {
public MsgType getMsgType() {
return MsgType.STATS_PERSIST_MSG;
}
public boolean isEmpty() {
return messagesProcessed == 0 && errorsOccurred == 0;
}
}

2
application/src/main/java/org/thingsboard/server/controller/ControllerConstants.java

@ -18,7 +18,7 @@ package org.thingsboard.server.controller;
public class ControllerConstants {
protected static final String NEW_LINE = "\n\n";
protected static final String UUID_WIKI_LINK = "[time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address%29) ";
protected static final String UUID_WIKI_LINK = "[time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)). ";
protected static final int DEFAULT_PAGE_SIZE = 1000;
protected static final String ENTITY_TYPE = "entityType";
protected static final String CUSTOMER_ID = "customerId";

3
application/src/main/java/org/thingsboard/server/controller/CustomerController.java

@ -60,6 +60,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_D
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@RestController
@TbCoreComponent
@ -136,7 +137,7 @@ public class CustomerController extends BaseController {
}
@ApiOperation(value = "Create or update Customer (saveCustomer)",
notes = "Creates or Updates the Customer. When creating customer, platform generates Customer Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) " +
notes = "Creates or Updates the Customer. When creating customer, platform generates Customer Id as " + UUID_WIKI_LINK +
"The newly created Customer Id will be present in the response. " +
"Specify existing Customer Id to update the Customer. " +
"Referencing non-existing Customer Id will cause 'Not Found' error." + TENANT_AUTHORITY_PARAGRAPH)

3
application/src/main/java/org/thingsboard/server/controller/DashboardController.java

@ -86,6 +86,7 @@ import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHO
import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@RestController
@TbCoreComponent
@ -166,7 +167,7 @@ public class DashboardController extends BaseController {
}
@ApiOperation(value = "Create Or Update Dashboard (saveDashboard)",
notes = "Create or update the Dashboard. When creating dashboard, platform generates Dashboard Id as [time-based UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address)." +
notes = "Create or update the Dashboard. When creating dashboard, platform generates Dashboard Id as " + UUID_WIKI_LINK +
"The newly created Dashboard id will be present in the response. " +
"Specify existing Dashboard id to update the dashboard. " +
"Referencing non-existing dashboard Id will cause 'Not Found' error. " +

7
application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.service.install.update;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
@ -24,13 +25,13 @@ import org.springframework.stereotype.Service;
import java.util.Objects;
@RequiredArgsConstructor
@Service
@Profile("install")
@Slf4j
public class DefaultCacheCleanupService implements CacheCleanupService {
@Autowired
CacheManager cacheManager;
private final CacheManager cacheManager;
/**
* Cleanup caches that can not deserialize anymore due to schema upgrade or data update using sql scripts.
@ -61,7 +62,7 @@ public class DefaultCacheCleanupService implements CacheCleanupService {
clearAllCaches();
break;
default:
throw new RuntimeException("Unable to update cache, unsupported fromVersion: " + fromVersion);
//Do nothing, since cache cleanup is optional.
}
}

34
application/src/main/resources/thingsboard.yml

@ -31,7 +31,7 @@ server:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${SSL_PEM_CERT:server.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${SSL_PEM_KEY:server_key.pem}"
# Server certificate private key password (optional)
key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}"
@ -54,7 +54,7 @@ server:
log_controller_error_stack_trace: "${HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE:false}"
ws:
send_timeout: "${TB_SERVER_WS_SEND_TIMEOUT:5000}"
ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:30000}"
ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:15000}"
limits:
# Limit the amount of sessions and subscriptions available on each server. Put values to zero to disable particular limitation
max_sessions_per_tenant: "${TB_SERVER_WS_TENANT_RATE_LIMITS_MAX_SESSIONS_PER_TENANT:0}"
@ -211,7 +211,7 @@ cassandra:
init_retry_interval_ms: "${CASSANDRA_CLUSTER_INIT_RETRY_INTERVAL_MS:3000}"
max_requests_per_connection_local: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_LOCAL:32768}"
max_requests_per_connection_remote: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_REMOTE:32768}"
# Credential parameters #
# Credential parameters
credentials: "${CASSANDRA_USE_CREDENTIALS:false}"
# Specify your username
username: "${CASSANDRA_USERNAME:}"
@ -595,7 +595,7 @@ js:
remote:
# Maximum allowed JavaScript execution errors before JavaScript will be blacklisted
max_errors: "${REMOTE_JS_SANDBOX_MAX_ERRORS:3}"
# Maximum time in seconds for black listed function to stay in 1:the list.
# Maximum time in seconds for black listed function to stay in the list.
max_black_list_duration_sec: "${REMOTE_JS_SANDBOX_MAX_BLACKLIST_DURATION_SEC:60}"
stats:
enabled: "${TB_JS_REMOTE_STATS_ENABLED:false}"
@ -644,7 +644,7 @@ transport:
bind_address: "${MQTT_SSL_BIND_ADDRESS:0.0.0.0}"
# MQTT SSL bind port
bind_port: "${MQTT_SSL_BIND_PORT:8883}"
# SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext
# SSL protocol: See https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms
protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}"
# Server SSL credentials
credentials:
@ -654,7 +654,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}"
@ -666,7 +666,9 @@ transport:
store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
# Password used to access the key store
store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
# Password used to access the key
# Optional alias of the private key; If not set, the platform will load the first private key from the keystore;
key_alias: "${MQTT_SSL_KEY_ALIAS:}"
# Optional password to access the private key. If not set, the platform will attempt to load the private keys that are not protected with the password;
key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
# Skip certificate validity check for client certificates.
skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}"
@ -694,7 +696,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}"
@ -736,7 +738,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}"
@ -772,7 +774,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}"
@ -1030,8 +1032,8 @@ queue:
# For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited
failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries;
max-pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:3}"# Max allowed time in seconds for pause between retries.
pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}" # Time in seconds to wait in consumer thread before retries;
max-pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:3}" # Max allowed time in seconds for pause between retries.
- name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}"
topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}"
poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}"
@ -1047,8 +1049,8 @@ queue:
# For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited
failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries;
max-pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}"# Max allowed time in seconds for pause between retries.
pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}" # Time in seconds to wait in consumer thread before retries;
max-pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries.
- name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}"
topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}"
poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}"
@ -1064,8 +1066,8 @@ queue:
# For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited
failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries;
max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}"# Max allowed time in seconds for pause between retries.
pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}" # Time in seconds to wait in consumer thread before retries;
max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries.
transport:
# For high priority notifications that require minimum latency and processing time
notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}"

69
application/src/test/java/org/thingsboard/server/actors/stats/StatsActorTest.java

@ -0,0 +1,69 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* 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
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.actors.stats;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.common.data.Event;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.event.EventService;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
class StatsActorTest {
StatsActor statsActor;
ActorSystemContext actorSystemContext;
EventService eventService;
TbServiceInfoProvider serviceInfoProvider;
@BeforeEach
void setUp() {
actorSystemContext = mock(ActorSystemContext.class);
eventService = mock(EventService.class);
willReturn(eventService).given(actorSystemContext).getEventService();
serviceInfoProvider = mock(TbServiceInfoProvider.class);
willReturn(serviceInfoProvider).given(actorSystemContext).getServiceInfoProvider();
statsActor = new StatsActor(actorSystemContext);
}
@Test
void givenEmptyStatMessage_whenOnStatsPersistMsg_thenNoAction() {
StatsPersistMsg emptyStats = new StatsPersistMsg(0, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID);
statsActor.onStatsPersistMsg(emptyStats);
verify(actorSystemContext, never()).getEventService();
}
@Test
void givenNonEmptyStatMessage_whenOnStatsPersistMsg_thenNoAction() {
statsActor.onStatsPersistMsg(new StatsPersistMsg(0, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID));
verify(eventService, times(1)).save(any(Event.class));
statsActor.onStatsPersistMsg(new StatsPersistMsg(1, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID));
verify(eventService, times(2)).save(any(Event.class));
statsActor.onStatsPersistMsg(new StatsPersistMsg(1, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID));
verify(eventService, times(3)).save(any(Event.class));
}
}

38
application/src/test/java/org/thingsboard/server/actors/stats/StatsPersistMsgTest.java

@ -0,0 +1,38 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* 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
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.actors.stats;
import org.junit.jupiter.api.Test;
import org.thingsboard.server.common.data.id.TenantId;
import static org.assertj.core.api.Assertions.assertThat;
class StatsPersistMsgTest {
@Test
void testIsEmpty() {
StatsPersistMsg emptyStats = new StatsPersistMsg(0, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID);
assertThat(emptyStats.isEmpty()).isTrue();
}
@Test
void testNotEmpty() {
assertThat(new StatsPersistMsg(1, 0, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isEmpty()).isFalse();
assertThat(new StatsPersistMsg(0, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isEmpty()).isFalse();
assertThat(new StatsPersistMsg(1, 1, TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID).isEmpty()).isFalse();
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/device/profile/DeviceProfileAlarm.java

@ -19,6 +19,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
import javax.validation.Valid;
@ -32,6 +33,7 @@ public class DeviceProfileAlarm implements Serializable {
@ApiModelProperty(position = 1, value = "String value representing the alarm rule id", example = "highTemperatureAlarmID")
private String id;
@Length(fieldName = "alarm type")
@NoXss
@ApiModelProperty(position = 2, value = "String value representing type of the alarm", example = "High Temperature Alarm")
private String alarmType;

2
common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChainMetaData.java

@ -21,6 +21,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.thingsboard.server.common.data.id.RuleChainId;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
@ -37,6 +38,7 @@ public class RuleChainMetaData {
@ApiModelProperty(position = 2, required = true, value = "Index of the first rule node in the 'nodes' list")
private Integer firstNodeIndex;
@Valid
@ApiModelProperty(position = 3, required = true, value = "List of rule node JSON objects")
private List<RuleNode> nodes;

1
common/message/src/main/java/org/thingsboard/server/common/msg/tools/TbRateLimitsException.java

@ -26,6 +26,7 @@ public class TbRateLimitsException extends RuntimeException {
private final EntityType entityType;
public TbRateLimitsException(EntityType entityType) {
super(entityType.name() + " rate limits reached!");
this.entityType = entityType;
}
}

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java

@ -125,6 +125,10 @@ public class LwM2mClient implements Serializable {
@Getter
private final AtomicInteger retryAttempts;
@Getter
@Setter
private UUID lastSentRpcId;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -274,8 +274,8 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2mClient = null;
UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
Predicate<LwM2mClient> isClientFilter = c ->
sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB())));
Predicate<LwM2mClient> isClientFilter =
c -> c.getSession() != null && sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB())));
if (this.lwM2mClientsByEndpoint.size() > 0) {
lwM2mClient = this.lwM2mClientsByEndpoint.values().stream().filter(isClientFilter).findAny().orElse(null);
}

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java

@ -473,6 +473,10 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
Registration registration = client.getRegistration();
try {
logService.log(client, String.format("[%s][%s] Sending request: %s to %s", registration.getId(), registration.getSocketAddress(), request.getClass().getSimpleName(), pathToStringFunction.apply(request)));
if (!callback.onSent(request)) {
return;
}
context.getServer().send(registration, request, timeoutInMs, response -> {
executor.submit(() -> {
try {
@ -484,7 +488,6 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
}
});
}, e -> handleDownlinkError(client, request, callback, e));
callback.onSent(request);
} catch (Exception e) {
handleDownlinkError(client, request, callback, e);
}
@ -520,6 +523,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
private <R extends DownlinkRequest<T>, T extends LwM2mResponse> void handleDownlinkError(LwM2mClient client, R request, DownlinkRequestCallback<R, T> callback, Exception e) {
log.trace("[{}] Received downlink error: {}.", client.getEndpoint(), e);
client.updateLastUplinkTime();
executor.submit(() -> {
if (e instanceof TimeoutException || e instanceof ClientSleepingException) {
log.trace("[{}] Received {}, client is probably sleeping", client.getEndpoint(), e.getClass().getSimpleName());

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DownlinkRequestCallback.java

@ -17,7 +17,9 @@ package org.thingsboard.server.transport.lwm2m.server.downlink;
public interface DownlinkRequestCallback<R, T> {
default void onSent(R request){};
default boolean onSent(R request){
return true;
};
void onSuccess(R request, T response);

156
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

@ -19,6 +19,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonSyntaxException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mPath;
@ -94,88 +95,99 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
@Override
public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequest, TransportProtos.SessionInfoProto sessionInfo) {
log.debug("Received params: {}", rpcRequest.getParams());
LwM2MOperationType operationType = LwM2MOperationType.fromType(rpcRequest.getMethodName());
if (operationType == null) {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName());
return;
}
LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);
if (client.getRegistration() == null) {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty");
return;
}
try {
if (operationType.isHasObjectId()) {
LwM2MRpcRequestHeader header = JacksonUtil.fromString(rpcRequest.getParams(), LwM2MRpcRequestHeader.class);
String objectId = getIdFromParameters(client, header);
switch (operationType) {
case READ:
sendReadRequest(client, rpcRequest, objectId);
break;
case OBSERVE:
sendObserveRequest(client, rpcRequest, objectId);
break;
case DISCOVER:
sendDiscoverRequest(client, rpcRequest, objectId);
break;
case EXECUTE:
sendExecuteRequest(client, rpcRequest, objectId);
break;
case WRITE_ATTRIBUTES:
sendWriteAttributesRequest(client, rpcRequest, objectId);
break;
case OBSERVE_CANCEL:
sendCancelObserveRequest(client, rpcRequest, objectId);
break;
case DELETE:
sendDeleteRequest(client, rpcRequest, objectId);
break;
case WRITE_UPDATE:
sendWriteUpdateRequest(client, rpcRequest, objectId);
break;
case WRITE_REPLACE:
sendWriteReplaceRequest(client, rpcRequest, objectId);
break;
case CREATE:
sendCreateRequest(client, rpcRequest, objectId);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
} else if (operationType.isComposite()) {
ContentFormat contentFormatComposite = this.getCompositeContentFormat(client);
if (contentFormatComposite != null) {
LwM2MOperationType operationType = LwM2MOperationType.fromType(rpcRequest.getMethodName());
if (operationType == null) {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED, "Unsupported operation type: " + rpcRequest.getMethodName());
return;
}
LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);
if (client.getRegistration() == null) {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, "Registration is empty");
return;
}
UUID rpcId = new UUID(rpcRequest.getRequestIdMSB(), rpcRequest.getRequestIdLSB());
if (rpcId.equals(client.getLastSentRpcId())) {
log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId);
return;
}
try {
if (operationType.isHasObjectId()) {
LwM2MRpcRequestHeader header = JacksonUtil.fromString(rpcRequest.getParams(), LwM2MRpcRequestHeader.class);
String objectId = getIdFromParameters(client, header);
switch (operationType) {
case READ_COMPOSITE:
sendReadCompositeRequest(client, rpcRequest, contentFormatComposite);
case READ:
sendReadRequest(client, rpcRequest, objectId);
break;
case OBSERVE:
sendObserveRequest(client, rpcRequest, objectId);
break;
case DISCOVER:
sendDiscoverRequest(client, rpcRequest, objectId);
break;
case EXECUTE:
sendExecuteRequest(client, rpcRequest, objectId);
break;
case WRITE_ATTRIBUTES:
sendWriteAttributesRequest(client, rpcRequest, objectId);
break;
case OBSERVE_CANCEL:
sendCancelObserveRequest(client, rpcRequest, objectId);
break;
case WRITE_COMPOSITE:
sendWriteCompositeRequest(client, rpcRequest, contentFormatComposite);
case DELETE:
sendDeleteRequest(client, rpcRequest, objectId);
break;
case WRITE_UPDATE:
sendWriteUpdateRequest(client, rpcRequest, objectId);
break;
case WRITE_REPLACE:
sendWriteReplaceRequest(client, rpcRequest, objectId);
break;
case CREATE:
sendCreateRequest(client, rpcRequest, objectId);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
} else if (operationType.isComposite()) {
ContentFormat contentFormatComposite = this.getCompositeContentFormat(client);
if (contentFormatComposite != null) {
switch (operationType) {
case READ_COMPOSITE:
sendReadCompositeRequest(client, rpcRequest, contentFormatComposite);
break;
case WRITE_COMPOSITE:
sendWriteCompositeRequest(client, rpcRequest, contentFormatComposite);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
} else {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(),
ResponseCode.INTERNAL_SERVER_ERROR, "This device does not support Composite Operation");
}
} else {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(),
ResponseCode.INTERNAL_SERVER_ERROR, "This device does not support Composite Operation");
}
} else {
switch (operationType) {
case OBSERVE_CANCEL_ALL:
sendCancelAllObserveRequest(client, rpcRequest);
break;
case OBSERVE_READ_ALL:
sendObserveAllRequest(client, rpcRequest);
break;
case DISCOVER_ALL:
sendDiscoverAllRequest(client, rpcRequest);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
switch (operationType) {
case OBSERVE_CANCEL_ALL:
sendCancelAllObserveRequest(client, rpcRequest);
break;
case OBSERVE_READ_ALL:
sendObserveAllRequest(client, rpcRequest);
break;
case DISCOVER_ALL:
sendDiscoverAllRequest(client, rpcRequest);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
}
} catch (IllegalArgumentException e) {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage());
}
} catch (IllegalArgumentException e) {
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage());
} catch (Exception e) {
log.error("[{}] Failed to send RPC: [{}]", sessionInfo, rpcRequest, e);
this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR, ExceptionUtils.getRootCauseMessage(e));
}
}

18
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.request.exception.ClientSleepingException;
import org.thingsboard.common.util.JacksonUtil;
@ -26,8 +27,10 @@ import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
@Slf4j
public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkRequestCallback<R, T> {
private final TransportService transportService;
@ -44,8 +47,20 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR
}
@Override
public void onSent(R request) {
public boolean onSent(R request) {
client.lock();
try {
UUID rpcId = new UUID(this.request.getRequestIdMSB(), this.request.getRequestIdLSB());
if (rpcId.equals(client.getLastSentRpcId())) {
log.debug("[{}]][{}] Rpc has already sent!", client.getEndpoint(), rpcId);
return false;
}
client.setLastSentRpcId(rpcId);
} finally {
client.unlock();
}
transportService.process(client.getSession(), this.request, RpcStatus.SENT, TransportServiceCallback.EMPTY);
return true;
}
@Override
@ -68,6 +83,7 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR
@Override
public void onError(String params, Exception e) {
if (e instanceof TimeoutException || e instanceof org.eclipse.leshan.core.request.exception.TimeoutException) {
client.setLastSentRpcId(null);
transportService.process(client.getSession(), this.request, RpcStatus.TIMEOUT, TransportServiceCallback.EMPTY);
} else if (!(e instanceof ClientSleepingException)) {
sendRpcReplyOnError(e);

2
common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java

@ -951,7 +951,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
@Override
public void onError(Throwable e) {
if (e instanceof TbRateLimitsException) {
log.trace("[{}] Failed to submit session event", sessionId, e);
log.trace("[{}] Failed to submit session event: {}", sessionId, e.getMessage());
} else {
log.warn("[{}] Failed to submit session event", sessionId, e);
}

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/limits/DefaultTransportRateLimitService.java

@ -57,7 +57,7 @@ public class DefaultTransportRateLimitService implements TransportRateLimitServi
@Override
public EntityType checkLimits(TenantId tenantId, DeviceId deviceId, int dataPoints) {
if (!tenantAllowed.getOrDefault(tenantId, Boolean.TRUE)) {
return EntityType.TENANT;
return EntityType.API_USAGE_STATE;
}
if (!checkEntityRateLimit(dataPoints, getTenantRateLimits(tenantId))) {
return EntityType.TENANT;

2
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -52,6 +52,7 @@ import org.thingsboard.server.common.data.rule.RuleNode;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.ConstraintValidator;
import org.thingsboard.server.dao.service.DataValidator;
import org.thingsboard.server.dao.service.PaginatedRemover;
import org.thingsboard.server.dao.service.Validator;
@ -135,6 +136,7 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
if (ruleChain == null) {
return false;
}
ConstraintValidator.validateFields(ruleChainMetaData);
if (CollectionUtils.isNotEmpty(ruleChainMetaData.getConnections())) {
validateCircles(ruleChainMetaData.getConnections());

8
k8s/.env

@ -1,8 +0,0 @@
# Can be either basic (with single instance of Zookeeper, Kafka and Redis) or high-availability (with Zookeeper, Kafka and Redis in cluster modes).
# According to the deployment type corresponding kubernetes resources will be deployed (see content of the directories ./basic and ./high-availability for details).
DEPLOYMENT_TYPE=basic
# Database used by ThingsBoard, can be either postgres (PostgreSQL) or hybrid (PostgreSQL for entities database and Cassandra for timeseries database).
# According to the database type corresponding kubernetes resources will be deployed (see postgres.yml, cassandra.yml for details).
DATABASE=postgres

130
k8s/README.md

@ -1,130 +0,0 @@
# Kubernetes resources configuration for ThingsBoard Microservices
This folder containing scripts and Kubernetes resources configurations to run ThingsBoard in Microservices mode.
## Prerequisites
ThingsBoard Microservices run on the Kubernetes cluster.
You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.
If you do not have a cluster already, you can create one by using [Minikube](https://kubernetes.io/docs/setup/minikube),
or you can choose any other available [Kubernetes cluster deployment solutions](https://kubernetes.io/docs/setup/pick-right-solution/).
### Enable ingress addon
By default ingress addon is disabled in the Minikube, and available only in cluster providers.
To enable ingress, please execute the following command:
`
$ minikube addons enable ingress
`
## Installation
Before performing initial installation you can configure the type of database to be used with ThingsBoard and the type of deployment.
To set database type change the value of `DATABASE` variable in `.env` file to one of the following:
- `postgres` - use PostgreSQL database;
- `hybrid` - use PostgreSQL for entities database and Cassandra for timeseries database;
**NOTE**: According to the database type corresponding kubernetes resources will be deployed (see `postgres.yml`, `cassandra.yml` for details).
To set deployment type change the value of `DEPLOYMENT_TYPE` variable in `.env` file to one of the following:
- `basic` - startup with a single instance of Zookeeper, Kafka and Redis;
- `high-availability` - startup with Zookeeper, Kafka, and Redis in cluster modes;
**NOTE**: According to the deployment type corresponding kubernetes resources will be deployed (see the content of the directories `./basic` and `./high-availability` for details).
Execute the following command to run the installation:
`
$ ./k8s-install-tb.sh --loadDemo
`
Where:
- `--loadDemo` - optional argument. Whether to load additional demo data.
## Running
Execute the following command to deploy third-party resources:
`
$ ./k8s-deploy-thirdparty.sh
`
Type **'yes'** when prompted, if you are running ThingsBoard in `high-availability` `DEPLOYMENT_TYPE` for the first time and don't have configured Redis cluster.
Execute the following command to deploy resources:
`
$ ./k8s-deploy-resources.sh
`
After a while when all resources will be successfully started you can open `http://{your-cluster-ip}` in your browser (for ex. `http://192.168.99.101`).
You should see the ThingsBoard login page.
Use the following default credentials:
- **System Administrator**: sysadmin@thingsboard.org / sysadmin
If you installed DataBase with demo data (using `--loadDemo` flag) you can also use the following credentials:
- **Tenant Administrator**: tenant@thingsboard.org / tenant
- **Customer User**: customer@thingsboard.org / customer
In case of any issues, you can examine service logs for errors.
For example to see ThingsBoard node logs execute the following commands:
1) Get the list of the running tb-node pods:
`
$ kubectl get pods -l app=tb-node
`
2) Fetch logs of the tb-node pod:
`
$ kubectl logs -f [tb-node-pod-name]
`
Where:
- `tb-node-pod-name` - tb-node pod name obtained from the list of the running tb-node pods.
Or use `kubectl get pods` to see the state of all the pods.
Or use `kubectl get services` to see the state of all the services.
Or use `kubectl get deployments` to see the state of all the deployments.
See [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) command reference for details.
Execute the following command to delete all ThingsBoard microservices:
`
$ ./k8s-delete-resources.sh
`
Execute the following command to delete all third-party microservices:
`
$ ./k8s-delete-thirdparty.sh
`
Execute the following command to delete all resources (including database):
`
$ ./k8s-delete-all.sh
`
## Upgrading
In case when database upgrade is needed, execute the following commands:
```
$ ./k8s-delete-resources.sh
$ ./k8s-upgrade-tb.sh --fromVersion=[FROM_VERSION]
$ ./k8s-deploy-resources.sh
```
Where:
- `FROM_VERSION` - from which version upgrade should be started. See [Upgrade Instructions](https://thingsboard.io/docs/user-guide/install/upgrade-instructions) for valid `fromVersion` values.

26
k8s/basic/tb-node-cache-configmap.yml

@ -1,26 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-node-cache-config
namespace: thingsboard
labels:
name: tb-node-cache-config
data:
CACHE_TYPE: redis
REDIS_HOST: tb-redis

181
k8s/basic/thirdparty.yml

@ -1,181 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: zookeeper
namespace: thingsboard
spec:
selector:
matchLabels:
app: zookeeper
template:
metadata:
labels:
app: zookeeper
spec:
containers:
- name: server
imagePullPolicy: Always
image: zookeeper:3.5
ports:
- containerPort: 2181
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 2181
livenessProbe:
initialDelaySeconds: 15
periodSeconds: 5
tcpSocket:
port: 2181
env:
- name: ZOO_MY_ID
value: "1"
- name: ZOO_SERVERS
value: "server.1=0.0.0.0:2888:3888;0.0.0.0:2181"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper
namespace: thingsboard
spec:
type: ClusterIP
selector:
app: zookeeper
ports:
- name: zk-port
port: 2181
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-kafka
namespace: thingsboard
spec:
selector:
matchLabels:
app: tb-kafka
template:
metadata:
labels:
app: tb-kafka
spec:
containers:
- name: server
imagePullPolicy: Always
image: wurstmeister/kafka:2.12-2.2.1
ports:
- containerPort: 9092
readinessProbe:
periodSeconds: 20
tcpSocket:
port: 9092
livenessProbe:
initialDelaySeconds: 25
periodSeconds: 5
tcpSocket:
port: 9092
env:
- name: KAFKA_ZOOKEEPER_CONNECT
value: "zookeeper:2181"
- name: KAFKA_LISTENERS
value: "INSIDE://:9093,OUTSIDE://:9092"
- name: KAFKA_ADVERTISED_LISTENERS
value: "INSIDE://:9093,OUTSIDE://tb-kafka:9092"
- name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
value: "INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT"
- name: KAFKA_INTER_BROKER_LISTENER_NAME
value: "INSIDE"
- name: KAFKA_CREATE_TOPICS
value: "js_eval.requests:100:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_transport.api.requests:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_rule_engine:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600"
- name: KAFKA_AUTO_CREATE_TOPICS_ENABLE
value: "false"
- name: KAFKA_LOG_RETENTION_BYTES
value: "1073741824"
- name: KAFKA_LOG_SEGMENT_BYTES
value: "268435456"
- name: KAFKA_LOG_RETENTION_MS
value: "300000"
- name: KAFKA_LOG_CLEANUP_POLICY
value: "delete"
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-kafka
namespace: thingsboard
spec:
type: ClusterIP
selector:
app: tb-kafka
ports:
- name: tb-kafka-port
port: 9092
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-redis
namespace: thingsboard
spec:
selector:
matchLabels:
app: tb-redis
template:
metadata:
labels:
app: tb-redis
spec:
containers:
- name: server
imagePullPolicy: Always
image: redis:4.0
ports:
- containerPort: 6379
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
volumeMounts:
- mountPath: /data
name: redis-data
volumes:
- name: redis-data
emptyDir: {}
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-redis
namespace: thingsboard
spec:
type: ClusterIP
selector:
app: tb-redis
ports:
- name: tb-redis-port
port: 6379
---

164
k8s/common/cassandra.yml

@ -1,164 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
namespace: thingsboard
provisioner: k8s.io/minikube-hostpath
parameters:
type: pd-ssd
---
apiVersion: v1
kind: ConfigMap
metadata:
name: cassandra-probe-config
namespace: thingsboard
labels:
name: cassandra-probe-config
data:
probe: |
if [[ $(nodetool status | grep $POD_IP) == *"UN"* ]]; then
if [[ $DEBUG ]]; then
echo "UN";
fi
exit 0;
else
if [[ $DEBUG ]]; then
echo "Not Up";
fi
exit 1;
fi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: cassandra
namespace: thingsboard
labels:
app: cassandra
spec:
serviceName: cassandra
replicas: 1
selector:
matchLabels:
app: cassandra
template:
metadata:
labels:
app: cassandra
spec:
volumes:
- name: cassandra-probe-config
configMap:
name: cassandra-probe-config
items:
- key: probe
path: ready-probe.sh
mode: 0777
terminationGracePeriodSeconds: 1800
containers:
- name: cassandra
image: cassandra:3.11.3
imagePullPolicy: Always
ports:
- containerPort: 7000
name: intra-node
- containerPort: 7001
name: tls-intra-node
- containerPort: 7199
name: jmx
- containerPort: 9042
name: cql
- containerPort: 9160
name: thrift
resources:
limits:
cpu: "1000m"
memory: 2Gi
requests:
cpu: "1000m"
memory: 2Gi
securityContext:
capabilities:
add:
- IPC_LOCK
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- nodetool drain
env:
- name: CASSANDRA_SEEDS
value: "cassandra-0.cassandra.thingsboard.svc.cluster.local"
- name: MAX_HEAP_SIZE
value: 1024M
- name: HEAP_NEWSIZE
value: 256M
- name: CASSANDRA_CLUSTER_NAME
value: "Thingsboard Cluster"
- name: CASSANDRA_DC
value: "datacenter1"
- name: CASSANDRA_RACK
value: "Rack-Thingsboard-Cluster"
- name: CASSANDRA_AUTO_BOOTSTRAP
value: "false"
- name: CASSANDRA_ENDPOINT_SNITCH
value: GossipingPropertyFileSnitch
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
readinessProbe:
exec:
command:
- /bin/bash
- -c
- /probe/ready-probe.sh
initialDelaySeconds: 60
timeoutSeconds: 5
volumeMounts:
- name: cassandra-probe-config
mountPath: /probe
- name: cassandra-data
mountPath: /var/lib/cassandra
volumeClaimTemplates:
- metadata:
name: cassandra-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: fast
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
labels:
app: cassandra
name: cassandra
namespace: thingsboard
spec:
clusterIP: None
ports:
- port: 9042
selector:
app: cassandra
---

43
k8s/common/database-setup.yml

@ -1,43 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: Pod
metadata:
name: tb-db-setup
namespace: thingsboard
spec:
volumes:
- name: tb-node-config
configMap:
name: tb-node-config
items:
- key: conf
path: thingsboard.conf
- key: logback
path: logback.xml
containers:
- name: tb-db-setup
imagePullPolicy: Always
image: thingsboard/tb-node:latest
envFrom:
- configMapRef:
name: tb-node-db-config
volumeMounts:
- mountPath: /config
name: tb-node-config
command: ['sh', '-c', 'while [ ! -f /tmp/install-finished ]; do sleep 2; done;']
restartPolicy: Never

102
k8s/common/postgres.yml

@ -1,102 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pv-claim
namespace: thingsboard
labels:
app: postgres
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
namespace: thingsboard
labels:
app: postgres
spec:
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pv-claim
containers:
- name: postgres
imagePullPolicy: Always
image: postgres:12
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_DB
value: "thingsboard"
- name: POSTGRES_PASSWORD
value: "postgres"
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres-data
livenessProbe:
exec:
command:
- pg_isready
- -h
- localhost
- -U
- postgres
initialDelaySeconds: 60
timeoutSeconds: 30
readinessProbe:
exec:
command:
- pg_isready
- -h
- localhost
- -U
- postgres
initialDelaySeconds: 5
timeoutSeconds: 1
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-database
namespace: thingsboard
spec:
type: ClusterIP
selector:
app: postgres
ports:
- port: 5432
name: postgres
---

65
k8s/common/tb-coap-transport-configmap.yml

@ -1,65 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-coap-transport-config
namespace: thingsboard
labels:
name: tb-coap-transport-config
data:
conf: |
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-coap-transport/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-coap-transport/${TB_SERVICE_ID}-heapdump.bin"
export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError"
export LOG_FILENAME=tb-coap-transport.out
export LOADER_PATH=/usr/share/tb-coap-transport/conf
logback: |
<!DOCTYPE configuration>
<configuration scan="true" scanPeriod="10 seconds">
<appender name="fileLogAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/tb-coap-transport/${TB_SERVICE_ID}/tb-coap-transport.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/tb-coap-transport/${TB_SERVICE_ID}/tb-coap-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.thingsboard.server" level="INFO" />
<root level="INFO">
<appender-ref ref="fileLogAppender"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>

65
k8s/common/tb-http-transport-configmap.yml

@ -1,65 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-http-transport-config
namespace: thingsboard
labels:
name: tb-http-transport-config
data:
conf: |
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-http-transport/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-http-transport/${TB_SERVICE_ID}-heapdump.bin"
export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError"
export LOG_FILENAME=tb-http-transport.out
export LOADER_PATH=/usr/share/tb-http-transport/conf
logback: |
<!DOCTYPE configuration>
<configuration scan="true" scanPeriod="10 seconds">
<appender name="fileLogAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/tb-http-transport/${TB_SERVICE_ID}/tb-http-transport.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/tb-http-transport/${TB_SERVICE_ID}/tb-http-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.thingsboard.server" level="INFO" />
<root level="INFO">
<appender-ref ref="fileLogAppender"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>

65
k8s/common/tb-mqtt-transport-configmap.yml

@ -1,65 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-mqtt-transport-config
namespace: thingsboard
labels:
name: tb-mqtt-transport-config
data:
conf: |
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-mqtt-transport/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-mqtt-transport/${TB_SERVICE_ID}-heapdump.bin"
export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError"
export LOG_FILENAME=tb-mqtt-transport.out
export LOADER_PATH=/usr/share/tb-mqtt-transport/conf
logback: |
<!DOCTYPE configuration>
<configuration scan="true" scanPeriod="10 seconds">
<appender name="fileLogAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/tb-mqtt-transport/${TB_SERVICE_ID}/tb-mqtt-transport.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/tb-mqtt-transport/${TB_SERVICE_ID}/tb-mqtt-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.thingsboard.server" level="INFO" />
<root level="INFO">
<appender-ref ref="fileLogAppender"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>

22
k8s/common/tb-namespace.yml

@ -1,22 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: Namespace
metadata:
name: thingsboard
labels:
name: thingsboard

67
k8s/common/tb-node-configmap.yml

@ -1,67 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-node-config
namespace: thingsboard
labels:
name: tb-node-config
data:
conf: |
export JAVA_OPTS="$JAVA_OPTS -Dplatform=deb -Dinstall.data_dir=/usr/share/thingsboard/data"
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/thingsboard/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/thingsboard/${TB_SERVICE_ID}-heapdump.bin"
export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError"
export LOG_FILENAME=thingsboard.out
export LOADER_PATH=/usr/share/thingsboard/conf,/usr/share/thingsboard/extensions
logback: |
<!DOCTYPE configuration>
<configuration scan="true" scanPeriod="10 seconds">
<appender name="fileLogAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/thingsboard/${TB_SERVICE_ID}/thingsboard.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/thingsboard/${TB_SERVICE_ID}/thingsboard.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.thingsboard.server" level="INFO" />
<logger name="com.google.common.util.concurrent.AggregateFuture" level="OFF" />
<root level="INFO">
<appender-ref ref="fileLogAppender"/>
<appender-ref ref="STDOUT"/>
</root>
</configuration>

32
k8s/common/tb-node-hybrid-configmap.yml

@ -1,32 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-node-db-config
namespace: thingsboard
labels:
name: tb-node-db-config
data:
SPRING_JPA_DATABASE_PLATFORM: org.hibernate.dialect.PostgreSQLDialect
SPRING_DRIVER_CLASS_NAME: org.postgresql.Driver
SPRING_DATASOURCE_URL: jdbc:postgresql://tb-database:5432/thingsboard
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: postgres
DATABASE_TS_TYPE: cassandra
CASSANDRA_URL: cassandra:9042
CASSANDRA_SOCKET_READ_TIMEOUT: "60000"

30
k8s/common/tb-node-postgres-configmap.yml

@ -1,30 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-node-db-config
namespace: thingsboard
labels:
name: tb-node-db-config
data:
DATABASE_TS_TYPE: sql
SPRING_JPA_DATABASE_PLATFORM: org.hibernate.dialect.PostgreSQLDialect
SPRING_DRIVER_CLASS_NAME: org.postgresql.Driver
SPRING_DATASOURCE_URL: jdbc:postgresql://tb-database:5432/thingsboard
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: postgres

98
k8s/common/tb-node.yml

@ -1,98 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-node
namespace: thingsboard
spec:
replicas: 2
selector:
matchLabels:
app: tb-node
template:
metadata:
labels:
app: tb-node
spec:
volumes:
- name: tb-node-config
configMap:
name: tb-node-config
items:
- key: conf
path: thingsboard.conf
- key: logback
path: logback.xml
containers:
- name: server
imagePullPolicy: Always
image: thingsboard/tb-node:latest
ports:
- containerPort: 8080
name: http
- containerPort: 9001
name: rpc
env:
- name: TB_SERVICE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: TB_SERVICE_TYPE
value: "monolith"
- name: TB_QUEUE_TYPE
value: "kafka"
- name: ZOOKEEPER_ENABLED
value: "true"
- name: ZOOKEEPER_URL
value: "zookeeper:2181"
- name: TB_KAFKA_SERVERS
value: "tb-kafka:9092"
- name: JS_EVALUATOR
value: "remote"
- name: TRANSPORT_TYPE
value: "remote"
- name: HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE
value: "false"
envFrom:
- configMapRef:
name: tb-node-db-config
- configMapRef:
name: tb-node-cache-config
volumeMounts:
- mountPath: /config
name: tb-node-config
livenessProbe:
httpGet:
path: /login
port: http
initialDelaySeconds: 300
timeoutSeconds: 10
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-node
namespace: thingsboard
spec:
type: ClusterIP
selector:
app: tb-node
ports:
- port: 8080
name: http

451
k8s/common/thingsboard.yml

@ -1,451 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-js-executor
namespace: thingsboard
spec:
replicas: 20
selector:
matchLabels:
app: tb-js-executor
template:
metadata:
labels:
app: tb-js-executor
spec:
containers:
- name: server
imagePullPolicy: Always
image: thingsboard/tb-js-executor:latest
env:
- name: REMOTE_JS_EVAL_REQUEST_TOPIC
value: "js_eval.requests"
- name: TB_KAFKA_SERVERS
value: "tb-kafka:9092"
- name: LOGGER_LEVEL
value: "info"
- name: LOG_FOLDER
value: "logs"
- name: LOGGER_FILENAME
value: "tb-js-executor-%DATE%.log"
- name: DOCKER_MODE
value: "true"
- name: SCRIPT_BODY_TRACE_FREQUENCY
value: "1000"
restartPolicy: Always
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-mqtt-transport
namespace: thingsboard
spec:
replicas: 2
selector:
matchLabels:
app: tb-mqtt-transport
template:
metadata:
labels:
app: tb-mqtt-transport
spec:
volumes:
- name: tb-mqtt-transport-config
configMap:
name: tb-mqtt-transport-config
items:
- key: conf
path: tb-mqtt-transport.conf
- key: logback
path: logback.xml
containers:
- name: server
imagePullPolicy: Always
image: thingsboard/tb-mqtt-transport:latest
ports:
- containerPort: 1883
name: mqtt
env:
- name: TB_SERVICE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: TB_QUEUE_TYPE
value: "kafka"
- name: MQTT_BIND_ADDRESS
value: "0.0.0.0"
- name: MQTT_BIND_PORT
value: "1883"
- name: MQTT_TIMEOUT
value: "10000"
- name: TB_KAFKA_SERVERS
value: "tb-kafka:9092"
volumeMounts:
- mountPath: /config
name: tb-mqtt-transport-config
readinessProbe:
periodSeconds: 20
tcpSocket:
port: 1883
livenessProbe:
initialDelaySeconds: 120
periodSeconds: 20
tcpSocket:
port: 1883
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-mqtt-transport
namespace: thingsboard
spec:
type: LoadBalancer
selector:
app: tb-mqtt-transport
ports:
- port: 1883
targetPort: 1883
name: mqtt
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-http-transport
namespace: thingsboard
spec:
replicas: 2
selector:
matchLabels:
app: tb-http-transport
template:
metadata:
labels:
app: tb-http-transport
spec:
volumes:
- name: tb-http-transport-config
configMap:
name: tb-http-transport-config
items:
- key: conf
path: tb-http-transport.conf
- key: logback
path: logback.xml
containers:
- name: server
imagePullPolicy: Always
image: thingsboard/tb-http-transport:latest
ports:
- containerPort: 8080
name: http
env:
- name: TB_SERVICE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: TB_QUEUE_TYPE
value: "kafka"
- name: HTTP_BIND_ADDRESS
value: "0.0.0.0"
- name: HTTP_BIND_PORT
value: "8080"
- name: HTTP_REQUEST_TIMEOUT
value: "60000"
- name: TB_KAFKA_SERVERS
value: "tb-kafka:9092"
volumeMounts:
- mountPath: /config
name: tb-http-transport-config
readinessProbe:
periodSeconds: 20
tcpSocket:
port: 8080
livenessProbe:
initialDelaySeconds: 120
periodSeconds: 20
tcpSocket:
port: 8080
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-http-transport
namespace: thingsboard
spec:
type: ClusterIP
selector:
app: tb-http-transport
ports:
- port: 8080
name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-coap-transport
namespace: thingsboard
spec:
replicas: 2
selector:
matchLabels:
app: tb-coap-transport
template:
metadata:
labels:
app: tb-coap-transport
spec:
volumes:
- name: tb-coap-transport-config
configMap:
name: tb-coap-transport-config
items:
- key: conf
path: tb-coap-transport.conf
- key: logback
path: logback.xml
containers:
- name: server
imagePullPolicy: Always
image: thingsboard/tb-coap-transport:latest
ports:
- containerPort: 5683
name: coap
protocol: UDP
env:
- name: TB_SERVICE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: TB_QUEUE_TYPE
value: "kafka"
- name: COAP_BIND_ADDRESS
value: "0.0.0.0"
- name: COAP_BIND_PORT
value: "5683"
- name: COAP_TIMEOUT
value: "10000"
- name: TB_KAFKA_SERVERS
value: "tb-kafka:9092"
volumeMounts:
- mountPath: /config
name: tb-coap-transport-config
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-coap-transport
namespace: thingsboard
spec:
type: LoadBalancer
selector:
app: tb-coap-transport
ports:
- port: 5683
name: coap
protocol: UDP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-lwm2m-transport
namespace: thingsboard
spec:
replicas: 2
selector:
matchLabels:
app: tb-lwm2m-transport
template:
metadata:
labels:
app: tb-lwm2m-transport
spec:
volumes:
- name: tb-lwm2m-transport-config
configMap:
name: tb-lwm2m-transport-config
items:
- key: conf
path: tb-lwm2m-transport.conf
- key: logback
path: logback.xml
containers:
- name: server
imagePullPolicy: Always
image: thingsboard/tb-lwm2m-transport:latest
ports:
- containerPort: 5685
name: lwm2m
protocol: UDP
env:
- name: TB_SERVICE_ID
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: TB_QUEUE_TYPE
value: "kafka"
- name: LWM2M_BIND_ADDRESS
value: "0.0.0.0"
- name: LWM2M_BIND_PORT
value: "5685"
- name: LWM2M_TIMEOUT
value: "10000"
- name: TB_KAFKA_SERVERS
value: "tb-kafka:9092"
volumeMounts:
- mountPath: /config
name: tb-lwm2m-transport-config
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-lwm2m-transport
namespace: thingsboard
spec:
type: LoadBalancer
selector:
app: tb-lwm2m-transport
ports:
- port: 5685
name: lwm2m
protocol: UDP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tb-web-ui
namespace: thingsboard
spec:
replicas: 2
selector:
matchLabels:
app: tb-web-ui
template:
metadata:
labels:
app: tb-web-ui
spec:
containers:
- name: server
imagePullPolicy: Always
image: thingsboard/tb-web-ui:latest
ports:
- containerPort: 8080
name: http
env:
- name: HTTP_BIND_ADDRESS
value: "0.0.0.0"
- name: HTTP_BIND_PORT
value: "8080"
- name: TB_ENABLE_PROXY
value: "false"
- name: LOGGER_LEVEL
value: "info"
- name: LOG_FOLDER
value: "logs"
- name: LOGGER_FILENAME
value: "tb-web-ui-%DATE%.log"
- name: DOCKER_MODE
value: "true"
livenessProbe:
httpGet:
path: /index.html
port: http
initialDelaySeconds: 120
timeoutSeconds: 10
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: tb-web-ui
namespace: thingsboard
spec:
type: ClusterIP
selector:
app: tb-web-ui
ports:
- port: 8080
name: http
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tb-ingress
namespace: thingsboard
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
spec:
rules:
- http:
paths:
- path: /api/v1/.*
backend:
serviceName: tb-http-transport
servicePort: 8080
- path: /api/.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /swagger.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /webjars.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /v2/.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /v3/.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /static/rulenode/.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /assets/help/.*/rulenode/.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /oauth2/.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /login/oauth2/.*
backend:
serviceName: tb-node
servicePort: 8080
- path: /
backend:
serviceName: tb-web-ui
servicePort: 8080
- path: /.*
backend:
serviceName: tb-web-ui
servicePort: 8080
---

27
k8s/high-availability/tb-node-cache-configmap.yml

@ -1,27 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-node-cache-config
namespace: thingsboard
labels:
name: tb-node-cache-config
data:
CACHE_TYPE: redis
REDIS_CONNECTION_TYPE: cluster
REDIS_NODES: tb-redis:6379

301
k8s/high-availability/thirdparty.yml

@ -1,301 +0,0 @@
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zookeeper
namespace: thingsboard
spec:
serviceName: "zookeeper"
replicas: 3
podManagementPolicy: Parallel
selector:
matchLabels:
app: zookeeper
template:
metadata:
labels:
app: zookeeper
spec:
containers:
- name: zookeeper
imagePullPolicy: Always
image: zookeeper:3.5
ports:
- containerPort: 2181
name: client
- containerPort: 2888
name: server
- containerPort: 3888
name: election
readinessProbe:
periodSeconds: 60
tcpSocket:
port: 2181
livenessProbe:
periodSeconds: 60
tcpSocket:
port: 2181
env:
- name: ZOO_SERVERS
value: "server.0=zookeeper-0.zookeeper:2888:3888;2181 server.1=zookeeper-1.zookeeper:2888:3888;2181 server.2=zookeeper-2.zookeeper:2888:3888;2181"
- name: JVMFLAGS
value: "-Dzookeeper.electionPortBindRetry=0"
volumeMounts:
- name: data
mountPath: /data
readOnly: false
initContainers:
- command:
- /bin/bash
- -c
- |-
set -ex;
mkdir -p "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR";
chown "$ZOO_USER:$ZOO_USER" "$ZOO_DATA_LOG_DIR" "$ZOO_DATA_DIR" "$ZOO_CONF_DIR"
if [[ ! -f "$ZOO_DATA_DIR/myid" ]]; then
echo $HOSTNAME| rev | cut -d "-" -f1 | rev > "$ZOO_DATA_DIR/myid"
fi
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: metadata.name
image: zookeeper:3.5
imagePullPolicy: IfNotPresent
name: zookeeper-init
securityContext:
runAsUser: 0
volumeMounts:
- name: data
mountPath: /data
readOnly: false
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Mi
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper
namespace: thingsboard
spec:
type: ClusterIP
ports:
- port: 2181
targetPort: 2181
name: client
- port: 2888
targetPort: 2888
name: server
- port: 3888
targetPort: 3888
name: election
selector:
app: zookeeper
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: tb-kafka
namespace: thingsboard
spec:
serviceName: "tb-kafka"
replicas: 3
podManagementPolicy: Parallel
selector:
matchLabels:
app: tb-kafka
template:
metadata:
labels:
app: tb-kafka
spec:
containers:
- name: tb-kafka
imagePullPolicy: Always
image: wurstmeister/kafka:2.12-2.2.1
ports:
- containerPort: 9092
name: kafka-int
readinessProbe:
periodSeconds: 5
timeoutSeconds: 5
tcpSocket:
port: 9092
initialDelaySeconds: 60
livenessProbe:
timeoutSeconds: 5
periodSeconds: 5
tcpSocket:
port: 9092
initialDelaySeconds: 80
env:
- name: BROKER_ID_COMMAND
value: "hostname | cut -d'-' -f3"
- name: KAFKA_ZOOKEEPER_CONNECT
value: "zookeeper:2181"
- name: KAFKA_ZOOKEEPER_CONNECTION_TIMEOUT_MS
value: "60000"
- name: KAFKA_UNCLEAN_LEADER_ELECTION_ENABLE
value: "true"
- name: KAFKA_LISTENERS
value: "INSIDE://:9092"
- name: KAFKA_ADVERTISED_LISTENERS
value: "INSIDE://:9092"
- name: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
value: "INSIDE:PLAINTEXT"
- name: KAFKA_INTER_BROKER_LISTENER_NAME
value: "INSIDE"
- name: KAFKA_CONTROLLER_SHUTDOWN_ENABLE
value: "true"
- name: KAFKA_CREATE_TOPICS
value: "js_eval.requests:100:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_transport.api.requests:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600,tb_rule_engine:30:1:delete --config=retention.ms=60000 --config=segment.bytes=26214400 --config=retention.bytes=104857600"
- name: KAFKA_AUTO_CREATE_TOPICS_ENABLE
value: "false"
- name: KAFKA_LOG_RETENTION_BYTES
value: "1073741824"
- name: KAFKA_LOG_SEGMENT_BYTES
value: "268435456"
- name: KAFKA_LOG_RETENTION_MS
value: "300000"
- name: KAFKA_LOG_CLEANUP_POLICY
value: "delete"
- name: KAFKA_PORT
value: "9092"
- name: KAFKA_LOG_DIRS
value: "/kafka-logs"
volumeMounts:
- name: logs
mountPath: /kafka-logs
subPath: logs
volumeClaimTemplates:
- metadata:
name: logs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
name: tb-kafka
namespace: thingsboard
spec:
type: ClusterIP
ports:
- port: 9092
targetPort: 9092
name: kafka-int
selector:
app: tb-kafka
---
apiVersion: v1
kind: ConfigMap
metadata:
name: tb-redis
namespace: thingsboard
data:
update-node.sh: |
#!/bin/sh
REDIS_NODES="/data/nodes.conf"
sed -i -e "/myself/ s/[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/${POD_IP}/" ${REDIS_NODES}
exec "$@"
redis.conf: |+
cluster-enabled yes
cluster-require-full-coverage no
cluster-node-timeout 15000
cluster-config-file /data/nodes.conf
cluster-migration-barrier 1
appendonly yes
protected-mode no
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: tb-redis
namespace: thingsboard
spec:
serviceName: server
replicas: 6
selector:
matchLabels:
app: tb-redis
template:
metadata:
labels:
app: tb-redis
spec:
containers:
- name: redis
image: redis:5.0.1-alpine
ports:
- containerPort: 6379
name: client
- containerPort: 16379
name: gossip
command: ["/conf/update-node.sh", "redis-server", "/conf/redis.conf"]
env:
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
volumeMounts:
- name: conf
mountPath: /conf
readOnly: false
- name: data
mountPath: /data
readOnly: false
volumes:
- name: conf
configMap:
name: tb-redis
defaultMode: 0755
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Mi
---
apiVersion: v1
kind: Service
metadata:
name: tb-redis
namespace: thingsboard
spec:
type: ClusterIP
ports:
- port: 6379
targetPort: 6379
name: client
- port: 16379
targetPort: 16379
name: gossip
selector:
app: tb-redis

20
k8s/k8s-delete-all.sh

@ -1,20 +0,0 @@
#!/bin/bash
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
kubectl -n thingsboard delete svc,sts,deploy,cm,po,ing --all
kubectl -n thingsboard get pvc --no-headers=true | awk '//{print $1}' | xargs kubectl -n thingsboard delete --ignore-not-found=true pvc

25
k8s/k8s-delete-resources.sh

@ -1,25 +0,0 @@
#!/bin/bash
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e
source .env
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard
kubectl delete -f common/thingsboard.yml
kubectl delete -f common/tb-node.yml

23
k8s/k8s-delete-thirdparty.sh

@ -1,23 +0,0 @@
#!/bin/bash
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e
source .env
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard
kubectl delete -f $DEPLOYMENT_TYPE/thirdparty.yml

30
k8s/k8s-deploy-resources.sh

@ -1,30 +0,0 @@
#!/bin/bash
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e
source .env
kubectl apply -f common/tb-namespace.yml
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard
kubectl apply -f common/tb-node-configmap.yml
kubectl apply -f common/tb-mqtt-transport-configmap.yml
kubectl apply -f common/tb-http-transport-configmap.yml
kubectl apply -f common/tb-coap-transport-configmap.yml
kubectl apply -f common/thingsboard.yml
kubectl apply -f $DEPLOYMENT_TYPE/tb-node-cache-configmap.yml
kubectl apply -f common/tb-node.yml

45
k8s/k8s-deploy-thirdparty.sh

@ -1,45 +0,0 @@
#!/bin/bash
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e
source .env
kubectl apply -f common/tb-namespace.yml
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard
kubectl apply -f $DEPLOYMENT_TYPE/thirdparty.yml
if [ "$DEPLOYMENT_TYPE" == "high-availability" ]; then
echo -n "waiting for all redis pods to be ready";
while [[ $(kubectl get pods tb-redis-5 -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}' 2>/dev/null) != "True" ]];
do
echo -n "." && sleep 5;
done
if [[ $(kubectl exec -it tb-redis-0 -- redis-cli cluster info 2>&1 | head -n 1) =~ "cluster_state:ok" ]]
then
echo "redis cluster is already configured"
else
echo "starting redis cluster"
redisNodes=$(kubectl get pods -l app=tb-redis -o jsonpath='{range.items[*]}{.status.podIP}:6379 ')
kubectl exec -it tb-redis-0 -- redis-cli --cluster create --cluster-replicas 1 $redisNodes
fi
fi

106
k8s/k8s-install-tb.sh

@ -1,106 +0,0 @@
#!/bin/bash
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
function installTb() {
loadDemo=$1
kubectl apply -f common/tb-node-configmap.yml
kubectl apply -f common/database-setup.yml &&
kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s &&
kubectl exec tb-db-setup -- sh -c 'export INSTALL_TB=true; export LOAD_DEMO='"$loadDemo"'; start-tb-node.sh; touch /tmp/install-finished;'
kubectl delete pod tb-db-setup
}
function installPostgres() {
kubectl apply -f common/postgres.yml
kubectl apply -f common/tb-node-postgres-configmap.yml
kubectl rollout status deployment/postgres
}
function installHybrid() {
kubectl apply -f common/postgres.yml
kubectl apply -f common/cassandra.yml
kubectl apply -f common/tb-node-hybrid-configmap.yml
kubectl rollout status deployment/postgres
kubectl rollout status statefulset/cassandra
kubectl exec -it cassandra-0 -- bash -c "cqlsh -e \
\"CREATE KEYSPACE IF NOT EXISTS thingsboard \
WITH replication = { \
'class' : 'SimpleStrategy', \
'replication_factor' : 1 \
};\""
}
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
--loadDemo)
LOAD_DEMO=true
shift # past argument
;;
*)
# unknown option
;;
esac
shift # past argument or value
done
if [ "$LOAD_DEMO" == "true" ]; then
loadDemo=true
else
loadDemo=false
fi
source .env
kubectl apply -f common/tb-namespace.yml
kubectl config set-context $(kubectl config current-context) --namespace=thingsboard
case $DEPLOYMENT_TYPE in
basic)
;;
high-availability)
;;
*)
echo "Unknown DEPLOYMENT_TYPE value specified: '${DEPLOYMENT_TYPE}'. Should be either basic or high-availability." >&2
exit 1
esac
case $DATABASE in
postgres)
installPostgres
installTb ${loadDemo}
;;
hybrid)
installHybrid
installTb ${loadDemo}
;;
*)
echo "Unknown DATABASE value specified: '${DATABASE}'. Should be either postgres or hybrid." >&2
exit 1
esac

43
k8s/k8s-upgrade-tb.sh

@ -1,43 +0,0 @@
#!/bin/bash
#
# Copyright © 2016-2021 The Thingsboard Authors
#
# 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
#
# 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.
# See the License for the specific language governing permissions and
# limitations under the License.
#
for i in "$@"
do
case $i in
--fromVersion=*)
FROM_VERSION="${i#*=}"
shift
;;
*)
# unknown option
;;
esac
done
if [[ -z "${FROM_VERSION// }" ]]; then
echo "--fromVersion parameter is invalid or unspecified!"
echo "Usage: k8s-upgrade-tb.sh --fromVersion={VERSION}"
exit 1
else
fromVersion="${FROM_VERSION// }"
fi
kubectl apply -f common/database-setup.yml &&
kubectl wait --for=condition=Ready pod/tb-db-setup --timeout=120s &&
kubectl exec tb-db-setup -- sh -c 'export UPGRADE_TB=true; export FROM_VERSION='"$fromVersion"'; start-tb-node.sh; touch /tmp/install-finished;'
kubectl delete pod tb-db-setup

1
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNodeConfiguration.java

@ -37,7 +37,6 @@ public class TbMqttNodeConfiguration implements NodeConfiguration<TbMqttNodeConf
public TbMqttNodeConfiguration defaultConfiguration() {
TbMqttNodeConfiguration configuration = new TbMqttNodeConfiguration();
configuration.setTopicPattern("my-topic");
configuration.setHost("localhost");
configuration.setPort(1883);
configuration.setConnectTimeoutSec(10);
configuration.setCleanSession(true);

2
rule-engine/rule-engine-components/src/main/resources/public/static/rulenode/rulenode-core-config.js

File diff suppressed because one or more lines are too long

2
transport/coap/src/main/resources/tb-coap-transport.yml

@ -106,7 +106,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}"

2
transport/http/src/main/resources/tb-http-transport.yml

@ -31,7 +31,7 @@ server:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${SSL_PEM_CERT:server.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${SSL_PEM_KEY:server_key.pem}"
# Server certificate private key password (optional)
key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}"

4
transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml

@ -121,7 +121,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}"
@ -157,7 +157,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}"

6
transport/mqtt/src/main/resources/tb-mqtt-transport.yml

@ -104,7 +104,7 @@ transport:
bind_address: "${MQTT_SSL_BIND_ADDRESS:0.0.0.0}"
# MQTT SSL bind port
bind_port: "${MQTT_SSL_BIND_PORT:8883}"
# SSL protocol: See http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#SSLContext
# SSL protocol: See https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms
protocol: "${MQTT_SSL_PROTOCOL:TLSv1.2}"
# Server SSL credentials
credentials:
@ -114,7 +114,7 @@ transport:
pem:
# Path to the server certificate file (holds server certificate or certificate chain, may include server private key)
cert_file: "${MQTT_SSL_PEM_CERT:mqttserver.pem}"
# Path to the server certificate private key file (optional)
# Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file;
key_file: "${MQTT_SSL_PEM_KEY:mqttserver_key.pem}"
# Server certificate private key password (optional)
key_password: "${MQTT_SSL_PEM_KEY_PASSWORD:server_key_password}"
@ -126,6 +126,8 @@ transport:
store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}"
# Password used to access the key store
store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}"
# Optional alias of the private key; If not set, the platform will load the first private key from the keystore;
key_alias: "${MQTT_SSL_KEY_ALIAS:}"
# Password used to access the key
key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}"
# Skip certificate validity check for client certificates.

3
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html

@ -45,6 +45,9 @@
<mat-error *ngIf="alarmFormGroup.get('alarmType').hasError('unique')">
{{ 'device-profile.alarm-type-unique' | translate }}
</mat-error>
<mat-error *ngIf="alarmFormGroup.get('alarmType').hasError('maxlength')">
{{ 'device-profile.alarm-type-max-length' | translate }}
</mat-error>
</mat-form-field>
</div>
<mat-expansion-panel class="advanced-settings" [expanded]="false">

2
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.ts

@ -93,7 +93,7 @@ export class DeviceProfileAlarmComponent implements ControlValueAccessor, OnInit
ngOnInit() {
this.alarmFormGroup = this.fb.group({
id: [null, Validators.required],
alarmType: [null, Validators.required],
alarmType: [null, [Validators.required, Validators.maxLength(255)]],
createRules: [null],
clearRule: [null],
propagate: [null],

17
ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html

@ -22,7 +22,7 @@
class="tb-json-input__form"
[formGroup]="attributeUpdateFormGroup"
(ngSubmit)="save()">
<div fxLayout="column" fxLayoutGap="10px" fxFlex *ngIf="entityDetected && isValidParameter && dataKeyDetected">
<div fxLayout="column" fxLayoutGap="10px" fxFlex *ngIf="datasourceDetected && !errorMessage; else errorContainer">
<fieldset fxFlex>
<tb-json-object-edit
[editorStyle]="{minHeight: '100px'}"
@ -51,19 +51,10 @@
</div>
</div>
<div fxLayout="column" fxLayoutAlign="center center" fxFlex *ngIf="!entityDetected || !dataKeyDetected || !isValidParameter">
<div class="tb-json-input__error"
*ngIf="!entityDetected">
{{ 'widgets.input-widgets.no-entity-selected' | translate }}
</div>
<div class="tb-json-input__error"
*ngIf="entityDetected && !dataKeyDetected">
{{ 'widgets.input-widgets.no-datakey-selected' | translate }}
</div>
<div class="tb-json-input__error"
*ngIf="dataKeyDetected && !isValidParameter">
<ng-template #errorContainer>
<div class="tb-json-input__error" fxLayout="column" fxLayoutAlign="center center" fxFlex>
{{ errorMessage | translate }}
</div>
</div>
</ng-template>
</form>
</div>

1
ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.scss

@ -25,7 +25,6 @@
}
&__error {
text-align: center;
font-size: 18px;
color: #a0a0a0;
}

44
ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.ts

@ -28,7 +28,7 @@ import { AttributeService } from '@core/http/attribute.service';
import { AttributeData, AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
import { EntityId } from '@shared/models/id/entity-id';
import { EntityType } from '@shared/models/entity-type.models';
import { createLabelFromDatasource } from '@core/utils';
import { createLabelFromDatasource, isDefinedAndNotNull } from '@core/utils';
import { Observable } from 'rxjs';
enum JsonInputWidgetMode {
@ -63,9 +63,7 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit {
labelValue: string;
entityDetected = false;
dataKeyDetected = false;
isValidParameter = false;
datasourceDetected = false;
errorMessage: string;
isFocused: boolean;
@ -111,30 +109,26 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit {
}
private validateDatasources() {
if (this.datasource?.type === DatasourceType.entity) {
this.entityDetected = true;
if (this.datasource.dataKeys.length) {
this.dataKeyDetected = true;
if (this.settings.widgetMode === JsonInputWidgetMode.ATTRIBUTE) {
if (this.datasource.dataKeys[0].type === DataKeyType.attribute) {
if (this.settings.attributeScope === AttributeScope.SERVER_SCOPE || this.datasource.entityType === EntityType.DEVICE) {
this.isValidParameter = true;
} else {
this.errorMessage = 'widgets.input-widgets.not-allowed-entity';
}
} else {
this.errorMessage = 'widgets.input-widgets.no-attribute-selected';
this.datasourceDetected = isDefinedAndNotNull(this.datasource);
if (!this.datasourceDetected) {
return;
}
if (this.datasource.type === DatasourceType.entity) {
if (this.settings.widgetMode === JsonInputWidgetMode.ATTRIBUTE) {
if (this.datasource.dataKeys[0].type === DataKeyType.attribute) {
if (this.settings.attributeScope !== AttributeScope.SERVER_SCOPE && this.datasource.entityType !== EntityType.DEVICE) {
this.errorMessage = 'widgets.input-widgets.not-allowed-entity';
}
} else {
if (this.datasource.dataKeys[0].type === DataKeyType.timeseries) {
this.isValidParameter = true;
} else {
this.errorMessage = 'widgets.input-widgets.no-timeseries-selected';
}
this.errorMessage = 'widgets.input-widgets.no-attribute-selected';
}
} else {
if (this.datasource.dataKeys[0].type !== DataKeyType.timeseries) {
this.errorMessage = 'widgets.input-widgets.no-timeseries-selected';
}
}
} else {
this.errorMessage = 'widgets.input-widgets.no-entity-selected';
}
}
@ -152,7 +146,7 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit {
}
private updateWidgetData(data: Array<DatasourceData>) {
if (this.isValidParameter) {
if (!this.errorMessage) {
let value = {};
if (data[0].data[0][1] !== '') {
try {

14
ui-ngx/src/app/modules/home/pages/api-usage/api_usage_json.raw

File diff suppressed because one or more lines are too long

3
ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.html

@ -32,6 +32,9 @@
|| ruleNodeFormGroup.get('name').hasError('pattern')">
{{ 'rulenode.name-required' | translate }}
</mat-error>
<mat-error *ngIf="ruleNodeFormGroup.get('name').hasError('maxlength')">
{{ 'rulenode.name-max-length' | translate }}
</mat-error>
</mat-form-field>
<mat-checkbox formControlName="debugMode">
{{ 'rulenode.debug-mode' | translate }}

2
ui-ngx/src/app/modules/home/pages/rulechain/rule-node-details.component.ts

@ -78,7 +78,7 @@ export class RuleNodeDetailsComponent extends PageComponent implements OnInit, O
if (this.ruleNode.component.type !== RuleNodeType.RULE_CHAIN) {
this.ruleNodeFormGroup = this.fb.group({
name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*')]],
name: [this.ruleNode.name, [Validators.required, Validators.pattern('(.|\\s)*\\S(.|\\s)*'), Validators.maxLength(255)]],
debugMode: [this.ruleNode.debugMode, []],
configuration: [this.ruleNode.configuration, [Validators.required]],
additionalInfo: this.fb.group(

2
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1174,6 +1174,7 @@
"alarm-type": "Alarm type",
"alarm-type-required": "Alarm type is required.",
"alarm-type-unique": "Alarm type must be unique within the device profile alarm rules.",
"alarm-type-max-length": "Alarm type should be less than 256",
"create-alarm-pattern": "Create <b>{{alarmType}}</b> alarm",
"create-alarm-rules": "Create alarm rules",
"no-create-alarm-rules": "No create conditions configured",
@ -2595,6 +2596,7 @@
"add": "Add rule node",
"name": "Name",
"name-required": "Name is required.",
"name-max-length": "Name should be less than 256",
"type": "Type",
"description": "Description",
"delete": "Delete rule node",

Loading…
Cancel
Save