From bd7536b257907d9012084c27dc5cc3595e5dba3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lehel=20Bo=C3=A9r?= Date: Thu, 20 May 2021 17:08:02 +0200 Subject: [PATCH] NIFI-3328: SendTrapSNMP and ListenTrapSNMP processors added. --- .../nifi-snmp-processors/pom.xml | 8 +- .../snmp/configuration/SNMPConfiguration.java | 128 +++++++- .../SNMPConfigurationBuilder.java | 100 ------ .../configuration/V1TrapConfiguration.java | 117 +++++++ .../V2TrapConfiguration.java} | 16 +- .../ErrorStatus.java} | 46 ++- .../SNMPResponseStatus.java} | 71 +++-- .../nifi/snmp/dto/SNMPSingleResponse.java | 2 +- .../nifi/snmp/dto/SNMPTreeResponse.java | 8 + .../org/apache/nifi/snmp/dto/UserDetails.java | 58 ++++ .../nifi/snmp/exception/SNMPException.java | 4 + .../snmp/factory/AbstractSNMPFactory.java | 91 ------ .../snmp/factory/CompositeSNMPFactory.java | 70 ----- .../nifi/snmp/factory/V3SNMPFactory.java | 76 ----- .../nifi/snmp/factory/core/SNMPContext.java | 50 +++ .../factory/core/SNMPFactoryProvider.java | 48 +++ .../SNMPManagerFactory.java} | 32 +- .../V1V2cSNMPFactory.java} | 26 +- .../nifi/snmp/factory/core/V3SNMPFactory.java | 77 +++++ .../snmp/factory/trap/V1TrapPDUFactory.java | 58 ++++ .../snmp/factory/trap/V2TrapPDUFactory.java | 54 ++++ .../nifi/snmp/operations/GetSNMPHandler.java | 150 +++++++++ .../operations/SNMPRequestHandlerFactory.java | 38 --- .../snmp/operations/SNMPResourceHandler.java | 70 +++++ .../snmp/operations/SNMPTrapReceiver.java | 77 +++++ .../operations/SNMPTrapReceiverHandler.java | 124 ++++++++ .../snmp/operations/SendTrapSNMPHandler.java | 75 +++++ .../nifi/snmp/operations/SetSNMPHandler.java | 66 ++++ .../StandardSNMPRequestHandler.java | 148 --------- .../processors/AbstractSNMPProcessor.java | 269 ++++------------ .../apache/nifi/snmp/processors/GetSNMP.java | 157 +++++++--- .../nifi/snmp/processors/ListenTrapSNMP.java | 143 +++++++++ .../nifi/snmp/processors/SendTrapSNMP.java | 170 ++++++++++ .../apache/nifi/snmp/processors/SetSNMP.java | 68 ++-- .../properties/BasicProperties.java | 77 +++++ .../properties/V1TrapProperties.java | 80 +++++ .../properties/V2TrapProperties.java | 42 +++ .../properties/V3SecurityProperties.java | 130 ++++++++ .../org/apache/nifi/snmp/utils/SNMPUtils.java | 116 ++++--- .../org.apache.nifi.processor.Processor | 2 + .../additionalDetails.html | 11 +- .../additionalDetails.html | 54 ++++ .../additionalDetails.html | 45 +++ .../configuration/SNMPConfigurationTest.java | 75 +++++ .../V1TrapConfigurationTest.java | 141 +++++++++ .../nifi/snmp/dto/SNMPTreeResponseTest.java | 165 ++++++++++ .../snmp/factory/SNMPClientFactoryTest.java | 68 ---- .../snmp/factory/core/SNMPContextTest.java | 47 +++ .../factory/core/SNMPFactoryProviderTest.java | 37 +++ .../factory/core/V1V2cSNMPFactoryTest.java | 90 ++++++ .../snmp/factory/core/V3SNMPFactoryTest.java | 107 +++++++ .../factory/trap/V1TrapPDUFactoryTest.java | 59 ++++ .../factory/trap/V2TrapPDUFactoryTest.java | 58 ++++ .../nifi/snmp/helper/SNMPTestUtils.java | 68 ---- .../snmp/helper/TrapConfigurationFactory.java | 46 +++ .../SNMPConfigurationFactory.java} | 16 +- .../SNMPV1V2cConfigurationFactory.java | 57 ++++ .../SNMPV3ConfigurationFactory.java | 71 +++++ .../testrunners/SNMPTestRunnerFactory.java | 58 ++++ .../testrunners/SNMPV1TestRunnerFactory.java | 93 ++++++ .../testrunners/SNMPV2cTestRunnerFactory.java | 89 ++++++ .../testrunners/SNMPV3TestRunnerFactory.java | 112 +++++++ .../snmp/operations/GetSNMPHandlerTest.java | 271 ++++++++++++++++ .../nifi/snmp/operations/SNMPRequestTest.java | 296 +++++++++++++++--- .../SNMPTrapReceiverHandlerTest.java | 146 +++++++++ .../snmp/operations/SNMPTrapReceiverTest.java | 153 +++++++++ .../snmp/operations/SNMPV1RequestTest.java | 86 ----- .../snmp/operations/SNMPV2CRequestTest.java | 86 ----- .../snmp/operations/SNMPV3RequestTest.java | 135 -------- .../operations/SendTrapSNMPHandlerTest.java | 109 +++++++ .../snmp/operations/SetSNMPHandlerTest.java | 119 +++++++ .../processors/AbstractSNMPProcessorTest.java | 162 ++++++++++ .../processors/GetSNMPIntegrationTest.java | 154 +++++++++ .../nifi/snmp/processors/GetSNMPTest.java | 86 ++--- .../processors/SetSNMPIntegrationTest.java | 112 +++++++ .../nifi/snmp/processors/SetSNMPTest.java | 88 ------ .../processors/TrapSNMPIntegrationTest.java | 108 +++++++ .../nifi/snmp/testagents/TestAgent.java | 5 + .../src/test/resources/users.json | 16 + 79 files changed, 5243 insertions(+), 1598 deletions(-) delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfigurationBuilder.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java rename nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/{exception/CreateSNMPClientException.java => configuration/V2TrapConfiguration.java} (65%) rename nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/{exception/CloseSNMPClientException.java => dto/ErrorStatus.java} (79%) rename nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/{operations/SNMPRequestHandler.java => dto/SNMPResponseStatus.java} (61%) create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/UserDetails.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/AbstractSNMPFactory.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/CompositeSNMPFactory.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V3SNMPFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPContext.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProvider.java rename nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/{V2cSNMPFactory.java => core/SNMPManagerFactory.java} (58%) rename nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/{V1SNMPFactory.java => core/V1V2cSNMPFactory.java} (64%) create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/V3SNMPFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/GetSNMPHandler.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandlerFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPResourceHandler.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiver.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SetSNMPHandler.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/StandardSNMPRequestHandler.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/BasicProperties.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V1TrapProperties.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V2TrapProperties.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.SendTrapSNMP/additionalDetails.html create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/SNMPConfigurationTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/dto/SNMPTreeResponseTest.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/SNMPClientFactoryTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPContextTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProviderTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V1V2cSNMPFactoryTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V3SNMPFactoryTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactoryTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactoryTest.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/SNMPTestUtils.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/TrapConfigurationFactory.java rename nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/{main/java/org/apache/nifi/snmp/factory/SNMPFactory.java => test/java/org/apache/nifi/snmp/helper/configurations/SNMPConfigurationFactory.java} (67%) create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1V2cConfigurationFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV3ConfigurationFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPTestRunnerFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV1TestRunnerFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV2cTestRunnerFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/GetSNMPHandlerTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverTest.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV1RequestTest.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV2CRequestTest.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV3RequestTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SetSNMPHandlerTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessorTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPIntegrationTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPIntegrationTest.java delete mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/TrapSNMPIntegrationTest.java create mode 100644 nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml index ab5b06efa6..88bc157876 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/pom.xml @@ -51,6 +51,12 @@ language governing permissions and limitations under the License. --> 1.16.0-SNAPSHOT test + + com.fasterxml.jackson.core + jackson-databind + 2.12.3 + compile + @@ -61,7 +67,7 @@ language governing permissions and limitations under the License. --> - src/test/resources/testdata/* + src/test/resources/* diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfiguration.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfiguration.java index aa65ada526..36a371b50d 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfiguration.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfiguration.java @@ -18,10 +18,11 @@ package org.apache.nifi.snmp.configuration; public class SNMPConfiguration { - private final String agentHost; - private final String agentPort; + private final int managerPort; + private final String targetHost; + private final String targetPort; private final int retries; - private final int timeout; + private final long timeoutInMs; private final int version; private final String authProtocol; private final String authPassphrase; @@ -31,10 +32,11 @@ public class SNMPConfiguration { private final String securityLevel; private final String communityString; - SNMPConfiguration(final String agentHost, - final String agentPort, + SNMPConfiguration(final int managerPort, + final String targetHost, + final String targetPort, final int retries, - final int timeout, + final long timeoutInMs, final int version, final String authProtocol, final String authPassphrase, @@ -43,10 +45,11 @@ public class SNMPConfiguration { final String securityName, final String securityLevel, final String communityString) { - this.agentHost = agentHost; - this.agentPort = agentPort; + this.managerPort = managerPort; + this.targetHost = targetHost; + this.targetPort = targetPort; this.retries = retries; - this.timeout = timeout; + this.timeoutInMs = timeoutInMs; this.version = version; this.authProtocol = authProtocol; this.authPassphrase = authPassphrase; @@ -57,20 +60,24 @@ public class SNMPConfiguration { this.communityString = communityString; } - public String getAgentHost() { - return agentHost; + public int getManagerPort() { + return managerPort; } - public String getAgentPort() { - return agentPort; + public String getTargetHost() { + return targetHost; + } + + public String getTargetPort() { + return targetPort; } public int getRetries() { return retries; } - public int getTimeout() { - return timeout; + public long getTimeoutInMs() { + return timeoutInMs; } public int getVersion() { @@ -104,4 +111,95 @@ public class SNMPConfiguration { public String getCommunityString() { return communityString; } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private int managerPort; + private String targetHost; + private String targetPort; + private int retries; + private long timeoutInMs = 500L; + private int version; + private String authProtocol; + private String authPassphrase; + private String privacyProtocol; + private String privacyPassphrase; + private String securityName; + private String securityLevel; + private String communityString; + + public Builder setManagerPort(final int managerPort) { + this.managerPort = managerPort; + return this; + } + + public Builder setTargetHost(final String targetHost) { + this.targetHost = targetHost; + return this; + } + + public Builder setTargetPort(final String targetPort) { + this.targetPort = targetPort; + return this; + } + + public Builder setRetries(final int retries) { + this.retries = retries; + return this; + } + + public Builder setTimeoutInMs(final long timeoutInMs) { + this.timeoutInMs = timeoutInMs; + return this; + } + + public Builder setVersion(final int version) { + this.version = version; + return this; + } + + public Builder setAuthProtocol(final String authProtocol) { + this.authProtocol = authProtocol; + return this; + } + + public Builder setAuthPassphrase(final String authPassphrase) { + this.authPassphrase = authPassphrase; + return this; + } + + public Builder setPrivacyProtocol(final String privacyProtocol) { + this.privacyProtocol = privacyProtocol; + return this; + } + + public Builder setPrivacyPassphrase(final String privacyPassphrase) { + this.privacyPassphrase = privacyPassphrase; + return this; + } + + public Builder setSecurityName(final String securityName) { + this.securityName = securityName; + return this; + } + + public Builder setSecurityLevel(final String securityLevel) { + this.securityLevel = securityLevel; + return this; + } + + public Builder setCommunityString(String communityString) { + this.communityString = communityString; + return this; + } + + public SNMPConfiguration build() { + return new SNMPConfiguration(managerPort, targetHost, targetPort, retries, timeoutInMs, version, authProtocol, + authPassphrase, privacyProtocol, privacyPassphrase, securityName, securityLevel, communityString); + } + } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfigurationBuilder.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfigurationBuilder.java deleted file mode 100644 index dbb7728219..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfigurationBuilder.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.configuration; - -public class SNMPConfigurationBuilder { - private String agentHost; - private String agentPort; - private int retries; - private int timeout; - private int version; - private String authProtocol; - private String authPassphrase; - private String privacyProtocol; - private String privacyPassphrase; - private String securityName; - private String securityLevel; - private String communityString; - - public SNMPConfigurationBuilder setAgentHost(final String agentHost) { - this.agentHost = agentHost; - return this; - } - - public SNMPConfigurationBuilder setAgentPort(final String agentPort) { - this.agentPort = agentPort; - return this; - } - - public SNMPConfigurationBuilder setRetries(final int retries) { - this.retries = retries; - return this; - } - - public SNMPConfigurationBuilder setTimeout(final int timeout) { - this.timeout = timeout; - return this; - } - - public SNMPConfigurationBuilder setVersion(final int version) { - this.version = version; - return this; - } - - public SNMPConfigurationBuilder setAuthProtocol(final String authProtocol) { - this.authProtocol = authProtocol; - return this; - } - - public SNMPConfigurationBuilder setAuthPassphrase(final String authPassphrase) { - this.authPassphrase = authPassphrase; - return this; - } - - public SNMPConfigurationBuilder setPrivacyProtocol(final String privacyProtocol) { - this.privacyProtocol = privacyProtocol; - return this; - } - - public SNMPConfigurationBuilder setPrivacyPassphrase(final String privacyPassphrase) { - this.privacyPassphrase = privacyPassphrase; - return this; - } - - public SNMPConfigurationBuilder setSecurityName(final String securityName) { - this.securityName = securityName; - return this; - } - - public SNMPConfigurationBuilder setSecurityLevel(final String securityLevel) { - this.securityLevel = securityLevel; - return this; - } - - public SNMPConfigurationBuilder setCommunityString(final String communityString) { - this.communityString = communityString; - return this; - } - - public SNMPConfiguration build() { - final boolean isValid = agentHost != null && agentPort != null; - if (!isValid) { - throw new IllegalStateException("Required properties are not set."); - } - return new SNMPConfiguration(agentHost, agentPort, retries, timeout, version, authProtocol, authPassphrase, privacyProtocol, privacyPassphrase, securityName, securityLevel, communityString); - } -} \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java new file mode 100644 index 0000000000..896b0d9728 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V1TrapConfiguration.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.configuration; + +import org.apache.nifi.util.StringUtils; + +public class V1TrapConfiguration { + + private final String enterpriseOid; + private final String agentAddress; + private final String genericTrapType; + private final String specificTrapType; + + private V1TrapConfiguration(final V1TrapConfiguration.Builder builder) { + this.enterpriseOid = builder.enterpriseOid; + this.agentAddress = builder.agentAddress; + this.genericTrapType = builder.genericTrapType; + this.specificTrapType = builder.specificTrapType; + } + + public String getEnterpriseOid() { + return enterpriseOid; + } + + public String getAgentAddress() { + return agentAddress; + } + + public int getGenericTrapType() { + return Integer.parseInt(genericTrapType); + } + + public Integer getSpecificTrapType() { + if (StringUtils.isNotEmpty(specificTrapType)) { + return Integer.parseInt(specificTrapType); + } + return null; + } + + public static V1TrapConfiguration.Builder builder() { + return new V1TrapConfiguration.Builder(); + } + + public static final class Builder { + String enterpriseOid; + String agentAddress; + String genericTrapType; + String specificTrapType; + + public Builder enterpriseOid(String enterpriseOid) { + this.enterpriseOid = enterpriseOid; + return this; + } + + public Builder agentAddress(String agentAddress) { + this.agentAddress = agentAddress; + return this; + } + + public Builder genericTrapType(String genericTrapType) { + this.genericTrapType = genericTrapType; + return this; + } + + public Builder specificTrapType(String specificTrapType) { + this.specificTrapType = specificTrapType; + return this; + } + + public V1TrapConfiguration build() { + if (StringUtils.isEmpty(enterpriseOid)) { + throw new IllegalArgumentException("Enterprise OID must be specified."); + } + if (StringUtils.isEmpty(agentAddress)) { + throw new IllegalArgumentException("Agent address must be specified."); + } + + final int parsedGenericTrapType; + try { + parsedGenericTrapType = Integer.parseInt(genericTrapType); + if (parsedGenericTrapType < 0 || parsedGenericTrapType > 6) { + throw new IllegalArgumentException("Generic Trap Type must be between 0 and 6."); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Generic Trap Type is not a number."); + } + + if (parsedGenericTrapType == 6) { + try { + final int parsedSpecificTrapType = Integer.parseInt(specificTrapType); + if (parsedSpecificTrapType < 0) { + throw new IllegalArgumentException("Specific Trap Type must be between 0 and 2147483647."); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Generic Trap Type is [6 - Enterprise Specific] but Specific Trap Type is not provided or not a number."); + } + } else if (StringUtils.isNotEmpty(specificTrapType)) { + throw new IllegalArgumentException("Invalid argument: Generic Trap Type is not [6 - Enterprise Specific] but Specific Trap Type is provided."); + } + return new V1TrapConfiguration(this); + } + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/CreateSNMPClientException.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V2TrapConfiguration.java similarity index 65% rename from nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/CreateSNMPClientException.java rename to nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V2TrapConfiguration.java index f803605979..145acbe21c 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/CreateSNMPClientException.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/V2TrapConfiguration.java @@ -14,12 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.snmp.exception; +package org.apache.nifi.snmp.configuration; -public class CreateSNMPClientException extends SNMPException { +public class V2TrapConfiguration { - public CreateSNMPClientException(final String errorMessage) { - super(errorMessage); + private final String trapOidValue; + + public V2TrapConfiguration(final String trapOidValue) { + if (trapOidValue.isEmpty()) { + throw new IllegalArgumentException("Trap OID Value must be specified."); + } + this.trapOidValue = trapOidValue; } + public String getTrapOidValue() { + return trapOidValue; + } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/CloseSNMPClientException.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/ErrorStatus.java similarity index 79% rename from nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/CloseSNMPClientException.java rename to nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/ErrorStatus.java index 4c70250729..2582e13b99 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/CloseSNMPClientException.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/ErrorStatus.java @@ -1,25 +1,21 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.exception; - -public class CloseSNMPClientException extends SNMPException { - - public CloseSNMPClientException(final String errorMessage) { - super(errorMessage); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.dto; + +public enum ErrorStatus { + FAILURE, SUCCESS +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPResponseStatus.java similarity index 61% rename from nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandler.java rename to nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPResponseStatus.java index 97759eda0e..8080e7c7fc 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandler.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPResponseStatus.java @@ -1,34 +1,37 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.operations; - -import org.apache.nifi.flowfile.FlowFile; -import org.apache.nifi.snmp.dto.SNMPSingleResponse; -import org.apache.nifi.snmp.dto.SNMPTreeResponse; - -import java.io.IOException; - -public interface SNMPRequestHandler { - - SNMPSingleResponse get(final String oid) throws IOException; - - SNMPTreeResponse walk(final String oid); - - SNMPSingleResponse set(final FlowFile flowfile) throws IOException; - - void close(); -} +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.dto; + +public class SNMPResponseStatus { + + private final String errorMessage; + private final ErrorStatus errorStatus; + + + public SNMPResponseStatus(String errorMessage, ErrorStatus errorStatus) { + this.errorMessage = errorMessage; + this.errorStatus = errorStatus; + } + + public String getErrorMessage() { + return errorMessage; + } + + public ErrorStatus getErrorStatus() { + return errorStatus; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPSingleResponse.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPSingleResponse.java index dabf41a9bb..03f8306de0 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPSingleResponse.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPSingleResponse.java @@ -38,7 +38,6 @@ public class SNMPSingleResponse { return responsePdu.getErrorStatus() == PDU.noError; } - public Map getAttributes() { return SNMPUtils.getPduAttributeMap(responsePdu); } @@ -65,4 +64,5 @@ public class SNMPSingleResponse { public boolean isReportPdu() { return responsePdu.getType() == PDU.REPORT; } + } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPTreeResponse.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPTreeResponse.java index c250e8d831..d58116d71a 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPTreeResponse.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/SNMPTreeResponse.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; public class SNMPTreeResponse { @@ -56,4 +57,11 @@ public class SNMPTreeResponse { .filter(TreeEvent::isError) .forEach(event -> logger.error("Error occured in SNMP walk event: {}", event.getErrorMessage())); } + + public boolean isError() { + final Optional first = events.stream() + .filter(TreeEvent::isError) + .findFirst(); + return first.isPresent(); + } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/UserDetails.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/UserDetails.java new file mode 100644 index 0000000000..26cc9ff5b1 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/dto/UserDetails.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.dto; + +public class UserDetails { + + private String securityName; + private String authProtocol; + private String authPassphrase; + private String privProtocol; + private String privPassphrase; + + public UserDetails() { + } + + public UserDetails(final String securityName, final String authProtocol, final String authPassphrase, + final String privProtocol, final String privPassphrase) { + this.securityName = securityName; + this.authProtocol = authProtocol; + this.authPassphrase = authPassphrase; + this.privProtocol = privProtocol; + this.privPassphrase = privPassphrase; + } + + public String getSecurityName() { + return securityName; + } + + public String getAuthProtocol() { + return authProtocol; + } + + public String getAuthPassphrase() { + return authPassphrase; + } + + public String getPrivProtocol() { + return privProtocol; + } + + public String getPrivPassphrase() { + return privPassphrase; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/SNMPException.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/SNMPException.java index 4e842daa90..7b51e0a0d1 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/SNMPException.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/exception/SNMPException.java @@ -22,4 +22,8 @@ public class SNMPException extends RuntimeException { super(errorMessage); } + public SNMPException(final Exception exception) { + super(exception); + } + } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/AbstractSNMPFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/AbstractSNMPFactory.java deleted file mode 100644 index baa458885d..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/AbstractSNMPFactory.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.factory; - -import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.apache.nifi.snmp.exception.CreateSNMPClientException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.snmp4j.CommunityTarget; -import org.snmp4j.Snmp; -import org.snmp4j.Target; -import org.snmp4j.UserTarget; -import org.snmp4j.security.SecurityLevel; -import org.snmp4j.smi.OctetString; -import org.snmp4j.smi.UdpAddress; -import org.snmp4j.transport.DefaultUdpTransportMapping; - -import java.io.IOException; -import java.util.Optional; - -public abstract class AbstractSNMPFactory { - - private static final Logger logger = LoggerFactory.getLogger(AbstractSNMPFactory.class); - - protected AbstractSNMPFactory() { - // hide implicit constructor - } - - protected static Snmp createSnmpClient() { - final Snmp snmp; - try { - snmp = new Snmp(new DefaultUdpTransportMapping()); - snmp.listen(); - return snmp; - } catch (IOException e) { - final String errorMessage = "Creating SNMP client failed."; - logger.error(errorMessage, e); - throw new CreateSNMPClientException(errorMessage); - } - } - - protected static Target createUserTarget(final SNMPConfiguration configuration) { - final UserTarget userTarget = new UserTarget(); - setupTargetBasicProperties(userTarget, configuration); - - final int securityLevel = SecurityLevel.valueOf(configuration.getSecurityLevel()).getSnmpValue(); - userTarget.setSecurityLevel(securityLevel); - - final String securityName = configuration.getSecurityName(); - Optional.ofNullable(securityName).map(OctetString::new).ifPresent(userTarget::setSecurityName); - - return userTarget; - } - - protected static Target createCommunityTarget(final SNMPConfiguration configuration) { - final Target communityTarget = new CommunityTarget(); - setupTargetBasicProperties(communityTarget, configuration); - final String community = configuration.getCommunityString(); - - Optional.ofNullable(community).map(OctetString::new).ifPresent(communityTarget::setSecurityName); - - return communityTarget; - } - - private static void setupTargetBasicProperties(final Target target, final SNMPConfiguration configuration) { - final int snmpVersion = configuration.getVersion(); - final String host = configuration.getAgentHost(); - final String port = configuration.getAgentPort(); - final int retries = configuration.getRetries(); - final int timeout = configuration.getTimeout(); - - target.setVersion(snmpVersion); - target.setAddress(new UdpAddress(host + "/" + port)); - target.setRetries(retries); - target.setTimeout(timeout); - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/CompositeSNMPFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/CompositeSNMPFactory.java deleted file mode 100644 index f1234bc6f2..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/CompositeSNMPFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.factory; - -import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.apache.nifi.snmp.exception.InvalidSnmpVersionException; -import org.snmp4j.Snmp; -import org.snmp4j.Target; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -public class CompositeSNMPFactory implements SNMPFactory { - - private static final String INVALID_SNMP_VERSION = "SNMP version is not supported."; - private static final List FACTORIES; - - static { - final List factories = Arrays.asList(new V1SNMPFactory(), new V2cSNMPFactory(), new V3SNMPFactory()); - FACTORIES = Collections.unmodifiableList(factories); - } - - @Override - public boolean supports(final int version) { - return !getMatchingFactory(version).isPresent(); - } - - @Override - public Snmp createSnmpManagerInstance(final SNMPConfiguration configuration) { - final Optional factory = getMatchingFactory(configuration.getVersion()); - if (!factory.isPresent()) { - throw new InvalidSnmpVersionException(INVALID_SNMP_VERSION); - } - return factory.get().createSnmpManagerInstance(configuration); - } - - @Override - public Target createTargetInstance(final SNMPConfiguration configuration) { - final Optional factory = getMatchingFactory(configuration.getVersion()); - if (!factory.isPresent()) { - throw new InvalidSnmpVersionException(INVALID_SNMP_VERSION); - } - return factory.get().createTargetInstance(configuration); - } - - private Optional getMatchingFactory(final int version) { - for (final SNMPFactory factory : FACTORIES) { - if (factory.supports(version)) { - return Optional.of(factory); - } - } - return Optional.empty(); - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V3SNMPFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V3SNMPFactory.java deleted file mode 100644 index 75e34d0c37..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V3SNMPFactory.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.factory; - -import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.apache.nifi.snmp.utils.SNMPUtils; -import org.snmp4j.Snmp; -import org.snmp4j.Target; -import org.snmp4j.mp.MPv3; -import org.snmp4j.mp.SnmpConstants; -import org.snmp4j.security.SecurityModels; -import org.snmp4j.security.SecurityProtocols; -import org.snmp4j.security.USM; -import org.snmp4j.security.UsmUser; -import org.snmp4j.smi.OID; -import org.snmp4j.smi.OctetString; - -import java.util.Optional; - -public class V3SNMPFactory extends AbstractSNMPFactory implements SNMPFactory { - - @Override - public boolean supports(final int version) { - return SnmpConstants.version3 == version; - } - - @Override - public Snmp createSnmpManagerInstance(final SNMPConfiguration configuration) { - final Snmp snmp = createSnmpClient(); - - // If there's a USM instance associated with the MPv3 bound to this Snmp instance (like an agent running - // on the same host) it is not null. - if (snmp.getUSM() == null) { - final OctetString localEngineId = new OctetString(MPv3.createLocalEngineID()); - final USM usm = new USM(SecurityProtocols.getInstance(), localEngineId, 0); - SecurityModels.getInstance().addSecurityModel(usm); - } - - final String username = configuration.getSecurityName(); - final OID authProtocol = Optional.ofNullable(configuration.getAuthProtocol()) - .map(SNMPUtils::getAuth).orElse(null); - final OID privacyProtocol = Optional.ofNullable(configuration.getPrivacyProtocol()) - .map(SNMPUtils::getPriv).orElse(null); - final String authPassword = configuration.getAuthPassphrase(); - final String privacyPassword = configuration.getPrivacyPassphrase(); - final OctetString authPasswordOctet = authPassword != null ? new OctetString(authPassword) : null; - final OctetString privacyPasswordOctet = privacyPassword != null ? new OctetString(privacyPassword) : null; - - // Add user information. - snmp.getUSM().addUser( - new OctetString(username), - new UsmUser(new OctetString(username), authProtocol, authPasswordOctet, - privacyProtocol, privacyPasswordOctet)); - - return snmp; - } - - @Override - public Target createTargetInstance(final SNMPConfiguration configuration) { - return createUserTarget(configuration); - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPContext.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPContext.java new file mode 100644 index 0000000000..d3dd885613 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPContext.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.core; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.operations.SNMPResourceHandler; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.smi.UdpAddress; + +public interface SNMPContext { + + default SNMPResourceHandler createSNMPResourceHandler(final SNMPConfiguration snmpConfiguration) { + return new SNMPResourceHandler( + createSnmpManagerInstance(snmpConfiguration), + createTargetInstance(snmpConfiguration) + ); + } + + default void setupTargetBasicProperties(final Target target, final SNMPConfiguration configuration) { + final int snmpVersion = configuration.getVersion(); + final String host = configuration.getTargetHost(); + final String port = configuration.getTargetPort(); + final int retries = configuration.getRetries(); + final long timeout = configuration.getTimeoutInMs(); + + target.setVersion(snmpVersion); + target.setAddress(new UdpAddress(host + "/" + port)); + target.setRetries(retries); + target.setTimeout(timeout); + } + + Snmp createSnmpManagerInstance(final SNMPConfiguration configuration); + + Target createTargetInstance(final SNMPConfiguration configuration); +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProvider.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProvider.java new file mode 100644 index 0000000000..6cc62aaa03 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProvider.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.core; + +import org.apache.nifi.snmp.exception.InvalidSnmpVersionException; +import org.snmp4j.mp.SnmpConstants; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class SNMPFactoryProvider { + + private SNMPFactoryProvider() { + // not to instantiate + } + + private static final String INVALID_SNMP_VERSION = "SNMP version is not supported: %s"; + private static final Map FACTORIES; + + static { + final Map factories = new HashMap<>(); + factories.put(SnmpConstants.version1, new V1V2cSNMPFactory()); + factories.put(SnmpConstants.version2c, new V1V2cSNMPFactory()); + factories.put(SnmpConstants.version3, new V3SNMPFactory()); + FACTORIES = Collections.unmodifiableMap(factories); + } + + public static SNMPContext getFactory(final int version) { + return Optional.ofNullable(FACTORIES.get(version)) + .orElseThrow(() -> new InvalidSnmpVersionException(String.format(INVALID_SNMP_VERSION, version))); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V2cSNMPFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPManagerFactory.java similarity index 58% rename from nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V2cSNMPFactory.java rename to nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPManagerFactory.java index b34609d72c..17afbb0607 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V2cSNMPFactory.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/SNMPManagerFactory.java @@ -14,27 +14,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.snmp.factory; +package org.apache.nifi.snmp.factory.core; +import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.snmp.configuration.SNMPConfiguration; import org.snmp4j.Snmp; -import org.snmp4j.Target; -import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.smi.UdpAddress; +import org.snmp4j.transport.DefaultUdpTransportMapping; -public class V2cSNMPFactory extends AbstractSNMPFactory implements SNMPFactory { +import java.io.IOException; - @Override - public boolean supports(final int version) { - return SnmpConstants.version2c == version; - } +public class SNMPManagerFactory { + + private static final String LOCALHOST = "127.0.0.1"; - @Override public Snmp createSnmpManagerInstance(final SNMPConfiguration configuration) { - return createSnmpClient(); - } - - @Override - public Target createTargetInstance(final SNMPConfiguration configuration) { - return createCommunityTarget(configuration); + final String managerAddress = LOCALHOST + "/" + configuration.getManagerPort(); + final Snmp snmpManager; + try { + snmpManager = new Snmp(new DefaultUdpTransportMapping(new UdpAddress(managerAddress))); + snmpManager.listen(); + } catch (IOException e) { + throw new ProcessException(e); + } + return snmpManager; } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V1SNMPFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/V1V2cSNMPFactory.java similarity index 64% rename from nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V1SNMPFactory.java rename to nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/V1V2cSNMPFactory.java index e0896583cc..636ca4a7ca 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/V1SNMPFactory.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/V1V2cSNMPFactory.java @@ -14,27 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.snmp.factory; +package org.apache.nifi.snmp.factory.core; import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.snmp4j.Snmp; +import org.snmp4j.CommunityTarget; import org.snmp4j.Target; -import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.smi.OctetString; -public class V1SNMPFactory extends AbstractSNMPFactory implements SNMPFactory { +import java.util.Optional; - @Override - public boolean supports(final int version) { - return SnmpConstants.version1 == version; - } - - @Override - public Snmp createSnmpManagerInstance(final SNMPConfiguration configuration) { - return createSnmpClient(); - } +public class V1V2cSNMPFactory extends SNMPManagerFactory implements SNMPContext { @Override public Target createTargetInstance(final SNMPConfiguration configuration) { - return createCommunityTarget(configuration); + final Target communityTarget = new CommunityTarget(); + setupTargetBasicProperties(communityTarget, configuration); + final String community = configuration.getCommunityString(); + + Optional.ofNullable(community).map(OctetString::new).ifPresent(communityTarget::setSecurityName); + + return communityTarget; } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/V3SNMPFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/V3SNMPFactory.java new file mode 100644 index 0000000000..4bc089730e --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/core/V3SNMPFactory.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.core; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.UserTarget; +import org.snmp4j.mp.MPv3; +import org.snmp4j.security.SecurityLevel; +import org.snmp4j.security.SecurityModels; +import org.snmp4j.security.SecurityProtocols; +import org.snmp4j.security.USM; +import org.snmp4j.security.UsmUser; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.OctetString; + +import java.util.Optional; + +public class V3SNMPFactory extends SNMPManagerFactory implements SNMPContext { + + @Override + public Snmp createSnmpManagerInstance(final SNMPConfiguration configuration) { + final Snmp snmpManager = super.createSnmpManagerInstance(configuration); + + // Create USM. + final OctetString localEngineId = new OctetString(MPv3.createLocalEngineID()); + final USM usm = new USM(SecurityProtocols.getInstance(), localEngineId, 0); + SecurityModels.getInstance().addSecurityModel(usm); + + Optional.ofNullable(configuration.getSecurityName()) + .map(OctetString::new) + .ifPresent(securityName -> { + OID authProtocol = Optional.ofNullable(configuration.getAuthProtocol()) + .map(SNMPUtils::getAuth).orElse(null); + OctetString authPassphrase = Optional.ofNullable(configuration.getAuthPassphrase()) + .map(OctetString::new).orElse(null); + OID privacyProtocol = Optional.ofNullable(configuration.getPrivacyProtocol()) + .map(SNMPUtils::getPriv).orElse(null); + OctetString privacyPassphrase = Optional.ofNullable(configuration.getPrivacyPassphrase()) + .map(OctetString::new).orElse(null); + snmpManager.getUSM().addUser(securityName, new UsmUser(securityName, authProtocol, authPassphrase, + privacyProtocol, privacyPassphrase)); + }); + + return snmpManager; + } + + @Override + public Target createTargetInstance(final SNMPConfiguration configuration) { + final UserTarget userTarget = new UserTarget(); + setupTargetBasicProperties(userTarget, configuration); + + final int securityLevel = SecurityLevel.valueOf(configuration.getSecurityLevel()).getSnmpValue(); + userTarget.setSecurityLevel(securityLevel); + + final String securityName = configuration.getSecurityName(); + Optional.ofNullable(securityName).map(OctetString::new).ifPresent(userTarget::setSecurityName); + + return userTarget; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactory.java new file mode 100644 index 0000000000..a68f2b1e76 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactory.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.trap; + +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.snmp4j.PDU; +import org.snmp4j.PDUv1; +import org.snmp4j.Target; +import org.snmp4j.smi.IpAddress; +import org.snmp4j.smi.OID; +import org.snmp4j.util.DefaultPDUFactory; +import org.snmp4j.util.PDUFactory; + +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; + +/** + * Factory class to create SNMPv1-Trap-PDU for SNMPv1. + */ +public class V1TrapPDUFactory { + + private static final PDUFactory v1PduFactory = new DefaultPDUFactory(PDU.V1TRAP); + + final Target target; + final Instant startTime; + + public V1TrapPDUFactory(final Target target, final Instant startTime) { + this.target = target; + this.startTime = startTime; + } + + public PDU get(final V1TrapConfiguration v1TrapConfiguration) { + final PDUv1 pdu = (PDUv1) v1PduFactory.createPDU(target); + Optional.ofNullable(v1TrapConfiguration.getEnterpriseOid()).map(OID::new).ifPresent(pdu::setEnterprise); + Optional.ofNullable(v1TrapConfiguration.getAgentAddress()).map(IpAddress::new).ifPresent(pdu::setAgentAddress); + pdu.setGenericTrap(v1TrapConfiguration.getGenericTrapType()); + Optional.ofNullable(v1TrapConfiguration.getSpecificTrapType()).ifPresent(pdu::setSpecificTrap); + final long elapsedMillis = Duration.between(startTime, Instant.now()).toMillis(); + pdu.setTimestamp(elapsedMillis); + return pdu; + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactory.java new file mode 100644 index 0000000000..7ff58646b0 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactory.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.trap; + +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.snmp4j.PDU; +import org.snmp4j.Target; +import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.smi.OctetString; +import org.snmp4j.smi.TimeTicks; +import org.snmp4j.smi.VariableBinding; +import org.snmp4j.util.DefaultPDUFactory; +import org.snmp4j.util.PDUFactory; + +import java.time.Duration; +import java.time.Instant; + +/** + * Factory class to create SNMPv2-Trap-PDU for SNMPv2c and SNMPv3. + */ +public class V2TrapPDUFactory { + private static final PDUFactory v2PduFactory = new DefaultPDUFactory(PDU.TRAP); + + final Target target; + final Instant startTime; + + public V2TrapPDUFactory(final Target target, final Instant startTime) { + this.target = target; + this.startTime = startTime; + } + + public PDU get(final V2TrapConfiguration v2TrapConfiguration) { + final PDU pdu = v2PduFactory.createPDU(target); + pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OctetString(v2TrapConfiguration.getTrapOidValue()))); + final long elapsedMillis = Duration.between(startTime, Instant.now()).toMillis(); + pdu.add(new VariableBinding(SnmpConstants.sysUpTime, new TimeTicks(elapsedMillis))); + return pdu; + } + +} \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/GetSNMPHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/GetSNMPHandler.java new file mode 100644 index 0000000000..3514dd776f --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/GetSNMPHandler.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.snmp.dto.SNMPSingleResponse; +import org.apache.nifi.snmp.dto.SNMPTreeResponse; +import org.apache.nifi.snmp.exception.RequestTimeoutException; +import org.apache.nifi.snmp.exception.SNMPWalkException; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.event.ResponseEvent; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.VariableBinding; +import org.snmp4j.util.DefaultPDUFactory; +import org.snmp4j.util.PDUFactory; +import org.snmp4j.util.TreeEvent; +import org.snmp4j.util.TreeUtils; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.nifi.snmp.operations.SNMPResourceHandler.REQUEST_TIMEOUT_EXCEPTION_TEMPLATE; + +public class GetSNMPHandler { + + private static final PDUFactory getPduFactory = new DefaultPDUFactory(PDU.GET); + + protected static final String EMPTY_SUBTREE_EXCEPTION_MESSAGE = "Agent is not available, the %s OID not found or user not found. " + + "Please, check if (1) the agent is available, (2) the processor's SNMP version matches the agent version, " + + "(3) the OID is correct, (4) The user is valid."; + + protected static final String SNMP_ERROR_EXCEPTION_MESSAGE = "Agent is not available, OID not found or user not found. " + + "Please, check if (1) the agent is available, (2) the processor's SNMP version matches the agent version, " + + "(3) the OID is correct, (4) The user is valid."; + + protected static final String LEAF_ELEMENT_EXCEPTION_MESSAGE = "OID not found or it is a single leaf element. The leaf element " + + "associated with this %s OID does not contain child OIDs. Please check if the OID exists in the agent " + + "MIB or specify a parent OID with at least one child element"; + + private final SNMPResourceHandler snmpResourceHandler; + private TreeUtils treeUtils; + + public GetSNMPHandler(final SNMPResourceHandler snmpResourceHandler) { + this.snmpResourceHandler = snmpResourceHandler; + this.treeUtils = new TreeUtils(snmpResourceHandler.getSnmpManager(), getPduFactory); + } + + public SNMPSingleResponse get(final String oid) throws IOException { + final Target target = snmpResourceHandler.getTarget(); + final Snmp snmpManager = snmpResourceHandler.getSnmpManager(); + + final PDU pdu = getPduFactory.createPDU(target); + pdu.add(new VariableBinding(new OID(oid))); + + final PDU responsePdu = getResponsePdu(target, snmpManager, pdu); + return new SNMPSingleResponse(target, responsePdu); + } + + public Optional get(final Map flowFileAttributes) throws IOException { + final Target target = snmpResourceHandler.getTarget(); + final Snmp snmpManager = snmpResourceHandler.getSnmpManager(); + + final PDU pdu = getPduFactory.createPDU(target); + VariableBinding[] variableBindings = SNMPUtils.addGetVariables(flowFileAttributes); + if (variableBindings.length == 0) { + return Optional.empty(); + } + pdu.addAll(variableBindings); + + final PDU responsePdu = getResponsePdu(target, snmpManager, pdu); + return Optional.of(new SNMPSingleResponse(target, responsePdu)); + } + + public SNMPTreeResponse walk(final String oid) { + final Target target = snmpResourceHandler.getTarget(); + final List subtree = treeUtils.getSubtree(target, new OID(oid)); + + evaluateSubtreeErrors(oid, subtree); + + return new SNMPTreeResponse(target, subtree); + } + + public Optional walk(final Map flowFileAttributes) { + final Target target = snmpResourceHandler.getTarget(); + final List subtree; + + final OID[] oids = SNMPUtils.addWalkVariables(flowFileAttributes); + if (oids.length == 0) { + return Optional.empty(); + } + subtree = treeUtils.walk(target, oids); + + evaluateSubtreeErrors(Arrays.toString(oids), subtree); + + return Optional.of(new SNMPTreeResponse(target, subtree)); + } + + private PDU getResponsePdu(Target target, Snmp snmpManager, PDU pdu) throws IOException { + final ResponseEvent response = snmpManager.get(pdu, target); + final PDU responsePdu = response.getResponse(); + if (responsePdu == null) { + throw new RequestTimeoutException(String.format(REQUEST_TIMEOUT_EXCEPTION_TEMPLATE, "read")); + } + return responsePdu; + } + + private void evaluateSubtreeErrors(String oid, List subtree) { + if (subtree.isEmpty()) { + throw new SNMPWalkException(String.format(EMPTY_SUBTREE_EXCEPTION_MESSAGE, oid)); + } + if (isSnmpError(subtree)) { + throw new SNMPWalkException(SNMP_ERROR_EXCEPTION_MESSAGE); + } + if (isLeafElement(subtree)) { + throw new SNMPWalkException(String.format(LEAF_ELEMENT_EXCEPTION_MESSAGE, oid)); + } + } + + private boolean isSnmpError(final List subtree) { + return subtree.size() == 1 && subtree.get(0).getVariableBindings() == null; + } + + private boolean isLeafElement(final List subtree) { + return subtree.size() == 1 && subtree.get(0).getVariableBindings().length == 0; + } + + // Visible for testing + void setTreeUtils(final TreeUtils treeUtils) { + this.treeUtils = treeUtils; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandlerFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandlerFactory.java deleted file mode 100644 index 6663c4e8a1..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandlerFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.operations; - -import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.apache.nifi.snmp.factory.CompositeSNMPFactory; -import org.apache.nifi.snmp.factory.SNMPFactory; -import org.snmp4j.Snmp; -import org.snmp4j.Target; - -public final class SNMPRequestHandlerFactory { - - public static SNMPRequestHandler createStandardRequestHandler(final SNMPConfiguration configuration) { - final SNMPFactory snmpFactory = new CompositeSNMPFactory(); - final Snmp snmpClient = snmpFactory.createSnmpManagerInstance(configuration); - final Target target = snmpFactory.createTargetInstance(configuration); - return new StandardSNMPRequestHandler(snmpClient, target); - } - - private SNMPRequestHandlerFactory() { - // This should not be instantiated. - } - -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPResourceHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPResourceHandler.java new file mode 100644 index 0000000000..b19ded6047 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPResourceHandler.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.processor.exception.ProcessException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.security.SecurityModels; +import org.snmp4j.smi.Integer32; + +import java.io.IOException; + +public class SNMPResourceHandler { + + public static final String INVALID_FLOWFILE_EXCEPTION_MESSAGE = "Could not read the variable bindings from the " + + "flowfile. Please, add the OIDs to set in separate properties. E.g. Property name: snmp$1.3.6.1.2.1.1.1.0 " + + "Value: Example value. "; + + public static final String REQUEST_TIMEOUT_EXCEPTION_TEMPLATE = "Request timed out. Please check if (1). the " + + "agent host and port is correctly set, (2). the agent is running, (3). the agent SNMP version corresponds" + + " with the processor's one, (4) the community string is correct and has %1$s access, (5) In case of SNMPv3" + + " check if the user credentials are valid and the user in a group with %1$s access."; + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final Snmp snmpManager; + private final Target target; + + public SNMPResourceHandler(final Snmp snmpManager, final Target target) { + this.snmpManager = snmpManager; + this.target = target; + } + + public Snmp getSnmpManager() { + return snmpManager; + } + + public Target getTarget() { + return target; + } + + public void close() { + try { + if (snmpManager.getUSM() != null) { + snmpManager.getUSM().removeAllUsers(); + SecurityModels.getInstance().removeSecurityModel(new Integer32(snmpManager.getUSM().getID())); + } + snmpManager.close(); + } catch (IOException e) { + final String errorMessage = "Could not close SNMP manager."; + logger.error(errorMessage, e); + throw new ProcessException(errorMessage); + } + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiver.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiver.java new file mode 100644 index 0000000000..d2eaf19528 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiver.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.processor.ProcessSession; +import org.apache.nifi.processor.ProcessSessionFactory; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.CommandResponder; +import org.snmp4j.CommandResponderEvent; +import org.snmp4j.PDU; +import org.snmp4j.PDUv1; + +import java.util.Map; + +import static org.apache.nifi.snmp.processors.ListenTrapSNMP.REL_FAILURE; +import static org.apache.nifi.snmp.processors.ListenTrapSNMP.REL_SUCCESS; + +public class SNMPTrapReceiver implements CommandResponder { + + private final ProcessSessionFactory processSessionFactory; + private final ComponentLog logger; + + public SNMPTrapReceiver(final ProcessSessionFactory processSessionFactory, final ComponentLog logger) { + this.processSessionFactory = processSessionFactory; + this.logger = logger; + } + + @Override + public void processPdu(final CommandResponderEvent event) { + final PDU pdu = event.getPDU(); + if (isValidTrapPdu(pdu)) { + final ProcessSession processSession = processSessionFactory.createSession(); + final FlowFile flowFile = createFlowFile(processSession, pdu); + processSession.getProvenanceReporter().create(flowFile, event.getPeerAddress() + "/" + pdu.getRequestID()); + if (pdu.getErrorStatus() == PDU.noError) { + processSession.transfer(flowFile, REL_SUCCESS); + } else { + processSession.transfer(flowFile, REL_FAILURE); + } + processSession.commitAsync(); + } else { + logger.error("Request timed out or parameters are incorrect."); + } + } + + private FlowFile createFlowFile(final ProcessSession processSession, final PDU pdu) { + FlowFile flowFile = processSession.create(); + final Map attributes; + if (pdu instanceof PDUv1) { + attributes = SNMPUtils.getV1TrapPduAttributeMap((PDUv1) pdu); + } else { + attributes = SNMPUtils.getPduAttributeMap(pdu); + } + flowFile = processSession.putAllAttributes(flowFile, attributes); + return flowFile; + } + + private boolean isValidTrapPdu(final PDU pdu) { + return pdu != null && (pdu.getType() == PDU.V1TRAP || pdu.getType() == PDU.TRAP); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java new file mode 100644 index 0000000000..53b1ff2eda --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.processor.ProcessSessionFactory; +import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.dto.UserDetails; +import org.apache.nifi.snmp.factory.core.SNMPManagerFactory; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.snmp4j.Snmp; +import org.snmp4j.mp.MPv3; +import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.security.SecurityModels; +import org.snmp4j.security.SecurityProtocols; +import org.snmp4j.security.USM; +import org.snmp4j.security.UsmUser; +import org.snmp4j.smi.Integer32; +import org.snmp4j.smi.OctetString; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; +import java.util.Scanner; + +public class SNMPTrapReceiverHandler { + + private static final Logger logger = LoggerFactory.getLogger(SNMPTrapReceiverHandler.class); + + private final SNMPConfiguration configuration; + private final String usmUsersFilePath; + private Snmp snmpManager; + private boolean isStarted; + + public SNMPTrapReceiverHandler(final SNMPConfiguration configuration, final String usmUsersFilePath) { + this.configuration = configuration; + this.usmUsersFilePath = usmUsersFilePath; + snmpManager = new SNMPManagerFactory().createSnmpManagerInstance(configuration); + } + + public void createTrapReceiver(final ProcessSessionFactory processSessionFactory, final ComponentLog logger) { + addUsmUsers(); + SNMPTrapReceiver trapReceiver = new SNMPTrapReceiver(processSessionFactory, logger); + snmpManager.addCommandResponder(trapReceiver); + isStarted = true; + } + + public boolean isStarted() { + return isStarted; + } + + public void close() { + try { + if (snmpManager.getUSM() != null) { + snmpManager.getUSM().removeAllUsers(); + SecurityModels.getInstance().removeSecurityModel(new Integer32(snmpManager.getUSM().getID())); + } + snmpManager.close(); + isStarted = false; + } catch (IOException e) { + final String errorMessage = "Could not close SNMP manager."; + logger.error(errorMessage, e); + throw new ProcessException(errorMessage); + } + } + + private void addUsmUsers() { + if (configuration.getVersion() == SnmpConstants.version3) { + USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0); + SecurityModels.getInstance().addSecurityModel(usm); + + try (Scanner scanner = new Scanner(new File(usmUsersFilePath))) { + final String content = scanner.useDelimiter("\\Z").next(); + final ObjectMapper mapper = new ObjectMapper(); + final List userDetails = mapper.readValue(content, new TypeReference>() { + }); + userDetails.stream() + .map(this::convertToUsmUser) + .forEach(user -> snmpManager.getUSM().addUser(user)); + + } catch (FileNotFoundException e) { + throw new ProcessException("USM user file not found, please check the file path and file permissions.", e); + } catch (JsonProcessingException e) { + throw new ProcessException("Could not parse USM user file, please check the processor details for examples.", e); + } + } + } + + private UsmUser convertToUsmUser(final UserDetails user) { + return new UsmUser( + new OctetString(user.getSecurityName()), + SNMPUtils.getAuth(user.getAuthProtocol()), + new OctetString(user.getAuthPassphrase()), + SNMPUtils.getPriv(user.getPrivProtocol()), + new OctetString(user.getPrivPassphrase()) + ); + } + + // Visible for testing. + void setSnmpManager(final Snmp snmpManager) { + this.snmpManager = snmpManager; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java new file mode 100644 index 0000000000..f9f608d670 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandler.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.apache.nifi.snmp.factory.trap.V1TrapPDUFactory; +import org.apache.nifi.snmp.factory.trap.V2TrapPDUFactory; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.Target; + +import java.io.IOException; +import java.time.Instant; +import java.util.Map; + +public class SendTrapSNMPHandler { + private final SNMPResourceHandler snmpResourceHandler; + private final ComponentLog logger; + private final V1TrapPDUFactory v1TrapPDUFactory; + private final V2TrapPDUFactory v2TrapPDUFactory; + + public SendTrapSNMPHandler(final SNMPResourceHandler snmpResourceHandler, final Instant startTime, final ComponentLog logger) { + this.snmpResourceHandler = snmpResourceHandler; + this.logger = logger; + v1TrapPDUFactory = createV1TrapPduFactory(startTime); + v2TrapPDUFactory = createV2TrapPduFactory(startTime); + } + + public void sendTrap(final Map flowFileAttributes, final V1TrapConfiguration trapConfiguration) throws IOException { + final PDU pdu = v1TrapPDUFactory.get(trapConfiguration); + sendTrap(flowFileAttributes, pdu); + } + + public void sendTrap(final Map flowFileAttributes, final V2TrapConfiguration trapConfiguration) throws IOException { + final PDU pdu = v2TrapPDUFactory.get(trapConfiguration); + sendTrap(flowFileAttributes, pdu); + } + + private void sendTrap(Map flowFileAttributes, PDU pdu) throws IOException { + final Target target = snmpResourceHandler.getTarget(); + final Snmp snmpManager = snmpResourceHandler.getSnmpManager(); + + final boolean isAnyVariableAdded = SNMPUtils.addVariables(pdu, flowFileAttributes); + if (!isAnyVariableAdded) { + logger.debug("No optional SNMP specific variables found in flowfile."); + } + + snmpManager.send(pdu, target); + } + + V1TrapPDUFactory createV1TrapPduFactory(final Instant startTime) { + return new V1TrapPDUFactory(snmpResourceHandler.getTarget(), startTime); + } + + V2TrapPDUFactory createV2TrapPduFactory(final Instant startTime) { + return new V2TrapPDUFactory(snmpResourceHandler.getTarget(), startTime); + } +} \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SetSNMPHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SetSNMPHandler.java new file mode 100644 index 0000000000..f77c4eb33d --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SetSNMPHandler.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.snmp.dto.SNMPSingleResponse; +import org.apache.nifi.snmp.exception.RequestTimeoutException; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.event.ResponseEvent; +import org.snmp4j.util.DefaultPDUFactory; +import org.snmp4j.util.PDUFactory; + +import java.io.IOException; +import java.util.Map; +import java.util.Optional; + +import static org.apache.nifi.snmp.operations.SNMPResourceHandler.REQUEST_TIMEOUT_EXCEPTION_TEMPLATE; + +public class SetSNMPHandler { + private static PDUFactory setPduFactory = new DefaultPDUFactory(PDU.SET); + + private final SNMPResourceHandler snmpResourceHandler; + + public SetSNMPHandler(final SNMPResourceHandler snmpResourceHandler) { + this.snmpResourceHandler = snmpResourceHandler; + } + + public Optional set(final Map flowFileAttributes) throws IOException { + Target target = snmpResourceHandler.getTarget(); + Snmp snmpManager = snmpResourceHandler.getSnmpManager(); + + final PDU pdu = setPduFactory.createPDU(target); + final boolean isAnySnmpVariableInFlowFile = SNMPUtils.addVariables(pdu, flowFileAttributes); + if (isAnySnmpVariableInFlowFile) { + final ResponseEvent response = snmpManager.set(pdu, target); + final PDU responsePdu = response.getResponse(); + if (responsePdu == null) { + throw new RequestTimeoutException(String.format(REQUEST_TIMEOUT_EXCEPTION_TEMPLATE, "write")); + } + return Optional.of(new SNMPSingleResponse(target, responsePdu)); + } else { + return Optional.empty(); + } + } + + // visible for testing + static void setSetPduFactory(final PDUFactory setPduFactory) { + SetSNMPHandler.setPduFactory = setPduFactory; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/StandardSNMPRequestHandler.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/StandardSNMPRequestHandler.java deleted file mode 100644 index 47ce736b6a..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/StandardSNMPRequestHandler.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.operations; - -import org.apache.nifi.flowfile.FlowFile; -import org.apache.nifi.snmp.dto.SNMPSingleResponse; -import org.apache.nifi.snmp.dto.SNMPTreeResponse; -import org.apache.nifi.snmp.exception.CloseSNMPClientException; -import org.apache.nifi.snmp.exception.InvalidFlowFileException; -import org.apache.nifi.snmp.exception.RequestTimeoutException; -import org.apache.nifi.snmp.exception.SNMPWalkException; -import org.apache.nifi.snmp.utils.SNMPUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.snmp4j.PDU; -import org.snmp4j.Snmp; -import org.snmp4j.Target; -import org.snmp4j.event.ResponseEvent; -import org.snmp4j.security.SecurityModels; -import org.snmp4j.smi.Integer32; -import org.snmp4j.smi.OID; -import org.snmp4j.smi.VariableBinding; -import org.snmp4j.util.DefaultPDUFactory; -import org.snmp4j.util.PDUFactory; -import org.snmp4j.util.TreeEvent; -import org.snmp4j.util.TreeUtils; - -import java.io.IOException; -import java.util.List; - -final class StandardSNMPRequestHandler implements SNMPRequestHandler { - - private static final Logger logger = LoggerFactory.getLogger(StandardSNMPRequestHandler.class); - private static final PDUFactory getPduFactory = new DefaultPDUFactory(PDU.GET); - private static final PDUFactory setPduFactory = new DefaultPDUFactory(PDU.SET); - private final Snmp snmpManager; - private final Target target; - - StandardSNMPRequestHandler(final Snmp snmpManager, final Target target) { - this.snmpManager = snmpManager; - this.target = target; - } - - /** - * Construct the PDU to perform the SNMP Get request and returns - * the result in order to create the flow file. - * - * @return {@link ResponseEvent} - */ - public SNMPSingleResponse get(final String oid) throws IOException { - final PDU pdu = getPduFactory.createPDU(target); - pdu.add(new VariableBinding(new OID(oid))); - final ResponseEvent response = snmpManager.get(pdu, target); - final PDU responsePdu = response.getResponse(); - if (responsePdu == null) { - throw new RequestTimeoutException("Request timed out. Please check if (1). the agent host and port is correctly set, " + - "(2). the agent is running, (3). the agent SNMP version corresponds with the processor's one, (4) the " + - "community string is correct and has read access, (5) In case of SNMPv3 check if the user credentials " + - "are valid and the user in a group with read access."); - } - return new SNMPSingleResponse(target, responsePdu); - } - - /** - * Perform a SNMP walk and returns the list of {@link TreeEvent} - * - * @return the list of {@link TreeEvent} - */ - public SNMPTreeResponse walk(final String oid) { - final TreeUtils treeUtils = new TreeUtils(snmpManager, getPduFactory); - final List subtree = treeUtils.getSubtree(target, new OID(oid)); - if (subtree.isEmpty()) { - throw new SNMPWalkException(String.format("The subtree associated with the specified OID %s is empty.", oid)); - } - if (isSnmpError(subtree)) { - throw new SNMPWalkException("Agent is not available, OID not found or user not found. Please, check if (1) the " + - "agent is available, (2) the processor's SNMP version matches the agent version, (3) the OID is " + - "correct, (4) The user is valid."); - } - if (isLeafElement(subtree)) { - throw new SNMPWalkException(String.format("OID not found or it is a single leaf element. The leaf element " + - "associated with this %s OID does not contain child OIDs. Please check if the OID exists in the agent " + - "MIB or specify a parent OID with at least one child element", oid)); - } - - return new SNMPTreeResponse(target, subtree); - } - - private boolean isSnmpError(final List subtree) { - return subtree.size() == 1 && subtree.get(0).getVariableBindings() == null; - } - - private boolean isLeafElement(final List subtree) { - return subtree.size() == 1 && subtree.get(0).getVariableBindings().length == 0; - } - - /** - * Executes the SNMP set request and returns the response. - * - * @param flowFile FlowFile which contains variables for the PDU - * @return Response event - * @throws IOException IO Exception - */ - public SNMPSingleResponse set(final FlowFile flowFile) throws IOException { - final PDU pdu = setPduFactory.createPDU(target); - if (SNMPUtils.addVariables(pdu, flowFile.getAttributes())) { - final ResponseEvent response = snmpManager.set(pdu, target); - final PDU responsePdu = response.getResponse(); - if (responsePdu == null) { - throw new RequestTimeoutException("Request timed out. Please check if (1). the agent host and port is correctly set, " + - "(2). the agent is running, (3). the agent SNMP version corresponds with the processor's one, (4) the " + - "community string is correct and has write access, (5) In case of SNMPv3 check if the user credentials " + - "are valid and the user in a group with write access."); - } - return new SNMPSingleResponse(target, responsePdu); - } - throw new InvalidFlowFileException("Could not read the variable bindings from the flowfile. Please, " + - "add the OIDs to set in separate properties. E.g. Property name: snmp$1.3.6.1.2.1.1.1.0 Value: Example value. "); - } - - public void close() { - try { - if (snmpManager.getUSM() != null) { - snmpManager.getUSM().removeAllUsers(); - SecurityModels.getInstance().removeSecurityModel(new Integer32(snmpManager.getUSM().getID())); - } - snmpManager.close(); - } catch (IOException e) { - final String errorMessage = "Could not close SNMP client."; - logger.error(errorMessage, e); - throw new CloseSNMPClientException(errorMessage); - } - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessor.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessor.java index 7b9c5d080f..43c3a1095d 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessor.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessor.java @@ -19,7 +19,6 @@ package org.apache.nifi.snmp.processors; import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading; import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.annotation.lifecycle.OnStopped; -import org.apache.nifi.components.AllowableValue; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.processor.AbstractProcessor; @@ -27,21 +26,20 @@ import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessSession; import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.util.StandardValidators; -import org.apache.nifi.reporting.InitializationException; import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.apache.nifi.snmp.configuration.SNMPConfigurationBuilder; +import org.apache.nifi.snmp.dto.ErrorStatus; +import org.apache.nifi.snmp.dto.SNMPResponseStatus; import org.apache.nifi.snmp.dto.SNMPSingleResponse; import org.apache.nifi.snmp.dto.SNMPValue; -import org.apache.nifi.snmp.exception.SNMPException; +import org.apache.nifi.snmp.factory.core.SNMPFactoryProvider; import org.apache.nifi.snmp.logging.SLF4JLogFactory; -import org.apache.nifi.snmp.operations.SNMPRequestHandler; -import org.apache.nifi.snmp.operations.SNMPRequestHandlerFactory; +import org.apache.nifi.snmp.operations.SNMPResourceHandler; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V3SecurityProperties; import org.apache.nifi.snmp.utils.SNMPUtils; import org.snmp4j.log.LogFactory; import org.snmp4j.mp.SnmpConstants; -import java.util.HashMap; -import java.util.Map; import java.util.Optional; /** @@ -55,49 +53,7 @@ abstract class AbstractSNMPProcessor extends AbstractProcessor { LogFactory.setLogFactory(new SLF4JLogFactory()); } - private static final String SHA_2_ALGORITHM = "Provides authentication based on the HMAC-SHA-2 algorithm."; private static final String NO_SUCH_OBJECT = "noSuchObject"; - // SNMP versions - public static final AllowableValue SNMP_V1 = new AllowableValue("SNMPv1", "v1", "SNMP version 1"); - public static final AllowableValue SNMP_V2C = new AllowableValue("SNMPv2c", "v2c", "SNMP version 2c"); - public static final AllowableValue SNMP_V3 = new AllowableValue("SNMPv3", "v3", "SNMP version 3 with improved security"); - - // SNMPv3 security levels - public static final AllowableValue NO_AUTH_NO_PRIV = new AllowableValue("noAuthNoPriv", "noAuthNoPriv", - "No authentication or encryption."); - public static final AllowableValue AUTH_NO_PRIV = new AllowableValue("authNoPriv", "authNoPriv", - "Authentication without encryption."); - public static final AllowableValue AUTH_PRIV = new AllowableValue("authPriv", "authPriv", - "Authentication and encryption."); - - // SNMPv3 authentication protocols - public static final AllowableValue MD5 = new AllowableValue("MD5", "MD5", - "Provides authentication based on the HMAC-MD5 algorithm."); - public static final AllowableValue SHA = new AllowableValue("SHA", "SHA", - "Provides authentication based on the HMAC-SHA algorithm."); - public static final AllowableValue HMAC128SHA224 = new AllowableValue("HMAC128SHA224", "SHA224", - SHA_2_ALGORITHM); - public static final AllowableValue HMAC192SHA256 = new AllowableValue("HMAC192SHA256", "SHA256", - SHA_2_ALGORITHM); - public static final AllowableValue HMAC256SHA384 = new AllowableValue("HMAC256SHA384", "SHA384", - SHA_2_ALGORITHM); - public static final AllowableValue HMAC384SHA512 = new AllowableValue("HMAC384SHA512", "SHA512", - SHA_2_ALGORITHM); - - // SNMPv3 encryption - public static final AllowableValue DES = new AllowableValue("DES", "DES", - "Symmetric-key algorithm for the encryption of digital data. DES has been considered insecure" + - "because of the feasilibity of brute-force attacks. We recommend using the AES encryption protocol."); - public static final AllowableValue DES3 = new AllowableValue("3DES", "3DES", - "Symmetric-key block cipher, which applies the DES cipher algorithm three times to each data block." + - " 3DES has been considered insecure has been deprecated by NIST in 2017. We recommend using the AES encryption protocol."); - - private static final String AES_DESCRIPTION = "AES is a symmetric algorithm which uses the same 128, 192, or 256 bit" + - " key for both encryption and decryption (the security of an AES system increases exponentially with key length)."; - - public static final AllowableValue AES128 = new AllowableValue("AES128", "AES128", AES_DESCRIPTION); - public static final AllowableValue AES192 = new AllowableValue("AES192", "AES192", AES_DESCRIPTION); - public static final AllowableValue AES256 = new AllowableValue("AES256", "AES256", AES_DESCRIPTION); public static final PropertyDescriptor AGENT_HOST = new PropertyDescriptor.Builder() .name("snmp-hostname") @@ -117,136 +73,31 @@ abstract class AbstractSNMPProcessor extends AbstractProcessor { .addValidator(StandardValidators.PORT_VALIDATOR) .build(); - public static final PropertyDescriptor SNMP_VERSION = new PropertyDescriptor.Builder() - .name("snmp-version") - .displayName("SNMP Version") - .description("Three significant versions of SNMP have been developed and deployed. " + - "SNMPv1 is the original version of the protocol. More recent versions, " + - "SNMPv2c and SNMPv3, feature improvements in performance, flexibility and security.") - .required(true) - .allowableValues(SNMP_V1, SNMP_V2C, SNMP_V3) - .defaultValue(SNMP_V1.getValue()) - .build(); - - public static final PropertyDescriptor SNMP_COMMUNITY = new PropertyDescriptor.Builder() - .name("snmp-community") - .displayName("SNMP Community") - .description("SNMPv1 and SNMPv2 use communities to establish trust between managers and agents." + - " Most agents support three community names, one each for read-only, read-write and trap." + - " These three community strings control different types of activities. The read-only community" + - " applies to get requests. The read-write community string applies to set requests. The trap" + - " community string applies to receipt of traps.") - .required(true) - .sensitive(true) - .defaultValue("public") - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .dependsOn(SNMP_VERSION, SNMP_V1, SNMP_V2C) - .build(); - - public static final PropertyDescriptor SNMP_SECURITY_LEVEL = new PropertyDescriptor.Builder() - .name("snmp-security-level") - .displayName("SNMP Security Level") - .description("SNMP version 3 provides extra security with User Based Security Model (USM). The three levels of security is " + - "1. Communication without authentication and encryption (NoAuthNoPriv). " + - "2. Communication with authentication and without encryption (AuthNoPriv). " + - "3. Communication with authentication and encryption (AuthPriv).") - .required(true) - .allowableValues(NO_AUTH_NO_PRIV, AUTH_NO_PRIV, AUTH_PRIV) - .defaultValue(NO_AUTH_NO_PRIV.getValue()) - .dependsOn(SNMP_VERSION, SNMP_V3) - .build(); - - public static final PropertyDescriptor SNMP_SECURITY_NAME = new PropertyDescriptor.Builder() - .name("snmp-security-name") - .displayName("SNMP Security Name") - .description("User name used for SNMP v3 Authentication.") - .required(true) - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .dependsOn(SNMP_VERSION, SNMP_V3) - .build(); - - public static final PropertyDescriptor SNMP_AUTH_PROTOCOL = new PropertyDescriptor.Builder() - .name("snmp-authentication-protocol") - .displayName("SNMP Authentication Protocol") - .description("Hash based authentication protocol for secure authentication.") - .required(true) - .allowableValues(MD5, SHA, HMAC128SHA224, HMAC192SHA256, HMAC256SHA384, HMAC384SHA512) - .dependsOn(SNMP_SECURITY_LEVEL, AUTH_NO_PRIV, AUTH_PRIV) - .build(); - - public static final PropertyDescriptor SNMP_AUTH_PASSWORD = new PropertyDescriptor.Builder() - .name("snmp-authentication-passphrase") - .displayName("SNMP Authentication Passphrase") - .description("Passphrase used for SNMP authentication protocol.") - .required(true) - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .sensitive(true) - .dependsOn(SNMP_SECURITY_LEVEL, AUTH_NO_PRIV, AUTH_PRIV) - .build(); - - public static final PropertyDescriptor SNMP_PRIVACY_PROTOCOL = new PropertyDescriptor.Builder() - .name("snmp-private-protocol") - .displayName("SNMP Privacy Protocol") - .description("Privacy allows for encryption of SNMP v3 messages to ensure confidentiality of data.") - .required(true) - .allowableValues(DES, DES3, AES128, AES192, AES256) - .dependsOn(SNMP_SECURITY_LEVEL, AUTH_PRIV) - .build(); - - public static final PropertyDescriptor SNMP_PRIVACY_PASSWORD = new PropertyDescriptor.Builder() - .name("snmp-private-protocol-passphrase") - .displayName("SNMP Privacy Passphrase") - .description("Passphrase used for SNMP privacy protocol.") - .required(true) - .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .sensitive(true) - .dependsOn(SNMP_SECURITY_LEVEL, AUTH_PRIV) - .build(); - - public static final PropertyDescriptor SNMP_RETRIES = new PropertyDescriptor.Builder() - .name("snmp-retries") - .displayName("Number of Retries") - .description("Set the number of retries when requesting the SNMP Agent.") - .required(false) - .defaultValue("0") - .addValidator(StandardValidators.NON_NEGATIVE_INTEGER_VALIDATOR) - .build(); - - public static final PropertyDescriptor SNMP_TIMEOUT = new PropertyDescriptor.Builder() - .name("snmp-timeout") - .displayName("Timeout (ms)") - .description("Set the timeout (in milliseconds) when requesting the SNMP Agent.") - .required(false) - .defaultValue("5000") - .addValidator(StandardValidators.NON_NEGATIVE_INTEGER_VALIDATOR) - .build(); - - - protected volatile SNMPRequestHandler snmpRequestHandler; + protected volatile SNMPResourceHandler snmpResourceHandler; @OnScheduled - public void initSnmpManager(final ProcessContext context) throws InitializationException { - final int version = SNMPUtils.getVersion(context.getProperty(SNMP_VERSION).getValue()); + public void initSnmpManager(final ProcessContext context) { + final int version = SNMPUtils.getVersion(context.getProperty(BasicProperties.SNMP_VERSION).getValue()); final SNMPConfiguration configuration; - try { - configuration = new SNMPConfigurationBuilder() - .setAgentHost(context.getProperty(AGENT_HOST).getValue()) - .setAgentPort(context.getProperty(AGENT_PORT).toString()) - .setRetries(context.getProperty(SNMP_RETRIES).asInteger()) - .setTimeout(context.getProperty(SNMP_TIMEOUT).asInteger()) - .setVersion(version) - .setAuthProtocol(context.getProperty(SNMP_AUTH_PROTOCOL).getValue()) - .setAuthPassphrase(context.getProperty(SNMP_AUTH_PASSWORD).getValue()) - .setPrivacyProtocol(context.getProperty(SNMP_PRIVACY_PROTOCOL).getValue()) - .setPrivacyPassphrase(context.getProperty(SNMP_PRIVACY_PASSWORD).getValue()) - .setSecurityName(context.getProperty(SNMP_SECURITY_NAME).getValue()) - .setSecurityLevel(context.getProperty(SNMP_SECURITY_LEVEL).getValue()) - .setCommunityString(context.getProperty(SNMP_COMMUNITY).getValue()) - .build(); - } catch (IllegalStateException e) { - throw new InitializationException(e); - } - snmpRequestHandler = SNMPRequestHandlerFactory.createStandardRequestHandler(configuration); + final String targetHost = getTargetHost(context); + final String targetPort = getTargetPort(context); + + configuration = SNMPConfiguration.builder() + .setTargetHost(targetHost) + .setTargetPort(targetPort) + .setRetries(context.getProperty(BasicProperties.SNMP_RETRIES).asInteger()) + .setTimeoutInMs(context.getProperty(BasicProperties.SNMP_TIMEOUT).asInteger()) + .setVersion(version) + .setAuthProtocol(context.getProperty(V3SecurityProperties.SNMP_AUTH_PROTOCOL).getValue()) + .setAuthPassphrase(context.getProperty(V3SecurityProperties.SNMP_AUTH_PASSWORD).getValue()) + .setPrivacyProtocol(context.getProperty(V3SecurityProperties.SNMP_PRIVACY_PROTOCOL).getValue()) + .setPrivacyPassphrase(context.getProperty(V3SecurityProperties.SNMP_PRIVACY_PASSWORD).getValue()) + .setSecurityName(context.getProperty(V3SecurityProperties.SNMP_SECURITY_NAME).getValue()) + .setSecurityLevel(context.getProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL).getValue()) + .setCommunityString(context.getProperty(BasicProperties.SNMP_COMMUNITY).getValue()) + .build(); + + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(configuration); } /** @@ -254,61 +105,61 @@ abstract class AbstractSNMPProcessor extends AbstractProcessor { */ @OnStopped public void close() { - if (snmpRequestHandler != null) { - snmpRequestHandler.close(); - snmpRequestHandler = null; + if (snmpResourceHandler != null) { + snmpResourceHandler.close(); + snmpResourceHandler = null; } } - /** - * Method to add attribute in flow file - * - * @param key attribute key - * @param value attribute value - * @param flowFile flow file to update - * @param processSession session - * @return updated flow file - */ - protected FlowFile addAttribute(final String key, final String value, FlowFile flowFile, final ProcessSession processSession) { - final Map attributes = new HashMap<>(); - attributes.put(key, value); - flowFile = processSession.putAllAttributes(flowFile, attributes); - return flowFile; + protected void handleResponse(final ProcessContext context, final ProcessSession processSession, final FlowFile flowFile, final SNMPSingleResponse response, + final Relationship success, final Relationship failure, final String provenanceAddress) { + final SNMPResponseStatus snmpResponseStatus = processResponse(response); + processSession.putAllAttributes(flowFile, response.getAttributes()); + if (snmpResponseStatus.getErrorStatus() == ErrorStatus.FAILURE) { + getLogger().error("SNMP request failed, response error: " + snmpResponseStatus.getErrorMessage()); + processSession.getProvenanceReporter().modifyAttributes(flowFile, response.getTargetAddress() + provenanceAddress); + processSession.transfer(flowFile, failure); + context.yield(); + } else { + processSession.getProvenanceReporter().modifyAttributes(flowFile, response.getTargetAddress() + provenanceAddress); + processSession.transfer(flowFile, success); + } } - protected void processResponse(final ProcessSession processSession, FlowFile flowFile, final SNMPSingleResponse response, - final String provenanceAddress, final Relationship success) { + protected SNMPResponseStatus processResponse(final SNMPSingleResponse response) { if (response.isValid()) { if (response.isReportPdu()) { final String oid = response.getVariableBindings().get(0).getOid(); final Optional reportPduErrorMessage = SNMPUtils.getErrorMessage(oid); if (!reportPduErrorMessage.isPresent()) { - throw new SNMPException(String.format("SNMP request failed, Report-PDU returned, but no error message found. " + - "Please, check the OID %s in an online OID repository.", oid)); + return new SNMPResponseStatus(String.format("Report-PDU returned, but no error message found. " + + "Please, check the OID %s in an online OID repository.", oid), ErrorStatus.FAILURE); } - throw new SNMPException("SNMPRequest failed, Report-PDU returned. " + reportPduErrorMessage.get()); + return new SNMPResponseStatus("Report-PDU returned. " + reportPduErrorMessage.get(), ErrorStatus.FAILURE); } - checkV2cV3VariableBindings(response); - flowFile = processSession.putAllAttributes(flowFile, response.getAttributes()); - processSession.transfer(flowFile, success); - processSession.getProvenanceReporter().receive(flowFile, provenanceAddress); + return checkV2cV3VariableBindings(response); } else { - final String error = response.getErrorStatusText(); - throw new SNMPException("SNMP request failed, response error: " + error); + final String errorMessage = response.getErrorStatusText(); + return new SNMPResponseStatus(errorMessage, ErrorStatus.FAILURE); } } - private void checkV2cV3VariableBindings(SNMPSingleResponse response) { - if (response.getVersion() != SnmpConstants.version1) { + private SNMPResponseStatus checkV2cV3VariableBindings(SNMPSingleResponse response) { + if (response.getVersion() == SnmpConstants.version2c || response.getVersion() == SnmpConstants.version3) { final Optional firstVariableBinding = response.getVariableBindings().stream().findFirst(); if (firstVariableBinding.isPresent()) { final String value = firstVariableBinding.get().getVariable(); if (NO_SUCH_OBJECT.equals(value)) { - throw new SNMPException("SNMP Request failed, OID not found."); + return new SNMPResponseStatus("OID not found.", ErrorStatus.FAILURE); } } else { - throw new SNMPException("Empty SNMP response: no variable binding found."); + return new SNMPResponseStatus("Empty SNMP response: no variable binding found.", ErrorStatus.FAILURE); } } + return new SNMPResponseStatus("Successful SNMP Response", ErrorStatus.SUCCESS); } + + protected abstract String getTargetHost(ProcessContext processContext); + + protected abstract String getTargetPort(ProcessContext processContext); } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/GetSNMP.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/GetSNMP.java index 58a08bde66..2aa29ab8ef 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/GetSNMP.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/GetSNMP.java @@ -22,6 +22,7 @@ import org.apache.nifi.annotation.behavior.WritesAttribute; import org.apache.nifi.annotation.behavior.WritesAttributes; import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.components.AllowableValue; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.flowfile.FlowFile; @@ -31,8 +32,10 @@ import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.snmp.dto.SNMPSingleResponse; import org.apache.nifi.snmp.dto.SNMPTreeResponse; -import org.apache.nifi.snmp.exception.SNMPException; import org.apache.nifi.snmp.exception.SNMPWalkException; +import org.apache.nifi.snmp.operations.GetSNMPHandler; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V3SecurityProperties; import org.apache.nifi.snmp.utils.SNMPUtils; import org.apache.nifi.snmp.validators.OIDValidator; @@ -41,16 +44,20 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.Set; /** - * Retrieving data from configured SNMP agent which, upon each invocation of - * {@link #onTrigger(ProcessContext, ProcessSession)} method, will construct a - * {@link FlowFile} containing in its properties the information retrieved. + * Performs an SNMP Get operation based on processor or incoming FlowFile attributes. + * Upon each invocation of {@link #onTrigger(ProcessContext, ProcessSession)} + * method, in case of a valid incoming FlowFile, it will inspect the attributes of + * the FlowFile and look for attributes with name formatted as "snmp$OID" to set the + * attribute value to this OID. * The output {@link FlowFile} won't have any content. */ @Tags({"snmp", "get", "oid", "walk"}) -@InputRequirement(Requirement.INPUT_FORBIDDEN) +@InputRequirement(Requirement.INPUT_ALLOWED) @CapabilityDescription("Retrieves information from SNMP Agent with SNMP Get request and outputs a FlowFile with information" + " in attributes and without any content") @WritesAttributes({ @@ -74,11 +81,12 @@ public class GetSNMP extends AbstractSNMPProcessor { "A manager-to-agent request to retrieve the value of multiple variables. Snmp WALK also traverses all subnodes " + "under the specified OID."); - // OID to request (if walk, it is the root ID of the request). public static final PropertyDescriptor OID = new PropertyDescriptor.Builder() .name("snmp-oid") .displayName("OID") - .description("Each OID (object identifier) identifies a variable that can be read or set via SNMP.") + .description("Each OID (object identifier) identifies a variable that can be read or set via SNMP." + + " This value is not taken into account for an input flowfile and will be omitted. Can be set to empty" + + "string when the OIDs are provided through flowfile.") .required(true) .addValidator(new OIDValidator()) .build(); @@ -95,7 +103,8 @@ public class GetSNMP extends AbstractSNMPProcessor { public static final PropertyDescriptor TEXTUAL_OID = new PropertyDescriptor.Builder() .name("snmp-textual-oid") .displayName("Textual OID") - .description("The textual OID to request.") + .description("The textual form of the numeric OID to request. This property is user defined, not processed and appended to " + + "the outgoing flowfile.") .required(false) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .defaultValue(null) @@ -114,16 +123,16 @@ public class GetSNMP extends AbstractSNMPProcessor { protected static final List PROPERTY_DESCRIPTORS = Collections.unmodifiableList(Arrays.asList( AGENT_HOST, AGENT_PORT, - SNMP_VERSION, - SNMP_COMMUNITY, - SNMP_SECURITY_LEVEL, - SNMP_SECURITY_NAME, - SNMP_AUTH_PROTOCOL, - SNMP_AUTH_PASSWORD, - SNMP_PRIVACY_PROTOCOL, - SNMP_PRIVACY_PASSWORD, - SNMP_RETRIES, - SNMP_TIMEOUT, + BasicProperties.SNMP_VERSION, + BasicProperties.SNMP_COMMUNITY, + V3SecurityProperties.SNMP_SECURITY_LEVEL, + V3SecurityProperties.SNMP_SECURITY_NAME, + V3SecurityProperties.SNMP_AUTH_PROTOCOL, + V3SecurityProperties.SNMP_AUTH_PASSWORD, + V3SecurityProperties.SNMP_PRIVACY_PROTOCOL, + V3SecurityProperties.SNMP_PRIVACY_PASSWORD, + BasicProperties.SNMP_RETRIES, + BasicProperties.SNMP_TIMEOUT, OID, TEXTUAL_OID, SNMP_STRATEGY @@ -134,54 +143,100 @@ public class GetSNMP extends AbstractSNMPProcessor { REL_FAILURE ))); + private volatile GetSNMPHandler snmpHandler; + + @OnScheduled + public void init(final ProcessContext context) { + initSnmpManager(context); + snmpHandler = new GetSNMPHandler(snmpResourceHandler); + } + @Override public void onTrigger(final ProcessContext context, final ProcessSession processSession) { final SNMPStrategy snmpStrategy = SNMPStrategy.valueOf(context.getProperty(SNMP_STRATEGY).getValue()); final String oid = context.getProperty(OID).getValue(); + final FlowFile flowfile = processSession.get(); if (SNMPStrategy.GET == snmpStrategy) { - performSnmpGet(context, processSession, oid); + performSnmpGet(context, processSession, oid, flowfile); } else if (SNMPStrategy.WALK == snmpStrategy) { - performSnmpWalk(context, processSession, oid); + performSnmpWalk(context, processSession, oid, flowfile); } } - private void performSnmpWalk(final ProcessContext context, final ProcessSession processSession, final String oid) { + void performSnmpWalk(final ProcessContext context, final ProcessSession processSession, final String oid, + final FlowFile flowFile) { try { - final SNMPTreeResponse response = snmpRequestHandler.walk(oid); - response.logErrors(getLogger()); - FlowFile flowFile = createFlowFileWithTreeEventProperties(response, processSession); - processSession.getProvenanceReporter().receive(flowFile, response.getTargetAddress() + "/" + oid); - processSession.transfer(flowFile, REL_SUCCESS); + if (flowFile != null) { + performSnmpWalkWithFlowFile(processSession, flowFile); + } else { + performSnmpWalkWithoutFlowFile(processSession, oid); + } } catch (SNMPWalkException e) { getLogger().error(e.getMessage()); context.yield(); - processSession.rollback(); } } - private void performSnmpGet(final ProcessContext context, final ProcessSession processSession, final String oid) { - final SNMPSingleResponse response; + private void performSnmpWalkWithFlowFile(ProcessSession processSession, FlowFile flowFile) { + final Optional optionalResponse = snmpHandler.walk(flowFile.getAttributes()); + if (optionalResponse.isPresent()) { + final SNMPTreeResponse response = optionalResponse.get(); + response.logErrors(getLogger()); + processSession.putAllAttributes(flowFile, response.getAttributes()); + processSession.getProvenanceReporter().modifyAttributes(flowFile, response.getTargetAddress() + "/walk"); + processSession.transfer(flowFile, response.isError() ? REL_FAILURE : REL_SUCCESS); + } else { + getLogger().warn("No SNMP specific attributes found in flowfile."); + processSession.getProvenanceReporter().receive(flowFile, "/walk"); + processSession.transfer(flowFile, REL_FAILURE); + } + } + + private void performSnmpWalkWithoutFlowFile(ProcessSession processSession, String oid) { + final SNMPTreeResponse response = snmpHandler.walk(oid); + response.logErrors(getLogger()); + final FlowFile outgoingFlowFile = processSession.create(); + processSession.putAllAttributes(outgoingFlowFile, response.getAttributes()); + processSession.getProvenanceReporter().create(outgoingFlowFile, response.getTargetAddress() + "/walk"); + processSession.transfer(outgoingFlowFile, REL_SUCCESS); + } + + void performSnmpGet(final ProcessContext context, final ProcessSession processSession, final String oid, + final FlowFile flowFile) { + final String textualOidKey = SNMPUtils.SNMP_PROP_PREFIX + "textualOid"; + final Map textualOidMap = Collections.singletonMap(textualOidKey, context.getProperty(TEXTUAL_OID).getValue()); try { - response = snmpRequestHandler.get(oid); - final FlowFile flowFile = processSession.create(); - addAttribute(SNMPUtils.SNMP_PROP_PREFIX + "textualOid", context.getProperty(TEXTUAL_OID).getValue(), flowFile, processSession); - final String provenanceAddress = response.getTargetAddress() + "/" + oid; - processResponse(processSession, flowFile, response, provenanceAddress, REL_SUCCESS); - } catch (SNMPException e) { - getLogger().error(e.getMessage()); - context.yield(); - processSession.rollback(); + if (flowFile != null) { + performSnmpGetWithFlowFile(context, processSession, flowFile, textualOidMap); + } else { + performSnmpGetWithoutFlowFile(context, processSession, oid, textualOidMap); + } } catch (IOException e) { - getLogger().error("Failed to send request to the agent. Check if the agent supports the used version."); + getLogger().error("Failed to send request to the agent. Check if the agent supports the used version.", e); context.yield(); - processSession.rollback(); } } - @Override - protected List getSupportedPropertyDescriptors() { - return PROPERTY_DESCRIPTORS; + private void performSnmpGetWithoutFlowFile(ProcessContext context, ProcessSession processSession, String oid, Map textualOidMap) throws IOException { + final SNMPSingleResponse response = snmpHandler.get(oid); + final FlowFile outgoingFlowFile = processSession.create(); + processSession.putAllAttributes(outgoingFlowFile, textualOidMap); + processSession.getProvenanceReporter().receive(outgoingFlowFile, response.getTargetAddress() + "/get"); + handleResponse(context, processSession, outgoingFlowFile, response, REL_SUCCESS, REL_FAILURE, "/get"); + } + + private void performSnmpGetWithFlowFile(ProcessContext context, ProcessSession processSession, FlowFile flowFile, Map textualOidMap) throws IOException { + final Optional optionalResponse = snmpHandler.get(flowFile.getAttributes()); + if (optionalResponse.isPresent()) { + final SNMPSingleResponse response = optionalResponse.get(); + processSession.putAllAttributes(flowFile, textualOidMap); + handleResponse(context, processSession, flowFile, response, REL_SUCCESS, REL_FAILURE, "/get"); + } else { + getLogger().warn("No SNMP specific attributes found in flowfile."); + processSession.transfer(flowFile, REL_FAILURE); + context.yield(); + } } @Override @@ -189,10 +244,18 @@ public class GetSNMP extends AbstractSNMPProcessor { return RELATIONSHIPS; } - private FlowFile createFlowFileWithTreeEventProperties(final SNMPTreeResponse response, final ProcessSession processSession) { - FlowFile flowFile = processSession.create(); - flowFile = processSession.putAllAttributes(flowFile, response.getAttributes()); - return flowFile; + @Override + protected List getSupportedPropertyDescriptors() { + return PROPERTY_DESCRIPTORS; + } + + protected String getTargetHost(ProcessContext processContext) { + return processContext.getProperty(AGENT_HOST).getValue(); + } + + @Override + protected String getTargetPort(ProcessContext processContext) { + return processContext.getProperty(AGENT_PORT).getValue(); } private enum SNMPStrategy { diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java new file mode 100644 index 0000000000..b36ff7d226 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors; + +import org.apache.nifi.annotation.behavior.InputRequirement; +import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading; +import org.apache.nifi.annotation.behavior.WritesAttribute; +import org.apache.nifi.annotation.documentation.CapabilityDescription; +import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnScheduled; +import org.apache.nifi.annotation.lifecycle.OnStopped; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.processor.AbstractSessionFactoryProcessor; +import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processor.ProcessSessionFactory; +import org.apache.nifi.processor.Relationship; +import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.operations.SNMPTrapReceiverHandler; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V3SecurityProperties; +import org.apache.nifi.snmp.utils.SNMPUtils; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Receiving data from a configured SNMP agent which, upon each invocation of + * {@link #onTrigger(ProcessContext, ProcessSessionFactory)} method, will construct a + * {@link FlowFile} containing in its properties the information retrieved. + * The output {@link FlowFile} won't have any content. + */ +@Tags({"snmp", "listen", "trap"}) +@InputRequirement(InputRequirement.Requirement.INPUT_FORBIDDEN) +@CapabilityDescription("Receives information from SNMP Agent and outputs a FlowFile with information in attributes and without any content") +@WritesAttribute(attribute = SNMPUtils.SNMP_PROP_PREFIX + "*", description = "Attributes retrieved from the SNMP response. It may include:" + + " snmp$errorIndex, snmp$errorStatus, snmp$errorStatusText, snmp$nonRepeaters, snmp$requestID, snmp$type, snmp$variableBindings") +@RequiresInstanceClassLoading +public class ListenTrapSNMP extends AbstractSessionFactoryProcessor { + + public static final PropertyDescriptor SNMP_MANAGER_PORT = new PropertyDescriptor.Builder() + .name("snmp-manager-port") + .displayName("SNMP Manager Port") + .description("The port where the SNMP Manager listens to the incoming traps.") + .required(true) + .defaultValue("0") + .addValidator(StandardValidators.PORT_VALIDATOR) + .build(); + + public static final PropertyDescriptor SNMP_USM_USERS_FILE_PATH = new PropertyDescriptor.Builder() + .name("snmp-usm-users-file-path") + .displayName("SNMP Users File Path") + .description("The path of the json file containing the user credentials for SNMPv3. Check Usage for more details.") + .required(true) + .defaultValue("") + .dependsOn(BasicProperties.SNMP_VERSION, BasicProperties.SNMP_V3) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .build(); + + public static final Relationship REL_SUCCESS = new Relationship.Builder() + .name("success") + .description("All FlowFiles that are received from the SNMP agent are routed to this relationship") + .build(); + + public static final Relationship REL_FAILURE = new Relationship.Builder() + .name("failure") + .description("All FlowFiles that cannot received from the SNMP agent are routed to this relationship") + .build(); + + protected static final List PROPERTY_DESCRIPTORS = Collections.unmodifiableList(Arrays.asList( + SNMP_MANAGER_PORT, + BasicProperties.SNMP_VERSION, + BasicProperties.SNMP_COMMUNITY, + V3SecurityProperties.SNMP_SECURITY_LEVEL, + SNMP_USM_USERS_FILE_PATH + )); + + private static final Set RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + REL_SUCCESS, + REL_FAILURE + ))); + + private volatile SNMPTrapReceiverHandler snmpTrapReceiverHandler; + + @OnScheduled + public void initSnmpManager(ProcessContext context) { + final int version = SNMPUtils.getVersion(context.getProperty(BasicProperties.SNMP_VERSION).getValue()); + final int managerPort = context.getProperty(SNMP_MANAGER_PORT).asInteger(); + final String usmUsersFilePath = context.getProperty(SNMP_USM_USERS_FILE_PATH).getValue(); + SNMPConfiguration configuration; + + configuration = SNMPConfiguration.builder() + .setManagerPort(managerPort) + .setVersion(version) + .setSecurityLevel(context.getProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL).getValue()) + .setCommunityString(context.getProperty(BasicProperties.SNMP_COMMUNITY).getValue()) + .build(); + + snmpTrapReceiverHandler = new SNMPTrapReceiverHandler(configuration, usmUsersFilePath); + } + + @Override + public void onTrigger(final ProcessContext context, final ProcessSessionFactory processSessionFactory) { + if (!snmpTrapReceiverHandler.isStarted()) { + snmpTrapReceiverHandler.createTrapReceiver(processSessionFactory, getLogger()); + } + } + + @OnStopped + public void close() { + if (snmpTrapReceiverHandler != null) { + snmpTrapReceiverHandler.close(); + } + } + + @Override + public Set getRelationships() { + return RELATIONSHIPS; + } + + @Override + protected List getSupportedPropertyDescriptors() { + return PROPERTY_DESCRIPTORS; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java new file mode 100644 index 0000000000..04b06e62fc --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors; + +import org.apache.nifi.annotation.behavior.InputRequirement; +import org.apache.nifi.annotation.behavior.InputRequirement.Requirement; +import org.apache.nifi.annotation.documentation.CapabilityDescription; +import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnScheduled; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processor.ProcessSession; +import org.apache.nifi.processor.Relationship; +import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.apache.nifi.snmp.operations.SendTrapSNMPHandler; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V1TrapProperties; +import org.apache.nifi.snmp.processors.properties.V2TrapProperties; +import org.apache.nifi.snmp.processors.properties.V3SecurityProperties; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.mp.SnmpConstants; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Sends data to an SNMP manager which, upon each invocation of + * {@link #onTrigger(ProcessContext, ProcessSession)} method, will construct a + * {@link FlowFile} containing in its properties the information retrieved. + * The output {@link FlowFile} won't have any content. + */ +@Tags({"snmp", "send", "trap"}) +@InputRequirement(Requirement.INPUT_ALLOWED) +@CapabilityDescription("Sends information to SNMP Manager.") +public class SendTrapSNMP extends AbstractSNMPProcessor { + + public static final PropertyDescriptor SNMP_MANAGER_HOST = new PropertyDescriptor.Builder() + .name("snmp-trap-manager-host") + .displayName("SNMP Manager Host") + .description("The host where the SNMP Manager sends the trap.") + .required(true) + .defaultValue("localhost") + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .build(); + + public static final PropertyDescriptor SNMP_MANAGER_PORT = new PropertyDescriptor.Builder() + .name("snmp-trap-manager-port") + .displayName("SNMP Manager Port") + .description("The port where the SNMP Manager listens to the incoming traps.") + .required(true) + .defaultValue("0") + .addValidator(StandardValidators.PORT_VALIDATOR) + .build(); + + public static final Relationship REL_SUCCESS = new Relationship.Builder() + .name("success") + .description("All FlowFiles that have been successfully used to perform SNMP Set are routed to this relationship") + .build(); + + public static final Relationship REL_FAILURE = new Relationship.Builder() + .name("failure") + .description("All FlowFiles that cannot received from the SNMP agent are routed to this relationship") + .build(); + + protected static final List PROPERTY_DESCRIPTORS = Collections.unmodifiableList(Arrays.asList( + SNMP_MANAGER_HOST, + SNMP_MANAGER_PORT, + BasicProperties.SNMP_VERSION, + BasicProperties.SNMP_COMMUNITY, + V3SecurityProperties.SNMP_SECURITY_LEVEL, + V3SecurityProperties.SNMP_SECURITY_NAME, + V3SecurityProperties.SNMP_AUTH_PROTOCOL, + V3SecurityProperties.SNMP_AUTH_PASSWORD, + V3SecurityProperties.SNMP_PRIVACY_PROTOCOL, + V3SecurityProperties.SNMP_PRIVACY_PASSWORD, + BasicProperties.SNMP_RETRIES, + BasicProperties.SNMP_TIMEOUT, + V1TrapProperties.ENTERPRISE_OID, + V1TrapProperties.AGENT_ADDRESS, + V1TrapProperties.GENERIC_TRAP_TYPE, + V1TrapProperties.SPECIFIC_TRAP_TYPE, + V2TrapProperties.TRAP_OID_VALUE + )); + + private static final Set RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + REL_SUCCESS, REL_FAILURE + ))); + + private volatile SendTrapSNMPHandler snmpHandler; + + @OnScheduled + public void init(ProcessContext context) { + Instant startTime = Instant.now(); + initSnmpManager(context); + snmpHandler = new SendTrapSNMPHandler(snmpResourceHandler, startTime, getLogger()); + } + + @Override + public void onTrigger(final ProcessContext context, final ProcessSession processSession) { + final FlowFile flowFile = processSession.get(); + if (flowFile != null) { + try { + final int snmpVersion = SNMPUtils.getVersion(context.getProperty(BasicProperties.SNMP_VERSION).getValue()); + if (SnmpConstants.version1 == snmpVersion) { + V1TrapConfiguration v1TrapConfiguration = V1TrapConfiguration.builder() + .enterpriseOid(context.getProperty(V1TrapProperties.ENTERPRISE_OID).evaluateAttributeExpressions(flowFile).getValue()) + .agentAddress(context.getProperty(V1TrapProperties.AGENT_ADDRESS).evaluateAttributeExpressions(flowFile).getValue()) + .genericTrapType(context.getProperty(V1TrapProperties.GENERIC_TRAP_TYPE).evaluateAttributeExpressions(flowFile).getValue()) + .specificTrapType(context.getProperty(V1TrapProperties.SPECIFIC_TRAP_TYPE).evaluateAttributeExpressions(flowFile).getValue()) + .build(); + snmpHandler.sendTrap(flowFile.getAttributes(), v1TrapConfiguration); + } else { + V2TrapConfiguration v2TrapConfiguration = new V2TrapConfiguration( + context.getProperty(V2TrapProperties.TRAP_OID_VALUE).evaluateAttributeExpressions(flowFile).getValue() + ); + snmpHandler.sendTrap(flowFile.getAttributes(), v2TrapConfiguration); + } + processSession.transfer(flowFile, REL_SUCCESS); + } catch (IOException e) { + getLogger().error("Failed to send request to the agent. Check if the agent supports the used version.", e); + processSession.transfer(processSession.penalize(flowFile), REL_FAILURE); + } catch (IllegalArgumentException e) { + getLogger().error("Invalid trap configuration.", e); + processSession.transfer(processSession.penalize(flowFile), REL_FAILURE); + } + } + } + + @Override + public Set getRelationships() { + return RELATIONSHIPS; + } + + @Override + protected List getSupportedPropertyDescriptors() { + return PROPERTY_DESCRIPTORS; + } + + @Override + protected String getTargetHost(ProcessContext processContext) { + return processContext.getProperty(SNMP_MANAGER_HOST).getValue(); + } + + @Override + protected String getTargetPort(ProcessContext processContext) { + return processContext.getProperty(SNMP_MANAGER_PORT).getValue(); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SetSNMP.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SetSNMP.java index ab5ca72359..74d18a071a 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SetSNMP.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SetSNMP.java @@ -22,13 +22,16 @@ import org.apache.nifi.annotation.behavior.WritesAttribute; import org.apache.nifi.annotation.behavior.WritesAttributes; import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.ProcessSession; import org.apache.nifi.processor.Relationship; import org.apache.nifi.snmp.dto.SNMPSingleResponse; -import org.apache.nifi.snmp.exception.SNMPException; +import org.apache.nifi.snmp.operations.SetSNMPHandler; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V3SecurityProperties; import org.apache.nifi.snmp.utils.SNMPUtils; import java.io.IOException; @@ -36,19 +39,21 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; /** - * Performs a SNMP Set operation based on attributes of incoming FlowFile. + * Performs an SNMP Set operation based on attributes of incoming FlowFile. * Upon each invocation of {@link #onTrigger(ProcessContext, ProcessSession)} * method, it will inspect attributes of FlowFile and look for attributes with * name formatted as "snmp$OID" to set the attribute value to this OID. + * The output {@link FlowFile} won't have any content. */ @Tags({"snmp", "set", "oid"}) @InputRequirement(Requirement.INPUT_REQUIRED) @CapabilityDescription("Based on incoming FlowFile attributes, the processor will execute SNMP Set requests." + " When finding attributes with the name snmp$, the processor will attempt to set the value of" + - " the attribute to the corresponding OID given in the attribute name") + " the attribute to the corresponding OID given in the attribute name.") @WritesAttributes({ @WritesAttribute(attribute = SNMPUtils.SNMP_PROP_PREFIX + "", description = "Response variable binding: OID (e.g. 1.3.6.1.4.1.343) and its value."), @WritesAttribute(attribute = SNMPUtils.SNMP_PROP_PREFIX + "errorIndex", description = "Denotes the variable binding in which the error occured."), @@ -74,16 +79,16 @@ public class SetSNMP extends AbstractSNMPProcessor { private static final List PROPERTY_DESCRIPTORS = Collections.unmodifiableList(Arrays.asList( AGENT_HOST, AGENT_PORT, - SNMP_VERSION, - SNMP_COMMUNITY, - SNMP_SECURITY_LEVEL, - SNMP_SECURITY_NAME, - SNMP_AUTH_PROTOCOL, - SNMP_AUTH_PASSWORD, - SNMP_PRIVACY_PROTOCOL, - SNMP_PRIVACY_PASSWORD, - SNMP_RETRIES, - SNMP_TIMEOUT + BasicProperties.SNMP_VERSION, + BasicProperties.SNMP_COMMUNITY, + V3SecurityProperties.SNMP_SECURITY_LEVEL, + V3SecurityProperties.SNMP_SECURITY_NAME, + V3SecurityProperties.SNMP_AUTH_PROTOCOL, + V3SecurityProperties.SNMP_AUTH_PASSWORD, + V3SecurityProperties.SNMP_PRIVACY_PROTOCOL, + V3SecurityProperties.SNMP_PRIVACY_PASSWORD, + BasicProperties.SNMP_RETRIES, + BasicProperties.SNMP_TIMEOUT )); private static final Set RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( @@ -91,19 +96,34 @@ public class SetSNMP extends AbstractSNMPProcessor { REL_FAILURE ))); + private volatile SetSNMPHandler snmpHandler; + + @OnScheduled + public void init(final ProcessContext context) { + initSnmpManager(context); + snmpHandler = new SetSNMPHandler(snmpResourceHandler); + } + @Override public void onTrigger(final ProcessContext context, final ProcessSession processSession) { final FlowFile flowFile = processSession.get(); if (flowFile != null) { try { - final SNMPSingleResponse response = snmpRequestHandler.set(flowFile); - processResponse(processSession, flowFile, response, response.getTargetAddress(), REL_SUCCESS); - } catch (SNMPException e) { - getLogger().error(e.getMessage()); - processError(context, processSession, flowFile); + final Optional optionalResponse = snmpHandler.set(flowFile.getAttributes()); + if (optionalResponse.isPresent()) { + processSession.remove(flowFile); + final FlowFile outgoingFlowFile = processSession.create(); + final SNMPSingleResponse response = optionalResponse.get(); + processSession.getProvenanceReporter().receive(outgoingFlowFile, "/set"); + handleResponse(context, processSession, outgoingFlowFile, response, REL_SUCCESS, REL_FAILURE, "/set"); + } else { + getLogger().warn("No SNMP specific attributes found in flowfile."); + processSession.transfer(flowFile, REL_FAILURE); + } } catch (IOException e) { getLogger().error("Failed to send request to the agent. Check if the agent supports the used version."); - processError(context, processSession, flowFile); + processSession.transfer(processSession.penalize(flowFile), REL_FAILURE); + context.yield(); } } } @@ -118,9 +138,13 @@ public class SetSNMP extends AbstractSNMPProcessor { return RELATIONSHIPS; } + @Override + protected String getTargetHost(ProcessContext processContext) { + return processContext.getProperty(AGENT_HOST).getValue(); + } - private void processError(final ProcessContext context, final ProcessSession processSession, final FlowFile flowFile) { - processSession.transfer(processSession.penalize(flowFile), REL_FAILURE); - context.yield(); + @Override + protected String getTargetPort(ProcessContext processContext) { + return processContext.getProperty(AGENT_PORT).getValue(); } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/BasicProperties.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/BasicProperties.java new file mode 100644 index 0000000000..ccc6677781 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/BasicProperties.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors.properties; + +import org.apache.nifi.components.AllowableValue; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.processor.util.StandardValidators; + +public class BasicProperties { + + private BasicProperties() { + // Utility class, not needed to instantiate. + } + + public static final AllowableValue SNMP_V1 = new AllowableValue("SNMPv1", "v1", "SNMP version 1"); + public static final AllowableValue SNMP_V2C = new AllowableValue("SNMPv2c", "v2c", "SNMP version 2c"); + public static final AllowableValue SNMP_V3 = new AllowableValue("SNMPv3", "v3", "SNMP version 3 with improved security"); + + + public static final PropertyDescriptor SNMP_VERSION = new PropertyDescriptor.Builder() + .name("snmp-version") + .displayName("SNMP Version") + .description("Three significant versions of SNMP have been developed and deployed. " + + "SNMPv1 is the original version of the protocol. More recent versions, " + + "SNMPv2c and SNMPv3, feature improvements in performance, flexibility and security.") + .required(true) + .allowableValues(SNMP_V1, SNMP_V2C, SNMP_V3) + .defaultValue(SNMP_V1.getValue()) + .build(); + + public static final PropertyDescriptor SNMP_COMMUNITY = new PropertyDescriptor.Builder() + .name("snmp-community") + .displayName("SNMP Community") + .description("SNMPv1 and SNMPv2 use communities to establish trust between managers and agents." + + " Most agents support three community names, one each for read-only, read-write and trap." + + " These three community strings control different types of activities. The read-only community" + + " applies to get requests. The read-write community string applies to set requests. The trap" + + " community string applies to receipt of traps.") + .required(true) + .sensitive(true) + .defaultValue("public") + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V1, SNMP_V2C) + .build(); + + public static final PropertyDescriptor SNMP_RETRIES = new PropertyDescriptor.Builder() + .name("snmp-retries") + .displayName("Number of Retries") + .description("Set the number of retries when requesting the SNMP Agent.") + .required(false) + .defaultValue("0") + .addValidator(StandardValidators.NON_NEGATIVE_INTEGER_VALIDATOR) + .build(); + + public static final PropertyDescriptor SNMP_TIMEOUT = new PropertyDescriptor.Builder() + .name("snmp-timeout") + .displayName("Timeout (ms)") + .description("Set the timeout in ms when requesting the SNMP Agent.") + .required(false) + .defaultValue("5000") + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .build(); +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V1TrapProperties.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V1TrapProperties.java new file mode 100644 index 0000000000..bcdf122189 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V1TrapProperties.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors.properties; + +import org.apache.nifi.components.AllowableValue; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.expression.ExpressionLanguageScope; +import org.apache.nifi.processor.util.StandardValidators; + +import static org.apache.nifi.snmp.processors.properties.BasicProperties.SNMP_V1; +import static org.apache.nifi.snmp.processors.properties.BasicProperties.SNMP_VERSION; + + +public class V1TrapProperties { + + private V1TrapProperties() { + // Utility class, not needed to instantiate. + } + + private static final AllowableValue GENERIC_TRAP_TYPE_ENTERPRISE_SPECIFIC = new AllowableValue("6", "Enterprise Specific", + "An enterpriseSpecific trap signifies that a particular enterprise-specific trap has occurred which " + + "can be defined in the Specific Trap Type field."); + + public static final PropertyDescriptor ENTERPRISE_OID = new PropertyDescriptor.Builder() + .name("snmp-trap-enterprise-oid") + .displayName("Enterprise OID") + .description("Enterprise is the vendor identification (OID) for the network management sub-system that generated the trap.") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V1) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor AGENT_ADDRESS = new PropertyDescriptor.Builder() + .name("snmp-trap-agent-address") + .displayName("SNMP Trap Agent Address") + .description("The address where the SNMP Manager sends the trap.") + .required(true) + .defaultValue("0") + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V1) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor GENERIC_TRAP_TYPE = new PropertyDescriptor.Builder() + .name("snmp-trap-generic-type") + .displayName("Generic Trap Type") + .description("Generic trap type is an integer in the range of 0 to 6. See processor usage for details.") + .required(false) + .addValidator(StandardValidators.createLongValidator(0, 6, true)) + .dependsOn(SNMP_VERSION, SNMP_V1) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor SPECIFIC_TRAP_TYPE = new PropertyDescriptor.Builder() + .name("snmp-trap-specific-type") + .displayName("Specific Trap Type") + .description("Specific trap type is a number that further specifies the nature of the event that generated " + + "the trap in the case of traps of generic type 6 (enterpriseSpecific). The interpretation of this " + + "code is vendor-specific.") + .required(true) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V1) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V2TrapProperties.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V2TrapProperties.java new file mode 100644 index 0000000000..1866bb5e0e --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V2TrapProperties.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors.properties; + +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.expression.ExpressionLanguageScope; +import org.apache.nifi.processor.util.StandardValidators; + +import static org.apache.nifi.snmp.processors.properties.BasicProperties.SNMP_V2C; +import static org.apache.nifi.snmp.processors.properties.BasicProperties.SNMP_V3; +import static org.apache.nifi.snmp.processors.properties.BasicProperties.SNMP_VERSION; + +public class V2TrapProperties { + + private V2TrapProperties() { + // Utility class, not needed to instantiate. + } + + public static final PropertyDescriptor TRAP_OID_VALUE = new PropertyDescriptor.Builder() + .name("snmp-trap-oid-value") + .displayName("Trap OID Value") + .description("The value of the trap OID.") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V2C, SNMP_V3) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java new file mode 100644 index 0000000000..07688d7b15 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/V3SecurityProperties.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors.properties; + +import org.apache.nifi.components.AllowableValue; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.processor.util.StandardValidators; +import org.snmp4j.security.SecurityLevel; + +import static org.apache.nifi.snmp.processors.properties.BasicProperties.SNMP_V3; +import static org.apache.nifi.snmp.processors.properties.BasicProperties.SNMP_VERSION; + +public class V3SecurityProperties { + + private V3SecurityProperties() { + // Utility class, not needed to instantiate. + } + + private static final String SHA_2_ALGORITHM = "Provides authentication based on the HMAC-SHA-2 algorithm."; + private static final String AES_DESCRIPTION = "AES is a symmetric algorithm which uses the same 128, 192, or 256 bit" + + " key for both encryption and decryption (the security of an AES system increases exponentially with key length)."; + + // SNMPv3 security levels + public static final AllowableValue NO_AUTH_NO_PRIV = new AllowableValue(SecurityLevel.noAuthNoPriv.name(), SecurityLevel.noAuthNoPriv.name(), + "No authentication or encryption."); + public static final AllowableValue AUTH_NO_PRIV = new AllowableValue(SecurityLevel.authNoPriv.name(), SecurityLevel.authNoPriv.name(), + "Authentication without encryption."); + public static final AllowableValue AUTH_PRIV = new AllowableValue(SecurityLevel.authPriv.name(), SecurityLevel.authPriv.name(), + "Authentication and encryption."); + + // SNMPv3 authentication protocols + public static final AllowableValue MD5 = new AllowableValue("MD5", "MD5", + "Provides authentication based on the HMAC-MD5 algorithm."); + public static final AllowableValue SHA = new AllowableValue("SHA", "SHA", + "Provides authentication based on the HMAC-SHA algorithm."); + public static final AllowableValue HMAC128SHA224 = new AllowableValue("HMAC128SHA224", "SHA224", + SHA_2_ALGORITHM); + public static final AllowableValue HMAC192SHA256 = new AllowableValue("HMAC192SHA256", "SHA256", + SHA_2_ALGORITHM); + public static final AllowableValue HMAC256SHA384 = new AllowableValue("HMAC256SHA384", "SHA384", + SHA_2_ALGORITHM); + public static final AllowableValue HMAC384SHA512 = new AllowableValue("HMAC384SHA512", "SHA512", + SHA_2_ALGORITHM); + + // SNMPv3 encryption + public static final AllowableValue DES = new AllowableValue("DES", "DES", + "Symmetric-key algorithm for the encryption of digital data. DES has been considered insecure" + + "because of the feasilibity of brute-force attacks. We recommend using the AES encryption protocol."); + public static final AllowableValue DES3 = new AllowableValue("3DES", "3DES", + "Symmetric-key block cipher, which applies the DES cipher algorithm three times to each data block." + + " 3DES has been considered insecure has been deprecated by NIST in 2017. We recommend using the AES encryption protocol."); + + public static final AllowableValue AES128 = new AllowableValue("AES128", "AES128", AES_DESCRIPTION); + public static final AllowableValue AES192 = new AllowableValue("AES192", "AES192", AES_DESCRIPTION); + public static final AllowableValue AES256 = new AllowableValue("AES256", "AES256", AES_DESCRIPTION); + + public static final PropertyDescriptor SNMP_SECURITY_LEVEL = new PropertyDescriptor.Builder() + .name("snmp-security-level") + .displayName("SNMP Security Level") + .description("SNMP version 3 provides extra security with User Based Security Model (USM). The three levels of security is " + + "1. Communication without authentication and encryption (NoAuthNoPriv). " + + "2. Communication with authentication and without encryption (AuthNoPriv). " + + "3. Communication with authentication and encryption (AuthPriv).") + .required(true) + .allowableValues(NO_AUTH_NO_PRIV, AUTH_NO_PRIV, AUTH_PRIV) + .defaultValue(NO_AUTH_NO_PRIV.getValue()) + .dependsOn(SNMP_VERSION, SNMP_V3) + .build(); + + public static final PropertyDescriptor SNMP_SECURITY_NAME = new PropertyDescriptor.Builder() + .name("snmp-security-name") + .displayName("SNMP Security Name") + .description("User name used for SNMP v3 Authentication.") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V3) + .build(); + + public static final PropertyDescriptor SNMP_AUTH_PROTOCOL = new PropertyDescriptor.Builder() + .name("snmp-authentication-protocol") + .displayName("SNMP Authentication Protocol") + .description("Hash based authentication protocol for secure authentication.") + .required(true) + .allowableValues(MD5, SHA, HMAC128SHA224, HMAC192SHA256, HMAC256SHA384, HMAC384SHA512) + .dependsOn(SNMP_SECURITY_LEVEL, AUTH_NO_PRIV, AUTH_PRIV) + .build(); + + public static final PropertyDescriptor SNMP_AUTH_PASSWORD = new PropertyDescriptor.Builder() + .name("snmp-authentication-passphrase") + .displayName("SNMP Authentication Passphrase") + .description("Passphrase used for SNMP authentication protocol.") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .sensitive(true) + .dependsOn(SNMP_SECURITY_LEVEL, AUTH_NO_PRIV, AUTH_PRIV) + .build(); + + public static final PropertyDescriptor SNMP_PRIVACY_PROTOCOL = new PropertyDescriptor.Builder() + .name("snmp-private-protocol") + .displayName("SNMP Privacy Protocol") + .description("Privacy allows for encryption of SNMP v3 messages to ensure confidentiality of data.") + .required(true) + .allowableValues(DES, DES3, AES128, AES192, AES256) + .dependsOn(SNMP_SECURITY_LEVEL, AUTH_PRIV) + .build(); + + public static final PropertyDescriptor SNMP_PRIVACY_PASSWORD = new PropertyDescriptor.Builder() + .name("snmp-private-protocol-passphrase") + .displayName("SNMP Privacy Passphrase") + .description("Passphrase used for SNMP privacy protocol.") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .sensitive(true) + .dependsOn(SNMP_SECURITY_LEVEL, AUTH_PRIV) + .build(); +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SNMPUtils.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SNMPUtils.java index 788b73ba75..a14e195d8c 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SNMPUtils.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SNMPUtils.java @@ -16,13 +16,13 @@ */ package org.apache.nifi.snmp.utils; -import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.snmp.exception.InvalidAuthProtocolException; import org.apache.nifi.snmp.exception.InvalidPrivProtocolException; import org.apache.nifi.snmp.exception.InvalidSnmpVersionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.snmp4j.PDU; +import org.snmp4j.PDUv1; import org.snmp4j.mp.SnmpConstants; import org.snmp4j.security.AuthHMAC128SHA224; import org.snmp4j.security.AuthHMAC192SHA256; @@ -44,6 +44,7 @@ import org.snmp4j.smi.OctetString; import org.snmp4j.smi.Variable; import org.snmp4j.smi.VariableBinding; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -67,8 +68,8 @@ public final class SNMPUtils { private static final Map AUTH_MAP; private static final Map PRIV_MAP; - private static final Map VERSION_MAP; private static final Map REPORT_MAP; + private static final Map VERSION_MAP; private SNMPUtils() { // hide implicit constructor @@ -132,12 +133,18 @@ public final class SNMPUtils { return attributes; } - /** - * Method to construct {@link FlowFile} attributes from a vector of {@link VariableBinding} - * - * @param variableBindings list of {@link VariableBinding} - * @return the attributes map - */ + public static Map getV1TrapPduAttributeMap(final PDUv1 v1TrapPdu) { + final Map trapAttributes = getPduAttributeMap(v1TrapPdu); + + trapAttributes.computeIfAbsent(SNMP_PROP_PREFIX + "enterprise", v -> String.valueOf(v1TrapPdu.getEnterprise())); + trapAttributes.computeIfAbsent(SNMP_PROP_PREFIX + "agentAddress", v -> String.valueOf(v1TrapPdu.getAgentAddress())); + trapAttributes.computeIfAbsent(SNMP_PROP_PREFIX + "genericTrapType", v -> String.valueOf(v1TrapPdu.getGenericTrap())); + trapAttributes.computeIfAbsent(SNMP_PROP_PREFIX + "specificTrapType", v -> String.valueOf(v1TrapPdu.getSpecificTrap())); + trapAttributes.computeIfAbsent(SNMP_PROP_PREFIX + "timestamp", v -> String.valueOf(v1TrapPdu.getTimestamp())); + + return trapAttributes; + } + public static Map createWalkOidValuesMap(final List variableBindings) { final Map attributes = new HashMap<>(); variableBindings.forEach(vb -> addAttributeFromVariable(vb, attributes)); @@ -159,46 +166,72 @@ public final class SNMPUtils { throw new InvalidAuthProtocolException("Invalid authentication protocol provided."); } - public static int getVersion(final String snmpVersion) { - return Optional.ofNullable(VERSION_MAP.get(snmpVersion)) - .orElseThrow(() -> new InvalidSnmpVersionException("Invalid SNMP version provided.")); - } - - /** - * Method to construct {@link VariableBinding} based on {@link FlowFile} - * attributes in order to update the {@link PDU} that is going to be sent to - * the SNMP Agent. - * - * @param pdu {@link PDU} to be sent - * @param attributes {@link FlowFile} attributes - * @return true if at least one {@link VariableBinding} has been created, false otherwise - */ public static boolean addVariables(final PDU pdu, final Map attributes) { boolean result = false; - for (Map.Entry attributeEntry : attributes.entrySet()) { - if (attributeEntry.getKey().startsWith(SNMPUtils.SNMP_PROP_PREFIX)) { - final String[] splits = attributeEntry.getKey().split("\\" + SNMPUtils.SNMP_PROP_DELIMITER); - final String snmpPropName = splits[1]; - final String snmpPropValue = attributeEntry.getValue(); - if (SNMPUtils.OID_PATTERN.matcher(snmpPropName).matches()) { - final Optional var; - if (splits.length == 2) { // no SMI syntax defined - var = Optional.of(new OctetString(snmpPropValue)); - } else { - final int smiSyntax = Integer.parseInt(splits[2]); - var = SNMPUtils.stringToVariable(snmpPropValue, smiSyntax); - } - if (var.isPresent()) { - final VariableBinding varBind = new VariableBinding(new OID(snmpPropName), var.get()); - pdu.add(varBind); - result = true; + try { + for (Map.Entry attributeEntry : attributes.entrySet()) { + if (attributeEntry.getKey().startsWith(SNMPUtils.SNMP_PROP_PREFIX)) { + final String[] splits = attributeEntry.getKey().split("\\" + SNMPUtils.SNMP_PROP_DELIMITER); + final String snmpPropName = splits[1]; + final String snmpPropValue = attributeEntry.getValue(); + if (SNMPUtils.OID_PATTERN.matcher(snmpPropName).matches()) { + final Optional var; + if (splits.length == 2) { // no SMI syntax defined + var = Optional.of(new OctetString(snmpPropValue)); + } else { + final int smiSyntax = Integer.parseInt(splits[2]); + var = SNMPUtils.stringToVariable(snmpPropValue, smiSyntax); + } + if (var.isPresent()) { + final VariableBinding varBind = new VariableBinding(new OID(snmpPropName), var.get()); + pdu.add(varBind); + result = true; + } } } } + } catch (ArrayIndexOutOfBoundsException e) { + return false; } return result; } + public static VariableBinding[] addGetVariables(final Map attributes) { + List variableBindings = new ArrayList<>(); + try { + for (Map.Entry attributeEntry : attributes.entrySet()) { + if (attributeEntry.getKey().startsWith(SNMPUtils.SNMP_PROP_PREFIX)) { + final String[] splits = attributeEntry.getKey().split("\\" + SNMPUtils.SNMP_PROP_DELIMITER); + final String snmpPropName = splits[1]; + if (SNMPUtils.OID_PATTERN.matcher(snmpPropName).matches()) { + variableBindings.add(new VariableBinding(new OID(snmpPropName))); + } + } + } + } catch (ArrayIndexOutOfBoundsException e) { + return new VariableBinding[0]; + } + return variableBindings.toArray(new VariableBinding[0]); + } + + public static OID[] addWalkVariables(final Map attributes) { + List oids = new ArrayList<>(); + try { + for (Map.Entry attributeEntry : attributes.entrySet()) { + if (attributeEntry.getKey().startsWith(SNMPUtils.SNMP_PROP_PREFIX)) { + final String[] splits = attributeEntry.getKey().split("\\" + SNMPUtils.SNMP_PROP_DELIMITER); + final String snmpPropName = splits[1]; + if (SNMPUtils.OID_PATTERN.matcher(snmpPropName).matches()) { + oids.add(new OID(snmpPropName)); + } + } + } + } catch (ArrayIndexOutOfBoundsException e) { + return new OID[0]; + } + return oids.toArray(new OID[0]); + } + private static void addAttributeFromVariable(final VariableBinding variableBinding, final Map attributes) { attributes.put(SNMP_PROP_PREFIX + variableBinding.getOid() + SNMP_PROP_DELIMITER + variableBinding.getVariable().getSyntax(), variableBinding.getVariable().toString()); } @@ -231,4 +264,9 @@ public final class SNMPUtils { } return errorMessage.map(s -> oid + ": " + s); } + + public static int getVersion(final String snmpVersion) { + return Optional.ofNullable(VERSION_MAP.get(snmpVersion)) + .orElseThrow(() -> new InvalidSnmpVersionException("Invalid SNMP version provided.")); + } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor index c3fcde09ab..03592712e9 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor @@ -14,3 +14,5 @@ # limitations under the License. org.apache.nifi.snmp.processors.GetSNMP org.apache.nifi.snmp.processors.SetSNMP +org.apache.nifi.snmp.processors.SendTrapSNMP +org.apache.nifi.snmp.processors.ListenTrapSNMP diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.GetSNMP/additionalDetails.html b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.GetSNMP/additionalDetails.html index 24f982c081..1607987ffb 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.GetSNMP/additionalDetails.html +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.GetSNMP/additionalDetails.html @@ -23,12 +23,19 @@

Summary

- This processor polls a SNMP agent to get information for a given OID (Strategy = GET) or for all the sub-tree - associated to a given OID + This processor polls a SNMP agent to get information for a given OID or OIDs (Strategy = GET) or for all the sub-tree + associated to a given OID or OIDs (Strategy = WALK). This processors supports SNMPv1, SNMPv2c and SNMPv3. The component is based on SNMP4J.

+ The processor can compile the SNMP Get PDU from the attributes of an input flowfile (multiple OIDs can be specified) + or from a single OID specified in the processor property. In the former case, the processor will only consider the + OIDs specified in the flowfile. + The processor is looking for attributes prefixed with snmp$. If such an attribute is found, the attribute name is split using + the $ character. The second element must respect the OID format to be considered as a valid OID. The flowfile attribute + value can be empty (it will be later filled with the retrieved value and written into the outgoing flowfile). + When the processor is triggered, it sends the SNMP request and gets the information associated to request OID(s). Once response is received from the SNMP agent, a FlowFile is constructed. The FlowFile content is empty, all the information is written in the diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html new file mode 100644 index 0000000000..37aaa668f7 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.ListenTrapSNMP/additionalDetails.html @@ -0,0 +1,54 @@ + + + + + + ListenTrapSNMP + + + + +

Summary

+

+ This processor listens to SNMP traps and creates a flowfile from the trap PDU. + The versions SNMPv1, SNMPv2c and SNMPv3 are supproted. The component is based on SNMP4J. +

+

+ In case of SNMPv3, users can be specified in a json file. E.g.: +

+
+[
+   {
+      "securityName":"user1",
+      "authProtocol":"MD5",
+      "authPassphrase":"abc12345",
+      "privProtocol":"DES",
+      "privPassphrase":"abc12345"
+   },
+   {
+      "securityName":"newUser2",
+      "authProtocol":"MD5",
+      "authPassphrase":"abc12345",
+      "privProtocol":"AES256",
+      "privPassphrase":"abc12345"
+   }
+]
+
+
+
+

+ + \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.SendTrapSNMP/additionalDetails.html b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.SendTrapSNMP/additionalDetails.html new file mode 100644 index 0000000000..ef9ed95bb6 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/resources/docs/org.apache.nifi.snmp.processors.SendTrapSNMP/additionalDetails.html @@ -0,0 +1,45 @@ + + + + + + SendTrapSNMP + + + + +

Summary

+

+ This processor generates and transmits SNMP Traps to the specified SNMP manager. Attributes can be given + as processor properties, either predefined or dynamically using Expression Language from flowfiles. + Flowfile properties with snmp prefix (e.g. snmp$1.2.3.4.5 - OID) value can be used to define additional PDU variables. +

+

+ The allowable Generic Trap Types are: +

    +
  1. Cold Start
  2. +
  3. Warm Start
  4. +
  5. Link Down
  6. +
  7. Link Up
  8. +
  9. Authentication Failure
  10. +
  11. EGP Neighbor Loss
  12. +
  13. Enterprise Specific
  14. +
+ + Specific trap type can set in case of Enterprise Specific generic trap type is chosen. +

+ + \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/SNMPConfigurationTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/SNMPConfigurationTest.java new file mode 100644 index 0000000000..e5cd4d38bc --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/SNMPConfigurationTest.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.configuration; + +import org.apache.nifi.remote.io.socket.NetworkUtils; +import org.junit.Test; +import org.snmp4j.mp.SnmpConstants; + +import static org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory.COMMUNITY_STRING; +import static org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory.DEFAULT_HOST; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.AUTH_PASSPHRASE; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.AUTH_PROTOCOL; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.PRIV_PASSPHRASE; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.PRIV_PROTOCOL; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.SECURITY_LEVEL; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.SECURITY_NAME; +import static org.junit.Assert.assertEquals; + +public class SNMPConfigurationTest { + + private static final int MANAGER_PORT = NetworkUtils.availablePort(); + private static final String TARGET_PORT = "55556"; + private static final int RETRIES = 3; + private static final int VERSION = SnmpConstants.version3; + private static final int TIMEOUT_IN_MS = 3000; + + @Test + public void testMembersAreSetCorrectly() { + final SNMPConfiguration snmpConfiguration = SNMPConfiguration.builder() + .setManagerPort(MANAGER_PORT) + .setTargetHost(DEFAULT_HOST) + .setTargetPort(TARGET_PORT) + .setRetries(RETRIES) + .setTimeoutInMs(TIMEOUT_IN_MS) + .setVersion(VERSION) + .setCommunityString(COMMUNITY_STRING) + .setSecurityLevel(SECURITY_LEVEL) + .setSecurityName(SECURITY_NAME) + .setAuthProtocol(AUTH_PROTOCOL) + .setAuthPassphrase(AUTH_PASSPHRASE) + .setPrivacyProtocol(PRIV_PROTOCOL) + .setPrivacyPassphrase(PRIV_PASSPHRASE) + .build(); + + assertEquals(MANAGER_PORT, snmpConfiguration.getManagerPort()); + assertEquals(DEFAULT_HOST, snmpConfiguration.getTargetHost()); + assertEquals(TARGET_PORT, snmpConfiguration.getTargetPort()); + assertEquals(RETRIES, snmpConfiguration.getRetries()); + assertEquals(TIMEOUT_IN_MS, snmpConfiguration.getTimeoutInMs()); + assertEquals(VERSION, snmpConfiguration.getVersion()); + assertEquals(COMMUNITY_STRING, snmpConfiguration.getCommunityString()); + assertEquals(SECURITY_LEVEL, snmpConfiguration.getSecurityLevel()); + assertEquals(SECURITY_NAME, snmpConfiguration.getSecurityName()); + assertEquals(AUTH_PROTOCOL, snmpConfiguration.getAuthProtocol()); + assertEquals(AUTH_PASSPHRASE, snmpConfiguration.getAuthPassphrase()); + assertEquals(PRIV_PROTOCOL, snmpConfiguration.getPrivacyProtocol()); + assertEquals(PRIV_PASSPHRASE, snmpConfiguration.getPrivacyPassphrase()); + + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java new file mode 100644 index 0000000000..1575113165 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/configuration/V1TrapConfigurationTest.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.configuration; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +public class V1TrapConfigurationTest { + + private static final String AGENT_ADDRESS = "127.0.0.1"; + private static final String ENTERPRISE_OID = "1.3.6.1.4.1.8072.2.3.0.1"; + private static final int GENERIC_TRAP_TYPE = 6; + private static final Integer SPECIFIC_TRAP_TYPE = 2; + + @Rule + public ExpectedException exceptionRule = ExpectedException.none(); + + @Test + public void testMembersAreSetCorrectly() { + final V1TrapConfiguration v1TrapConfiguration = V1TrapConfiguration.builder() + .enterpriseOid(ENTERPRISE_OID) + .agentAddress(AGENT_ADDRESS) + .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE)) + .specificTrapType(String.valueOf(SPECIFIC_TRAP_TYPE)) + .build(); + + assertEquals(ENTERPRISE_OID, v1TrapConfiguration.getEnterpriseOid()); + assertEquals(AGENT_ADDRESS, v1TrapConfiguration.getAgentAddress()); + assertEquals(GENERIC_TRAP_TYPE, v1TrapConfiguration.getGenericTrapType()); + assertEquals(SPECIFIC_TRAP_TYPE, v1TrapConfiguration.getSpecificTrapType()); + } + + @Test + public void testRequireNonNullEnterpriseOid() { + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Enterprise OID must be specified."); + V1TrapConfiguration.builder() + .agentAddress(AGENT_ADDRESS) + .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE)) + .specificTrapType(String.valueOf(SPECIFIC_TRAP_TYPE)) + .build(); + } + + @Test + public void testRequireNonNullAgentAddress() { + exceptionRule.expect(IllegalArgumentException.class); + exceptionRule.expectMessage("Agent address must be specified."); + V1TrapConfiguration.builder() + .enterpriseOid(ENTERPRISE_OID) + .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE)) + .specificTrapType(String.valueOf(SPECIFIC_TRAP_TYPE)) + .build(); + } + + @Test + public void testGenericTypeIsNegative() { + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> V1TrapConfiguration.builder() + .agentAddress(AGENT_ADDRESS) + .enterpriseOid(ENTERPRISE_OID) + .genericTrapType("-1") + .build() + ); + assertEquals("Generic Trap Type must be between 0 and 6.", exception.getMessage()); + } + + @Test + public void testGenericTypeIsGreaterThan6() { + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> V1TrapConfiguration.builder() + .agentAddress(AGENT_ADDRESS) + .enterpriseOid(ENTERPRISE_OID) + .genericTrapType("7") + .build() + ); + assertEquals("Generic Trap Type must be between 0 and 6.", exception.getMessage()); + } + + @Test + public void testGenericTypeIsNotANumber() { + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> V1TrapConfiguration.builder() + .agentAddress(AGENT_ADDRESS) + .enterpriseOid(ENTERPRISE_OID) + .genericTrapType("invalid") + .build() + ); + assertEquals("Generic Trap Type is not a number.", exception.getMessage()); + } + + @Test + public void testSpecificTrapTypeIsNegative() { + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> V1TrapConfiguration.builder() + .agentAddress(AGENT_ADDRESS) + .enterpriseOid(ENTERPRISE_OID) + .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE)) + .specificTrapType("-1") + .build() + ); + assertEquals("Specific Trap Type must be between 0 and 2147483647.", exception.getMessage()); + } + + @Test + public void testGenericTrapTypeIsEnterpriseSpecificButSpecificTrapTypeIsNotSet() { + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> V1TrapConfiguration.builder() + .agentAddress(AGENT_ADDRESS) + .enterpriseOid(ENTERPRISE_OID) + .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE)) + .build() + ); + assertEquals("Generic Trap Type is [6 - Enterprise Specific] but Specific Trap Type is not provided or not a number.", exception.getMessage()); + } + + @Test + public void testGenericTrapTypeIsNotEnterpriseSpecificButSpecificTrapTypeIsSet() { + final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> V1TrapConfiguration.builder() + .agentAddress(AGENT_ADDRESS) + .enterpriseOid(ENTERPRISE_OID) + .genericTrapType("5") + .specificTrapType("123") + .build() + ); + assertEquals("Invalid argument: Generic Trap Type is not [6 - Enterprise Specific] but Specific Trap Type is provided.", exception.getMessage()); + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/dto/SNMPTreeResponseTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/dto/SNMPTreeResponseTest.java new file mode 100644 index 0000000000..1a325bf5c1 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/dto/SNMPTreeResponseTest.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.dto; + +import org.apache.nifi.util.LogMessage; +import org.apache.nifi.util.MockComponentLog; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mock; +import org.snmp4j.CommunityTarget; +import org.snmp4j.Target; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.OctetString; +import org.snmp4j.smi.UdpAddress; +import org.snmp4j.smi.VariableBinding; +import org.snmp4j.util.TreeEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SNMPTreeResponseTest { + + private static final String SNMP_SEPARATOR = "$"; + private static final String SNMP_PREFIX = "snmp" + SNMP_SEPARATOR; + private static final String VB_SYNTAX = "4"; + + private static final String OID_1 = "1.3.6.1.4.1.32437.1.5.1.4.2.0"; + private static final String OID_2 = "1.3.6.1.4.1.32437.1.5.1.4.3.0"; + private static final String OID_3 = "1.3.6.1.4.1.32437.1.5.1.4.4.0"; + private static final String OID_1_VALUE = "OID_1_VALUE"; + private static final String OID_2_VALUE = "OID_2_VALUE"; + private static final String OID_3_VALUE = "OID_3_VALUE"; + + private static final String TARGET_ADDRESS = "127.0.0.1/50555"; + + private static VariableBinding[] vbs1; + private static VariableBinding[] vbs2; + private static VariableBinding[] vbs3; + private static Map vbMap; + @Mock + private static Target target; + + @BeforeClass + public static void setUp() { + vbMap = new HashMap<>(); + vbMap.put(SNMP_PREFIX + OID_1 + SNMP_SEPARATOR + VB_SYNTAX, OID_1_VALUE); + vbMap.put(SNMP_PREFIX + OID_2 + SNMP_SEPARATOR + VB_SYNTAX, OID_2_VALUE); + vbMap.put(SNMP_PREFIX + OID_3 + SNMP_SEPARATOR + VB_SYNTAX, OID_3_VALUE); + + target = new CommunityTarget(); + target.setAddress(new UdpAddress(TARGET_ADDRESS)); + + vbs1 = new VariableBinding[]{ + new VariableBinding(new OID(OID_1), new OctetString(OID_1_VALUE)), + }; + vbs2 = new VariableBinding[]{ + new VariableBinding(new OID(OID_2), new OctetString(OID_2_VALUE)), + }; + vbs3 = new VariableBinding[]{ + new VariableBinding(new OID(OID_3), new OctetString(OID_3_VALUE)) + }; + } + + @Test + public void testGetAttributes() { + final TreeEvent treeEvent1 = mock(TreeEvent.class); + when(treeEvent1.getVariableBindings()).thenReturn(vbs1); + final TreeEvent treeEvent2 = mock(TreeEvent.class); + when(treeEvent2.getVariableBindings()).thenReturn(vbs2); + final TreeEvent treeEvent3 = mock(TreeEvent.class); + when(treeEvent3.getVariableBindings()).thenReturn(vbs3); + + final List treeEvents = new ArrayList<>(); + Collections.addAll(treeEvents, treeEvent1, treeEvent2, treeEvent3); + + final SNMPTreeResponse snmpTreeResponse = new SNMPTreeResponse(target, treeEvents); + final Map attributes = snmpTreeResponse.getAttributes(); + + assertEquals(3, attributes.size()); + assertEquals(vbMap, attributes); + } + + @Test + public void testGetAttributesFlattensEmptyVariableBindingArrays() { + final TreeEvent emptyTreeEvent = mock(TreeEvent.class); + when(emptyTreeEvent.getVariableBindings()).thenReturn(new VariableBinding[0]); + final TreeEvent normalTreeEvent = mock(TreeEvent.class); + when(normalTreeEvent.getVariableBindings()).thenReturn(vbs1); + + final List treeEvents = new ArrayList<>(); + Collections.addAll(treeEvents, emptyTreeEvent, normalTreeEvent); + + final SNMPTreeResponse snmpTreeResponse = new SNMPTreeResponse(target, treeEvents); + final Map attributes = snmpTreeResponse.getAttributes(); + + assertEquals(1, attributes.size()); + assertEquals(OID_1_VALUE, attributes.get(SNMP_PREFIX + OID_1 + SNMP_SEPARATOR + VB_SYNTAX)); + } + + @Test + public void testGetAttributesFiltersNullVariableBindings() { + final TreeEvent nullTreeEvent = mock(TreeEvent.class); + when(nullTreeEvent.getVariableBindings()).thenReturn(null); + final TreeEvent normalTreeEvent = mock(TreeEvent.class); + when(normalTreeEvent.getVariableBindings()).thenReturn(vbs1); + + final List treeEvents = new ArrayList<>(); + Collections.addAll(treeEvents, nullTreeEvent, normalTreeEvent); + + final SNMPTreeResponse snmpTreeResponse = new SNMPTreeResponse(target, treeEvents); + final Map attributes = snmpTreeResponse.getAttributes(); + + assertEquals(1, attributes.size()); + assertEquals(OID_1_VALUE, attributes.get(SNMP_PREFIX + OID_1 + SNMP_SEPARATOR + VB_SYNTAX)); + } + + @Test + public void testGetTargetAddress() { + final TreeEvent treeEvent = mock(TreeEvent.class); + final List treeEvents = new ArrayList<>(); + treeEvents.add(treeEvent); + final SNMPTreeResponse snmpTreeResponse = new SNMPTreeResponse(target, treeEvents); + final String actualTargetAddress = snmpTreeResponse.getTargetAddress(); + + assertEquals(TARGET_ADDRESS, actualTargetAddress); + } + + @Test + public void testLogErrors() { + final MockComponentLog logger = new MockComponentLog("id1", new Object()); + + + final List treeEvents = new ArrayList<>(); + final TreeEvent treeEvent = mock(TreeEvent.class); + when(treeEvent.isError()).thenReturn(true); + when(treeEvent.getErrorMessage()).thenReturn("ERROR MESSAGE"); + treeEvents.add(treeEvent); + final SNMPTreeResponse snmpTreeResponse = new SNMPTreeResponse(target, treeEvents); + snmpTreeResponse.logErrors(logger); + + final List errorMessages = logger.getErrorMessages(); + System.out.println("asd"); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/SNMPClientFactoryTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/SNMPClientFactoryTest.java deleted file mode 100644 index 50719fc451..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/SNMPClientFactoryTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.factory; - -import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.apache.nifi.snmp.configuration.SNMPConfigurationBuilder; -import org.junit.jupiter.api.Test; -import org.snmp4j.Snmp; -import org.snmp4j.mp.SnmpConstants; -import org.snmp4j.security.UsmUser; -import org.snmp4j.smi.OID; -import org.snmp4j.smi.OctetString; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -public class SNMPClientFactoryTest { - - private final SNMPConfigurationBuilder configurationBuilder = new SNMPConfigurationBuilder() - .setAgentHost("127.0.0.1") - .setAgentPort("12345") - .setRetries(1) - .setTimeout(1000) - .setSecurityLevel("noAuthNoPriv") - .setSecurityName("userName") - .setAuthProtocol("SHA") - .setAuthPassphrase("authPassword") - .setPrivacyProtocol("DES") - .setPrivacyPassphrase("privacyPassword") - .setCommunityString("public"); - - @Test - public void testSnmpV3ClientWithoutCorrespondingAgentDoesNotHaveUSM() { - final SNMPConfiguration configuration = configurationBuilder - .setVersion(SnmpConstants.version3) - .build(); - - - final SNMPFactory snmpFactory = new CompositeSNMPFactory(); - final Snmp snmpManager = snmpFactory.createSnmpManagerInstance(configuration); - final UsmUser user = snmpManager.getUSM().getUserTable().getUser(new OctetString("userName")).getUsmUser(); - - final OID usmHMACSHAAuthProtocol = new OID("1.3.6.1.6.3.10.1.1.3"); - final OID usmDESPrivProtocol = new OID("1.3.6.1.6.3.10.1.2.2"); - - assertThat("userName", is(equalTo(user.getSecurityName().toString()))); - assertThat(usmHMACSHAAuthProtocol, is(equalTo(user.getAuthenticationProtocol()))); - assertThat("authPassword", is(equalTo(user.getAuthenticationPassphrase().toString()))); - assertThat(usmDESPrivProtocol, is(equalTo(user.getPrivacyProtocol()))); - assertThat("privacyPassword", is(equalTo(user.getPrivacyPassphrase().toString()))); - assertThat(3, is(equalTo(user.getSecurityModel()))); - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPContextTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPContextTest.java new file mode 100644 index 0000000000..0d073aca63 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPContextTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.core; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.junit.Test; +import org.snmp4j.Snmp; +import org.snmp4j.Target; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class SNMPContextTest { + + @Test + public void testCreateSNMPContext() { + final SNMPContext snmpContext = spy(SNMPContext.class); + final Snmp mockSnmpManager = mock(Snmp.class); + final Target mockTarget = mock(Target.class); + final SNMPConfiguration snmpConfiguration = mock(SNMPConfiguration.class); + + when(snmpContext.createSnmpManagerInstance(snmpConfiguration)).thenReturn(mockSnmpManager); + when(snmpContext.createTargetInstance(snmpConfiguration)).thenReturn(mockTarget); + + snmpContext.createSNMPResourceHandler(snmpConfiguration); + + verify(snmpContext).createSnmpManagerInstance(snmpConfiguration); + verify(snmpContext).createTargetInstance(snmpConfiguration); + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProviderTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProviderTest.java new file mode 100644 index 0000000000..eaf23efe89 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/SNMPFactoryProviderTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.core; + +import org.junit.Test; +import org.snmp4j.mp.SnmpConstants; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsInstanceOf.instanceOf; + +public class SNMPFactoryProviderTest { + + @Test + public void testCreateFactoryByVersion() { + final SNMPContext snmpV1V2cFactoryFromVersion1 = SNMPFactoryProvider.getFactory(SnmpConstants.version1); + final SNMPContext snmpV1V2cFactoryFromVersion2c = SNMPFactoryProvider.getFactory(SnmpConstants.version2c); + final SNMPContext snmpV3Factory = SNMPFactoryProvider.getFactory(SnmpConstants.version3); + assertThat(snmpV1V2cFactoryFromVersion1, instanceOf(V1V2cSNMPFactory.class)); + assertThat(snmpV1V2cFactoryFromVersion2c, instanceOf(V1V2cSNMPFactory.class)); + assertThat(snmpV3Factory, instanceOf(V3SNMPFactory.class)); + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V1V2cSNMPFactoryTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V1V2cSNMPFactoryTest.java new file mode 100644 index 0000000000..281bbecbe7 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V1V2cSNMPFactoryTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.core; + +import org.apache.nifi.remote.io.socket.NetworkUtils; +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.util.StringUtils; +import org.junit.Test; +import org.snmp4j.CommunityTarget; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.security.SecurityLevel; + +import static org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory.DEFAULT_HOST; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +public class V1V2cSNMPFactoryTest { + + private static final int RETRIES = 3; + + @Test + public void testFactoryCreatesV1V2Configuration() { + final V1V2cSNMPFactory snmpFactory = new V1V2cSNMPFactory(); + final int managerPort = NetworkUtils.availablePort(); + final String targetPort = String.valueOf(NetworkUtils.availablePort()); + final SNMPConfiguration snmpConfiguration = getSnmpConfiguration(managerPort, targetPort); + + final Target target = snmpFactory.createTargetInstance(snmpConfiguration); + + assertThat(target, instanceOf(CommunityTarget.class)); + assertEquals(DEFAULT_HOST + "/" + targetPort, target.getAddress().toString()); + assertEquals(RETRIES, target.getRetries()); + assertEquals(1, target.getSecurityLevel()); + assertEquals(StringUtils.EMPTY, target.getSecurityName().toString()); + } + + @Test + public void testFactoryCreatesSnmpManager() { + final V1V2cSNMPFactory snmpFactory = new V1V2cSNMPFactory(); + final int managerPort = NetworkUtils.availablePort(); + final String targetPort = String.valueOf(NetworkUtils.availablePort()); + final SNMPConfiguration snmpConfiguration = getSnmpConfiguration(managerPort, targetPort); + + final Snmp snmpManager = snmpFactory.createSnmpManagerInstance(snmpConfiguration); + + final String address = snmpManager.getMessageDispatcher().getTransportMappings().iterator().next().getListenAddress().toString(); + assertEquals(DEFAULT_HOST + "/" + managerPort, address); + } + + @Test + public void testFactoryCreatesResourceHandler() { + final V1V2cSNMPFactory snmpFactory = spy(V1V2cSNMPFactory.class); + final int managerPort = NetworkUtils.availablePort(); + final String targetPort = String.valueOf(NetworkUtils.availablePort()); + final SNMPConfiguration snmpConfiguration = getSnmpConfiguration(managerPort, targetPort); + + snmpFactory.createSNMPResourceHandler(snmpConfiguration); + + verify(snmpFactory).createTargetInstance(snmpConfiguration); + verify(snmpFactory).createSnmpManagerInstance(snmpConfiguration); + } + + private SNMPConfiguration getSnmpConfiguration(int managerPort, String targetPort) { + return new SNMPConfiguration.Builder() + .setRetries(RETRIES) + .setManagerPort(managerPort) + .setTargetHost(DEFAULT_HOST) + .setTargetPort(targetPort) + .setSecurityLevel(SecurityLevel.noAuthNoPriv.name()) + .build(); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V3SNMPFactoryTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V3SNMPFactoryTest.java new file mode 100644 index 0000000000..7962389881 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/core/V3SNMPFactoryTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.core; + +import org.apache.nifi.remote.io.socket.NetworkUtils; +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.junit.Test; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.UserTarget; +import org.snmp4j.security.SecurityLevel; +import org.snmp4j.security.SecurityModels; +import org.snmp4j.security.USM; +import org.snmp4j.smi.Integer32; +import org.snmp4j.smi.OctetString; + +import static org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory.DEFAULT_HOST; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.AUTH_PASSPHRASE; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.AUTH_PROTOCOL; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.PRIV_PASSPHRASE; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.PRIV_PROTOCOL; +import static org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory.SECURITY_NAME; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +public class V3SNMPFactoryTest { + + private static final int RETRIES = 3; + private static final int EXPECTED_SECURITY_LEVEL = 3; + + @Test + public void testFactoryCreatesTarget() { + final V3SNMPFactory snmpFactory = new V3SNMPFactory(); + final int managerPort = NetworkUtils.availablePort(); + final String targetPort = String.valueOf(NetworkUtils.availablePort()); + final SNMPConfiguration snmpConfiguration = getSnmpConfiguration(managerPort, targetPort); + + final Target target = snmpFactory.createTargetInstance(snmpConfiguration); + + assertThat(target, instanceOf(UserTarget.class)); + assertEquals(DEFAULT_HOST + "/" + targetPort, target.getAddress().toString()); + assertEquals(RETRIES, target.getRetries()); + assertEquals(EXPECTED_SECURITY_LEVEL, target.getSecurityLevel()); + assertEquals(SECURITY_NAME, target.getSecurityName().toString()); + } + + @Test + public void testFactoryCreatesSnmpManager() { + final V3SNMPFactory snmpFactory = new V3SNMPFactory(); + final int managerPort = NetworkUtils.availablePort(); + final String targetPort = String.valueOf(NetworkUtils.availablePort()); + final SNMPConfiguration snmpConfiguration = getSnmpConfiguration(managerPort, targetPort); + + final Snmp snmpManager = snmpFactory.createSnmpManagerInstance(snmpConfiguration); + + final String address = snmpManager.getMessageDispatcher().getTransportMappings().iterator().next().getListenAddress().toString(); + USM usm = (USM) SecurityModels.getInstance().getSecurityModel(new Integer32(3)); + assertEquals(DEFAULT_HOST + "/" + managerPort, address); + assertTrue(usm.hasUser(null, new OctetString("SHAAES128"))); + } + + @Test + public void testFactoryCreatesResourceHandler() { + final V3SNMPFactory snmpFactory = spy(V3SNMPFactory.class); + final int managerPort = NetworkUtils.availablePort(); + final String targetPort = String.valueOf(NetworkUtils.availablePort()); + final SNMPConfiguration snmpConfiguration = getSnmpConfiguration(managerPort, targetPort); + snmpFactory.createSNMPResourceHandler(snmpConfiguration); + + verify(snmpFactory).createTargetInstance(snmpConfiguration); + verify(snmpFactory).createSnmpManagerInstance(snmpConfiguration); + } + + private SNMPConfiguration getSnmpConfiguration(int managerPort, String targetPort) { + return new SNMPConfiguration.Builder() + .setRetries(RETRIES) + .setManagerPort(managerPort) + .setTargetHost(DEFAULT_HOST) + .setTargetPort(targetPort) + .setSecurityLevel(SecurityLevel.authPriv.name()) + .setSecurityName(SECURITY_NAME) + .setAuthProtocol(AUTH_PROTOCOL) + .setAuthPassphrase(AUTH_PASSPHRASE) + .setPrivacyProtocol(PRIV_PROTOCOL) + .setPrivacyPassphrase(PRIV_PASSPHRASE) + .build(); + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactoryTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactoryTest.java new file mode 100644 index 0000000000..3cd699d76d --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V1TrapPDUFactoryTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.trap; + +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.junit.Test; +import org.snmp4j.PDU; +import org.snmp4j.PDUv1; +import org.snmp4j.Target; + +import java.time.Instant; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +public class V1TrapPDUFactoryTest { + + private static final String AGENT_ADDRESS = "127.0.0.1"; + private static final String ENTERPRISE_OID = "1.3.6.1.4.1.8072.2.3.0.1"; + private static final int GENERIC_TRAP_TYPE = 6; + private static final int SPECIFIC_TRAP_TYPE = 2; + + @Test + public void testCreateV1TrapPdu() { + final Target mockTarget = mock(Target.class); + final V1TrapConfiguration v1TrapConfiguration = V1TrapConfiguration.builder() + .enterpriseOid(ENTERPRISE_OID) + .agentAddress(AGENT_ADDRESS) + .genericTrapType(String.valueOf(GENERIC_TRAP_TYPE)) + .specificTrapType(String.valueOf(SPECIFIC_TRAP_TYPE)) + .build(); + + final V1TrapPDUFactory v1TrapPduFactory = new V1TrapPDUFactory(mockTarget, Instant.now()); + final PDU pdu = v1TrapPduFactory.get(v1TrapConfiguration); + + assertEquals(PDU.V1TRAP, pdu.getType()); + + final PDUv1 pduV1 = (PDUv1) pdu; + + assertEquals(ENTERPRISE_OID, pduV1.getEnterprise().toString()); + assertEquals(AGENT_ADDRESS, pduV1.getAgentAddress().toString()); + assertEquals(GENERIC_TRAP_TYPE, pduV1.getGenericTrap()); + assertEquals(SPECIFIC_TRAP_TYPE, pduV1.getSpecificTrap()); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactoryTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactoryTest.java new file mode 100644 index 0000000000..64b81e9dd8 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactoryTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.factory.trap; + +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.junit.Test; +import org.snmp4j.PDU; +import org.snmp4j.Target; +import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.smi.VariableBinding; + +import java.time.Instant; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.Vector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class V2TrapPDUFactoryTest { + + private static final String TRAP_OID = "1.3.6.1.4.1.8072.2.3.0.1"; + + @Test + public void testCreateV2TrapPdu() { + final Target mockTarget = mock(Target.class); + final V2TrapConfiguration v2TrapConfiguration = new V2TrapConfiguration(TRAP_OID); + final V2TrapPDUFactory v2TrapPduFactory = new V2TrapPDUFactory(mockTarget, Instant.now()); + + final PDU pdu = v2TrapPduFactory.get(v2TrapConfiguration); + + final Vector variableBindings = pdu.getVariableBindings(); + + Set expected = new HashSet<>(Arrays.asList(SnmpConstants.snmpTrapOID.toString(), TRAP_OID)); + Set actual = variableBindings.stream() + .flatMap(c -> Stream.of(c.getOid().toString(), c.getVariable().toString())) + .collect(Collectors.toSet()); + assertTrue(actual.containsAll(expected)); + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/SNMPTestUtils.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/SNMPTestUtils.java deleted file mode 100644 index 492690fa4f..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/SNMPTestUtils.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.helper; - -import org.snmp4j.CommunityTarget; -import org.snmp4j.Snmp; -import org.snmp4j.UserTarget; -import org.snmp4j.security.UsmUser; -import org.snmp4j.smi.OID; -import org.snmp4j.smi.OctetString; -import org.snmp4j.smi.UdpAddress; -import org.snmp4j.transport.DefaultUdpTransportMapping; - -import java.io.IOException; - -public class SNMPTestUtils { - - public static Snmp createSnmpClient() throws IOException { - final DefaultUdpTransportMapping transportMapping = new DefaultUdpTransportMapping(); - transportMapping.listen(); - return new Snmp(transportMapping); - } - - public static CommunityTarget createCommTarget(final String community, final String address, final int version) { - final CommunityTarget target = new CommunityTarget(); - target.setVersion(version); - target.setCommunity(new OctetString(community)); - target.setAddress(new UdpAddress(address)); - target.setRetries(0); - target.setTimeout(500); - return target; - } - - public static UserTarget createUserTarget(final String address, final int securityLevel, final String securityName, final int version) { - final UserTarget target = new UserTarget(); - target.setVersion(version); - target.setSecurityLevel(securityLevel); - target.setSecurityName(new OctetString(securityName)); - target.setAddress(new UdpAddress(address)); - target.setRetries(0); - target.setTimeout(500); - return target; - } - - public static UserTarget prepareUser(final Snmp snmp, final int version, final String address, final int securityLevel, final String securityName, - final OID auth, final OID priv, final String authPwd, final String privPwd) { - snmp.getUSM().removeAllUsers(); - final OctetString aPwd = authPwd != null ? new OctetString(authPwd) : null; - final OctetString pPwd = privPwd != null ? new OctetString(privPwd) : null; - snmp.getUSM().addUser(new OctetString(securityName), new UsmUser(new OctetString(securityName), auth, aPwd, priv, pPwd)); - return createUserTarget(address, securityLevel, securityName, version); - } - -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/TrapConfigurationFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/TrapConfigurationFactory.java new file mode 100644 index 0000000000..dff77e8e79 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/TrapConfigurationFactory.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.helper; + +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.snmp4j.PDUv1; + +public class TrapConfigurationFactory { + + // v1 specific + private static final String ENTERPRISE_OID = "1.3.5.7.11"; + private static final String AGENT_ADDRESS = "1.2.3.4"; + private static final String GENERIC_TRAP_TYPE = String.valueOf(PDUv1.ENTERPRISE_SPECIFIC); + private static final String SPECIFIC_TRAP_TYPE = "2"; + + // v2c/v3 specific + private static final String TRAP_OID_VALUE = "testTrapOidValue"; + + public static V1TrapConfiguration getV1TrapConfiguration() { + return V1TrapConfiguration.builder() + .enterpriseOid(ENTERPRISE_OID) + .agentAddress(AGENT_ADDRESS) + .genericTrapType(GENERIC_TRAP_TYPE) + .specificTrapType(SPECIFIC_TRAP_TYPE) + .build(); + } + + public static V2TrapConfiguration getV2TrapConfiguration() { + return new V2TrapConfiguration(TRAP_OID_VALUE); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/SNMPFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPConfigurationFactory.java similarity index 67% rename from nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/SNMPFactory.java rename to nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPConfigurationFactory.java index 442c03e092..89e8bd4db5 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/SNMPFactory.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPConfigurationFactory.java @@ -14,17 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.snmp.factory; +package org.apache.nifi.snmp.helper.configurations; import org.apache.nifi.snmp.configuration.SNMPConfiguration; -import org.snmp4j.Snmp; -import org.snmp4j.Target; -public interface SNMPFactory { +public interface SNMPConfigurationFactory { - boolean supports(final int version); + String DEFAULT_HOST = "127.0.0.1"; + String COMMUNITY_STRING = "public"; - Snmp createSnmpManagerInstance(final SNMPConfiguration configuration); + SNMPConfiguration createSnmpGetSetConfiguration(int agentPort); + + SNMPConfiguration createSnmpGetSetConfigWithCustomHost(final String host, final int agentPort); + + SNMPConfiguration createSnmpListenTrapConfig(final int managerPort); - Target createTargetInstance(final SNMPConfiguration configuration); } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1V2cConfigurationFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1V2cConfigurationFactory.java new file mode 100644 index 0000000000..72591bec15 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1V2cConfigurationFactory.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.helper.configurations; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; + +public class SNMPV1V2cConfigurationFactory implements SNMPConfigurationFactory { + + private int snmpVersion; + + public SNMPV1V2cConfigurationFactory(int snmpVersion) { + this.snmpVersion = snmpVersion; + } + + @Override + public SNMPConfiguration createSnmpGetSetConfiguration(final int agentPort) { + return SNMPConfiguration.builder() + .setTargetHost(DEFAULT_HOST) + .setTargetPort(String.valueOf(agentPort)) + .setCommunityString(COMMUNITY_STRING) + .setVersion(snmpVersion) + .build(); + } + + @Override + public SNMPConfiguration createSnmpGetSetConfigWithCustomHost(final String host, final int agentPort) { + return SNMPConfiguration.builder() + .setTargetHost(host) + .setTargetPort(String.valueOf(agentPort)) + .setCommunityString(COMMUNITY_STRING) + .setVersion(snmpVersion) + .build(); + } + + @Override + public SNMPConfiguration createSnmpListenTrapConfig(final int managerPort) { + return SNMPConfiguration.builder() + .setManagerPort(managerPort) + .setCommunityString(COMMUNITY_STRING) + .setVersion(snmpVersion) + .build(); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV3ConfigurationFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV3ConfigurationFactory.java new file mode 100644 index 0000000000..7a278f5bbc --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV3ConfigurationFactory.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.helper.configurations; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.snmp4j.mp.SnmpConstants; + +public class SNMPV3ConfigurationFactory implements SNMPConfigurationFactory { + + // V3 security (users are set in test agents) + public static final String SECURITY_LEVEL = "authPriv"; + public static final String SECURITY_NAME = "SHAAES128"; + public static final String AUTH_PROTOCOL = "SHA"; + public static final String AUTH_PASSPHRASE = "SHAAES128AuthPassphrase"; + public static final String PRIV_PROTOCOL = "AES128"; + public static final String PRIV_PASSPHRASE = "SHAAES128PrivPassphrase"; + + @Override + public SNMPConfiguration createSnmpGetSetConfiguration(final int agentPort) { + return SNMPConfiguration.builder() + .setTargetHost(DEFAULT_HOST) + .setTargetPort(String.valueOf(agentPort)) + .setCommunityString(COMMUNITY_STRING) + .setVersion(SnmpConstants.version3) + .setSecurityLevel(SECURITY_LEVEL) + .setSecurityName(SECURITY_NAME) + .setAuthProtocol(AUTH_PROTOCOL) + .setAuthPassphrase(AUTH_PASSPHRASE) + .setPrivacyProtocol(PRIV_PROTOCOL) + .setPrivacyPassphrase(PRIV_PASSPHRASE) + .build(); + } + + @Override + public SNMPConfiguration createSnmpGetSetConfigWithCustomHost(final String host, final int agentPort) { + return SNMPConfiguration.builder() + .setTargetHost(host) + .setTargetPort(String.valueOf(agentPort)) + .setCommunityString(COMMUNITY_STRING) + .setVersion(SnmpConstants.version3) + .setSecurityLevel(SECURITY_LEVEL) + .setSecurityName(SECURITY_NAME) + .setAuthProtocol(AUTH_PROTOCOL) + .setAuthPassphrase(AUTH_PASSPHRASE) + .setPrivacyProtocol(PRIV_PROTOCOL) + .setPrivacyPassphrase(PRIV_PASSPHRASE) + .build(); + } + + @Override + public SNMPConfiguration createSnmpListenTrapConfig(final int managerPort) { + return SNMPConfiguration.builder() + .setManagerPort(managerPort) + .setVersion(SnmpConstants.version3) + .build(); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPTestRunnerFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPTestRunnerFactory.java new file mode 100644 index 0000000000..4096f45a00 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPTestRunnerFactory.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.helper.testrunners; + +import org.apache.nifi.snmp.exception.InvalidSnmpVersionException; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.snmp4j.mp.SnmpConstants; + +import java.util.HashMap; +import java.util.Map; + +import static org.apache.nifi.snmp.utils.SNMPUtils.SNMP_PROP_PREFIX; + +public interface SNMPTestRunnerFactory { + + TestRunner createSnmpGetTestRunner(final int agentPort, final String oid, final String strategy); + + TestRunner createSnmpSetTestRunner(final int agentPort, final String oid, final String oidValue); + + TestRunner createSnmpSendTrapTestRunner(final int managerPort, final String oid, final String oidValue); + + TestRunner createSnmpListenTrapTestRunner(final int managerPort); + + default MockFlowFile getFlowFile(String oid, String oidValue) { + final MockFlowFile flowFile = new MockFlowFile(1L); + final Map attributes = new HashMap<>(); + attributes.put(SNMP_PROP_PREFIX + oid, oidValue); + flowFile.putAttributes(attributes); + return flowFile; + } + + default String getVersionName(final int version) { + if (version == SnmpConstants.version1) { + return "SNMPv1"; + } else if (version == SnmpConstants.version2c) { + return "SNMPv2c"; + } else if (version == SnmpConstants.version3) { + return "SNMPv3"; + } else { + throw new InvalidSnmpVersionException("Invalid SNMP version"); + } + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV1TestRunnerFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV1TestRunnerFactory.java new file mode 100644 index 0000000000..4bb17b5318 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV1TestRunnerFactory.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.helper.testrunners; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.apache.nifi.snmp.helper.TrapConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPV1V2cConfigurationFactory; +import org.apache.nifi.snmp.processors.GetSNMP; +import org.apache.nifi.snmp.processors.ListenTrapSNMP; +import org.apache.nifi.snmp.processors.SendTrapSNMP; +import org.apache.nifi.snmp.processors.SetSNMP; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V1TrapProperties; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; +import org.snmp4j.mp.SnmpConstants; + +public class SNMPV1TestRunnerFactory implements SNMPTestRunnerFactory { + + + private static final SNMPConfigurationFactory snmpV1V2ConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version1); + + @Override + public TestRunner createSnmpGetTestRunner(final int agentPort, final String oid, final String strategy) { + final TestRunner runner = TestRunners.newTestRunner(GetSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV1V2ConfigurationFactory.createSnmpGetSetConfiguration(agentPort); + runner.setProperty(GetSNMP.AGENT_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(GetSNMP.AGENT_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(GetSNMP.SNMP_STRATEGY, strategy); + runner.setProperty(GetSNMP.OID, oid); + return runner; + } + + @Override + public TestRunner createSnmpSetTestRunner(final int agentPort, final String oid, final String oidValue) { + final TestRunner runner = TestRunners.newTestRunner(SetSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV1V2ConfigurationFactory.createSnmpGetSetConfiguration(agentPort); + runner.setProperty(SetSNMP.AGENT_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(SetSNMP.AGENT_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + final MockFlowFile flowFile = getFlowFile(oid, oidValue); + runner.enqueue(flowFile); + return runner; + } + + @Override + public TestRunner createSnmpSendTrapTestRunner(final int managerPort, final String oid, final String oidValue) { + final TestRunner runner = TestRunners.newTestRunner(SendTrapSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV1V2ConfigurationFactory.createSnmpGetSetConfiguration(managerPort); + final V1TrapConfiguration trapConfiguration = TrapConfigurationFactory.getV1TrapConfiguration(); + runner.setProperty(SendTrapSNMP.SNMP_MANAGER_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(SendTrapSNMP.SNMP_MANAGER_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(V1TrapProperties.ENTERPRISE_OID, trapConfiguration.getEnterpriseOid()); + runner.setProperty(V1TrapProperties.AGENT_ADDRESS, trapConfiguration.getAgentAddress()); + runner.setProperty(V1TrapProperties.GENERIC_TRAP_TYPE, String.valueOf(trapConfiguration.getGenericTrapType())); + runner.setProperty(V1TrapProperties.SPECIFIC_TRAP_TYPE, String.valueOf(trapConfiguration.getSpecificTrapType())); + final MockFlowFile flowFile = getFlowFile(oid, oidValue); + runner.enqueue(flowFile); + return runner; + } + + @Override + public TestRunner createSnmpListenTrapTestRunner(final int managerPort) { + final TestRunner runner = TestRunners.newTestRunner(ListenTrapSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV1V2ConfigurationFactory.createSnmpListenTrapConfig(managerPort); + runner.setProperty(ListenTrapSNMP.SNMP_MANAGER_PORT, String.valueOf(snmpConfiguration.getManagerPort())); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + return runner; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV2cTestRunnerFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV2cTestRunnerFactory.java new file mode 100644 index 0000000000..63fc49e6b2 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV2cTestRunnerFactory.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.helper.testrunners; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.apache.nifi.snmp.helper.TrapConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPV1V2cConfigurationFactory; +import org.apache.nifi.snmp.processors.GetSNMP; +import org.apache.nifi.snmp.processors.ListenTrapSNMP; +import org.apache.nifi.snmp.processors.SendTrapSNMP; +import org.apache.nifi.snmp.processors.SetSNMP; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V2TrapProperties; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; +import org.snmp4j.mp.SnmpConstants; + +public class SNMPV2cTestRunnerFactory implements SNMPTestRunnerFactory { + + private static final SNMPConfigurationFactory snmpV2cConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version2c); + + @Override + public TestRunner createSnmpGetTestRunner(int agentPort, String oid, String strategy) { + final TestRunner runner = TestRunners.newTestRunner(GetSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV2cConfigurationFactory.createSnmpGetSetConfiguration(agentPort); + runner.setProperty(GetSNMP.OID, oid); + runner.setProperty(GetSNMP.AGENT_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(GetSNMP.AGENT_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(GetSNMP.SNMP_STRATEGY, strategy); + return runner; + } + + @Override + public TestRunner createSnmpSetTestRunner(int agentPort, String oid, String oidValue) { + final TestRunner runner = TestRunners.newTestRunner(SetSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV2cConfigurationFactory.createSnmpGetSetConfiguration(agentPort); + runner.setProperty(SetSNMP.AGENT_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(SetSNMP.AGENT_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + final MockFlowFile flowFile = getFlowFile(oid, oidValue); + runner.enqueue(flowFile); + return runner; + } + + @Override + public TestRunner createSnmpSendTrapTestRunner(int managerPort, final String oid, final String oidValue) { + final TestRunner runner = TestRunners.newTestRunner(SendTrapSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV2cConfigurationFactory.createSnmpGetSetConfiguration(managerPort); + final V2TrapConfiguration trapConfiguration = TrapConfigurationFactory.getV2TrapConfiguration(); + runner.setProperty(SendTrapSNMP.SNMP_MANAGER_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(SendTrapSNMP.SNMP_MANAGER_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(V2TrapProperties.TRAP_OID_VALUE, trapConfiguration.getTrapOidValue()); + final MockFlowFile flowFile = getFlowFile(oid, oidValue); + runner.enqueue(flowFile); + return runner; + } + + @Override + public TestRunner createSnmpListenTrapTestRunner(int managerPort) { + final TestRunner runner = TestRunners.newTestRunner(ListenTrapSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV2cConfigurationFactory.createSnmpListenTrapConfig(managerPort); + runner.setProperty(ListenTrapSNMP.SNMP_MANAGER_PORT, String.valueOf(snmpConfiguration.getManagerPort())); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + return runner; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java new file mode 100644 index 0000000000..998766e21f --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV3TestRunnerFactory.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.helper.testrunners; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.apache.nifi.snmp.helper.TrapConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory; +import org.apache.nifi.snmp.processors.GetSNMP; +import org.apache.nifi.snmp.processors.ListenTrapSNMP; +import org.apache.nifi.snmp.processors.SendTrapSNMP; +import org.apache.nifi.snmp.processors.SetSNMP; +import org.apache.nifi.snmp.processors.properties.BasicProperties; +import org.apache.nifi.snmp.processors.properties.V2TrapProperties; +import org.apache.nifi.snmp.processors.properties.V3SecurityProperties; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; + +public class SNMPV3TestRunnerFactory implements SNMPTestRunnerFactory { + + private static final String USM_USERS_FILE_PATH = "src/test/resources/usm.json"; + private static final SNMPConfigurationFactory snmpV3ConfigurationFactory = new SNMPV3ConfigurationFactory(); + + @Override + public TestRunner createSnmpGetTestRunner(int agentPort, String oid, String strategy) { + final TestRunner runner = TestRunners.newTestRunner(GetSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV3ConfigurationFactory.createSnmpGetSetConfiguration(agentPort); + runner.setProperty(GetSNMP.OID, oid); + runner.setProperty(GetSNMP.SNMP_STRATEGY, strategy); + runner.setProperty(GetSNMP.AGENT_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(GetSNMP.AGENT_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL, snmpConfiguration.getSecurityLevel()); + runner.setProperty(V3SecurityProperties.SNMP_SECURITY_NAME, snmpConfiguration.getSecurityName()); + runner.setProperty(V3SecurityProperties.SNMP_AUTH_PROTOCOL, snmpConfiguration.getAuthProtocol()); + runner.setProperty(V3SecurityProperties.SNMP_AUTH_PASSWORD, snmpConfiguration.getAuthPassphrase()); + runner.setProperty(V3SecurityProperties.SNMP_PRIVACY_PROTOCOL, snmpConfiguration.getPrivacyProtocol()); + runner.setProperty(V3SecurityProperties.SNMP_PRIVACY_PASSWORD, snmpConfiguration.getPrivacyPassphrase()); + return runner; + } + + @Override + public TestRunner createSnmpSetTestRunner(int agentPort, String oid, String oidValue) { + final TestRunner runner = TestRunners.newTestRunner(SetSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV3ConfigurationFactory.createSnmpGetSetConfiguration(agentPort); + runner.setProperty(SetSNMP.AGENT_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(SetSNMP.AGENT_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL, snmpConfiguration.getSecurityLevel()); + runner.setProperty(V3SecurityProperties.SNMP_SECURITY_NAME, snmpConfiguration.getSecurityName()); + runner.setProperty(V3SecurityProperties.SNMP_AUTH_PROTOCOL, snmpConfiguration.getAuthProtocol()); + runner.setProperty(V3SecurityProperties.SNMP_AUTH_PASSWORD, snmpConfiguration.getAuthPassphrase()); + runner.setProperty(V3SecurityProperties.SNMP_PRIVACY_PROTOCOL, snmpConfiguration.getPrivacyProtocol()); + runner.setProperty(V3SecurityProperties.SNMP_PRIVACY_PASSWORD, snmpConfiguration.getPrivacyPassphrase()); + final MockFlowFile flowFile = getFlowFile(oid, oidValue); + runner.enqueue(flowFile); + return runner; + } + + @Override + public TestRunner createSnmpSendTrapTestRunner(int managerPort, final String oid, final String oidValue) { + final TestRunner runner = TestRunners.newTestRunner(SendTrapSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV3ConfigurationFactory.createSnmpGetSetConfiguration(managerPort); + final V2TrapConfiguration trapConfiguration = TrapConfigurationFactory.getV2TrapConfiguration(); + runner.setProperty(SendTrapSNMP.SNMP_MANAGER_HOST, snmpConfiguration.getTargetHost()); + runner.setProperty(SendTrapSNMP.SNMP_MANAGER_PORT, snmpConfiguration.getTargetPort()); + runner.setProperty(BasicProperties.SNMP_COMMUNITY, snmpConfiguration.getCommunityString()); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(V2TrapProperties.TRAP_OID_VALUE, trapConfiguration.getTrapOidValue()); + + runner.setProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL, snmpConfiguration.getSecurityLevel()); + runner.setProperty(V3SecurityProperties.SNMP_SECURITY_NAME, snmpConfiguration.getSecurityName()); + runner.setProperty(V3SecurityProperties.SNMP_AUTH_PROTOCOL, snmpConfiguration.getAuthProtocol()); + runner.setProperty(V3SecurityProperties.SNMP_AUTH_PASSWORD, snmpConfiguration.getAuthPassphrase()); + runner.setProperty(V3SecurityProperties.SNMP_PRIVACY_PROTOCOL, snmpConfiguration.getPrivacyProtocol()); + runner.setProperty(V3SecurityProperties.SNMP_PRIVACY_PASSWORD, snmpConfiguration.getPrivacyPassphrase()); + + final MockFlowFile flowFile = getFlowFile(oid, oidValue); + runner.enqueue(flowFile); + + return runner; + } + + @Override + public TestRunner createSnmpListenTrapTestRunner(int managerPort) { + final TestRunner runner = TestRunners.newTestRunner(ListenTrapSNMP.class); + final SNMPConfiguration snmpConfiguration = snmpV3ConfigurationFactory.createSnmpListenTrapConfig(managerPort); + runner.setProperty(ListenTrapSNMP.SNMP_MANAGER_PORT, String.valueOf(snmpConfiguration.getManagerPort())); + runner.setProperty(BasicProperties.SNMP_VERSION, getVersionName(snmpConfiguration.getVersion())); + runner.setProperty(ListenTrapSNMP.SNMP_USM_USERS_FILE_PATH, USM_USERS_FILE_PATH); + + return runner; + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/GetSNMPHandlerTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/GetSNMPHandlerTest.java new file mode 100644 index 0000000000..8c98ec100b --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/GetSNMPHandlerTest.java @@ -0,0 +1,271 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.snmp.dto.SNMPSingleResponse; +import org.apache.nifi.snmp.dto.SNMPTreeResponse; +import org.apache.nifi.snmp.exception.RequestTimeoutException; +import org.apache.nifi.snmp.exception.SNMPWalkException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.event.ResponseEvent; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.OctetString; +import org.snmp4j.smi.VariableBinding; +import org.snmp4j.util.TreeEvent; +import org.snmp4j.util.TreeUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.nifi.snmp.operations.GetSNMPHandler.EMPTY_SUBTREE_EXCEPTION_MESSAGE; +import static org.apache.nifi.snmp.operations.GetSNMPHandler.LEAF_ELEMENT_EXCEPTION_MESSAGE; +import static org.apache.nifi.snmp.operations.GetSNMPHandler.SNMP_ERROR_EXCEPTION_MESSAGE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class GetSNMPHandlerTest { + + private static final String OID = "1.3.6.1.4.1.343"; + + private Target mockTarget; + private Snmp mockSnmpManager; + private SNMPResourceHandler snmpResourceHandler; + + @Before + public void init() { + mockTarget = mock(Target.class); + mockSnmpManager = mock(Snmp.class); + snmpResourceHandler = new SNMPResourceHandler(mockSnmpManager, mockTarget); + } + + @Test + public void testGetSnmpWithEmptyFlowFile() throws IOException { + final ResponseEvent mockResponseEvent = mock(ResponseEvent.class); + final PDU mockPdu = mock(PDU.class); + when(mockResponseEvent.getResponse()).thenReturn(mockPdu); + when(mockSnmpManager.get(any(PDU.class), any(Target.class))).thenReturn(mockResponseEvent); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.get(OID); + + ArgumentCaptor captor = ArgumentCaptor.forClass(PDU.class); + Mockito.verify(mockSnmpManager).get(captor.capture(), any(Target.class)); + + final PDU pdu = captor.getValue(); + assertEquals(1, pdu.getVariableBindings().size()); + assertEquals(OID, pdu.getVariableBindings().get(0).getOid().toString()); + } + + @Test + public void testGetSnmpWithInvalidFlowFile() throws IOException { + final Map invalidFlowFileAttributes = new HashMap<>(); + invalidFlowFileAttributes.put("invalid", "flowfile attribute"); + + final ResponseEvent mockResponseEvent = mock(ResponseEvent.class); + final PDU mockPdu = mock(PDU.class); + when(mockResponseEvent.getResponse()).thenReturn(mockPdu); + when(mockSnmpManager.get(any(PDU.class), any(Target.class))).thenReturn(mockResponseEvent); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final Optional optionalResponse = getSNMPHandler.get(invalidFlowFileAttributes); + + assertFalse(optionalResponse.isPresent()); + } + + @Test + public void testGetSnmpWithValidFlowFile() throws IOException { + final String flowFileOid = "1.3.6.1.2.1.1.1.0"; + final Map flowFileAttributes = new HashMap<>(); + flowFileAttributes.put("snmp$" + flowFileOid, "OID value"); + + final ResponseEvent mockResponseEvent = mock(ResponseEvent.class); + final PDU mockPdu = mock(PDU.class); + when(mockResponseEvent.getResponse()).thenReturn(mockPdu); + when(mockSnmpManager.get(any(PDU.class), any(Target.class))).thenReturn(mockResponseEvent); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.get(flowFileAttributes); + + ArgumentCaptor captor = ArgumentCaptor.forClass(PDU.class); + Mockito.verify(mockSnmpManager).get(captor.capture(), any(Target.class)); + + final PDU pdu = captor.getValue(); + assertEquals(1, pdu.getVariableBindings().size()); + assertEquals(flowFileOid, pdu.getVariableBindings().get(0).getOid().toString()); + assertEquals("Null", pdu.getVariableBindings().get(0).getVariable().toString()); + } + + @Test + public void testGetSnmpWhenTimeout() throws IOException { + final ResponseEvent mockResponseEvent = mock(ResponseEvent.class); + when(mockResponseEvent.getResponse()).thenReturn(null); + when(mockSnmpManager.get(any(PDU.class), any(Target.class))).thenReturn(mockResponseEvent); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + + final RequestTimeoutException requestTimeoutException = Assert.assertThrows( + RequestTimeoutException.class, + () -> getSNMPHandler.get(OID) + ); + + assertEquals(String.format(SNMPResourceHandler.REQUEST_TIMEOUT_EXCEPTION_TEMPLATE, "read"), + requestTimeoutException.getMessage()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWalkSnmpWithEmptyFlowFile() { + final TreeUtils mockTreeUtils = mock(TreeUtils.class); + final TreeEvent mockTreeEvent = mock(TreeEvent.class); + final List mockSubtree = (List) mock(List.class); + + final VariableBinding[] variableBindings = new VariableBinding[1]; + variableBindings[0] = new VariableBinding(new OID(OID), new OctetString("OID value")); + when(mockTreeEvent.getVariableBindings()).thenReturn(variableBindings); + when(mockSubtree.get(0)).thenReturn(mockTreeEvent); + when(mockTreeUtils.getSubtree(mockTarget, new OID(OID))).thenReturn(mockSubtree); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.setTreeUtils(mockTreeUtils); + getSNMPHandler.walk(OID); + + ArgumentCaptor captor = ArgumentCaptor.forClass(OID.class); + Mockito.verify(mockTreeUtils).getSubtree(any(Target.class), captor.capture()); + + assertEquals(OID, captor.getValue().toString()); + } + + @Test + public void testWalkSnmpWithInvalidFlowFile() { + final Map invalidFlowFileAttributes = new HashMap<>(); + invalidFlowFileAttributes.put("invalid", "flowfile attribute"); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final Optional optionalResponse = getSNMPHandler.walk(invalidFlowFileAttributes); + + assertFalse(optionalResponse.isPresent()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWalkSnmpWithValidFlowFile() { + final String flowFileOid = "1.3.6.1.2.1.1.1.0"; + final Map flowFileAttributes = new HashMap<>(); + flowFileAttributes.put("snmp$" + flowFileOid, "OID value"); + + final TreeUtils mockTreeUtils = mock(TreeUtils.class); + final TreeEvent mockTreeEvent = mock(TreeEvent.class); + final List mockSubtree = (List) mock(List.class); + + final VariableBinding[] variableBindings = new VariableBinding[1]; + variableBindings[0] = new VariableBinding(new OID(OID), new OctetString("OID value")); + when(mockTreeEvent.getVariableBindings()).thenReturn(variableBindings); + when(mockSubtree.get(0)).thenReturn(mockTreeEvent); + when(mockSubtree.isEmpty()).thenReturn(false); + when(mockTreeUtils.walk(any(Target.class), any(OID[].class))).thenReturn(mockSubtree); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.setTreeUtils(mockTreeUtils); + getSNMPHandler.walk(flowFileAttributes); + + ArgumentCaptor captor = ArgumentCaptor.forClass(OID[].class); + Mockito.verify(mockTreeUtils).walk(any(Target.class), captor.capture()); + + assertEquals(flowFileOid, captor.getValue()[0].toString()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWalkSnmpWithEmptySubtreeThrowsException() { + final TreeUtils mockTreeUtils = mock(TreeUtils.class); + final List mockSubtree = (List) mock(List.class); + + when(mockSubtree.isEmpty()).thenReturn(true); + when(mockTreeUtils.getSubtree(any(Target.class), any(org.snmp4j.smi.OID.class))).thenReturn(mockSubtree); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.setTreeUtils(mockTreeUtils); + + final SNMPWalkException snmpWalkException = Assert.assertThrows( + SNMPWalkException.class, + () -> getSNMPHandler.walk(OID) + ); + + assertEquals(String.format(EMPTY_SUBTREE_EXCEPTION_MESSAGE, OID), snmpWalkException.getMessage()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWalkSnmpWithSubtreeErrorThrowsException() { + final TreeUtils mockTreeUtils = mock(TreeUtils.class); + final TreeEvent mockTreeEvent = mock(TreeEvent.class); + final List mockSubtree = (List) mock(List.class); + + when(mockSubtree.get(0)).thenReturn(mockTreeEvent); + when(mockSubtree.isEmpty()).thenReturn(false); + when(mockSubtree.size()).thenReturn(1); + when(mockTreeUtils.getSubtree(any(Target.class), any(org.snmp4j.smi.OID.class))).thenReturn(mockSubtree); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.setTreeUtils(mockTreeUtils); + + final SNMPWalkException snmpWalkException = Assert.assertThrows( + SNMPWalkException.class, + () -> getSNMPHandler.walk(OID) + ); + + assertEquals(SNMP_ERROR_EXCEPTION_MESSAGE, snmpWalkException.getMessage()); + } + + @SuppressWarnings("unchecked") + @Test + public void testWalkSnmpWithLeafElementSubtreeThrowsException() { + final TreeUtils mockTreeUtils = mock(TreeUtils.class); + final TreeEvent mockTreeEvent = mock(TreeEvent.class); + final List mockSubtree = (List) mock(List.class); + + final VariableBinding[] variableBindings = new VariableBinding[0]; + when(mockTreeEvent.getVariableBindings()).thenReturn(variableBindings); + when(mockSubtree.get(0)).thenReturn(mockTreeEvent); + when(mockSubtree.isEmpty()).thenReturn(false); + when(mockSubtree.size()).thenReturn(1); + when(mockTreeUtils.getSubtree(any(Target.class), any(org.snmp4j.smi.OID.class))).thenReturn(mockSubtree); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.setTreeUtils(mockTreeUtils); + + final SNMPWalkException snmpWalkException = Assert.assertThrows( + SNMPWalkException.class, + () -> getSNMPHandler.walk(OID) + ); + + assertEquals(String.format(LEAF_ELEMENT_EXCEPTION_MESSAGE, OID), snmpWalkException.getMessage()); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPRequestTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPRequestTest.java index a3ca32299a..1b1e2574a2 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPRequestTest.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPRequestTest.java @@ -16,45 +16,67 @@ */ package org.apache.nifi.snmp.operations; +import org.apache.nifi.snmp.configuration.SNMPConfiguration; import org.apache.nifi.snmp.dto.SNMPSingleResponse; import org.apache.nifi.snmp.dto.SNMPTreeResponse; -import org.apache.nifi.snmp.helper.SNMPTestUtils; +import org.apache.nifi.snmp.dto.SNMPValue; +import org.apache.nifi.snmp.exception.RequestTimeoutException; +import org.apache.nifi.snmp.factory.core.SNMPFactoryProvider; +import org.apache.nifi.snmp.helper.configurations.SNMPConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPV1V2cConfigurationFactory; +import org.apache.nifi.snmp.helper.configurations.SNMPV3ConfigurationFactory; import org.apache.nifi.snmp.testagents.TestAgent; -import org.apache.nifi.util.MockFlowFile; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.snmp4j.CommunityTarget; -import org.snmp4j.Snmp; +import org.apache.nifi.snmp.testagents.TestSNMPV1Agent; +import org.apache.nifi.snmp.testagents.TestSNMPV2cAgent; +import org.apache.nifi.snmp.testagents.TestSNMPV3Agent; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import org.snmp4j.agent.mo.DefaultMOFactory; import org.snmp4j.agent.mo.MOAccessImpl; +import org.snmp4j.mp.SnmpConstants; import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; -public abstract class SNMPRequestTest { +@RunWith(Parameterized.class) +public class SNMPRequestTest { - protected static final String LOCALHOST = "127.0.0.1"; - protected static final String INVALID_HOST = "127.0.0.2"; - protected static final String READ_ONLY_OID_1 = "1.3.6.1.4.1.32437.1.5.1.4.2.0"; - protected static final String READ_ONLY_OID_2 = "1.3.6.1.4.1.32437.1.5.1.4.3.0"; - protected static final String WRITE_ONLY_OID = "1.3.6.1.4.1.32437.1.5.1.4.4.0"; - protected static final String READ_ONLY_OID_VALUE_1 = "TestOID1"; - protected static final String READ_ONLY_OID_VALUE_2 = "TestOID2"; - protected static final String WRITE_ONLY_OID_VALUE = "writeOnlyOID"; - protected static final String SNMP_PROP_DELIMITER = "$"; - protected static final String SNMP_PROP_PREFIX = "snmp" + SNMP_PROP_DELIMITER; - protected static final String NOT_WRITABLE = "Not writable"; - protected static final String NO_ACCESS = "No access"; - protected static final String SUCCESS = "Success"; - protected static final String EXPECTED_OID_VALUE = "testValue"; + private static final String LOCALHOST = "127.0.0.1"; + private static final String INVALID_HOST = "127.0.0.2"; + private static final String READ_ONLY_OID_1 = "1.3.6.1.4.1.32437.1.5.1.4.2.0"; + private static final String READ_ONLY_OID_2 = "1.3.6.1.4.1.32437.1.5.1.4.3.0"; + private static final String WRITE_ONLY_OID = "1.3.6.1.4.1.32437.1.5.1.4.4.0"; + private static final String WALK_OID = "1.3.6.1.4.1.32437"; + private static final String INVALID_OID = "1.3.6.1.4.1.32437.0"; + private static final String READ_ONLY_OID_VALUE_1 = "TestOID1"; + private static final String READ_ONLY_OID_VALUE_2 = "TestOID2"; + private static final String WRITE_ONLY_OID_VALUE = "writeOnlyOID"; + private static final String SNMP_PROP_DELIMITER = "$"; + private static final String SNMP_PROP_PREFIX = "snmp" + SNMP_PROP_DELIMITER; + private static final String NOT_WRITABLE = "Not writable"; + private static final String NO_ACCESS = "No access"; + private static final String SUCCESS = "Success"; + private static final String NO_SUCH_OBJECT = "noSuchObject"; + private static final String UNABLE_TO_CREATE_OBJECT = "Unable to create object"; + private static final String TEST_OID_VALUE = "testValue"; + private static final String NO_SUCH_NAME = "No such name"; protected static final Map WALK_OID_MAP; static { @@ -64,53 +86,217 @@ public abstract class SNMPRequestTest { WALK_OID_MAP = Collections.unmodifiableMap(oidMap); } - protected final TestAgent agent = getAgentInstance(); + private static final SNMPConfigurationFactory snmpV1ConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version1); + private static final SNMPConfigurationFactory snmpv2cConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version2c); + private static final SNMPConfigurationFactory snmpv3ConfigurationFactory = new SNMPV3ConfigurationFactory(); - protected abstract TestAgent getAgentInstance(); + private static final TestAgent v1TestAgent = new TestSNMPV1Agent(LOCALHOST); + private static final TestAgent v2cTestAgent = new TestSNMPV2cAgent(LOCALHOST); + private static final TestAgent v3TestAgent = new TestSNMPV3Agent(LOCALHOST); - @BeforeEach + private SNMPResourceHandler snmpResourceHandler; + + static { + registerManagedObjects(v1TestAgent); + registerManagedObjects(v2cTestAgent); + registerManagedObjects(v3TestAgent); + } + + @Before public void initAgent() throws IOException { agent.start(); - agent.registerManagedObjects( - DefaultMOFactory.getInstance().createScalar(new OID(READ_ONLY_OID_1), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(READ_ONLY_OID_VALUE_1)), - DefaultMOFactory.getInstance().createScalar(new OID(READ_ONLY_OID_2), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(READ_ONLY_OID_VALUE_2)), - DefaultMOFactory.getInstance().createScalar(new OID(WRITE_ONLY_OID), MOAccessImpl.ACCESS_WRITE_ONLY, new OctetString(WRITE_ONLY_OID_VALUE)) - ); } - @AfterEach + @After public void tearDown() { agent.stop(); + agent.unregister(); + snmpResourceHandler.close(); } - protected SNMPTreeResponse getTreeEvents(final int port, final int version) throws IOException { - final Snmp snmp = SNMPTestUtils.createSnmpClient(); - final CommunityTarget target = SNMPTestUtils.createCommTarget("public", LOCALHOST + "/" + port, version); - final StandardSNMPRequestHandler standardSnmpRequestHandler = new StandardSNMPRequestHandler(snmp, target); - return standardSnmpRequestHandler.walk("1.3.6.1.4.1.32437"); + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + {SnmpConstants.version1, snmpV1ConfigurationFactory, v1TestAgent, NO_SUCH_NAME, NO_SUCH_NAME, NO_SUCH_NAME, NO_SUCH_NAME}, + {SnmpConstants.version2c, snmpv2cConfigurationFactory, v2cTestAgent, NOT_WRITABLE, NO_ACCESS, NO_SUCH_OBJECT, UNABLE_TO_CREATE_OBJECT}, + {SnmpConstants.version3, snmpv3ConfigurationFactory, v3TestAgent, NOT_WRITABLE, NO_ACCESS, NO_SUCH_OBJECT, UNABLE_TO_CREATE_OBJECT} + }); } - protected SNMPSingleResponse getResponseEvent(final String address, final int port, final int version, final String oid) throws IOException { - final Snmp snmp = SNMPTestUtils.createSnmpClient(); - final CommunityTarget target = SNMPTestUtils.createCommTarget("public", address + "/" + port, version); - final StandardSNMPRequestHandler standardSnmpRequestHandler = new StandardSNMPRequestHandler(snmp, target); - return standardSnmpRequestHandler.get(oid); + private final int version; + private final SNMPConfigurationFactory snmpConfigurationFactory; + private final TestAgent agent; + private final String cannotSetReadOnlyOidStatusMessage; + private final String cannotModifyOidStatusMessage; + private final String getInvalidOidStatusMessage; + private final String setInvalidOidStatusMessage; + + public SNMPRequestTest(final int version, final SNMPConfigurationFactory snmpConfigurationFactory, final TestAgent agent, + final String cannotSetReadOnlyOidStatusMessage, final String cannotModifyOidStatusMessage, + final String getInvalidOidStatusMessage, final String setInvalidOidStatusMessage) { + this.version = version; + this.snmpConfigurationFactory = snmpConfigurationFactory; + this.agent = agent; + this.cannotSetReadOnlyOidStatusMessage = cannotSetReadOnlyOidStatusMessage; + this.cannotModifyOidStatusMessage = cannotModifyOidStatusMessage; + this.getInvalidOidStatusMessage = getInvalidOidStatusMessage; + this.setInvalidOidStatusMessage = setInvalidOidStatusMessage; } - protected SNMPSingleResponse getSetResponse(final int port, final int version, final String oid, final String expectedOid) throws IOException { - final Snmp snmp = SNMPTestUtils.createSnmpClient(); - final CommunityTarget target = SNMPTestUtils.createCommTarget("public", LOCALHOST + "/" + port, version); - final StandardSNMPRequestHandler standardSnmpRequestHandler = new StandardSNMPRequestHandler(snmp, target); + @Test + public void testSuccessfulSnmpGet() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final SNMPSingleResponse response = getSNMPHandler.get(READ_ONLY_OID_1); + assertEquals(READ_ONLY_OID_VALUE_1, response.getVariableBindings().get(0).getVariable()); + assertEquals(SUCCESS, response.getErrorStatusText()); - final MockFlowFile flowFile = new MockFlowFile(1L); + } + + @Test + public void testSuccessfulSnmpGetWithFlowFileInput() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final Optional optionalResponse = getSNMPHandler.get(getFlowFileAttributesForSnmpGet(READ_ONLY_OID_1, READ_ONLY_OID_2)); + if (optionalResponse.isPresent()) { + final SNMPSingleResponse response = optionalResponse.get(); + Set expectedVariables = new HashSet<>(Arrays.asList(READ_ONLY_OID_VALUE_1, READ_ONLY_OID_VALUE_2)); + Set actualVariables = response.getVariableBindings().stream().map(SNMPValue::getVariable).collect(Collectors.toSet()); + assertEquals(expectedVariables, actualVariables); + assertEquals(SUCCESS, response.getErrorStatusText()); + } else { + fail("Response is not present."); + } + } + + @Test + public void testSuccessfulSnmpWalk() { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final SNMPTreeResponse response = getSNMPHandler.walk(WALK_OID); + + assertSubTreeContainsOids(response); + } + + @Test(expected = RequestTimeoutException.class) + public void testSnmpGetTimeoutReturnsNull() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfigWithCustomHost(INVALID_HOST, agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + getSNMPHandler.get(READ_ONLY_OID_1); + } + + @Test + public void testSnmpGetInvalidOidWithFlowFileInput() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final Optional optionalResponse = getSNMPHandler.get(getFlowFileAttributesForSnmpGet(INVALID_OID, READ_ONLY_OID_2)); + if (optionalResponse.isPresent()) { + final SNMPSingleResponse response = optionalResponse.get(); + if (version == SnmpConstants.version1) { + assertEquals("Null", response.getVariableBindings().get(1).getVariable()); + assertEquals(READ_ONLY_OID_VALUE_2, response.getVariableBindings().get(0).getVariable()); + assertEquals(NO_SUCH_NAME, response.getErrorStatusText()); + } else { + assertEquals(NO_SUCH_OBJECT, response.getVariableBindings().get(1).getVariable()); + assertEquals(READ_ONLY_OID_VALUE_2, response.getVariableBindings().get(0).getVariable()); + assertEquals(SUCCESS, response.getErrorStatusText()); + } + } else { + fail("Response is not present."); + } + } + + @Test + public void testSuccessfulSnmpSet() throws IOException { + final Map flowFileAttributes = getFlowFileAttributes(WRITE_ONLY_OID); + + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final SetSNMPHandler setSNMPHandler = new SetSNMPHandler(snmpResourceHandler); + final Optional optionalResponse = setSNMPHandler.set(flowFileAttributes); + if (optionalResponse.isPresent()) { + final SNMPSingleResponse response = optionalResponse.get(); + assertEquals(TEST_OID_VALUE, response.getVariableBindings().get(0).getVariable()); + assertEquals(SUCCESS, response.getErrorStatusText()); + } else { + fail("Response is not present."); + } + } + + @Test + public void testCannotSetReadOnlyObject() throws IOException { + final Map flowFileAttributes = getFlowFileAttributes(READ_ONLY_OID_1); + + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final SetSNMPHandler setSNMPHandler = new SetSNMPHandler(snmpResourceHandler); + final Optional optionalResponse = setSNMPHandler.set(flowFileAttributes); + if (optionalResponse.isPresent()) { + final SNMPSingleResponse response = optionalResponse.get(); + assertEquals(cannotSetReadOnlyOidStatusMessage, response.getErrorStatusText()); + } else { + fail("Response is not present."); + } + } + + @Test + public void testCannotGetWriteOnlyObject() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final SNMPSingleResponse response = getSNMPHandler.get(WRITE_ONLY_OID); + + assertEquals(cannotModifyOidStatusMessage, response.getErrorStatusText()); + } + + @Test + public void testCannotGetInvalidOid() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final SNMPSingleResponse response = getSNMPHandler.get(INVALID_OID); + if (version == SnmpConstants.version1) { + assertEquals(getInvalidOidStatusMessage, response.getErrorStatusText()); + } else { + assertEquals(getInvalidOidStatusMessage, response.getVariableBindings().get(0).getVariable()); + assertEquals(SUCCESS, response.getErrorStatusText()); + } + } + + @Test + public void testCannotSetInvalidOid() throws IOException { + final Map flowFileAttributes = getFlowFileAttributes(INVALID_OID); + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + snmpResourceHandler = SNMPFactoryProvider.getFactory(version).createSNMPResourceHandler(snmpConfiguration); + final SetSNMPHandler setSNMPHandler = new SetSNMPHandler(snmpResourceHandler); + final Optional optionalResponse = setSNMPHandler.set(flowFileAttributes); + if (optionalResponse.isPresent()) { + final SNMPSingleResponse response = optionalResponse.get(); + assertEquals(setInvalidOidStatusMessage, response.getErrorStatusText()); + } else { + fail("Response is not present."); + } + } + + private Map getFlowFileAttributes(String oid) { final Map attributes = new HashMap<>(); - attributes.put(SNMP_PROP_PREFIX + oid, expectedOid); - flowFile.putAttributes(attributes); - - return standardSnmpRequestHandler.set(flowFile); + attributes.put(SNMP_PROP_PREFIX + oid, TEST_OID_VALUE); + return attributes; } - protected void assertSubTreeContainsOids(SNMPTreeResponse response) { + private Map getFlowFileAttributesForSnmpGet(String... oids) { + final Map attributes = new HashMap<>(); + Arrays.stream(oids).forEach(oid -> attributes.put(SNMP_PROP_PREFIX + oid, null)); + return attributes; + } + + private void assertSubTreeContainsOids(SNMPTreeResponse response) { final Map attributes = response.getAttributes(); attributes.entrySet().forEach(this::checkEntryContainsSubString); } @@ -124,7 +310,15 @@ public abstract class SNMPRequestTest { } }); if (!isMatch.get()) { - fail("Expected OID did not found in subtree."); + fail("Expected OID is not found in subtree."); } } + + private static void registerManagedObjects(final TestAgent agent) { + agent.registerManagedObjects( + DefaultMOFactory.getInstance().createScalar(new OID(READ_ONLY_OID_1), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(READ_ONLY_OID_VALUE_1)), + DefaultMOFactory.getInstance().createScalar(new OID(READ_ONLY_OID_2), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(READ_ONLY_OID_VALUE_2)), + DefaultMOFactory.getInstance().createScalar(new OID(WRITE_ONLY_OID), MOAccessImpl.ACCESS_WRITE_ONLY, new OctetString(WRITE_ONLY_OID_VALUE)) + ); + } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java new file mode 100644 index 0000000000..795c4ea881 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandlerTest.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.nifi.processor.ProcessSessionFactory; +import org.apache.nifi.remote.io.socket.NetworkUtils; +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.apache.nifi.snmp.dto.UserDetails; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.apache.nifi.util.MockComponentLog; +import org.junit.Test; +import org.snmp4j.Snmp; +import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.security.USM; +import org.snmp4j.security.UsmUser; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Scanner; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class SNMPTrapReceiverHandlerTest { + + public static final String USERS_JSON = "src/test/resources/users.json"; + + @Test + public void testTrapReceiverCreatesCommandResponder() { + final SNMPConfiguration snmpConfiguration = mock(SNMPConfiguration.class); + final ProcessSessionFactory mockProcessSessionFactory = mock(ProcessSessionFactory.class); + final MockComponentLog mockComponentLog = new MockComponentLog("componentId", new Object()); + final Snmp mockSnmpManager = mock(Snmp.class); + when(snmpConfiguration.getManagerPort()).thenReturn(NetworkUtils.availablePort()); + when(snmpConfiguration.getVersion()).thenReturn(SnmpConstants.version1); + + final SNMPTrapReceiverHandler trapReceiverHandler = new SNMPTrapReceiverHandler(snmpConfiguration, null); + trapReceiverHandler.setSnmpManager(mockSnmpManager); + trapReceiverHandler.createTrapReceiver(mockProcessSessionFactory, mockComponentLog); + + + verify(mockSnmpManager).addCommandResponder(any(SNMPTrapReceiver.class)); + + assertTrue(trapReceiverHandler.isStarted()); + } + + @Test + public void testCloseTrapReceiverCleansUpResources() throws IOException { + final SNMPConfiguration snmpConfiguration = mock(SNMPConfiguration.class); + final ProcessSessionFactory mockProcessSessionFactory = mock(ProcessSessionFactory.class); + final MockComponentLog mockComponentLog = new MockComponentLog("componentId", new Object()); + final USM mockUsm = mock(USM.class); + final Snmp mockSnmpManager = mock(Snmp.class); + + when(mockSnmpManager.getUSM()).thenReturn(mockUsm); + when(snmpConfiguration.getManagerPort()).thenReturn(NetworkUtils.availablePort()); + when(snmpConfiguration.getVersion()).thenReturn(SnmpConstants.version1); + + final SNMPTrapReceiverHandler trapReceiverHandler = new SNMPTrapReceiverHandler(snmpConfiguration, null); + trapReceiverHandler.setSnmpManager(mockSnmpManager); + trapReceiverHandler.createTrapReceiver(mockProcessSessionFactory, mockComponentLog); + trapReceiverHandler.close(); + + verify(mockUsm).removeAllUsers(); + verify(mockSnmpManager).close(); + + assertFalse(trapReceiverHandler.isStarted()); + } + + @Test + public void testAddUsmUsers() throws JsonProcessingException, FileNotFoundException { + final Set expectedUserAttributes = new HashSet<>(); + try (Scanner scanner = new Scanner(new File(USERS_JSON))) { + final String content = scanner.useDelimiter("\\Z").next(); + final ObjectMapper mapper = new ObjectMapper(); + final List userDetails = mapper.readValue(content, new TypeReference>() { + }); + userDetails + .forEach(user -> { + expectedUserAttributes.add(user.getSecurityName()); + expectedUserAttributes.add(SNMPUtils.getAuth(user.getAuthProtocol()).toString()); + expectedUserAttributes.add(user.getAuthPassphrase()); + expectedUserAttributes.add(SNMPUtils.getPriv(user.getPrivProtocol()).toString()); + expectedUserAttributes.add(user.getPrivPassphrase()); + }); + } + final Set usmAttributes = new HashSet<>(); + final SNMPConfiguration snmpConfiguration = mock(SNMPConfiguration.class); + final ProcessSessionFactory mockProcessSessionFactory = mock(ProcessSessionFactory.class); + final MockComponentLog mockComponentLog = new MockComponentLog("componentId", new Object()); + final Snmp mockSnmpManager = mock(Snmp.class); + final USM mockUsm = mock(USM.class); + + when(snmpConfiguration.getManagerPort()).thenReturn(NetworkUtils.availablePort()); + when(snmpConfiguration.getVersion()).thenReturn(SnmpConstants.version3); + doAnswer(invocation -> { + UsmUser usmUser = (UsmUser) invocation.getArgument(0); + usmAttributes.add(usmUser.getSecurityName().toString()); + usmAttributes.add(usmUser.getAuthenticationProtocol().toString()); + usmAttributes.add(usmUser.getAuthenticationPassphrase().toString()); + usmAttributes.add(usmUser.getPrivacyProtocol().toString()); + usmAttributes.add(usmUser.getPrivacyPassphrase().toString()); + return null; + }).when(mockUsm).addUser(any(UsmUser.class)); + when(mockSnmpManager.getUSM()).thenReturn(mockUsm); + + final SNMPTrapReceiverHandler trapReceiverHandler = new SNMPTrapReceiverHandler(snmpConfiguration, USERS_JSON); + trapReceiverHandler.setSnmpManager(mockSnmpManager); + trapReceiverHandler.createTrapReceiver(mockProcessSessionFactory, mockComponentLog); + + + verify(mockSnmpManager).addCommandResponder(any(SNMPTrapReceiver.class)); + + assertTrue(trapReceiverHandler.isStarted()); + + assertEquals(expectedUserAttributes, usmAttributes); + } + +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverTest.java new file mode 100644 index 0000000000..6b77b85537 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverTest.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.processor.ProcessSessionFactory; +import org.apache.nifi.snmp.processors.ListenTrapSNMP; +import org.apache.nifi.util.LogMessage; +import org.apache.nifi.util.MockComponentLog; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.MockProcessSession; +import org.apache.nifi.util.SharedSessionState; +import org.junit.Before; +import org.junit.Test; +import org.snmp4j.CommandResponderEvent; +import org.snmp4j.PDU; +import org.snmp4j.PDUv1; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.VariableBinding; + +import java.util.List; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicLong; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SNMPTrapReceiverTest { + + private static final Object MOCK_COMPONENT_ID = new Object(); + + private ProcessSessionFactory mockProcessSessionFactory; + private MockProcessSession mockProcessSession; + private MockComponentLog mockComponentLog; + private PDU mockPdu; + private SNMPTrapReceiver snmpTrapReceiver; + + + @Before + public void init() { + mockProcessSessionFactory = mock(ProcessSessionFactory.class); + mockComponentLog = new MockComponentLog("componentId", MOCK_COMPONENT_ID); + mockPdu = mock(PDU.class); + snmpTrapReceiver = new SNMPTrapReceiver(mockProcessSessionFactory, mockComponentLog); + final ListenTrapSNMP listenTrapSNMP = new ListenTrapSNMP(); + mockProcessSession = new MockProcessSession(new SharedSessionState(listenTrapSNMP, new AtomicLong(0L)), listenTrapSNMP); + } + + @Test + public void testReceiveTrapWithNullPduLogsError() { + CommandResponderEvent mockEvent = mock(CommandResponderEvent.class); + + snmpTrapReceiver.processPdu(mockEvent); + + final LogMessage logMessage = mockComponentLog.getErrorMessages().get(0); + + assertEquals(String.format("%s Request timed out or parameters are incorrect.", MOCK_COMPONENT_ID), logMessage.getMsg()); + } + + @Test + public void testReceiveTrapWithInvalidPduTypeLogsError() { + final CommandResponderEvent mockEvent = mock(CommandResponderEvent.class); + + when(mockPdu.getType()).thenReturn(PDU.REPORT); + when(mockEvent.getPDU()).thenReturn(mockPdu); + snmpTrapReceiver.processPdu(mockEvent); + + final LogMessage logMessage = mockComponentLog.getErrorMessages().get(0); + + assertEquals(String.format("%s Request timed out or parameters are incorrect.", MOCK_COMPONENT_ID), logMessage.getMsg()); + } + + @Test + public void testTrapReceiverCreatesTrapPduV1FlowFile() { + final CommandResponderEvent mockEvent = mock(CommandResponderEvent.class); + final PDUv1 mockV1Pdu = mock(PDUv1.class); + + when(mockV1Pdu.getType()).thenReturn(PDU.V1TRAP); + when(mockV1Pdu.getEnterprise()).thenReturn(new OID("1.3.6.1.2.1.1.1.0")); + when(mockV1Pdu.getSpecificTrap()).thenReturn(4); + final Vector vbs = new Vector<>(); + doReturn(vbs).when(mockV1Pdu).getVariableBindings(); + when(mockEvent.getPDU()).thenReturn(mockV1Pdu); + when(mockProcessSessionFactory.createSession()).thenReturn(mockProcessSession); + + snmpTrapReceiver.processPdu(mockEvent); + + final List flowFiles = mockProcessSession.getFlowFilesForRelationship(ListenTrapSNMP.REL_SUCCESS); + final FlowFile flowFile = flowFiles.get(0); + + assertEquals("1.3.6.1.2.1.1.1.0", flowFile.getAttribute("snmp$enterprise")); + assertEquals(String.valueOf(4), flowFile.getAttribute("snmp$specificTrapType")); + } + + @Test + public void testTrapReceiverCreatesTrapPduV2FlowFile() { + final CommandResponderEvent mockEvent = mock(CommandResponderEvent.class); + + when(mockPdu.getType()).thenReturn(PDU.TRAP); + when(mockPdu.getErrorIndex()).thenReturn(123); + when(mockPdu.getErrorStatusText()).thenReturn("test error status text"); + final Vector vbs = new Vector<>(); + doReturn(vbs).when(mockPdu).getVariableBindings(); + when(mockEvent.getPDU()).thenReturn(mockPdu); + when(mockProcessSessionFactory.createSession()).thenReturn(mockProcessSession); + + snmpTrapReceiver.processPdu(mockEvent); + + final List flowFiles = mockProcessSession.getFlowFilesForRelationship(ListenTrapSNMP.REL_SUCCESS); + final FlowFile flowFile = flowFiles.get(0); + + assertEquals(String.valueOf(123), flowFile.getAttribute("snmp$errorIndex")); + assertEquals("test error status text", flowFile.getAttribute("snmp$errorStatusText")); + } + + @Test + public void testReceiveTrapWithErrorGetsTransferredToFailure() { + final CommandResponderEvent mockEvent = mock(CommandResponderEvent.class); + + when(mockPdu.getType()).thenReturn(PDU.TRAP); + when(mockPdu.getErrorStatus()).thenReturn(PDU.badValue); + final Vector vbs = new Vector<>(); + doReturn(vbs).when(mockPdu).getVariableBindings(); + when(mockEvent.getPDU()).thenReturn(mockPdu); + when(mockProcessSessionFactory.createSession()).thenReturn(mockProcessSession); + + snmpTrapReceiver.processPdu(mockEvent); + + final List flowFiles = mockProcessSession.getFlowFilesForRelationship(ListenTrapSNMP.REL_FAILURE); + + assertFalse(flowFiles.isEmpty()); + final FlowFile flowFile = flowFiles.get(0); + + assertEquals(String.valueOf(PDU.badValue), flowFile.getAttribute("snmp$errorStatus")); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV1RequestTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV1RequestTest.java deleted file mode 100644 index 15be017e2c..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV1RequestTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.operations; - -import org.apache.nifi.snmp.dto.SNMPSingleResponse; -import org.apache.nifi.snmp.dto.SNMPTreeResponse; -import org.apache.nifi.snmp.exception.RequestTimeoutException; -import org.apache.nifi.snmp.testagents.TestAgent; -import org.apache.nifi.snmp.testagents.TestSNMPV1Agent; -import org.junit.jupiter.api.Test; -import org.snmp4j.MessageException; -import org.snmp4j.mp.SnmpConstants; - -import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class SNMPV1RequestTest extends SNMPRequestTest { - - private static final String NO_SUCH_NAME = "No such name"; - - @Override - protected TestAgent getAgentInstance() { - return new TestSNMPV1Agent(LOCALHOST); - } - - @Test - public void testSuccessfulSnmpGet() throws IOException { - final SNMPSingleResponse response = getResponseEvent(LOCALHOST, agent.getPort(), SnmpConstants.version1, READ_ONLY_OID_1); - assertEquals(READ_ONLY_OID_VALUE_1, response.getVariableBindings().get(0).getVariable()); - assertEquals(SUCCESS, response.getErrorStatusText()); - } - - @Test - public void testSuccessfulSnmpWalk() throws IOException { - final SNMPTreeResponse response = getTreeEvents(agent.getPort(), SnmpConstants.version1); - assertSubTreeContainsOids(response); - } - - @Test - public void testSnmpGetTimeoutReturnsNull() { - assertThrows(RequestTimeoutException.class, () -> getResponseEvent(INVALID_HOST, agent.getPort(), SnmpConstants.version1, READ_ONLY_OID_1)); - } - - @Test - public void testSnmpGetWithInvalidTargetThrowsException() { - assertThrows(MessageException.class, () -> getResponseEvent(LOCALHOST, agent.getPort(), -1, READ_ONLY_OID_1)); - } - - @Test - public void testSuccessfulSnmpSet() throws IOException { - final SNMPSingleResponse response = getSetResponse(agent.getPort(), SnmpConstants.version1, WRITE_ONLY_OID, EXPECTED_OID_VALUE); - - assertEquals(EXPECTED_OID_VALUE, response.getVariableBindings().get(0).getVariable()); - assertEquals(SUCCESS, response.getErrorStatusText()); - } - - @Test - public void testCannotSetReadOnlyObject() throws IOException { - final SNMPSingleResponse response = getSetResponse(agent.getPort(), SnmpConstants.version1, READ_ONLY_OID_1, EXPECTED_OID_VALUE); - - assertEquals(NO_SUCH_NAME, response.getErrorStatusText()); - } - - @Test - public void testCannotGetWriteOnlyObject() throws IOException { - final SNMPSingleResponse response = getResponseEvent(LOCALHOST, agent.getPort(), SnmpConstants.version1, WRITE_ONLY_OID); - - assertEquals(NO_SUCH_NAME, response.getErrorStatusText()); - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV2CRequestTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV2CRequestTest.java deleted file mode 100644 index c5eeac1b2c..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV2CRequestTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.operations; - -import org.apache.nifi.snmp.dto.SNMPSingleResponse; -import org.apache.nifi.snmp.dto.SNMPTreeResponse; -import org.apache.nifi.snmp.exception.RequestTimeoutException; -import org.apache.nifi.snmp.testagents.TestAgent; -import org.apache.nifi.snmp.testagents.TestSNMPV2cAgent; -import org.junit.jupiter.api.Test; -import org.snmp4j.MessageException; -import org.snmp4j.mp.SnmpConstants; - -import java.io.IOException; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class SNMPV2CRequestTest extends SNMPRequestTest { - - @Override - protected TestAgent getAgentInstance() { - return new TestSNMPV2cAgent(LOCALHOST); - } - - @Test - public void testSuccessfulSnmpGet() throws IOException { - final SNMPSingleResponse response = getResponseEvent(LOCALHOST, agent.getPort(), SnmpConstants.version2c, READ_ONLY_OID_1); - - assertEquals(READ_ONLY_OID_VALUE_1, response.getVariableBindings().get(0).getVariable()); - assertEquals(SUCCESS, response.getErrorStatusText()); - } - - @Test - public void testSuccessfulSnmpWalk() throws IOException { - final SNMPTreeResponse response = getTreeEvents(agent.getPort(), SnmpConstants.version2c); - - assertSubTreeContainsOids(response); - } - - @Test - public void testSnmpGetTimeoutReturnsNull() { - assertThrows(RequestTimeoutException.class, () -> getResponseEvent(INVALID_HOST, agent.getPort(), SnmpConstants.version2c, READ_ONLY_OID_1)); - } - - @Test - public void testSnmpGetWithInvalidTargetThrowsException() { - assertThrows(MessageException.class, () -> getResponseEvent(LOCALHOST, agent.getPort(), -1, READ_ONLY_OID_1)); - } - - @Test - public void testSuccessfulSnmpSet() throws IOException { - final SNMPSingleResponse response = getSetResponse(agent.getPort(), SnmpConstants.version2c, WRITE_ONLY_OID, EXPECTED_OID_VALUE); - - assertEquals(EXPECTED_OID_VALUE, response.getVariableBindings().get(0).getVariable()); - assertEquals(SUCCESS, response.getErrorStatusText()); - } - - @Test - public void testCannotSetReadOnlyObject() throws IOException { - final SNMPSingleResponse response = getSetResponse(agent.getPort(), SnmpConstants.version2c, READ_ONLY_OID_1, EXPECTED_OID_VALUE); - - assertEquals(NOT_WRITABLE, response.getErrorStatusText()); - } - - @Test - public void testCannotGetWriteOnlyObject() throws IOException { - final SNMPSingleResponse response = getResponseEvent(LOCALHOST, agent.getPort(), SnmpConstants.version2c, WRITE_ONLY_OID); - - assertEquals(NO_ACCESS, response.getErrorStatusText()); - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV3RequestTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV3RequestTest.java deleted file mode 100644 index 1586862894..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPV3RequestTest.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.operations; - -import org.apache.nifi.snmp.dto.SNMPSingleResponse; -import org.apache.nifi.snmp.dto.SNMPTreeResponse; -import org.apache.nifi.snmp.exception.RequestTimeoutException; -import org.apache.nifi.snmp.helper.SNMPTestUtils; -import org.apache.nifi.snmp.testagents.TestAgent; -import org.apache.nifi.snmp.testagents.TestSNMPV3Agent; -import org.apache.nifi.util.MockFlowFile; -import org.junit.jupiter.api.Test; -import org.snmp4j.MessageException; -import org.snmp4j.SNMP4JSettings; -import org.snmp4j.Snmp; -import org.snmp4j.UserTarget; -import org.snmp4j.mp.SnmpConstants; -import org.snmp4j.security.AuthSHA; -import org.snmp4j.security.SecurityLevel; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -public class SNMPV3RequestTest extends SNMPRequestTest { - - @Override - protected TestAgent getAgentInstance() { - return new TestSNMPV3Agent(LOCALHOST); - } - - @Test - public void testSuccessfulSnmpGet() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(LOCALHOST, SnmpConstants.version3, - "SHA", "SHAAuthPassword"); - final SNMPSingleResponse response = standardSnmpRequestHandler.get(READ_ONLY_OID_1); - assertEquals(READ_ONLY_OID_VALUE_1, response.getVariableBindings().get(0).getVariable()); - assertEquals(SUCCESS, response.getErrorStatusText()); - } - - @Test - public void testSuccessfulSnmpWalk() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(LOCALHOST, SnmpConstants.version3, - "SHA", "SHAAuthPassword"); - final SNMPTreeResponse response = standardSnmpRequestHandler.walk("1.3.6.1.4.1.32437"); - - assertSubTreeContainsOids(response); - } - - @Test - public void testSnmpGetTimeoutReturnsNull() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(INVALID_HOST, SnmpConstants.version3, - "SHA", "SHAAuthPassword"); - assertThrows(RequestTimeoutException.class, () -> standardSnmpRequestHandler.get(READ_ONLY_OID_1)); - } - - @Test - public void testSnmpGetWithInvalidTargetThrowsException() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(LOCALHOST, -1, "SHA", "SHAAuthPassword"); - assertThrows(MessageException.class, () -> standardSnmpRequestHandler.get(READ_ONLY_OID_1)); - } - - @Test - public void testSuccessfulSnmpSet() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(LOCALHOST, SnmpConstants.version3, - "SHA", "SHAAuthPassword"); - - final MockFlowFile flowFile = new MockFlowFile(1L); - final Map attributes = new HashMap<>(); - attributes.put(SNMP_PROP_PREFIX + WRITE_ONLY_OID, EXPECTED_OID_VALUE); - flowFile.putAttributes(attributes); - - final SNMPSingleResponse response = standardSnmpRequestHandler.set(flowFile); - - assertEquals(EXPECTED_OID_VALUE, response.getVariableBindings().get(0).getVariable()); - - } - - @Test - public void testCannotSetReadOnlyObject() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(LOCALHOST, SnmpConstants.version3, - "SHA", "SHAAuthPassword"); - - final MockFlowFile flowFile = new MockFlowFile(1L); - final Map attributes = new HashMap<>(); - attributes.put(SNMP_PROP_PREFIX + READ_ONLY_OID_1, EXPECTED_OID_VALUE); - flowFile.putAttributes(attributes); - - final SNMPSingleResponse response = standardSnmpRequestHandler.set(flowFile); - - assertEquals(NOT_WRITABLE, response.getErrorStatusText()); - } - - @Test - public void testCannotGetWriteOnlyObject() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(LOCALHOST, SnmpConstants.version3, "SHA", "SHAAuthPassword"); - - final SNMPSingleResponse response = standardSnmpRequestHandler.get(WRITE_ONLY_OID); - - assertEquals(NO_ACCESS, response.getErrorStatusText()); - } - - @Test - public void testUnauthorizedUserSnmpGetReturnsNull() throws IOException { - final StandardSNMPRequestHandler standardSnmpRequestHandler = getSnmpV3Getter(LOCALHOST, SnmpConstants.version3, - "FakeUserName", "FakeAuthPassword"); - final SNMPSingleResponse response = standardSnmpRequestHandler.get(READ_ONLY_OID_1); - assertEquals("Null", response.getVariableBindings().get(0).getVariable()); - } - - private StandardSNMPRequestHandler getSnmpV3Getter(final String host, final int version, final String sha, final String shaAuthPassword) throws IOException { - SNMP4JSettings.setForwardRuntimeExceptions(true); - final Snmp snmp = SNMPTestUtils.createSnmpClient(); - final UserTarget userTarget = SNMPTestUtils.prepareUser(snmp, version, host + "/" + agent.getPort(), SecurityLevel.AUTH_NOPRIV, - sha, AuthSHA.ID, null, shaAuthPassword, null); - return new StandardSNMPRequestHandler(snmp, userTarget); - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java new file mode 100644 index 0000000000..6a202055f4 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SendTrapSNMPHandlerTest.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.apache.nifi.snmp.factory.trap.V1TrapPDUFactory; +import org.apache.nifi.snmp.factory.trap.V2TrapPDUFactory; +import org.apache.nifi.util.MockComponentLog; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.Target; + +import java.io.IOException; +import java.time.Instant; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class SendTrapSNMPHandlerTest { + + private Target mockTarget; + private Snmp mockSnmpManager; + private PDU mockPdu; + private MockComponentLog mockComponentLog; + private V1TrapConfiguration mockV1TrapConfiguration; + private V2TrapConfiguration mockV2TrapConfiguration; + private SNMPResourceHandler snmpResourceHandler; + private SendTrapSNMPHandler sendTrapSNMPHandler; + + @Before + public void init() { + mockTarget = mock(Target.class); + mockSnmpManager = mock(Snmp.class); + mockPdu = mock(PDU.class); + mockComponentLog = new MockComponentLog("id", new Object()); + mockV1TrapConfiguration = mock(V1TrapConfiguration.class); + mockV2TrapConfiguration = mock(V2TrapConfiguration.class); + V1TrapPDUFactory mockV1TrapPDUFactory = mock(V1TrapPDUFactory.class); + when(mockV1TrapPDUFactory.get(mockV1TrapConfiguration)).thenReturn(mockPdu); + V2TrapPDUFactory mockV2TrapPDUFactory = mock(V2TrapPDUFactory.class); + when(mockV2TrapPDUFactory.get(mockV2TrapConfiguration)).thenReturn(mockPdu); + + snmpResourceHandler = new SNMPResourceHandler(mockSnmpManager, mockTarget); + + sendTrapSNMPHandler = new SendTrapSNMPHandler(snmpResourceHandler, Instant.now(), mockComponentLog) { + @Override + V1TrapPDUFactory createV1TrapPduFactory(final Instant startTime) { + return mockV1TrapPDUFactory; + } + + @Override + V2TrapPDUFactory createV2TrapPduFactory(final Instant startTime) { + return mockV2TrapPDUFactory; + } + }; + } + + @After + public void tearDown() { + snmpResourceHandler.close(); + } + + @Test + public void testSendV1TrapWithValidFlowfile() throws IOException { + final String flowFileOid = "1.3.6.1.2.1.1.1.0"; + sendTrapSNMPHandler.sendTrap(Collections.singletonMap("snmp$" + flowFileOid, "OID value"), mockV1TrapConfiguration); + + verify(mockSnmpManager).send(mockPdu, mockTarget); + } + + @Test + public void testSendV2TrapWithValidFlowfile() throws IOException { + final String flowFileOid = "1.3.6.1.2.1.1.1.0"; + sendTrapSNMPHandler.sendTrap(Collections.singletonMap("snmp$" + flowFileOid, "OID value"), mockV2TrapConfiguration); + + verify(mockSnmpManager).send(mockPdu, mockTarget); + } + + @Test + public void testSendV1TrapWithFlowfileWithoutOptionalSnmpAttributes() throws IOException { + sendTrapSNMPHandler.sendTrap(Collections.singletonMap("invalid key", "invalid value"), mockV1TrapConfiguration); + + verify(mockSnmpManager).send(mockPdu, mockTarget); + + final String expectedDebugLog = "{} No optional SNMP specific variables found in flowfile."; + assertEquals(expectedDebugLog, mockComponentLog.getDebugMessages().get(0).getMsg()); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SetSNMPHandlerTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SetSNMPHandlerTest.java new file mode 100644 index 0000000000..65d9f59b2b --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SetSNMPHandlerTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.operations; + +import org.apache.nifi.snmp.dto.SNMPSingleResponse; +import org.apache.nifi.snmp.exception.RequestTimeoutException; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.Target; +import org.snmp4j.event.ResponseEvent; +import org.snmp4j.util.DefaultPDUFactory; +import org.snmp4j.util.PDUFactory; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.apache.nifi.snmp.operations.SNMPResourceHandler.REQUEST_TIMEOUT_EXCEPTION_TEMPLATE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class SetSNMPHandlerTest { + + private static final PDUFactory defaultSetPduFactory = new DefaultPDUFactory(PDU.SET); + + private Target mockTarget; + private Snmp mockSnmpManager; + private PDU mockPdu; + private PDU mockResponsePdu; + private ResponseEvent mockResponseEvent; + + private SetSNMPHandler setSNMPHandler; + + @Before + public void init() { + mockTarget = mock(Target.class); + mockSnmpManager = mock(Snmp.class); + PDUFactory mockPduFactory = mock(PDUFactory.class); + mockPdu = mock(PDU.class); + mockResponsePdu = mock(PDU.class); + mockResponseEvent = mock(ResponseEvent.class); + + when(mockPduFactory.createPDU(mockTarget)).thenReturn(mockPdu); + + SNMPResourceHandler snmpResourceHandler = new SNMPResourceHandler(mockSnmpManager, mockTarget); + setSNMPHandler = new SetSNMPHandler(snmpResourceHandler); + SetSNMPHandler.setSetPduFactory(mockPduFactory); + } + + @After + public void tearDown() { + SetSNMPHandler.setSetPduFactory(defaultSetPduFactory); + } + + @Test + public void testSetSnmpValidResponse() throws IOException { + final String flowFileOid = "1.3.6.1.2.1.1.1.0"; + final Map flowFileAttributes = new HashMap<>(); + flowFileAttributes.put("snmp$" + flowFileOid, "OID value"); + + when(mockResponseEvent.getResponse()).thenReturn(mockResponsePdu); + when(mockSnmpManager.set(any(PDU.class), any(Target.class))).thenReturn(mockResponseEvent); + + setSNMPHandler.set(flowFileAttributes); + + verify(mockSnmpManager).set(mockPdu, mockTarget); + } + + @Test + public void testSetSnmpTimeoutThrowsException() throws IOException { + final String flowFileOid = "1.3.6.1.2.1.1.1.0"; + final Map flowFileAttributes = new HashMap<>(); + flowFileAttributes.put("snmp$" + flowFileOid, "OID value"); + + when(mockSnmpManager.set(any(PDU.class), any(Target.class))).thenReturn(mockResponseEvent); + + final RequestTimeoutException requestTimeoutException = Assert.assertThrows( + RequestTimeoutException.class, + () -> setSNMPHandler.set(flowFileAttributes) + ); + + assertEquals(String.format(REQUEST_TIMEOUT_EXCEPTION_TEMPLATE, "write"), requestTimeoutException.getMessage()); + } + + @Test + public void testSetSnmpWithInvalidPduThrowsException() throws IOException { + final Map flowFileAttributes = new HashMap<>(); + flowFileAttributes.put("invalid key", "invalid value"); + + when(mockSnmpManager.set(any(PDU.class), any(Target.class))).thenReturn(mockResponseEvent); + + final Optional optionalResponse = setSNMPHandler.set(flowFileAttributes); + + assertFalse(optionalResponse.isPresent()); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessorTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessorTest.java new file mode 100644 index 0000000000..a9b66a8f82 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessorTest.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors; + +import org.apache.nifi.remote.io.socket.NetworkUtils; +import org.apache.nifi.snmp.dto.SNMPSingleResponse; +import org.apache.nifi.snmp.dto.SNMPValue; +import org.apache.nifi.snmp.helper.testrunners.SNMPV1TestRunnerFactory; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.MockProcessContext; +import org.apache.nifi.util.MockProcessSession; +import org.apache.nifi.util.SharedSessionState; +import org.apache.nifi.util.TestRunner; +import org.junit.Before; +import org.junit.Test; +import org.snmp4j.mp.SnmpConstants; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AbstractSNMPProcessorTest { + + private static final String TEST_OID = "1.3.6.1.4.1.32437.1.5.1.4.2.0"; + private static final String UNSUPPORTED_SECURITY_LEVEL = "1.3.6.1.6.3.15.1.1.1"; + + private GetSNMP getSNMP; + private MockProcessContext mockProcessContext; + private MockProcessSession mockProcessSession; + private MockFlowFile mockFlowFile; + private SNMPSingleResponse mockResponse; + private TestRunner getTestRunner; + + @Before + public void init() { + getTestRunner = new SNMPV1TestRunnerFactory().createSnmpGetTestRunner(NetworkUtils.availablePort(), TEST_OID, "GET"); + getSNMP = (GetSNMP) getTestRunner.getProcessor(); + mockProcessContext = new MockProcessContext(getSNMP); + mockProcessSession = new MockProcessSession(new SharedSessionState(getSNMP, new AtomicLong(0L)), getSNMP); + mockFlowFile = mockProcessSession.create(); + mockResponse = mock(SNMPSingleResponse.class); + } + + @Test + public void testProcessResponseWithInvalidResponseThrowsException() { + final String errorStatus = "Test error status text"; + when(mockResponse.getErrorStatusText()).thenReturn(errorStatus); + + + getSNMP.handleResponse(mockProcessContext, mockProcessSession, mockFlowFile, mockResponse, GetSNMP.REL_SUCCESS, GetSNMP.REL_FAILURE, "provenanceAddress"); + + final String actualLogMessage = getTestRunner.getLogger().getErrorMessages().get(0).getMsg(); + final String expectedLogMessage = String.format("SNMP request failed, response error: %s", errorStatus); + assertTrue(actualLogMessage.contains(expectedLogMessage)); + } + + @Test + public void testProcessResponseWithNoSuchObjectThrowsException() { + when(mockResponse.isValid()).thenReturn(true); + when(mockResponse.getVersion()).thenReturn(SnmpConstants.version2c); + + List vbs = Collections.singletonList(new SNMPValue(TEST_OID, "noSuchObject")); + when(mockResponse.getVariableBindings()).thenReturn(vbs); + + + getSNMP.handleResponse(mockProcessContext, mockProcessSession, mockFlowFile, mockResponse, GetSNMP.REL_SUCCESS, GetSNMP.REL_FAILURE, "provenanceAddress"); + + + final String actualLogMessage = getTestRunner.getLogger().getErrorMessages().get(0).getMsg(); + final String expectedLogMessage = "SNMP request failed, response error: OID not found."; + assertTrue(actualLogMessage.contains(expectedLogMessage)); + } + + @Test + public void testValidProcessResponseWithoutVariableBindingThrowsException() { + when(mockResponse.isValid()).thenReturn(true); + when(mockResponse.getVersion()).thenReturn(SnmpConstants.version2c); + + when(mockResponse.getVariableBindings()).thenReturn(Collections.emptyList()); + + getSNMP.handleResponse(mockProcessContext, mockProcessSession, mockFlowFile, mockResponse, GetSNMP.REL_SUCCESS, GetSNMP.REL_FAILURE, "provenanceAddress"); + + + final String actualLogMessage = getTestRunner.getLogger().getErrorMessages().get(0).getMsg(); + final String expectedLogMessage = "Empty SNMP response: no variable binding found."; + assertTrue(actualLogMessage.contains(expectedLogMessage)); + } + + @Test + public void testValidProcessResponse() { + when(mockResponse.isValid()).thenReturn(true); + when(mockResponse.getVersion()).thenReturn(SnmpConstants.version2c); + + final List vbs = Collections.singletonList(new SNMPValue(TEST_OID, "testOIDValue")); + when(mockResponse.getVariableBindings()).thenReturn(vbs); + + final Map attributes = Collections.singletonMap(TEST_OID, "testOIDValue"); + when(mockResponse.getAttributes()).thenReturn(attributes); + + getSNMP.handleResponse(mockProcessContext, mockProcessSession, mockFlowFile, mockResponse, GetSNMP.REL_SUCCESS, GetSNMP.REL_FAILURE, "provenanceAddress"); + final List flowFilesForRelationship = mockProcessSession.getFlowFilesForRelationship(GetSNMP.REL_SUCCESS); + + assertEquals("testOIDValue", flowFilesForRelationship.get(0).getAttribute(TEST_OID)); + } + + @Test + public void testProcessResponseWithReportPduWithoutErrorMessage() { + when(mockResponse.isValid()).thenReturn(true); + when(mockResponse.isReportPdu()).thenReturn(true); + + final List vbs = Collections.singletonList(new SNMPValue(TEST_OID, "testOIDValue")); + when(mockResponse.getVariableBindings()).thenReturn(vbs); + + + getSNMP.handleResponse(mockProcessContext, mockProcessSession, mockFlowFile, mockResponse, GetSNMP.REL_SUCCESS, GetSNMP.REL_FAILURE, "provenanceAddress"); + + + final String actualLogMessage = getTestRunner.getLogger().getErrorMessages().get(0).getMsg(); + final String expectedLogMessage = String.format("SNMP request failed, response error: Report-PDU returned, but no error message found. " + + "Please, check the OID %s in an online OID repository.", TEST_OID); + + assertTrue(actualLogMessage.contains(expectedLogMessage)); + } + + @Test + public void testProcessResponseWithReportPdu() { + when(mockResponse.isValid()).thenReturn(true); + when(mockResponse.isReportPdu()).thenReturn(true); + + final List vbs = Collections.singletonList(new SNMPValue(UNSUPPORTED_SECURITY_LEVEL, "testOIDValue")); + when(mockResponse.getVariableBindings()).thenReturn(vbs); + + + getSNMP.handleResponse(mockProcessContext, mockProcessSession, mockFlowFile, mockResponse, GetSNMP.REL_SUCCESS, GetSNMP.REL_FAILURE, "provenanceAddress"); + + + final String actualLogMessage = getTestRunner.getLogger().getErrorMessages().get(0).getMsg(); + final String expectedLogMessage = String.format("SNMP request failed, response error: Report-PDU returned. %s: usmStatsUnsupportedSecLevels", UNSUPPORTED_SECURITY_LEVEL); + + assertTrue(actualLogMessage.contains(expectedLogMessage)); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPIntegrationTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPIntegrationTest.java new file mode 100644 index 0000000000..ce0f7dc869 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPIntegrationTest.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.snmp.helper.testrunners.SNMPTestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV1TestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV2cTestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV3TestRunnerFactory; +import org.apache.nifi.snmp.testagents.TestAgent; +import org.apache.nifi.snmp.testagents.TestSNMPV1Agent; +import org.apache.nifi.snmp.testagents.TestSNMPV2cAgent; +import org.apache.nifi.snmp.testagents.TestSNMPV3Agent; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.snmp4j.agent.mo.DefaultMOFactory; +import org.snmp4j.agent.mo.MOAccessImpl; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.OctetString; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(Parameterized.class) +public class GetSNMPIntegrationTest { + + private static final String LOCALHOST = "127.0.0.1"; + private static final String READ_ONLY_OID_1 = "1.3.6.1.4.1.32437.1.5.1.4.2.0"; + private static final String READ_ONLY_OID_2 = "1.3.6.1.4.1.32437.1.5.1.4.3.0"; + private static final String NOT_FOUND_OID = "1.3.4.1.2.1.343"; + private static final String WALK_OID = "1.3.6.1.4.1.32437"; + private static final String READ_ONLY_OID_VALUE_1 = "TestOID1"; + private static final String READ_ONLY_OID_VALUE_2 = "TestOID2"; + private static final String GET = "GET"; + private static final String WALK = "WALK"; + + private static final SNMPTestRunnerFactory v1TestRunnerFactory = new SNMPV1TestRunnerFactory(); + private static final SNMPTestRunnerFactory v2cTestRunnerFactory = new SNMPV2cTestRunnerFactory(); + private static final SNMPTestRunnerFactory v3TestRunnerFactory = new SNMPV3TestRunnerFactory(); + + private static final TestAgent v1TestAgent = new TestSNMPV1Agent(LOCALHOST); + private static final TestAgent v2cTestAgent = new TestSNMPV2cAgent(LOCALHOST); + private static final TestAgent v3TestAgent = new TestSNMPV3Agent(LOCALHOST); + + static { + registerManagedObjects(v1TestAgent); + registerManagedObjects(v2cTestAgent); + registerManagedObjects(v3TestAgent); + } + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + {v1TestAgent, v1TestRunnerFactory}, + {v2cTestAgent, v2cTestRunnerFactory}, + {v3TestAgent, v3TestRunnerFactory} + }); + } + + private final TestAgent testAgent; + private final SNMPTestRunnerFactory testRunnerFactory; + + public GetSNMPIntegrationTest(final TestAgent testAgent, final SNMPTestRunnerFactory testRunnerFactory) { + this.testAgent = testAgent; + this.testRunnerFactory = testRunnerFactory; + } + + @Before + public void setUp() throws IOException { + testAgent.start(); + } + + @After + public void tearDown() { + testAgent.stop(); + testAgent.unregister(); + } + + @Test + public void testSnmpGet() { + + final TestRunner runner = testRunnerFactory.createSnmpGetTestRunner(testAgent.getPort(), READ_ONLY_OID_1, GET); + runner.run(); + final MockFlowFile successFF = runner.getFlowFilesForRelationship(GetSNMP.REL_SUCCESS).get(0); + + assertNotNull(successFF); + assertEquals(READ_ONLY_OID_VALUE_1, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + READ_ONLY_OID_1 + SNMPUtils.SNMP_PROP_DELIMITER + "4")); + } + + @Test + public void testSnmpWalk() { + final TestRunner runner = testRunnerFactory.createSnmpGetTestRunner(testAgent.getPort(), WALK_OID, WALK); + runner.run(); + final MockFlowFile successFF = runner.getFlowFilesForRelationship(GetSNMP.REL_SUCCESS).get(0); + assertNotNull(successFF); + + assertEquals(READ_ONLY_OID_VALUE_1, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + READ_ONLY_OID_1 + SNMPUtils.SNMP_PROP_DELIMITER + "4")); + assertEquals(READ_ONLY_OID_VALUE_2, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + READ_ONLY_OID_2 + SNMPUtils.SNMP_PROP_DELIMITER + "4")); + } + + @Test + public void testSnmpGetWithEmptyResponse() { + final MockFlowFile mockFlowFile = new MockFlowFile(0L); + mockFlowFile.putAttributes(Collections.singletonMap("snmp$" + NOT_FOUND_OID, StringUtils.EMPTY)); + final TestRunner runner = testRunnerFactory.createSnmpGetTestRunner(testAgent.getPort(), NOT_FOUND_OID, GET); + runner.enqueue(mockFlowFile); + runner.run(); + + if (testAgent == v1TestAgent) { + final MockFlowFile failureFF = runner.getFlowFilesForRelationship(GetSNMP.REL_FAILURE).get(0); + assertNotNull(failureFF); + assertEquals(StringUtils.EMPTY, failureFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + NOT_FOUND_OID)); + assertEquals("No such name", failureFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "errorStatusText")); + } else { + final MockFlowFile failureFF = runner.getFlowFilesForRelationship(GetSNMP.REL_FAILURE).get(0); + assertNotNull(failureFF); + assertEquals("noSuchObject", failureFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + NOT_FOUND_OID + SNMPUtils.SNMP_PROP_DELIMITER + "128")); + assertEquals("Success", failureFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "errorStatusText")); + } + + } + + private static void registerManagedObjects(final TestAgent agent) { + agent.registerManagedObjects( + DefaultMOFactory.getInstance().createScalar(new OID(READ_ONLY_OID_1), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(READ_ONLY_OID_VALUE_1)), + DefaultMOFactory.getInstance().createScalar(new OID(READ_ONLY_OID_2), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(READ_ONLY_OID_VALUE_2)) + ); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPTest.java index ef6332d2d0..59ccb0f137 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPTest.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/GetSNMPTest.java @@ -16,77 +16,47 @@ */ package org.apache.nifi.snmp.processors; -import org.apache.nifi.snmp.testagents.TestSNMPV1Agent; -import org.apache.nifi.snmp.utils.SNMPUtils; -import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.remote.io.socket.NetworkUtils; +import org.apache.nifi.snmp.helper.testrunners.SNMPV1TestRunnerFactory; +import org.apache.nifi.util.MockProcessSession; +import org.apache.nifi.util.SharedSessionState; import org.apache.nifi.util.TestRunner; -import org.apache.nifi.util.TestRunners; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.snmp4j.agent.mo.DefaultMOFactory; -import org.snmp4j.agent.mo.MOAccessImpl; -import org.snmp4j.smi.OID; -import org.snmp4j.smi.OctetString; -import java.io.IOException; +import java.util.concurrent.atomic.AtomicLong; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; public class GetSNMPTest { - private static TestSNMPV1Agent snmpV1Agent; - private static final OID readOnlyOID1 = new OID("1.3.6.1.4.1.32437.1.5.1.4.2.0"); - private static final OID readOnlyOID2 = new OID("1.3.6.1.4.1.32437.1.5.1.4.3.0"); - private static final String OIDValue1 = "TestOID1"; - private static final String OIDValue2 = "TestOID2"; - private static final String GET = "GET"; - private static final String WALK = "WALK"; + private static final String OID = "1.3.6.1.4.1.32437.1.5.1.4.2.0"; - @BeforeAll - public static void setUp() throws IOException { - snmpV1Agent = new TestSNMPV1Agent("127.0.0.1"); - snmpV1Agent.start(); - snmpV1Agent.registerManagedObjects( - DefaultMOFactory.getInstance().createScalar(new OID(readOnlyOID1), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(OIDValue1)), - DefaultMOFactory.getInstance().createScalar(new OID(readOnlyOID2), MOAccessImpl.ACCESS_READ_ONLY, new OctetString(OIDValue2)) - ); - } + @Test + public void testOnTriggerWithGetStrategyPerformsSnmpGet() { + final TestRunner getSnmpTestRunner = new SNMPV1TestRunnerFactory().createSnmpGetTestRunner(NetworkUtils.availablePort(), OID, "GET"); + final GetSNMP spyGetSNMP = spy((GetSNMP) getSnmpTestRunner.getProcessor()); + final MockProcessSession mockProcessSession = new MockProcessSession(new SharedSessionState(spyGetSNMP, new AtomicLong(0L)), spyGetSNMP); - @AfterAll - public static void tearDown() { - snmpV1Agent.stop(); + doNothing().when(spyGetSNMP).performSnmpGet(any(), any(), any(), any()); + + spyGetSNMP.onTrigger(getSnmpTestRunner.getProcessContext(), mockProcessSession); + + verify(spyGetSNMP).performSnmpGet(any(), any(), any(), any()); } @Test - public void testSnmpV1Get() { - final TestRunner runner = getTestRunner(readOnlyOID1.toString(), String.valueOf(snmpV1Agent.getPort()), GET); - runner.run(); - final MockFlowFile successFF = runner.getFlowFilesForRelationship(GetSNMP.REL_SUCCESS).get(0); - assertNotNull(successFF); - assertEquals(OIDValue1, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + readOnlyOID1.toString() + SNMPUtils.SNMP_PROP_DELIMITER + "4")); - } + public void testOnTriggerWithWalkStrategyPerformsSnmpWalk() { + final TestRunner getSnmpTestRunner = new SNMPV1TestRunnerFactory().createSnmpGetTestRunner(NetworkUtils.availablePort(), OID, "WALK"); + final GetSNMP spyGetSNMP = spy((GetSNMP) getSnmpTestRunner.getProcessor()); + final MockProcessSession mockProcessSession = new MockProcessSession(new SharedSessionState(spyGetSNMP, new AtomicLong(0L)), spyGetSNMP); - @Test - public void testSnmpV1Walk() { - final TestRunner runner = getTestRunner("1.3.6.1.4.1.32437", String.valueOf(snmpV1Agent.getPort()), WALK); - runner.run(); - final MockFlowFile successFF = runner.getFlowFilesForRelationship(GetSNMP.REL_SUCCESS).get(0); - assertNotNull(successFF); - assertEquals(OIDValue1, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + readOnlyOID1.toString() + SNMPUtils.SNMP_PROP_DELIMITER + "4")); - assertEquals(OIDValue2, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + readOnlyOID2.toString() + SNMPUtils.SNMP_PROP_DELIMITER + "4")); - } + doNothing().when(spyGetSNMP).performSnmpWalk(any(), any(), any(), any()); - private TestRunner getTestRunner(final String oid, final String port, final String strategy) { - final TestRunner runner = TestRunners.newTestRunner(GetSNMP.class); - runner.setProperty(GetSNMP.OID, oid); - runner.setProperty(GetSNMP.AGENT_HOST, "127.0.0.1"); - runner.setProperty(GetSNMP.AGENT_PORT, port); - runner.setProperty(GetSNMP.SNMP_COMMUNITY, "public"); - runner.setProperty(GetSNMP.SNMP_VERSION, "SNMPv1"); - runner.setProperty(GetSNMP.SNMP_STRATEGY, strategy); - runner.setProperty(GetSNMP.SNMP_SECURITY_LEVEL, "noAuthNoPriv"); - return runner; + spyGetSNMP.onTrigger(getSnmpTestRunner.getProcessContext(), mockProcessSession); + + verify(spyGetSNMP).performSnmpWalk(any(), any(), any(), any()); } } diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPIntegrationTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPIntegrationTest.java new file mode 100644 index 0000000000..d96a4f4dda --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPIntegrationTest.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors; + +import org.apache.nifi.snmp.helper.testrunners.SNMPTestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV1TestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV2cTestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV3TestRunnerFactory; +import org.apache.nifi.snmp.testagents.TestAgent; +import org.apache.nifi.snmp.testagents.TestSNMPV1Agent; +import org.apache.nifi.snmp.testagents.TestSNMPV2cAgent; +import org.apache.nifi.snmp.testagents.TestSNMPV3Agent; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.snmp4j.agent.mo.DefaultMOFactory; +import org.snmp4j.agent.mo.MOAccessImpl; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.OctetString; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(Parameterized.class) +public class SetSNMPIntegrationTest { + + private static final String LOCALHOST = "127.0.0.1"; + private static final String TEST_OID = "1.3.6.1.4.1.32437.1.5.1.4.2.0"; + private static final String TEST_OID_VALUE = "TestOID"; + + private static final SNMPTestRunnerFactory v1TestRunnerFactory = new SNMPV1TestRunnerFactory(); + private static final SNMPTestRunnerFactory v2cTestRunnerFactory = new SNMPV2cTestRunnerFactory(); + private static final SNMPTestRunnerFactory v3TestRunnerFactory = new SNMPV3TestRunnerFactory(); + + private static final TestAgent v1TestAgent = new TestSNMPV1Agent(LOCALHOST); + private static final TestAgent v2cTestAgent = new TestSNMPV2cAgent(LOCALHOST); + private static final TestAgent v3TestAgent = new TestSNMPV3Agent(LOCALHOST); + + static { + registerManagedObjects(v1TestAgent); + registerManagedObjects(v2cTestAgent); + registerManagedObjects(v3TestAgent); + } + + @Parameterized.Parameters + public static Collection data() { + return Arrays.asList(new Object[][]{ + {v1TestAgent, v1TestRunnerFactory}, + {v2cTestAgent, v2cTestRunnerFactory}, + {v3TestAgent, v3TestRunnerFactory} + }); + } + + private final TestAgent testAgent; + private final SNMPTestRunnerFactory testRunnerFactory; + + public SetSNMPIntegrationTest(final TestAgent testAgent, final SNMPTestRunnerFactory testRunnerFactory) { + this.testAgent = testAgent; + this.testRunnerFactory = testRunnerFactory; + } + + @Before + public void setUp() throws IOException { + testAgent.start(); + } + + @After + public void tearDown() { + testAgent.stop(); + testAgent.unregister(); + } + + + @Test + public void testSnmpSet() { + final TestRunner runner = testRunnerFactory.createSnmpSetTestRunner(testAgent.getPort(), TEST_OID, TEST_OID_VALUE); + runner.run(); + final MockFlowFile successFF = runner.getFlowFilesForRelationship(SetSNMP.REL_SUCCESS).get(0); + + assertNotNull(successFF); + assertEquals(TEST_OID_VALUE, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + TEST_OID + SNMPUtils.SNMP_PROP_DELIMITER + "4")); + } + + private static void registerManagedObjects(final TestAgent agent) { + agent.registerManagedObjects( + DefaultMOFactory.getInstance().createScalar(new OID(TEST_OID), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(TEST_OID_VALUE)) + ); + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPTest.java deleted file mode 100644 index 0e9f96700b..0000000000 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/SetSNMPTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.snmp.processors; - -import org.apache.nifi.snmp.testagents.TestSNMPV1Agent; -import org.apache.nifi.snmp.utils.SNMPUtils; -import org.apache.nifi.util.MockFlowFile; -import org.apache.nifi.util.TestRunner; -import org.apache.nifi.util.TestRunners; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.snmp4j.agent.mo.DefaultMOFactory; -import org.snmp4j.agent.mo.MOAccessImpl; -import org.snmp4j.smi.OID; -import org.snmp4j.smi.OctetString; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class SetSNMPTest { - - private static TestSNMPV1Agent snmpV1Agent; - private static final OID TEST_OID = new OID("1.3.6.1.4.1.32437.1.5.1.4.2.0"); - private static final String TEST_OID_VALUE = "TestOID"; - private static final String LOCALHOST = "127.0.0.1"; - private static final String VALID_OID_FF_ATTRIBUTE = "snmp$1.3.6.1.4.1.32437.1.5.1.4.2.0$4"; - private static final String INVALID_OID_FF_ATTRIBUTE = "snmp$1.3.6.1.4.1.32437.1.5.1.4.213.0$4"; - - @BeforeAll - public static void setUp() throws IOException { - snmpV1Agent = new TestSNMPV1Agent("127.0.0.1"); - snmpV1Agent.start(); - snmpV1Agent.registerManagedObjects( - DefaultMOFactory.getInstance().createScalar(new OID(TEST_OID), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(TEST_OID_VALUE)) - ); - } - - @AfterAll - public static void tearDown() { - snmpV1Agent.stop(); - } - - @Test - public void testSnmpV1Set() { - final TestRunner runner = getTestRunner(LOCALHOST, String.valueOf(snmpV1Agent.getPort()), VALID_OID_FF_ATTRIBUTE, true); - runner.run(); - final MockFlowFile successFF = runner.getFlowFilesForRelationship(SetSNMP.REL_SUCCESS).get(0); - assertNotNull(successFF); - assertEquals(TEST_OID_VALUE, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + TEST_OID.toString() + SNMPUtils.SNMP_PROP_DELIMITER + "4")); - } - - private TestRunner getTestRunner(final String host, final String port, final String oid, final boolean withAttributes) { - final SetSNMP processor = new SetSNMP(); - final TestRunner runner = TestRunners.newTestRunner(processor); - final MockFlowFile ff = new MockFlowFile(123); - if (withAttributes) { - final Map attributes = ff.getAttributes(); - final Map newAttributes = new HashMap<>(attributes); - newAttributes.put(oid, TEST_OID_VALUE); - ff.putAttributes(newAttributes); - } - runner.enqueue(ff); - runner.setProperty(GetSNMP.AGENT_HOST, host); - runner.setProperty(GetSNMP.AGENT_PORT, port); - runner.setProperty(GetSNMP.SNMP_COMMUNITY, "public"); - runner.setProperty(GetSNMP.SNMP_VERSION, "SNMPv1"); - return runner; - } -} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/TrapSNMPIntegrationTest.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/TrapSNMPIntegrationTest.java new file mode 100644 index 0000000000..b5b0f6246e --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/processors/TrapSNMPIntegrationTest.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.nifi.snmp.processors; + +import org.apache.nifi.remote.io.socket.NetworkUtils; +import org.apache.nifi.snmp.configuration.V1TrapConfiguration; +import org.apache.nifi.snmp.configuration.V2TrapConfiguration; +import org.apache.nifi.snmp.helper.TrapConfigurationFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPTestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV1TestRunnerFactory; +import org.apache.nifi.snmp.helper.testrunners.SNMPV2cTestRunnerFactory; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.junit.Ignore; +import org.junit.Test; +import org.snmp4j.mp.SnmpConstants; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class TrapSNMPIntegrationTest { + + protected static final String SYSTEM_DESCRIPTION_OID = "1.3.6.1.2.1.1.1.0"; + protected static final String SYSTEM_DESCRIPTION_OID_VALUE = "optionalTrapOidTestValue"; + + @Test + public void testSendReceiveV1Trap() throws InterruptedException { + final int listenPort = NetworkUtils.availablePort(); + + final V1TrapConfiguration v1TrapConfiguration = TrapConfigurationFactory.getV1TrapConfiguration(); + final SNMPTestRunnerFactory v1TestRunnerFactory = new SNMPV1TestRunnerFactory(); + + final TestRunner sendTrapTestRunner = v1TestRunnerFactory.createSnmpSendTrapTestRunner(listenPort, SYSTEM_DESCRIPTION_OID, SYSTEM_DESCRIPTION_OID_VALUE); + final TestRunner listenTrapTestRunner = v1TestRunnerFactory.createSnmpListenTrapTestRunner(listenPort); + + listenTrapTestRunner.run(1, false); + sendTrapTestRunner.run(1); + + Thread.sleep(50); + + final MockFlowFile successFF = listenTrapTestRunner.getFlowFilesForRelationship(GetSNMP.REL_SUCCESS).get(0); + + assertNotNull(successFF); + assertEquals("Success", successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "errorStatusText")); + + assertEquals(v1TrapConfiguration.getEnterpriseOid(), successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "enterprise")); + assertEquals(v1TrapConfiguration.getAgentAddress(), successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "agentAddress")); + assertEquals(String.valueOf(v1TrapConfiguration.getGenericTrapType()), successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "genericTrapType")); + assertEquals(String.valueOf(v1TrapConfiguration.getSpecificTrapType()), successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "specificTrapType")); + + + assertEquals(SYSTEM_DESCRIPTION_OID_VALUE, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + SYSTEM_DESCRIPTION_OID + + SNMPUtils.SNMP_PROP_DELIMITER + "4")); + + listenTrapTestRunner.shutdown(); + } + + @Test + public void testSendReceiveV2Trap() throws InterruptedException { + final int listenPort = NetworkUtils.availablePort(); + + final V2TrapConfiguration v2TrapConfiguration = TrapConfigurationFactory.getV2TrapConfiguration(); + final SNMPTestRunnerFactory v2cTestRunnerFactory = new SNMPV2cTestRunnerFactory(); + + final TestRunner sendTrapTestRunner = v2cTestRunnerFactory.createSnmpSendTrapTestRunner(listenPort, SYSTEM_DESCRIPTION_OID, SYSTEM_DESCRIPTION_OID_VALUE); + final TestRunner listenTrapTestRunner = v2cTestRunnerFactory.createSnmpListenTrapTestRunner(listenPort); + + listenTrapTestRunner.run(1, false); + sendTrapTestRunner.run(1); + + Thread.sleep(50); + + final MockFlowFile successFF = listenTrapTestRunner.getFlowFilesForRelationship(GetSNMP.REL_SUCCESS).get(0); + + assertNotNull(successFF); + assertEquals("Success", successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + "errorStatusText")); + + assertEquals(v2TrapConfiguration.getTrapOidValue(), successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + SnmpConstants.snmpTrapOID + + SNMPUtils.SNMP_PROP_DELIMITER + "4")); + + assertEquals(SYSTEM_DESCRIPTION_OID_VALUE, successFF.getAttribute(SNMPUtils.SNMP_PROP_PREFIX + SYSTEM_DESCRIPTION_OID + + SNMPUtils.SNMP_PROP_DELIMITER + "4")); + + listenTrapTestRunner.shutdown(); + } + + @Ignore("The ListenTrapSNMP and SendTrapSNMP processors use the same SecurityProtocols instance" + + " and same USM (the USM is stored in a map by version), hence this case shall be manually tested." + + " Check assertByVersion() to see what the trap payload must contain.") + @Test + public void testReceiveV3Trap() { + } +} diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/testagents/TestAgent.java b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/testagents/TestAgent.java index 06ad0b32a0..9d05190140 100644 --- a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/testagents/TestAgent.java +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/testagents/TestAgent.java @@ -53,6 +53,11 @@ public abstract class TestAgent extends BaseAgent { this.address = String.format("udp:%s/%d", host, port); } + public void unregister() { + unregisterSnmpMIBs(); + snmpMpdMib.unregisterMOs(server, getContext(snmpMpdMib)); + } + @Override protected void initTransportMappings() { transportMappings = new TransportMapping[1]; diff --git a/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json new file mode 100644 index 0000000000..b6ce71a154 --- /dev/null +++ b/nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/resources/users.json @@ -0,0 +1,16 @@ +[ + { + "securityName":"user1", + "authProtocol":"MD5", + "authPassphrase":"abc12345", + "privProtocol":"DES", + "privPassphrase":"abc12345" + }, + { + "securityName":"newUser2", + "authProtocol":"MD5", + "authPassphrase":"abc12345", + "privProtocol":"AES256", + "privPassphrase":"abc12345" + } +] \ No newline at end of file