Skip to content
Snippets Groups Projects
Commit 8cd763e2 authored by Saurav Das's avatar Saurav Das
Browse files

DebugEvent items:

1. making the API more RESTful by replacing dashes with slashes and maintaining URI tree
2. adding REST calls for listing events and resetting events
3. completing the REST API for GET calls
parent face0d99
No related branches found
No related tags found
No related merge requests found
......@@ -70,9 +70,12 @@ public class CircularBuffer<T> implements Iterable<T>{
}
/**
* ArrayDeques are not threadsafe and thus must be externally synchronized.
* For concurrent iteration we call a copy constructor on the ArrayDeque and
* return the iterator of the newly created ArrayDeque.
* Returns an iterator over the elements in the circular buffer in proper sequence.
* The elements will be returned in order from oldest to most-recent.
* The returned Iterator is a "weakly consistent" iterator that will never
* throw ConcurrentModificationException, and guarantees to traverse elements
* as they existed upon construction of the iterator, and may (but is not
* guaranteed to) reflect any modifications subsequent to construction.
*/
@Override
public Iterator<T> iterator() {
......@@ -82,4 +85,11 @@ public class CircularBuffer<T> implements Iterable<T>{
public int size() {
return buffer.size();
}
/**
* Atomically removes all elements in the circular buffer
*/
public void clear() {
buffer.clear();
}
}
......@@ -39,15 +39,8 @@ public class DebugEvent implements IFloodlightModule, IDebugEventService {
protected int eventIdCounter = 0;
protected Object eventIdLock = new Object();
/**
* A limit on the maximum number of event types that can be created
*/
protected static final int MAX_EVENTS = 2000;
private static final long MIN_FLUSH_DELAY = 100; //ms
private static final int PCT_LOCAL_CAP = 10; // % of global capacity
private static final int MIN_LOCAL_CAPACITY = 10; //elements
/**
......@@ -62,8 +55,8 @@ public class DebugEvent implements IFloodlightModule, IDebugEventService {
String eventDesc;
String eventName;
String moduleName;
String moduleEventName;
boolean flushNow;
String moduleEventName;
public EventInfo(int eventId, boolean enabled, int bufferCapacity,
EventType etype, String formatStr, String eventDesc,
......@@ -76,8 +69,8 @@ public class DebugEvent implements IFloodlightModule, IDebugEventService {
this.eventDesc = eventDesc;
this.eventName = eventName;
this.moduleName = moduleName;
this.moduleEventName = moduleName + "-" + eventName;
this.flushNow = flushNow;
this.moduleEventName = moduleName + "/" + eventName;
}
public int getEventId() { return eventId; }
......@@ -89,7 +82,6 @@ public class DebugEvent implements IFloodlightModule, IDebugEventService {
public String getEventName() { return eventName; }
public String getModuleName() { return moduleName; }
public String getModuleEventName() { return moduleEventName; }
}
//******************
......@@ -324,50 +316,107 @@ public class DebugEvent implements IFloodlightModule, IDebugEventService {
}
@Override
public boolean containsMEName(String moduleEventName) {
String[] temp = moduleEventName.split("-");
if (temp.length != 2) return false;
if (!moduleEvents.containsKey(temp[0])) return false;
if (moduleEvents.get(temp[0]).containsKey(temp[1])) return true;
public boolean containsModuleEventName(String moduleName, String eventName) {
if (!moduleEvents.containsKey(moduleName)) return false;
if (moduleEvents.get(moduleName).containsKey(eventName)) return true;
return false;
}
@Override
public boolean containsModName(String moduleName) {
public boolean containsModuleName(String moduleName) {
return moduleEvents.containsKey(moduleName);
}
@Override
public List<DebugEventInfo> getAllEventHistory() {
// TODO Auto-generated method stub
return null;
ArrayList<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
for (Map<String, Integer> modev : moduleEvents.values()) {
for (int eventId : modev.values()) {
DebugEventHistory de = allEvents[eventId];
if (de != null) {
ArrayList<String> ret = new ArrayList<String>();
for (Event e : de.eventBuffer) {
ret.add(e.toString(de.einfo.formatStr, de.einfo.moduleEventName));
}
moduleEventList.add(new DebugEventInfo(de.einfo, ret));
}
}
}
return moduleEventList;
}
@Override
public List<DebugEventInfo> getModuleEventHistory(String moduleName) {
// TODO Auto-generated method stub
return null;
if (!moduleEvents.containsKey(moduleName)) return null;
ArrayList<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
for (int eventId : moduleEvents.get(moduleName).values()) {
DebugEventHistory de = allEvents[eventId];
if (de != null) {
ArrayList<String> ret = new ArrayList<String>();
for (Event e : de.eventBuffer) {
ret.add(e.toString(de.einfo.formatStr, de.einfo.moduleEventName));
}
moduleEventList.add(new DebugEventInfo(de.einfo, ret));
}
}
return moduleEventList;
}
@Override
public DebugEventInfo getSingleEventHistory(String moduleEventName) {
String[] temp = moduleEventName.split("-");
if (temp.length != 2) return null;
if (!moduleEvents.containsKey(temp[0])) return null;
Integer eventId = moduleEvents.get(temp[0]).get(temp[1]);
public DebugEventInfo getSingleEventHistory(String moduleName, String eventName) {
if (!moduleEvents.containsKey(moduleName)) return null;
Integer eventId = moduleEvents.get(moduleName).get(eventName);
if (eventId == null) return null;
DebugEventHistory de = allEvents[eventId];
if (de != null) {
ArrayList<String> ret = new ArrayList<String>();
for (Event e : de.eventBuffer) {
ret.add(e.toString(de.einfo.formatStr, de.einfo.moduleEventName));
//ret.add(e.toString());
}
return new DebugEventInfo(de.einfo, ret);
}
return null;
}
@Override
public void resetAllEvents() {
for (Map<String, Integer> eventMap : moduleEvents.values()) {
for (Integer evId : eventMap.values()) {
allEvents[evId].eventBuffer.clear();
}
}
}
@Override
public void resetAllModuleEvents(String moduleName) {
if (!moduleEvents.containsKey(moduleName)) return;
Map<String, Integer> modEvents = moduleEvents.get(moduleName);
for (Integer evId : modEvents.values()) {
allEvents[evId].eventBuffer.clear();
}
}
@Override
public void resetSingleEvent(String moduleName, String eventName) {
if (!moduleEvents.containsKey(moduleName)) return;
Integer eventId = moduleEvents.get(moduleName).get(eventName);
if (eventId == null) return;
DebugEventHistory de = allEvents[eventId];
if (de != null) {
de.eventBuffer.clear();
}
}
@Override
public ArrayList<EventInfo> getEventList() {
ArrayList<EventInfo> eil = new ArrayList<EventInfo>();
for (Map<String, Integer> eventMap : moduleEvents.values()) {
for (Integer evId : eventMap.values()) {
eil.add(allEvents[evId].einfo);
}
}
return eil;
}
protected void printEvents() {
for (int eventId : currentEvents) {
......
......@@ -17,6 +17,11 @@ public interface IDebugEventService extends IFloodlightService {
LOG_ON_DEMAND
}
/**
* A limit on the maximum number of event types that can be created
*/
public static final int MAX_EVENTS = 2000;
/**
* Public class for information returned in response to rest API calls.
*/
......@@ -54,7 +59,7 @@ public interface IDebugEventService extends IFloodlightService {
* in the packet processing pipeline (eg. switch
* connect/disconnect).
* @param eventDescription A descriptive string describing event.
* @param et EventType for this event.
* @param eventType EventType for this event.
* @param bufferCapacity Number of events to store for this event in a circular
* buffer. Older events will be discarded once the
* buffer is full.
......@@ -74,7 +79,7 @@ public interface IDebugEventService extends IFloodlightService {
* @throws MaxEventsRegistered
*/
public int registerEvent(String moduleName, String eventName, boolean flushNow,
String eventDescription, EventType et,
String eventDescription, EventType eventType,
int bufferCapacity, String formatStr, Object[] params)
throws MaxEventsRegistered;
......@@ -106,37 +111,67 @@ public interface IDebugEventService extends IFloodlightService {
public void flushEvents();
/**
* Determine if moduleEventName is a registered event. moduleEventName must
* be of the type {moduleName-eventName} eg. linkdiscovery-linkevent
* Determine if eventName is a registered event for a given moduleName
*/
public boolean containsMEName(String moduleEventName);
public boolean containsModuleEventName(String moduleName, String eventName);
/**
* Determine if any events have been registerd by a module of name moduleName
* Determine if any events have been registered for module of name moduleName
*/
public boolean containsModName(String moduleName);
public boolean containsModuleName(String moduleName);
/**
* Get event history for all events. This call can be expensive as it
* formats the event histories for all events.
*
* @return
* @return a list of all event histories or an empty list if no events have
* been registered
*/
public List<DebugEventInfo> getAllEventHistory();
/**
* Get event history for all events registered for a given moduleName
*
* @param moduleName
* @return
* @return a list of all event histories for all events registered for the
* the module or null if there are no events for this module
*/
public List<DebugEventInfo> getModuleEventHistory(String moduleName);
/**
* Get event history for an event of name moduleEventName. moduleEventName
* must be of the type {moduleName-eventName} eg. linkdiscovery-linkevent
* Get event history for a single event
*
* @param moduleEventName
* @param moduleName registered module name
* @param eventName registered event name for moduleName
* @return DebugEventInfo for that event, or null if the moduleEventName
* does not correspond to a registered event.
*/
public DebugEventInfo getSingleEventHistory(String moduleEventName);
public DebugEventInfo getSingleEventHistory(String moduleName, String eventName);
/**
* Wipe out all event history for all registered active events
*/
public void resetAllEvents();
/**
* Wipe out all event history for all events registered for a specific module
*
* @param moduleName registered module name
*/
public void resetAllModuleEvents(String moduleName);
/**
* Wipe out event history for a single event
* @param moduleName registered module name
* @param eventName registered event name for moduleName
*/
public void resetSingleEvent(String moduleName, String eventName);
/**
* Retrieve information on all registered events
*
* @return the arraylist of event-info or an empty list if no events are registered
*/
public ArrayList<EventInfo> getEventList();
}
......@@ -10,6 +10,7 @@ import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.debugevent.DebugEvent.EventInfo;
public class NullDebugEvent implements IFloodlightModule, IDebugEventService {
......@@ -70,13 +71,13 @@ public class NullDebugEvent implements IFloodlightModule, IDebugEventService {
}
@Override
public boolean containsMEName(String param) {
public boolean containsModuleEventName(String moduleName, String eventName) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean containsModName(String param) {
public boolean containsModuleName(String moduleName) {
// TODO Auto-generated method stub
return false;
}
......@@ -94,7 +95,31 @@ public class NullDebugEvent implements IFloodlightModule, IDebugEventService {
}
@Override
public DebugEventInfo getSingleEventHistory(String param) {
public DebugEventInfo getSingleEventHistory(String moduleName, String eventName) {
// TODO Auto-generated method stub
return null;
}
@Override
public void resetAllEvents() {
// TODO Auto-generated method stub
}
@Override
public void resetAllModuleEvents(String moduleName) {
// TODO Auto-generated method stub
}
@Override
public void resetSingleEvent(String moduleName, String eventName) {
// TODO Auto-generated method stub
}
@Override
public ArrayList<EventInfo> getEventList() {
// TODO Auto-generated method stub
return null;
}
......
......@@ -5,24 +5,16 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.floodlightcontroller.debugevent.DebugEvent.EventInfo;
import net.floodlightcontroller.debugevent.IDebugEventService.DebugEventInfo;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Return the debug event data for the get rest-api call
*
* URI must be in one of the following forms:
* "http://{controller-hostname}:8080/wm/debugevent/{param}/json
*
* where {param} must be one of (no quotes):
* "all" returns value/info on all active events.
* "{moduleName}" returns value/info on all active events for the specified module.
* "{moduleEventName}" returns value/info for specific event if it is active.
* Web interface for Debug Events
*
* @author Saurav
*/
......@@ -34,17 +26,21 @@ public class DebugEventResource extends DebugEventResourceBase {
* The output JSON model that contains the counter information
*/
public static class DebugEventInfoOutput {
public Map<String, DebugEventInfo> eventMap;
public String error;
public Map<String, DebugEventInfo> eventMap = null;
public List<EventInfo> eventList = null;
public String error = null;
DebugEventInfoOutput() {
eventMap = new HashMap<String, DebugEventInfo>();
error = null;
DebugEventInfoOutput(boolean getList) {
if (!getList) {
eventMap = new HashMap<String, DebugEventInfo>();
}
}
public Map<String, DebugEventInfo> getEventMap() {
return eventMap;
}
public List<EventInfo> getEventList() {
return eventList;
}
public String getError() {
return error;
}
......@@ -56,31 +52,153 @@ public class DebugEventResource extends DebugEventResourceBase {
ERROR_BAD_MODULE_EVENT_NAME
}
public static class DebugEventPost {
public Boolean reset;
public Boolean getReset() {
return reset;
}
public void setReset(Boolean reset) {
this.reset = reset;
}
}
public static class ResetOutput {
String error = null;
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}
/**
* Reset events
*
* If using curl:
* curl -X POST -d {\"reset\":true} -H "Content-Type: application/json" URL
* where URL must be in one of the following forms for resetting registered events:
* "http://{controller-hostname}:8080/wm/debugevent/
* "http://{controller-hostname}:8080/wm/debugevent/{param1}
* "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2}
*
* Not giving {param1} will reset all events
* {param1} can be 'all' or the name of a module. The former case will reset
* all events, while the latter will reset all events for the moduleName.
* {param2} must be an eventName for the given moduleName
*/
@Post
public ResetOutput postHandler(DebugEventPost postData) {
ResetOutput output = new ResetOutput();
String param1 = (String)getRequestAttributes().get("param1");
String param2 = (String)getRequestAttributes().get("param2");
if (postData.getReset() != null && postData.getReset()) {
Option choice = Option.ERROR_BAD_PARAM;
if (param1 == null) {
param1 = "all";
choice = Option.ALL;
} else if (param1.equals("all")) {
choice = Option.ALL;
} else if (param2 == null) {
boolean isRegistered = debugEvent.containsModuleName(param1);
if (isRegistered) {
choice = Option.ONE_MODULE;
} else {
choice = Option.ERROR_BAD_MODULE_NAME;
}
} else {
// differentiate between disabled and non-existing events
boolean isRegistered = debugEvent.containsModuleEventName(param1, param2);
if (isRegistered) {
choice = Option.ONE_MODULE_EVENT;
} else {
choice = Option.ERROR_BAD_MODULE_EVENT_NAME;
}
}
switch (choice) {
case ALL:
debugEvent.resetAllEvents();
break;
case ONE_MODULE:
debugEvent.resetAllModuleEvents(param1);
break;
case ONE_MODULE_EVENT:
debugEvent.resetSingleEvent(param1, param2);
break;
case ERROR_BAD_MODULE_NAME:
output.error = "Module name has no corresponding registered events";
break;
case ERROR_BAD_MODULE_EVENT_NAME:
output.error = "Event not registered";
break;
case ERROR_BAD_PARAM:
output.error = "Bad param";
}
}
return output;
}
/**
* Return the debug event data for the get rest-api call
*
* URL must be in one of the following forms for retrieving a list of all
* registered events:
* "http://{controller-hostname}:8080/wm/debugevent/
*
* URL must be in one of the following forms for retrieving event data:
* "http://{controller-hostname}:8080/wm/debugevent/{param1}
* "http://{controller-hostname}:8080/wm/debugevent/{param1}/{param2}
*
* where {param1} must be one of (no quotes):
* "all" returns value/info on all active events.
* "{moduleName}" returns value/info on events for the specified module
* depending on the value of param2
* and {param2} must be one of (no quotes):
* "{eventName}" returns value/info for specific event if it is active.
*
* {param2} is optional; in which case the event history for all the events registered
* for that moduleName will be returned.
*
*/
@Get("json")
public DebugEventInfoOutput handleEventInfoQuery() {
DebugEventInfoOutput output = new DebugEventInfoOutput();
Option choice = Option.ERROR_BAD_PARAM;
DebugEventInfoOutput output;
String param = (String)getRequestAttributes().get("param");
if (param == null) {
param = "all";
choice = Option.ALL;
} else if (param.equals("all")) {
String param1 = (String)getRequestAttributes().get("param1");
String param2 = (String)getRequestAttributes().get("param2");
if (param1 == null && param2 == null) {
output = new DebugEventInfoOutput(true);
return listEvents(output);
}
output = new DebugEventInfoOutput(false);
if (param1 == null && param2 != null) {
choice = Option.ERROR_BAD_PARAM;
} else if (param1.equals("all")) {
choice = Option.ALL;
} else if (param.contains("-")) {
// differentiate between disabled and non-existing counters
boolean isRegistered = debugEvent.containsMEName(param);
} else if (param2 == null) {
boolean isRegistered = debugEvent.containsModuleName(param1);
if (isRegistered) {
choice = Option.ONE_MODULE_EVENT;
choice = Option.ONE_MODULE;
} else {
choice = Option.ERROR_BAD_MODULE_EVENT_NAME;
choice = Option.ERROR_BAD_MODULE_NAME;
}
} else {
boolean isRegistered = debugEvent.containsModName(param);
// differentiate between disabled and non-existing events
boolean isRegistered = debugEvent.containsModuleEventName(param1, param2);
if (isRegistered) {
choice = Option.ONE_MODULE;
choice = Option.ONE_MODULE_EVENT;
} else {
choice = Option.ERROR_BAD_MODULE_NAME;
choice = Option.ERROR_BAD_MODULE_EVENT_NAME;
}
}
......@@ -89,10 +207,11 @@ public class DebugEventResource extends DebugEventResourceBase {
populateEvents(debugEvent.getAllEventHistory(), output);
break;
case ONE_MODULE:
populateEvents(debugEvent.getModuleEventHistory(param), output);
populateEvents(debugEvent.getModuleEventHistory(param1), output);
break;
case ONE_MODULE_EVENT:
populateSingleEvent(debugEvent.getSingleEventHistory(param), output);
populateSingleEvent(debugEvent.getSingleEventHistory(param1, param2),
output);
break;
case ERROR_BAD_MODULE_NAME:
output.error = "Module name has no corresponding registered events";
......@@ -107,6 +226,11 @@ public class DebugEventResource extends DebugEventResourceBase {
return output;
}
private DebugEventInfoOutput listEvents(DebugEventInfoOutput output) {
output.eventList = debugEvent.getEventList();
return output;
}
private void populateSingleEvent(DebugEventInfo singleEventHistory,
DebugEventInfoOutput output) {
if (singleEventHistory != null) {
......
......@@ -11,7 +11,11 @@ public class DebugEventRoutable implements RestletRoutable {
@Override
public Restlet getRestlet(Context context) {
Router router = new Router(context);
router.attach("/{param}", DebugEventResource.class);
router.attach("/{param1}/{param2}/", DebugEventResource.class);
router.attach("/{param1}/{param2}", DebugEventResource.class);
router.attach("/{param1}/", DebugEventResource.class);
router.attach("/{param1}", DebugEventResource.class);
router.attach("/", DebugEventResource.class);
return router;
}
......
......@@ -42,9 +42,9 @@ public class DebugEventTest extends FloodlightTestCase {
get("switchevent").intValue());
assertEquals(eventId2, debugEvent.moduleEvents.get("dbgevtest").
get("pktinevent").intValue());
assertEquals(true, debugEvent.containsModName("dbgevtest"));
assertEquals(true, debugEvent.containsMEName("dbgevtest-switchevent"));
assertEquals(true, debugEvent.containsMEName("dbgevtest-pktinevent"));
assertEquals(true, debugEvent.containsModuleName("dbgevtest"));
assertEquals(true, debugEvent.containsModuleEventName("dbgevtest","switchevent"));
assertEquals(true, debugEvent.containsModuleEventName("dbgevtest","pktinevent"));
assertEquals(0, DebugEvent.allEvents[eventId1].eventBuffer.size());
assertEquals(0, DebugEvent.allEvents[eventId2].eventBuffer.size());
......@@ -61,12 +61,12 @@ public class DebugEventTest extends FloodlightTestCase {
assertEquals(1, DebugEvent.allEvents[eventId1].eventBuffer.size());
assertEquals(1, DebugEvent.allEvents[eventId2].eventBuffer.size());
DebugEventInfo de = debugEvent.getSingleEventHistory("dbgevtest-switchevent");
DebugEventInfo de = debugEvent.getSingleEventHistory("dbgevtest","switchevent");
assertEquals(1, de.events.size());
assertEquals(true, de.events.get(0)
.contains("Sw=00:00:00:00:00:00:00:01, reason=connected"));
DebugEventInfo de2 = debugEvent.getSingleEventHistory("dbgevtest-pktinevent");
DebugEventInfo de2 = debugEvent.getSingleEventHistory("dbgevtest","pktinevent");
assertEquals(1, de2.events.size());
assertEquals(true, de2.events.get(0)
.contains("Sw=1, reason=switch sent pkt-in"));
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment