diff --git a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java index 8243934b074916ef436bcadbe63274d7e775d20c..7f9ff596ad0ab785fa33660c55512ef6d94fd37e 100644 --- a/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java +++ b/src/main/java/net/floodlightcontroller/core/IFloodlightProviderService.java @@ -88,6 +88,11 @@ public interface IFloodlightProviderService extends */ public Role getRole(); + /** + * Get the current role of the controller + */ + public RoleInfo getRoleInfo(); + /** * Get the current mapping of controller IDs to their IP addresses * Returns a copy of the current mapping. @@ -98,8 +103,10 @@ public interface IFloodlightProviderService extends /** * Set the role of the controller + * @param role The new role for the controller node + * @param changeDescription The reason or other information for this role change */ - public void setRole(Role role); + public void setRole(Role role, String changeDescription); /** * Add a switch listener diff --git a/src/main/java/net/floodlightcontroller/core/web/RoleInfo.java b/src/main/java/net/floodlightcontroller/core/RoleInfo.java similarity index 50% rename from src/main/java/net/floodlightcontroller/core/web/RoleInfo.java rename to src/main/java/net/floodlightcontroller/core/RoleInfo.java index c8fa0c1a49a6bf564dee230cfa38b7abbfca1c31..248cd17b694037c12e86a93aaedf7a80556fea0c 100644 --- a/src/main/java/net/floodlightcontroller/core/web/RoleInfo.java +++ b/src/main/java/net/floodlightcontroller/core/RoleInfo.java @@ -14,29 +14,57 @@ * under the License. **/ -package net.floodlightcontroller.core.web; +package net.floodlightcontroller.core; + +import java.util.Date; import net.floodlightcontroller.core.IFloodlightProviderService.Role; +import org.codehaus.jackson.annotate.JsonProperty; + + public class RoleInfo { protected String role; - + protected String roleChangeDescription; + protected Date roleChangeDateTime; + public RoleInfo() { } - + public RoleInfo(String role) { setRole(role); } - - public RoleInfo(Role role) { + + public RoleInfo(Role role, String description) { + this.role = (role != null) ? role.name() : "DISABLED"; + this.roleChangeDescription = description; + } + + public RoleInfo(Role role, String description, Date dt) { this.role = (role != null) ? role.name() : "DISABLED"; + this.roleChangeDescription = description; + this.roleChangeDateTime = dt; } - + public String getRole() { return role; } - + public void setRole(String role) { this.role = role; } + + @JsonProperty(value="change-description") + public String getRoleChangeDescription() { + return roleChangeDescription; + } + @JsonProperty(value="change-description") + public void setRoleChangeDescription(String roleChangeDescription) { + this.roleChangeDescription = roleChangeDescription; + } + @JsonProperty(value="change-date-time") + public String getRoleChangeDateTime() { + return roleChangeDateTime == null ? "" : roleChangeDateTime.toString(); + } + } \ No newline at end of file diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java index a0b2c3ce3c99f6c14880f4b60f7abaeba8d19ed0..db0e2e87be822d5855bff33897e046428305a419 100644 --- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java +++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java @@ -24,6 +24,7 @@ import java.nio.channels.ClosedChannelException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -55,6 +56,7 @@ import net.floodlightcontroller.core.IOFSwitchDriver; import net.floodlightcontroller.core.IOFSwitchFilter; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.OFSwitchBase; +import net.floodlightcontroller.core.RoleInfo; import net.floodlightcontroller.core.annotations.LogMessageDoc; import net.floodlightcontroller.core.annotations.LogMessageDocs; import net.floodlightcontroller.core.internal.OFChannelState.HandshakeState; @@ -180,6 +182,8 @@ public class Controller implements IFloodlightProviderService, // The current role of the controller. // If the controller isn't configured to support roles, then this is null. protected Role role; + protected String lastRoleChangeDescription = "Inital role set during startup."; + protected Date roleChangeDateTime = new Date(); // This is the role of the controller based on HARoleChange notifications // we have sent. I.e., this field reflects the last role notification // we have sent to the listeners. On a transition to slave we first set @@ -188,7 +192,9 @@ public class Controller implements IFloodlightProviderService, // OF messages while the modules are in slave role. // The pendingRole is a role change just received, but not sent out // notifications yet. - protected Role pendingRole;protected volatile Role notifiedRole; + protected Role pendingRole; + protected String pendRoleChangeDescription; + protected volatile Role notifiedRole; // A helper that handles sending and timeout handling for role requests protected RoleChanger roleChanger; protected SingletonTask roleChangeDamper; @@ -382,12 +388,20 @@ public class Controller implements IFloodlightProviderService, } @Override - public void setRole(Role role) { + public RoleInfo getRoleInfo() { + synchronized(roleChanger) { + return new RoleInfo(role, lastRoleChangeDescription, roleChangeDateTime); + } + } + + @Override + public void setRole(Role role, String roleChangeDescription) { if (role == null) throw new NullPointerException("Role can not be null."); // If role is changed in quick succession for some reason, // the 2 second delay will dampen the frequency. this.pendingRole = role; + pendRoleChangeDescription = roleChangeDescription; roleChangeDamper.reschedule(2000, TimeUnit.MILLISECONDS); } @@ -405,6 +419,9 @@ public class Controller implements IFloodlightProviderService, Role oldRole = this.role; this.role = pendingRole; + this.lastRoleChangeDescription = this.pendRoleChangeDescription; + this.pendRoleChangeDescription = null; + this.roleChangeDateTime = new Date(); log.debug("Submitting role change request to role {}", role); roleChanger.submitRequest(connectedSwitches, role); diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java index 003fbbc25fbfcd6e8755f078ab62bfdcdcc25217..e31c9cdae08403b59b3726f9aabbf3b4c5d33b79 100644 --- a/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/ControllerRoleResource.java @@ -20,6 +20,7 @@ import org.restlet.data.Status; import org.restlet.resource.ServerResource; import net.floodlightcontroller.core.IFloodlightProviderService; +import net.floodlightcontroller.core.RoleInfo; import net.floodlightcontroller.core.IFloodlightProviderService.Role; import net.floodlightcontroller.core.annotations.LogMessageDoc; @@ -37,7 +38,7 @@ public class ControllerRoleResource extends ServerResource { IFloodlightProviderService floodlightProvider = (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); - return new RoleInfo(floodlightProvider.getRole()); + return floodlightProvider.getRoleInfo(); } @Post("json") @@ -68,6 +69,6 @@ public class ControllerRoleResource extends ServerResource { (IFloodlightProviderService)getContext().getAttributes(). get(IFloodlightProviderService.class.getCanonicalName()); - floodlightProvider.setRole(role); + floodlightProvider.setRole(role, roleInfo.getRoleChangeDescription()); } } diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java index 5da407b94ba0203274de890eaea89c3e31e47ffe..74a228eea5858a61cc50dee54aecdc310d5bd120 100644 --- a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java +++ b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java @@ -23,6 +23,7 @@ import org.restlet.resource.ServerResource; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFSwitch; +import net.floodlightcontroller.core.RoleInfo; import org.restlet.resource.Get; import org.slf4j.Logger; @@ -46,7 +47,7 @@ public class SwitchRoleResource extends ServerResource { HashMap<String,RoleInfo> model = new HashMap<String,RoleInfo>(); for (IOFSwitch sw: floodlightProvider.getSwitches().values()) { switchId = sw.getStringId(); - roleInfo = new RoleInfo(sw.getHARole()); + roleInfo = new RoleInfo(sw.getHARole(), null); model.put(switchId, roleInfo); } return model; @@ -56,7 +57,7 @@ public class SwitchRoleResource extends ServerResource { IOFSwitch sw = floodlightProvider.getSwitches().get(dpid); if (sw == null) return null; - roleInfo = new RoleInfo(sw.getHARole()); + roleInfo = new RoleInfo(sw.getHARole(), null); return roleInfo; } } diff --git a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java index f6f94f880fda7904abd0cc68580094c9713f4971..eaf508592306c6b487ba14fef50ae1e0fc098f04 100644 --- a/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java +++ b/src/test/java/net/floodlightcontroller/core/internal/ControllerTest.java @@ -742,7 +742,7 @@ public class ControllerTest extends FloodlightTestCase @Test public void testSetRoleNull() { try { - controller.setRole(null); + controller.setRole(null, null); fail("Should have thrown an Exception"); } catch (NullPointerException e) { @@ -761,7 +761,7 @@ public class ControllerTest extends FloodlightTestCase controller.updates.size()); replay(roleChanger); - controller.setRole(Role.SLAVE); + controller.setRole(Role.SLAVE, "Testing"); controller.doSetRole(); // avoid wait verify(roleChanger); @@ -1531,7 +1531,7 @@ public class ControllerTest extends FloodlightTestCase anyObject(FloodlightContext.class)); expectLastCall().andReturn(Command.STOP).once(); replay(sw, listener); - controller.setRole(Role.SLAVE); + controller.setRole(Role.SLAVE, "Testing"); controller.doSetRole(); // avoid the wait chdlr.processOFMessage(pi); verify(sw, listener); @@ -1551,7 +1551,7 @@ public class ControllerTest extends FloodlightTestCase // transition back to master but don't notify yet resetToDefault(listener); replay(listener); - controller.setRole(Role.MASTER); + controller.setRole(Role.MASTER, "Testing"); controller.doSetRole(); // avoid the wait chdlr.processOFMessage(pi); verify(listener); diff --git a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java index 1f6a59352ac121d4d955368503e94b4d2f6c0c57..6db18a150c8fed2d8fb84c412cfe0bfa3aad3c98 100644 --- a/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java +++ b/src/test/java/net/floodlightcontroller/core/test/MockFloodlightProvider.java @@ -39,6 +39,7 @@ import net.floodlightcontroller.core.IOFSwitchDriver; import net.floodlightcontroller.core.IOFSwitchFilter; import net.floodlightcontroller.core.IOFSwitchListener; import net.floodlightcontroller.core.IListener.Command; +import net.floodlightcontroller.core.RoleInfo; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; @@ -102,6 +103,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro /** * @return the listeners */ + @Override public Map<OFType, List<IOFMessageListener>> getListeners() { Map<OFType, List<IOFMessageListener>> lers = new HashMap<OFType, List<IOFMessageListener>>(); @@ -158,6 +160,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } } + @Override public void handleOutgoingMessage(IOFSwitch sw, OFMessage m, FloodlightContext bc) { List<IOFMessageListener> msgListeners = null; if (listeners.containsKey(m.getType())) { @@ -191,6 +194,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro return switchListeners; } + @Override public void terminate() { } @@ -289,7 +293,7 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } @Override - public void setRole(Role role) { + public void setRole(Role role, String roleChangeDescription) { } @@ -351,4 +355,10 @@ public class MockFloodlightProvider implements IFloodlightModule, IFloodlightPro } + @Override + public RoleInfo getRoleInfo() { + // TODO Auto-generated method stub + return null; + } + }