tpalfy commented on a change in pull request #5088: URL: https://github.com/apache/nifi/pull/5088#discussion_r681710094
########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/properties/BasicProperties.java ########## @@ -0,0 +1,74 @@ +/* + * 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.mp.SnmpConstants; + +public class BasicProperties { + + public static final AllowableValue SNMP_V1 = new AllowableValue(String.valueOf(SnmpConstants.version1), "v1", "SNMP version 1"); + public static final AllowableValue SNMP_V2C = new AllowableValue(String.valueOf(SnmpConstants.version2c), "v2c", "SNMP version 2c"); + public static final AllowableValue SNMP_V3 = new AllowableValue(String.valueOf(SnmpConstants.version3), "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 milliseconds) when requesting the SNMP Agent.") + .required(false) + .defaultValue("5000") + .addValidator(StandardValidators.NON_NEGATIVE_INTEGER_VALIDATOR) + .build(); Review comment: ```suggestion public static final PropertyDescriptor SNMP_TIMEOUT = new PropertyDescriptor.Builder() .name("snmp-timeout") .displayName("Timeout") .description("Set the timeout when requesting the SNMP Agent.") .required(false) .defaultValue("5000 ms") .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) .build(); ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/ListenTrapSNMP.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.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.reporting.InitializationException; +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 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<PropertyDescriptor> 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<Relationship> RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + REL_SUCCESS, + REL_FAILURE + ))); + + private volatile SNMPTrapReceiverHandler snmpTrapReceiverHandler; + + @OnScheduled + public void initSnmpManager(ProcessContext context) throws InitializationException { + final int version = context.getProperty(BasicProperties.SNMP_VERSION).asInteger(); + final int managerPort = context.getProperty(SNMP_MANAGER_PORT).asInteger(); + final String usmUsersFilePath = context.getProperty(SNMP_USM_USERS_FILE_PATH).getValue(); + SNMPConfiguration configuration; + try { + configuration = SNMPConfiguration.builder() + .setManagerPort(managerPort) + .setVersion(version) + .setSecurityLevel(context.getProperty(V3SecurityProperties.SNMP_SECURITY_LEVEL).getValue()) + .setCommunityString(context.getProperty(BasicProperties.SNMP_COMMUNITY).getValue()) + .build(); + } catch (IllegalStateException e) { Review comment: Is there a reason for this `catch`? Don't see how the building of the configuration object can throw an exception. ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/ClientSNMPFactoryTest.java ########## @@ -0,0 +1,69 @@ +/* + * 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.factory.core.SNMPFactoryProvider; +import org.junit.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 ClientSNMPFactoryTest { + + private final SNMPConfiguration.Builder configurationBuilder = SNMPConfiguration.builder() + .setManagerPort(0) + .setTargetHost("1.2.3.4") + .setTargetPort("12345") + .setRetries(1) + .setTimeoutInMs(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 Snmp snmpManager = SNMPFactoryProvider.getFactory(configuration.getVersion()) + .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()))); + } +} Review comment: ```suggestion @Test public void testSnmpV3ClientWithoutCorrespondingAgentDoesNotHaveUSM() { // GIVEN final SNMPConfiguration configuration = SNMPConfiguration.builder() .setSecurityName("userName") .setAuthProtocol("SHA") .setAuthPassphrase("authPassword") .setPrivacyProtocol("DES") .setPrivacyPassphrase("privacyPassword") .setVersion(SnmpConstants.version3) .build(); final UsmUser expected = new UsmUser( new OctetString("userName"), SnmpConstants.usmHMACSHAAuthProtocol, new OctetString("authPassword"), SnmpConstants.usmDESPrivProtocol, new OctetString("privacyPassword") ); // WHEN final Snmp snmpManager = SNMPFactoryProvider.getFactory(configuration.getVersion()) .createSnmpManagerInstance(configuration); // THEN final UsmUser actual = snmpManager.getUSM().getUserTable().getUser(new OctetString("userName")).getUsmUser(); Assert.assertEquals(expected, actual); } ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/trap/V2TrapPDUFactory.java ########## @@ -0,0 +1,49 @@ +/* + * 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.util.function.Supplier; + +public class V2TrapPDUFactory implements Supplier<PDU> { Review comment: Shouldn't this be called `V2cV3TrapConfiguration` instead? ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/AbstractSNMPProcessor.java ########## @@ -117,146 +75,43 @@ .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()); + final int version = context.getProperty(BasicProperties.SNMP_VERSION).asInteger(); final SNMPConfiguration configuration; + final String targetHost = getTargetHost(context); + final String targetPort = getTargetPort(context); 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()) + configuration = SNMPConfiguration.builder() + .setTargetHost(targetHost) + .setTargetPort(targetPort) + .setRetries(context.getProperty(BasicProperties.SNMP_RETRIES).asInteger()) + .setTimeoutInMs(context.getProperty(BasicProperties.SNMP_TIMEOUT).asInteger()) Review comment: ```suggestion .setTimeoutInMs(context.getProperty(BasicProperties.SNMP_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue()) ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/SNMPClientFactoryTest.java ########## @@ -31,11 +31,11 @@ public class SNMPClientFactoryTest { Review comment: This file is basically the same as `ClientSNMPFactoryTest.java`. Seems like we could delete it. ########## File path: 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 (isTrapPdu(pdu)) { + final ProcessSession processSession = processSessionFactory.createSession(); + final FlowFile flowFile = createFlowFile(processSession, pdu); + processSession.getProvenanceReporter().receive(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<String, String> attributes; + if (pdu instanceof PDUv1) { + attributes = SNMPUtils.getV1TrapPduAttributeMap(pdu); Review comment: ```suggestion attributes = SNMPUtils.getV1TrapPduAttributeMap((PDUv1)pdu); ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV2cTestRunnerFactory.java ########## @@ -0,0 +1,88 @@ +/* + * 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.SNMPV2cConfigurationFactory; +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; + +public class SNMPV2cTestRunnerFactory implements SNMPTestRunnerFactory { + + private static final SNMPV2cConfigurationFactory snmpV2ConfigurationFactory = new SNMPV2cConfigurationFactory(); Review comment: ```suggestion private static final SNMPConfigurationFactory snmpV2ConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version2c); ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/utils/SNMPUtils.java ########## @@ -132,12 +122,19 @@ private 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<String, String> getV1TrapPduAttributeMap(final PDU pdu) { + final Map<String, String> trapAttributes = getPduAttributeMap(pdu); + PDUv1 v1TrapPdu = (PDUv1) pdu; Review comment: ```suggestion public static Map<String, String> getV1TrapPduAttributeMap(final PDUv1 v1TrapPdu) { final Map<String, String> trapAttributes = getPduAttributeMap(v1TrapPdu); ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1ConfigurationFactory.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.configurations; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.snmp4j.mp.SnmpConstants; + +public class SNMPV1ConfigurationFactory implements SNMPConfigurationFactory { + + @Override + public SNMPConfiguration createSnmpGetSetConfiguration(final int agentPort) { + return SNMPConfiguration.builder() + .setTargetHost(DEFAULT_HOST) + .setTargetPort(String.valueOf(agentPort)) + .setCommunityString(COMMUNITY_STRING) + .setVersion(SnmpConstants.version1) Review comment: ```suggestion .setVersion(snmpVersion) ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1ConfigurationFactory.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.configurations; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.snmp4j.mp.SnmpConstants; + +public class SNMPV1ConfigurationFactory implements SNMPConfigurationFactory { + Review comment: ```suggestion public class SNMPV1V2cConfigurationFactory implements SNMPConfigurationFactory { private int snmpVersion; public SNMPV1V2cConfigurationFactory(int snmpVersion) { this.snmpVersion = snmpVersion; } ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1ConfigurationFactory.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.configurations; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.snmp4j.mp.SnmpConstants; + +public class SNMPV1ConfigurationFactory implements SNMPConfigurationFactory { + + @Override + public SNMPConfiguration createSnmpGetSetConfiguration(final int agentPort) { + return SNMPConfiguration.builder() + .setTargetHost(DEFAULT_HOST) + .setTargetPort(String.valueOf(agentPort)) + .setCommunityString(COMMUNITY_STRING) + .setVersion(SnmpConstants.version1) + .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.version1) + .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) + .setCommunityString(COMMUNITY_STRING) + .setVersion(SnmpConstants.version1) Review comment: ```suggestion .setVersion(snmpVersion) ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPRequestTest.java ########## @@ -64,53 +82,210 @@ WALK_OID_MAP = Collections.unmodifiableMap(oidMap); } - protected final TestAgent agent = getAgentInstance(); + private static final SNMPV1ConfigurationFactory snmpv1ConfigurationFactory = new SNMPV1ConfigurationFactory(); + private static final SNMPV2cConfigurationFactory snmpv2cConfigurationFactory = new SNMPV2cConfigurationFactory(); Review comment: ```suggestion private static final SNMPV1V2cConfigurationFactory snmpv1ConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version1); private static final SNMPV1V2cConfigurationFactory snmpv2cConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version2c); ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1ConfigurationFactory.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.configurations; + +import org.apache.nifi.snmp.configuration.SNMPConfiguration; +import org.snmp4j.mp.SnmpConstants; + +public class SNMPV1ConfigurationFactory implements SNMPConfigurationFactory { + + @Override + public SNMPConfiguration createSnmpGetSetConfiguration(final int agentPort) { + return SNMPConfiguration.builder() + .setTargetHost(DEFAULT_HOST) + .setTargetPort(String.valueOf(agentPort)) + .setCommunityString(COMMUNITY_STRING) + .setVersion(SnmpConstants.version1) + .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.version1) Review comment: ```suggestion .setVersion(snmpVersion) ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/operations/SNMPRequestTest.java ########## @@ -64,53 +82,210 @@ WALK_OID_MAP = Collections.unmodifiableMap(oidMap); } - protected final TestAgent agent = getAgentInstance(); + private static final SNMPV1ConfigurationFactory snmpv1ConfigurationFactory = new SNMPV1ConfigurationFactory(); + private static final SNMPV2cConfigurationFactory snmpv2cConfigurationFactory = new SNMPV2cConfigurationFactory(); + private static final SNMPV3ConfigurationFactory snmpv3ConfigurationFactory = new SNMPV3ConfigurationFactory(); + + private static final TestAgent v1TestAgent = new TestSNMPV1Agent(LOCALHOST); + private static final TestAgent v2cTestAgent = new TestSNMPV2cAgent(LOCALHOST); + private static final TestAgent v3TestAgent = new TestSNMPV3Agent(LOCALHOST); - protected abstract TestAgent getAgentInstance(); + 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)) - ); } @After public void tearDown() { agent.stop(); + agent.unregister(); + } + + @Parameterized.Parameters + public static Collection<Object[]> 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} + }); + } + + 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 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"); + @Test + public void testSuccessfulSnmpGet() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + try (final SNMPResourceHandler snmpResourceHandler = SNMPFactoryProvider.getFactory(version) + .createSNMPResourceHandler(snmpConfiguration)) { + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final SNMPSingleResponse response = getSNMPHandler.get(READ_ONLY_OID_1, Collections.emptyMap()); + + assertEquals(READ_ONLY_OID_VALUE_1, response.getVariableBindings().get(0).getVariable()); + assertEquals(SUCCESS, response.getErrorStatusText()); + } + } + + @Test + public void testSuccessfulSnmpGetWithFlowFileInput() throws IOException { + final SNMPConfiguration snmpConfiguration = snmpConfigurationFactory.createSnmpGetSetConfiguration(agent.getPort()); + try (final SNMPResourceHandler snmpResourceHandler = SNMPFactoryProvider.getFactory(version) + .createSNMPResourceHandler(snmpConfiguration)) { + final GetSNMPHandler getSNMPHandler = new GetSNMPHandler(snmpResourceHandler); + final SNMPSingleResponse response = getSNMPHandler.get(null, getFlowFileAttributesForSnmpGet(READ_ONLY_OID_1, READ_ONLY_OID_2)); + + assertEquals(READ_ONLY_OID_VALUE_1, response.getVariableBindings().get(1).getVariable()); + assertEquals(READ_ONLY_OID_VALUE_2, response.getVariableBindings().get(0).getVariable()); + assertEquals(SUCCESS, response.getErrorStatusText()); Review comment: We have a `Map` input and we still rely on an ordered result. I would do try to avoid that. ```suggestion Set<String> expectedVariables = new HashSet<>(Arrays.asList(READ_ONLY_OID_VALUE_1, READ_ONLY_OID_VALUE_2)); Set<String> actualVariables = response.getVariableBindings().stream().map(SNMPValue::getVariable).collect(Collectors.toSet()); assertEquals(expectedVariables, actualVariables); assertEquals(SUCCESS, response.getErrorStatusText()); ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/GetSNMP.java ########## @@ -134,59 +141,77 @@ REL_FAILURE ))); + private volatile GetSNMPHandler snmpHandler; + + @OnScheduled + public void init(final ProcessContext context) throws InitializationException { + 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 Optional<FlowFile> flowfile = Optional.ofNullable(processSession.get()); + Map<String, String> flowFileAttributes = flowfile.map(FlowFile::getAttributes).orElse(Collections.emptyMap()); if (SNMPStrategy.GET == snmpStrategy) { - performSnmpGet(context, processSession, oid); + performSnmpGet(context, processSession, oid, flowFileAttributes); } else if (SNMPStrategy.WALK == snmpStrategy) { - performSnmpWalk(context, processSession, oid); + performSnmpWalk(context, processSession, oid, flowFileAttributes); } } - private void performSnmpWalk(final ProcessContext context, final ProcessSession processSession, final String oid) { + private void performSnmpWalk(final ProcessContext context, final ProcessSession processSession, final String oid, + final Map<String, String> flowFileAttributes) { try { - final SNMPTreeResponse response = snmpRequestHandler.walk(oid); + final SNMPTreeResponse response = snmpHandler.walk(oid, flowFileAttributes); response.logErrors(getLogger()); FlowFile flowFile = createFlowFileWithTreeEventProperties(response, processSession); processSession.getProvenanceReporter().receive(flowFile, response.getTargetAddress() + "/" + oid); processSession.transfer(flowFile, REL_SUCCESS); } catch (SNMPWalkException e) { getLogger().error(e.getMessage()); context.yield(); - processSession.rollback(); } } - private void performSnmpGet(final ProcessContext context, final ProcessSession processSession, final String oid) { + private void performSnmpGet(final ProcessContext context, final ProcessSession processSession, final String oid, + final Map<String, String> flowFileAttributes) { final SNMPSingleResponse response; try { - response = snmpRequestHandler.get(oid); + response = snmpHandler.get(oid, flowFileAttributes); final FlowFile flowFile = processSession.create(); addAttribute(SNMPUtils.SNMP_PROP_PREFIX + "textualOid", context.getProperty(TEXTUAL_OID).getValue(), flowFile, processSession); final String provenanceAddress = response.getTargetAddress() + "/" + oid; Review comment: Is this going to be okay even if we are getting OIDs from the flowfiles and not from the property? ```java final String provenanceAddress = response.getTargetAddress() + "/" + oid; ``` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPV1TestRunnerFactory.java ########## @@ -0,0 +1,92 @@ +/* + * 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.SNMPV1ConfigurationFactory; +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; + +public class SNMPV1TestRunnerFactory implements SNMPTestRunnerFactory { + + + private static final SNMPV1ConfigurationFactory snmpv1ConfigurationFactory = new SNMPV1ConfigurationFactory(); Review comment: ```suggestion private static final SNMPV1V2cConfigurationFactory snmpv1ConfigurationFactory = new SNMPV1V2cConfigurationFactory(SnmpConstants.version1); ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
