[ONOS-3203] End-to-end demo of Fault Management via SNMP.
This adds SNMP device-discovery, and a Fault Management app which makes alarms available to users via REST/GUI/CLI interfaces.
There is still code cleanup that could be done, but aim of this commit is an end-to-end proof of concept.
To demonstrate :
1) /opt/onos/bin/onos-service
onos> app activate org.onosproject.snmp
onos> app activate org.onosproject.faultmanagement
2) SNMP devices are seeded via config file. The default seed file contains connection details for devices (SNMP agents) available via internet e.g. demo.snmplabs.com
cp /opt/onos/apache-karaf-3.0.3/etc/samples/org.onosproject.provider.snmp.device.impl.SnmpDeviceProvider.cfg /opt/onos/apache-karaf-3.0.3/etc/
3) ONOS will poll these SNMP devices and store their alarms.
4) You can now manipulate the alarms via REST e.g. http://<onos>:8181/onos/v1/fm/alarms , via CLI via various "alarm-*” commands or in UI with an Alarms Overlay.
More info at https://wiki.onosproject.org/display/ONOS/Fault+Management
15/Dec/15: Updated regarding review comments from Thomas Vachuska.
17/Dec/15: Updated coreService.registerApplication(name) as per https://gerrit.onosproject.org/#/c/6878/
Change-Id: I886f8511f178dc4600ab96e5ff10cc90329cabec
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmEvent.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmEvent.java
index bbbd993..4041a7a 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmEvent.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmEvent.java
@@ -15,51 +15,64 @@
*/
package org.onosproject.incubator.net.faultmanagement.alarm;
+import java.util.Set;
import org.onosproject.event.AbstractEvent;
+import org.onosproject.net.DeviceId;
/**
- * Entity that represents Alarm events.
+ * Entity that represents Alarm events. Note: although the event will itself have a time, consumers may be more
+ * interested in the times embedded in the alarms themselves.
+ *
*/
-public class AlarmEvent extends AbstractEvent<AlarmEvent.Type, Alarm> {
+public class AlarmEvent extends AbstractEvent<AlarmEvent.Type, Set<Alarm>> {
+ private final DeviceId deviceRefreshed;
/**
- * Creates an event of a given type and for the specified alarm and the
- * current time.
+ * Creates an event due to one or more notification.
*
- * @param type topology event type
- * @param alarm the alarm
+ * @param alarms the set one or more of alarms.
*/
- public AlarmEvent(Type type, Alarm alarm) {
- super(type, alarm);
+ public AlarmEvent(Set<Alarm> alarms) {
+ super(Type.NOTIFICATION, alarms);
+ deviceRefreshed = null;
}
/**
- * Creates an event of a given type and for the specified alarm and time.
+ * Creates an event due to alarm discovery for a device.
*
- * @param type link event type
- * @param alarm the alarm
- * @param time occurrence time
+ * @param alarms the set of alarms.
+ * @param deviceRefreshed if of refreshed device, populated after a de-discovery
*/
- public AlarmEvent(Type type, Alarm alarm,
- long time) {
- super(type, alarm, time);
+ public AlarmEvent(Set<Alarm> alarms,
+ DeviceId deviceRefreshed) {
+ super(Type.DEVICE_DISCOVERY, alarms);
+ this.deviceRefreshed = deviceRefreshed;
+
}
/**
- * Type of alarm events.
+ * Gets which device was refreshed.
+ *
+ * @return the refreshed device, or null if event related to a asynchronous notification(s)
+ */
+ public DeviceId getDeviceRefreshed() {
+ return deviceRefreshed;
+ }
+
+ /**
+ * Type of alarm event.
*/
public enum Type {
- /**
- * A Raised Alarm.
- */
- RAISE,
/**
- * A Cleared Alarm.
+ * Individual alarm(s) updated.
*/
- CLEAR
+ NOTIFICATION,
+ /**
+ * Alarm set updated for a given device.
+ */
+ DEVICE_DISCOVERY,
}
-
}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmId.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmId.java
index e0107f8..4e65009 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmId.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmId.java
@@ -16,11 +16,9 @@
package org.onosproject.incubator.net.faultmanagement.alarm;
import com.google.common.annotations.Beta;
-
import java.util.Objects;
-
import static com.google.common.base.MoreObjects.toStringHelper;
-
+import static com.google.common.base.Preconditions.checkArgument;
/**
* Alarm identifier suitable as an external key.
* <p>
@@ -30,23 +28,29 @@
public final class AlarmId {
private final long id;
+ public static final AlarmId NONE = new AlarmId();
/**
* Instantiates a new Alarm id.
*
* @param id the id
*/
- public AlarmId(final long id) {
+ private AlarmId(long id) {
+ checkArgument(id != 0L, "id must be non-zero");
this.id = id;
}
+ private AlarmId() {
+ this.id = 0L;
+ }
+
/**
* Creates an alarm identifier from the specified long representation.
*
* @param value long value
* @return intent identifier
*/
- public static AlarmId valueOf(final long value) {
+ public static AlarmId alarmId(long value) {
return new AlarmId(value);
}
@@ -65,12 +69,12 @@
}
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof AlarmId) {
- final AlarmId other = (AlarmId) obj;
+ AlarmId other = (AlarmId) obj;
return Objects.equals(this.id, other.id);
}
return false;
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProvider.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProvider.java
index 82bcda2..2b82744 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProvider.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProvider.java
@@ -24,14 +24,25 @@
public interface AlarmProvider extends Provider {
/**
- * Triggers an asynchronous discovery of the alarms on the specified device,
- * intended to refresh internal alarm model for the device. An indirect
- * result of this should be invocation of
- * {@link org.onosproject.incubator.net.faultmanagement.alarm.AlarmProviderService#updateAlarmList} )}
- * at some later point in time.
+ * Triggers an asynchronous discovery of the alarms on the specified device, intended to refresh internal alarm
+ * model for the device. An indirect result of this should be a event sent later with discovery result ie a set of
+ * alarms.
*
* @param deviceId ID of device to be probed
*/
void triggerProbe(DeviceId deviceId);
+ /**
+ * Register a listener for alarms.
+ *
+ * @param listener the listener to notify
+ */
+ void addAlarmListener(AlarmListener listener);
+
+ /**
+ * Unregister a listener.
+ *
+ * @param listener the listener to unregister
+ */
+ void removeAlarmListener(AlarmListener listener);
}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProviderService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProviderService.java
index 727aa28..3e8519a 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProviderService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmProviderService.java
@@ -16,6 +16,7 @@
package org.onosproject.incubator.net.faultmanagement.alarm;
+import com.google.common.annotations.Beta;
import org.onosproject.net.DeviceId;
import org.onosproject.net.provider.ProviderService;
@@ -24,6 +25,7 @@
/**
* The interface Alarm provider service.
*/
+@Beta
public interface AlarmProviderService extends ProviderService<AlarmProvider> {
/**
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java
index 03c0c7b..d31b3f4 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/AlarmService.java
@@ -16,60 +16,65 @@
package org.onosproject.incubator.net.faultmanagement.alarm;
import com.google.common.annotations.Beta;
-//import org.onosproject.event.ListenerService;
+import java.util.Map;
import java.util.Set;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
/**
- * Service for interacting with the alarm handling of devices. Unless stated
- * otherwise method return active AND recently-cleared alarms.
+ * Service for interacting with the alarm handling of devices. Unless stated otherwise, getter methods
+ * return active AND recently-cleared alarms.
*/
@Beta
public interface AlarmService {
-// extends ListenerService<AlarmEvent, AlarmListener> {
/**
- * Alarm should be updated in ONOS's internal representation; only
- * administration/book-keeping fields may be updated. Attempting to update
- * fields which are mapped directly from device is prohibited.
+ * Update book-keeping (ie administrative) fields for the alarm matching the specified identifier.
*
- * @param replacement alarm with updated book-keeping fields
- * @return updated alarm (including any recent device derived changes)
-
- * @throws java.lang.IllegalStateException if attempt to update not allowed
- * fields.
+ * @param id alarm identifier
+ * @param isAcknowledged new acknowledged state
+ * @param assignedUser new assigned user, null clear
+ * @return updated alarm (including any recent device-derived changes)
+ *
*/
- Alarm update(Alarm replacement);
+ Alarm updateBookkeepingFields(AlarmId id, boolean isAcknowledged, String assignedUser);
/**
- * Returns the number of ACTIVE alarms on a device.
+ * Returns summary of alarms on a given device.
*
* @param deviceId the device
- * @return number of alarms
+ * @return map of severity (if applicable) vs alarm counts; empty map if either the device has no alarms or
+ * identified device is not managed.
*/
- int getActiveAlarmCount(DeviceId deviceId);
+ Map<Alarm.SeverityLevel, Long> getAlarmCounts(DeviceId deviceId);
+
+ /**
+ * Returns summary of alarms on all devices.
+ *
+ * @return map of severity (if applicable) vs alarm counts; empty map if no alarms.
+ */
+ Map<Alarm.SeverityLevel, Long> getAlarmCounts();
/**
* Returns the alarm with the specified identifier.
*
* @param alarmId alarm identifier
- * @return alarm or null if one with the given identifier is not known
+ * @return alarm matching id; null if no alarm matches the identifier.
*/
Alarm getAlarm(AlarmId alarmId);
/**
* Returns all of the alarms.
*
- * @return the alarms
+ * @return set of alarms; empty set if no alarms
*/
Set<Alarm> getAlarms();
/**
* Returns all of the ACTIVE alarms. Recently cleared alarms excluded.
*
- * @return the alarms
+ * @return set of alarms; empty set if no alarms
*/
Set<Alarm> getActiveAlarms();
@@ -77,16 +82,15 @@
* Returns the alarms with the specified severity.
*
* @param severity the alarm severity
- * @return the active alarms with a particular severity
+ * @return set of alarms with a particular severity; empty set if no alarms
*/
Set<Alarm> getAlarms(Alarm.SeverityLevel severity);
/**
- * Returns the alarm for a given device, regardless of source within that
- * device.
+ * Returns the alarm matching a given device, regardless of source within that device.
*
- * @param deviceId the device
- * @return the alarms
+ * @param deviceId the device to use when searching alarms.
+ * @return set of alarms; empty set if no alarms
*/
Set<Alarm> getAlarms(DeviceId deviceId);
@@ -95,7 +99,7 @@
*
* @param deviceId the device
* @param source the source within the device
- * @return the alarms
+ * @return set of alarms; empty set if no alarms
*/
Set<Alarm> getAlarms(DeviceId deviceId, AlarmEntityId source);
@@ -104,7 +108,7 @@
*
* @param src one end of the link
* @param dst one end of the link
- * @return the alarms
+ * @return set of alarms; empty set if no alarms
*/
Set<Alarm> getAlarmsForLink(ConnectPoint src, ConnectPoint dst);
@@ -113,9 +117,9 @@
*
* @param deviceId the device
* @param flowId the flow
- * @return the alarms
+ * @return set of alarms; empty set if no alarms
*/
Set<Alarm> getAlarmsForFlow(DeviceId deviceId, long flowId);
-// Support retrieving alarms affecting other ONOS entity types may be added in future release
+ // TODO Support retrieving alarms affecting other entity types may be added in future release
}
diff --git a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java
index afa366a..013eec1 100644
--- a/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java
+++ b/incubator/api/src/main/java/org/onosproject/incubator/net/faultmanagement/alarm/DefaultAlarm.java
@@ -145,14 +145,16 @@
@Override
public int hashCode() {
- return Objects.hash(id, deviceId, description,
- source, timeRaised, timeUpdated, timeCleared, severity,
+ // id or timeRaised or timeUpdated may differ
+ return Objects.hash(deviceId, description,
+ source, timeCleared, severity,
isServiceAffecting, isAcknowledged,
isManuallyClearable, assignedUser);
}
@Override
public boolean equals(final Object obj) {
+ // Make sure equals() is tune with hashCode() so works ok in a hashSet !
if (obj == null) {
return false;
}
@@ -160,9 +162,8 @@
return false;
}
final DefaultAlarm other = (DefaultAlarm) obj;
- if (!Objects.equals(this.id, other.id)) {
- return false;
- }
+
+ // id or timeRaised or timeUpdated may differ
if (!Objects.equals(this.deviceId, other.deviceId)) {
return false;
}
@@ -172,12 +173,7 @@
if (!Objects.equals(this.source, other.source)) {
return false;
}
- if (this.timeRaised != other.timeRaised) {
- return false;
- }
- if (this.timeUpdated != other.timeUpdated) {
- return false;
- }
+
if (!Objects.equals(this.timeCleared, other.timeCleared)) {
return false;
}
@@ -219,11 +215,11 @@
public static class Builder {
- // Manadatory fields ..
- private final AlarmId id;
+ // Manadatory fields when constructing alarm ...
+ private AlarmId id;
private final DeviceId deviceId;
private final String description;
- private final SeverityLevel severity;
+ private SeverityLevel severity;
private final long timeRaised;
// Optional fields ..
@@ -236,8 +232,8 @@
private String assignedUser = null;
public Builder(final Alarm alarm) {
- this(alarm.id(), alarm.deviceId(), alarm.description(), alarm.severity(), alarm.timeRaised());
- this.source = AlarmEntityId.NONE;
+ this(alarm.deviceId(), alarm.description(), alarm.severity(), alarm.timeRaised());
+ this.source = alarm.source();
this.timeUpdated = alarm.timeUpdated();
this.timeCleared = alarm.timeCleared();
this.isServiceAffecting = alarm.serviceAffecting();
@@ -247,10 +243,10 @@
}
- public Builder(final AlarmId id, final DeviceId deviceId,
+ public Builder(final DeviceId deviceId,
final String description, final SeverityLevel severity, final long timeRaised) {
super();
- this.id = id;
+ this.id = AlarmId.NONE;
this.deviceId = deviceId;
this.description = description;
this.severity = severity;
@@ -274,6 +270,17 @@
return this;
}
+ public Builder withId(final AlarmId id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder clear() {
+ this.severity = SeverityLevel.CLEARED;
+ final long now = System.currentTimeMillis();
+ return withTimeCleared(now).withTimeUpdated(now);
+ }
+
public Builder withServiceAffecting(final boolean isServiceAffecting) {
this.isServiceAffecting = isServiceAffecting;
return this;