ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jonathanhur...@apache.org
Subject ambari git commit: AMBARI-8251 - Alerts: SNMP Target for Notifications (Yurii Shylov via jonathanhurley)
Date Tue, 23 Dec 2014 18:32:40 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk c5cb5a16b -> 3603ce63f


AMBARI-8251 - Alerts: SNMP Target for Notifications (Yurii Shylov via jonathanhurley)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/3603ce63
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/3603ce63
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/3603ce63

Branch: refs/heads/trunk
Commit: 3603ce63fcf3c8c3e31b893790dd029803d7cf26
Parents: c5cb5a1
Author: Jonathan Hurley <jhurley@hortonworks.com>
Authored: Tue Dec 23 13:32:24 2014 -0500
Committer: Jonathan Hurley <jhurley@hortonworks.com>
Committed: Tue Dec 23 13:32:24 2014 -0500

----------------------------------------------------------------------
 ambari-server/pom.xml                           |   5 +
 .../server/notifications/DispatchFactory.java   |   4 +-
 .../dispatchers/SNMPDispatcher.java             | 335 +++++++++++++++++
 .../dispatchers/SNMPDispatcherTest.java         | 370 +++++++++++++++++++
 4 files changed, 713 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3603ce63/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 56de3dd..f2cbdad 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -1739,6 +1739,11 @@
       <artifactId>smtp</artifactId>
       <version>1.5.2</version>
     </dependency>
+    <dependency>
+      <groupId>org.snmp4j</groupId>
+      <artifactId>snmp4j</artifactId>
+      <version>1.10.1</version>
+    </dependency>
   </dependencies>
 
   <pluginRepositories>

