Commit e3292e89c15e604211fcb33a7ab45229462dd2ff
Committed by
GitHub
Merge pull request #4301 from thingsboard/develop/snmp
SNMP Transport
Showing
100 changed files
with
3701 additions
and
99 deletions
Too many changes to show.
To preserve performance only 100 of 125 files are displayed.
... | ... | @@ -90,6 +90,10 @@ |
90 | 90 | <artifactId>lwm2m</artifactId> |
91 | 91 | </dependency> |
92 | 92 | <dependency> |
93 | + <groupId>org.thingsboard.common.transport</groupId> | |
94 | + <artifactId>snmp</artifactId> | |
95 | + </dependency> | |
96 | + <dependency> | |
93 | 97 | <groupId>org.thingsboard</groupId> |
94 | 98 | <artifactId>dao</artifactId> |
95 | 99 | </dependency> | ... | ... |
... | ... | @@ -25,7 +25,6 @@ import org.springframework.stereotype.Service; |
25 | 25 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
26 | 26 | import org.thingsboard.server.actors.ActorSystemContext; |
27 | 27 | import org.thingsboard.server.actors.DefaultTbActorSystem; |
28 | -import org.thingsboard.server.actors.TbActorId; | |
29 | 28 | import org.thingsboard.server.actors.TbActorRef; |
30 | 29 | import org.thingsboard.server.actors.TbActorSystem; |
31 | 30 | import org.thingsboard.server.actors.TbActorSystemSettings; |
... | ... | @@ -33,14 +32,13 @@ import org.thingsboard.server.actors.app.AppActor; |
33 | 32 | import org.thingsboard.server.actors.app.AppInitMsg; |
34 | 33 | import org.thingsboard.server.actors.stats.StatsActor; |
35 | 34 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
36 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
37 | 35 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
36 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
38 | 37 | |
39 | 38 | import javax.annotation.PostConstruct; |
40 | 39 | import javax.annotation.PreDestroy; |
41 | 40 | import java.util.concurrent.ExecutorService; |
42 | 41 | import java.util.concurrent.Executors; |
43 | -import java.util.concurrent.ScheduledExecutorService; | |
44 | 42 | |
45 | 43 | @Service |
46 | 44 | @Slf4j | ... | ... |
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
... | ... | @@ -56,7 +56,7 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; |
56 | 56 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
57 | 57 | import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; |
58 | 58 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
59 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
59 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
60 | 60 | import org.thingsboard.server.queue.discovery.PartitionService; |
61 | 61 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
62 | 62 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; | ... | ... |
... | ... | @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantProfileId; |
23 | 23 | import org.thingsboard.server.common.msg.queue.TbCallback; |
24 | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
25 | 25 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
26 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
26 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
27 | 27 | |
28 | 28 | public interface TbApiUsageStateService extends ApplicationListener<PartitionChangeEvent> { |
29 | 29 | ... | ... |
... | ... | @@ -55,7 +55,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceM |
55 | 55 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
56 | 56 | import org.thingsboard.server.queue.TbQueueConsumer; |
57 | 57 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
58 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
58 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
59 | 59 | import org.thingsboard.server.queue.provider.TbCoreQueueFactory; |
60 | 60 | import org.thingsboard.server.queue.util.TbCoreComponent; |
61 | 61 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | ... | ... |
... | ... | @@ -38,7 +38,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; |
38 | 38 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
39 | 39 | import org.thingsboard.server.queue.TbQueueConsumer; |
40 | 40 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
41 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
41 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
42 | 42 | import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; |
43 | 43 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
44 | 44 | import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | package org.thingsboard.server.service.queue; |
17 | 17 | |
18 | 18 | import org.springframework.context.ApplicationListener; |
19 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
20 | 20 | |
21 | 21 | public interface TbCoreConsumerService extends ApplicationListener<PartitionChangeEvent> { |
22 | 22 | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | package org.thingsboard.server.service.queue; |
17 | 17 | |
18 | 18 | import org.springframework.context.ApplicationListener; |
19 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
20 | 20 | |
21 | 21 | public interface TbRuleEngineConsumerService extends ApplicationListener<PartitionChangeEvent> { |
22 | 22 | ... | ... |
... | ... | @@ -35,7 +35,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; |
35 | 35 | import org.thingsboard.server.common.msg.queue.TbCallback; |
36 | 36 | import org.thingsboard.server.queue.TbQueueConsumer; |
37 | 37 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
38 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
38 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
39 | 39 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
40 | 40 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
41 | 41 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | ... | ... |
... | ... | @@ -54,7 +54,7 @@ import org.thingsboard.server.dao.tenant.TenantService; |
54 | 54 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
55 | 55 | import org.thingsboard.common.util.JacksonUtil; |
56 | 56 | import org.thingsboard.server.gen.transport.TransportProtos; |
57 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
57 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
58 | 58 | import org.thingsboard.server.queue.discovery.PartitionService; |
59 | 59 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
60 | 60 | import org.thingsboard.server.queue.util.TbCoreComponent; | ... | ... |
... | ... | @@ -18,7 +18,7 @@ package org.thingsboard.server.service.state; |
18 | 18 | import org.springframework.context.ApplicationListener; |
19 | 19 | import org.thingsboard.server.common.data.Device; |
20 | 20 | import org.thingsboard.server.common.data.id.DeviceId; |
21 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
21 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
22 | 22 | import org.thingsboard.server.gen.transport.TransportProtos; |
23 | 23 | import org.thingsboard.server.common.msg.queue.TbCallback; |
24 | 24 | ... | ... |
... | ... | @@ -46,7 +46,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdate |
46 | 46 | import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateValueListProto; |
47 | 47 | import org.thingsboard.server.queue.TbQueueProducer; |
48 | 48 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
49 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
49 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
50 | 50 | import org.thingsboard.server.queue.discovery.PartitionService; |
51 | 51 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
52 | 52 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | ... | ... |
... | ... | @@ -20,10 +20,9 @@ import org.springframework.beans.factory.annotation.Autowired; |
20 | 20 | import org.springframework.context.annotation.Lazy; |
21 | 21 | import org.springframework.context.event.EventListener; |
22 | 22 | import org.springframework.stereotype.Service; |
23 | -import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
24 | 23 | import org.thingsboard.server.gen.transport.TransportProtos; |
25 | -import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent; | |
26 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
24 | +import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; | |
25 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
27 | 26 | import org.thingsboard.server.queue.discovery.PartitionService; |
28 | 27 | import org.thingsboard.server.common.msg.queue.ServiceType; |
29 | 28 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ... | ... |
... | ... | @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.id.TenantId; |
22 | 22 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
23 | 23 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
24 | 24 | import org.thingsboard.server.common.msg.queue.TbCallback; |
25 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
25 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
26 | 26 | |
27 | 27 | import java.util.List; |
28 | 28 | ... | ... |
... | ... | @@ -15,8 +15,8 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.subscription; |
17 | 17 | |
18 | -import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent; | |
19 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
18 | +import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; | |
19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
20 | 20 | import org.thingsboard.server.common.msg.queue.TbCallback; |
21 | 21 | import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; |
22 | 22 | import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate; | ... | ... |
... | ... | @@ -22,35 +22,18 @@ import lombok.extern.slf4j.Slf4j; |
22 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 23 | import org.springframework.context.ApplicationListener; |
24 | 24 | import org.springframework.context.event.EventListener; |
25 | -import org.springframework.stereotype.Service; | |
26 | 25 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
27 | -import org.thingsboard.server.common.data.id.EntityId; | |
28 | -import org.thingsboard.server.common.data.id.TenantId; | |
29 | -import org.thingsboard.server.common.data.kv.AttributeKvEntry; | |
30 | -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | |
31 | -import org.thingsboard.server.common.data.kv.BooleanDataEntry; | |
32 | -import org.thingsboard.server.common.data.kv.DoubleDataEntry; | |
33 | -import org.thingsboard.server.common.data.kv.LongDataEntry; | |
34 | -import org.thingsboard.server.common.data.kv.StringDataEntry; | |
35 | -import org.thingsboard.server.common.data.kv.TsKvEntry; | |
36 | 26 | import org.thingsboard.server.common.msg.queue.ServiceType; |
37 | -import org.thingsboard.server.common.msg.queue.TbCallback; | |
38 | 27 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
39 | -import org.thingsboard.server.dao.attributes.AttributesService; | |
40 | -import org.thingsboard.server.dao.timeseries.TimeseriesService; | |
41 | -import org.thingsboard.server.gen.transport.TransportProtos; | |
42 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
28 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
43 | 29 | import org.thingsboard.server.queue.discovery.PartitionService; |
44 | 30 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
45 | 31 | import org.thingsboard.server.service.queue.TbClusterService; |
46 | 32 | import org.thingsboard.server.service.subscription.SubscriptionManagerService; |
47 | -import org.thingsboard.server.service.subscription.TbSubscriptionUtils; | |
48 | 33 | |
49 | 34 | import javax.annotation.Nullable; |
50 | 35 | import javax.annotation.PostConstruct; |
51 | 36 | import javax.annotation.PreDestroy; |
52 | -import java.util.Collections; | |
53 | -import java.util.List; | |
54 | 37 | import java.util.Optional; |
55 | 38 | import java.util.Set; |
56 | 39 | import java.util.concurrent.ConcurrentHashMap; | ... | ... |
... | ... | @@ -17,8 +17,7 @@ package org.thingsboard.server.service.telemetry; |
17 | 17 | |
18 | 18 | import org.springframework.context.ApplicationListener; |
19 | 19 | import org.thingsboard.rule.engine.api.RuleEngineAlarmService; |
20 | -import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; | |
21 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
20 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
22 | 21 | |
23 | 22 | /** |
24 | 23 | * Created by ashvayka on 27.03.18. | ... | ... |
application/src/main/java/org/thingsboard/server/service/telemetry/TelemetrySubscriptionService.java
... | ... | @@ -16,8 +16,7 @@ |
16 | 16 | package org.thingsboard.server.service.telemetry; |
17 | 17 | |
18 | 18 | import org.springframework.context.ApplicationListener; |
19 | -import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; | |
20 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | |
19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
21 | 20 | |
22 | 21 | /** |
23 | 22 | * Created by ashvayka on 27.03.18. | ... | ... |
... | ... | @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.ApiUsageState; |
31 | 31 | import org.thingsboard.server.common.data.DataConstants; |
32 | 32 | import org.thingsboard.server.common.data.Device; |
33 | 33 | import org.thingsboard.server.common.data.DeviceProfile; |
34 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
34 | 35 | import org.thingsboard.server.common.data.EntityType; |
35 | 36 | import org.thingsboard.server.common.data.Firmware; |
36 | 37 | import org.thingsboard.server.common.data.FirmwareInfo; |
... | ... | @@ -45,6 +46,8 @@ import org.thingsboard.server.common.data.id.DeviceId; |
45 | 46 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
46 | 47 | import org.thingsboard.server.common.data.id.FirmwareId; |
47 | 48 | import org.thingsboard.server.common.data.id.TenantId; |
49 | +import org.thingsboard.server.common.data.page.PageData; | |
50 | +import org.thingsboard.server.common.data.page.PageLink; | |
48 | 51 | import org.thingsboard.server.common.data.relation.EntityRelation; |
49 | 52 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
50 | 53 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
... | ... | @@ -64,11 +67,15 @@ import org.thingsboard.server.dao.relation.RelationService; |
64 | 67 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
65 | 68 | import org.thingsboard.server.gen.transport.TransportProtos; |
66 | 69 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; |
70 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceCredentialsRequestMsg; | |
71 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceRequestMsg; | |
67 | 72 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; |
68 | 73 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; |
69 | 74 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
70 | 75 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; |
71 | 76 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; |
77 | +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesRequestMsg; | |
78 | +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesResponseMsg; | |
72 | 79 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; |
73 | 80 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
74 | 81 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
... | ... | @@ -91,6 +98,7 @@ import java.util.concurrent.ConcurrentHashMap; |
91 | 98 | import java.util.concurrent.ConcurrentMap; |
92 | 99 | import java.util.concurrent.locks.Lock; |
93 | 100 | import java.util.concurrent.locks.ReentrantLock; |
101 | +import java.util.stream.Collectors; | |
94 | 102 | |
95 | 103 | /** |
96 | 104 | * Created by ashvayka on 05.10.18. |
... | ... | @@ -144,43 +152,43 @@ public class DefaultTransportApiService implements TransportApiService { |
144 | 152 | @Override |
145 | 153 | public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) { |
146 | 154 | TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue(); |
155 | + ListenableFuture<TransportApiResponseMsg> result = null; | |
156 | + | |
147 | 157 | if (transportApiRequestMsg.hasValidateTokenRequestMsg()) { |
148 | 158 | ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg(); |
149 | - return Futures.transform(validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN), | |
150 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
159 | + result = validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN); | |
151 | 160 | } else if (transportApiRequestMsg.hasValidateBasicMqttCredRequestMsg()) { |
152 | 161 | TransportProtos.ValidateBasicMqttCredRequestMsg msg = transportApiRequestMsg.getValidateBasicMqttCredRequestMsg(); |
153 | - return Futures.transform(validateCredentials(msg), | |
154 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
162 | + result = validateCredentials(msg); | |
155 | 163 | } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) { |
156 | 164 | ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg(); |
157 | - return Futures.transform(validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE), | |
158 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
165 | + result = validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE); | |
159 | 166 | } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { |
160 | - return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()), | |
161 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
167 | + result = handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()); | |
162 | 168 | } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) { |
163 | - return Futures.transform(handle(transportApiRequestMsg.getEntityProfileRequestMsg()), | |
164 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
169 | + result = handle(transportApiRequestMsg.getEntityProfileRequestMsg()); | |
165 | 170 | } else if (transportApiRequestMsg.hasLwM2MRequestMsg()) { |
166 | - return Futures.transform(handle(transportApiRequestMsg.getLwM2MRequestMsg()), | |
167 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
171 | + result = handle(transportApiRequestMsg.getLwM2MRequestMsg()); | |
168 | 172 | } else if (transportApiRequestMsg.hasValidateDeviceLwM2MCredentialsRequestMsg()) { |
169 | 173 | ValidateDeviceLwM2MCredentialsRequestMsg msg = transportApiRequestMsg.getValidateDeviceLwM2MCredentialsRequestMsg(); |
170 | - return Futures.transform(validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS), | |
171 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
174 | + result = validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS); | |
172 | 175 | } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { |
173 | - return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()), | |
174 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
176 | + result = handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()); | |
175 | 177 | } else if (transportApiRequestMsg.hasResourceRequestMsg()) { |
176 | - return Futures.transform(handle(transportApiRequestMsg.getResourceRequestMsg()), | |
177 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
178 | + result = handle(transportApiRequestMsg.getResourceRequestMsg()); | |
179 | + } else if (transportApiRequestMsg.hasSnmpDevicesRequestMsg()) { | |
180 | + result = handle(transportApiRequestMsg.getSnmpDevicesRequestMsg()); | |
181 | + } else if (transportApiRequestMsg.hasDeviceRequestMsg()) { | |
182 | + result = handle(transportApiRequestMsg.getDeviceRequestMsg()); | |
183 | + } else if (transportApiRequestMsg.hasDeviceCredentialsRequestMsg()) { | |
184 | + result = handle(transportApiRequestMsg.getDeviceCredentialsRequestMsg()); | |
178 | 185 | } else if (transportApiRequestMsg.hasFirmwareRequestMsg()) { |
179 | - return Futures.transform(handle(transportApiRequestMsg.getFirmwareRequestMsg()), | |
180 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
186 | + result = handle(transportApiRequestMsg.getFirmwareRequestMsg()); | |
181 | 187 | } |
182 | - return Futures.transform(getEmptyTransportApiResponseFuture(), | |
183 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | |
188 | + | |
189 | + return Futures.transform(Optional.ofNullable(result).orElseGet(this::getEmptyTransportApiResponseFuture), | |
190 | + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), | |
191 | + MoreExecutors.directExecutor()); | |
184 | 192 | } |
185 | 193 | |
186 | 194 | private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) { |
... | ... | @@ -374,6 +382,39 @@ public class DefaultTransportApiService implements TransportApiService { |
374 | 382 | return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(builder).build()); |
375 | 383 | } |
376 | 384 | |
385 | + private ListenableFuture<TransportApiResponseMsg> handle(GetDeviceRequestMsg requestMsg) { | |
386 | + DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB())); | |
387 | + Device device = deviceService.findDeviceById(TenantId.SYS_TENANT_ID, deviceId); | |
388 | + | |
389 | + TransportApiResponseMsg responseMsg; | |
390 | + if (device != null) { | |
391 | + UUID deviceProfileId = device.getDeviceProfileId().getId(); | |
392 | + responseMsg = TransportApiResponseMsg.newBuilder() | |
393 | + .setDeviceResponseMsg(TransportProtos.GetDeviceResponseMsg.newBuilder() | |
394 | + .setDeviceProfileIdMSB(deviceProfileId.getMostSignificantBits()) | |
395 | + .setDeviceProfileIdLSB(deviceProfileId.getLeastSignificantBits()) | |
396 | + .setDeviceTransportConfiguration(ByteString.copyFrom( | |
397 | + dataDecodingEncodingService.encode(device.getDeviceData().getTransportConfiguration()) | |
398 | + ))) | |
399 | + .build(); | |
400 | + } else { | |
401 | + responseMsg = TransportApiResponseMsg.getDefaultInstance(); | |
402 | + } | |
403 | + | |
404 | + return Futures.immediateFuture(responseMsg); | |
405 | + } | |
406 | + | |
407 | + private ListenableFuture<TransportApiResponseMsg> handle(GetDeviceCredentialsRequestMsg requestMsg) { | |
408 | + DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB())); | |
409 | + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(TenantId.SYS_TENANT_ID, deviceId); | |
410 | + | |
411 | + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder() | |
412 | + .setDeviceCredentialsResponseMsg(TransportProtos.GetDeviceCredentialsResponseMsg.newBuilder() | |
413 | + .setDeviceCredentialsData(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceCredentials)))) | |
414 | + .build()); | |
415 | + } | |
416 | + | |
417 | + | |
377 | 418 | private ListenableFuture<TransportApiResponseMsg> handle(GetResourceRequestMsg requestMsg) { |
378 | 419 | TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); |
379 | 420 | ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType()); |
... | ... | @@ -392,6 +433,22 @@ public class DefaultTransportApiService implements TransportApiService { |
392 | 433 | return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setResourceResponseMsg(builder).build()); |
393 | 434 | } |
394 | 435 | |
436 | + private ListenableFuture<TransportApiResponseMsg> handle(GetSnmpDevicesRequestMsg requestMsg) { | |
437 | + PageLink pageLink = new PageLink(requestMsg.getPageSize(), requestMsg.getPage()); | |
438 | + PageData<UUID> result = deviceService.findDevicesIdsByDeviceProfileTransportType(DeviceTransportType.SNMP, pageLink); | |
439 | + | |
440 | + GetSnmpDevicesResponseMsg responseMsg = GetSnmpDevicesResponseMsg.newBuilder() | |
441 | + .addAllIds(result.getData().stream() | |
442 | + .map(UUID::toString) | |
443 | + .collect(Collectors.toList())) | |
444 | + .setHasNextPage(result.hasNext()) | |
445 | + .build(); | |
446 | + | |
447 | + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder() | |
448 | + .setSnmpDevicesResponseMsg(responseMsg) | |
449 | + .build()); | |
450 | + } | |
451 | + | |
395 | 452 | private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { |
396 | 453 | return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> { |
397 | 454 | if (device == null) { | ... | ... |
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | </appender> |
27 | 27 | |
28 | 28 | <logger name="org.thingsboard.server" level="INFO" /> |
29 | + <logger name="org.thingsboard.server.transport.snmp" level="TRACE" /> | |
29 | 30 | |
30 | 31 | <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> |
31 | 32 | <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> | ... | ... |
... | ... | @@ -686,6 +686,13 @@ transport: |
686 | 686 | alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}" |
687 | 687 | # Use redis for Security and Registration stores |
688 | 688 | redis.enabled: "${LWM2M_REDIS_ENABLED:false}" |
689 | + snmp: | |
690 | + enabled: "${SNMP_ENABLED:true}" | |
691 | + response_processing: | |
692 | + # parallelism level for executor (workStealingPool) that is responsible for handling responses from SNMP devices | |
693 | + parallelism_level: "${SNMP_RESPONSE_PROCESSING_PARALLELISM_LEVEL:20}" | |
694 | + # to configure SNMP to work over UDP or TCP | |
695 | + underlying_protocol: "${SNMP_UNDERLYING_PROTOCOL:udp}" | |
689 | 696 | |
690 | 697 | # Edges parameters |
691 | 698 | edges: | ... | ... |
... | ... | @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.Device; |
20 | 20 | import org.thingsboard.server.common.data.DeviceInfo; |
21 | 21 | import org.thingsboard.server.common.data.DeviceProfile; |
22 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
22 | 23 | import org.thingsboard.server.common.data.EntitySubtype; |
23 | 24 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
24 | 25 | import org.thingsboard.server.common.data.id.CustomerId; |
... | ... | @@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; |
32 | 33 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
33 | 34 | |
34 | 35 | import java.util.List; |
36 | +import java.util.UUID; | |
35 | 37 | |
36 | 38 | public interface DeviceService { |
37 | 39 | |
... | ... | @@ -93,6 +95,8 @@ public interface DeviceService { |
93 | 95 | |
94 | 96 | Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile); |
95 | 97 | |
98 | + PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink); | |
99 | + | |
96 | 100 | Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); |
97 | 101 | |
98 | 102 | Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); | ... | ... |
... | ... | @@ -87,6 +87,10 @@ |
87 | 87 | <groupId>org.thingsboard</groupId> |
88 | 88 | <artifactId>protobuf-dynamic</artifactId> |
89 | 89 | </dependency> |
90 | + <dependency> | |
91 | + <groupId>org.apache.commons</groupId> | |
92 | + <artifactId>commons-lang3</artifactId> | |
93 | + </dependency> | |
90 | 94 | </dependencies> |
91 | 95 | |
92 | 96 | <build> | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data; | |
17 | + | |
18 | +public interface TbTransportService { | |
19 | + String getName(); | |
20 | +} | ... | ... |
... | ... | @@ -21,6 +21,8 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; |
21 | 21 | import com.fasterxml.jackson.annotation.JsonTypeInfo; |
22 | 22 | import org.thingsboard.server.common.data.DeviceTransportType; |
23 | 23 | |
24 | +import java.io.Serializable; | |
25 | + | |
24 | 26 | @JsonIgnoreProperties(ignoreUnknown = true) |
25 | 27 | @JsonTypeInfo( |
26 | 28 | use = JsonTypeInfo.Id.NAME, |
... | ... | @@ -29,11 +31,14 @@ import org.thingsboard.server.common.data.DeviceTransportType; |
29 | 31 | @JsonSubTypes({ |
30 | 32 | @JsonSubTypes.Type(value = DefaultDeviceTransportConfiguration.class, name = "DEFAULT"), |
31 | 33 | @JsonSubTypes.Type(value = MqttDeviceTransportConfiguration.class, name = "MQTT"), |
34 | + @JsonSubTypes.Type(value = CoapDeviceTransportConfiguration.class, name = "COAP"), | |
32 | 35 | @JsonSubTypes.Type(value = Lwm2mDeviceTransportConfiguration.class, name = "LWM2M"), |
33 | - @JsonSubTypes.Type(value = CoapDeviceTransportConfiguration.class, name = "COAP")}) | |
34 | -public interface DeviceTransportConfiguration { | |
35 | - | |
36 | + @JsonSubTypes.Type(value = SnmpDeviceTransportConfiguration.class, name = "SNMP")}) | |
37 | +public interface DeviceTransportConfiguration extends Serializable { | |
36 | 38 | @JsonIgnore |
37 | 39 | DeviceTransportType getType(); |
38 | 40 | |
41 | + default void validate() { | |
42 | + } | |
43 | + | |
39 | 44 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.device.data; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
19 | +import lombok.Data; | |
20 | +import lombok.ToString; | |
21 | +import org.apache.commons.lang3.ObjectUtils; | |
22 | +import org.apache.commons.lang3.StringUtils; | |
23 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
24 | +import org.thingsboard.server.common.data.transport.snmp.AuthenticationProtocol; | |
25 | +import org.thingsboard.server.common.data.transport.snmp.PrivacyProtocol; | |
26 | +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | |
27 | + | |
28 | +import java.util.Objects; | |
29 | + | |
30 | +@Data | |
31 | +@ToString(of = {"host", "port", "protocolVersion"}) | |
32 | +public class SnmpDeviceTransportConfiguration implements DeviceTransportConfiguration { | |
33 | + private String host; | |
34 | + private Integer port; | |
35 | + private SnmpProtocolVersion protocolVersion; | |
36 | + | |
37 | + /* | |
38 | + * For SNMP v1 and v2c | |
39 | + * */ | |
40 | + private String community; | |
41 | + | |
42 | + /* | |
43 | + * For SNMP v3 | |
44 | + * */ | |
45 | + private String username; | |
46 | + private String securityName; | |
47 | + private String contextName; | |
48 | + private AuthenticationProtocol authenticationProtocol; | |
49 | + private String authenticationPassphrase; | |
50 | + private PrivacyProtocol privacyProtocol; | |
51 | + private String privacyPassphrase; | |
52 | + private String engineId; | |
53 | + | |
54 | + @Override | |
55 | + public DeviceTransportType getType() { | |
56 | + return DeviceTransportType.SNMP; | |
57 | + } | |
58 | + | |
59 | + @Override | |
60 | + public void validate() { | |
61 | + if (!isValid()) { | |
62 | + throw new IllegalArgumentException("Transport configuration is not valid"); | |
63 | + } | |
64 | + } | |
65 | + | |
66 | + @JsonIgnore | |
67 | + private boolean isValid() { | |
68 | + boolean isValid = StringUtils.isNotBlank(host) && port != null && protocolVersion != null; | |
69 | + if (isValid) { | |
70 | + switch (protocolVersion) { | |
71 | + case V1: | |
72 | + case V2C: | |
73 | + isValid = StringUtils.isNotEmpty(community); | |
74 | + break; | |
75 | + case V3: | |
76 | + isValid = StringUtils.isNotBlank(username) && StringUtils.isNotBlank(securityName) | |
77 | + && contextName != null && authenticationProtocol != null | |
78 | + && StringUtils.isNotBlank(authenticationPassphrase) | |
79 | + && privacyProtocol != null && privacyPassphrase != null && engineId != null; | |
80 | + break; | |
81 | + } | |
82 | + } | |
83 | + return isValid; | |
84 | + } | |
85 | +} | ... | ... |
... | ... | @@ -29,13 +29,18 @@ import java.io.Serializable; |
29 | 29 | include = JsonTypeInfo.As.PROPERTY, |
30 | 30 | property = "type") |
31 | 31 | @JsonSubTypes({ |
32 | - @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"), | |
33 | - @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"), | |
34 | - @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M"), | |
35 | - @JsonSubTypes.Type(value = CoapDeviceProfileTransportConfiguration.class, name = "COAP")}) | |
32 | + @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"), | |
33 | + @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"), | |
34 | + @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M"), | |
35 | + @JsonSubTypes.Type(value = CoapDeviceProfileTransportConfiguration.class, name = "COAP"), | |
36 | + @JsonSubTypes.Type(value = SnmpDeviceProfileTransportConfiguration.class, name = "SNMP") | |
37 | +}) | |
36 | 38 | public interface DeviceProfileTransportConfiguration extends Serializable { |
37 | 39 | |
38 | 40 | @JsonIgnore |
39 | 41 | DeviceTransportType getType(); |
40 | 42 | |
43 | + default void validate() { | |
44 | + } | |
45 | + | |
41 | 46 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.device.profile; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
19 | +import lombok.Data; | |
20 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
21 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
22 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
23 | + | |
24 | +import java.util.List; | |
25 | + | |
26 | +@Data | |
27 | +public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { | |
28 | + private Integer timeoutMs; | |
29 | + private Integer retries; | |
30 | + private List<SnmpCommunicationConfig> communicationConfigs; | |
31 | + | |
32 | + @Override | |
33 | + public DeviceTransportType getType() { | |
34 | + return DeviceTransportType.SNMP; | |
35 | + } | |
36 | + | |
37 | + @Override | |
38 | + public void validate() { | |
39 | + if (!isValid()) { | |
40 | + throw new IllegalArgumentException("SNMP transport configuration is not valid"); | |
41 | + } | |
42 | + } | |
43 | + | |
44 | + @JsonIgnore | |
45 | + private boolean isValid() { | |
46 | + return timeoutMs != null && timeoutMs >= 0 && retries != null && retries >= 0 | |
47 | + && communicationConfigs != null | |
48 | + && communicationConfigs.stream().allMatch(config -> config != null && config.isValid()) | |
49 | + && communicationConfigs.stream().flatMap(config -> config.getAllMappings().stream()).map(SnmpMapping::getOid) | |
50 | + .distinct().count() == communicationConfigs.stream().mapToInt(config -> config.getAllMappings().size()).sum(); | |
51 | + } | |
52 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp; | |
17 | + | |
18 | +import java.util.Arrays; | |
19 | +import java.util.Optional; | |
20 | + | |
21 | +public enum AuthenticationProtocol { | |
22 | + SHA_1("1.3.6.1.6.3.10.1.1.3"), | |
23 | + SHA_224("1.3.6.1.6.3.10.1.1.4"), | |
24 | + SHA_256("1.3.6.1.6.3.10.1.1.5"), | |
25 | + SHA_384("1.3.6.1.6.3.10.1.1.6"), | |
26 | + SHA_512("1.3.6.1.6.3.10.1.1.7"), | |
27 | + MD5("1.3.6.1.6.3.10.1.1.2"); | |
28 | + | |
29 | + // oids taken from org.snmp4j.security.SecurityProtocol implementations | |
30 | + private final String oid; | |
31 | + | |
32 | + AuthenticationProtocol(String oid) { | |
33 | + this.oid = oid; | |
34 | + } | |
35 | + | |
36 | + public String getOid() { | |
37 | + return oid; | |
38 | + } | |
39 | + | |
40 | + public static Optional<AuthenticationProtocol> forName(String name) { | |
41 | + return Arrays.stream(values()) | |
42 | + .filter(protocol -> protocol.name().equalsIgnoreCase(name)) | |
43 | + .findFirst(); | |
44 | + } | |
45 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/PrivacyProtocol.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp; | |
17 | + | |
18 | +import java.util.Arrays; | |
19 | +import java.util.Optional; | |
20 | + | |
21 | +public enum PrivacyProtocol { | |
22 | + DES("1.3.6.1.6.3.10.1.2.2"), | |
23 | + AES_128("1.3.6.1.6.3.10.1.2.4"), | |
24 | + AES_192("1.3.6.1.4.1.4976.2.2.1.1.1"), | |
25 | + AES_256("1.3.6.1.4.1.4976.2.2.1.1.2"); | |
26 | + | |
27 | + // oids taken from org.snmp4j.security.SecurityProtocol implementations | |
28 | + private final String oid; | |
29 | + | |
30 | + PrivacyProtocol(String oid) { | |
31 | + this.oid = oid; | |
32 | + } | |
33 | + | |
34 | + public String getOid() { | |
35 | + return oid; | |
36 | + } | |
37 | + | |
38 | + public static Optional<PrivacyProtocol> forName(String name) { | |
39 | + return Arrays.stream(values()) | |
40 | + .filter(protocol -> protocol.name().equalsIgnoreCase(name)) | |
41 | + .findFirst(); | |
42 | + } | |
43 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp; | |
17 | + | |
18 | +public enum SnmpCommunicationSpec { | |
19 | + TELEMETRY_QUERYING, | |
20 | + | |
21 | + CLIENT_ATTRIBUTES_QUERYING, | |
22 | + SHARED_ATTRIBUTES_SETTING, | |
23 | + | |
24 | + TO_DEVICE_RPC_REQUEST, | |
25 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMapping.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
19 | +import lombok.AllArgsConstructor; | |
20 | +import lombok.Data; | |
21 | +import lombok.NoArgsConstructor; | |
22 | +import org.apache.commons.lang3.StringUtils; | |
23 | +import org.thingsboard.server.common.data.kv.DataType; | |
24 | + | |
25 | +import java.util.regex.Pattern; | |
26 | + | |
27 | +@Data | |
28 | +@AllArgsConstructor | |
29 | +@NoArgsConstructor | |
30 | +public class SnmpMapping { | |
31 | + private String oid; | |
32 | + private String key; | |
33 | + private DataType dataType; | |
34 | + | |
35 | + private static final Pattern OID_PATTERN = Pattern.compile("^\\.?([0-2])((\\.0)|(\\.[1-9][0-9]*))*$"); | |
36 | + | |
37 | + @JsonIgnore | |
38 | + public boolean isValid() { | |
39 | + return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() && StringUtils.isNotBlank(key); | |
40 | + } | |
41 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMethod.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp; | |
17 | + | |
18 | +public enum SnmpMethod { | |
19 | + GET(-96), | |
20 | + SET(-93); | |
21 | + | |
22 | + // codes taken from org.snmp4j.PDU class | |
23 | + private final int code; | |
24 | + | |
25 | + SnmpMethod(int code) { | |
26 | + this.code = code; | |
27 | + } | |
28 | + | |
29 | + public int getCode() { | |
30 | + return code; | |
31 | + } | |
32 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpProtocolVersion.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp; | |
17 | + | |
18 | +public enum SnmpProtocolVersion { | |
19 | + V1(0), | |
20 | + V2C(1), | |
21 | + V3(3); | |
22 | + | |
23 | + private final int code; | |
24 | + | |
25 | + SnmpProtocolVersion(int code) { | |
26 | + this.code = code; | |
27 | + } | |
28 | + | |
29 | + public int getCode() { | |
30 | + return code; | |
31 | + } | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
20 | + | |
21 | +import java.util.List; | |
22 | + | |
23 | +@Data | |
24 | +public abstract class MultipleMappingsSnmpCommunicationConfig implements SnmpCommunicationConfig { | |
25 | + protected List<SnmpMapping> mappings; | |
26 | + | |
27 | + @Override | |
28 | + public boolean isValid() { | |
29 | + return mappings != null && !mappings.isEmpty() && mappings.stream().allMatch(mapping -> mapping != null && mapping.isValid()); | |
30 | + } | |
31 | + | |
32 | + @Override | |
33 | + public List<SnmpMapping> getAllMappings() { | |
34 | + return mappings; | |
35 | + } | |
36 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import lombok.EqualsAndHashCode; | |
20 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | |
21 | + | |
22 | +@EqualsAndHashCode(callSuper = true) | |
23 | +@Data | |
24 | +public abstract class RepeatingQueryingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { | |
25 | + private Long queryingFrequencyMs; | |
26 | + | |
27 | + @Override | |
28 | + public SnmpMethod getMethod() { | |
29 | + return SnmpMethod.GET; | |
30 | + } | |
31 | + | |
32 | + @Override | |
33 | + public boolean isValid() { | |
34 | + return queryingFrequencyMs != null && queryingFrequencyMs > 0 && super.isValid(); | |
35 | + } | |
36 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | |
17 | + | |
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
19 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | |
20 | +import com.fasterxml.jackson.annotation.JsonSubTypes; | |
21 | +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; | |
22 | +import com.fasterxml.jackson.annotation.JsonTypeInfo; | |
23 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | |
24 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
25 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | |
26 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.ClientAttributesQueryingSnmpCommunicationConfig; | |
27 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.SharedAttributesSettingSnmpCommunicationConfig; | |
28 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.TelemetryQueryingSnmpCommunicationConfig; | |
29 | + | |
30 | +import java.util.List; | |
31 | + | |
32 | +@JsonIgnoreProperties(ignoreUnknown = true) | |
33 | +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "spec") | |
34 | +@JsonSubTypes({ | |
35 | + @Type(value = TelemetryQueryingSnmpCommunicationConfig.class, name = "TELEMETRY_QUERYING"), | |
36 | + @Type(value = ClientAttributesQueryingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_QUERYING"), | |
37 | + @Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING") | |
38 | +}) | |
39 | +public interface SnmpCommunicationConfig { | |
40 | + | |
41 | + SnmpCommunicationSpec getSpec(); | |
42 | + | |
43 | + @JsonIgnore | |
44 | + default SnmpMethod getMethod() { | |
45 | + return null; | |
46 | + } | |
47 | + | |
48 | + @JsonIgnore | |
49 | + List<SnmpMapping> getAllMappings(); | |
50 | + | |
51 | + @JsonIgnore | |
52 | + boolean isValid(); | |
53 | + | |
54 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | |
17 | + | |
18 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | |
19 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | |
20 | + | |
21 | +public class ClientAttributesQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { | |
22 | + | |
23 | + @Override | |
24 | + public SnmpCommunicationSpec getSpec() { | |
25 | + return SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING; | |
26 | + } | |
27 | + | |
28 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | |
17 | + | |
18 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | |
19 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | |
20 | +import org.thingsboard.server.common.data.transport.snmp.config.MultipleMappingsSnmpCommunicationConfig; | |
21 | + | |
22 | +public class SharedAttributesSettingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { | |
23 | + | |
24 | + @Override | |
25 | + public SnmpCommunicationSpec getSpec() { | |
26 | + return SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING; | |
27 | + } | |
28 | + | |
29 | + @Override | |
30 | + public SnmpMethod getMethod() { | |
31 | + return SnmpMethod.SET; | |
32 | + } | |
33 | + | |
34 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import lombok.EqualsAndHashCode; | |
20 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | |
21 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | |
22 | + | |
23 | +@EqualsAndHashCode(callSuper = true) | |
24 | +@Data | |
25 | +public class TelemetryQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { | |
26 | + | |
27 | + @Override | |
28 | + public SnmpCommunicationSpec getSpec() { | |
29 | + return SnmpCommunicationSpec.TELEMETRY_QUERYING; | |
30 | + } | |
31 | + | |
32 | +} | ... | ... |
... | ... | @@ -19,19 +19,23 @@ import lombok.Getter; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
21 | 21 | import org.springframework.beans.factory.annotation.Value; |
22 | +import org.springframework.context.ApplicationContext; | |
22 | 23 | import org.springframework.stereotype.Component; |
23 | 24 | import org.springframework.util.StringUtils; |
25 | +import org.thingsboard.server.common.data.TbTransportService; | |
24 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
25 | 27 | import org.thingsboard.server.common.msg.queue.ServiceType; |
26 | 28 | import org.thingsboard.server.gen.transport.TransportProtos; |
27 | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; |
28 | 30 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
29 | 31 | import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; |
32 | +import org.thingsboard.server.queue.util.AfterContextReady; | |
30 | 33 | |
31 | 34 | import javax.annotation.PostConstruct; |
32 | 35 | import java.net.InetAddress; |
33 | 36 | import java.net.UnknownHostException; |
34 | 37 | import java.util.Arrays; |
38 | +import java.util.Collection; | |
35 | 39 | import java.util.Collections; |
36 | 40 | import java.util.List; |
37 | 41 | import java.util.Optional; |
... | ... | @@ -56,6 +60,8 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { |
56 | 60 | |
57 | 61 | @Autowired(required = false) |
58 | 62 | private TbQueueRuleEngineSettings ruleEngineSettings; |
63 | + @Autowired | |
64 | + private ApplicationContext applicationContext; | |
59 | 65 | |
60 | 66 | private List<ServiceType> serviceTypes; |
61 | 67 | private ServiceInfo serviceInfo; |
... | ... | @@ -102,6 +108,19 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { |
102 | 108 | serviceInfo = builder.build(); |
103 | 109 | } |
104 | 110 | |
111 | + @AfterContextReady | |
112 | + public void setTransports() { | |
113 | + serviceInfo = ServiceInfo.newBuilder(serviceInfo) | |
114 | + .addAllTransports(getTransportServices().stream() | |
115 | + .map(TbTransportService::getName) | |
116 | + .collect(Collectors.toSet())) | |
117 | + .build(); | |
118 | + } | |
119 | + | |
120 | + private Collection<TbTransportService> getTransportServices() { | |
121 | + return applicationContext.getBeansOfType(TbTransportService.class).values(); | |
122 | + } | |
123 | + | |
105 | 124 | @Override |
106 | 125 | public ServiceInfo getServiceInfo() { |
107 | 126 | return serviceInfo; | ... | ... |
... | ... | @@ -15,26 +15,27 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.queue.discovery; |
17 | 17 | |
18 | -import com.google.common.hash.HashCode; | |
19 | 18 | import com.google.common.hash.HashFunction; |
19 | +import com.google.common.hash.Hasher; | |
20 | 20 | import com.google.common.hash.Hashing; |
21 | -import lombok.Getter; | |
22 | 21 | import lombok.extern.slf4j.Slf4j; |
23 | 22 | import org.springframework.beans.factory.annotation.Value; |
24 | 23 | import org.springframework.context.ApplicationEventPublisher; |
25 | 24 | import org.springframework.stereotype.Service; |
26 | 25 | import org.thingsboard.server.common.data.id.EntityId; |
27 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
28 | -import org.thingsboard.server.common.msg.queue.ServiceQueueKey; | |
29 | 27 | import org.thingsboard.server.common.msg.queue.ServiceQueue; |
28 | +import org.thingsboard.server.common.msg.queue.ServiceQueueKey; | |
30 | 29 | import org.thingsboard.server.common.msg.queue.ServiceType; |
31 | 30 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
32 | 31 | import org.thingsboard.server.gen.transport.TransportProtos; |
33 | 32 | import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; |
33 | +import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; | |
34 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
35 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | |
34 | 36 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
35 | 37 | |
36 | 38 | import javax.annotation.PostConstruct; |
37 | -import java.nio.charset.StandardCharsets; | |
38 | 39 | import java.util.ArrayList; |
39 | 40 | import java.util.Collections; |
40 | 41 | import java.util.Comparator; |
... | ... | @@ -46,7 +47,6 @@ import java.util.Set; |
46 | 47 | import java.util.UUID; |
47 | 48 | import java.util.concurrent.ConcurrentHashMap; |
48 | 49 | import java.util.concurrent.ConcurrentMap; |
49 | -import java.util.concurrent.ConcurrentNavigableMap; | |
50 | 50 | import java.util.stream.Collectors; |
51 | 51 | |
52 | 52 | @Service |
... | ... | @@ -186,6 +186,8 @@ public class HashPartitionService implements PartitionService { |
186 | 186 | applicationEventPublisher.publishEvent(new ClusterTopologyChangeEvent(this, changes)); |
187 | 187 | } |
188 | 188 | } |
189 | + | |
190 | + applicationEventPublisher.publishEvent(new ServiceListChangedEvent(otherServices, currentService)); | |
189 | 191 | } |
190 | 192 | |
191 | 193 | @Override |
... | ... | @@ -219,6 +221,14 @@ public class HashPartitionService implements PartitionService { |
219 | 221 | } |
220 | 222 | } |
221 | 223 | |
224 | + @Override | |
225 | + public int resolvePartitionIndex(UUID entityId, int partitions) { | |
226 | + int hash = hashFunction.newHasher() | |
227 | + .putLong(entityId.getMostSignificantBits()) | |
228 | + .putLong(entityId.getLeastSignificantBits()).hash().asInt(); | |
229 | + return Math.abs(hash % partitions); | |
230 | + } | |
231 | + | |
222 | 232 | private Map<ServiceQueueKey, List<ServiceInfo>> getServiceKeyListMap(List<ServiceInfo> services) { |
223 | 233 | final Map<ServiceQueueKey, List<ServiceInfo>> currentMap = new HashMap<>(); |
224 | 234 | services.forEach(serviceInfo -> { | ... | ... |
... | ... | @@ -20,9 +20,11 @@ import org.thingsboard.server.common.data.id.TenantId; |
20 | 20 | import org.thingsboard.server.common.msg.queue.ServiceType; |
21 | 21 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
22 | 22 | import org.thingsboard.server.gen.transport.TransportProtos; |
23 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | |
23 | 24 | |
24 | 25 | import java.util.List; |
25 | 26 | import java.util.Set; |
27 | +import java.util.UUID; | |
26 | 28 | |
27 | 29 | /** |
28 | 30 | * Once application is ready or cluster topology changes, this Service will produce {@link PartitionChangeEvent} |
... | ... | @@ -55,4 +57,6 @@ public interface PartitionService { |
55 | 57 | * @return |
56 | 58 | */ |
57 | 59 | TopicPartitionInfo getNotificationsTopic(ServiceType serviceType, String serviceId); |
60 | + | |
61 | + int resolvePartitionIndex(UUID entityId, int partitions); | |
58 | 62 | } | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.queue.discovery; |
17 | 17 | |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | 19 | import org.springframework.context.ApplicationListener; |
20 | +import org.thingsboard.server.queue.discovery.event.TbApplicationEvent; | |
20 | 21 | |
21 | 22 | import java.util.concurrent.locks.Lock; |
22 | 23 | import java.util.concurrent.locks.ReentrantLock; | ... | ... |
... | ... | @@ -33,12 +33,14 @@ import org.apache.zookeeper.KeeperException; |
33 | 33 | import org.springframework.beans.factory.annotation.Value; |
34 | 34 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
35 | 35 | import org.springframework.boot.context.event.ApplicationReadyEvent; |
36 | +import org.springframework.context.ApplicationEventPublisher; | |
36 | 37 | import org.springframework.context.event.EventListener; |
37 | 38 | import org.springframework.core.annotation.Order; |
38 | 39 | import org.springframework.stereotype.Service; |
39 | 40 | import org.springframework.util.Assert; |
40 | 41 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
41 | 42 | import org.thingsboard.server.gen.transport.TransportProtos; |
43 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | |
42 | 44 | |
43 | 45 | import javax.annotation.PostConstruct; |
44 | 46 | import javax.annotation.PreDestroy; |
... | ... | @@ -77,7 +79,8 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi |
77 | 79 | |
78 | 80 | private volatile boolean stopped = true; |
79 | 81 | |
80 | - public ZkDiscoveryService(TbServiceInfoProvider serviceInfoProvider, PartitionService partitionService) { | |
82 | + public ZkDiscoveryService(TbServiceInfoProvider serviceInfoProvider, | |
83 | + PartitionService partitionService) { | |
81 | 84 | this.serviceInfoProvider = serviceInfoProvider; |
82 | 85 | this.partitionService = partitionService; |
83 | 86 | } | ... | ... |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ClusterTopologyChangeEvent.java
renamed from
common/queue/src/main/java/org/thingsboard/server/queue/discovery/ClusterTopologyChangeEvent.java
... | ... | @@ -13,10 +13,9 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.queue.discovery; | |
16 | +package org.thingsboard.server.queue.discovery.event; | |
17 | 17 | |
18 | 18 | import lombok.Getter; |
19 | -import org.springframework.context.ApplicationEvent; | |
20 | 19 | import org.thingsboard.server.common.msg.queue.ServiceQueueKey; |
21 | 20 | |
22 | 21 | import java.util.Set; | ... | ... |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java
renamed from
common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionChangeEvent.java
... | ... | @@ -13,10 +13,9 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.queue.discovery; | |
16 | +package org.thingsboard.server.queue.discovery.event; | |
17 | 17 | |
18 | 18 | import lombok.Getter; |
19 | -import org.springframework.context.ApplicationEvent; | |
20 | 19 | import org.thingsboard.server.common.msg.queue.ServiceQueueKey; |
21 | 20 | import org.thingsboard.server.common.msg.queue.ServiceType; |
22 | 21 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ... | ... |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ServiceListChangedEvent.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.queue.discovery.event; | |
17 | + | |
18 | +import lombok.Getter; | |
19 | +import lombok.ToString; | |
20 | +import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; | |
21 | + | |
22 | +import java.util.List; | |
23 | + | |
24 | +@Getter | |
25 | +@ToString | |
26 | +public class ServiceListChangedEvent extends TbApplicationEvent { | |
27 | + private final List<ServiceInfo> otherServices; | |
28 | + private final ServiceInfo currentService; | |
29 | + | |
30 | + public ServiceListChangedEvent(List<ServiceInfo> otherServices, ServiceInfo currentService) { | |
31 | + super(otherServices); | |
32 | + this.otherServices = otherServices; | |
33 | + this.currentService = currentService; | |
34 | + } | |
35 | +} | ... | ... |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/TbApplicationEvent.java
renamed from
common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbApplicationEvent.java
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.queue.discovery; | |
16 | +package org.thingsboard.server.queue.discovery.event; | |
17 | 17 | |
18 | 18 | import lombok.Getter; |
19 | 19 | import org.springframework.context.ApplicationEvent; | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.queue.util; | |
17 | + | |
18 | +import org.springframework.context.event.ContextRefreshedEvent; | |
19 | +import org.springframework.context.event.EventListener; | |
20 | +import org.springframework.core.annotation.AliasFor; | |
21 | +import org.springframework.core.annotation.Order; | |
22 | + | |
23 | +import java.lang.annotation.ElementType; | |
24 | +import java.lang.annotation.Retention; | |
25 | +import java.lang.annotation.RetentionPolicy; | |
26 | +import java.lang.annotation.Target; | |
27 | + | |
28 | +@Retention(RetentionPolicy.RUNTIME) | |
29 | +@Target(ElementType.METHOD) | |
30 | +@EventListener(ContextRefreshedEvent.class) | |
31 | +@Order | |
32 | +public @interface AfterContextReady { | |
33 | + @AliasFor(annotation = Order.class, attribute = "value") | |
34 | + int order() default Integer.MAX_VALUE; | |
35 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.queue.util; | |
17 | + | |
18 | +import org.springframework.boot.context.event.ApplicationReadyEvent; | |
19 | +import org.springframework.context.event.EventListener; | |
20 | +import org.springframework.core.annotation.AliasFor; | |
21 | +import org.springframework.core.annotation.Order; | |
22 | + | |
23 | +import java.lang.annotation.ElementType; | |
24 | +import java.lang.annotation.Retention; | |
25 | +import java.lang.annotation.RetentionPolicy; | |
26 | +import java.lang.annotation.Target; | |
27 | + | |
28 | +@Retention(RetentionPolicy.RUNTIME) | |
29 | +@Target(ElementType.METHOD) | |
30 | +@EventListener(ApplicationReadyEvent.class) | |
31 | +@Order | |
32 | +public @interface AfterStartUp { | |
33 | + @AliasFor(annotation = Order.class, attribute = "value") | |
34 | + int order() default Integer.MAX_VALUE; | |
35 | +} | ... | ... |
common/queue/src/main/java/org/thingsboard/server/queue/util/TbSnmpTransportComponent.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.queue.util; | |
17 | + | |
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | |
19 | + | |
20 | +import java.lang.annotation.ElementType; | |
21 | +import java.lang.annotation.Retention; | |
22 | +import java.lang.annotation.RetentionPolicy; | |
23 | +import java.lang.annotation.Target; | |
24 | + | |
25 | +@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.snmp.enabled}'=='true')") | |
26 | +@Retention(RetentionPolicy.RUNTIME) | |
27 | +@Target({ElementType.TYPE, ElementType.METHOD}) | |
28 | +public @interface TbSnmpTransportComponent { | |
29 | +} | ... | ... |
... | ... | @@ -34,6 +34,7 @@ message ServiceInfo { |
34 | 34 | int64 tenantIdMSB = 3; |
35 | 35 | int64 tenantIdLSB = 4; |
36 | 36 | repeated QueueInfo ruleEngineQueues = 5; |
37 | + repeated string transports = 6; | |
37 | 38 | } |
38 | 39 | |
39 | 40 | /** |
... | ... | @@ -246,6 +247,36 @@ message GetEntityProfileResponseMsg { |
246 | 247 | bytes apiState = 3; |
247 | 248 | } |
248 | 249 | |
250 | +message GetDeviceRequestMsg { | |
251 | + int64 deviceIdMSB = 1; | |
252 | + int64 deviceIdLSB = 2; | |
253 | +} | |
254 | + | |
255 | +message GetDeviceResponseMsg { | |
256 | + int64 deviceProfileIdMSB = 1; | |
257 | + int64 deviceProfileIdLSB = 2; | |
258 | + bytes deviceTransportConfiguration = 3; | |
259 | +} | |
260 | + | |
261 | +message GetDeviceCredentialsRequestMsg { | |
262 | + int64 deviceIdMSB = 1; | |
263 | + int64 deviceIdLSB = 2; | |
264 | +} | |
265 | + | |
266 | +message GetDeviceCredentialsResponseMsg { | |
267 | + bytes deviceCredentialsData = 1; | |
268 | +} | |
269 | + | |
270 | +message GetSnmpDevicesRequestMsg { | |
271 | + int32 page = 1; | |
272 | + int32 pageSize = 2; | |
273 | +} | |
274 | + | |
275 | +message GetSnmpDevicesResponseMsg { | |
276 | + repeated string ids = 1; | |
277 | + bool hasNextPage = 2; | |
278 | +} | |
279 | + | |
249 | 280 | message EntityUpdateMsg { |
250 | 281 | string entityType = 1; |
251 | 282 | bytes data = 2; |
... | ... | @@ -590,6 +621,9 @@ message TransportApiRequestMsg { |
590 | 621 | ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; |
591 | 622 | GetResourceRequestMsg resourceRequestMsg = 9; |
592 | 623 | GetFirmwareRequestMsg firmwareRequestMsg = 10; |
624 | + GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11; | |
625 | + GetDeviceRequestMsg deviceRequestMsg = 12; | |
626 | + GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13; | |
593 | 627 | } |
594 | 628 | |
595 | 629 | /* Response from ThingsBoard Core Service to Transport Service */ |
... | ... | @@ -598,9 +632,12 @@ message TransportApiResponseMsg { |
598 | 632 | GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; |
599 | 633 | GetEntityProfileResponseMsg entityProfileResponseMsg = 3; |
600 | 634 | ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; |
635 | + GetSnmpDevicesResponseMsg snmpDevicesResponseMsg = 5; | |
601 | 636 | LwM2MResponseMsg lwM2MResponseMsg = 6; |
602 | 637 | GetResourceResponseMsg resourceResponseMsg = 7; |
603 | 638 | GetFirmwareResponseMsg firmwareResponseMsg = 8; |
639 | + GetDeviceResponseMsg deviceResponseMsg = 9; | |
640 | + GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 10; | |
604 | 641 | } |
605 | 642 | |
606 | 643 | /* Messages that are handled by ThingsBoard Core Service */ | ... | ... |
... | ... | @@ -21,6 +21,7 @@ import org.eclipse.californium.core.CoapServer; |
21 | 21 | import org.springframework.beans.factory.annotation.Autowired; |
22 | 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
23 | 23 | import org.springframework.stereotype.Service; |
24 | +import org.thingsboard.server.common.data.TbTransportService; | |
24 | 25 | import org.thingsboard.server.coapserver.CoapServerService; |
25 | 26 | import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource; |
26 | 27 | |
... | ... | @@ -31,7 +32,7 @@ import java.net.UnknownHostException; |
31 | 32 | @Service("CoapTransportService") |
32 | 33 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')") |
33 | 34 | @Slf4j |
34 | -public class CoapTransportService { | |
35 | +public class CoapTransportService implements TbTransportService { | |
35 | 36 | |
36 | 37 | private static final String V1 = "v1"; |
37 | 38 | private static final String API = "api"; |
... | ... | @@ -65,4 +66,9 @@ public class CoapTransportService { |
65 | 66 | public void shutdown() { |
66 | 67 | log.info("CoAP transport stopped!"); |
67 | 68 | } |
69 | + | |
70 | + @Override | |
71 | + public String getName() { | |
72 | + return "COAP"; | |
73 | + } | |
68 | 74 | } | ... | ... |
... | ... | @@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestParam; |
34 | 34 | import org.springframework.web.bind.annotation.RestController; |
35 | 35 | import org.springframework.web.context.request.async.DeferredResult; |
36 | 36 | import org.thingsboard.server.common.data.DeviceTransportType; |
37 | +import org.thingsboard.server.common.data.TbTransportService; | |
37 | 38 | import org.thingsboard.server.common.data.id.DeviceId; |
38 | 39 | import org.thingsboard.server.common.transport.SessionMsgListener; |
39 | 40 | import org.thingsboard.server.common.transport.TransportContext; |
... | ... | @@ -70,7 +71,7 @@ import java.util.function.Consumer; |
70 | 71 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.http.enabled}'=='true')") |
71 | 72 | @RequestMapping("/api/v1") |
72 | 73 | @Slf4j |
73 | -public class DeviceApiController { | |
74 | +public class DeviceApiController implements TbTransportService { | |
74 | 75 | |
75 | 76 | @Autowired |
76 | 77 | private HttpTransportContext transportContext; |
... | ... | @@ -407,4 +408,9 @@ public class DeviceApiController { |
407 | 408 | } |
408 | 409 | } |
409 | 410 | |
411 | + @Override | |
412 | + public String getName() { | |
413 | + return "HTTP"; | |
414 | + } | |
415 | + | |
410 | 416 | } | ... | ... |
... | ... | @@ -20,13 +20,14 @@ import org.eclipse.leshan.core.response.ReadResponse; |
20 | 20 | import org.eclipse.leshan.server.registration.Registration; |
21 | 21 | import org.thingsboard.server.common.data.Device; |
22 | 22 | import org.thingsboard.server.common.data.DeviceProfile; |
23 | +import org.thingsboard.server.common.data.TbTransportService; | |
23 | 24 | import org.thingsboard.server.gen.transport.TransportProtos; |
24 | 25 | import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; |
25 | 26 | |
26 | 27 | import java.util.Collection; |
27 | 28 | import java.util.Optional; |
28 | 29 | |
29 | -public interface LwM2mTransportService { | |
30 | +public interface LwM2mTransportService extends TbTransportService { | |
30 | 31 | |
31 | 32 | void onRegistered(Registration registration, Collection<Observation> previousObsersations); |
32 | 33 | ... | ... |
... | ... | @@ -40,6 +40,7 @@ import org.springframework.stereotype.Service; |
40 | 40 | import org.thingsboard.common.util.JacksonUtil; |
41 | 41 | import org.thingsboard.server.common.data.Device; |
42 | 42 | import org.thingsboard.server.common.data.DeviceProfile; |
43 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
43 | 44 | import org.thingsboard.server.common.transport.TransportService; |
44 | 45 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
45 | 46 | import org.thingsboard.server.common.transport.service.DefaultTransportService; |
... | ... | @@ -1353,4 +1354,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1353 | 1354 | objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : |
1354 | 1355 | objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId))); |
1355 | 1356 | } |
1357 | + | |
1358 | + @Override | |
1359 | + public String getName() { | |
1360 | + return "LWM2M"; | |
1361 | + } | |
1362 | + | |
1356 | 1363 | } | ... | ... |
... | ... | @@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value; |
28 | 28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
29 | 29 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
30 | 30 | import org.springframework.stereotype.Service; |
31 | +import org.thingsboard.server.common.data.TbTransportService; | |
31 | 32 | |
32 | 33 | import javax.annotation.PostConstruct; |
33 | 34 | import javax.annotation.PreDestroy; |
... | ... | @@ -38,7 +39,7 @@ import javax.annotation.PreDestroy; |
38 | 39 | @Service("MqttTransportService") |
39 | 40 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled}'=='true')") |
40 | 41 | @Slf4j |
41 | -public class MqttTransportService { | |
42 | +public class MqttTransportService implements TbTransportService { | |
42 | 43 | |
43 | 44 | @Value("${transport.mqtt.bind_address}") |
44 | 45 | private String host; |
... | ... | @@ -90,4 +91,9 @@ public class MqttTransportService { |
90 | 91 | } |
91 | 92 | log.info("MQTT transport stopped!"); |
92 | 93 | } |
94 | + | |
95 | + @Override | |
96 | + public String getName() { | |
97 | + return "MQTT"; | |
98 | + } | |
93 | 99 | } | ... | ... |
common/transport/snmp/pom.xml
0 → 100644
1 | +<!-- | |
2 | + | |
3 | + Copyright © 2016-2021 The Thingsboard Authors | |
4 | + | |
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | + you may not use this file except in compliance with the License. | |
7 | + You may obtain a copy of the License at | |
8 | + | |
9 | + http://www.apache.org/licenses/LICENSE-2.0 | |
10 | + | |
11 | + Unless required by applicable law or agreed to in writing, software | |
12 | + distributed under the License is distributed on an "AS IS" BASIS, | |
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | + See the License for the specific language governing permissions and | |
15 | + limitations under the License. | |
16 | + | |
17 | +--> | |
18 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
19 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
20 | + <modelVersion>4.0.0</modelVersion> | |
21 | + | |
22 | + <parent> | |
23 | + <groupId>org.thingsboard.common</groupId> | |
24 | + <version>3.3.0-SNAPSHOT</version> | |
25 | + <artifactId>transport</artifactId> | |
26 | + </parent> | |
27 | + | |
28 | + <groupId>org.thingsboard.common.transport</groupId> | |
29 | + <artifactId>snmp</artifactId> | |
30 | + <packaging>jar</packaging> | |
31 | + | |
32 | + <name>Thingsboard SNMP Transport Common</name> | |
33 | + <url>https://thingsboard.io</url> | |
34 | + | |
35 | + <properties> | |
36 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |
37 | + <main.dir>${basedir}/../../..</main.dir> | |
38 | + </properties> | |
39 | + | |
40 | + <dependencies> | |
41 | + <dependency> | |
42 | + <groupId>org.thingsboard.common.transport</groupId> | |
43 | + <artifactId>transport-api</artifactId> | |
44 | + </dependency> | |
45 | + <dependency> | |
46 | + <groupId>org.springframework</groupId> | |
47 | + <artifactId>spring-context-support</artifactId> | |
48 | + </dependency> | |
49 | + <dependency> | |
50 | + <groupId>org.springframework</groupId> | |
51 | + <artifactId>spring-context</artifactId> | |
52 | + </dependency> | |
53 | + <dependency> | |
54 | + <groupId>org.slf4j</groupId> | |
55 | + <artifactId>slf4j-api</artifactId> | |
56 | + </dependency> | |
57 | + <dependency> | |
58 | + <groupId>org.snmp4j</groupId> | |
59 | + <artifactId>snmp4j</artifactId> | |
60 | + </dependency> | |
61 | + <dependency> | |
62 | + <groupId>org.snmp4j</groupId> | |
63 | + <artifactId>snmp4j-agent</artifactId> | |
64 | + <version>3.3.6</version> | |
65 | + <scope>test</scope> | |
66 | + </dependency> | |
67 | + </dependencies> | |
68 | +</project> | ... | ... |
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp; | |
17 | + | |
18 | +import lombok.Getter; | |
19 | +import lombok.RequiredArgsConstructor; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.springframework.context.event.EventListener; | |
22 | +import org.springframework.stereotype.Component; | |
23 | +import org.thingsboard.server.common.data.Device; | |
24 | +import org.thingsboard.server.common.data.DeviceProfile; | |
25 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
26 | +import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration; | |
27 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | |
28 | +import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; | |
29 | +import org.thingsboard.server.common.data.id.DeviceId; | |
30 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
31 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | |
32 | +import org.thingsboard.server.common.data.security.DeviceCredentialsType; | |
33 | +import org.thingsboard.server.common.transport.DeviceUpdatedEvent; | |
34 | +import org.thingsboard.server.common.transport.TransportContext; | |
35 | +import org.thingsboard.server.common.transport.TransportDeviceProfileCache; | |
36 | +import org.thingsboard.server.common.transport.TransportService; | |
37 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | |
38 | +import org.thingsboard.server.common.transport.auth.SessionInfoCreator; | |
39 | +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | |
40 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
41 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | |
42 | +import org.thingsboard.server.queue.util.AfterStartUp; | |
43 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
44 | +import org.thingsboard.server.transport.snmp.service.ProtoTransportEntityService; | |
45 | +import org.thingsboard.server.transport.snmp.service.SnmpAuthService; | |
46 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportBalancingService; | |
47 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportService; | |
48 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | |
49 | + | |
50 | +import java.util.Collection; | |
51 | +import java.util.LinkedList; | |
52 | +import java.util.List; | |
53 | +import java.util.Map; | |
54 | +import java.util.Optional; | |
55 | +import java.util.UUID; | |
56 | +import java.util.concurrent.ConcurrentHashMap; | |
57 | +import java.util.concurrent.ConcurrentLinkedDeque; | |
58 | +import java.util.stream.Collectors; | |
59 | + | |
60 | +@TbSnmpTransportComponent | |
61 | +@Component | |
62 | +@Slf4j | |
63 | +@RequiredArgsConstructor | |
64 | +public class SnmpTransportContext extends TransportContext { | |
65 | + @Getter | |
66 | + private final SnmpTransportService snmpTransportService; | |
67 | + private final TransportDeviceProfileCache deviceProfileCache; | |
68 | + private final TransportService transportService; | |
69 | + private final ProtoTransportEntityService protoEntityService; | |
70 | + private final SnmpTransportBalancingService balancingService; | |
71 | + @Getter | |
72 | + private final SnmpAuthService snmpAuthService; | |
73 | + | |
74 | + private final Map<DeviceId, DeviceSessionContext> sessions = new ConcurrentHashMap<>(); | |
75 | + private Collection<DeviceId> allSnmpDevicesIds = new ConcurrentLinkedDeque<>(); | |
76 | + | |
77 | + @AfterStartUp(order = 2) | |
78 | + public void initDevicesSessions() { | |
79 | + log.info("Initializing SNMP devices sessions"); | |
80 | + allSnmpDevicesIds = protoEntityService.getAllSnmpDevicesIds().stream() | |
81 | + .map(DeviceId::new) | |
82 | + .collect(Collectors.toList()); | |
83 | + log.trace("Found all SNMP devices ids: {}", allSnmpDevicesIds); | |
84 | + | |
85 | + List<DeviceId> managedDevicesIds = allSnmpDevicesIds.stream() | |
86 | + .filter(deviceId -> balancingService.isManagedByCurrentTransport(deviceId.getId())) | |
87 | + .collect(Collectors.toList()); | |
88 | + log.info("SNMP devices managed by current SNMP transport: {}", managedDevicesIds); | |
89 | + | |
90 | + managedDevicesIds.stream() | |
91 | + .map(protoEntityService::getDeviceById) | |
92 | + .collect(Collectors.toList()) | |
93 | + .forEach(this::establishDeviceSession); | |
94 | + } | |
95 | + | |
96 | + private void establishDeviceSession(Device device) { | |
97 | + if (device == null) return; | |
98 | + log.info("Establishing SNMP session for device {}", device.getId()); | |
99 | + | |
100 | + DeviceProfileId deviceProfileId = device.getDeviceProfileId(); | |
101 | + DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId); | |
102 | + | |
103 | + DeviceCredentials credentials = protoEntityService.getDeviceCredentialsByDeviceId(device.getId()); | |
104 | + if (credentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { | |
105 | + log.warn("[{}] Expected credentials type is {} but found {}", device.getId(), DeviceCredentialsType.ACCESS_TOKEN, credentials.getCredentialsType()); | |
106 | + return; | |
107 | + } | |
108 | + | |
109 | + SnmpDeviceProfileTransportConfiguration profileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); | |
110 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration(); | |
111 | + | |
112 | + DeviceSessionContext deviceSessionContext; | |
113 | + try { | |
114 | + deviceSessionContext = new DeviceSessionContext( | |
115 | + device, deviceProfile, credentials.getCredentialsId(), | |
116 | + profileTransportConfiguration, deviceTransportConfiguration, this | |
117 | + ); | |
118 | + registerSessionMsgListener(deviceSessionContext); | |
119 | + } catch (Exception e) { | |
120 | + log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.toString()); | |
121 | + return; | |
122 | + } | |
123 | + sessions.put(device.getId(), deviceSessionContext); | |
124 | + snmpTransportService.createQueryingTasks(deviceSessionContext); | |
125 | + log.info("Established SNMP device session for device {}", device.getId()); | |
126 | + } | |
127 | + | |
128 | + private void updateDeviceSession(DeviceSessionContext sessionContext, Device device, DeviceProfile deviceProfile) { | |
129 | + log.info("Updating SNMP session for device {}", device.getId()); | |
130 | + | |
131 | + DeviceCredentials credentials = protoEntityService.getDeviceCredentialsByDeviceId(device.getId()); | |
132 | + if (credentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { | |
133 | + log.warn("[{}] Expected credentials type is {} but found {}", device.getId(), DeviceCredentialsType.ACCESS_TOKEN, credentials.getCredentialsType()); | |
134 | + destroyDeviceSession(sessionContext); | |
135 | + return; | |
136 | + } | |
137 | + | |
138 | + SnmpDeviceProfileTransportConfiguration newProfileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); | |
139 | + SnmpDeviceTransportConfiguration newDeviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration(); | |
140 | + | |
141 | + try { | |
142 | + if (!newProfileTransportConfiguration.equals(sessionContext.getProfileTransportConfiguration())) { | |
143 | + sessionContext.setProfileTransportConfiguration(newProfileTransportConfiguration); | |
144 | + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration); | |
145 | + snmpTransportService.cancelQueryingTasks(sessionContext); | |
146 | + snmpTransportService.createQueryingTasks(sessionContext); | |
147 | + } else if (!newDeviceTransportConfiguration.equals(sessionContext.getDeviceTransportConfiguration())) { | |
148 | + sessionContext.setDeviceTransportConfiguration(newDeviceTransportConfiguration); | |
149 | + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration); | |
150 | + } else { | |
151 | + log.trace("Configuration of the device {} was not updated", device); | |
152 | + } | |
153 | + } catch (Exception e) { | |
154 | + log.error("Failed to update session for SNMP device {}: {}", sessionContext.getDeviceId(), e.getMessage()); | |
155 | + destroyDeviceSession(sessionContext); | |
156 | + } | |
157 | + } | |
158 | + | |
159 | + private void destroyDeviceSession(DeviceSessionContext sessionContext) { | |
160 | + if (sessionContext == null) return; | |
161 | + log.info("Destroying SNMP device session for device {}", sessionContext.getDevice().getId()); | |
162 | + sessionContext.close(); | |
163 | + snmpAuthService.cleanUpSnmpAuthInfo(sessionContext); | |
164 | + transportService.deregisterSession(sessionContext.getSessionInfo()); | |
165 | + snmpTransportService.cancelQueryingTasks(sessionContext); | |
166 | + sessions.remove(sessionContext.getDeviceId()); | |
167 | + log.trace("Unregistered and removed session"); | |
168 | + } | |
169 | + | |
170 | + private void registerSessionMsgListener(DeviceSessionContext deviceSessionContext) { | |
171 | + transportService.process(DeviceTransportType.SNMP, | |
172 | + TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceSessionContext.getToken()).build(), | |
173 | + new TransportServiceCallback<>() { | |
174 | + @Override | |
175 | + public void onSuccess(ValidateDeviceCredentialsResponse msg) { | |
176 | + if (msg.hasDeviceInfo()) { | |
177 | + SessionInfoProto sessionInfo = SessionInfoCreator.create( | |
178 | + msg, SnmpTransportContext.this, UUID.randomUUID() | |
179 | + ); | |
180 | + | |
181 | + transportService.registerAsyncSession(sessionInfo, deviceSessionContext); | |
182 | + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), TransportServiceCallback.EMPTY); | |
183 | + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), TransportServiceCallback.EMPTY); | |
184 | + | |
185 | + deviceSessionContext.setSessionInfo(sessionInfo); | |
186 | + deviceSessionContext.setDeviceInfo(msg.getDeviceInfo()); | |
187 | + } else { | |
188 | + log.warn("[{}] Failed to process device auth", deviceSessionContext.getDeviceId()); | |
189 | + } | |
190 | + } | |
191 | + | |
192 | + @Override | |
193 | + public void onError(Throwable e) { | |
194 | + log.warn("[{}] Failed to process device auth: {}", deviceSessionContext.getDeviceId(), e); | |
195 | + } | |
196 | + }); | |
197 | + } | |
198 | + | |
199 | + @EventListener(DeviceUpdatedEvent.class) | |
200 | + public void onDeviceUpdatedOrCreated(DeviceUpdatedEvent deviceUpdatedEvent) { | |
201 | + Device device = deviceUpdatedEvent.getDevice(); | |
202 | + log.trace("Got creating or updating device event for device {}", device); | |
203 | + DeviceTransportType transportType = Optional.ofNullable(device.getDeviceData().getTransportConfiguration()) | |
204 | + .map(DeviceTransportConfiguration::getType) | |
205 | + .orElse(null); | |
206 | + if (!allSnmpDevicesIds.contains(device.getId())) { | |
207 | + if (transportType != DeviceTransportType.SNMP) { | |
208 | + return; | |
209 | + } | |
210 | + allSnmpDevicesIds.add(device.getId()); | |
211 | + if (balancingService.isManagedByCurrentTransport(device.getId().getId())) { | |
212 | + establishDeviceSession(device); | |
213 | + } | |
214 | + } else { | |
215 | + if (balancingService.isManagedByCurrentTransport(device.getId().getId())) { | |
216 | + DeviceSessionContext sessionContext = sessions.get(device.getId()); | |
217 | + if (transportType == DeviceTransportType.SNMP) { | |
218 | + if (sessionContext != null) { | |
219 | + updateDeviceSession(sessionContext, device, deviceProfileCache.get(device.getDeviceProfileId())); | |
220 | + } else { | |
221 | + establishDeviceSession(device); | |
222 | + } | |
223 | + } else { | |
224 | + log.trace("Transport type was changed to {}", transportType); | |
225 | + destroyDeviceSession(sessionContext); | |
226 | + } | |
227 | + } | |
228 | + } | |
229 | + } | |
230 | + | |
231 | + public void onDeviceDeleted(DeviceSessionContext sessionContext) { | |
232 | + destroyDeviceSession(sessionContext); | |
233 | + } | |
234 | + | |
235 | + public void onDeviceProfileUpdated(DeviceProfile deviceProfile, DeviceSessionContext sessionContext) { | |
236 | + updateDeviceSession(sessionContext, sessionContext.getDevice(), deviceProfile); | |
237 | + } | |
238 | + | |
239 | + public void onSnmpTransportListChanged() { | |
240 | + log.trace("SNMP transport list changed. Updating sessions"); | |
241 | + List<DeviceId> deleted = new LinkedList<>(); | |
242 | + for (DeviceId deviceId : allSnmpDevicesIds) { | |
243 | + if (balancingService.isManagedByCurrentTransport(deviceId.getId())) { | |
244 | + if (!sessions.containsKey(deviceId)) { | |
245 | + Device device = protoEntityService.getDeviceById(deviceId); | |
246 | + if (device != null) { | |
247 | + log.info("SNMP device {} is now managed by current transport node", deviceId); | |
248 | + establishDeviceSession(device); | |
249 | + } else { | |
250 | + deleted.add(deviceId); | |
251 | + } | |
252 | + } | |
253 | + } else { | |
254 | + Optional.ofNullable(sessions.get(deviceId)) | |
255 | + .ifPresent(sessionContext -> { | |
256 | + log.info("SNMP session for device {} is not managed by current transport node anymore", deviceId); | |
257 | + destroyDeviceSession(sessionContext); | |
258 | + }); | |
259 | + } | |
260 | + } | |
261 | + log.trace("Removing deleted SNMP devices: {}", deleted); | |
262 | + allSnmpDevicesIds.removeAll(deleted); | |
263 | + } | |
264 | + | |
265 | + | |
266 | + public Collection<DeviceSessionContext> getSessions() { | |
267 | + return sessions.values(); | |
268 | + } | |
269 | + | |
270 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.event; | |
17 | + | |
18 | +import lombok.RequiredArgsConstructor; | |
19 | +import org.springframework.stereotype.Component; | |
20 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
21 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | |
22 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
23 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportBalancingService; | |
24 | + | |
25 | +@TbSnmpTransportComponent | |
26 | +@Component | |
27 | +@RequiredArgsConstructor | |
28 | +public class ServiceListChangedEventListener extends TbApplicationEventListener<ServiceListChangedEvent> { | |
29 | + private final SnmpTransportBalancingService snmpTransportBalancingService; | |
30 | + | |
31 | + @Override | |
32 | + protected void onTbApplicationEvent(ServiceListChangedEvent event) { | |
33 | + snmpTransportBalancingService.onServiceListChanged(event); | |
34 | + } | |
35 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.event; | |
17 | + | |
18 | +import org.thingsboard.server.queue.discovery.event.TbApplicationEvent; | |
19 | + | |
20 | +public class SnmpTransportListChangedEvent extends TbApplicationEvent { | |
21 | + public SnmpTransportListChangedEvent() { | |
22 | + super(new Object()); | |
23 | + } | |
24 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.event; | |
17 | + | |
18 | +import lombok.RequiredArgsConstructor; | |
19 | +import org.springframework.stereotype.Component; | |
20 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | |
21 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
22 | +import org.thingsboard.server.transport.snmp.SnmpTransportContext; | |
23 | + | |
24 | +@TbSnmpTransportComponent | |
25 | +@Component | |
26 | +@RequiredArgsConstructor | |
27 | +public class SnmpTransportListChangedEventListener extends TbApplicationEventListener<SnmpTransportListChangedEvent> { | |
28 | + private final SnmpTransportContext snmpTransportContext; | |
29 | + | |
30 | + @Override | |
31 | + protected void onTbApplicationEvent(SnmpTransportListChangedEvent event) { | |
32 | + snmpTransportContext.onSnmpTransportListChanged(); | |
33 | + } | |
34 | +} | ... | ... |
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/PduService.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.service; | |
17 | + | |
18 | +import com.google.gson.JsonObject; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.snmp4j.PDU; | |
21 | +import org.snmp4j.ScopedPDU; | |
22 | +import org.snmp4j.smi.Integer32; | |
23 | +import org.snmp4j.smi.Null; | |
24 | +import org.snmp4j.smi.OID; | |
25 | +import org.snmp4j.smi.OctetString; | |
26 | +import org.snmp4j.smi.Variable; | |
27 | +import org.snmp4j.smi.VariableBinding; | |
28 | +import org.springframework.stereotype.Service; | |
29 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | |
30 | +import org.thingsboard.server.common.data.kv.DataType; | |
31 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
32 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | |
33 | +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | |
34 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
35 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
36 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | |
37 | + | |
38 | +import java.util.HashMap; | |
39 | +import java.util.List; | |
40 | +import java.util.Map; | |
41 | +import java.util.Objects; | |
42 | +import java.util.Optional; | |
43 | +import java.util.stream.Collectors; | |
44 | +import java.util.stream.IntStream; | |
45 | + | |
46 | +@TbSnmpTransportComponent | |
47 | +@Service | |
48 | +@Slf4j | |
49 | +public class PduService { | |
50 | + public PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) { | |
51 | + PDU pdu = setUpPdu(sessionContext); | |
52 | + | |
53 | + pdu.setType(communicationConfig.getMethod().getCode()); | |
54 | + pdu.addAll(communicationConfig.getAllMappings().stream() | |
55 | + .filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey())) | |
56 | + .map(mapping -> Optional.ofNullable(values.get(mapping.getKey())) | |
57 | + .map(value -> { | |
58 | + Variable variable = toSnmpVariable(value, mapping.getDataType()); | |
59 | + return new VariableBinding(new OID(mapping.getOid()), variable); | |
60 | + }) | |
61 | + .orElseGet(() -> new VariableBinding(new OID(mapping.getOid())))) | |
62 | + .collect(Collectors.toList())); | |
63 | + | |
64 | + return pdu; | |
65 | + } | |
66 | + | |
67 | + public PDU createSingleVariablePdu(DeviceSessionContext sessionContext, SnmpMethod snmpMethod, String oid, String value, DataType dataType) { | |
68 | + PDU pdu = setUpPdu(sessionContext); | |
69 | + pdu.setType(snmpMethod.getCode()); | |
70 | + | |
71 | + Variable variable = value == null ? Null.instance : toSnmpVariable(value, dataType); | |
72 | + pdu.add(new VariableBinding(new OID(oid), variable)); | |
73 | + | |
74 | + return pdu; | |
75 | + } | |
76 | + | |
77 | + private Variable toSnmpVariable(String value, DataType dataType) { | |
78 | + dataType = dataType == null ? DataType.STRING : dataType; | |
79 | + Variable variable; | |
80 | + switch (dataType) { | |
81 | + case LONG: | |
82 | + try { | |
83 | + variable = new Integer32(Integer.parseInt(value)); | |
84 | + break; | |
85 | + } catch (NumberFormatException ignored) { | |
86 | + } | |
87 | + case DOUBLE: | |
88 | + case BOOLEAN: | |
89 | + case STRING: | |
90 | + case JSON: | |
91 | + default: | |
92 | + variable = new OctetString(value); | |
93 | + } | |
94 | + return variable; | |
95 | + } | |
96 | + | |
97 | + private PDU setUpPdu(DeviceSessionContext sessionContext) { | |
98 | + PDU pdu; | |
99 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); | |
100 | + SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion(); | |
101 | + switch (snmpVersion) { | |
102 | + case V1: | |
103 | + case V2C: | |
104 | + pdu = new PDU(); | |
105 | + break; | |
106 | + case V3: | |
107 | + ScopedPDU scopedPdu = new ScopedPDU(); | |
108 | + scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName())); | |
109 | + scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId())); | |
110 | + pdu = scopedPdu; | |
111 | + break; | |
112 | + default: | |
113 | + throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported"); | |
114 | + } | |
115 | + return pdu; | |
116 | + } | |
117 | + | |
118 | + | |
119 | + public JsonObject processPdu(PDU pdu, List<SnmpMapping> responseMappings) { | |
120 | + Map<OID, String> values = processPdu(pdu); | |
121 | + | |
122 | + Map<OID, SnmpMapping> mappings = new HashMap<>(); | |
123 | + if (responseMappings != null) { | |
124 | + for (SnmpMapping mapping : responseMappings) { | |
125 | + OID oid = new OID(mapping.getOid()); | |
126 | + mappings.put(oid, mapping); | |
127 | + } | |
128 | + } | |
129 | + | |
130 | + JsonObject data = new JsonObject(); | |
131 | + values.forEach((oid, value) -> { | |
132 | + log.trace("Processing variable binding: {} - {}", oid, value); | |
133 | + | |
134 | + SnmpMapping mapping = mappings.get(oid); | |
135 | + if (mapping == null) { | |
136 | + log.debug("No SNMP mapping for oid {}", oid); | |
137 | + return; | |
138 | + } | |
139 | + | |
140 | + processValue(mapping.getKey(), mapping.getDataType(), value, data); | |
141 | + }); | |
142 | + | |
143 | + return data; | |
144 | + } | |
145 | + | |
146 | + public Map<OID, String> processPdu(PDU pdu) { | |
147 | + return IntStream.range(0, pdu.size()) | |
148 | + .mapToObj(pdu::get) | |
149 | + .filter(Objects::nonNull) | |
150 | + .filter(variableBinding -> !(variableBinding.getVariable() instanceof Null)) | |
151 | + .collect(Collectors.toMap(VariableBinding::getOid, VariableBinding::toValueString)); | |
152 | + } | |
153 | + | |
154 | + private void processValue(String key, DataType dataType, String value, JsonObject result) { | |
155 | + switch (dataType) { | |
156 | + case LONG: | |
157 | + result.addProperty(key, Long.parseLong(value)); | |
158 | + break; | |
159 | + case BOOLEAN: | |
160 | + result.addProperty(key, Boolean.parseBoolean(value)); | |
161 | + break; | |
162 | + case DOUBLE: | |
163 | + result.addProperty(key, Double.parseDouble(value)); | |
164 | + break; | |
165 | + case STRING: | |
166 | + case JSON: | |
167 | + default: | |
168 | + result.addProperty(key, value); | |
169 | + } | |
170 | + } | |
171 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.service; | |
17 | + | |
18 | +import lombok.RequiredArgsConstructor; | |
19 | +import org.springframework.stereotype.Service; | |
20 | +import org.thingsboard.server.common.data.Device; | |
21 | +import org.thingsboard.server.common.data.device.data.DeviceData; | |
22 | +import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration; | |
23 | +import org.thingsboard.server.common.data.id.DeviceId; | |
24 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | |
25 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | |
26 | +import org.thingsboard.server.common.transport.TransportService; | |
27 | +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | |
28 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
29 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
30 | + | |
31 | +import java.util.ArrayList; | |
32 | +import java.util.List; | |
33 | +import java.util.UUID; | |
34 | +import java.util.stream.Collectors; | |
35 | + | |
36 | +@TbSnmpTransportComponent | |
37 | +@Service | |
38 | +@RequiredArgsConstructor | |
39 | +public class ProtoTransportEntityService { | |
40 | + private final TransportService transportService; | |
41 | + private final DataDecodingEncodingService dataDecodingEncodingService; | |
42 | + | |
43 | + public Device getDeviceById(DeviceId id) { | |
44 | + TransportProtos.GetDeviceResponseMsg deviceProto = transportService.getDevice(TransportProtos.GetDeviceRequestMsg.newBuilder() | |
45 | + .setDeviceIdMSB(id.getId().getMostSignificantBits()) | |
46 | + .setDeviceIdLSB(id.getId().getLeastSignificantBits()) | |
47 | + .build()); | |
48 | + | |
49 | + if (deviceProto == null) { | |
50 | + return null; | |
51 | + } | |
52 | + | |
53 | + DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID( | |
54 | + deviceProto.getDeviceProfileIdMSB(), deviceProto.getDeviceProfileIdLSB()) | |
55 | + ); | |
56 | + | |
57 | + Device device = new Device(); | |
58 | + device.setId(id); | |
59 | + device.setDeviceProfileId(deviceProfileId); | |
60 | + | |
61 | + DeviceTransportConfiguration deviceTransportConfiguration = (DeviceTransportConfiguration) dataDecodingEncodingService.decode( | |
62 | + deviceProto.getDeviceTransportConfiguration().toByteArray() | |
63 | + ).orElseThrow(() -> new IllegalStateException("Can't find device transport configuration")); | |
64 | + | |
65 | + DeviceData deviceData = new DeviceData(); | |
66 | + deviceData.setTransportConfiguration(deviceTransportConfiguration); | |
67 | + device.setDeviceData(deviceData); | |
68 | + | |
69 | + return device; | |
70 | + } | |
71 | + | |
72 | + public DeviceCredentials getDeviceCredentialsByDeviceId(DeviceId deviceId) { | |
73 | + TransportProtos.GetDeviceCredentialsResponseMsg deviceCredentialsResponse = transportService.getDeviceCredentials( | |
74 | + TransportProtos.GetDeviceCredentialsRequestMsg.newBuilder() | |
75 | + .setDeviceIdMSB(deviceId.getId().getMostSignificantBits()) | |
76 | + .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) | |
77 | + .build() | |
78 | + ); | |
79 | + | |
80 | + return (DeviceCredentials) dataDecodingEncodingService.decode(deviceCredentialsResponse.getDeviceCredentialsData().toByteArray()) | |
81 | + .orElseThrow(() -> new IllegalArgumentException("Device credentials not found")); | |
82 | + } | |
83 | + | |
84 | + public List<UUID> getAllSnmpDevicesIds() { | |
85 | + List<UUID> result = new ArrayList<>(); | |
86 | + | |
87 | + int page = 0; | |
88 | + int pageSize = 512; | |
89 | + boolean hasNextPage = true; | |
90 | + | |
91 | + while (hasNextPage) { | |
92 | + TransportProtos.GetSnmpDevicesResponseMsg responseMsg = requestSnmpDevicesIds(page, pageSize); | |
93 | + result.addAll(responseMsg.getIdsList().stream() | |
94 | + .map(UUID::fromString) | |
95 | + .collect(Collectors.toList())); | |
96 | + hasNextPage = responseMsg.getHasNextPage(); | |
97 | + page++; | |
98 | + } | |
99 | + | |
100 | + return result; | |
101 | + } | |
102 | + | |
103 | + private TransportProtos.GetSnmpDevicesResponseMsg requestSnmpDevicesIds(int page, int pageSize) { | |
104 | + TransportProtos.GetSnmpDevicesRequestMsg requestMsg = TransportProtos.GetSnmpDevicesRequestMsg.newBuilder() | |
105 | + .setPage(page) | |
106 | + .setPageSize(pageSize) | |
107 | + .build(); | |
108 | + return transportService.getSnmpDevicesIds(requestMsg); | |
109 | + } | |
110 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.service; | |
17 | + | |
18 | +import lombok.RequiredArgsConstructor; | |
19 | +import org.snmp4j.AbstractTarget; | |
20 | +import org.snmp4j.CommunityTarget; | |
21 | +import org.snmp4j.Target; | |
22 | +import org.snmp4j.UserTarget; | |
23 | +import org.snmp4j.security.SecurityLevel; | |
24 | +import org.snmp4j.security.SecurityModel; | |
25 | +import org.snmp4j.security.SecurityProtocols; | |
26 | +import org.snmp4j.security.USM; | |
27 | +import org.snmp4j.smi.Address; | |
28 | +import org.snmp4j.smi.GenericAddress; | |
29 | +import org.snmp4j.smi.OID; | |
30 | +import org.snmp4j.smi.OctetString; | |
31 | +import org.springframework.beans.factory.annotation.Value; | |
32 | +import org.springframework.stereotype.Service; | |
33 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | |
34 | +import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; | |
35 | +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | |
36 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
37 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportService; | |
38 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | |
39 | + | |
40 | +import java.util.Optional; | |
41 | + | |
42 | +@Service | |
43 | +@TbSnmpTransportComponent | |
44 | +@RequiredArgsConstructor | |
45 | +public class SnmpAuthService { | |
46 | + private final SnmpTransportService snmpTransportService; | |
47 | + | |
48 | + @Value("${transport.snmp.underlying_protocol}") | |
49 | + private String snmpUnderlyingProtocol; | |
50 | + | |
51 | + public Target setUpSnmpTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) { | |
52 | + AbstractTarget target; | |
53 | + | |
54 | + SnmpProtocolVersion protocolVersion = deviceTransportConfig.getProtocolVersion(); | |
55 | + switch (protocolVersion) { | |
56 | + case V1: | |
57 | + CommunityTarget communityTargetV1 = new CommunityTarget(); | |
58 | + communityTargetV1.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv1); | |
59 | + communityTargetV1.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV); | |
60 | + communityTargetV1.setCommunity(new OctetString(deviceTransportConfig.getCommunity())); | |
61 | + target = communityTargetV1; | |
62 | + break; | |
63 | + case V2C: | |
64 | + CommunityTarget communityTargetV2 = new CommunityTarget(); | |
65 | + communityTargetV2.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c); | |
66 | + communityTargetV2.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV); | |
67 | + communityTargetV2.setCommunity(new OctetString(deviceTransportConfig.getCommunity())); | |
68 | + target = communityTargetV2; | |
69 | + break; | |
70 | + case V3: | |
71 | + OctetString username = new OctetString(deviceTransportConfig.getUsername()); | |
72 | + OctetString securityName = new OctetString(deviceTransportConfig.getSecurityName()); | |
73 | + OctetString engineId = new OctetString(deviceTransportConfig.getEngineId()); | |
74 | + | |
75 | + OID authenticationProtocol = new OID(deviceTransportConfig.getAuthenticationProtocol().getOid()); | |
76 | + OID privacyProtocol = new OID(deviceTransportConfig.getPrivacyProtocol().getOid()); | |
77 | + OctetString authenticationPassphrase = new OctetString(deviceTransportConfig.getAuthenticationPassphrase()); | |
78 | + authenticationPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(authenticationProtocol, authenticationPassphrase, engineId.getValue())); | |
79 | + OctetString privacyPassphrase = new OctetString(deviceTransportConfig.getPrivacyPassphrase()); | |
80 | + privacyPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(privacyProtocol, authenticationProtocol, privacyPassphrase, engineId.getValue())); | |
81 | + | |
82 | + USM usm = snmpTransportService.getSnmp().getUSM(); | |
83 | + if (usm.hasUser(engineId, securityName)) { | |
84 | + usm.removeAllUsers(username, engineId); | |
85 | + } | |
86 | + usm.addLocalizedUser( | |
87 | + engineId.getValue(), username, | |
88 | + authenticationProtocol, authenticationPassphrase.getValue(), | |
89 | + privacyProtocol, privacyPassphrase.getValue() | |
90 | + ); | |
91 | + | |
92 | + UserTarget userTarget = new UserTarget(); | |
93 | + userTarget.setSecurityName(securityName); | |
94 | + userTarget.setAuthoritativeEngineID(engineId.getValue()); | |
95 | + userTarget.setSecurityModel(SecurityModel.SECURITY_MODEL_USM); | |
96 | + userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV); | |
97 | + target = userTarget; | |
98 | + break; | |
99 | + default: | |
100 | + throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported"); | |
101 | + } | |
102 | + | |
103 | + Address address = GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getHost() + "/" + deviceTransportConfig.getPort()); | |
104 | + target.setAddress(Optional.ofNullable(address).orElseThrow(() -> new IllegalArgumentException("Address of the SNMP device is invalid"))); | |
105 | + target.setTimeout(profileTransportConfig.getTimeoutMs()); | |
106 | + target.setRetries(profileTransportConfig.getRetries()); | |
107 | + target.setVersion(protocolVersion.getCode()); | |
108 | + | |
109 | + return target; | |
110 | + } | |
111 | + | |
112 | + public void cleanUpSnmpAuthInfo(DeviceSessionContext sessionContext) { | |
113 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); | |
114 | + if (deviceTransportConfiguration.getProtocolVersion() == SnmpProtocolVersion.V3) { | |
115 | + OctetString username = new OctetString(deviceTransportConfiguration.getUsername()); | |
116 | + OctetString engineId = new OctetString(deviceTransportConfiguration.getEngineId()); | |
117 | + snmpTransportService.getSnmp().getUSM().removeAllUsers(username, engineId); | |
118 | + } | |
119 | + } | |
120 | + | |
121 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.service; | |
17 | + | |
18 | +import lombok.RequiredArgsConstructor; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.springframework.context.ApplicationEventPublisher; | |
21 | +import org.springframework.stereotype.Service; | |
22 | +import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; | |
23 | +import org.thingsboard.server.queue.discovery.PartitionService; | |
24 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | |
25 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
26 | +import org.thingsboard.server.transport.snmp.event.SnmpTransportListChangedEvent; | |
27 | + | |
28 | +import java.util.Comparator; | |
29 | +import java.util.List; | |
30 | +import java.util.UUID; | |
31 | +import java.util.stream.Collectors; | |
32 | +import java.util.stream.Stream; | |
33 | + | |
34 | +@TbSnmpTransportComponent | |
35 | +@Service | |
36 | +@RequiredArgsConstructor | |
37 | +@Slf4j | |
38 | +public class SnmpTransportBalancingService { | |
39 | + private final PartitionService partitionService; | |
40 | + private final ApplicationEventPublisher eventPublisher; | |
41 | + private final SnmpTransportService snmpTransportService; | |
42 | + | |
43 | + private int snmpTransportsCount = 1; | |
44 | + private Integer currentTransportPartitionIndex = 0; | |
45 | + | |
46 | + public void onServiceListChanged(ServiceListChangedEvent event) { | |
47 | + log.trace("Got service list changed event: {}", event); | |
48 | + recalculatePartitions(event.getOtherServices(), event.getCurrentService()); | |
49 | + } | |
50 | + | |
51 | + public boolean isManagedByCurrentTransport(UUID entityId) { | |
52 | + boolean isManaged = resolvePartitionIndexForEntity(entityId) == currentTransportPartitionIndex; | |
53 | + if (!isManaged) { | |
54 | + log.trace("Entity {} is not managed by current SNMP transport node", entityId); | |
55 | + } | |
56 | + return isManaged; | |
57 | + } | |
58 | + | |
59 | + private int resolvePartitionIndexForEntity(UUID entityId) { | |
60 | + return partitionService.resolvePartitionIndex(entityId, snmpTransportsCount); | |
61 | + } | |
62 | + | |
63 | + private void recalculatePartitions(List<ServiceInfo> otherServices, ServiceInfo currentService) { | |
64 | + log.info("Recalculating partitions for SNMP transports"); | |
65 | + List<ServiceInfo> snmpTransports = Stream.concat(otherServices.stream(), Stream.of(currentService)) | |
66 | + .filter(service -> service.getTransportsList().contains(snmpTransportService.getName())) | |
67 | + .sorted(Comparator.comparing(ServiceInfo::getServiceId)) | |
68 | + .collect(Collectors.toList()); | |
69 | + log.trace("Found SNMP transports: {}", snmpTransports); | |
70 | + | |
71 | + int previousCurrentTransportPartitionIndex = currentTransportPartitionIndex; | |
72 | + int previousSnmpTransportsCount = snmpTransportsCount; | |
73 | + | |
74 | + if (!snmpTransports.isEmpty()) { | |
75 | + for (int i = 0; i < snmpTransports.size(); i++) { | |
76 | + if (snmpTransports.get(i).equals(currentService)) { | |
77 | + currentTransportPartitionIndex = i; | |
78 | + break; | |
79 | + } | |
80 | + } | |
81 | + snmpTransportsCount = snmpTransports.size(); | |
82 | + } | |
83 | + | |
84 | + if (snmpTransportsCount != previousSnmpTransportsCount || currentTransportPartitionIndex != previousCurrentTransportPartitionIndex) { | |
85 | + log.info("SNMP transports partitions have changed: transports count = {}, current transport partition index = {}", snmpTransportsCount, currentTransportPartitionIndex); | |
86 | + eventPublisher.publishEvent(new SnmpTransportListChangedEvent()); | |
87 | + } else { | |
88 | + log.info("SNMP transports partitions have not changed"); | |
89 | + } | |
90 | + } | |
91 | + | |
92 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.service; | |
17 | + | |
18 | +import com.google.gson.JsonElement; | |
19 | +import com.google.gson.JsonObject; | |
20 | +import lombok.Data; | |
21 | +import lombok.Getter; | |
22 | +import lombok.RequiredArgsConstructor; | |
23 | +import lombok.extern.slf4j.Slf4j; | |
24 | +import org.snmp4j.PDU; | |
25 | +import org.snmp4j.Snmp; | |
26 | +import org.snmp4j.TransportMapping; | |
27 | +import org.snmp4j.event.ResponseEvent; | |
28 | +import org.snmp4j.mp.MPv3; | |
29 | +import org.snmp4j.security.SecurityModels; | |
30 | +import org.snmp4j.security.SecurityProtocols; | |
31 | +import org.snmp4j.security.USM; | |
32 | +import org.snmp4j.smi.OctetString; | |
33 | +import org.snmp4j.transport.DefaultTcpTransportMapping; | |
34 | +import org.snmp4j.transport.DefaultUdpTransportMapping; | |
35 | +import org.springframework.beans.factory.annotation.Value; | |
36 | +import org.springframework.stereotype.Service; | |
37 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
38 | +import org.thingsboard.server.common.data.TbTransportService; | |
39 | +import org.thingsboard.server.common.data.kv.DataType; | |
40 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | |
41 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
42 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | |
43 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | |
44 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
45 | +import org.thingsboard.server.common.transport.TransportService; | |
46 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | |
47 | +import org.thingsboard.server.common.transport.adaptor.JsonConverter; | |
48 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
49 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
50 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | |
51 | + | |
52 | +import javax.annotation.PostConstruct; | |
53 | +import javax.annotation.PreDestroy; | |
54 | +import java.io.IOException; | |
55 | +import java.util.Arrays; | |
56 | +import java.util.Collections; | |
57 | +import java.util.EnumMap; | |
58 | +import java.util.List; | |
59 | +import java.util.Map; | |
60 | +import java.util.Optional; | |
61 | +import java.util.concurrent.ExecutorService; | |
62 | +import java.util.concurrent.Executors; | |
63 | +import java.util.concurrent.ScheduledExecutorService; | |
64 | +import java.util.concurrent.ScheduledFuture; | |
65 | +import java.util.concurrent.TimeUnit; | |
66 | +import java.util.stream.Collectors; | |
67 | + | |
68 | +@TbSnmpTransportComponent | |
69 | +@Service | |
70 | +@Slf4j | |
71 | +@RequiredArgsConstructor | |
72 | +public class SnmpTransportService implements TbTransportService { | |
73 | + private final TransportService transportService; | |
74 | + private final PduService pduService; | |
75 | + | |
76 | + @Getter | |
77 | + private Snmp snmp; | |
78 | + private ScheduledExecutorService queryingExecutor; | |
79 | + private ExecutorService responseProcessingExecutor; | |
80 | + | |
81 | + private final Map<SnmpCommunicationSpec, ResponseDataMapper> responseDataMappers = new EnumMap<>(SnmpCommunicationSpec.class); | |
82 | + private final Map<SnmpCommunicationSpec, ResponseProcessor> responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class); | |
83 | + | |
84 | + @Value("${transport.snmp.response_processing.parallelism_level}") | |
85 | + private Integer responseProcessingParallelismLevel; | |
86 | + @Value("${transport.snmp.underlying_protocol}") | |
87 | + private String snmpUnderlyingProtocol; | |
88 | + | |
89 | + @PostConstruct | |
90 | + private void init() throws IOException { | |
91 | + queryingExecutor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), ThingsBoardThreadFactory.forName("snmp-querying")); | |
92 | + responseProcessingExecutor = Executors.newWorkStealingPool(responseProcessingParallelismLevel); | |
93 | + | |
94 | + initializeSnmp(); | |
95 | + configureResponseDataMappers(); | |
96 | + configureResponseProcessors(); | |
97 | + | |
98 | + log.info("SNMP transport service initialized"); | |
99 | + } | |
100 | + | |
101 | + private void initializeSnmp() throws IOException { | |
102 | + TransportMapping<?> transportMapping; | |
103 | + switch (snmpUnderlyingProtocol) { | |
104 | + case "udp": | |
105 | + transportMapping = new DefaultUdpTransportMapping(); | |
106 | + break; | |
107 | + case "tcp": | |
108 | + transportMapping = new DefaultTcpTransportMapping(); | |
109 | + break; | |
110 | + default: | |
111 | + throw new IllegalArgumentException("Underlying protocol " + snmpUnderlyingProtocol + " for SNMP is not supported"); | |
112 | + } | |
113 | + snmp = new Snmp(transportMapping); | |
114 | + snmp.listen(); | |
115 | + | |
116 | + USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0); | |
117 | + SecurityModels.getInstance().addSecurityModel(usm); | |
118 | + } | |
119 | + | |
120 | + public void createQueryingTasks(DeviceSessionContext sessionContext) { | |
121 | + List<ScheduledFuture<?>> queryingTasks = sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream() | |
122 | + .filter(communicationConfig -> communicationConfig instanceof RepeatingQueryingSnmpCommunicationConfig) | |
123 | + .map(config -> { | |
124 | + RepeatingQueryingSnmpCommunicationConfig repeatingCommunicationConfig = (RepeatingQueryingSnmpCommunicationConfig) config; | |
125 | + Long queryingFrequency = repeatingCommunicationConfig.getQueryingFrequencyMs(); | |
126 | + | |
127 | + return queryingExecutor.scheduleWithFixedDelay(() -> { | |
128 | + try { | |
129 | + if (sessionContext.isActive()) { | |
130 | + sendRequest(sessionContext, repeatingCommunicationConfig); | |
131 | + } | |
132 | + } catch (Exception e) { | |
133 | + log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.toString()); | |
134 | + } | |
135 | + }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS); | |
136 | + }) | |
137 | + .collect(Collectors.toList()); | |
138 | + sessionContext.getQueryingTasks().addAll(queryingTasks); | |
139 | + } | |
140 | + | |
141 | + public void cancelQueryingTasks(DeviceSessionContext sessionContext) { | |
142 | + sessionContext.getQueryingTasks().forEach(task -> task.cancel(true)); | |
143 | + sessionContext.getQueryingTasks().clear(); | |
144 | + } | |
145 | + | |
146 | + | |
147 | + private void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) { | |
148 | + sendRequest(sessionContext, communicationConfig, Collections.emptyMap()); | |
149 | + } | |
150 | + | |
151 | + private void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) { | |
152 | + PDU request = pduService.createPdu(sessionContext, communicationConfig, values); | |
153 | + RequestInfo requestInfo = new RequestInfo(communicationConfig.getSpec(), communicationConfig.getAllMappings()); | |
154 | + sendRequest(sessionContext, request, requestInfo); | |
155 | + } | |
156 | + | |
157 | + private void sendRequest(DeviceSessionContext sessionContext, PDU request, RequestInfo requestInfo) { | |
158 | + if (request.size() > 0) { | |
159 | + log.trace("Executing SNMP request for device {}. Variables bindings: {}", sessionContext.getDeviceId(), request.getVariableBindings()); | |
160 | + try { | |
161 | + snmp.send(request, sessionContext.getTarget(), requestInfo, sessionContext); | |
162 | + } catch (IOException e) { | |
163 | + log.error("Failed to send SNMP request to device {}: {}", sessionContext.getDeviceId(), e.toString()); | |
164 | + } | |
165 | + } | |
166 | + } | |
167 | + | |
168 | + public void onAttributeUpdate(DeviceSessionContext sessionContext, TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification) { | |
169 | + sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream() | |
170 | + .filter(config -> config.getSpec() == SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING) | |
171 | + .findFirst() | |
172 | + .ifPresent(communicationConfig -> { | |
173 | + Map<String, String> sharedAttributes = JsonConverter.toJson(attributeUpdateNotification).entrySet().stream() | |
174 | + .collect(Collectors.toMap( | |
175 | + Map.Entry::getKey, | |
176 | + entry -> entry.getValue().isJsonPrimitive() ? entry.getValue().getAsString() : entry.getValue().toString() | |
177 | + )); | |
178 | + sendRequest(sessionContext, communicationConfig, sharedAttributes); | |
179 | + }); | |
180 | + } | |
181 | + | |
182 | + public void onToDeviceRpcRequest(DeviceSessionContext sessionContext, TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg) { | |
183 | + SnmpMethod snmpMethod = SnmpMethod.valueOf(toDeviceRpcRequestMsg.getMethodName()); | |
184 | + JsonObject params = JsonConverter.parse(toDeviceRpcRequestMsg.getParams()).getAsJsonObject(); | |
185 | + | |
186 | + String oid = Optional.ofNullable(params.get("oid")).map(JsonElement::getAsString).orElse(null); | |
187 | + String value = Optional.ofNullable(params.get("value")).map(JsonElement::getAsString).orElse(null); | |
188 | + DataType dataType = Optional.ofNullable(params.get("dataType")).map(e -> DataType.valueOf(e.getAsString())).orElse(DataType.STRING); | |
189 | + | |
190 | + if (oid == null || oid.isEmpty()) { | |
191 | + throw new IllegalArgumentException("OID in to-device RPC request is not specified"); | |
192 | + } | |
193 | + if (value == null && snmpMethod == SnmpMethod.SET) { | |
194 | + throw new IllegalArgumentException("Value must be specified for SNMP method 'SET'"); | |
195 | + } | |
196 | + | |
197 | + PDU request = pduService.createSingleVariablePdu(sessionContext, snmpMethod, oid, value, dataType); | |
198 | + sendRequest(sessionContext, request, new RequestInfo(toDeviceRpcRequestMsg.getRequestId(), SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST)); | |
199 | + } | |
200 | + | |
201 | + | |
202 | + public void processResponseEvent(DeviceSessionContext sessionContext, ResponseEvent event) { | |
203 | + ((Snmp) event.getSource()).cancel(event.getRequest(), sessionContext); | |
204 | + | |
205 | + if (event.getError() != null) { | |
206 | + log.warn("SNMP response error: {}", event.getError().toString()); | |
207 | + return; | |
208 | + } | |
209 | + | |
210 | + PDU response = event.getResponse(); | |
211 | + if (response == null) { | |
212 | + log.debug("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID()); | |
213 | + return; | |
214 | + } | |
215 | + | |
216 | + RequestInfo requestInfo = (RequestInfo) event.getUserObject(); | |
217 | + responseProcessingExecutor.execute(() -> { | |
218 | + processResponse(sessionContext, response, requestInfo); | |
219 | + }); | |
220 | + } | |
221 | + | |
222 | + private void processResponse(DeviceSessionContext sessionContext, PDU response, RequestInfo requestInfo) { | |
223 | + ResponseProcessor responseProcessor = responseProcessors.get(requestInfo.getCommunicationSpec()); | |
224 | + if (responseProcessor == null) return; | |
225 | + | |
226 | + JsonObject responseData = responseDataMappers.get(requestInfo.getCommunicationSpec()).map(response, requestInfo); | |
227 | + | |
228 | + if (responseData.entrySet().isEmpty()) { | |
229 | + log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), response.getRequestID()); | |
230 | + return; | |
231 | + } | |
232 | + | |
233 | + responseProcessor.process(responseData, requestInfo, sessionContext); | |
234 | + reportActivity(sessionContext.getSessionInfo()); | |
235 | + } | |
236 | + | |
237 | + private void configureResponseDataMappers() { | |
238 | + responseDataMappers.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (pdu, requestInfo) -> { | |
239 | + JsonObject responseData = new JsonObject(); | |
240 | + pduService.processPdu(pdu).forEach((oid, value) -> { | |
241 | + responseData.addProperty(oid.toDottedString(), value); | |
242 | + }); | |
243 | + return responseData; | |
244 | + }); | |
245 | + | |
246 | + ResponseDataMapper defaultResponseDataMapper = (pdu, requestInfo) -> { | |
247 | + return pduService.processPdu(pdu, requestInfo.getResponseMappings()); | |
248 | + }; | |
249 | + Arrays.stream(SnmpCommunicationSpec.values()) | |
250 | + .forEach(communicationSpec -> { | |
251 | + responseDataMappers.putIfAbsent(communicationSpec, defaultResponseDataMapper); | |
252 | + }); | |
253 | + } | |
254 | + | |
255 | + private void configureResponseProcessors() { | |
256 | + responseProcessors.put(SnmpCommunicationSpec.TELEMETRY_QUERYING, (responseData, requestInfo, sessionContext) -> { | |
257 | + TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(responseData); | |
258 | + transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, null); | |
259 | + log.debug("Posted telemetry for SNMP device {}: {}", sessionContext.getDeviceId(), responseData); | |
260 | + }); | |
261 | + | |
262 | + responseProcessors.put(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, (responseData, requestInfo, sessionContext) -> { | |
263 | + TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(responseData); | |
264 | + transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, null); | |
265 | + log.debug("Posted attributes for SNMP device {}: {}", sessionContext.getDeviceId(), responseData); | |
266 | + }); | |
267 | + | |
268 | + responseProcessors.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (responseData, requestInfo, sessionContext) -> { | |
269 | + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder() | |
270 | + .setRequestId(requestInfo.getRequestId()) | |
271 | + .setPayload(JsonConverter.toJson(responseData)) | |
272 | + .build(); | |
273 | + transportService.process(sessionContext.getSessionInfo(), rpcResponseMsg, null); | |
274 | + log.debug("Posted RPC response {} for device {}", responseData, sessionContext.getDeviceId()); | |
275 | + }); | |
276 | + } | |
277 | + | |
278 | + private void reportActivity(TransportProtos.SessionInfoProto sessionInfo) { | |
279 | + transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder() | |
280 | + .setAttributeSubscription(true) | |
281 | + .setRpcSubscription(true) | |
282 | + .setLastActivityTime(System.currentTimeMillis()) | |
283 | + .build(), TransportServiceCallback.EMPTY); | |
284 | + } | |
285 | + | |
286 | + | |
287 | + @Override | |
288 | + public String getName() { | |
289 | + return "SNMP"; | |
290 | + } | |
291 | + | |
292 | + @PreDestroy | |
293 | + public void shutdown() { | |
294 | + log.info("Stopping SNMP transport!"); | |
295 | + if (queryingExecutor != null) { | |
296 | + queryingExecutor.shutdownNow(); | |
297 | + } | |
298 | + if (responseProcessingExecutor != null) { | |
299 | + responseProcessingExecutor.shutdownNow(); | |
300 | + } | |
301 | + if (snmp != null) { | |
302 | + try { | |
303 | + snmp.close(); | |
304 | + } catch (IOException e) { | |
305 | + log.error(e.getMessage(), e); | |
306 | + } | |
307 | + } | |
308 | + log.info("SNMP transport stopped!"); | |
309 | + } | |
310 | + | |
311 | + @Data | |
312 | + private static class RequestInfo { | |
313 | + private Integer requestId; | |
314 | + private SnmpCommunicationSpec communicationSpec; | |
315 | + private List<SnmpMapping> responseMappings; | |
316 | + | |
317 | + public RequestInfo(Integer requestId, SnmpCommunicationSpec communicationSpec) { | |
318 | + this.requestId = requestId; | |
319 | + this.communicationSpec = communicationSpec; | |
320 | + } | |
321 | + | |
322 | + public RequestInfo(SnmpCommunicationSpec communicationSpec) { | |
323 | + this.communicationSpec = communicationSpec; | |
324 | + } | |
325 | + | |
326 | + public RequestInfo(SnmpCommunicationSpec communicationSpec, List<SnmpMapping> responseMappings) { | |
327 | + this.communicationSpec = communicationSpec; | |
328 | + this.responseMappings = responseMappings; | |
329 | + } | |
330 | + } | |
331 | + | |
332 | + private interface ResponseDataMapper { | |
333 | + JsonObject map(PDU pdu, RequestInfo requestInfo); | |
334 | + } | |
335 | + | |
336 | + private interface ResponseProcessor { | |
337 | + void process(JsonObject responseData, RequestInfo requestInfo, DeviceSessionContext sessionContext); | |
338 | + } | |
339 | + | |
340 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.session; | |
17 | + | |
18 | +import lombok.Getter; | |
19 | +import lombok.Setter; | |
20 | +import lombok.extern.slf4j.Slf4j; | |
21 | +import org.snmp4j.Target; | |
22 | +import org.snmp4j.event.ResponseEvent; | |
23 | +import org.snmp4j.event.ResponseListener; | |
24 | +import org.thingsboard.server.common.data.Device; | |
25 | +import org.thingsboard.server.common.data.DeviceProfile; | |
26 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | |
27 | +import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; | |
28 | +import org.thingsboard.server.common.data.id.DeviceId; | |
29 | +import org.thingsboard.server.common.transport.SessionMsgListener; | |
30 | +import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; | |
31 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
32 | +import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | |
33 | +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | |
34 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; | |
35 | +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; | |
36 | +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; | |
37 | +import org.thingsboard.server.transport.snmp.SnmpTransportContext; | |
38 | + | |
39 | +import java.util.LinkedList; | |
40 | +import java.util.List; | |
41 | +import java.util.UUID; | |
42 | +import java.util.concurrent.ScheduledFuture; | |
43 | +import java.util.concurrent.atomic.AtomicInteger; | |
44 | + | |
45 | +@Slf4j | |
46 | +public class DeviceSessionContext extends DeviceAwareSessionContext implements SessionMsgListener, ResponseListener { | |
47 | + @Getter | |
48 | + private Target target; | |
49 | + private final String token; | |
50 | + @Getter | |
51 | + @Setter | |
52 | + private SnmpDeviceProfileTransportConfiguration profileTransportConfiguration; | |
53 | + @Getter | |
54 | + @Setter | |
55 | + private SnmpDeviceTransportConfiguration deviceTransportConfiguration; | |
56 | + @Getter | |
57 | + private final Device device; | |
58 | + | |
59 | + private final SnmpTransportContext snmpTransportContext; | |
60 | + | |
61 | + private final AtomicInteger msgIdSeq = new AtomicInteger(0); | |
62 | + @Getter | |
63 | + private boolean isActive = true; | |
64 | + | |
65 | + @Getter | |
66 | + private final List<ScheduledFuture<?>> queryingTasks = new LinkedList<>(); | |
67 | + | |
68 | + public DeviceSessionContext(Device device, DeviceProfile deviceProfile, String token, | |
69 | + SnmpDeviceProfileTransportConfiguration profileTransportConfiguration, | |
70 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration, | |
71 | + SnmpTransportContext snmpTransportContext) throws Exception { | |
72 | + super(UUID.randomUUID()); | |
73 | + super.setDeviceId(device.getId()); | |
74 | + super.setDeviceProfile(deviceProfile); | |
75 | + this.device = device; | |
76 | + | |
77 | + this.token = token; | |
78 | + this.snmpTransportContext = snmpTransportContext; | |
79 | + | |
80 | + this.profileTransportConfiguration = profileTransportConfiguration; | |
81 | + this.deviceTransportConfiguration = deviceTransportConfiguration; | |
82 | + | |
83 | + initializeTarget(profileTransportConfiguration, deviceTransportConfiguration); | |
84 | + } | |
85 | + | |
86 | + @Override | |
87 | + public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto newSessionInfo, DeviceProfile deviceProfile) { | |
88 | + super.onDeviceProfileUpdate(newSessionInfo, deviceProfile); | |
89 | + if (isActive) { | |
90 | + snmpTransportContext.onDeviceProfileUpdated(deviceProfile, this); | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + @Override | |
95 | + public void onDeviceDeleted(DeviceId deviceId) { | |
96 | + snmpTransportContext.onDeviceDeleted(this); | |
97 | + } | |
98 | + | |
99 | + @Override | |
100 | + public void onResponse(ResponseEvent event) { | |
101 | + if (isActive) { | |
102 | + snmpTransportContext.getSnmpTransportService().processResponseEvent(this, event); | |
103 | + } | |
104 | + } | |
105 | + | |
106 | + public void initializeTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) throws Exception { | |
107 | + log.trace("Initializing target for SNMP session of device {}", device); | |
108 | + this.target = snmpTransportContext.getSnmpAuthService().setUpSnmpTarget(profileTransportConfig, deviceTransportConfig); | |
109 | + log.debug("SNMP target initialized: {}", target); | |
110 | + } | |
111 | + | |
112 | + public void close() { | |
113 | + isActive = false; | |
114 | + } | |
115 | + | |
116 | + public String getToken() { | |
117 | + return token; | |
118 | + } | |
119 | + | |
120 | + @Override | |
121 | + public int nextMsgId() { | |
122 | + return msgIdSeq.incrementAndGet(); | |
123 | + } | |
124 | + | |
125 | + @Override | |
126 | + public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) { | |
127 | + } | |
128 | + | |
129 | + @Override | |
130 | + public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) { | |
131 | + snmpTransportContext.getSnmpTransportService().onAttributeUpdate(this, attributeUpdateNotification); | |
132 | + } | |
133 | + | |
134 | + @Override | |
135 | + public void onRemoteSessionCloseCommand(SessionCloseNotificationProto sessionCloseNotification) { | |
136 | + } | |
137 | + | |
138 | + @Override | |
139 | + public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { | |
140 | + snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest); | |
141 | + } | |
142 | + | |
143 | + @Override | |
144 | + public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) { | |
145 | + } | |
146 | +} | ... | ... |
common/transport/snmp/src/test/java/org/thingsboard/server/transport/snmp/SnmpDeviceSimulatorV2.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp; | |
17 | + | |
18 | +import org.snmp4j.CommandResponderEvent; | |
19 | +import org.snmp4j.CommunityTarget; | |
20 | +import org.snmp4j.PDU; | |
21 | +import org.snmp4j.Snmp; | |
22 | +import org.snmp4j.Target; | |
23 | +import org.snmp4j.TransportMapping; | |
24 | +import org.snmp4j.agent.BaseAgent; | |
25 | +import org.snmp4j.agent.CommandProcessor; | |
26 | +import org.snmp4j.agent.DuplicateRegistrationException; | |
27 | +import org.snmp4j.agent.MOGroup; | |
28 | +import org.snmp4j.agent.ManagedObject; | |
29 | +import org.snmp4j.agent.mo.MOAccessImpl; | |
30 | +import org.snmp4j.agent.mo.MOScalar; | |
31 | +import org.snmp4j.agent.mo.snmp.RowStatus; | |
32 | +import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB; | |
33 | +import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB; | |
34 | +import org.snmp4j.agent.mo.snmp.SnmpTargetMIB; | |
35 | +import org.snmp4j.agent.mo.snmp.StorageType; | |
36 | +import org.snmp4j.agent.mo.snmp.VacmMIB; | |
37 | +import org.snmp4j.agent.security.MutableVACM; | |
38 | +import org.snmp4j.mp.MPv3; | |
39 | +import org.snmp4j.mp.SnmpConstants; | |
40 | +import org.snmp4j.security.SecurityLevel; | |
41 | +import org.snmp4j.security.SecurityModel; | |
42 | +import org.snmp4j.security.USM; | |
43 | +import org.snmp4j.smi.Address; | |
44 | +import org.snmp4j.smi.GenericAddress; | |
45 | +import org.snmp4j.smi.Integer32; | |
46 | +import org.snmp4j.smi.OID; | |
47 | +import org.snmp4j.smi.OctetString; | |
48 | +import org.snmp4j.smi.UdpAddress; | |
49 | +import org.snmp4j.smi.Variable; | |
50 | +import org.snmp4j.smi.VariableBinding; | |
51 | +import org.snmp4j.transport.TransportMappings; | |
52 | + | |
53 | +import java.io.File; | |
54 | +import java.io.IOException; | |
55 | +import java.util.Map; | |
56 | +import java.util.Scanner; | |
57 | +import java.util.function.Consumer; | |
58 | +import java.util.stream.Collectors; | |
59 | + | |
60 | +public class SnmpDeviceSimulatorV2 extends BaseAgent { | |
61 | + | |
62 | + public static class RequestProcessor extends CommandProcessor { | |
63 | + private final Consumer<CommandResponderEvent> processor; | |
64 | + | |
65 | + public RequestProcessor(Consumer<CommandResponderEvent> processor) { | |
66 | + super(new OctetString(MPv3.createLocalEngineID())); | |
67 | + this.processor = processor; | |
68 | + } | |
69 | + | |
70 | + @Override | |
71 | + public void processPdu(CommandResponderEvent event) { | |
72 | + processor.accept(event); | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + | |
77 | + private final Target target; | |
78 | + private final Address address; | |
79 | + private Snmp snmp; | |
80 | + | |
81 | + private final String password; | |
82 | + | |
83 | + public SnmpDeviceSimulatorV2(int port, String password) throws IOException { | |
84 | + super(new File("conf.agent"), new File("bootCounter.agent"), new RequestProcessor(event -> { | |
85 | + System.out.println("aboba"); | |
86 | + ((Snmp) event.getSource()).cancel(event.getPDU(), event1 -> System.out.println("canceled")); | |
87 | + })); | |
88 | + CommunityTarget target = new CommunityTarget(); | |
89 | + target.setCommunity(new OctetString(password)); | |
90 | + this.address = GenericAddress.parse("udp:0.0.0.0/" + port); | |
91 | + target.setAddress(address); | |
92 | + target.setRetries(2); | |
93 | + target.setTimeout(1500); | |
94 | + target.setVersion(SnmpConstants.version2c); | |
95 | + this.target = target; | |
96 | + this.password = password; | |
97 | + } | |
98 | + | |
99 | + public void start() throws IOException { | |
100 | + init(); | |
101 | + addShutdownHook(); | |
102 | + getServer().addContext(new OctetString("public")); | |
103 | + finishInit(); | |
104 | + run(); | |
105 | + sendColdStartNotification(); | |
106 | + snmp = new Snmp(transportMappings[0]); | |
107 | + } | |
108 | + | |
109 | + public void setUpMappings(Map<String, String> oidToResponseMappings) { | |
110 | + unregisterManagedObject(getSnmpv2MIB()); | |
111 | + oidToResponseMappings.forEach((oid, response) -> { | |
112 | + registerManagedObject(new MOScalar<>(new OID(oid), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(response))); | |
113 | + }); | |
114 | + } | |
115 | + | |
116 | + public void sendTrap(String host, int port, Map<String, String> values) throws IOException { | |
117 | + PDU pdu = new PDU(); | |
118 | + pdu.addAll(values.entrySet().stream() | |
119 | + .map(entry -> new VariableBinding(new OID(entry.getKey()), new OctetString(entry.getValue()))) | |
120 | + .collect(Collectors.toList())); | |
121 | + pdu.setType(PDU.TRAP); | |
122 | + | |
123 | + CommunityTarget remoteTarget = (CommunityTarget) getTarget().clone(); | |
124 | + remoteTarget.setAddress(new UdpAddress(host + "/" + port)); | |
125 | + | |
126 | + snmp.send(pdu, remoteTarget); | |
127 | + } | |
128 | + | |
129 | + @Override | |
130 | + protected void registerManagedObjects() { | |
131 | + } | |
132 | + | |
133 | + protected void registerManagedObject(ManagedObject mo) { | |
134 | + try { | |
135 | + server.register(mo, null); | |
136 | + } catch (DuplicateRegistrationException ex) { | |
137 | + throw new RuntimeException(ex); | |
138 | + } | |
139 | + } | |
140 | + | |
141 | + protected void unregisterManagedObject(MOGroup moGroup) { | |
142 | + moGroup.unregisterMOs(server, getContext(moGroup)); | |
143 | + } | |
144 | + | |
145 | + @Override | |
146 | + protected void addNotificationTargets(SnmpTargetMIB targetMIB, | |
147 | + SnmpNotificationMIB notificationMIB) { | |
148 | + } | |
149 | + | |
150 | + @Override | |
151 | + protected void addViews(VacmMIB vacm) { | |
152 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c, new OctetString( | |
153 | + "cpublic"), new OctetString("v1v2group"), | |
154 | + StorageType.nonVolatile); | |
155 | + | |
156 | + vacm.addAccess(new OctetString("v1v2group"), new OctetString("public"), | |
157 | + SecurityModel.SECURITY_MODEL_ANY, SecurityLevel.NOAUTH_NOPRIV, | |
158 | + MutableVACM.VACM_MATCH_EXACT, new OctetString("fullReadView"), | |
159 | + new OctetString("fullWriteView"), new OctetString( | |
160 | + "fullNotifyView"), StorageType.nonVolatile); | |
161 | + | |
162 | + vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"), | |
163 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
164 | + StorageType.nonVolatile); | |
165 | + } | |
166 | + | |
167 | + protected void addUsmUser(USM usm) { | |
168 | + } | |
169 | + | |
170 | + protected void initTransportMappings() { | |
171 | + transportMappings = new TransportMapping[]{TransportMappings.getInstance().createTransportMapping(address)}; | |
172 | + } | |
173 | + | |
174 | + protected void unregisterManagedObjects() { | |
175 | + } | |
176 | + | |
177 | + protected void addCommunities(SnmpCommunityMIB communityMIB) { | |
178 | + Variable[] com2sec = new Variable[]{ | |
179 | + new OctetString("public"), | |
180 | + new OctetString("cpublic"), | |
181 | + getAgent().getContextEngineID(), | |
182 | + new OctetString("public"), | |
183 | + new OctetString(), | |
184 | + new Integer32(StorageType.nonVolatile), | |
185 | + new Integer32(RowStatus.active) | |
186 | + }; | |
187 | + SnmpCommunityMIB.SnmpCommunityEntryRow row = communityMIB.getSnmpCommunityEntry().createRow( | |
188 | + new OctetString("public2public").toSubIndex(true), com2sec); | |
189 | + communityMIB.getSnmpCommunityEntry().addRow(row); | |
190 | + } | |
191 | + | |
192 | + public Target getTarget() { | |
193 | + return target; | |
194 | + } | |
195 | + | |
196 | +} | ... | ... |
common/transport/snmp/src/test/java/org/thingsboard/server/transport/snmp/SnmpDeviceSimulatorV3.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp; | |
17 | + | |
18 | +import org.snmp4j.MessageDispatcherImpl; | |
19 | +import org.snmp4j.TransportMapping; | |
20 | +import org.snmp4j.agent.BaseAgent; | |
21 | +import org.snmp4j.agent.CommandProcessor; | |
22 | +import org.snmp4j.agent.DuplicateRegistrationException; | |
23 | +import org.snmp4j.agent.MOGroup; | |
24 | +import org.snmp4j.agent.ManagedObject; | |
25 | +import org.snmp4j.agent.mo.DefaultMOMutableRow2PC; | |
26 | +import org.snmp4j.agent.mo.DefaultMOTable; | |
27 | +import org.snmp4j.agent.mo.MOAccessImpl; | |
28 | +import org.snmp4j.agent.mo.MOColumn; | |
29 | +import org.snmp4j.agent.mo.MOMutableColumn; | |
30 | +import org.snmp4j.agent.mo.MOMutableTableModel; | |
31 | +import org.snmp4j.agent.mo.MOScalar; | |
32 | +import org.snmp4j.agent.mo.MOTableIndex; | |
33 | +import org.snmp4j.agent.mo.MOTableRow; | |
34 | +import org.snmp4j.agent.mo.MOTableSubIndex; | |
35 | +import org.snmp4j.agent.mo.ext.AgentppSimulationMib; | |
36 | +import org.snmp4j.agent.mo.snmp.RowStatus; | |
37 | +import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB; | |
38 | +import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB; | |
39 | +import org.snmp4j.agent.mo.snmp.SnmpTargetMIB; | |
40 | +import org.snmp4j.agent.mo.snmp.StorageType; | |
41 | +import org.snmp4j.agent.mo.snmp.TransportDomains; | |
42 | +import org.snmp4j.agent.mo.snmp.VacmMIB; | |
43 | +import org.snmp4j.agent.mo.snmp4j.example.Snmp4jHeartbeatMib; | |
44 | +import org.snmp4j.agent.security.MutableVACM; | |
45 | +import org.snmp4j.mp.MPv1; | |
46 | +import org.snmp4j.mp.MPv2c; | |
47 | +import org.snmp4j.mp.MPv3; | |
48 | +import org.snmp4j.mp.MessageProcessingModel; | |
49 | +import org.snmp4j.security.AuthHMAC192SHA256; | |
50 | +import org.snmp4j.security.AuthMD5; | |
51 | +import org.snmp4j.security.AuthSHA; | |
52 | +import org.snmp4j.security.PrivAES128; | |
53 | +import org.snmp4j.security.PrivAES192; | |
54 | +import org.snmp4j.security.PrivAES256; | |
55 | +import org.snmp4j.security.PrivDES; | |
56 | +import org.snmp4j.security.SecurityLevel; | |
57 | +import org.snmp4j.security.SecurityModel; | |
58 | +import org.snmp4j.security.SecurityModels; | |
59 | +import org.snmp4j.security.SecurityProtocols; | |
60 | +import org.snmp4j.security.USM; | |
61 | +import org.snmp4j.security.UsmUser; | |
62 | +import org.snmp4j.smi.Address; | |
63 | +import org.snmp4j.smi.Gauge32; | |
64 | +import org.snmp4j.smi.GenericAddress; | |
65 | +import org.snmp4j.smi.Integer32; | |
66 | +import org.snmp4j.smi.OID; | |
67 | +import org.snmp4j.smi.OctetString; | |
68 | +import org.snmp4j.smi.SMIConstants; | |
69 | +import org.snmp4j.smi.TcpAddress; | |
70 | +import org.snmp4j.smi.TimeTicks; | |
71 | +import org.snmp4j.smi.UdpAddress; | |
72 | +import org.snmp4j.smi.Variable; | |
73 | +import org.snmp4j.transport.DefaultTcpTransportMapping; | |
74 | +import org.snmp4j.transport.TransportMappings; | |
75 | +import org.snmp4j.util.ThreadPool; | |
76 | + | |
77 | +import java.io.File; | |
78 | +import java.io.IOException; | |
79 | +import java.util.Map; | |
80 | + | |
81 | +/** | |
82 | + * The TestAgent is a sample SNMP agent implementation of all | |
83 | + * features (MIB implementations) provided by the SNMP4J-Agent framework. | |
84 | + * | |
85 | + * Note, for snmp4s, this code is mostly a copy from snmp4j. | |
86 | + * And don't remove snmp users | |
87 | + * | |
88 | + */ | |
89 | +public class SnmpDeviceSimulatorV3 extends BaseAgent { | |
90 | + protected String address; | |
91 | + private Snmp4jHeartbeatMib heartbeatMIB; | |
92 | + private AgentppSimulationMib agentppSimulationMIB; | |
93 | + | |
94 | + public SnmpDeviceSimulatorV3(CommandProcessor processor) throws IOException { | |
95 | + super(new File("SNMP4JTestAgentBC.cfg"), new File("SNMP4JTestAgentConfig.cfg"), | |
96 | + processor); | |
97 | + agent.setWorkerPool(ThreadPool.create("RequestPool", 4)); | |
98 | + } | |
99 | + | |
100 | + public void setUpMappings(Map<String, String> oidToResponseMappings) { | |
101 | + unregisterManagedObject(getSnmpv2MIB()); | |
102 | + oidToResponseMappings.forEach((oid, response) -> { | |
103 | + registerManagedObject(new MOScalar<>(new OID(oid), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(response))); | |
104 | + }); | |
105 | + } | |
106 | + protected void registerManagedObject(ManagedObject mo) { | |
107 | + try { | |
108 | + server.register(mo, null); | |
109 | + } catch (DuplicateRegistrationException ex) { | |
110 | + throw new RuntimeException(ex); | |
111 | + } | |
112 | + } | |
113 | + | |
114 | + protected void unregisterManagedObject(MOGroup moGroup) { | |
115 | + moGroup.unregisterMOs(server, getContext(moGroup)); | |
116 | + } | |
117 | + | |
118 | + protected void registerManagedObjects() { | |
119 | + try { | |
120 | + server.register(createStaticIfTable(), null); | |
121 | + server.register(createStaticIfXTable(), null); | |
122 | + agentppSimulationMIB.registerMOs(server, null); | |
123 | + heartbeatMIB.registerMOs(server, null); | |
124 | + } catch (DuplicateRegistrationException ex) { | |
125 | + ex.printStackTrace(); | |
126 | + } | |
127 | + } | |
128 | + | |
129 | + protected void addNotificationTargets(SnmpTargetMIB targetMIB, | |
130 | + SnmpNotificationMIB notificationMIB) { | |
131 | + targetMIB.addDefaultTDomains(); | |
132 | + | |
133 | + targetMIB.addTargetAddress(new OctetString("notificationV2c"), | |
134 | + TransportDomains.transportDomainUdpIpv4, | |
135 | + new OctetString(new UdpAddress("127.0.0.1/162").getValue()), | |
136 | + 200, 1, | |
137 | + new OctetString("notify"), | |
138 | + new OctetString("v2c"), | |
139 | + StorageType.permanent); | |
140 | + targetMIB.addTargetAddress(new OctetString("notificationV3"), | |
141 | + TransportDomains.transportDomainUdpIpv4, | |
142 | + new OctetString(new UdpAddress("127.0.0.1/1162").getValue()), | |
143 | + 200, 1, | |
144 | + new OctetString("notify"), | |
145 | + new OctetString("v3notify"), | |
146 | + StorageType.permanent); | |
147 | + targetMIB.addTargetParams(new OctetString("v2c"), | |
148 | + MessageProcessingModel.MPv2c, | |
149 | + SecurityModel.SECURITY_MODEL_SNMPv2c, | |
150 | + new OctetString("cpublic"), | |
151 | + SecurityLevel.AUTH_PRIV, | |
152 | + StorageType.permanent); | |
153 | + targetMIB.addTargetParams(new OctetString("v3notify"), | |
154 | + MessageProcessingModel.MPv3, | |
155 | + SecurityModel.SECURITY_MODEL_USM, | |
156 | + new OctetString("v3notify"), | |
157 | + SecurityLevel.NOAUTH_NOPRIV, | |
158 | + StorageType.permanent); | |
159 | + notificationMIB.addNotifyEntry(new OctetString("default"), | |
160 | + new OctetString("notify"), | |
161 | + SnmpNotificationMIB.SnmpNotifyTypeEnum.inform, | |
162 | + StorageType.permanent); | |
163 | + } | |
164 | + protected void addViews(VacmMIB vacm) { | |
165 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv1, | |
166 | + new OctetString("cpublic"), | |
167 | + new OctetString("v1v2group"), | |
168 | + StorageType.nonVolatile); | |
169 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c, | |
170 | + new OctetString("cpublic"), | |
171 | + new OctetString("v1v2group"), | |
172 | + StorageType.nonVolatile); | |
173 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
174 | + new OctetString("SHADES"), | |
175 | + new OctetString("v3group"), | |
176 | + StorageType.nonVolatile); | |
177 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
178 | + new OctetString("MD5DES"), | |
179 | + new OctetString("v3group"), | |
180 | + StorageType.nonVolatile); | |
181 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
182 | + new OctetString("TEST"), | |
183 | + new OctetString("v3test"), | |
184 | + StorageType.nonVolatile); | |
185 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
186 | + new OctetString("SHA"), | |
187 | + new OctetString("v3restricted"), | |
188 | + StorageType.nonVolatile); | |
189 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
190 | + new OctetString("SHAAES128"), | |
191 | + new OctetString("v3group"), | |
192 | + StorageType.nonVolatile); | |
193 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
194 | + new OctetString("SHAAES192"), | |
195 | + new OctetString("v3group"), | |
196 | + StorageType.nonVolatile); | |
197 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
198 | + new OctetString("SHAAES256"), | |
199 | + new OctetString("v3group"), | |
200 | + StorageType.nonVolatile); | |
201 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
202 | + new OctetString("MD5AES128"), | |
203 | + new OctetString("v3group"), | |
204 | + StorageType.nonVolatile); | |
205 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
206 | + new OctetString("MD5AES192"), | |
207 | + new OctetString("v3group"), | |
208 | + StorageType.nonVolatile); | |
209 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
210 | + new OctetString("MD5AES256"), | |
211 | + new OctetString("v3group"), | |
212 | + StorageType.nonVolatile); | |
213 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
214 | + new OctetString("aboba"), | |
215 | + new OctetString("v3group"), | |
216 | + StorageType.nonVolatile); | |
217 | + //============================================// | |
218 | + // agent5-auth-priv | |
219 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
220 | + new OctetString("agent5"), | |
221 | + new OctetString("v3group"), | |
222 | + StorageType.nonVolatile); | |
223 | + //===========================================// | |
224 | + // agent002 | |
225 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
226 | + new OctetString("agent002"), | |
227 | + new OctetString("v3group"), | |
228 | + StorageType.nonVolatile); | |
229 | + //===========================================// | |
230 | + // user001-auth-no-priv | |
231 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
232 | + new OctetString("user001"), | |
233 | + new OctetString("group001"), | |
234 | + StorageType.nonVolatile); | |
235 | + //===========================================// | |
236 | + | |
237 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
238 | + new OctetString("v3notify"), | |
239 | + new OctetString("v3group"), | |
240 | + StorageType.nonVolatile); | |
241 | + | |
242 | + //===========================================// | |
243 | + // group auth no priv | |
244 | + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM, | |
245 | + new OctetString("v3notify-auth"), | |
246 | + new OctetString("group001"), | |
247 | + StorageType.nonVolatile); | |
248 | + //===========================================// | |
249 | + | |
250 | + | |
251 | + | |
252 | + // my conf | |
253 | + vacm.addAccess(new OctetString("group001"), new OctetString("public"), | |
254 | + SecurityModel.SECURITY_MODEL_USM, | |
255 | + SecurityLevel.AUTH_NOPRIV, | |
256 | + MutableVACM.VACM_MATCH_EXACT, | |
257 | + new OctetString("fullReadView"), | |
258 | + new OctetString("fullWriteView"), | |
259 | + new OctetString("fullNotifyView"), | |
260 | + StorageType.nonVolatile); | |
261 | + | |
262 | + vacm.addAccess(new OctetString("v1v2group"), new OctetString("public"), | |
263 | + SecurityModel.SECURITY_MODEL_ANY, | |
264 | + SecurityLevel.NOAUTH_NOPRIV, | |
265 | + MutableVACM.VACM_MATCH_EXACT, | |
266 | + new OctetString("fullReadView"), | |
267 | + new OctetString("fullWriteView"), | |
268 | + new OctetString("fullNotifyView"), | |
269 | + StorageType.nonVolatile); | |
270 | + vacm.addAccess(new OctetString("v3group"), new OctetString(), | |
271 | + SecurityModel.SECURITY_MODEL_USM, | |
272 | + SecurityLevel.AUTH_PRIV, | |
273 | + MutableVACM.VACM_MATCH_EXACT, | |
274 | + new OctetString("fullReadView"), | |
275 | + new OctetString("fullWriteView"), | |
276 | + new OctetString("fullNotifyView"), | |
277 | + StorageType.nonVolatile); | |
278 | + vacm.addAccess(new OctetString("v3restricted"), new OctetString(), | |
279 | + SecurityModel.SECURITY_MODEL_USM, | |
280 | + SecurityLevel.NOAUTH_NOPRIV, | |
281 | + MutableVACM.VACM_MATCH_EXACT, | |
282 | + new OctetString("restrictedReadView"), | |
283 | + new OctetString("restrictedWriteView"), | |
284 | + new OctetString("restrictedNotifyView"), | |
285 | + StorageType.nonVolatile); | |
286 | + vacm.addAccess(new OctetString("v3test"), new OctetString(), | |
287 | + SecurityModel.SECURITY_MODEL_USM, | |
288 | + SecurityLevel.AUTH_PRIV, | |
289 | + MutableVACM.VACM_MATCH_EXACT, | |
290 | + new OctetString("testReadView"), | |
291 | + new OctetString("testWriteView"), | |
292 | + new OctetString("testNotifyView"), | |
293 | + StorageType.nonVolatile); | |
294 | + | |
295 | + vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"), | |
296 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
297 | + StorageType.nonVolatile); | |
298 | + vacm.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"), | |
299 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
300 | + StorageType.nonVolatile); | |
301 | + vacm.addViewTreeFamily(new OctetString("fullNotifyView"), new OID("1.3"), | |
302 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
303 | + StorageType.nonVolatile); | |
304 | + | |
305 | + vacm.addViewTreeFamily(new OctetString("restrictedReadView"), | |
306 | + new OID("1.3.6.1.2"), | |
307 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
308 | + StorageType.nonVolatile); | |
309 | + vacm.addViewTreeFamily(new OctetString("restrictedWriteView"), | |
310 | + new OID("1.3.6.1.2.1"), | |
311 | + new OctetString(), | |
312 | + VacmMIB.vacmViewIncluded, | |
313 | + StorageType.nonVolatile); | |
314 | + vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"), | |
315 | + new OID("1.3.6.1.2"), | |
316 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
317 | + StorageType.nonVolatile); | |
318 | + vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"), | |
319 | + new OID("1.3.6.1.6.3.1"), | |
320 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
321 | + StorageType.nonVolatile); | |
322 | + | |
323 | + vacm.addViewTreeFamily(new OctetString("testReadView"), | |
324 | + new OID("1.3.6.1.2"), | |
325 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
326 | + StorageType.nonVolatile); | |
327 | + vacm.addViewTreeFamily(new OctetString("testReadView"), | |
328 | + new OID("1.3.6.1.2.1.1"), | |
329 | + new OctetString(), VacmMIB.vacmViewExcluded, | |
330 | + StorageType.nonVolatile); | |
331 | + vacm.addViewTreeFamily(new OctetString("testWriteView"), | |
332 | + new OID("1.3.6.1.2.1"), | |
333 | + new OctetString(), | |
334 | + VacmMIB.vacmViewIncluded, | |
335 | + StorageType.nonVolatile); | |
336 | + vacm.addViewTreeFamily(new OctetString("testNotifyView"), | |
337 | + new OID("1.3.6.1.2"), | |
338 | + new OctetString(), VacmMIB.vacmViewIncluded, | |
339 | + StorageType.nonVolatile); | |
340 | + | |
341 | + } | |
342 | + | |
343 | + protected void addUsmUser(USM usm) { | |
344 | + UsmUser user = new UsmUser(new OctetString("SHADES"), | |
345 | + AuthSHA.ID, | |
346 | + new OctetString("SHADESAuthPassword"), | |
347 | + PrivDES.ID, | |
348 | + new OctetString("SHADESPrivPassword")); | |
349 | +// usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
350 | + usm.addUser(user.getSecurityName(), null, user); | |
351 | + user = new UsmUser(new OctetString("TEST"), | |
352 | + AuthSHA.ID, | |
353 | + new OctetString("maplesyrup"), | |
354 | + PrivDES.ID, | |
355 | + new OctetString("maplesyrup")); | |
356 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
357 | + user = new UsmUser(new OctetString("SHA"), | |
358 | + AuthSHA.ID, | |
359 | + new OctetString("SHAAuthPassword"), | |
360 | + null, | |
361 | + null); | |
362 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
363 | + user = new UsmUser(new OctetString("SHADES"), | |
364 | + AuthSHA.ID, | |
365 | + new OctetString("SHADESAuthPassword"), | |
366 | + PrivDES.ID, | |
367 | + new OctetString("SHADESPrivPassword")); | |
368 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
369 | + user = new UsmUser(new OctetString("MD5DES"), | |
370 | + AuthMD5.ID, | |
371 | + new OctetString("MD5DESAuthPassword"), | |
372 | + PrivDES.ID, | |
373 | + new OctetString("MD5DESPrivPassword")); | |
374 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
375 | + user = new UsmUser(new OctetString("SHAAES128"), | |
376 | + AuthSHA.ID, | |
377 | + new OctetString("SHAAES128AuthPassword"), | |
378 | + PrivAES128.ID, | |
379 | + new OctetString("SHAAES128PrivPassword")); | |
380 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
381 | + user = new UsmUser(new OctetString("SHAAES192"), | |
382 | + AuthSHA.ID, | |
383 | + new OctetString("SHAAES192AuthPassword"), | |
384 | + PrivAES192.ID, | |
385 | + new OctetString("SHAAES192PrivPassword")); | |
386 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
387 | + user = new UsmUser(new OctetString("SHAAES256"), | |
388 | + AuthSHA.ID, | |
389 | + new OctetString("SHAAES256AuthPassword"), | |
390 | + PrivAES256.ID, | |
391 | + new OctetString("SHAAES256PrivPassword")); | |
392 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
393 | + | |
394 | + user = new UsmUser(new OctetString("MD5AES128"), | |
395 | + AuthMD5.ID, | |
396 | + new OctetString("MD5AES128AuthPassword"), | |
397 | + PrivAES128.ID, | |
398 | + new OctetString("MD5AES128PrivPassword")); | |
399 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
400 | + user = new UsmUser(new OctetString("MD5AES192"), | |
401 | + AuthHMAC192SHA256.ID, | |
402 | + new OctetString("MD5AES192AuthPassword"), | |
403 | + PrivAES192.ID, | |
404 | + new OctetString("MD5AES192PrivPassword")); | |
405 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
406 | + //============================================================== | |
407 | + user = new UsmUser(new OctetString("MD5AES256"), | |
408 | + AuthMD5.ID, | |
409 | + new OctetString("MD5AES256AuthPassword"), | |
410 | + PrivAES256.ID, | |
411 | + new OctetString("MD5AES256PrivPassword")); | |
412 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
413 | + user = new UsmUser(new OctetString("MD5AES256"), | |
414 | + AuthMD5.ID, | |
415 | + new OctetString("MD5AES256AuthPassword"), | |
416 | + PrivAES256.ID, | |
417 | + new OctetString("MD5AES256PrivPassword")); | |
418 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
419 | + | |
420 | + OctetString securityName = new OctetString("aboba"); | |
421 | + OctetString authenticationPassphrase = new OctetString("abobaaboba"); | |
422 | + OctetString privacyPassphrase = new OctetString("abobaaboba"); | |
423 | + OID authenticationProtocol = AuthSHA.ID; | |
424 | + OID privacyProtocol = PrivDES.ID; // FIXME: to config | |
425 | + user = new UsmUser(securityName, authenticationProtocol, authenticationPassphrase, privacyProtocol, privacyPassphrase); | |
426 | + usm.addUser(user); | |
427 | + | |
428 | + //===============================================================// | |
429 | + user = new UsmUser(new OctetString("agent5"), | |
430 | + AuthSHA.ID, | |
431 | + new OctetString("authpass"), | |
432 | + PrivDES.ID, | |
433 | + new OctetString("privpass")); | |
434 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
435 | + //===============================================================// | |
436 | + // user001 | |
437 | + user = new UsmUser(new OctetString("user001"), | |
438 | + AuthSHA.ID, | |
439 | + new OctetString("authpass"), | |
440 | + null, null); | |
441 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
442 | + //===============================================================// | |
443 | + // user002 | |
444 | + user = new UsmUser(new OctetString("user001"), | |
445 | + null, | |
446 | + null, | |
447 | + null, null); | |
448 | + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user); | |
449 | + //===============================================================// | |
450 | + | |
451 | + user = new UsmUser(new OctetString("v3notify"), | |
452 | + null, | |
453 | + null, | |
454 | + null, | |
455 | + null); | |
456 | + usm.addUser(user.getSecurityName(), null, user); | |
457 | + | |
458 | + this.usm = usm; | |
459 | + } | |
460 | + | |
461 | + private static DefaultMOTable createStaticIfXTable() { | |
462 | + MOTableSubIndex[] subIndexes = | |
463 | + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) }; | |
464 | + MOTableIndex indexDef = new MOTableIndex(subIndexes, false); | |
465 | + MOColumn[] columns = new MOColumn[19]; | |
466 | + int c = 0; | |
467 | + columns[c++] = | |
468 | + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING, | |
469 | + MOAccessImpl.ACCESS_READ_ONLY); // ifName | |
470 | + columns[c++] = | |
471 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
472 | + MOAccessImpl.ACCESS_READ_ONLY); // ifInMulticastPkts | |
473 | + columns[c++] = | |
474 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
475 | + MOAccessImpl.ACCESS_READ_ONLY); // ifInBroadcastPkts | |
476 | + columns[c++] = | |
477 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
478 | + MOAccessImpl.ACCESS_READ_ONLY); // ifOutMulticastPkts | |
479 | + columns[c++] = | |
480 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
481 | + MOAccessImpl.ACCESS_READ_ONLY); // ifOutBroadcastPkts | |
482 | + columns[c++] = | |
483 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
484 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInOctets | |
485 | + columns[c++] = | |
486 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
487 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInUcastPkts | |
488 | + columns[c++] = | |
489 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
490 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInMulticastPkts | |
491 | + columns[c++] = | |
492 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
493 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInBroadcastPkts | |
494 | + columns[c++] = | |
495 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
496 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutOctets | |
497 | + columns[c++] = | |
498 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
499 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutUcastPkts | |
500 | + columns[c++] = | |
501 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
502 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutMulticastPkts | |
503 | + columns[c++] = | |
504 | + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32, | |
505 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutBroadcastPkts | |
506 | + columns[c++] = | |
507 | + new MOColumn(c, SMIConstants.SYNTAX_INTEGER, | |
508 | + MOAccessImpl.ACCESS_READ_WRITE); // ifLinkUpDownTrapEnable | |
509 | + columns[c++] = | |
510 | + new MOColumn(c, SMIConstants.SYNTAX_GAUGE32, | |
511 | + MOAccessImpl.ACCESS_READ_ONLY); // ifHighSpeed | |
512 | + columns[c++] = | |
513 | + new MOColumn(c, SMIConstants.SYNTAX_INTEGER, | |
514 | + MOAccessImpl.ACCESS_READ_WRITE); // ifPromiscuousMode | |
515 | + columns[c++] = | |
516 | + new MOColumn(c, SMIConstants.SYNTAX_INTEGER, | |
517 | + MOAccessImpl.ACCESS_READ_ONLY); // ifConnectorPresent | |
518 | + columns[c++] = | |
519 | + new MOMutableColumn(c, SMIConstants.SYNTAX_OCTET_STRING, // ifAlias | |
520 | + MOAccessImpl.ACCESS_READ_WRITE, null); | |
521 | + columns[c++] = | |
522 | + new MOColumn(c, SMIConstants.SYNTAX_TIMETICKS, | |
523 | + MOAccessImpl.ACCESS_READ_ONLY); // ifCounterDiscontinuityTime | |
524 | + | |
525 | + DefaultMOTable ifXTable = | |
526 | + new DefaultMOTable(new OID("1.3.6.1.2.1.31.1.1.1"), indexDef, columns); | |
527 | + MOMutableTableModel model = (MOMutableTableModel) ifXTable.getModel(); | |
528 | + Variable[] rowValues1 = new Variable[] { | |
529 | + new OctetString("Ethernet-0"), | |
530 | + new Integer32(1), | |
531 | + new Integer32(2), | |
532 | + new Integer32(3), | |
533 | + new Integer32(4), | |
534 | + new Integer32(5), | |
535 | + new Integer32(6), | |
536 | + new Integer32(7), | |
537 | + new Integer32(8), | |
538 | + new Integer32(9), | |
539 | + new Integer32(10), | |
540 | + new Integer32(11), | |
541 | + new Integer32(12), | |
542 | + new Integer32(13), | |
543 | + new Integer32(14), | |
544 | + new Integer32(15), | |
545 | + new Integer32(16), | |
546 | + new OctetString("My eth"), | |
547 | + new TimeTicks(1000) | |
548 | + }; | |
549 | + Variable[] rowValues2 = new Variable[] { | |
550 | + new OctetString("Loopback"), | |
551 | + new Integer32(21), | |
552 | + new Integer32(22), | |
553 | + new Integer32(23), | |
554 | + new Integer32(24), | |
555 | + new Integer32(25), | |
556 | + new Integer32(26), | |
557 | + new Integer32(27), | |
558 | + new Integer32(28), | |
559 | + new Integer32(29), | |
560 | + new Integer32(30), | |
561 | + new Integer32(31), | |
562 | + new Integer32(32), | |
563 | + new Integer32(33), | |
564 | + new Integer32(34), | |
565 | + new Integer32(35), | |
566 | + new Integer32(36), | |
567 | + new OctetString("My loop"), | |
568 | + new TimeTicks(2000) | |
569 | + }; | |
570 | + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1)); | |
571 | + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2)); | |
572 | + ifXTable.setVolatile(true); | |
573 | + return ifXTable; | |
574 | + } | |
575 | + | |
576 | + private static DefaultMOTable createStaticIfTable() { | |
577 | + MOTableSubIndex[] subIndexes = | |
578 | + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) }; | |
579 | + MOTableIndex indexDef = new MOTableIndex(subIndexes, false); | |
580 | + MOColumn[] columns = new MOColumn[8]; | |
581 | + int c = 0; | |
582 | + columns[c++] = | |
583 | + new MOColumn(c, SMIConstants.SYNTAX_INTEGER, | |
584 | + MOAccessImpl.ACCESS_READ_ONLY); // ifIndex | |
585 | + columns[c++] = | |
586 | + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING, | |
587 | + MOAccessImpl.ACCESS_READ_ONLY); // ifDescr | |
588 | + columns[c++] = | |
589 | + new MOColumn(c, SMIConstants.SYNTAX_INTEGER, | |
590 | + MOAccessImpl.ACCESS_READ_ONLY); // ifType | |
591 | + columns[c++] = | |
592 | + new MOColumn(c, SMIConstants.SYNTAX_INTEGER, | |
593 | + MOAccessImpl.ACCESS_READ_ONLY); // ifMtu | |
594 | + columns[c++] = | |
595 | + new MOColumn(c, SMIConstants.SYNTAX_GAUGE32, | |
596 | + MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed | |
597 | + columns[c++] = | |
598 | + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING, | |
599 | + MOAccessImpl.ACCESS_READ_ONLY); // ifPhysAddress | |
600 | + columns[c++] = | |
601 | + new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, // ifAdminStatus | |
602 | + MOAccessImpl.ACCESS_READ_WRITE, null); | |
603 | + columns[c++] = | |
604 | + new MOColumn(c, SMIConstants.SYNTAX_INTEGER, | |
605 | + MOAccessImpl.ACCESS_READ_ONLY); // ifOperStatus | |
606 | + | |
607 | + DefaultMOTable ifTable = | |
608 | + new DefaultMOTable(new OID("1.3.6.1.2.1.2.2.1"), indexDef, columns); | |
609 | + MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel(); | |
610 | + Variable[] rowValues1 = new Variable[] { | |
611 | + new Integer32(1), | |
612 | + new OctetString("eth0"), | |
613 | + new Integer32(6), | |
614 | + new Integer32(1500), | |
615 | + new Gauge32(100000000), | |
616 | + new OctetString("00:00:00:00:01"), | |
617 | + new Integer32(1), | |
618 | + new Integer32(1) | |
619 | + }; | |
620 | + Variable[] rowValues2 = new Variable[] { | |
621 | + new Integer32(2), | |
622 | + new OctetString("loopback"), | |
623 | + new Integer32(24), | |
624 | + new Integer32(1500), | |
625 | + new Gauge32(10000000), | |
626 | + new OctetString("00:00:00:00:02"), | |
627 | + new Integer32(1), | |
628 | + new Integer32(1) | |
629 | + }; | |
630 | + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1)); | |
631 | + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2)); | |
632 | + ifTable.setVolatile(true); | |
633 | + return ifTable; | |
634 | + } | |
635 | + | |
636 | + private static DefaultMOTable createStaticSnmp4sTable() { | |
637 | + MOTableSubIndex[] subIndexes = | |
638 | + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) }; | |
639 | + MOTableIndex indexDef = new MOTableIndex(subIndexes, false); | |
640 | + MOColumn[] columns = new MOColumn[8]; | |
641 | + int c = 0; | |
642 | + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_NULL, MOAccessImpl.ACCESS_READ_ONLY); // testNull | |
643 | + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // testBoolean | |
644 | + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifType | |
645 | + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifMtu | |
646 | + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_GAUGE32, MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed | |
647 | + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING, MOAccessImpl.ACCESS_READ_ONLY); //ifPhysAddress | |
648 | + columns[c++] = new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_WRITE, | |
649 | + null); | |
650 | + // ifAdminStatus | |
651 | + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); | |
652 | + // ifOperStatus | |
653 | + | |
654 | + DefaultMOTable ifTable = | |
655 | + new DefaultMOTable(new OID("1.3.6.1.4.1.50000.1.1"), indexDef, columns); | |
656 | + MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel(); | |
657 | + Variable[] rowValues1 = new Variable[] { | |
658 | + new Integer32(1), | |
659 | + new OctetString("eth0"), | |
660 | + new Integer32(6), | |
661 | + new Integer32(1500), | |
662 | + new Gauge32(100000000), | |
663 | + new OctetString("00:00:00:00:01"), | |
664 | + new Integer32(1), | |
665 | + new Integer32(1) | |
666 | + }; | |
667 | + Variable[] rowValues2 = new Variable[] { | |
668 | + new Integer32(2), | |
669 | + new OctetString("loopback"), | |
670 | + new Integer32(24), | |
671 | + new Integer32(1500), | |
672 | + new Gauge32(10000000), | |
673 | + new OctetString("00:00:00:00:02"), | |
674 | + new Integer32(1), | |
675 | + new Integer32(1) | |
676 | + }; | |
677 | + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1)); | |
678 | + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2)); | |
679 | + ifTable.setVolatile(true); | |
680 | + return ifTable; | |
681 | + } | |
682 | + | |
683 | + protected void initTransportMappings() throws IOException { | |
684 | + transportMappings = new TransportMapping[2]; | |
685 | + Address addr = GenericAddress.parse(address); | |
686 | + TransportMapping tm = | |
687 | + TransportMappings.getInstance().createTransportMapping(addr); | |
688 | + transportMappings[0] = tm; | |
689 | + transportMappings[1] = new DefaultTcpTransportMapping(new TcpAddress(address)); | |
690 | + } | |
691 | + | |
692 | + public void start(String ip, String port) throws IOException { | |
693 | + address = ip + "/" + port; | |
694 | + //BasicConfigurator.configure(); | |
695 | + init(); | |
696 | + addShutdownHook(); | |
697 | +// loadConfig(ImportModes.REPLACE_CREATE); | |
698 | + getServer().addContext(new OctetString("public")); | |
699 | + finishInit(); | |
700 | + run(); | |
701 | + sendColdStartNotification(); | |
702 | + } | |
703 | + | |
704 | + protected void unregisterManagedObjects() { | |
705 | + // here we should unregister those objects previously registered... | |
706 | + } | |
707 | + | |
708 | + protected void addCommunities(SnmpCommunityMIB communityMIB) { | |
709 | + Variable[] com2sec = new Variable[] { | |
710 | + new OctetString("public"), // community name | |
711 | + new OctetString("cpublic"), // security name | |
712 | + getAgent().getContextEngineID(), // local engine ID | |
713 | + new OctetString("public"), // default context name | |
714 | + new OctetString(), // transport tag | |
715 | + new Integer32(StorageType.nonVolatile), // storage type | |
716 | + new Integer32(RowStatus.active) // row status | |
717 | + }; | |
718 | + MOTableRow row = | |
719 | + communityMIB.getSnmpCommunityEntry().createRow( | |
720 | + new OctetString("public2public").toSubIndex(true), com2sec); | |
721 | + communityMIB.getSnmpCommunityEntry().addRow((SnmpCommunityMIB.SnmpCommunityEntryRow) row); | |
722 | +// snmpCommunityMIB.setSourceAddressFiltering(true); | |
723 | + } | |
724 | + | |
725 | + protected void registerSnmpMIBs() { | |
726 | + heartbeatMIB = new Snmp4jHeartbeatMib(super.getNotificationOriginator(), | |
727 | + new OctetString(), | |
728 | + super.snmpv2MIB.getSysUpTime()); | |
729 | + agentppSimulationMIB = new AgentppSimulationMib(); | |
730 | + super.registerSnmpMIBs(); | |
731 | + } | |
732 | + | |
733 | + protected void initMessageDispatcher() { | |
734 | + this.dispatcher = new MessageDispatcherImpl(); | |
735 | + this.mpv3 = new MPv3(this.agent.getContextEngineID().getValue()); | |
736 | + this.usm = new USM(SecurityProtocols.getInstance(), this.agent.getContextEngineID(), this.updateEngineBoots()); | |
737 | + SecurityModels.getInstance().addSecurityModel(this.usm); | |
738 | + SecurityProtocols.getInstance().addDefaultProtocols(); | |
739 | + this.dispatcher.addMessageProcessingModel(new MPv1()); | |
740 | + this.dispatcher.addMessageProcessingModel(new MPv2c()); | |
741 | + this.dispatcher.addMessageProcessingModel(this.mpv3); | |
742 | + this.initSnmpSession(); | |
743 | + } | |
744 | + | |
745 | +} | |
\ No newline at end of file | ... | ... |
common/transport/snmp/src/test/java/org/thingsboard/server/transport/snmp/SnmpTestV2.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp; | |
17 | + | |
18 | +import java.io.IOException; | |
19 | +import java.util.Map; | |
20 | +import java.util.Scanner; | |
21 | + | |
22 | +public class SnmpTestV2 { | |
23 | + public static void main(String[] args) throws IOException { | |
24 | + SnmpDeviceSimulatorV2 device = new SnmpDeviceSimulatorV2(1610, "public"); | |
25 | + | |
26 | + device.start(); | |
27 | + device.setUpMappings(Map.of( | |
28 | + ".1.3.6.1.2.1.1.1.50", "12", | |
29 | + ".1.3.6.1.2.1.2.1.52", "56", | |
30 | + ".1.3.6.1.2.1.3.1.54", "yes", | |
31 | + ".1.3.6.1.2.1.7.1.58", "" | |
32 | + )); | |
33 | + | |
34 | + | |
35 | +// while (true) { | |
36 | +// new Scanner(System.in).nextLine(); | |
37 | +// device.sendTrap("127.0.0.1", 1062, Map.of(".1.3.6.1.2.87.1.56", "12")); | |
38 | +// System.out.println("sent"); | |
39 | +// } | |
40 | + | |
41 | +// Snmp snmp = new Snmp(device.transportMappings[0]); | |
42 | +// device.snmp.addCommandResponder(event -> { | |
43 | +// System.out.println(event); | |
44 | +// }); | |
45 | + | |
46 | + new Scanner(System.in).nextLine(); | |
47 | + } | |
48 | + | |
49 | +} | ... | ... |
common/transport/snmp/src/test/java/org/thingsboard/server/transport/snmp/SnmpTestV3.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp; | |
17 | + | |
18 | +import org.snmp4j.CommandResponderEvent; | |
19 | +import org.snmp4j.agent.CommandProcessor; | |
20 | +import org.snmp4j.mp.MPv3; | |
21 | +import org.snmp4j.smi.OctetString; | |
22 | + | |
23 | +import java.io.IOException; | |
24 | +import java.util.Map; | |
25 | +import java.util.Scanner; | |
26 | + | |
27 | +public class SnmpTestV3 { | |
28 | + public static void main(String[] args) throws IOException { | |
29 | + SnmpDeviceSimulatorV3 device = new SnmpDeviceSimulatorV3(new CommandProcessor(new OctetString(MPv3.createLocalEngineID())) { | |
30 | + @Override | |
31 | + public void processPdu(CommandResponderEvent event) { | |
32 | + System.out.println("event: " + event); | |
33 | + } | |
34 | + }); | |
35 | + device.start("0.0.0.0", "1610"); | |
36 | + | |
37 | + device.setUpMappings(Map.of( | |
38 | + ".1.3.6.1.2.1.1.1.50", "12", | |
39 | + ".1.3.6.1.2.1.2.1.52", "56", | |
40 | + ".1.3.6.1.2.1.3.1.54", "yes", | |
41 | + ".1.3.6.1.2.1.7.1.58", "" | |
42 | + )); | |
43 | + | |
44 | + new Scanner(System.in).nextLine(); | |
45 | + } | |
46 | +} | ... | ... |
1 | +{ | |
2 | + "timeoutMs": 500, | |
3 | + "retries": 0, | |
4 | + "communicationConfigs": [ | |
5 | + { | |
6 | + "spec": "TELEMETRY_QUERYING", | |
7 | + "queryingFrequencyMs": 3000, | |
8 | + "mappings": [ | |
9 | + { | |
10 | + "oid": ".1.3.6.1.2.1.1.1.50", | |
11 | + "key": "temperature", | |
12 | + "dataType": "LONG" | |
13 | + }, | |
14 | + { | |
15 | + "oid": ".1.3.6.1.2.1.2.1.52", | |
16 | + "key": "humidity", | |
17 | + "dataType": "DOUBLE" | |
18 | + } | |
19 | + ] | |
20 | + }, | |
21 | + { | |
22 | + "spec": "CLIENT_ATTRIBUTES_QUERYING", | |
23 | + "queryingFrequencyMs": 5000, | |
24 | + "mappings": [ | |
25 | + { | |
26 | + "oid": ".1.3.6.1.2.1.3.1.54", | |
27 | + "key": "isCool", | |
28 | + "dataType": "STRING" | |
29 | + } | |
30 | + ] | |
31 | + }, | |
32 | + { | |
33 | + "spec": "SHARED_ATTRIBUTES_SETTING", | |
34 | + "mappings": [ | |
35 | + { | |
36 | + "oid": ".1.3.6.1.2.1.7.1.58", | |
37 | + "key": "shared", | |
38 | + "dataType": "STRING" | |
39 | + } | |
40 | + ] | |
41 | + } | |
42 | + ] | |
43 | +} | ... | ... |
1 | +{ | |
2 | + "address": "192.168.3.23", | |
3 | + "port": 1610, | |
4 | + "protocolVersion": "V3", | |
5 | + | |
6 | + "username": "tb-user", | |
7 | + "engineId": "qwertyuioa", | |
8 | + "securityName": "tb-user", | |
9 | + "authenticationProtocol": "SHA_512", | |
10 | + "authenticationPassphrase": "sdfghjkloifgh", | |
11 | + "privacyProtocol": "DES", | |
12 | + "privacyPassphrase": "rtytguijokod" | |
13 | +} | |
\ No newline at end of file | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.transport; | |
17 | + | |
18 | +import lombok.Getter; | |
19 | +import org.thingsboard.server.common.data.Device; | |
20 | + | |
21 | +@Getter | |
22 | +public class DeviceUpdatedEvent { | |
23 | + private final Device device; | |
24 | + | |
25 | + public DeviceUpdatedEvent(Device device) { | |
26 | + this.device = device; | |
27 | + } | |
28 | +} | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.common.transport; |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.Device; |
19 | 19 | import org.thingsboard.server.common.data.DeviceProfile; |
20 | +import org.thingsboard.server.common.data.id.DeviceId; | |
20 | 21 | import org.thingsboard.server.gen.transport.TransportProtos; |
21 | 22 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
22 | 23 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; |
... | ... | @@ -49,6 +50,8 @@ public interface SessionMsgListener { |
49 | 50 | default void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, |
50 | 51 | Optional<DeviceProfile> deviceProfileOpt) {} |
51 | 52 | |
53 | + default void onDeviceDeleted(DeviceId deviceId) {} | |
54 | + | |
52 | 55 | default void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {} |
53 | 56 | |
54 | 57 | default void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceUpdateMsgOpt) {} | ... | ... |
... | ... | @@ -22,6 +22,10 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes |
22 | 22 | import org.thingsboard.server.common.transport.service.SessionMetaData; |
23 | 23 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; |
24 | 24 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
25 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceCredentialsRequestMsg; | |
26 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceCredentialsResponseMsg; | |
27 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceRequestMsg; | |
28 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceResponseMsg; | |
25 | 29 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; |
26 | 30 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; |
27 | 31 | import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareRequestMsg; |
... | ... | @@ -29,6 +33,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareResponseM |
29 | 33 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
30 | 34 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; |
31 | 35 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceResponseMsg; |
36 | +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesRequestMsg; | |
37 | +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesResponseMsg; | |
32 | 38 | import org.thingsboard.server.gen.transport.TransportProtos.LwM2MRequestMsg; |
33 | 39 | import org.thingsboard.server.gen.transport.TransportProtos.LwM2MResponseMsg; |
34 | 40 | import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; |
... | ... | @@ -57,6 +63,12 @@ public interface TransportService { |
57 | 63 | |
58 | 64 | GetResourceResponseMsg getResource(GetResourceRequestMsg msg); |
59 | 65 | |
66 | + GetSnmpDevicesResponseMsg getSnmpDevicesIds(GetSnmpDevicesRequestMsg requestMsg); | |
67 | + | |
68 | + GetDeviceResponseMsg getDevice(GetDeviceRequestMsg requestMsg); | |
69 | + | |
70 | + GetDeviceCredentialsResponseMsg getDeviceCredentials(GetDeviceCredentialsRequestMsg requestMsg); | |
71 | + | |
60 | 72 | void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg, |
61 | 73 | TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); |
62 | 74 | ... | ... |
... | ... | @@ -289,7 +289,7 @@ public class JsonConverter { |
289 | 289 | return result; |
290 | 290 | } |
291 | 291 | |
292 | - public static JsonElement toJson(AttributeUpdateNotificationMsg payload) { | |
292 | + public static JsonObject toJson(AttributeUpdateNotificationMsg payload) { | |
293 | 293 | JsonObject result = new JsonObject(); |
294 | 294 | if (payload.getSharedUpdatedCount() > 0) { |
295 | 295 | payload.getSharedUpdatedList().forEach(addToObjectFromProto(result)); |
... | ... | @@ -558,6 +558,14 @@ public class JsonConverter { |
558 | 558 | } |
559 | 559 | } |
560 | 560 | |
561 | + public static JsonElement parse(String json) { | |
562 | + return JSON_PARSER.parse(json); | |
563 | + } | |
564 | + | |
565 | + public static String toJson(JsonElement element) { | |
566 | + return GSON.toJson(element); | |
567 | + } | |
568 | + | |
561 | 569 | public static void setTypeCastEnabled(boolean enabled) { |
562 | 570 | isTypeCastEnabled = enabled; |
563 | 571 | } |
... | ... | @@ -599,8 +607,7 @@ public class JsonConverter { |
599 | 607 | .build(); |
600 | 608 | } |
601 | 609 | |
602 | - private static TransportProtos.ProvisionDeviceCredentialsMsg buildProvisionDeviceCredentialsMsg(String | |
603 | - provisionKey, String provisionSecret) { | |
610 | + private static TransportProtos.ProvisionDeviceCredentialsMsg buildProvisionDeviceCredentialsMsg(String provisionKey, String provisionSecret) { | |
604 | 611 | return TransportProtos.ProvisionDeviceCredentialsMsg.newBuilder() |
605 | 612 | .setProvisionDeviceKey(provisionKey) |
606 | 613 | .setProvisionDeviceSecret(provisionSecret) | ... | ... |
... | ... | @@ -112,8 +112,8 @@ public class DefaultTransportDeviceProfileCache implements TransportDeviceProfil |
112 | 112 | profile = profileOpt.get(); |
113 | 113 | this.put(profile); |
114 | 114 | } else { |
115 | - log.warn("[{}] Can't device profile: {}", id, entityProfileMsg.getData()); | |
116 | - throw new RuntimeException("Can't device profile!"); | |
115 | + log.warn("[{}] Can't find device profile: {}", id, entityProfileMsg.getData()); | |
116 | + throw new RuntimeException("Can't find device profile!"); | |
117 | 117 | } |
118 | 118 | } finally { |
119 | 119 | deviceProfileFetchLock.unlock(); | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import com.google.gson.JsonObject; |
23 | 23 | import com.google.protobuf.ByteString; |
24 | 24 | import lombok.extern.slf4j.Slf4j; |
25 | 25 | import org.springframework.beans.factory.annotation.Value; |
26 | +import org.springframework.context.ApplicationEventPublisher; | |
26 | 27 | import org.springframework.stereotype.Service; |
27 | 28 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
28 | 29 | import org.thingsboard.server.common.data.ApiUsageRecordKey; |
... | ... | @@ -50,6 +51,7 @@ import org.thingsboard.server.common.msg.tools.TbRateLimitsException; |
50 | 51 | import org.thingsboard.server.common.stats.MessagesStats; |
51 | 52 | import org.thingsboard.server.common.stats.StatsFactory; |
52 | 53 | import org.thingsboard.server.common.stats.StatsType; |
54 | +import org.thingsboard.server.common.transport.DeviceUpdatedEvent; | |
53 | 55 | import org.thingsboard.server.common.transport.SessionMsgListener; |
54 | 56 | import org.thingsboard.server.common.transport.TransportDeviceProfileCache; |
55 | 57 | import org.thingsboard.server.common.transport.TransportResourceCache; |
... | ... | @@ -134,6 +136,7 @@ public class DefaultTransportService implements TransportService { |
134 | 136 | private final TransportRateLimitService rateLimitService; |
135 | 137 | private final DataDecodingEncodingService dataDecodingEncodingService; |
136 | 138 | private final SchedulerComponent scheduler; |
139 | + private final ApplicationEventPublisher eventPublisher; | |
137 | 140 | private final TransportResourceCache transportResourceCache; |
138 | 141 | |
139 | 142 | protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate; |
... | ... | @@ -161,7 +164,8 @@ public class DefaultTransportService implements TransportService { |
161 | 164 | TransportDeviceProfileCache deviceProfileCache, |
162 | 165 | TransportTenantProfileCache tenantProfileCache, |
163 | 166 | TbApiUsageClient apiUsageClient, TransportRateLimitService rateLimitService, |
164 | - DataDecodingEncodingService dataDecodingEncodingService, SchedulerComponent scheduler, TransportResourceCache transportResourceCache) { | |
167 | + DataDecodingEncodingService dataDecodingEncodingService, SchedulerComponent scheduler, TransportResourceCache transportResourceCache, | |
168 | + ApplicationEventPublisher eventPublisher) { | |
165 | 169 | this.serviceInfoProvider = serviceInfoProvider; |
166 | 170 | this.queueProvider = queueProvider; |
167 | 171 | this.producerProvider = producerProvider; |
... | ... | @@ -174,6 +178,7 @@ public class DefaultTransportService implements TransportService { |
174 | 178 | this.dataDecodingEncodingService = dataDecodingEncodingService; |
175 | 179 | this.scheduler = scheduler; |
176 | 180 | this.transportResourceCache = transportResourceCache; |
181 | + this.eventPublisher = eventPublisher; | |
177 | 182 | } |
178 | 183 | |
179 | 184 | @PostConstruct |
... | ... | @@ -272,6 +277,58 @@ public class DefaultTransportService implements TransportService { |
272 | 277 | } |
273 | 278 | |
274 | 279 | @Override |
280 | + public TransportProtos.GetSnmpDevicesResponseMsg getSnmpDevicesIds(TransportProtos.GetSnmpDevicesRequestMsg requestMsg) { | |
281 | + TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>( | |
282 | + UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder() | |
283 | + .setSnmpDevicesRequestMsg(requestMsg) | |
284 | + .build() | |
285 | + ); | |
286 | + | |
287 | + try { | |
288 | + TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get(); | |
289 | + return response.getValue().getSnmpDevicesResponseMsg(); | |
290 | + } catch (InterruptedException | ExecutionException e) { | |
291 | + throw new RuntimeException(e); | |
292 | + } | |
293 | + } | |
294 | + | |
295 | + @Override | |
296 | + public TransportProtos.GetDeviceResponseMsg getDevice(TransportProtos.GetDeviceRequestMsg requestMsg) { | |
297 | + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>( | |
298 | + UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder() | |
299 | + .setDeviceRequestMsg(requestMsg) | |
300 | + .build() | |
301 | + ); | |
302 | + | |
303 | + try { | |
304 | + TransportApiResponseMsg response = transportApiRequestTemplate.send(protoMsg).get().getValue(); | |
305 | + if (response.hasDeviceResponseMsg()) { | |
306 | + return response.getDeviceResponseMsg(); | |
307 | + } else { | |
308 | + return null; | |
309 | + } | |
310 | + } catch (InterruptedException | ExecutionException e) { | |
311 | + throw new RuntimeException(e); | |
312 | + } | |
313 | + } | |
314 | + | |
315 | + @Override | |
316 | + public TransportProtos.GetDeviceCredentialsResponseMsg getDeviceCredentials(TransportProtos.GetDeviceCredentialsRequestMsg requestMsg) { | |
317 | + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>( | |
318 | + UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder() | |
319 | + .setDeviceCredentialsRequestMsg(requestMsg) | |
320 | + .build() | |
321 | + ); | |
322 | + | |
323 | + try { | |
324 | + TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get(); | |
325 | + return response.getValue().getDeviceCredentialsResponseMsg(); | |
326 | + } catch (InterruptedException | ExecutionException e) { | |
327 | + throw new RuntimeException(e); | |
328 | + } | |
329 | + } | |
330 | + | |
331 | + @Override | |
275 | 332 | public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceTokenRequestMsg msg, |
276 | 333 | TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) { |
277 | 334 | log.trace("Processing msg: {}", msg); |
... | ... | @@ -704,7 +761,10 @@ public class DefaultTransportService implements TransportService { |
704 | 761 | } |
705 | 762 | } else if (EntityType.DEVICE.equals(entityType)) { |
706 | 763 | Optional<Device> deviceOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); |
707 | - deviceOpt.ifPresent(this::onDeviceUpdate); | |
764 | + deviceOpt.ifPresent(device -> { | |
765 | + onDeviceUpdate(device); | |
766 | + eventPublisher.publishEvent(new DeviceUpdatedEvent(device)); | |
767 | + }); | |
708 | 768 | } |
709 | 769 | } else if (toSessionMsg.hasEntityDeleteMsg()) { |
710 | 770 | TransportProtos.EntityDeleteMsg msg = toSessionMsg.getEntityDeleteMsg(); |
... | ... | @@ -718,6 +778,7 @@ public class DefaultTransportService implements TransportService { |
718 | 778 | rateLimitService.remove(new TenantId(entityUuid)); |
719 | 779 | } else if (EntityType.DEVICE.equals(entityType)) { |
720 | 780 | rateLimitService.remove(new DeviceId(entityUuid)); |
781 | + onDeviceDeleted(new DeviceId(entityUuid)); | |
721 | 782 | } |
722 | 783 | } else if (toSessionMsg.hasResourceUpdateMsg()) { |
723 | 784 | TransportProtos.ResourceUpdateMsg msg = toSessionMsg.getResourceUpdateMsg(); |
... | ... | @@ -800,6 +861,17 @@ public class DefaultTransportService implements TransportService { |
800 | 861 | }); |
801 | 862 | } |
802 | 863 | |
864 | + private void onDeviceDeleted(DeviceId deviceId) { | |
865 | + sessions.forEach((id, md) -> { | |
866 | + DeviceId sessionDeviceId = new DeviceId(new UUID(md.getSessionInfo().getDeviceIdMSB(), md.getSessionInfo().getDeviceIdLSB())); | |
867 | + if (sessionDeviceId.equals(deviceId)) { | |
868 | + transportCallbackExecutor.submit(() -> { | |
869 | + md.getListener().onDeviceDeleted(deviceId); | |
870 | + }); | |
871 | + } | |
872 | + }); | |
873 | + } | |
874 | + | |
803 | 875 | protected UUID toSessionId(TransportProtos.SessionInfoProto sessionInfo) { |
804 | 876 | return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); |
805 | 877 | } | ... | ... |
... | ... | @@ -18,11 +18,11 @@ package org.thingsboard.server.dao.device; |
18 | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | 19 | import org.thingsboard.server.common.data.Device; |
20 | 20 | import org.thingsboard.server.common.data.DeviceInfo; |
21 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
21 | 22 | import org.thingsboard.server.common.data.EntitySubtype; |
22 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
23 | 24 | import org.thingsboard.server.common.data.page.PageData; |
24 | 25 | import org.thingsboard.server.common.data.page.PageLink; |
25 | -import org.thingsboard.server.common.data.page.TimePageLink; | |
26 | 26 | import org.thingsboard.server.dao.Dao; |
27 | 27 | import org.thingsboard.server.dao.TenantEntityDao; |
28 | 28 | |
... | ... | @@ -219,6 +219,7 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao { |
219 | 219 | */ |
220 | 220 | PageData<Device> findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink); |
221 | 221 | |
222 | + PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink); | |
222 | 223 | |
223 | 224 | /** |
224 | 225 | * Find devices by tenantId, edgeId and page link. | ... | ... |
... | ... | @@ -363,6 +363,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D |
363 | 363 | } |
364 | 364 | |
365 | 365 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); |
366 | + transportConfiguration.validate(); | |
366 | 367 | if (transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) { |
367 | 368 | MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; |
368 | 369 | if (mqttTransportConfiguration.getTransportPayloadTypeConfiguration() instanceof ProtoTransportPayloadConfiguration) { | ... | ... |
... | ... | @@ -36,20 +36,22 @@ import org.thingsboard.server.common.data.Customer; |
36 | 36 | import org.thingsboard.server.common.data.Device; |
37 | 37 | import org.thingsboard.server.common.data.DeviceInfo; |
38 | 38 | import org.thingsboard.server.common.data.DeviceProfile; |
39 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
39 | 40 | import org.thingsboard.server.common.data.EntitySubtype; |
40 | 41 | import org.thingsboard.server.common.data.EntityType; |
41 | 42 | import org.thingsboard.server.common.data.EntityView; |
42 | 43 | import org.thingsboard.server.common.data.Firmware; |
43 | 44 | import org.thingsboard.server.common.data.Tenant; |
44 | -import org.thingsboard.server.common.data.asset.Asset; | |
45 | 45 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
46 | 46 | import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; |
47 | 47 | import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfiguration; |
48 | 48 | import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration; |
49 | 49 | import org.thingsboard.server.common.data.device.data.DefaultDeviceTransportConfiguration; |
50 | 50 | import org.thingsboard.server.common.data.device.data.DeviceData; |
51 | +import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration; | |
51 | 52 | import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration; |
52 | 53 | import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; |
54 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | |
53 | 55 | import org.thingsboard.server.common.data.edge.Edge; |
54 | 56 | import org.thingsboard.server.common.data.id.CustomerId; |
55 | 57 | import org.thingsboard.server.common.data.id.DeviceId; |
... | ... | @@ -59,7 +61,6 @@ import org.thingsboard.server.common.data.id.EntityId; |
59 | 61 | import org.thingsboard.server.common.data.id.TenantId; |
60 | 62 | import org.thingsboard.server.common.data.page.PageData; |
61 | 63 | import org.thingsboard.server.common.data.page.PageLink; |
62 | -import org.thingsboard.server.common.data.page.TimePageLink; | |
63 | 64 | import org.thingsboard.server.common.data.relation.EntityRelation; |
64 | 65 | import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
65 | 66 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
... | ... | @@ -86,6 +87,7 @@ import java.util.Collections; |
86 | 87 | import java.util.Comparator; |
87 | 88 | import java.util.List; |
88 | 89 | import java.util.Optional; |
90 | +import java.util.UUID; | |
89 | 91 | import java.util.concurrent.ExecutionException; |
90 | 92 | import java.util.stream.Collectors; |
91 | 93 | |
... | ... | @@ -269,11 +271,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
269 | 271 | case MQTT: |
270 | 272 | deviceData.setTransportConfiguration(new MqttDeviceTransportConfiguration()); |
271 | 273 | break; |
274 | + case COAP: | |
275 | + deviceData.setTransportConfiguration(new CoapDeviceTransportConfiguration()); | |
276 | + break; | |
272 | 277 | case LWM2M: |
273 | 278 | deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration()); |
274 | 279 | break; |
275 | - case COAP: | |
276 | - deviceData.setTransportConfiguration(new CoapDeviceTransportConfiguration()); | |
280 | + case SNMP: | |
281 | + deviceData.setTransportConfiguration(new SnmpDeviceTransportConfiguration()); | |
277 | 282 | break; |
278 | 283 | } |
279 | 284 | } |
... | ... | @@ -573,6 +578,11 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
573 | 578 | } |
574 | 579 | |
575 | 580 | @Override |
581 | + public PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink) { | |
582 | + return deviceDao.findDevicesIdsByDeviceProfileTransportType(transportType, pageLink); | |
583 | + } | |
584 | + | |
585 | + @Override | |
576 | 586 | public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) { |
577 | 587 | Device device = findDeviceById(tenantId, deviceId); |
578 | 588 | Edge edge = edgeService.findEdgeById(tenantId, edgeId); |
... | ... | @@ -677,6 +687,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
677 | 687 | throw new DataValidationException("Can't assign device to customer from different tenant!"); |
678 | 688 | } |
679 | 689 | } |
690 | + Optional.ofNullable(device.getDeviceData()) | |
691 | + .flatMap(deviceData -> Optional.ofNullable(deviceData.getTransportConfiguration())) | |
692 | + .ifPresent(DeviceTransportConfiguration::validate); | |
680 | 693 | |
681 | 694 | if (device.getFirmwareId() != null) { |
682 | 695 | Firmware firmware = firmwareService.findFirmwareById(tenantId, device.getFirmwareId()); | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable; |
20 | 20 | import org.springframework.data.jpa.repository.Query; |
21 | 21 | import org.springframework.data.repository.PagingAndSortingRepository; |
22 | 22 | import org.springframework.data.repository.query.Param; |
23 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
23 | 24 | import org.thingsboard.server.dao.model.sql.DeviceEntity; |
24 | 25 | import org.thingsboard.server.dao.model.sql.DeviceInfoEntity; |
25 | 26 | |
... | ... | @@ -210,4 +211,9 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit |
210 | 211 | * */ |
211 | 212 | @Query("SELECT count(*) FROM DeviceEntity d WHERE d.tenantId = :tenantId") |
212 | 213 | Long countByTenantId(@Param("tenantId") UUID tenantId); |
214 | + | |
215 | + @Query("SELECT d.id FROM DeviceEntity d " + | |
216 | + "INNER JOIN DeviceProfileEntity p ON d.deviceProfileId = p.id " + | |
217 | + "WHERE p.transportType = :transportType") | |
218 | + Page<UUID> findIdsByDeviceProfileTransportType(@Param("transportType") DeviceTransportType transportType, Pageable pageable); | |
213 | 219 | } | ... | ... |
... | ... | @@ -23,12 +23,12 @@ import org.springframework.stereotype.Component; |
23 | 23 | import org.springframework.util.StringUtils; |
24 | 24 | import org.thingsboard.server.common.data.Device; |
25 | 25 | import org.thingsboard.server.common.data.DeviceInfo; |
26 | +import org.thingsboard.server.common.data.DeviceTransportType; | |
26 | 27 | import org.thingsboard.server.common.data.EntitySubtype; |
27 | 28 | import org.thingsboard.server.common.data.EntityType; |
28 | 29 | import org.thingsboard.server.common.data.id.TenantId; |
29 | 30 | import org.thingsboard.server.common.data.page.PageData; |
30 | 31 | import org.thingsboard.server.common.data.page.PageLink; |
31 | -import org.thingsboard.server.common.data.page.TimePageLink; | |
32 | 32 | import org.thingsboard.server.dao.DaoUtil; |
33 | 33 | import org.thingsboard.server.dao.device.DeviceDao; |
34 | 34 | import org.thingsboard.server.dao.model.sql.DeviceEntity; |
... | ... | @@ -118,6 +118,11 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> |
118 | 118 | } |
119 | 119 | |
120 | 120 | @Override |
121 | + public PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink) { | |
122 | + return DaoUtil.pageToPageData(deviceRepository.findIdsByDeviceProfileTransportType(transportType, DaoUtil.toPageable(pageLink))); | |
123 | + } | |
124 | + | |
125 | + @Override | |
121 | 126 | public PageData<DeviceInfo> findDeviceInfosByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { |
122 | 127 | return DaoUtil.toPageData( |
123 | 128 | deviceRepository.findDeviceInfosByTenantIdAndCustomerId( | ... | ... |
... | ... | @@ -9,6 +9,7 @@ MQTT_TRANSPORT_DOCKER_NAME=tb-mqtt-transport |
9 | 9 | HTTP_TRANSPORT_DOCKER_NAME=tb-http-transport |
10 | 10 | COAP_TRANSPORT_DOCKER_NAME=tb-coap-transport |
11 | 11 | LWM2M_TRANSPORT_DOCKER_NAME=tb-lwm2m-transport |
12 | +SNMP_TRANSPORT_DOCKER_NAME=tb-snmp-transport | |
12 | 13 | |
13 | 14 | TB_VERSION=latest |
14 | 15 | ... | ... |
... | ... | @@ -50,6 +50,9 @@ services: |
50 | 50 | tb-mqtt-transport2: |
51 | 51 | volumes: |
52 | 52 | - tb-mqtt-transport-log-volume:/var/log/tb-mqtt-transport |
53 | + tb-snmp-transport: | |
54 | + volumes: | |
55 | + - tb-snmp-transport-log-volume:/var/log/tb-snmp-transport | |
53 | 56 | |
54 | 57 | volumes: |
55 | 58 | postgres-db-volume: |
... | ... | @@ -70,3 +73,6 @@ volumes: |
70 | 73 | tb-mqtt-transport-log-volume: |
71 | 74 | external: true |
72 | 75 | name: ${TB_MQTT_TRANSPORT_LOG_VOLUME} |
76 | + tb-snmp-transport-log-volume: | |
77 | + external: true | |
78 | + name: ${TB_SNMP_TRANSPORT_LOG_VOLUME} | ... | ... |
... | ... | @@ -217,6 +217,18 @@ services: |
217 | 217 | - ./tb-transports/lwm2m/log:/var/log/tb-lwm2m-transport |
218 | 218 | depends_on: |
219 | 219 | - zookeeper |
220 | + tb-snmp-transport: | |
221 | + restart: always | |
222 | + image: "${DOCKER_REPO}/${SNMP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" | |
223 | + environment: | |
224 | + TB_SERVICE_ID: tb-snmp-transport | |
225 | + env_file: | |
226 | + - tb-snmp-transport.env | |
227 | + volumes: | |
228 | + - ./tb-transports/snmp/conf:/config | |
229 | + - ./tb-transports/snmp/log:/var/log/tb-snmp-transport | |
230 | + depends_on: | |
231 | + - zookeeper | |
220 | 232 | tb-web-ui1: |
221 | 233 | restart: always |
222 | 234 | image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}" | ... | ... |
... | ... | @@ -24,3 +24,5 @@ mkdir -p tb-transports/lwm2m/log && sudo chown -R 799:799 tb-transports/lwm2m/lo |
24 | 24 | mkdir -p tb-transports/http/log && sudo chown -R 799:799 tb-transports/http/log |
25 | 25 | |
26 | 26 | mkdir -p tb-transports/mqtt/log && sudo chown -R 799:799 tb-transports/mqtt/log |
27 | + | |
28 | +mkdir -p tb-transports/snmp/log && sudo chown -R 799:799 tb-transports/snmp/log | ... | ... |
docker/tb-snmp-transport.env
0 → 100644