/* * 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 java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.nifi.annotation.behavior.InputRequirement; import org.apache.nifi.annotation.behavior.InputRequirement.Requirement; import org.apache.nifi.annotation.behavior.WritesAttribute; import org.apache.nifi.annotation.behavior.WritesAttributes; import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.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.Processor; import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.processor.exception.ProcessException; import org.snmp4j.PDU; import org.snmp4j.event.ResponseEvent; import org.snmp4j.smi.OID; import org.snmp4j.util.TreeEvent; /** * Retrieving data from configured SNMP agent which, upon each invocation of * {@link #onTrigger(ProcessContext, ProcessSession)} method, will construct a * {@link FlowFile} containing in its properties the information retrieved. * The output {@link FlowFile} won't have any content. */ @Tags({ "snmp", "get", "oid", "walk" }) @InputRequirement(Requirement.INPUT_FORBIDDEN) @CapabilityDescription("Retrieves information from SNMP Agent and outputs a FlowFile with information in attributes and without any content") @WritesAttributes({ @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"), @WritesAttribute(attribute=SNMPUtils.SNMP_PROP_PREFIX + "textualOid", description="This attribute will exist if and only if the strategy" + " is GET and will be equal to the value given in Textual Oid property.") }) public class GetSNMP extends AbstractSNMPProcessor<SNMPGetter> { /** OID to request (if walk, it is the root ID of the request) */ public static final PropertyDescriptor OID = new PropertyDescriptor.Builder() .name("snmp-oid") .displayName("OID") .description("The OID to request") .required(true) .addValidator(SNMPUtils.SNMP_OID_VALIDATOR) .build(); /** Textual OID to request */ public static final PropertyDescriptor TEXTUAL_OID = new PropertyDescriptor.Builder() .name("snmp-textual-oid") .displayName("Textual OID") .description("The textual OID to request") .required(false) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .defaultValue(null) .build(); /** SNMP strategy for SNMP Get processor : simple get or walk */ public static final PropertyDescriptor SNMP_STRATEGY = new PropertyDescriptor.Builder() .name("snmp-strategy") .displayName("SNMP strategy (GET/WALK)") .description("SNMP strategy to use (SNMP Get or SNMP Walk)") .required(true) .allowableValues("GET", "WALK") .defaultValue("GET") .build(); /** relationship for success */ 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(); /** relationship for failure */ 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(); /** list of property descriptors */ private final static List<PropertyDescriptor> propertyDescriptors; /** list of relationships */ private final static Set<Relationship> relationships; /* * Will ensure that the list of property descriptors is build only once. * Will also create a Set of relationships */ static { List<PropertyDescriptor> _propertyDescriptors = new ArrayList<>(); _propertyDescriptors.add(OID); _propertyDescriptors.add(TEXTUAL_OID); _propertyDescriptors.add(SNMP_STRATEGY); _propertyDescriptors.addAll(descriptors); propertyDescriptors = Collections.unmodifiableList(_propertyDescriptors); Set<Relationship> _relationships = new HashSet<>(); _relationships.add(REL_SUCCESS); _relationships.add(REL_FAILURE); relationships = Collections.unmodifiableSet(_relationships); } /** * Delegate method to supplement * {@link #onTrigger(ProcessContext, ProcessSession)}. It is implemented by * sub-classes to perform {@link Processor} specific functionality. * * @param context * instance of {@link ProcessContext} * @param processSession * instance of {@link ProcessSession} * @throws ProcessException Process exception */ @Override protected void onTriggerSnmp(ProcessContext context, ProcessSession processSession) throws ProcessException { if("GET".equals(context.getProperty(SNMP_STRATEGY).getValue())) { final ResponseEvent response = this.targetResource.get(); if (response.getResponse() != null){ FlowFile flowFile = processSession.create(); PDU pdu = response.getResponse(); flowFile = SNMPUtils.updateFlowFileAttributesWithPduProperties(pdu, flowFile, processSession); flowFile = SNMPUtils.addAttribute(SNMPUtils.SNMP_PROP_PREFIX + "textualOid", context.getProperty(TEXTUAL_OID).getValue(), flowFile, processSession); processSession.getProvenanceReporter().receive(flowFile, this.snmpTarget.getAddress().toString() + "/" + context.getProperty(OID).getValue()); if(pdu.getErrorStatus() == PDU.noError) { processSession.transfer(flowFile, REL_SUCCESS); } else { processSession.transfer(flowFile, REL_FAILURE); } } else { this.getLogger().error("Get request timed out or parameters are incorrect."); context.yield(); } } else if("WALK".equals(context.getProperty(SNMP_STRATEGY).getValue())) { final List<TreeEvent> events = this.targetResource.walk(); if((events != null) && !events.isEmpty() && (events.get(0).getVariableBindings() != null)) { FlowFile flowFile = processSession.create(); for (TreeEvent treeEvent : events) { flowFile = SNMPUtils.updateFlowFileAttributesWithTreeEventProperties(treeEvent, flowFile, processSession); } processSession.getProvenanceReporter().receive(flowFile, this.snmpTarget.getAddress().toString() + "/" + context.getProperty(OID).getValue()); processSession.transfer(flowFile, REL_SUCCESS); } else { this.getLogger().error("Get request timed out or parameters are incorrect."); context.yield(); } } } /** * Will create an instance of {@link SNMPGetter} */ @Override protected SNMPGetter finishBuildingTargetResource(ProcessContext context) { String oid = context.getProperty(OID).getValue(); return new SNMPGetter(this.snmp, this.snmpTarget, new OID(oid)); } /** * get list of supported property descriptors */ @Override protected List<PropertyDescriptor> getSupportedPropertyDescriptors() { return propertyDescriptors; } /** * get list of relationships */ @Override public Set<Relationship> getRelationships() { return relationships; } }