simonbence commented on a change in pull request #5088: URL: https://github.com/apache/nifi/pull/5088#discussion_r662050885
########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/TrapConfiguration.java ########## @@ -0,0 +1,38 @@ +/* + * 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 interface TrapConfiguration { Review comment: Please provide JavaDOC ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/TrapV2cV3Configuration.java ########## @@ -0,0 +1,63 @@ +/* + * 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 TrapV2cV3Configuration implements TrapConfiguration { + + private final String trapOidValue; + private final int sysUpTime; + + public TrapV2cV3Configuration(final String trapOidValue, final int sysUpTime) { + this.trapOidValue = trapOidValue; + this.sysUpTime = sysUpTime; + } + + @Override + public String getTrapOidValue() { + return trapOidValue; + } + + @Override + public int getSysUpTime() { + return sysUpTime; + } + + @Override + public String getEnterpriseOid() { + throw new UnsupportedOperationException("Enterprise OID is SNMPv1 specific property."); Review comment: This looks a pretty unlucky way to approach. If there are such a differences between the different versions, it would be better to avoid shared interface (or at least not using a facade interface tries to cover all) ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfiguration.java ########## @@ -104,4 +111,95 @@ public String getSecurityLevel() { public String getCommunityString() { return communityString; } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String managerPort = "0"; + private String targetHost; + private String targetPort; + private int retries; + private int timeout = 500; + 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 String 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 setTimeout(final int timeout) { + this.timeout = timeout; + 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() { Review comment: Is not any validation necessary? For example: is there any mandatory value must be set before building? ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/TrapV1Configuration.java ########## @@ -0,0 +1,111 @@ +/* + * 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 com.google.common.base.Preconditions; + +public final class TrapV1Configuration implements TrapConfiguration { + + private final String enterpriseOid; + private final String agentAddress; + private final int genericTrapType; + private final Integer specificTrapType; + private final int timeStamp; + + public TrapV1Configuration(final Builder builder) { Review comment: As this is highly coupled with the builder, it would be better to make this private ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/CompositeSNMPFactory.java ########## @@ -20,51 +20,40 @@ import org.apache.nifi.snmp.exception.InvalidSnmpVersionException; import org.snmp4j.Snmp; import org.snmp4j.Target; +import org.snmp4j.mp.SnmpConstants; -import java.util.Arrays; import java.util.Collections; -import java.util.List; +import java.util.HashMap; +import java.util.Map; 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<SNMPFactory> FACTORIES; + private static final Map<Integer, SNMPFactory> FACTORIES; static { - final List<SNMPFactory> factories = Arrays.asList(new V1SNMPFactory(), new V2cSNMPFactory(), new V3SNMPFactory()); - FACTORIES = Collections.unmodifiableList(factories); - } - - @Override - public boolean supports(final int version) { - return !getMatchingFactory(version).isPresent(); + final Map<Integer, SNMPFactory> factories = new HashMap<>(); + factories.put(SnmpConstants.version1, new V1SNMPFactory()); + factories.put(SnmpConstants.version2c, new V2cSNMPFactory()); + factories.put(SnmpConstants.version3, new V3SNMPFactory()); + FACTORIES = Collections.unmodifiableMap(factories); } @Override public Snmp createSnmpManagerInstance(final SNMPConfiguration configuration) { - final Optional<SNMPFactory> factory = getMatchingFactory(configuration.getVersion()); - if (!factory.isPresent()) { - throw new InvalidSnmpVersionException(INVALID_SNMP_VERSION); - } - return factory.get().createSnmpManagerInstance(configuration); + final SNMPFactory factory = getMatchingFactory(configuration.getVersion()); + return factory.createSnmpManagerInstance(configuration); } @Override - public Target createTargetInstance(final SNMPConfiguration configuration) { - final Optional<SNMPFactory> factory = getMatchingFactory(configuration.getVersion()); - if (!factory.isPresent()) { - throw new InvalidSnmpVersionException(INVALID_SNMP_VERSION); - } - return factory.get().createTargetInstance(configuration); + public Target createTargetInstance(SNMPConfiguration configuration) { Review comment: Please be consistent with the usage of "final" on the method arguments. Other methods have them, so please follow the local pattern ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/ListenTrapSNMPFactory.java ########## @@ -0,0 +1,35 @@ +/* + * 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.snmp4j.Snmp; +import org.snmp4j.Target; + +public class ListenTrapSNMPFactory extends AbstractSNMPFactory implements SNMPFactory { Review comment: As the `SNMPFactory` implementations are distinguished by version, this is kind of strange. Especially the this makes me wonder which version the `ListenTrap` is from? ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/TrapV2cV3Configuration.java ########## @@ -0,0 +1,63 @@ +/* + * 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 TrapV2cV3Configuration implements TrapConfiguration { + + private final String trapOidValue; + private final int sysUpTime; + + public TrapV2cV3Configuration(final String trapOidValue, final int sysUpTime) { Review comment: It's minor, but I see some asymmetry with this: TrapV1 uses a builder and this is being called directly. I would propose an approach like: use a builder without version and when you create the actual config, version specific builder methods might work well ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/StandardSNMPRequestHandler.java ########## @@ -44,9 +46,19 @@ final class StandardSNMPRequestHandler implements SNMPRequestHandler { + private 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. "; + + private static final String REQUEST_TIMEOUT_EXCEPTION_TEMPLATE = "Request timed out. Please check if (1). the " + Review comment: "Please check" might not be the luckiest phrasing. Maybe "Usually the following things might cause this" ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfiguration.java ########## @@ -104,4 +111,95 @@ public String getSecurityLevel() { public String getCommunityString() { return communityString; } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String managerPort = "0"; + private String targetHost; + private String targetPort; + private int retries; + private int timeout = 500; Review comment: Please incorporate the unit, for example "timeoutInMs" ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/TrapConfiguration.java ########## @@ -0,0 +1,38 @@ +/* + * 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 interface TrapConfiguration { + + // SNMPv1 specific + String getEnterpriseOid(); Review comment: If it is specific to SNMPv1, would it be possible to separate it from the generic methods? (child interface or such a thing) - Especially that implementations are version specific ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/SNMPConfiguration.java ########## @@ -104,4 +111,95 @@ public String getSecurityLevel() { public String getCommunityString() { return communityString; } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + private String managerPort = "0"; Review comment: I might move the value to a constant with a name like "WILDCARD_PORT" or something communicates the intention ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/TrapV1Configuration.java ########## @@ -0,0 +1,111 @@ +/* + * 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 com.google.common.base.Preconditions; + +public final class TrapV1Configuration implements TrapConfiguration { + + private final String enterpriseOid; + private final String agentAddress; + private final int genericTrapType; + private final Integer specificTrapType; + private final int timeStamp; + + public TrapV1Configuration(final Builder builder) { + Preconditions.checkNotNull(builder.enterpiseOid); Review comment: I think, these checks might be better in the `build()` method (as this is the only constructor). ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/AbstractSNMPFactory.java ########## @@ -35,22 +35,24 @@ public abstract class AbstractSNMPFactory { private static final Logger logger = LoggerFactory.getLogger(AbstractSNMPFactory.class); + private static final String LOCALHOST = "127.0.0.1"; protected AbstractSNMPFactory() { // hide implicit constructor } - protected static Snmp createSnmpClient() { - final Snmp snmp; + protected static Snmp createSimpleSnmpManager(SNMPConfiguration configuration) { + final String managerAddress = LOCALHOST + "/" + configuration.getManagerPort(); + final Snmp snmpManager; try { - snmp = new Snmp(new DefaultUdpTransportMapping()); - snmp.listen(); - return snmp; + snmpManager = new Snmp(new DefaultUdpTransportMapping(new UdpAddress(managerAddress))); + snmpManager.listen(); } catch (IOException e) { - final String errorMessage = "Creating SNMP client failed."; + final String errorMessage = "Creating SNMP manager failed."; logger.error(errorMessage, e); throw new CreateSNMPClientException(errorMessage); Review comment: You swallow the original exception by doing this. Please pass `e` as an argument of the thrown exception. I would think, the best would be passing `e` _instead_ of the message because the message itself does not provide additional information over the type of the exception. (And by doing that you can spare the error message local variable as well) ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPRequestHandlerFactory.java ########## @@ -26,9 +26,9 @@ public static SNMPRequestHandler createStandardRequestHandler(final SNMPConfiguration configuration) { final SNMPFactory snmpFactory = new CompositeSNMPFactory(); - final Snmp snmpClient = snmpFactory.createSnmpManagerInstance(configuration); + final Snmp snmpManager = snmpFactory.createSnmpManagerInstance(configuration); Review comment: As this used exclusively in `AbstractSNMPProcessor`, would not it make sense to reorganise and move this code into a method within it? ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/factory/CompositeSNMPFactory.java ########## @@ -20,51 +20,40 @@ import org.apache.nifi.snmp.exception.InvalidSnmpVersionException; import org.snmp4j.Snmp; import org.snmp4j.Target; +import org.snmp4j.mp.SnmpConstants; -import java.util.Arrays; import java.util.Collections; -import java.util.List; +import java.util.HashMap; +import java.util.Map; 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<SNMPFactory> FACTORIES; + private static final Map<Integer, SNMPFactory> FACTORIES; static { - final List<SNMPFactory> factories = Arrays.asList(new V1SNMPFactory(), new V2cSNMPFactory(), new V3SNMPFactory()); - FACTORIES = Collections.unmodifiableList(factories); - } - - @Override - public boolean supports(final int version) { - return !getMatchingFactory(version).isPresent(); + final Map<Integer, SNMPFactory> factories = new HashMap<>(); + factories.put(SnmpConstants.version1, new V1SNMPFactory()); + factories.put(SnmpConstants.version2c, new V2cSNMPFactory()); + factories.put(SnmpConstants.version3, new V3SNMPFactory()); + FACTORIES = Collections.unmodifiableMap(factories); } @Override public Snmp createSnmpManagerInstance(final SNMPConfiguration configuration) { - final Optional<SNMPFactory> factory = getMatchingFactory(configuration.getVersion()); - if (!factory.isPresent()) { - throw new InvalidSnmpVersionException(INVALID_SNMP_VERSION); - } - return factory.get().createSnmpManagerInstance(configuration); + final SNMPFactory factory = getMatchingFactory(configuration.getVersion()); + return factory.createSnmpManagerInstance(configuration); } @Override - public Target createTargetInstance(final SNMPConfiguration configuration) { - final Optional<SNMPFactory> factory = getMatchingFactory(configuration.getVersion()); - if (!factory.isPresent()) { - throw new InvalidSnmpVersionException(INVALID_SNMP_VERSION); - } - return factory.get().createTargetInstance(configuration); + public Target createTargetInstance(SNMPConfiguration configuration) { + final SNMPFactory factory = getMatchingFactory(configuration.getVersion()); + return factory.createTargetInstance(configuration); } - private Optional<SNMPFactory> getMatchingFactory(final int version) { - for (final SNMPFactory factory : FACTORIES) { - if (factory.supports(version)) { - return Optional.of(factory); - } - } - return Optional.empty(); + private SNMPFactory getMatchingFactory(final int version) { + return Optional.ofNullable(FACTORIES.get(version)) + .orElseThrow(() -> new InvalidSnmpVersionException(INVALID_SNMP_VERSION)); Review comment: It would be good to include the actual version argument into the exception's message ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java ########## @@ -0,0 +1,269 @@ +/* + * 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.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; +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.TrapConfiguration; +import org.apache.nifi.snmp.configuration.TrapV1Configuration; +import org.apache.nifi.snmp.configuration.TrapV2cV3Configuration; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.mp.SnmpConstants; + +import java.io.IOException; +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, 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(InputRequirement.Requirement.INPUT_FORBIDDEN) +@CapabilityDescription("Sends information to SNMP Manager.") +public class SendTrapSNMP extends AbstractSNMPProcessor { + + public static final AllowableValue GENERIC_TRAP_TYPE_0 = new AllowableValue("0", "Cold Start", Review comment: As nothing else uses these please make them `private`. Also, some more descriptive name would make readability better. Something like `GENERAIC_TRAP_WARM_START`. ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/operations/SNMPTrapReceiverHandler.java ########## @@ -0,0 +1,106 @@ +/* + * 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.alibaba.fastjson.JSON; +import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.processor.ProcessContext; +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.exception.CloseSNMPManagerException; +import org.apache.nifi.snmp.factory.ListenTrapSNMPFactory; +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(StandardSNMPRequestHandler.class); Review comment: Log should be for `SNMPTrapReceiverHandler` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java ########## @@ -0,0 +1,269 @@ +/* + * 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.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; +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.TrapConfiguration; +import org.apache.nifi.snmp.configuration.TrapV1Configuration; +import org.apache.nifi.snmp.configuration.TrapV2cV3Configuration; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.mp.SnmpConstants; + +import java.io.IOException; +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, 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(InputRequirement.Requirement.INPUT_FORBIDDEN) +@CapabilityDescription("Sends information to SNMP Manager.") +public class SendTrapSNMP extends AbstractSNMPProcessor { + + public static final AllowableValue GENERIC_TRAP_TYPE_0 = new AllowableValue("0", "Cold Start", + "A coldStart trap signifies that the sending protocol entity is reinitializing itself such that" + + " the agent's configuration or the protocol entity implementation may be altered."); + + public static final AllowableValue GENERIC_TRAP_TYPE_1 = new AllowableValue("1", "Warm Start", + "A warmStart trap signifies that the sending protocol entity is reinitializing itself such that" + + " neither the agent configuration nor the protocol entity implementation is altered."); + + public static final AllowableValue GENERIC_TRAP_TYPE_2 = new AllowableValue("2", "Link Down", + "A linkDown trap signifies that the sending protocol entity recognizes a failure in one of " + + "the communication links represented in the agent's configuration."); + + public static final AllowableValue GENERIC_TRAP_TYPE_3 = new AllowableValue("3", "Link Up", + "A linkUp trap signifies that the sending protocol entity recognizes that one of the communication " + + "links represented in the agent's configuration has come up."); + + public static final AllowableValue GENERIC_TRAP_TYPE_4 = new AllowableValue("4", "Authentication Failure", + "An authenticationFailure trap signifies that the sending protocol entity is the addressee of a " + + "protocol message that is not properly authenticated. While implementations of the SNMP must be " + + "capable of generating this trap, they must also be capable of suppressing the emission of such traps " + + "via an implementation- specific mechanism."); + + public static final AllowableValue GENERIC_TRAP_TYPE_5 = new AllowableValue("5", "EGP Neighbor Loss", + "An egpNeighborLoss trap signifies that an EGP neighbor for whom the sending protocol entity was " + + "an EGP peer has been marked down and the peer relationship no longer obtains."); + + public static final AllowableValue GENERIC_TRAP_TYPE_6 = 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 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(); + + // SNMPv1 TRAP PROPERTIES + + 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) + .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) + .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 Usage for details.") + .required(true) + .allowableValues(GENERIC_TRAP_TYPE_0, GENERIC_TRAP_TYPE_1, GENERIC_TRAP_TYPE_2, GENERIC_TRAP_TYPE_3, + GENERIC_TRAP_TYPE_4, GENERIC_TRAP_TYPE_5, GENERIC_TRAP_TYPE_6) + .addValidator(StandardValidators.createLongValidator(0, 6, true)) + .dependsOn(SNMP_VERSION, SNMP_V1) + .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) + .dependsOn(GENERIC_TRAP_TYPE, GENERIC_TRAP_TYPE_6) + .build(); + + public static final PropertyDescriptor TIME_STAMP = new PropertyDescriptor.Builder() + .name("snmp-trap-timestamp") + .displayName("Timestamp") + .description("Timestamp of the trap (unit: 0.01 second).") + .required(true) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V1) + .build(); + + // SNMPv2c/v3 TRAP PROPERTIES + + 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(false) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V2C, SNMP_V3) + .build(); + + public static final PropertyDescriptor SYSTEM_UPTIME = new PropertyDescriptor.Builder() + .name("snmp-trap-sysuptime") + .displayName("System Uptime") + .description("System uptime of the trap (unit: 0.01 second)") + .required(true) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V2C, SNMP_V3) + .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_HOST, + SNMP_MANAGER_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, + ENTERPRISE_OID, + AGENT_ADDRESS, + GENERIC_TRAP_TYPE, + SPECIFIC_TRAP_TYPE, + TIME_STAMP, + TRAP_OID_VALUE, + SYSTEM_UPTIME + )); + + private static final Set<Relationship> RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + REL_SUCCESS, + REL_FAILURE + ))); + + private volatile TrapConfiguration trapConfiguration; + + @OnScheduled + public void init(ProcessContext context) throws InitializationException { + initSnmpManager(context); + final int snmpVersion = SNMPUtils.getVersion(context.getProperty(SNMP_VERSION).getValue()); + if (SnmpConstants.version1 == snmpVersion) { + trapConfiguration = TrapV1Configuration.builder() + .enterpriseOid(context.getProperty(ENTERPRISE_OID).getValue()) + .agentAddress(context.getProperty(AGENT_ADDRESS).getValue()) + .genericTrapType(context.getProperty(GENERIC_TRAP_TYPE).asInteger()) + .specificTrapType(context.getProperty(SPECIFIC_TRAP_TYPE).asInteger()) + .timeStamp(context.getProperty(TIME_STAMP).asInteger()) + .build(); + } else { + trapConfiguration = new TrapV2cV3Configuration( + context.getProperty(TRAP_OID_VALUE).getValue(), + context.getProperty(SYSTEM_UPTIME).asInteger() + ); + } + } + + @Override + public void onTrigger(final ProcessContext context, final ProcessSession processSession) { + final FlowFile flowFile = processSession.get(); + try { + snmpRequestHandler.sendTrap(trapConfiguration, flowFile); + if (flowFile != null) { + processSession.remove(flowFile); Review comment: Are you sure about that the file needs to be removed? Why not depend on "Automatically Terminate Relationships"? ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/testrunners/SNMPTestRunners.java ########## @@ -0,0 +1,44 @@ +/* + * 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; Review comment: I think the same applies here as above: the downside of adding a lot of util classes into the tests (like a lot of boilerplate, extra abstractions and fragmented tests) overweights the benefits. ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java ########## @@ -0,0 +1,269 @@ +/* + * 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.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; +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.TrapConfiguration; +import org.apache.nifi.snmp.configuration.TrapV1Configuration; +import org.apache.nifi.snmp.configuration.TrapV2cV3Configuration; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.mp.SnmpConstants; + +import java.io.IOException; +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, 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(InputRequirement.Requirement.INPUT_FORBIDDEN) +@CapabilityDescription("Sends information to SNMP Manager.") +public class SendTrapSNMP extends AbstractSNMPProcessor { + + public static final AllowableValue GENERIC_TRAP_TYPE_0 = new AllowableValue("0", "Cold Start", + "A coldStart trap signifies that the sending protocol entity is reinitializing itself such that" + + " the agent's configuration or the protocol entity implementation may be altered."); + + public static final AllowableValue GENERIC_TRAP_TYPE_1 = new AllowableValue("1", "Warm Start", + "A warmStart trap signifies that the sending protocol entity is reinitializing itself such that" + + " neither the agent configuration nor the protocol entity implementation is altered."); + + public static final AllowableValue GENERIC_TRAP_TYPE_2 = new AllowableValue("2", "Link Down", + "A linkDown trap signifies that the sending protocol entity recognizes a failure in one of " + + "the communication links represented in the agent's configuration."); + + public static final AllowableValue GENERIC_TRAP_TYPE_3 = new AllowableValue("3", "Link Up", + "A linkUp trap signifies that the sending protocol entity recognizes that one of the communication " + + "links represented in the agent's configuration has come up."); + + public static final AllowableValue GENERIC_TRAP_TYPE_4 = new AllowableValue("4", "Authentication Failure", + "An authenticationFailure trap signifies that the sending protocol entity is the addressee of a " + + "protocol message that is not properly authenticated. While implementations of the SNMP must be " + + "capable of generating this trap, they must also be capable of suppressing the emission of such traps " + + "via an implementation- specific mechanism."); + + public static final AllowableValue GENERIC_TRAP_TYPE_5 = new AllowableValue("5", "EGP Neighbor Loss", + "An egpNeighborLoss trap signifies that an EGP neighbor for whom the sending protocol entity was " + + "an EGP peer has been marked down and the peer relationship no longer obtains."); + + public static final AllowableValue GENERIC_TRAP_TYPE_6 = 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 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(); + + // SNMPv1 TRAP PROPERTIES + + 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) + .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) + .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 Usage for details.") + .required(true) + .allowableValues(GENERIC_TRAP_TYPE_0, GENERIC_TRAP_TYPE_1, GENERIC_TRAP_TYPE_2, GENERIC_TRAP_TYPE_3, + GENERIC_TRAP_TYPE_4, GENERIC_TRAP_TYPE_5, GENERIC_TRAP_TYPE_6) + .addValidator(StandardValidators.createLongValidator(0, 6, true)) + .dependsOn(SNMP_VERSION, SNMP_V1) + .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) + .dependsOn(GENERIC_TRAP_TYPE, GENERIC_TRAP_TYPE_6) + .build(); + + public static final PropertyDescriptor TIME_STAMP = new PropertyDescriptor.Builder() + .name("snmp-trap-timestamp") + .displayName("Timestamp") + .description("Timestamp of the trap (unit: 0.01 second).") + .required(true) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V1) + .build(); + + // SNMPv2c/v3 TRAP PROPERTIES + + 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(false) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V2C, SNMP_V3) + .build(); + + public static final PropertyDescriptor SYSTEM_UPTIME = new PropertyDescriptor.Builder() + .name("snmp-trap-sysuptime") + .displayName("System Uptime") + .description("System uptime of the trap (unit: 0.01 second)") + .required(true) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V2C, SNMP_V3) + .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_HOST, + SNMP_MANAGER_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, + ENTERPRISE_OID, + AGENT_ADDRESS, + GENERIC_TRAP_TYPE, + SPECIFIC_TRAP_TYPE, + TIME_STAMP, + TRAP_OID_VALUE, + SYSTEM_UPTIME + )); + + private static final Set<Relationship> RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + REL_SUCCESS, Review comment: I did not find any usage for `REL_SUCCESS` ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/configurations/SNMPV1Configurations.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 SNMPV1Configurations implements SNMPConfigurations { Review comment: I think, there is too much util class for testing. Would not it be possible to move the code into the relevant tests? My reasoning: - The tests become too fragmented and because of this: hard to read - As I see, most of the calls are used at one place, which does not reason extracting in a test - The SNMPConfigurations abstraction is implemented in such a ways that V1... etc are used in the respected test file (V1... etc) only, thus the abstraction is not really provides benefit ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/configuration/TrapV2cV3Configuration.java ########## @@ -0,0 +1,63 @@ +/* + * 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 TrapV2cV3Configuration implements TrapConfiguration { + + private final String trapOidValue; + private final int sysUpTime; + + public TrapV2cV3Configuration(final String trapOidValue, final int sysUpTime) { Review comment: I would propose to separate V2 and V3. With the current usage, they should work identical, but this might not be the case in longer term. And separating them later will come with more headache. This level of code duplication, when the equality might be momentarily is not necessary a bad thing. ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/main/java/org/apache/nifi/snmp/processors/SendTrapSNMP.java ########## @@ -0,0 +1,269 @@ +/* + * 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.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; +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.TrapConfiguration; +import org.apache.nifi.snmp.configuration.TrapV1Configuration; +import org.apache.nifi.snmp.configuration.TrapV2cV3Configuration; +import org.apache.nifi.snmp.utils.SNMPUtils; +import org.snmp4j.mp.SnmpConstants; + +import java.io.IOException; +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, 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(InputRequirement.Requirement.INPUT_FORBIDDEN) +@CapabilityDescription("Sends information to SNMP Manager.") +public class SendTrapSNMP extends AbstractSNMPProcessor { + + public static final AllowableValue GENERIC_TRAP_TYPE_0 = new AllowableValue("0", "Cold Start", + "A coldStart trap signifies that the sending protocol entity is reinitializing itself such that" + + " the agent's configuration or the protocol entity implementation may be altered."); + + public static final AllowableValue GENERIC_TRAP_TYPE_1 = new AllowableValue("1", "Warm Start", + "A warmStart trap signifies that the sending protocol entity is reinitializing itself such that" + + " neither the agent configuration nor the protocol entity implementation is altered."); + + public static final AllowableValue GENERIC_TRAP_TYPE_2 = new AllowableValue("2", "Link Down", + "A linkDown trap signifies that the sending protocol entity recognizes a failure in one of " + + "the communication links represented in the agent's configuration."); + + public static final AllowableValue GENERIC_TRAP_TYPE_3 = new AllowableValue("3", "Link Up", + "A linkUp trap signifies that the sending protocol entity recognizes that one of the communication " + + "links represented in the agent's configuration has come up."); + + public static final AllowableValue GENERIC_TRAP_TYPE_4 = new AllowableValue("4", "Authentication Failure", + "An authenticationFailure trap signifies that the sending protocol entity is the addressee of a " + + "protocol message that is not properly authenticated. While implementations of the SNMP must be " + + "capable of generating this trap, they must also be capable of suppressing the emission of such traps " + + "via an implementation- specific mechanism."); + + public static final AllowableValue GENERIC_TRAP_TYPE_5 = new AllowableValue("5", "EGP Neighbor Loss", + "An egpNeighborLoss trap signifies that an EGP neighbor for whom the sending protocol entity was " + + "an EGP peer has been marked down and the peer relationship no longer obtains."); + + public static final AllowableValue GENERIC_TRAP_TYPE_6 = 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 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(); + + // SNMPv1 TRAP PROPERTIES + + 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) + .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) + .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 Usage for details.") + .required(true) + .allowableValues(GENERIC_TRAP_TYPE_0, GENERIC_TRAP_TYPE_1, GENERIC_TRAP_TYPE_2, GENERIC_TRAP_TYPE_3, + GENERIC_TRAP_TYPE_4, GENERIC_TRAP_TYPE_5, GENERIC_TRAP_TYPE_6) + .addValidator(StandardValidators.createLongValidator(0, 6, true)) + .dependsOn(SNMP_VERSION, SNMP_V1) + .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) + .dependsOn(GENERIC_TRAP_TYPE, GENERIC_TRAP_TYPE_6) + .build(); + + public static final PropertyDescriptor TIME_STAMP = new PropertyDescriptor.Builder() + .name("snmp-trap-timestamp") + .displayName("Timestamp") + .description("Timestamp of the trap (unit: 0.01 second).") + .required(true) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .dependsOn(SNMP_VERSION, SNMP_V1) + .build(); + + // SNMPv2c/v3 TRAP PROPERTIES Review comment: It might be a solution to avoid the comment by grouping the properties into collections like `PROPERTIES_V1` and like and use these when building `PROPERTY_DESCRIPTORS`. I am not sure however if this grouping will effect the property ordering negatively. ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/helper/SNMPTestUtils.java ########## @@ -16,53 +16,33 @@ */ 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 org.apache.nifi.snmp.exception.InvalidSnmpVersionException; +import org.apache.nifi.util.MockFlowFile; +import org.snmp4j.mp.SnmpConstants; -import java.io.IOException; +import java.util.HashMap; +import java.util.Map; -public class SNMPTestUtils { - - public static Snmp createSnmpClient() throws IOException { - final DefaultUdpTransportMapping transportMapping = new DefaultUdpTransportMapping(); - transportMapping.listen(); - return new Snmp(transportMapping); - } +import static org.apache.nifi.snmp.utils.SNMPUtils.SNMP_PROP_PREFIX; - 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 class SNMPTestUtils { - 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 String getVersionByInt(int version) { + if (SnmpConstants.version1 == version) { Review comment: Is not there a build-in SNMP support for such a conversion? ########## File path: nifi-nar-bundles/nifi-snmp-bundle/nifi-snmp-processors/src/test/java/org/apache/nifi/snmp/factory/SNMPFactoryTest.java ########## @@ -0,0 +1,68 @@ +/* + * 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.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 SNMPFactoryTest { + + private final SNMPConfiguration.Builder configurationBuilder = SNMPConfiguration.builder() + .setManagerPort("0") + .setTargetHost("1.2.3.4") Review comment: Minor: a realistic value would be better (this is true for port as well) -- 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: issues-unsubscr...@nifi.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org