2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.openflowplugin.impl.role;
10 import com.google.common.annotations.VisibleForTesting;
11 import com.google.common.base.Function;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.JdkFutureAdapters;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import io.netty.util.HashedWheelTimer;
18 import io.netty.util.TimerTask;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
26 import org.opendaylight.openflowplugin.api.OFConstants;
27 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
28 import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo;
29 import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
30 import org.opendaylight.openflowplugin.api.openflow.device.handlers.ClusterInitializationPhaseHandler;
31 import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService;
32 import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
33 import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
34 import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
41 import org.opendaylight.yangtools.yang.common.RpcResult;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * Role context try to make change device role on device
48 class RoleContextImpl implements RoleContext {
50 private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
52 // Timeout in seconds after what we will give up on propagating role
53 private static final int SET_ROLE_TIMEOUT = 10;
55 private SalRoleService salRoleService = null;
56 private final HashedWheelTimer hashedWheelTimer;
57 private final DeviceInfo deviceInfo;
58 private CONTEXT_STATE state;
59 private final RoleManager myManager;
60 private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler;
61 private final LifecycleService lifecycleService;
63 RoleContextImpl(final DeviceInfo deviceInfo,
64 final HashedWheelTimer hashedWheelTimer,
65 final RoleManager myManager,
66 final LifecycleService lifecycleService) {
67 this.deviceInfo = deviceInfo;
68 this.state = CONTEXT_STATE.WORKING;
69 this.myManager = myManager;
70 this.hashedWheelTimer = hashedWheelTimer;
71 this.lifecycleService = lifecycleService;
76 public <T> RequestContext<T> createRequestContext() {
77 return new AbstractRequestContext<T>(deviceInfo.reserveXidForDeviceMessage()) {
85 public void setSalRoleService(@Nonnull final SalRoleService salRoleService) {
86 Preconditions.checkNotNull(salRoleService);
87 this.salRoleService = salRoleService;
91 public CONTEXT_STATE getState() {
96 public void setState(CONTEXT_STATE state) {
101 public ServiceGroupIdentifier getServiceIdentifier() {
102 return this.deviceInfo.getServiceIdentifier();
106 public DeviceInfo getDeviceInfo() {
107 return this.deviceInfo;
110 public void startupClusterServices() throws ExecutionException, InterruptedException {
111 Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new RpcResultFutureCallback());
115 public ListenableFuture<Void> stopClusterServices(final boolean deviceDisconnected) {
117 if (!deviceDisconnected) {
118 ListenableFuture<Void> future = Futures.transform(makeDeviceSlave(), new Function<RpcResult<SetRoleOutput>, Void>() {
121 public Void apply(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
126 Futures.addCallback(future, new FutureCallback<Void>() {
128 public void onSuccess(@Nullable Void aVoid) {
129 if (LOG.isDebugEnabled()) {
130 LOG.debug("Role SLAVE was successfully propagated on device, node {}", deviceInfo.getLOGValue());
135 public void onFailure(final Throwable throwable) {
136 LOG.warn("Was not able to set role SLAVE to device on node {} ", deviceInfo.getLOGValue());
137 LOG.trace("Error occurred on device role setting, probably connection loss: ", throwable);
138 myManager.removeDeviceFromOperationalDS(deviceInfo);
143 return myManager.removeDeviceFromOperationalDS(deviceInfo);
148 public ListenableFuture<RpcResult<SetRoleOutput>> makeDeviceSlave(){
149 return sendRoleChangeToDevice(OfpRole.BECOMESLAVE);
153 ListenableFuture<RpcResult<SetRoleOutput>> sendRoleChangeToDevice(final OfpRole newRole) {
154 if (LOG.isDebugEnabled()) {
155 LOG.debug("Sending new role {} to device {}", newRole, deviceInfo.getNodeId());
157 final Future<RpcResult<SetRoleOutput>> setRoleOutputFuture;
158 if (deviceInfo.getVersion() >= OFConstants.OFP_VERSION_1_3) {
159 final SetRoleInput setRoleInput = (new SetRoleInputBuilder()).setControllerRole(newRole)
160 .setNode(new NodeRef(deviceInfo.getNodeInstanceIdentifier())).build();
161 setRoleOutputFuture = this.salRoleService.setRole(setRoleInput);
162 final TimerTask timerTask = timeout -> {
163 if (!setRoleOutputFuture.isDone()) {
164 LOG.warn("New role {} was not propagated to device {} during 5 sec", newRole, deviceInfo.getLOGValue());
165 setRoleOutputFuture.cancel(true);
168 hashedWheelTimer.newTimeout(timerTask, SET_ROLE_TIMEOUT, TimeUnit.SECONDS);
170 LOG.info("Device: {} with version: {} does not support role", deviceInfo.getLOGValue(), deviceInfo.getVersion());
171 return Futures.immediateFuture(null);
173 return JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture);
177 public void setLifecycleInitializationPhaseHandler(final ClusterInitializationPhaseHandler handler) {
178 this.clusterInitializationPhaseHandler = handler;
182 public boolean onContextInstantiateService(final ConnectionContext connectionContext) {
184 if (connectionContext.getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) {
185 LOG.warn("Connection on device {} was interrupted, will stop starting master services.", deviceInfo.getLOGValue());
189 Futures.addCallback(sendRoleChangeToDevice(OfpRole.BECOMEMASTER), new RpcResultFutureCallback());
190 return this.clusterInitializationPhaseHandler.onContextInstantiateService(connectionContext);
193 private class RpcResultFutureCallback implements FutureCallback<RpcResult<SetRoleOutput>> {
195 public void onSuccess(@Nullable RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
196 if (LOG.isDebugEnabled()) {
197 LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue());
202 public void onFailure(final Throwable throwable) {
203 LOG.warn("Was not able to set MASTER role on device, node {}", deviceInfo.getLOGValue());
204 lifecycleService.closeConnection();