*/
package org.opendaylight.openflowplugin.impl.role;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.JdkFutureAdapters;
import com.google.common.util.concurrent.ListenableFuture;
+import io.netty.util.HashedWheelTimer;
import io.netty.util.TimerTask;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
-import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleConductor;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
import org.slf4j.LoggerFactory;
/**
- * Role context hold information about entity ownership registration,
- * register and unregister candidate (main and tx)
+ * Role context try to make change device role on device
*/
class RoleContextImpl implements RoleContext {
private static final int MAX_CLEAN_DS_RETRIES = 3;
private SalRoleService salRoleService = null;
- private final LifecycleConductor conductor;
+ private final HashedWheelTimer hashedWheelTimer;
private final DeviceInfo deviceInfo;
private CONTEXT_STATE state;
private final RoleManager myManager;
+ private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
RoleContextImpl(final DeviceInfo deviceInfo,
- final LifecycleConductor lifecycleConductor,
+ final HashedWheelTimer hashedWheelTimer,
final RoleManager myManager) {
- this.conductor = lifecycleConductor;
this.deviceInfo = deviceInfo;
state = CONTEXT_STATE.WORKING;
this.myManager = myManager;
+ this.hashedWheelTimer = hashedWheelTimer;
}
@Nullable
@Override
public <T> RequestContext<T> createRequestContext() {
- return new AbstractRequestContext<T>(conductor.reserveXidForDeviceMessage(getDeviceInfo())) {
+ return new AbstractRequestContext<T>(deviceInfo.reserveXidForDeviceMessage()) {
@Override
public void close() {
}
this.salRoleService = salRoleService;
}
- @Override
- public SalRoleService getSalRoleService() {
- return this.salRoleService;
- }
-
@Override
public CONTEXT_STATE getState() {
return this.state;
}
public void startupClusterServices() throws ExecutionException, InterruptedException {
- //TODO: Add callback ?
- sendRoleChangeToDevice(OfpRole.BECOMEMASTER).get();
+ Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new FutureCallback<RpcResult<SetRoleOutput>>() {
+ @Override
+ public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
+ }
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue());
+ }
+ });
}
@Override
- public ListenableFuture<Void> stopClusterServices() {
- ListenableFuture<Void> future;
- try {
- //TODO: Add callback
- sendRoleChangeToDevice(OfpRole.BECOMESLAVE).get();
- } catch (InterruptedException | ExecutionException e) {
- LOG.warn("Send role to device failed ", e);
- } finally {
- myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
- future = Futures.immediateFuture(null);
+ public ListenableFuture<Void> stopClusterServices(final boolean deviceDisconnected) {
+
+ if (!deviceDisconnected) {
+ ListenableFuture<Void> future = Futures.transform(makeDeviceSlave(), new Function<RpcResult<SetRoleOutput>, Void>() {
+ @Nullable
+ @Override
+ public Void apply(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
+ return null;
+ }
+ });
+
+ Futures.addCallback(future, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(@Nullable Void aVoid) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Role SLAVE was successfully propagated on device, node {}", deviceInfo.getLOGValue());
+ }
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.warn("Was not able to set role SLAVE to device on node {} ", deviceInfo.getLOGValue());
+ LOG.trace("Error occurred on device role setting, probably connection loss: ", throwable);
+ myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
+
+ }
+ });
+ return future;
+ } else {
+ return myManager.removeDeviceFromOperationalDS(deviceInfo, MAX_CLEAN_DS_RETRIES);
}
- return future;
}
- private ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
+ @Override
+ public ListenableFuture<RpcResult<SetRoleOutput>> makeDeviceSlave(){
+ return sendRoleChangeToDevice(OfpRole.BECOMESLAVE);
+ }
+
+ @VisibleForTesting
+ ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
LOG.debug("Sending new role {} to device {}", newRole, deviceInfo.getNodeId());
final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
final Short version = deviceInfo.getVersion();
} else {
final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
.setNode(new NodeRef(DeviceStateUtil.createNodeInstanceIdentifier(deviceInfo.getNodeId()))).build();
- setRoleOutputFuture = getSalRoleService().setRole(setRoleInput);
+ setRoleOutputFuture = this.salRoleService.setRole(setRoleInput);
final TimerTask timerTask = timeout -> {
if (!setRoleOutputFuture.isDone()) {
- LOG.warn("New role {} was not propagated to device {} during 10 sec", newRole, deviceInfo.getNodeId());
+ LOG.warn("New role {} was not propagated to device {} during 10 sec", newRole, deviceInfo.getLOGValue());
setRoleOutputFuture.cancel(true);
}
};
- conductor.newTimeout(timerTask, 10, TimeUnit.SECONDS);
+ hashedWheelTimer.newTimeout(timerTask, 10, TimeUnit.SECONDS);
}
return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture);
}
+ @Override
+ public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
+ this.clusterInitializationPhaseHandler = handler;
+ }
+
+ @Override
+ public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
+
+ if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
+ LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue());
+ return false;
+ }
+
+ Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new FutureCallback<RpcResult<SetRoleOutput>>() {
+ @Override
+ public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
+ }
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue());
+ }
+ });
+
+ return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext);
+ }
}