http://git-wip-us.apache.org/repos/asf/ambari/blob/3603ce63/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
index e690e76..2675533 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/DispatchFactory.java
@@ -25,6 +25,7 @@ import org.apache.ambari.server.notifications.dispatchers.EmailDispatcher;
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Singleton;
+import org.apache.ambari.server.notifications.dispatchers.SNMPDispatcher;
 
 /**
  * The {@link DispatchFactory} is used to provide singleton instances of
@@ -45,8 +46,9 @@ public class DispatchFactory {
   @Inject
   public DispatchFactory(Injector injector) {
     EmailDispatcher emailDispatcher = injector.getInstance(EmailDispatcher.class);
-
+    SNMPDispatcher snmpDispatcher = injector.getInstance(SNMPDispatcher.class);
     m_dispatchers.put(emailDispatcher.getType(), emailDispatcher);
+    m_dispatchers.put(snmpDispatcher.getType(), snmpDispatcher);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/3603ce63/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcher.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcher.java
b/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcher.java
new file mode 100644
index 0000000..0e75801
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcher.java
@@ -0,0 +1,335 @@
+/**
+ * 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.ambari.server.notifications.dispatchers;
+
+import com.google.inject.Singleton;
+import org.apache.ambari.server.notifications.Notification;
+import org.apache.ambari.server.notifications.NotificationDispatcher;
+import org.apache.ambari.server.notifications.Recipient;
+import org.apache.ambari.server.state.alert.TargetType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.snmp4j.CommunityTarget;
+import org.snmp4j.PDU;
+import org.snmp4j.Snmp;
+import org.snmp4j.Target;
+import org.snmp4j.UserTarget;
+import org.snmp4j.mp.MPv3;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.security.AuthMD5;
+import org.snmp4j.security.PrivDES;
+import org.snmp4j.security.SecurityLevel;
+import org.snmp4j.security.SecurityModel;
+import org.snmp4j.security.SecurityModels;
+import org.snmp4j.security.SecurityProtocols;
+import org.snmp4j.security.USM;
+import org.snmp4j.security.UsmUser;
+import org.snmp4j.smi.OID;
+import org.snmp4j.smi.OctetString;
+import org.snmp4j.smi.UdpAddress;
+import org.snmp4j.smi.VariableBinding;
+import org.snmp4j.transport.DefaultUdpTransportMapping;
+import org.snmp4j.util.DefaultPDUFactory;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The {@link SNMPDispatcher} class is used to dispatch {@link Notification} via SNMP.
+ */
+@Singleton
+public class SNMPDispatcher implements NotificationDispatcher {
+
+  private static final Logger LOG = LoggerFactory.getLogger(SNMPDispatcher.class);
+
+  // Trap's object identifiers
+  public static final String BODY_OID_PROPERTY = "ambari.dispatch.snmp.oids.body";
+  public static final String SUBJECT_OID_PROPERTY = "ambari.dispatch.snmp.oids.subject";
+  public static final String TRAP_OID_PROPERTY = "ambari.dispatch.snmp.oids.trap";
+
+  // SNMP Server port
+  public static final String PORT_PROPERTY = "ambari.dispatch.snmp.port";
+
+  // SNMP version
+  public static final String SNMP_VERSION_PROPERTY = "ambari.dispatch.snmp.version";
+
+  // Properties for community-based security model configuration
+  public static final String COMMUNITY_PROPERTY = "ambari.dispatch.snmp.community";
+
+  // Properties for user-based security model configuration
+  public static final String SECURITY_USERNAME_PROPERTY = "ambari.dispatch.snmp.security.username";
+  public static final String SECURITY_AUTH_PASSPHRASE_PROPERTY = "ambari.dispatch.snmp.security.auth.passphrase";
+  public static final String SECURITY_PRIV_PASSPHRASE_PROPERTY = "ambari.dispatch.snmp.security.priv.passphrase";
+  public static final String SECURITY_LEVEL_PROPERTY = "ambari.dispatch.snmp.security.level";
+
+  private Snmp snmp;
+
+  public SNMPDispatcher(Snmp snmp) {
+    this.snmp = snmp;
+  }
+
+  public SNMPDispatcher() throws IOException {
+    this(new Snmp(new DefaultUdpTransportMapping()));
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getType() {
+    return TargetType.SNMP.name();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void dispatch(Notification notification) {
+    LOG.info("Sending SNMP trap: {}", notification.Subject);
+    try {
+      snmp = new Snmp(new DefaultUdpTransportMapping());
+      SnmpVersion snmpVersion = getSnmpVersion(notification);
+      sendTraps(notification, snmpVersion);
+      successCallback(notification);
+    } catch (InvalidSnmpConfigurationException ex) {
+      LOG.error("Unable to dispatch SNMP trap with invalid configuration. " + ex.getMessage());
+      failureCallback(notification);
+    } catch (Exception ex) {
+      LOG.error("Error occurred during SNMP trap dispatching.", ex);
+      failureCallback(notification);
+    }
+  }
+
+  /**
+   * Creates protocol data unit (PDU) with corresponding SNMP version for alert notification.
+   * @param notification alert notification to dispatch
+   * @param snmpVersion SNMP version
+   * @return PDU containing notification info
+   * @throws InvalidSnmpConfigurationException if notification's dispatch properties don't
contain any of required properties.
+   */
+  protected PDU prepareTrap(Notification notification, SnmpVersion snmpVersion) throws InvalidSnmpConfigurationException
{
+    PDU pdu = DefaultPDUFactory.createPDU(snmpVersion.getTargetVersion());
+    pdu.setType(snmpVersion.getTrapType());
+    // Set trap oid for PDU
+    pdu.add(new VariableBinding(SnmpConstants.snmpTrapOID, new OID(getDispatchProperty(notification,
TRAP_OID_PROPERTY))));
+    // Set notification body and subject for PDU objects with identifiers specified in dispatch
properties.
+    pdu.add(new VariableBinding(new OID(getDispatchProperty(notification, BODY_OID_PROPERTY)),
new OctetString(notification.Body)));
+    pdu.add(new VariableBinding(new OID(getDispatchProperty(notification, SUBJECT_OID_PROPERTY)),
new OctetString(notification.Subject)));
+    return pdu;
+  }
+
+  /**
+   * Creates trap based on alerts notification and sends it to hosts specified in recipients
list.
+   * @param notification alert notification to dispatch
+   * @param snmpVersion SNMP version
+   * @throws InvalidSnmpConfigurationException if notification's dispatch properties don't
contain any of required properties or recipient list is empty.
+   * @throws IOException if the SNMP trap could not be sent
+   */
+  protected void sendTraps(Notification notification, SnmpVersion snmpVersion) throws InvalidSnmpConfigurationException,
IOException {
+    PDU trap = prepareTrap(notification, snmpVersion);
+    String udpPort = getDispatchProperty(notification, PORT_PROPERTY);
+    for (Recipient recipient : getNotificationRecipients(notification)) {
+      String address = recipient.Identifier;
+      Target target = createTrapTarget(notification, snmpVersion);
+      target.setAddress(new UdpAddress(address + "/" + udpPort));
+      snmp.send(trap, target);
+    }
+  }
+
+  /**
+   * Creates snmp target with security model corresponding to snmp version.
+   * @param notification alerts notification
+   * @param snmpVersion SNMP version
+   * @return target with corresponding security model
+   * @throws InvalidSnmpConfigurationException if notification's dispatch properties don't
contain any of required properties
+   */
+  protected Target createTrapTarget(Notification notification, SnmpVersion snmpVersion) throws
InvalidSnmpConfigurationException {
+    if (snmpVersion.isCommunityTargetRequired()) {
+      OctetString community = new OctetString(getDispatchProperty(notification, COMMUNITY_PROPERTY));
+      CommunityTarget communityTarget = new CommunityTarget();
+      communityTarget.setCommunity(community);
+      communityTarget.setVersion(snmpVersion.getTargetVersion());
+      return communityTarget;
+    } else {
+      OctetString userName = new OctetString(getDispatchProperty(notification, SECURITY_USERNAME_PROPERTY));
+      if (snmp.getUSM() == null) {
+        // provide User-based Security Model (USM) with user specified
+        USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()),
0);
+        // authPassphraseProperty and privPassphraseProperty can be null for NoAuthNoPriv
security level
+        String authPassphraseProperty = notification.DispatchProperties.get(SECURITY_AUTH_PASSPHRASE_PROPERTY);
+        String privPassphraseProperty = notification.DispatchProperties.get(SECURITY_PRIV_PASSPHRASE_PROPERTY);
+        OctetString authPassphrase = authPassphraseProperty != null ? new OctetString(authPassphraseProperty)
: null;
+        OctetString privPassphrase = privPassphraseProperty != null ? new OctetString(privPassphraseProperty)
: null;
+        UsmUser usmUser = new UsmUser(userName, AuthMD5.ID, authPassphrase, PrivDES.ID, privPassphrase);
+        usm.addUser(userName, usmUser);
+        SecurityModels.getInstance().addSecurityModel(usm);
+      }
+      UserTarget userTarget = new UserTarget();
+      userTarget.setSecurityName(userName);
+      userTarget.setSecurityLevel(getSecurityLevel(notification).getSecurityLevel());
+      userTarget.setSecurityModel(SecurityModel.SECURITY_MODEL_USM);
+      userTarget.setVersion(snmpVersion.getTargetVersion());
+      return userTarget;
+    }
+  }
+
+  /**
+   * Possible SNMP security levels
+   */
+  protected enum TrapSecurity {
+
+    /**
+     * No password authentication and the communications between the agent and the server
are not encrypted.
+     */
+    NOAUTH_NOPRIV(SecurityLevel.NOAUTH_NOPRIV),
+    /**
+     * Password authentication is hash based and no encryption is used for communications
between the hosts.
+     */
+    AUTH_NOPRIV(SecurityLevel.AUTH_NOPRIV),
+    /**
+     * Password authentication is hash based and the communications between the agent and
the server are also encrypted.
+     */
+    AUTH_PRIV(SecurityLevel.AUTH_PRIV);
+
+    int securityLevel;
+
+    TrapSecurity(int securityLevel) {
+      this.securityLevel = securityLevel;
+    }
+
+    public int getSecurityLevel() {
+      return securityLevel;
+    }
+  }
+
+  /**
+   * Supported versions of SNMP
+   */
+  protected enum SnmpVersion {
+
+    SNMPv1(PDU.V1TRAP, SnmpConstants.version1, true),
+    SNMPv2c(PDU.TRAP, SnmpConstants.version2c, true),
+    SNMPv3(PDU.TRAP, SnmpConstants.version3, false);
+
+    private int trapType;
+    private int targetVersion;
+    private boolean communityTargetRequired;
+
+    SnmpVersion(int trapType, int targetVersion, boolean communityTargetRequired) {
+      this.trapType = trapType;
+      this.targetVersion = targetVersion;
+      this.communityTargetRequired = communityTargetRequired;
+    }
+
+    public int getTrapType() {
+      return trapType;
+    }
+
+    public int getTargetVersion() {
+      return targetVersion;
+    }
+
+    public boolean isCommunityTargetRequired() {
+      return communityTargetRequired;
+    }
+  }
+
+  /**
+   * Exception thrown when Notification configuration doesn't contain required properties.
+   */
+  protected static class InvalidSnmpConfigurationException extends Exception {
+
+    public InvalidSnmpConfigurationException(String message) {
+      super(message);
+    }
+  }
+
+  /**
+   * Get list of recipients for notification
+   * @param notification alerts notification
+   * @return list of recipients
+   * @throws InvalidSnmpConfigurationException if recipients is <code>null</code>
or empty
+   */
+  private List<Recipient> getNotificationRecipients(Notification notification) throws
InvalidSnmpConfigurationException {
+    if (notification.Recipients == null || notification.Recipients.isEmpty()) {
+      throw new InvalidSnmpConfigurationException("Destination addresses should be set.");
+    }
+    return notification.Recipients;
+  }
+
+  /**
+   * Get dispatch property with specific key from notification.
+   * @param notification alerts notification
+   * @param key property key
+   * @return property value
+   * @throws InvalidSnmpConfigurationException if property with such key does not exist
+   */
+  private static String getDispatchProperty(Notification notification, String key) throws
InvalidSnmpConfigurationException {
+    if (notification.DispatchProperties == null || !notification.DispatchProperties.containsKey(key))
{
+      throw new InvalidSnmpConfigurationException(String.format("Property \"%s\" should be
set.", key));
+    }
+    return notification.DispatchProperties.get(key);
+  }
+
+  /**
+   * Returns {@link SnmpVersion} instance corresponding to dispatch property <code>ambari.dispatch.snmp.version</code>
from notification.
+   * @param notification alerts notification
+   * @return corresponding SnmpVersion instance
+   * @throws InvalidSnmpConfigurationException if dispatch properties doesn't contain required
property
+   */
+  private SnmpVersion getSnmpVersion(Notification notification) throws InvalidSnmpConfigurationException
{
+    String snmpVersion = getDispatchProperty(notification, SNMP_VERSION_PROPERTY);
+    try {
+      return SnmpVersion.valueOf(snmpVersion);
+    } catch (IllegalArgumentException ex) {
+      String errorMessage = String.format("Incorrect SNMP version - \"%s\". Possible values
for \"%s\": %s",
+          snmpVersion, SNMP_VERSION_PROPERTY, Arrays.toString(SnmpVersion.values()));
+      throw new InvalidSnmpConfigurationException(errorMessage);
+    }
+  }
+
+  /**
+   * Returns {@link TrapSecurity} instance corresponding to dispatch property <code>ambari.dispatch.snmp.security.level</code>
from notification.
+   * @param notification alerts notification
+   * @return corresponding TrapSecurity instance
+   * @throws InvalidSnmpConfigurationException if dispatch properties doesn't contain required
property
+   */
+  private TrapSecurity getSecurityLevel(Notification notification) throws InvalidSnmpConfigurationException
{
+    String securityLevel = getDispatchProperty(notification, SECURITY_LEVEL_PROPERTY);
+    try {
+      return TrapSecurity.valueOf(securityLevel);
+    } catch (IllegalArgumentException ex) {
+      String errorMessage = String.format("Incorrect security level for trap - \"%s\". Possible
values for \"%s\": %s",
+          securityLevel, SECURITY_LEVEL_PROPERTY, Arrays.toString(TrapSecurity.values()));
+      throw new InvalidSnmpConfigurationException(errorMessage);
+    }
+  }
+
+  private void failureCallback(Notification notification) {
+    if (notification.Callback != null) {
+      notification.Callback.onFailure(notification.CallbackIds);
+    }
+  }
+
+  private void successCallback(Notification notification) {
+    if (notification.Callback != null) {
+      notification.Callback.onSuccess(notification.CallbackIds);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/3603ce63/ambari-server/src/test/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcherTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcherTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcherTest.java
new file mode 100644
index 0000000..db4af1c
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/notifications/dispatchers/SNMPDispatcherTest.java
@@ -0,0 +1,370 @@
+/**
+ * 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.ambari.server.notifications.dispatchers;
+
+import org.apache.ambari.server.notifications.DispatchCallback;
+import org.apache.ambari.server.notifications.Notification;
+import org.apache.ambari.server.notifications.Recipient;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.snmp4j.PDU;
+import org.snmp4j.Snmp;
+import org.snmp4j.Target;
+import org.snmp4j.mp.SnmpConstants;
+import org.snmp4j.smi.VariableBinding;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class SNMPDispatcherTest {
+
+  @Test
+  public void testDispatch_nullProperties() throws Exception {
+    SNMPDispatcher dispatcher = new SNMPDispatcher();
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    dispatcher.dispatch(notification);
+    verify(notification.Callback).onFailure(notification.CallbackIds);
+    verify(notification.Callback, never()).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_notDefinedProperties() throws Exception {
+    SNMPDispatcher dispatcher = new SNMPDispatcher();
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    notification.DispatchProperties = new HashMap<String, String>();
+    dispatcher.dispatch(notification);
+    verify(notification.Callback).onFailure(notification.CallbackIds);
+    verify(notification.Callback, never()).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_nullRecipients() throws Exception {
+    SNMPDispatcher dispatcher = new SNMPDispatcher();
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "3");
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "4");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv1");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    dispatcher.dispatch(notification);
+    verify(notification.Callback).onFailure(notification.CallbackIds);
+    verify(notification.Callback, never()).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_noRecipients() throws Exception {
+    SNMPDispatcher dispatcher = new SNMPDispatcher();
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "3");
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "4");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv1");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    notification.Recipients = new ArrayList<Recipient>();
+    dispatcher.dispatch(notification);
+    verify(notification.Callback).onFailure(notification.CallbackIds);
+    verify(notification.Callback, never()).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_sendTrapError() throws Exception {
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher());
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "3");
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "4");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv1");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    notification.Recipients = Arrays.asList(new Recipient());
+    doThrow(new RuntimeException()).when(dispatcher).sendTraps(eq(notification), any(SNMPDispatcher.SnmpVersion.class));
+    dispatcher.dispatch(notification);
+    verify(notification.Callback).onFailure(notification.CallbackIds);
+    verify(notification.Callback, never()).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_incorrectSnmpVersion() throws Exception {
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher());
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "3");
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "4");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv11");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    notification.Recipients = Arrays.asList(new Recipient());
+    dispatcher.dispatch(notification);
+    verify(notification.Callback).onFailure(notification.CallbackIds);
+    verify(notification.Callback, never()).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_successful_v1() throws Exception {
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher());
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv1;
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "3");
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "4");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv1");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    notification.Recipients = Arrays.asList(new Recipient());
+    doNothing().when(dispatcher).sendTraps(notification, snmpVersion);
+    dispatcher.dispatch(notification);
+    verify(notification.Callback, never()).onFailure(notification.CallbackIds);
+    verify(notification.Callback).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_successful_v2() throws Exception {
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher());
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv2c;
+    Notification notification = mock(Notification.class);
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "3");
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "4");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv2c");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    notification.Recipients = Arrays.asList(new Recipient());
+    doNothing().when(dispatcher).sendTraps(notification, snmpVersion);
+    dispatcher.dispatch(notification);
+    verify(notification.Callback, never()).onFailure(notification.CallbackIds);
+    verify(notification.Callback).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testDispatch_successful_v3() throws Exception {
+    SNMPDispatcher dispatcher = new SNMPDispatcher();
+    Notification notification = new Notification();
+    notification.Callback = mock(DispatchCallback.class);
+    notification.CallbackIds = mock(List.class);
+    notification.Body = "body";
+    notification.Subject = "subject";
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "162");
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "public");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv3");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    properties.put(SNMPDispatcher.SECURITY_USERNAME_PROPERTY, "USER");
+    properties.put(SNMPDispatcher.SECURITY_AUTH_PASSPHRASE_PROPERTY, "PASSPHRASE1");
+    properties.put(SNMPDispatcher.SECURITY_PRIV_PASSPHRASE_PROPERTY, "PASSPHRASE2");
+    properties.put(SNMPDispatcher.SECURITY_LEVEL_PROPERTY, "AUTH_NOPRIV");
+    notification.DispatchProperties = properties;
+    Recipient recipient = new Recipient();
+    recipient.Identifier = "192.168.0.2";
+    notification.Recipients = Arrays.asList(recipient);
+    dispatcher.dispatch(notification);
+    verify(notification.Callback, never()).onFailure(notification.CallbackIds);
+    verify(notification.Callback).onSuccess(notification.CallbackIds);
+  }
+
+  @Test
+  public void testPrepareTrap_v1() throws Exception {
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv1;
+    SNMPDispatcher dispatcher = new SNMPDispatcher();
+    Notification notification = new Notification();
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "3");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    PDU pdu = dispatcher.prepareTrap(notification, snmpVersion);
+    assertEquals(PDU.V1TRAP, pdu.getType());
+    Map<String, VariableBinding> variableBindings = new HashMap<String, VariableBinding>();
+    for (VariableBinding variableBinding : pdu.toArray()) {
+      variableBindings.put(variableBinding.getOid().toString(), variableBinding);
+    }
+    assertEquals(3, variableBindings.size());
+    assertEquals("subject", variableBindings.get("1").toValueString());
+    assertEquals("body", variableBindings.get("2").toValueString());
+    assertEquals("3", variableBindings.get(SnmpConstants.snmpTrapOID.toString()).toValueString());
+  }
+
+  @Test
+  public void testPrepareTrap_v2c() throws Exception {
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv2c;
+    SNMPDispatcher dispatcher = new SNMPDispatcher();
+    Notification notification = new Notification();
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.SUBJECT_OID_PROPERTY, "1");
+    properties.put(SNMPDispatcher.BODY_OID_PROPERTY, "2");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "4");
+    notification.DispatchProperties = properties;
+    notification.Body = "body";
+    notification.Subject = "subject";
+    PDU pdu = dispatcher.prepareTrap(notification, snmpVersion);
+    assertEquals(PDU.TRAP, pdu.getType());
+    Map<String, VariableBinding> variableBindings = new HashMap<String, VariableBinding>();
+    for (VariableBinding variableBinding : pdu.toArray()) {
+      variableBindings.put(variableBinding.getOid().toString(), variableBinding);
+    }
+    assertEquals(3, variableBindings.size());
+    assertEquals("subject", variableBindings.get("1").toValueString());
+    assertEquals("body", variableBindings.get("2").toValueString());
+    assertEquals("4", variableBindings.get(SnmpConstants.snmpTrapOID.toString()).toValueString());
+  }
+
+  @Test
+  public void testSendTraps_v1() throws Exception {
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv1;
+    Snmp snmp = mock(Snmp.class);
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher(snmp));
+    PDU trap = mock(PDU.class);
+    Notification notification = new Notification();
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "public");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "162");
+    notification.DispatchProperties = properties;
+    Recipient rec1 = new Recipient();
+    rec1.Identifier = "192.168.0.2";
+    notification.Recipients = Arrays.asList(rec1);
+    doReturn(trap).when(dispatcher).prepareTrap(notification, snmpVersion);
+    dispatcher.sendTraps(notification, snmpVersion);
+    ArgumentCaptor<Target> argument = ArgumentCaptor.forClass(Target.class);
+    verify(snmp, times(1)).send(eq(trap), argument.capture());
+    assertEquals("192.168.0.2/162", argument.getValue().getAddress().toString());
+    assertEquals(SnmpConstants.version1, argument.getValue().getVersion());
+  }
+
+  @Test
+  public void testSendTraps_v2() throws Exception {
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv2c;
+    Snmp snmp = mock(Snmp.class);
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher(snmp));
+    PDU trap = mock(PDU.class);
+    Notification notification = new Notification();
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.COMMUNITY_PROPERTY, "public");
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "162");
+    notification.DispatchProperties = properties;
+    Recipient rec1 = new Recipient();
+    rec1.Identifier = "192.168.0.2";
+    notification.Recipients = Arrays.asList(rec1);
+    doReturn(trap).when(dispatcher).prepareTrap(notification, snmpVersion);
+    dispatcher.sendTraps(notification, snmpVersion);
+    ArgumentCaptor<Target> argument = ArgumentCaptor.forClass(Target.class);
+    verify(snmp, times(1)).send(eq(trap), argument.capture());
+    assertEquals("192.168.0.2/162", argument.getValue().getAddress().toString());
+    assertEquals(SnmpConstants.version2c, argument.getValue().getVersion());
+  }
+
+  @Test
+  public void testSendTraps_v3() throws Exception {
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv3;
+    Snmp snmp = mock(Snmp.class);
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher(snmp));
+    PDU trap = mock(PDU.class);
+    Notification notification = new Notification();
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "162");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv3");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    properties.put(SNMPDispatcher.SECURITY_USERNAME_PROPERTY, "USER");
+    properties.put(SNMPDispatcher.SECURITY_AUTH_PASSPHRASE_PROPERTY, "PASSPHRASE1");
+    properties.put(SNMPDispatcher.SECURITY_PRIV_PASSPHRASE_PROPERTY, "PASSPHRASE2");
+    properties.put(SNMPDispatcher.SECURITY_LEVEL_PROPERTY, "AUTH_NOPRIV");
+    notification.DispatchProperties = properties;
+    Recipient rec1 = new Recipient();
+    rec1.Identifier = "192.168.0.2";
+    notification.Recipients = Arrays.asList(rec1);
+    doReturn(trap).when(dispatcher).prepareTrap(notification, snmpVersion);
+    dispatcher.sendTraps(notification, snmpVersion);
+    ArgumentCaptor<Target> argument = ArgumentCaptor.forClass(Target.class);
+    verify(snmp, times(1)).send(eq(trap), argument.capture());
+    assertEquals("192.168.0.2/162", argument.getValue().getAddress().toString());
+    assertEquals(SnmpConstants.version3, argument.getValue().getVersion());
+  }
+
+  @Test(expected = SNMPDispatcher.InvalidSnmpConfigurationException.class)
+  public void testSendTraps_v3_incorrectSecurityLevelVersion() throws Exception {
+    SNMPDispatcher.SnmpVersion snmpVersion = SNMPDispatcher.SnmpVersion.SNMPv3;
+    Snmp snmp = mock(Snmp.class);
+    SNMPDispatcher dispatcher = spy(new SNMPDispatcher(snmp));
+    PDU trap = mock(PDU.class);
+    Notification notification = new Notification();
+    Map<String, String> properties = new HashMap<String, String>();
+    properties.put(SNMPDispatcher.PORT_PROPERTY, "162");
+    properties.put(SNMPDispatcher.SNMP_VERSION_PROPERTY, "SNMPv3");
+    properties.put(SNMPDispatcher.TRAP_OID_PROPERTY, "1.3.6.1.6.3.1.1.5.4");
+    properties.put(SNMPDispatcher.SECURITY_USERNAME_PROPERTY, "USER");
+    properties.put(SNMPDispatcher.SECURITY_AUTH_PASSPHRASE_PROPERTY, "PASSPHRASE1");
+    properties.put(SNMPDispatcher.SECURITY_PRIV_PASSPHRASE_PROPERTY, "PASSPHRASE2");
+    properties.put(SNMPDispatcher.SECURITY_LEVEL_PROPERTY, "INCORRECT");
+    notification.DispatchProperties = properties;
+    Recipient rec1 = new Recipient();
+    rec1.Identifier = "192.168.0.2";
+    notification.Recipients = Arrays.asList(rec1);
+    doReturn(trap).when(dispatcher).prepareTrap(notification, snmpVersion);
+    dispatcher.sendTraps(notification, snmpVersion);
+  }
+}


Mime
View raw message